mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Preserve harness merge resolutions after DCO rebase
Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
@@ -759,13 +759,11 @@ pub async fn create_managed_agent(
|
||||
// Load personas once for harness/pack/avatar resolution below.
|
||||
let personas = load_personas(&app).unwrap_or_default();
|
||||
|
||||
// The persona runtime is authoritative. Persist an override only when
|
||||
// the selected runtime must remain pinned (`harness_override`). This
|
||||
// includes explicit picks and the visible fallback for a runtime-less
|
||||
// persona. `implicit_harness_fallback` distinguishes those intents so
|
||||
// the pin cannot adopt defaults owned by another harness. A divergence
|
||||
// without `harness_override` remains inherited so it can recover when
|
||||
// its configured runtime is installed. Persona-less creates always pin.
|
||||
// The persona runtime is authoritative. Persist an override only for a
|
||||
// pinned selection, including the visible runtime-less fallback.
|
||||
// `implicit_harness_fallback` distinguishes that automatic fallback so
|
||||
// it cannot adopt defaults owned by another harness. Other divergence
|
||||
// stays inherited; persona-less creates always pin.
|
||||
let (agent_command_override, agent_command_override_is_implicit) =
|
||||
crate::managed_agents::create_time_agent_command_override_state(
|
||||
requested_persona_id.as_deref(),
|
||||
|
||||
@@ -17,7 +17,7 @@ fn bare_agent_record(
|
||||
relay_url: "ws://localhost:3000".to_string(),
|
||||
avatar_url: None,
|
||||
acp_command: "buzz-acp".to_string(),
|
||||
agent_command: "goose".to_string(),
|
||||
agent_command: "buzz-agent".to_string(),
|
||||
agent_command_override: None,
|
||||
agent_command_override_is_implicit: false,
|
||||
agent_args: vec![],
|
||||
@@ -219,7 +219,7 @@ fn deploy_resolver_returns_none_for_orphaned_instance() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deploy_resolver_ignores_defaults_from_a_different_implicit_runtime() {
|
||||
fn deploy_resolver_keeps_defaults_for_an_explicit_harness_override() {
|
||||
let mut record = bare_agent_record(Some("p1"), None, None);
|
||||
record.agent_command_override = Some("goose".to_string());
|
||||
let personas = vec![persona_record("p1", None, None)];
|
||||
@@ -232,7 +232,7 @@ fn deploy_resolver_ignores_defaults_from_a_different_implicit_runtime() {
|
||||
|
||||
assert_eq!(
|
||||
resolve_deploy_model_provider(&record, &personas, &global),
|
||||
(None, None)
|
||||
(Some("auto".to_string()), Some("relay-mesh".to_string()))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -362,8 +362,6 @@ pub fn effective_agent_command(
|
||||
}
|
||||
|
||||
mod overrides;
|
||||
#[cfg(test)]
|
||||
pub use overrides::create_time_agent_command_override;
|
||||
pub use overrides::{apply_agent_command_update, create_time_agent_command_override_state};
|
||||
|
||||
/// Prefix of the typed dangling-harness error produced by
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::overrides::{divergent_agent_command_override, update_time_agent_command_override};
|
||||
use super::overrides::{
|
||||
create_time_agent_command_override, divergent_agent_command_override,
|
||||
update_time_agent_command_override,
|
||||
};
|
||||
use super::{
|
||||
apply_agent_command_update, classify_runtime, codex_adapter_availability,
|
||||
codex_adapter_is_outdated, create_time_agent_command_override, default_agent_command,
|
||||
effective_agent_command, find_nvm_default_bin, find_via_login_shell,
|
||||
is_login_shell_path_uninit, is_safe_nvm_tag, managed_agent_avatar_url, normalize_agent_args,
|
||||
parse_semver_tag, preset_catalog_entry, probe_codex_acp_major_version, record_agent_command,
|
||||
refresh_login_shell_path, try_record_agent_command, PresetHarness, BUZZ_AGENT_AVATAR_URL,
|
||||
CLAUDE_CODE_AVATAR_URL, CODEX_AVATAR_URL, GOOSE_AVATAR_URL,
|
||||
codex_adapter_is_outdated, default_agent_command, effective_agent_command,
|
||||
find_nvm_default_bin, find_via_login_shell, is_login_shell_path_uninit, is_safe_nvm_tag,
|
||||
managed_agent_avatar_url, normalize_agent_args, parse_semver_tag, preset_catalog_entry,
|
||||
probe_codex_acp_major_version, record_agent_command, refresh_login_shell_path,
|
||||
try_record_agent_command, PresetHarness, BUZZ_AGENT_AVATAR_URL, CLAUDE_CODE_AVATAR_URL,
|
||||
CODEX_AVATAR_URL, GOOSE_AVATAR_URL,
|
||||
};
|
||||
use crate::managed_agents::AcpAvailabilityStatus;
|
||||
|
||||
|
||||
@@ -72,16 +72,22 @@ fn non_blank(v: Option<&str>) -> Option<&str> {
|
||||
}
|
||||
|
||||
fn resolve_linked(
|
||||
record: &ManagedAgentRecord,
|
||||
definition: &AgentDefinition,
|
||||
definitions: &[AgentDefinition],
|
||||
global: &GlobalAgentConfig,
|
||||
) -> EffectiveAgentConfig {
|
||||
let global_defaults_apply =
|
||||
super::global_config::global_harness_defaults_apply_to_record(record, definitions, global);
|
||||
let model = match non_blank(definition.model.as_deref()) {
|
||||
Some(m) => ResolvedField {
|
||||
value: Some(m.to_owned()),
|
||||
source: ConfigSource::Definition,
|
||||
},
|
||||
None => ResolvedField {
|
||||
value: global.model.clone(),
|
||||
value: global_defaults_apply
|
||||
.then(|| global.model.clone())
|
||||
.flatten(),
|
||||
source: ConfigSource::Global,
|
||||
},
|
||||
};
|
||||
@@ -92,7 +98,9 @@ fn resolve_linked(
|
||||
source: ConfigSource::Definition,
|
||||
},
|
||||
None => ResolvedField {
|
||||
value: global.provider.clone(),
|
||||
value: global_defaults_apply
|
||||
.then(|| global.provider.clone())
|
||||
.flatten(),
|
||||
source: ConfigSource::Global,
|
||||
},
|
||||
};
|
||||
@@ -251,7 +259,9 @@ pub fn resolve_effective_config(
|
||||
) -> EffectiveConfigResult {
|
||||
match &record.persona_id {
|
||||
Some(pid) => match definitions.iter().find(|d| d.id == *pid) {
|
||||
Some(def) => EffectiveConfigResult::Resolved(resolve_linked(def, global)),
|
||||
Some(def) => {
|
||||
EffectiveConfigResult::Resolved(resolve_linked(record, def, definitions, global))
|
||||
}
|
||||
None => EffectiveConfigResult::OrphanedInstance {
|
||||
record_pubkey: record.pubkey.clone(),
|
||||
missing_persona_id: pid.clone(),
|
||||
|
||||
@@ -45,8 +45,9 @@ fn record(
|
||||
relay_url: "ws://localhost:3000".to_string(),
|
||||
avatar_url: None,
|
||||
acp_command: "buzz-acp".to_string(),
|
||||
agent_command: "goose".to_string(),
|
||||
agent_command: "buzz-agent".to_string(),
|
||||
agent_command_override: None,
|
||||
agent_command_override_is_implicit: false,
|
||||
agent_args: vec![],
|
||||
mcp_command: "".to_string(),
|
||||
turn_timeout_seconds: 300,
|
||||
|
||||
@@ -223,7 +223,7 @@ pub fn save_global_agent_config(app: &AppHandle, config: &GlobalAgentConfig) ->
|
||||
/// harness. Explicitly configured definitions and standalone agents keep
|
||||
/// normal global inheritance. Configs written before `preferred_runtime`
|
||||
/// existed implicitly belong to Buzz Agent.
|
||||
fn global_harness_defaults_apply_to_record(
|
||||
pub(crate) fn global_harness_defaults_apply_to_record(
|
||||
record: &ManagedAgentRecord,
|
||||
personas: &[AgentDefinition],
|
||||
global: &GlobalAgentConfig,
|
||||
@@ -255,27 +255,18 @@ fn global_harness_defaults_apply_to_record(
|
||||
let preferred_runtime = global
|
||||
.preferred_runtime
|
||||
.as_deref()
|
||||
.and_then(crate::managed_agents::known_acp_runtime)
|
||||
.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);
|
||||
.filter(|runtime| !runtime.trim().is_empty())
|
||||
.unwrap_or("buzz-agent");
|
||||
let preferred_command = crate::managed_agents::known_acp_runtime_exact(preferred_runtime)
|
||||
.and_then(|runtime| runtime.commands.first().copied())
|
||||
.map(str::to_string)
|
||||
.or_else(|| {
|
||||
crate::managed_agents::custom_harnesses::lookup_loaded_harness_by_id(preferred_runtime)
|
||||
.map(|harness| harness.command.clone())
|
||||
})
|
||||
.unwrap_or_else(|| preferred_runtime.to_string());
|
||||
|
||||
selected_runtime.is_some_and(|selected| {
|
||||
preferred_runtime.is_some_and(|preferred| preferred.id == selected.id)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the global provider/model values that are safe for this record.
|
||||
pub(crate) fn global_model_provider_for_record<'a>(
|
||||
record: &ManagedAgentRecord,
|
||||
personas: &[AgentDefinition],
|
||||
global: &'a GlobalAgentConfig,
|
||||
) -> (Option<&'a str>, Option<&'a str>) {
|
||||
if global_harness_defaults_apply_to_record(record, personas, global) {
|
||||
(global.model.as_deref(), global.provider.as_deref())
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
record.agent_command.trim() == preferred_command.trim()
|
||||
}
|
||||
|
||||
/// Return global env vars with harness-dependent defaults masked when an
|
||||
|
||||
@@ -307,7 +307,7 @@ fn bare_record() -> ManagedAgentRecord {
|
||||
relay_url: "ws://localhost:3000".to_string(),
|
||||
avatar_url: None,
|
||||
acp_command: "buzz-acp".to_string(),
|
||||
agent_command: "goose".to_string(),
|
||||
agent_command: "buzz-agent".to_string(),
|
||||
agent_command_override: None,
|
||||
agent_command_override_is_implicit: false,
|
||||
agent_args: vec![],
|
||||
@@ -494,10 +494,6 @@ fn explicit_harness_override_keeps_defaults_from_a_different_preferred_runtime()
|
||||
global_env_vars_for_record(&record, &personas, &global),
|
||||
global.env_vars
|
||||
);
|
||||
assert_eq!(
|
||||
global_env_vars_for_record(&record, &personas, &global),
|
||||
global.env_vars
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -547,6 +543,26 @@ fn explicit_harness_override_keeps_legacy_global_defaults() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_fallback_does_not_inherit_defaults_from_a_different_preferred_runtime() {
|
||||
let mut record = bare_record();
|
||||
record.persona_id = Some("p1".to_string());
|
||||
record.agent_command = "goose".to_string();
|
||||
record.agent_command_override = None;
|
||||
let personas = vec![persona("p1", None, None)];
|
||||
let global = GlobalAgentConfig {
|
||||
model: Some("auto".to_string()),
|
||||
provider: Some("relay-mesh".to_string()),
|
||||
preferred_runtime: Some("buzz-agent".to_string()),
|
||||
..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();
|
||||
@@ -571,7 +587,8 @@ fn default_command_fallback_does_not_inherit_defaults_from_another_preferred_run
|
||||
fn runtime_fallback_inherits_defaults_when_it_matches_the_preferred_runtime() {
|
||||
let mut record = bare_record();
|
||||
record.persona_id = Some("p1".to_string());
|
||||
record.agent_command_override = Some("goose".to_string());
|
||||
record.agent_command = "goose".to_string();
|
||||
record.agent_command_override = None;
|
||||
let personas = vec![persona("p1", None, None)];
|
||||
let global = GlobalAgentConfig {
|
||||
model: Some("global-model".to_string()),
|
||||
@@ -582,7 +599,10 @@ fn runtime_fallback_inherits_defaults_when_it_matches_the_preferred_runtime() {
|
||||
|
||||
assert_eq!(
|
||||
resolve_effective_model_provider(&record, &personas, &global),
|
||||
(Some("global-model"), Some("global-provider"))
|
||||
(
|
||||
Some("global-model".to_string()),
|
||||
Some("global-provider".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -601,7 +621,10 @@ fn explicit_runtime_keeps_global_defaults_when_another_runtime_is_preferred() {
|
||||
|
||||
assert_eq!(
|
||||
resolve_effective_model_provider(&record, &personas, &global),
|
||||
(Some("global-model"), Some("global-provider"))
|
||||
(
|
||||
Some("global-model".to_string()),
|
||||
Some("global-provider".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,8 @@ pub use env_vars::*;
|
||||
pub(crate) use git_bash::git_bash_available;
|
||||
pub(crate) use git_bash::{discover_git_bash, GitBashPrerequisite};
|
||||
pub(crate) use global_config::{
|
||||
global_env_vars_for_record, global_model_provider_for_record, load_global_agent_config,
|
||||
resolve_effective_model_provider, save_global_agent_config, validate_global_config,
|
||||
GlobalAgentConfig,
|
||||
global_env_vars_for_record, load_global_agent_config, resolve_effective_model_provider,
|
||||
save_global_agent_config, validate_global_config, GlobalAgentConfig,
|
||||
};
|
||||
pub(crate) use managed_node_paths::*;
|
||||
pub use nest::*;
|
||||
|
||||
@@ -15,6 +15,7 @@ fn sample_record() -> ManagedAgentRecord {
|
||||
acp_command: "buzz-acp".into(),
|
||||
agent_command: "goose".into(),
|
||||
agent_command_override: None,
|
||||
agent_command_override_is_implicit: false,
|
||||
agent_args: vec![],
|
||||
mcp_command: String::new(),
|
||||
turn_timeout_seconds: 320,
|
||||
|
||||
@@ -252,8 +252,7 @@ fn resolve_effective_agent_env_with_def(
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 3a: global env vars — the lowest user-settable layer.
|
||||
// Injected before persona/agent so per-agent values win on collision.
|
||||
// Layer 3a: global env vars, injected before persona/agent overrides.
|
||||
// `merged_user_env` with an empty "lower" map applies reserved/malformed-key
|
||||
// filtering to the global map for free.
|
||||
let applicable_global_env =
|
||||
|
||||
@@ -477,6 +477,7 @@ fn global_model_change_trips_hash_without_model_env_var() {
|
||||
let mut rec = record();
|
||||
rec.persona_id = Some("p1".into());
|
||||
rec.agent_command = "some-harness-without-model-env".into();
|
||||
rec.agent_command_override = Some(rec.agent_command.clone());
|
||||
|
||||
let personas = vec![{
|
||||
let mut p = persona("p1", None, "prompt");
|
||||
|
||||
@@ -2,11 +2,6 @@ import * as React from "react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
||||
|
||||
import type {
|
||||
AcpRuntimeCatalogEntry,
|
||||
CreatePersonaInput,
|
||||
UpdatePersonaInput,
|
||||
} from "@/shared/api/types";
|
||||
import { cn } from "@/shared/lib/cn";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { ChooserDialogContent } from "@/shared/ui/chooser-dialog-content";
|
||||
@@ -89,31 +84,8 @@ import {
|
||||
useSelectableAcpRuntimes,
|
||||
visibleAcpRuntimeSeedForCreate,
|
||||
} from "../lib/runtimeVisibilityPreference";
|
||||
|
||||
type AgentDefinitionDialogProps = {
|
||||
open: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
submitLabel: string;
|
||||
initialValues: CreatePersonaInput | UpdatePersonaInput | null;
|
||||
error: Error | null;
|
||||
isPending: boolean;
|
||||
runtimes: AcpRuntimeCatalogEntry[];
|
||||
runtimesLoading?: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onSubmit: (
|
||||
input: CreatePersonaInput | UpdatePersonaInput,
|
||||
) => Promise<unknown>;
|
||||
/** Rendered below the form fields in create mode only ("Where to run"). */
|
||||
createRunSection?: React.ReactNode;
|
||||
/** Extra create-mode submit gate (e.g. incomplete provider config). */
|
||||
createSubmitBlocked?: boolean;
|
||||
};
|
||||
|
||||
const ADVANCED_FIELDS_MOTION_TRANSITION = {
|
||||
duration: 0.18,
|
||||
ease: [0.23, 1, 0.32, 1],
|
||||
} as const;
|
||||
import type { AgentDefinitionDialogProps } from "./AgentDefinitionDialog.types";
|
||||
import { ADVANCED_FIELDS_MOTION_TRANSITION } from "./agentAdvancedFieldsMotion";
|
||||
|
||||
export function AgentDefinitionDialog({
|
||||
open,
|
||||
@@ -400,11 +372,7 @@ export function AgentDefinitionDialog({
|
||||
(runtime.trim().length > 0 && runtimeCanChooseLlmProvider) ||
|
||||
blankRuntimeModelProviderEditable;
|
||||
const trimmedProvider = provider.trim();
|
||||
// Required credential env keys for this runtime + provider combination.
|
||||
// Used to show required markers on the LLM provider label and amber
|
||||
// locked rows in the env vars editor.
|
||||
// File-layer config for the selected runtime (e.g. goose config.yaml).
|
||||
// Used to silence requirements already satisfied there.
|
||||
// File config satisfies credentials before the readiness gate renders them.
|
||||
const { data: runtimeFileConfig } = useRuntimeFileConfigQuery(runtime, {
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import type {
|
||||
AcpRuntimeCatalogEntry,
|
||||
CreatePersonaInput,
|
||||
UpdatePersonaInput,
|
||||
} from "@/shared/api/types";
|
||||
|
||||
export type AgentDefinitionDialogProps = {
|
||||
open: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
submitLabel: string;
|
||||
initialValues: CreatePersonaInput | UpdatePersonaInput | null;
|
||||
error: Error | null;
|
||||
isPending: boolean;
|
||||
runtimes: AcpRuntimeCatalogEntry[];
|
||||
runtimesLoading?: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onSubmit: (
|
||||
input: CreatePersonaInput | UpdatePersonaInput,
|
||||
) => Promise<unknown>;
|
||||
/** Rendered below the form fields in create mode only ("Where to run"). */
|
||||
createRunSection?: ReactNode;
|
||||
/** Extra create-mode submit gate (e.g. incomplete provider config). */
|
||||
createSubmitBlocked?: boolean;
|
||||
};
|
||||
@@ -13,11 +13,9 @@ import {
|
||||
} from "@/features/agents/hooks";
|
||||
import { isManagedAgentActive } from "@/features/agents/lib/managedAgentControlActions";
|
||||
import type {
|
||||
ManagedAgent,
|
||||
RespondToMode,
|
||||
UpdateManagedAgentInput,
|
||||
} from "@/shared/api/types";
|
||||
import type { EditAgentFocusTarget } from "@/features/agents/openEditAgentEvent";
|
||||
import { cn } from "@/shared/lib/cn";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { ChooserDialogContent } from "@/shared/ui/chooser-dialog-content";
|
||||
@@ -85,13 +83,10 @@ import { useProviderApiKeyFieldState } from "./providerApiKeyFieldState";
|
||||
import { useSelectableAcpRuntimes } from "../lib/runtimeVisibilityPreference";
|
||||
import { resolveModelFieldStatusMessage } from "./agentConfigControls";
|
||||
import { AdvancedRequiredBadge } from "./AdvancedRequiredBadge";
|
||||
import { ADVANCED_FIELDS_MOTION_TRANSITION } from "./agentAdvancedFieldsMotion";
|
||||
import type { AgentInstanceEditDialogProps } from "./AgentInstanceEditDialog.types";
|
||||
import { showAgentProfileSyncWarning } from "./agentProfileSyncWarning";
|
||||
|
||||
const ADVANCED_FIELDS_MOTION_TRANSITION = {
|
||||
duration: 0.18,
|
||||
ease: [0.23, 1, 0.32, 1],
|
||||
} as const;
|
||||
|
||||
export function AgentInstanceEditDialog({
|
||||
agent,
|
||||
initialFocus,
|
||||
@@ -99,16 +94,7 @@ export function AgentInstanceEditDialog({
|
||||
onEditLinkedPersona,
|
||||
onOpenChange,
|
||||
onUpdated,
|
||||
}: {
|
||||
agent: ManagedAgent;
|
||||
/** Optional field to scroll/focus when the dialog opens from a card deep-link. */
|
||||
initialFocus?: EditAgentFocusTarget;
|
||||
open: boolean;
|
||||
/** Present only when the linked definition is editable (non-built-in, resolved). Caller closes this dialog and enters definition-edit. */
|
||||
onEditLinkedPersona?: () => void;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onUpdated?: (agent: ManagedAgent) => void;
|
||||
}) {
|
||||
}: AgentInstanceEditDialogProps) {
|
||||
const updateMutation = useUpdateManagedAgentMutation();
|
||||
const startMutation = useStartManagedAgentMutation();
|
||||
const runtimesQuery = useAcpRuntimesQuery({ enabled: open });
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { EditAgentFocusTarget } from "@/features/agents/openEditAgentEvent";
|
||||
import type { ManagedAgent } from "@/shared/api/types";
|
||||
|
||||
export type AgentInstanceEditDialogProps = {
|
||||
agent: ManagedAgent;
|
||||
/** Optional field to scroll/focus when the dialog opens from a card deep-link. */
|
||||
initialFocus?: EditAgentFocusTarget;
|
||||
open: boolean;
|
||||
/** Present only when the linked definition is editable (non-built-in,
|
||||
* resolved). Caller closes this dialog and enters definition-edit. */
|
||||
onEditLinkedPersona?: () => void;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onUpdated?: (agent: ManagedAgent) => void;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export const ADVANCED_FIELDS_MOTION_TRANSITION = {
|
||||
duration: 0.18,
|
||||
ease: [0.23, 1, 0.32, 1],
|
||||
} as const;
|
||||
@@ -91,6 +91,34 @@ test("welcome readiness evaluates the runtime selected by the visible fallback",
|
||||
);
|
||||
});
|
||||
|
||||
test("welcome readiness keeps legacy Buzz Agent provider defaults", () => {
|
||||
const runtimes = [
|
||||
{
|
||||
id: "goose",
|
||||
label: "Goose",
|
||||
availability: "available",
|
||||
authStatus: { status: "not_applicable" },
|
||||
},
|
||||
{
|
||||
id: "buzz-agent",
|
||||
label: "Buzz Agent",
|
||||
availability: "available",
|
||||
authStatus: { status: "not_applicable" },
|
||||
},
|
||||
];
|
||||
const globalConfig = {
|
||||
env_vars: { OPENAI_COMPAT_API_KEY: "e2e-placeholder" },
|
||||
provider: "openai",
|
||||
model: "gpt-5.5",
|
||||
preferred_runtime: null,
|
||||
};
|
||||
|
||||
assert.deepEqual(resolveWelcomeAgentReadiness(runtimes, globalConfig, []), {
|
||||
ready: true,
|
||||
reason: "buzz-agent",
|
||||
});
|
||||
});
|
||||
|
||||
test("welcome provisioning requires an enabled available runtime", () => {
|
||||
const runtimes = [
|
||||
{
|
||||
|
||||
@@ -449,17 +449,10 @@ export type CreateManagedAgentInput = {
|
||||
relayUrl?: string;
|
||||
acpCommand?: string;
|
||||
agentCommand?: string;
|
||||
/**
|
||||
* True when `agentCommand` is a runtime command the caller deliberately wants
|
||||
* to preserve instead of inheriting the linked persona command. This covers
|
||||
* deploy-dialog runtime selections and discovered or installed aliases for the
|
||||
* same persona runtime id, while still ignoring missing-runtime fallbacks.
|
||||
*/
|
||||
/** True when `agentCommand` must remain pinned instead of inheriting the persona.
|
||||
* Covers explicit choices and installed aliases, but not missing-runtime fallbacks. */
|
||||
harnessOverride?: boolean;
|
||||
/**
|
||||
* True when `harnessOverride` pins an automatically selected runtime for a
|
||||
* runtime-less persona rather than a runtime the user explicitly selected.
|
||||
*/
|
||||
/** Whether the pinned runtime is an automatic fallback for a runtime-less persona. */
|
||||
implicitHarnessFallback?: boolean;
|
||||
agentArgs?: string[];
|
||||
mcpCommand?: string;
|
||||
|
||||
@@ -2681,7 +2681,7 @@ test("first-run onboarding posts the live Fizz kickoff", async ({ page }) => {
|
||||
page,
|
||||
{
|
||||
globalAgentConfig: {
|
||||
env_vars: { OPENAI_API_KEY: "e2e-placeholder" },
|
||||
env_vars: { OPENAI_COMPAT_API_KEY: "e2e-placeholder" },
|
||||
provider: "openai",
|
||||
model: "gpt-5.5",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user