Scope defaults to visible harness fallbacks

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-07-27 13:26:29 +01:00
parent 81fe1896e5
commit 0591b50b6f
10 changed files with 174 additions and 13 deletions
+6 -3
View File
@@ -93,9 +93,12 @@ with a TypeScript lookup table or an id comparison in a component.
runtime off must not uninstall it, stop it, or invalidate an existing
agent that already uses it. If the disabled runtime was the saved global
default, consumers immediately ignore that preference and the defaults
editor persists its visible fallback on the next save. Runtime-less agent
starts and team deploys must filter through the same visible-runtime set;
definitions already pinned to a hidden runtime remain runnable.
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.
Runtime-less agent starts and team deploys must filter through the same
visible-runtime set; definitions already pinned to a hidden runtime remain
runnable.
10. **The defaults modal is progressively disclosed.** An unset global config
starts on the Buzz Agent-first deployment fallback and carries that visible
harness into the next saved edit. The `progressive-defaults` disclosure
@@ -5,6 +5,7 @@ import {
availableRuntimesForStart,
buildInstanceInputForDefinition,
resolveStartRuntimeForDefinition,
shouldPinSelectedRuntimeForDefinition,
} from "./instanceInputForDefinition.ts";
// ── Phase 1B.3.5: the single definition→instance mapping ────────────────────
@@ -74,6 +75,9 @@ test("row 4: create input never contains definition env vars", async () => {
});
test("row 2: harnessOverride follows the backend-aligned formula", async () => {
assert.equal(shouldPinSelectedRuntimeForDefinition(undefined, "goose"), true);
assert.equal(shouldPinSelectedRuntimeForDefinition("claude", "goose"), false);
const match = await buildInstanceInputForDefinition(
persona({ runtime: "goose" }),
gooseRuntime,
@@ -88,6 +88,16 @@ export type BackendIntent = {
config: Record<string, unknown>;
};
/** Keep every definition-start surface aligned on runtime pinning semantics. */
export function shouldPinSelectedRuntimeForDefinition(
definitionRuntimeId: string | null | undefined,
selectedRuntimeId: string,
): boolean {
return (
!definitionRuntimeId || definitionRuntimeId.trim() === selectedRuntimeId
);
}
/**
* The single definition→instance mapping (Phase 1B.3.5 rows 2–4). Every
* surface that creates a running instance from a definition builds its
@@ -151,7 +161,10 @@ export async function buildInstanceInputForDefinition(
// at top of this function).
agentArgs: [],
mcpCommand: runtime.mcpCommand ?? "",
harnessOverride: !persona.runtime || persona.runtime === runtime.id,
harnessOverride: shouldPinSelectedRuntimeForDefinition(
persona.runtime,
runtime.id,
),
model: persona.model ?? undefined,
provider: persona.provider ?? undefined,
spawnAfterCreate: true,
@@ -66,16 +66,18 @@ test("stored runtime visibility is read from the versioned device key", () => {
assert.deepEqual(readDisabledAcpRuntimeIds(storage), ["claude"]);
});
test("a disabled saved runtime is removed from the effective preference", () => {
test("a disabled saved runtime and its dependent defaults are masked", () => {
const config = {
env_vars: {},
provider: null,
model: null,
provider: "relay-mesh",
model: "auto",
preferred_runtime: "Goose",
};
assert.deepEqual(maskDisabledAcpRuntimePreference(config, ["goose"]), {
...config,
provider: null,
model: null,
preferred_runtime: null,
});
assert.equal(maskDisabledAcpRuntimePreference(config, ["claude"]), config);
@@ -110,13 +110,20 @@ export function runtimesForImplicitAcpSelection<T extends { id: string }>(
}
/**
* Prevent a disabled runtime from remaining the effective global preference.
* Prevent a disabled runtime and its dependent defaults from remaining
* effective for new implicit selections.
*
* The persisted config is left untouched until the user next saves defaults;
* consumers immediately fall back through the normal runtime selection path.
* existing agents keep their configuration while new consumers immediately
* fall back through the normal runtime selection path without carrying a
* provider or model selected for the hidden harness.
*/
export function maskDisabledAcpRuntimePreference<
T extends { preferred_runtime: string | null },
T extends {
model: string | null;
preferred_runtime: string | null;
provider: string | null;
},
>(config: T, disabledRuntimeIds: readonly string[]): T {
const preferredRuntime = config.preferred_runtime;
if (
@@ -128,7 +135,12 @@ export function maskDisabledAcpRuntimePreference<
return config;
}
return { ...config, preferred_runtime: null };
return {
...config,
model: null,
preferred_runtime: null,
provider: null,
};
}
function getDisabledRuntimeIdsSnapshot(): readonly string[] {
@@ -11,6 +11,7 @@ import {
emptyResolvedTeamPersonas,
resolveTeamPersonas,
} from "@/features/agents/lib/teamPersonas";
import { shouldPinSelectedRuntimeForDefinition } from "@/features/agents/lib/instanceInputForDefinition";
import { useSelectableAcpRuntimes } from "@/features/agents/lib/runtimeVisibilityPreference";
import {
collectRuntimeWarnings,
@@ -147,6 +148,10 @@ export function AddTeamToChannelDialog({
name: persona.displayName,
systemPrompt: persona.systemPrompt,
avatarUrl: persona.avatarUrl ?? undefined,
harnessOverride: shouldPinSelectedRuntimeForDefinition(
persona.runtime,
runtimeToUse.id,
),
model: persona.model ?? undefined,
personaId: persona.id,
teamId: team.id,