mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Filter implicit runtime fallbacks centrally
Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
@@ -96,12 +96,14 @@ 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.
|
||||
`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 only for members that need an implicit fallback, so
|
||||
a fully pinned team remains deployable even when every installed runtime is
|
||||
hidden. Definitions already pinned to a hidden runtime remain runnable.
|
||||
`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
|
||||
these shared resolvers instead of duplicating default selection in a start
|
||||
surface. Team deploys use the same visible-runtime set only for members that
|
||||
need an implicit fallback, so a fully pinned team remains deployable even
|
||||
when every installed runtime is hidden. 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
|
||||
|
||||
@@ -33,6 +33,46 @@ test("resolvePersonaRuntime — undefined personaRuntimeId also returns defaultR
|
||||
});
|
||||
});
|
||||
|
||||
test("resolvePersonaRuntime — hidden defaults are skipped for runtime-less personas", () => {
|
||||
const result = resolvePersonaRuntime(null, runtimes, goose, false, ["goose"]);
|
||||
assert.deepEqual(result, {
|
||||
runtime: claude,
|
||||
warnings: [],
|
||||
isOverridden: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("resolvePersonaRuntime — explicitly pinned hidden runtimes remain available", () => {
|
||||
const result = resolvePersonaRuntime("goose", runtimes, claude, false, [
|
||||
"goose",
|
||||
]);
|
||||
assert.deepEqual(result, {
|
||||
runtime: goose,
|
||||
warnings: [],
|
||||
isOverridden: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("resolvePersonaRuntime — hidden fallback is replaced when a pinned runtime is unavailable", () => {
|
||||
const result = resolvePersonaRuntime("unknown-rt", runtimes, goose, false, [
|
||||
"goose",
|
||||
]);
|
||||
assert.equal(result.runtime, claude);
|
||||
assert.equal(result.warnings.length, 1);
|
||||
assert.match(result.warnings[0], /Claude/);
|
||||
assert.equal(result.isOverridden, true);
|
||||
});
|
||||
|
||||
test("resolvePersonaRuntime — no implicit fallback remains when every runtime is hidden", () => {
|
||||
const result = resolvePersonaRuntime(null, runtimes, goose, false, [
|
||||
"goose",
|
||||
"claude",
|
||||
]);
|
||||
assert.equal(result.runtime, null);
|
||||
assert.equal(result.warnings.length, 1);
|
||||
assert.equal(result.isOverridden, false);
|
||||
});
|
||||
|
||||
test("resolvePersonaRuntime — no personaRuntimeId and no defaultRuntime returns null with warning", () => {
|
||||
const result = resolvePersonaRuntime(null, runtimes, null);
|
||||
assert.equal(result.runtime, null);
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { AcpRuntime, AcpRuntimeCatalogEntry } from "@/shared/api/types";
|
||||
import {
|
||||
filterEnabledAcpRuntimes,
|
||||
getDisabledAcpRuntimeIdsSnapshot,
|
||||
} from "./runtimeVisibilityPreference";
|
||||
|
||||
/**
|
||||
* Select the best default runtime from a catalog, using the same preference
|
||||
@@ -55,18 +59,31 @@ export type ResolvePersonaRuntimeResult = {
|
||||
* fall back to `defaultRuntime` and emit a warning.
|
||||
* 4. If there is no `defaultRuntime` either → return `null` with an error
|
||||
* warning so the UI can block deployment.
|
||||
*
|
||||
* Hidden runtimes remain eligible when explicitly pinned by a persona. They
|
||||
* are removed only from the implicit fallback set, at this shared boundary,
|
||||
* so every provisioning surface observes the device visibility preference.
|
||||
*/
|
||||
export function resolvePersonaRuntime(
|
||||
personaRuntimeId: string | undefined | null,
|
||||
runtimes: readonly AcpRuntime[],
|
||||
defaultRuntime: AcpRuntime | null,
|
||||
forceOverride?: boolean,
|
||||
disabledRuntimeIds: readonly string[] = getDisabledAcpRuntimeIdsSnapshot(),
|
||||
): ResolvePersonaRuntimeResult {
|
||||
const implicitDefaultRuntime = forceOverride
|
||||
? defaultRuntime
|
||||
: resolveVisibleDefaultRuntime(
|
||||
runtimes,
|
||||
defaultRuntime,
|
||||
disabledRuntimeIds,
|
||||
);
|
||||
|
||||
// Case 1: Persona has no runtime preference — use the default.
|
||||
if (!personaRuntimeId) {
|
||||
return {
|
||||
runtime: defaultRuntime,
|
||||
warnings: defaultRuntime
|
||||
runtime: implicitDefaultRuntime,
|
||||
warnings: implicitDefaultRuntime
|
||||
? []
|
||||
: [
|
||||
"No agent runtimes are available. Install a runtime (e.g. Goose) to deploy agents.",
|
||||
@@ -78,28 +95,35 @@ export function resolvePersonaRuntime(
|
||||
// Case 2: Persona's preferred runtime is available.
|
||||
const matched = runtimes.find((p) => p.id === personaRuntimeId);
|
||||
if (matched) {
|
||||
if (forceOverride && defaultRuntime && matched.id !== defaultRuntime.id) {
|
||||
if (
|
||||
forceOverride &&
|
||||
implicitDefaultRuntime &&
|
||||
matched.id !== implicitDefaultRuntime.id
|
||||
) {
|
||||
return {
|
||||
runtime: defaultRuntime,
|
||||
runtime: implicitDefaultRuntime,
|
||||
warnings: [
|
||||
`Runtime override: using ${defaultRuntime.label} instead of ${matched.label}.`,
|
||||
`Runtime override: using ${implicitDefaultRuntime.label} instead of ${matched.label}.`,
|
||||
],
|
||||
isOverridden: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
runtime: forceOverride && defaultRuntime ? defaultRuntime : matched,
|
||||
runtime:
|
||||
forceOverride && implicitDefaultRuntime
|
||||
? implicitDefaultRuntime
|
||||
: matched,
|
||||
warnings: [],
|
||||
isOverridden: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Case 3 & 4: Persona's runtime is not available — fall back.
|
||||
if (defaultRuntime) {
|
||||
if (implicitDefaultRuntime) {
|
||||
return {
|
||||
runtime: defaultRuntime,
|
||||
runtime: implicitDefaultRuntime,
|
||||
warnings: [
|
||||
`This agent is configured for runtime "${personaRuntimeId}" but it is not available. Using ${defaultRuntime.label} instead.`,
|
||||
`This agent is configured for runtime "${personaRuntimeId}" but it is not available. Using ${implicitDefaultRuntime.label} instead.`,
|
||||
],
|
||||
isOverridden: true,
|
||||
};
|
||||
@@ -114,6 +138,24 @@ export function resolvePersonaRuntime(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveVisibleDefaultRuntime(
|
||||
runtimes: readonly AcpRuntime[],
|
||||
defaultRuntime: AcpRuntime | null,
|
||||
disabledRuntimeIds: readonly string[],
|
||||
): AcpRuntime | null {
|
||||
if (!defaultRuntime) return null;
|
||||
|
||||
const visibleRuntimes = filterEnabledAcpRuntimes(
|
||||
runtimes,
|
||||
disabledRuntimeIds,
|
||||
);
|
||||
return (
|
||||
visibleRuntimes.find((runtime) => runtime.id === defaultRuntime.id) ??
|
||||
visibleRuntimes[0] ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect runtime-resolution warnings for a list of personas.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user