Apply harness visibility to every agent start

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-07-27 13:26:45 +01:00
parent 0591b50b6f
commit 6bebda4f07
5 changed files with 46 additions and 18 deletions
+5 -3
View File
@@ -96,9 +96,11 @@ 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.
Runtime-less agent starts and team deploys must filter through the same
visible-runtime set; definitions already pinned to a hidden runtime remain
runnable.
`resolveStartRuntimeForDefinition` is the shared boundary that filters every
runtime-less start through the device's visible-runtime set; call it instead
of duplicating default selection in a start surface. Team deploys use 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
@@ -331,6 +331,28 @@ test("item-13: goose-only available — persona with no runtime resolves goose",
assert.deepEqual(warnings, []);
});
test("runtime-less starts exclude disabled runtimes at the shared resolver", () => {
const { runtime, warnings } = resolveStartRuntimeForDefinition(
persona({ runtime: undefined }),
[gooseRuntime, buzzAgentRuntime],
"buzz-agent",
["buzz-agent"],
);
assert.equal(runtime.id, "goose");
assert.deepEqual(warnings, []);
});
test("explicit definitions can still start on a hidden runtime", () => {
const { runtime, warnings } = resolveStartRuntimeForDefinition(
persona({ runtime: "buzz-agent" }),
[gooseRuntime, buzzAgentRuntime],
null,
["buzz-agent"],
);
assert.equal(runtime.id, "buzz-agent");
assert.deepEqual(warnings, []);
});
test("item-13: no runtimes available — refuses with actionable error", () => {
assert.throws(
() => resolveStartRuntimeForDefinition(persona({ runtime: undefined }), []),
@@ -9,6 +9,10 @@ import {
resolvePersonaRuntime,
type ResolvePersonaRuntimeResult,
} from "./resolvePersonaRuntime";
import {
getDisabledAcpRuntimeIdsSnapshot,
runtimesForImplicitAcpSelection,
} from "./runtimeVisibilityPreference";
import {
resolveManagedAgentAvatarUrl,
type UploadMediaBytes,
@@ -46,13 +50,22 @@ export function resolveStartRuntimeForDefinition(
persona: AgentPersona,
runtimes: readonly AcpRuntime[],
preferredRuntimeId?: string | null,
disabledRuntimeIds: readonly string[] = getDisabledAcpRuntimeIdsSnapshot(),
): { runtime: AcpRuntime; warnings: string[] } {
const selectableRuntimes = runtimesForImplicitAcpSelection(
runtimes,
disabledRuntimeIds,
persona.runtime,
);
// Use the buzz-agent-first preference (buzz-agent → goose → first available)
// so a freshly installed goose never beats the bundled buzz-agent sidecar
// for runtime-less personas (item 13 regression guard).
const defaultRuntime = getDefaultPersonaRuntime(runtimes, preferredRuntimeId);
const defaultRuntime = getDefaultPersonaRuntime(
selectableRuntimes,
preferredRuntimeId,
);
const { runtime, warnings, isOverridden }: ResolvePersonaRuntimeResult =
resolvePersonaRuntime(persona.runtime, runtimes, defaultRuntime);
resolvePersonaRuntime(persona.runtime, selectableRuntimes, defaultRuntime);
if (!runtime) {
throw new Error("No available runtime found for this agent.");
@@ -143,7 +143,7 @@ export function maskDisabledAcpRuntimePreference<
};
}
function getDisabledRuntimeIdsSnapshot(): readonly string[] {
export function getDisabledAcpRuntimeIdsSnapshot(): readonly string[] {
const storage = getLocalStorage();
if (!storage) return EMPTY_DISABLED_RUNTIME_IDS;
@@ -191,7 +191,7 @@ export function setAcpRuntimeEnabled(
const storage = getLocalStorage();
if (!storage) return false;
const current = getDisabledRuntimeIdsSnapshot();
const current = getDisabledAcpRuntimeIdsSnapshot();
const next = nextDisabledAcpRuntimeIds(current, runtimeId, enabled);
if (next === current) return true;
@@ -211,7 +211,7 @@ export function setAcpRuntimeEnabled(
export function useDisabledAcpRuntimeIds(): readonly string[] {
return React.useSyncExternalStore(
subscribeToRuntimeVisibility,
getDisabledRuntimeIdsSnapshot,
getDisabledAcpRuntimeIdsSnapshot,
() => EMPTY_DISABLED_RUNTIME_IDS,
);
}
@@ -35,14 +35,9 @@ import {
buildInstanceInputForDefinition,
resolveStartRuntimeForDefinition,
} from "../lib/instanceInputForDefinition";
import {
runtimesForImplicitAcpSelection,
useDisabledAcpRuntimeIds,
} from "../lib/runtimeVisibilityPreference";
export function useManagedAgentActions() {
const { globalConfig } = useGlobalAgentConfig();
const disabledRuntimeIds = useDisabledAcpRuntimeIds();
const relayAgentsQuery = useRelayAgentsQuery();
const managedAgentsQuery = useManagedAgentsQuery();
const [shouldLoadChannels, setShouldLoadChannels] = React.useState(false);
@@ -197,11 +192,7 @@ export function useManagedAgentActions() {
setPersonaStartPending(persona.id, true);
clearFeedback();
try {
const runtimes = runtimesForImplicitAcpSelection(
await availableRuntimesForStart(availableRuntimesQuery),
disabledRuntimeIds,
persona.runtime,
);
const runtimes = await availableRuntimesForStart(availableRuntimesQuery);
const { runtime, warnings } = resolveStartRuntimeForDefinition(
persona,
runtimes,