Scope hidden harness defaults by dialog mode

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-07-27 13:28:43 +01:00
parent 2864db1ca7
commit 9901cf621e
7 changed files with 126 additions and 11 deletions
+2
View File
@@ -96,6 +96,8 @@ with a TypeScript lookup table or an id comparison in a component.
editor persists its visible fallback on the next save. Its dependent
provider/model defaults are also ignored for new implicit fallback agents,
without changing the persisted configuration used by existing agents.
Create-mode dialogs use the implicit masked config; existing definition and
instance edit dialogs use the raw persisted config.
`resolvePersonaRuntime` is the shared visibility boundary for every
runtime-less deployment or provisioning path. Definition-to-instance starts
use the stricter `resolveStartRuntimeForDefinition` wrapper; call one of
@@ -68,7 +68,7 @@ import {
usePersonaModelDiscovery,
} from "./usePersonaModelDiscovery";
import { useBakedBuildEnvKeysQuery, useRuntimeFileConfigQuery } from "../hooks";
import { useAgentDialogDefaults } from "./useAgentDialogDefaults";
import { useDefinitionAgentDialogDefaults } from "./useAgentDialogDefaults";
import { AgentDefaultsDialog } from "./AgentDefaultsDialog";
import { AgentHarnessField } from "./AgentHarnessField";
import {
@@ -164,7 +164,7 @@ export function AgentDefinitionDialog({
model: inheritedModelDefault,
},
inheritedEnvVars: inheritedEnvVarsForAdvanced,
} = useAgentDialogDefaults({ open });
} = useDefinitionAgentDialogDefaults(initialValues, open);
const selectableRuntimes = useSelectableAcpRuntimes(runtimes);
const defaultRuntime = getDefaultPersonaRuntime(
selectableRuntimes,
@@ -367,7 +367,11 @@ export function AgentInstanceEditDialog({
model: inheritedModelDefault,
},
inheritedEnvVars: inheritedEnvVarsForAdvanced,
} = useAgentDialogDefaults({ inheritedEnvVars, open });
} = useAgentDialogDefaults({
configScope: "existing",
inheritedEnvVars,
open,
});
// Runtime/provider-required credential state, derived from the PROSPECTIVE
// post-submit runtime — see the hook for the inherit-transition rationale.
@@ -207,6 +207,20 @@ test("reconcilePreferredRuntimeFallback updates a hidden saved default", () => {
assert.equal(reconcilePreferredRuntimeFallback(config, "goose"), config);
});
test("reconcilePreferredRuntimeFallback persists an unsaved displayed fallback", () => {
const config = {
env_vars: { SHARED: "kept" },
provider: "relay-mesh",
model: "auto",
preferred_runtime: null,
};
assert.deepEqual(reconcilePreferredRuntimeFallback(config, "buzz-agent"), {
...config,
preferred_runtime: "buzz-agent",
});
});
// ── getPersonaModelOptions — codex/claude do not use global provider ──────────
//
// The discovery call in AgentDefinitionDialog passes
@@ -199,21 +199,25 @@ export function resetConfigForHarnessChange(
}
/**
* Align a stale or hidden saved preference with the fallback shown by a
* runtime selector, clearing values that are not portable across harnesses.
* Align a missing, stale, or hidden saved preference with the shown fallback.
* A missing preference adopts the current context without clearing its draft;
* switching away from a saved harness clears values that are not portable.
*/
export function reconcilePreferredRuntimeFallback(
config: GlobalAgentConfig,
fallbackRuntimeId: string | null,
): GlobalAgentConfig {
if (
!config.preferred_runtime ||
!fallbackRuntimeId ||
config.preferred_runtime === fallbackRuntimeId
) {
if (!fallbackRuntimeId || config.preferred_runtime === fallbackRuntimeId) {
return config;
}
if (!config.preferred_runtime) {
return {
...config,
preferred_runtime: fallbackRuntimeId,
};
}
return resetConfigForHarnessChange(config, fallbackRuntimeId);
}
@@ -0,0 +1,42 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
agentDefinitionConfigScope,
resolveAgentDialogGlobalConfig,
} from "./useAgentDialogDefaults.ts";
const persistedConfig = {
env_vars: { SHARED: "kept" },
provider: "relay-mesh",
model: "auto",
preferred_runtime: "buzz-agent",
};
test("create-mode defaults mask values owned by a hidden harness", () => {
assert.deepEqual(
resolveAgentDialogGlobalConfig(persistedConfig, "implicit", ["buzz-agent"]),
{
env_vars: { SHARED: "kept" },
provider: null,
model: null,
preferred_runtime: null,
},
);
});
test("existing edit defaults preserve values owned by a hidden harness", () => {
assert.equal(
resolveAgentDialogGlobalConfig(persistedConfig, "existing", ["buzz-agent"]),
persistedConfig,
);
});
test("definition dialogs select config scope from create versus edit values", () => {
assert.equal(agentDefinitionConfigScope(null), "implicit");
assert.equal(agentDefinitionConfigScope({ displayName: "New" }), "implicit");
assert.equal(
agentDefinitionConfigScope({ id: "existing", displayName: "Existing" }),
"existing",
);
});
@@ -1,18 +1,57 @@
import * as React from "react";
import type {
CreatePersonaInput,
GlobalAgentConfig,
UpdatePersonaInput,
} from "@/shared/api/types";
import { useBakedBuildEnvQuery } from "../hooks";
import {
maskDisabledAcpRuntimePreference,
useDisabledAcpRuntimeIds,
} from "../lib/runtimeVisibilityPreference";
import { useGlobalAgentConfig } from "../useGlobalAgentConfig";
import { BUZZ_AGENT_THINKING_EFFORT } from "./buzzAgentConfig";
import { getInheritedAgentDefaults } from "./bakedEnvHelpers";
export type AgentDialogConfigScope = "existing" | "implicit";
export function agentDefinitionConfigScope(
initialValues: CreatePersonaInput | UpdatePersonaInput | null,
): AgentDialogConfigScope {
return initialValues && "id" in initialValues ? "existing" : "implicit";
}
export function resolveAgentDialogGlobalConfig(
persistedConfig: GlobalAgentConfig,
configScope: AgentDialogConfigScope,
disabledRuntimeIds: readonly string[],
): GlobalAgentConfig {
return configScope === "implicit"
? maskDisabledAcpRuntimePreference(persistedConfig, disabledRuntimeIds)
: persistedConfig;
}
export function useAgentDialogDefaults({
configScope,
inheritedEnvVars = {},
open,
}: {
configScope: AgentDialogConfigScope;
inheritedEnvVars?: Record<string, string>;
open: boolean;
}) {
const { globalConfig } = useGlobalAgentConfig();
const { globalConfig: persistedConfig } = useGlobalAgentConfig();
const disabledRuntimeIds = useDisabledAcpRuntimeIds();
const globalConfig = React.useMemo(
() =>
resolveAgentDialogGlobalConfig(
persistedConfig,
configScope,
disabledRuntimeIds,
),
[configScope, disabledRuntimeIds, persistedConfig],
);
const { data: bakedEnv } = useBakedBuildEnvQuery({ enabled: open });
const inheritedDefaults = getInheritedAgentDefaults(globalConfig, bakedEnv);
const effectiveInheritedEnvVars = React.useMemo(
@@ -31,3 +70,13 @@ export function useAgentDialogDefaults({
inheritedEnvVars: effectiveInheritedEnvVars,
};
}
export function useDefinitionAgentDialogDefaults(
initialValues: CreatePersonaInput | UpdatePersonaInput | null,
open: boolean,
) {
return useAgentDialogDefaults({
configScope: agentDefinitionConfigScope(initialValues),
open,
});
}