Align hidden harness fallback readiness

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-07-27 13:30:37 +01:00
parent 7f6819ee84
commit 2a8a7bc773
7 changed files with 100 additions and 10 deletions
@@ -214,6 +214,8 @@ pub fn save_global_agent_config(app: &AppHandle, config: &GlobalAgentConfig) ->
/// command is pinned on the record, and provider/model defaults belonging to a
/// different preferred runtime must not cross the harness boundary. Explicitly
/// configured definitions and standalone agents keep normal global inheritance.
/// Configs written before `preferred_runtime` existed implicitly belong to
/// Buzz Agent.
pub(crate) fn global_model_provider_for_record<'a>(
record: &ManagedAgentRecord,
personas: &[AgentDefinition],
@@ -235,17 +237,17 @@ pub(crate) fn global_model_provider_for_record<'a>(
return global_values;
}
let Some(preferred_runtime) = global
let preferred_runtime = global
.preferred_runtime
.as_deref()
.and_then(crate::managed_agents::known_acp_runtime)
else {
return global_values;
};
.or_else(|| crate::managed_agents::known_acp_runtime("buzz-agent"));
let selected_command = crate::managed_agents::record_agent_command(record, personas);
let selected_runtime = crate::managed_agents::known_acp_runtime(&selected_command);
if selected_runtime.is_some_and(|selected| preferred_runtime.id == selected.id) {
if selected_runtime.is_some_and(|selected| {
preferred_runtime.is_some_and(|preferred| preferred.id == selected.id)
}) {
global_values
} else {
(None, None)
@@ -491,6 +491,25 @@ fn runtime_fallback_does_not_inherit_defaults_from_a_different_preferred_runtime
);
}
#[test]
fn legacy_runtime_fallback_does_not_inherit_implicit_buzz_agent_defaults() {
let mut record = bare_record();
record.persona_id = Some("p1".to_string());
record.agent_command_override = Some("goose".to_string());
let personas = vec![persona("p1", None, None)];
let global = GlobalAgentConfig {
model: Some("auto".to_string()),
provider: Some("relay-mesh".to_string()),
preferred_runtime: None,
..Default::default()
};
assert_eq!(
resolve_effective_model_provider(&record, &personas, &global),
(None, None)
);
}
#[test]
fn default_command_fallback_does_not_inherit_defaults_from_another_preferred_runtime() {
let mut record = bare_record();
+3
View File
@@ -96,6 +96,9 @@ 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.
Legacy global defaults with no saved preferred runtime are treated as
Buzz Agent-owned for this masking boundary, so hiding Buzz Agent cannot
leak its provider/model into another implicit fallback.
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
@@ -118,3 +118,19 @@ test("a disabled saved runtime and its dependent defaults are masked", () => {
});
assert.equal(maskDisabledAcpRuntimePreference(config, ["claude"]), config);
});
test("legacy defaults without a saved runtime are owned by buzz-agent", () => {
const config = {
env_vars: {},
provider: "relay-mesh",
model: "auto",
preferred_runtime: null,
};
assert.deepEqual(maskDisabledAcpRuntimePreference(config, ["buzz-agent"]), {
...config,
provider: null,
model: null,
});
assert.equal(maskDisabledAcpRuntimePreference(config, ["goose"]), config);
});
@@ -166,7 +166,8 @@ export function visibleAcpRuntimeSeedForCreate<T extends { id: string }>(
* The persisted config is left untouched until the user next saves defaults;
* 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.
* provider or model selected for the hidden harness. Configs written before
* preferred_runtime existed implicitly belong to Buzz Agent.
*/
export function maskDisabledAcpRuntimePreference<
T extends {
@@ -176,11 +177,11 @@ export function maskDisabledAcpRuntimePreference<
},
>(config: T, disabledRuntimeIds: readonly string[]): T {
const preferredRuntime = config.preferred_runtime;
const implicitLegacyRuntime = preferredRuntime?.trim() || "buzz-agent";
if (
!preferredRuntime ||
!disabledRuntimeIds
.map(normalizeRuntimeId)
.includes(normalizeRuntimeId(preferredRuntime))
.includes(normalizeRuntimeId(implicitLegacyRuntime))
) {
return config;
}
@@ -57,6 +57,40 @@ test("welcome readiness ignores a hidden logged-in runtime", () => {
);
});
test("welcome readiness evaluates the runtime selected by the visible fallback", () => {
const runtimes = [
{
id: "buzz-agent",
label: "Buzz Agent",
availability: "available",
authStatus: { status: "not_applicable" },
},
{
id: "goose",
label: "Goose",
availability: "available",
authStatus: { status: "not_applicable" },
},
{
id: "claude",
label: "Claude",
availability: "available",
authStatus: { status: "logged_in" },
},
];
const globalConfig = {
env_vars: {},
provider: null,
model: null,
preferred_runtime: "buzz-agent",
};
assert.deepEqual(
resolveWelcomeAgentReadiness(runtimes, globalConfig, ["buzz-agent"]),
{ ready: false },
);
});
test("welcome provisioning requires an enabled available runtime", () => {
const runtimes = [
{
@@ -9,6 +9,7 @@ import {
filterEnabledAcpRuntimes,
useDisabledAcpRuntimeIds,
} from "@/features/agents/lib/runtimeVisibilityPreference";
import { getDefaultPersonaRuntime } from "@/features/agents/lib/resolvePersonaRuntime";
import { clearActiveTurnsForAgentOnStop } from "@/features/agents/managedAgentRuntimeHooks";
import { useImplicitGlobalAgentConfig } from "@/features/agents/useGlobalAgentConfig";
import { useCommunities } from "@/features/communities/useCommunities";
@@ -61,9 +62,23 @@ export function resolveWelcomeAgentReadiness(
globalConfig: GlobalAgentConfig,
disabledRuntimeIds: readonly string[],
) {
const visibleRuntimes = filterEnabledAcpRuntimes(
runtimes,
disabledRuntimeIds,
);
const selectedRuntime = getDefaultPersonaRuntime(
visibleRuntimes,
globalConfig.preferred_runtime,
);
if (!selectedRuntime) return { ready: false } as const;
return resolveAgentReadiness(
filterEnabledAcpRuntimes(runtimes, disabledRuntimeIds),
globalConfig,
visibleRuntimes,
{
...globalConfig,
preferred_runtime: selectedRuntime.id,
},
"preferred",
);
}