mirror of
https://github.com/block/buzz.git
synced 2026-10-30 05:51:46 +00:00
Refactor oversized shared instruction modules
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
use crate::huddle::HuddleState;
|
||||
pub(crate) use crate::identity_storage::{IdentityStorage, RecoveryState, ResolvedIdentity};
|
||||
use crate::managed_agents::config_bridge::SessionConfigCache;
|
||||
use crate::managed_agents::{ManagedAgentPairRuntime, ManagedAgentRuntimeKey};
|
||||
use nostr::{Keys, ToBech32};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::Write,
|
||||
@@ -6,16 +11,8 @@ use std::{
|
||||
Arc, Mutex,
|
||||
},
|
||||
};
|
||||
|
||||
use nostr::{Keys, ToBech32};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::sync::Mutex as AsyncMutex;
|
||||
|
||||
use crate::huddle::HuddleState;
|
||||
pub(crate) use crate::identity_storage::{IdentityStorage, RecoveryState, ResolvedIdentity};
|
||||
use crate::managed_agents::config_bridge::SessionConfigCache;
|
||||
use crate::managed_agents::{ManagedAgentPairRuntime, ManagedAgentRuntimeKey};
|
||||
|
||||
pub struct AppState {
|
||||
pub keys: Mutex<Keys>,
|
||||
/// Durable backend holding `keys`. Updated after the key write and before
|
||||
@@ -135,7 +132,6 @@ pub struct AppState {
|
||||
pub pending_owned_channels: Mutex<std::collections::HashSet<(String, String)>>,
|
||||
pub archive_db: crate::archive::ArchiveDb,
|
||||
}
|
||||
|
||||
/// Parse the `BUZZ_PRIVATE_KEY` env var into identity keys. `Some` means the
|
||||
/// env var was present and valid and MUST win over any persisted/keyring key
|
||||
/// (the dev/CI/harness override). `None` means absent or malformed — callers
|
||||
@@ -157,7 +153,6 @@ fn identity_from_env() -> Option<Keys> {
|
||||
Err(std::env::VarError::NotPresent) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the no-redirect HTTP client used for authenticated relay media
|
||||
/// fetches (download / copy).
|
||||
///
|
||||
|
||||
724
desktop/src-tauri/src/commands/agents/agents_deploy_tests.rs
Normal file
724
desktop/src-tauri/src/commands/agents/agents_deploy_tests.rs
Normal file
@@ -0,0 +1,724 @@
|
||||
use super::*;
|
||||
use crate::managed_agents::{readiness::EffectiveHarnessDescriptor, RespondTo, TeamRecord};
|
||||
|
||||
fn record() -> ManagedAgentRecord {
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "abcd1234",
|
||||
"name": "agent-handle",
|
||||
"display_name": "Agent\u{0000} Name",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 320,
|
||||
"idle_timeout_seconds": 17,
|
||||
"max_turn_duration_seconds": 23,
|
||||
"parallelism": 4,
|
||||
"respond_to": RespondTo::OwnerOnly,
|
||||
"respond_to_allowlist": [],
|
||||
"team_id": "team-1",
|
||||
"created_at": "2026-01-01T00:00:00Z",
|
||||
"updated_at": "2026-01-01T00:00:00Z"
|
||||
}))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linked_assignments_resolve_from_live_definition() {
|
||||
let mut record = record();
|
||||
record.persona_id = Some("persona-1".into());
|
||||
record.assigned_shared_instructions = vec!["stale-a".into(), "revoked-b".into()];
|
||||
let mut persona: AgentDefinition = serde_json::from_value(serde_json::json!({
|
||||
"id": "persona-1",
|
||||
"display_name": "Persona",
|
||||
"system_prompt": "prompt",
|
||||
"name_pool": [],
|
||||
"is_builtin": false,
|
||||
"is_active": true,
|
||||
"created_at": "2026-01-01T00:00:00Z",
|
||||
"updated_at": "2026-01-01T00:00:00Z"
|
||||
}))
|
||||
.unwrap();
|
||||
persona.assigned_shared_instructions = vec!["current-a".into()];
|
||||
let personas = [persona];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&personas,
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"],
|
||||
"current-a"
|
||||
);
|
||||
assert!(
|
||||
!launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("revoked-b")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_omits_shared_instructions_when_experiment_is_disabled() {
|
||||
let mut record = record();
|
||||
record.assigned_shared_instructions = vec![format!("30023:{}:review", "a".repeat(64))];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([(
|
||||
"BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS".into(),
|
||||
"user-supplied".into(),
|
||||
)]),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: false,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
assert!(launch["env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_preserves_descriptor_and_spawn_policy() {
|
||||
let mut record = record();
|
||||
let coordinate = format!("30023:{}:review", "a".repeat(64));
|
||||
record.assigned_shared_instructions = vec![coordinate.clone()];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec!["acp".into()],
|
||||
env: BTreeMap::from([
|
||||
("GOOSE_MODE".into(), "custom".into()),
|
||||
("SECRET_FROM_PERSONA".into(), "secret".into()),
|
||||
(
|
||||
"BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS".into(),
|
||||
"user-supplied".into(),
|
||||
),
|
||||
]),
|
||||
};
|
||||
let teams: Vec<TeamRecord> = serde_json::from_value(serde_json::json!([{
|
||||
"id": "team-1", "name": "Team", "instructions": "Coordinate", "persona_ids": [], "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T00:00:00Z"
|
||||
}])).unwrap();
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&teams,
|
||||
&[],
|
||||
Some("prompt"),
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("model"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(launch["command"], "goose");
|
||||
assert_eq!(launch["args"], serde_json::json!(["acp"]));
|
||||
assert_eq!(launch["env"]["GOOSE_MODE"], "custom");
|
||||
// policy_env is applied first, so this default remains separate from
|
||||
// the descriptor value that wins in launch.env.
|
||||
assert_eq!(launch["policy_env"]["GOOSE_MODE"], "auto");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_LAZY_POOL"], "true");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_RELAY_OBSERVER"], "true");
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_TEAM_INSTRUCTIONS"],
|
||||
"Coordinate"
|
||||
);
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"],
|
||||
coordinate
|
||||
);
|
||||
assert!(launch["env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_SESSION_TITLE"], "Agent Name");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_DISPLAY_NAME"], "Agent Name");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_SYSTEM_PROMPT"], "prompt");
|
||||
// goose runtime: model goes via BUZZ_ACP_MODEL (non-claude path).
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MODEL"], "model");
|
||||
assert!(
|
||||
launch["policy_env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"goose must NOT receive ANTHROPIC_MODEL"
|
||||
);
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_IDLE_TIMEOUT"], "17");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MAX_TURN_DURATION"], "23");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_AGENTS"], "4");
|
||||
assert_eq!(launch["owner_pubkey"], "owner-hex");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_claude_runtime_uses_anthropic_model_not_buzz_acp_model() {
|
||||
// B2: remote claude deploys must send ANTHROPIC_MODEL, not BUZZ_ACP_MODEL,
|
||||
// so the remote harness has a single startup model authority matching A1.
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let teams: Vec<TeamRecord> = vec![];
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&teams,
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("claude-opus-4"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
launch["policy_env"]["ANTHROPIC_MODEL"], "claude-opus-4",
|
||||
"claude remote must receive ANTHROPIC_MODEL"
|
||||
);
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"claude remote must NOT receive BUZZ_ACP_MODEL"
|
||||
);
|
||||
}
|
||||
|
||||
/// F2: remote Claude launch must mirror local A1 — ALWAYS strip BOTH
|
||||
/// BUZZ_ACP_MODEL and ANTHROPIC_MODEL from launch.env (tier 2), so the
|
||||
/// canonical model in policy_env (tier 1) is the sole authority. Since
|
||||
/// launch.env later-wins over policy_env, a user BUZZ_ACP_MODEL would add a
|
||||
/// second startup authority and a user ANTHROPIC_MODEL would silently
|
||||
/// override the canonical model.
|
||||
#[test]
|
||||
fn launch_block_claude_strips_both_model_keys_from_launch_env() {
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([
|
||||
("BUZZ_ACP_MODEL".to_string(), "user-sonnet".to_string()),
|
||||
("ANTHROPIC_MODEL".to_string(), "user-opus".to_string()),
|
||||
("KEEP_ME".to_string(), "yes".to_string()),
|
||||
]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("claude-opus-4"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Canonical model rides policy_env alone.
|
||||
assert_eq!(launch["policy_env"]["ANTHROPIC_MODEL"], "claude-opus-4");
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_MODEL"].is_null());
|
||||
// Both model keys are stripped from launch.env — neither can later-win.
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"user BUZZ_ACP_MODEL must be stripped from launch.env for claude"
|
||||
);
|
||||
assert!(
|
||||
launch["env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"user ANTHROPIC_MODEL must be stripped from launch.env for claude"
|
||||
);
|
||||
// Unrelated user env survives.
|
||||
assert_eq!(launch["env"]["KEEP_ME"], "yes");
|
||||
}
|
||||
|
||||
/// F2: when no canonical model resolves, a Claude launch still strips both
|
||||
/// model keys from launch.env, so neither authority reaches the remote
|
||||
/// process — matching local `apply_claude_model_env(None)`, which removes
|
||||
/// both.
|
||||
#[test]
|
||||
fn launch_block_claude_strips_model_keys_even_without_canonical() {
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([
|
||||
("BUZZ_ACP_MODEL".to_string(), "user-sonnet".to_string()),
|
||||
("ANTHROPIC_MODEL".to_string(), "user-opus".to_string()),
|
||||
]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(launch["policy_env"]["ANTHROPIC_MODEL"].is_null());
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_MODEL"].is_null());
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"user BUZZ_ACP_MODEL must be stripped even without a canonical model"
|
||||
);
|
||||
assert!(
|
||||
launch["env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"user ANTHROPIC_MODEL must be stripped even without a canonical model"
|
||||
);
|
||||
}
|
||||
|
||||
/// F2: non-Claude runtimes must NOT strip model keys from launch.env — the
|
||||
/// model authority stripping is Claude-specific (BUZZ_ACP_MODEL is the
|
||||
/// spawn authority for other runtimes and rides policy_env there).
|
||||
#[test]
|
||||
fn launch_block_non_claude_preserves_user_model_env() {
|
||||
let record = record(); // goose command
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([("BUZZ_ACP_MODEL".to_string(), "user-model".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("model"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// goose puts canonical in policy_env, and the user launch.env value is
|
||||
// preserved (later-wins is the intended goose behavior).
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MODEL"], "model");
|
||||
assert_eq!(launch["env"]["BUZZ_ACP_MODEL"], "user-model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_claude_runtime_injects_effort_level_when_set() {
|
||||
// I-4: remote parity — record.effort_level → BUZZ_ACP_EFFORT_LEVEL in policy_env.
|
||||
let mut record = record();
|
||||
record.effort_level = Some("high".to_string());
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"], "high",
|
||||
"claude remote must receive BUZZ_ACP_EFFORT_LEVEL when effort_level is set"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_does_not_inject_effort_level_when_absent() {
|
||||
// I-4: no BUZZ_ACP_EFFORT_LEVEL in policy_env when record.effort_level is None.
|
||||
let record = record(); // effort_level is None by default
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"policy_env must NOT contain BUZZ_ACP_EFFORT_LEVEL when effort_level is None"
|
||||
);
|
||||
}
|
||||
|
||||
/// B5 remote parity: when a canonical effort_level is persisted, a conflicting
|
||||
/// user-supplied BUZZ_ACP_EFFORT_LEVEL in descriptor.env must NOT shadow it.
|
||||
/// The canonical value in policy_env (tier 1) must win in the final build_env
|
||||
/// output — the key must be absent from launch.env (tier 2) so tier 1 is
|
||||
/// authoritative.
|
||||
#[test]
|
||||
fn launch_block_canonical_effort_strips_user_env_collision() {
|
||||
let mut record = record();
|
||||
record.effort_level = Some("high".to_string());
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
// User-supplied conflicting value in descriptor.env.
|
||||
env: BTreeMap::from([("BUZZ_ACP_EFFORT_LEVEL".to_string(), "low".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Canonical must be in policy_env (tier 1).
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"], "high",
|
||||
"canonical effort must be in policy_env when record.effort_level is Some"
|
||||
);
|
||||
// Conflicting user value must be absent from launch.env (tier 2) so it
|
||||
// cannot shadow the canonical tier-1 value in build_env.
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"user BUZZ_ACP_EFFORT_LEVEL must be stripped from launch.env when canonical is present"
|
||||
);
|
||||
}
|
||||
|
||||
/// B5 remote parity: when no canonical effort is persisted (effort_level is
|
||||
/// None), a user-supplied BUZZ_ACP_EFFORT_LEVEL in descriptor.env survives
|
||||
/// into launch.env — passthrough preserved for startup seeding.
|
||||
#[test]
|
||||
fn launch_block_user_effort_env_survives_when_no_canonical_value() {
|
||||
let record = record(); // effort_level is None
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([("BUZZ_ACP_EFFORT_LEVEL".to_string(), "low".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// No canonical — key must NOT appear in policy_env.
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"policy_env must NOT contain BUZZ_ACP_EFFORT_LEVEL when effort_level is None"
|
||||
);
|
||||
// User value must survive in launch.env so the harness can use it.
|
||||
assert_eq!(
|
||||
launch["env"]["BUZZ_ACP_EFFORT_LEVEL"], "low",
|
||||
"user-supplied effort must survive in launch.env when no canonical value"
|
||||
);
|
||||
}
|
||||
|
||||
/// OpenClaw descriptor: `launch.policy_env["BUZZ_ACP_AGENTS"]` must be "5"
|
||||
/// even when the record's requested parallelism is 10. This is the direct
|
||||
/// `launch.policy_env` seam test — the executable contract for remote providers.
|
||||
#[test]
|
||||
fn launch_block_openclaw_over_cap_policy_env_is_capped() {
|
||||
let mut record = record();
|
||||
record.agent_command = "openclaw".into();
|
||||
record.parallelism = 10; // above the OpenClaw spawn-time cap
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be capped at {} for OpenClaw, not 10",
|
||||
crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM
|
||||
);
|
||||
}
|
||||
|
||||
/// Uncapped harness (goose): `launch.policy_env["BUZZ_ACP_AGENTS"]` passes
|
||||
/// the requested value through unchanged.
|
||||
#[test]
|
||||
fn launch_block_goose_policy_env_is_not_capped() {
|
||||
let mut record = record();
|
||||
record.parallelism = 8;
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"], "8",
|
||||
"goose: policy_env[BUZZ_ACP_AGENTS] must pass through requested value 8"
|
||||
);
|
||||
}
|
||||
|
||||
/// deploy_payload_json: legacy top-level `parallelism` is the effective value
|
||||
/// derived from the descriptor, not `record.agent_command`.
|
||||
///
|
||||
/// Stale-persona scenario: `record.agent_command` is "goose" (created before
|
||||
/// the user switched the persona to OpenClaw), but the live descriptor resolves
|
||||
/// OpenClaw. Both `launch.policy_env["BUZZ_ACP_AGENTS"]` and the legacy
|
||||
/// top-level `parallelism` must be the effective OpenClaw value (5), not the
|
||||
/// record's stale Goose identity (requested 10).
|
||||
#[test]
|
||||
fn deploy_payload_json_stale_goose_record_live_openclaw_descriptor_both_capped() {
|
||||
let mut record = record();
|
||||
// Stale agent_command from record creation — persona has since switched to OpenClaw.
|
||||
record.agent_command = "goose".into();
|
||||
record.parallelism = 10;
|
||||
// Resolved descriptor reflects the live persona (OpenClaw).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let cap = crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM;
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
cap.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be capped at {cap} for live OpenClaw descriptor"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], cap,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be {cap}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Inverse stale-persona scenario: `record.agent_command` is "openclaw"
|
||||
/// (created before the user switched the persona to Goose), but the live
|
||||
/// descriptor resolves Goose. Both projections must be the uncapped requested
|
||||
/// value (4), not the old OpenClaw cap.
|
||||
#[test]
|
||||
fn deploy_payload_json_stale_openclaw_record_live_goose_descriptor_both_uncapped() {
|
||||
let mut record = record();
|
||||
// Stale agent_command from record creation — persona has since switched to Goose.
|
||||
record.agent_command = "openclaw".into();
|
||||
record.parallelism = 4;
|
||||
// Resolved descriptor reflects the live persona (Goose).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
"4",
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must pass through requested 4 for live Goose descriptor"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], 4,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be 4 (uncapped)"
|
||||
);
|
||||
}
|
||||
|
||||
/// Explicit agent_command_override direction: record has an explicit override
|
||||
/// pinning OpenClaw while the persona default is Goose. The override wins
|
||||
/// via the descriptor — both projections must be capped at the OpenClaw limit.
|
||||
#[test]
|
||||
fn deploy_payload_json_explicit_openclaw_override_both_capped() {
|
||||
let mut record = record();
|
||||
// Explicit override: user pinned OpenClaw on this agent.
|
||||
record.agent_command_override = Some("openclaw".into());
|
||||
record.agent_command = "goose".into(); // persona default, overridden
|
||||
record.parallelism = 10;
|
||||
// Descriptor reflects the resolved override (OpenClaw wins).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let cap = crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM;
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
cap.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be {cap} for explicit OpenClaw override"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], cap,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be {cap}"
|
||||
);
|
||||
}
|
||||
@@ -307,729 +307,5 @@ pub(super) fn deploy_payload_json(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::managed_agents::{readiness::EffectiveHarnessDescriptor, RespondTo, TeamRecord};
|
||||
|
||||
fn record() -> ManagedAgentRecord {
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "abcd1234",
|
||||
"name": "agent-handle",
|
||||
"display_name": "Agent\u{0000} Name",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 320,
|
||||
"idle_timeout_seconds": 17,
|
||||
"max_turn_duration_seconds": 23,
|
||||
"parallelism": 4,
|
||||
"respond_to": RespondTo::OwnerOnly,
|
||||
"respond_to_allowlist": [],
|
||||
"team_id": "team-1",
|
||||
"created_at": "2026-01-01T00:00:00Z",
|
||||
"updated_at": "2026-01-01T00:00:00Z"
|
||||
}))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linked_assignments_resolve_from_live_definition() {
|
||||
let mut record = record();
|
||||
record.persona_id = Some("persona-1".into());
|
||||
record.assigned_shared_instructions = vec!["stale-a".into(), "revoked-b".into()];
|
||||
let mut persona: AgentDefinition = serde_json::from_value(serde_json::json!({
|
||||
"id": "persona-1",
|
||||
"display_name": "Persona",
|
||||
"system_prompt": "prompt",
|
||||
"name_pool": [],
|
||||
"is_builtin": false,
|
||||
"is_active": true,
|
||||
"created_at": "2026-01-01T00:00:00Z",
|
||||
"updated_at": "2026-01-01T00:00:00Z"
|
||||
}))
|
||||
.unwrap();
|
||||
persona.assigned_shared_instructions = vec!["current-a".into()];
|
||||
let personas = [persona];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&personas,
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"],
|
||||
"current-a"
|
||||
);
|
||||
assert!(
|
||||
!launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("revoked-b")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_omits_shared_instructions_when_experiment_is_disabled() {
|
||||
let mut record = record();
|
||||
record.assigned_shared_instructions = vec![format!("30023:{}:review", "a".repeat(64))];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([(
|
||||
"BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS".into(),
|
||||
"user-supplied".into(),
|
||||
)]),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: false,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
assert!(launch["env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_preserves_descriptor_and_spawn_policy() {
|
||||
let mut record = record();
|
||||
let coordinate = format!("30023:{}:review", "a".repeat(64));
|
||||
record.assigned_shared_instructions = vec![coordinate.clone()];
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec!["acp".into()],
|
||||
env: BTreeMap::from([
|
||||
("GOOSE_MODE".into(), "custom".into()),
|
||||
("SECRET_FROM_PERSONA".into(), "secret".into()),
|
||||
(
|
||||
"BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS".into(),
|
||||
"user-supplied".into(),
|
||||
),
|
||||
]),
|
||||
};
|
||||
let teams: Vec<TeamRecord> = serde_json::from_value(serde_json::json!([{
|
||||
"id": "team-1", "name": "Team", "instructions": "Coordinate", "persona_ids": [], "created_at": "2026-01-01T00:00:00Z", "updated_at": "2026-01-01T00:00:00Z"
|
||||
}])).unwrap();
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&teams,
|
||||
&[],
|
||||
Some("prompt"),
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("model"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(launch["command"], "goose");
|
||||
assert_eq!(launch["args"], serde_json::json!(["acp"]));
|
||||
assert_eq!(launch["env"]["GOOSE_MODE"], "custom");
|
||||
// policy_env is applied first, so this default remains separate from
|
||||
// the descriptor value that wins in launch.env.
|
||||
assert_eq!(launch["policy_env"]["GOOSE_MODE"], "auto");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_LAZY_POOL"], "true");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_RELAY_OBSERVER"], "true");
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_TEAM_INSTRUCTIONS"],
|
||||
"Coordinate"
|
||||
);
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"],
|
||||
coordinate
|
||||
);
|
||||
assert!(launch["env"]["BUZZ_ACP_ASSIGNED_SHARED_INSTRUCTIONS"].is_null());
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_SESSION_TITLE"], "Agent Name");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_DISPLAY_NAME"], "Agent Name");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_SYSTEM_PROMPT"], "prompt");
|
||||
// goose runtime: model goes via BUZZ_ACP_MODEL (non-claude path).
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MODEL"], "model");
|
||||
assert!(
|
||||
launch["policy_env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"goose must NOT receive ANTHROPIC_MODEL"
|
||||
);
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_IDLE_TIMEOUT"], "17");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MAX_TURN_DURATION"], "23");
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_AGENTS"], "4");
|
||||
assert_eq!(launch["owner_pubkey"], "owner-hex");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_claude_runtime_uses_anthropic_model_not_buzz_acp_model() {
|
||||
// B2: remote claude deploys must send ANTHROPIC_MODEL, not BUZZ_ACP_MODEL,
|
||||
// so the remote harness has a single startup model authority matching A1.
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let teams: Vec<TeamRecord> = vec![];
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&teams,
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("claude-opus-4"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
launch["policy_env"]["ANTHROPIC_MODEL"], "claude-opus-4",
|
||||
"claude remote must receive ANTHROPIC_MODEL"
|
||||
);
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"claude remote must NOT receive BUZZ_ACP_MODEL"
|
||||
);
|
||||
}
|
||||
|
||||
/// F2: remote Claude launch must mirror local A1 — ALWAYS strip BOTH
|
||||
/// BUZZ_ACP_MODEL and ANTHROPIC_MODEL from launch.env (tier 2), so the
|
||||
/// canonical model in policy_env (tier 1) is the sole authority. Since
|
||||
/// launch.env later-wins over policy_env, a user BUZZ_ACP_MODEL would add a
|
||||
/// second startup authority and a user ANTHROPIC_MODEL would silently
|
||||
/// override the canonical model.
|
||||
#[test]
|
||||
fn launch_block_claude_strips_both_model_keys_from_launch_env() {
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([
|
||||
("BUZZ_ACP_MODEL".to_string(), "user-sonnet".to_string()),
|
||||
("ANTHROPIC_MODEL".to_string(), "user-opus".to_string()),
|
||||
("KEEP_ME".to_string(), "yes".to_string()),
|
||||
]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("claude-opus-4"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Canonical model rides policy_env alone.
|
||||
assert_eq!(launch["policy_env"]["ANTHROPIC_MODEL"], "claude-opus-4");
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_MODEL"].is_null());
|
||||
// Both model keys are stripped from launch.env — neither can later-win.
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"user BUZZ_ACP_MODEL must be stripped from launch.env for claude"
|
||||
);
|
||||
assert!(
|
||||
launch["env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"user ANTHROPIC_MODEL must be stripped from launch.env for claude"
|
||||
);
|
||||
// Unrelated user env survives.
|
||||
assert_eq!(launch["env"]["KEEP_ME"], "yes");
|
||||
}
|
||||
|
||||
/// F2: when no canonical model resolves, a Claude launch still strips both
|
||||
/// model keys from launch.env, so neither authority reaches the remote
|
||||
/// process — matching local `apply_claude_model_env(None)`, which removes
|
||||
/// both.
|
||||
#[test]
|
||||
fn launch_block_claude_strips_model_keys_even_without_canonical() {
|
||||
let record = record();
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([
|
||||
("BUZZ_ACP_MODEL".to_string(), "user-sonnet".to_string()),
|
||||
("ANTHROPIC_MODEL".to_string(), "user-opus".to_string()),
|
||||
]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(launch["policy_env"]["ANTHROPIC_MODEL"].is_null());
|
||||
assert!(launch["policy_env"]["BUZZ_ACP_MODEL"].is_null());
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_MODEL"].is_null(),
|
||||
"user BUZZ_ACP_MODEL must be stripped even without a canonical model"
|
||||
);
|
||||
assert!(
|
||||
launch["env"]["ANTHROPIC_MODEL"].is_null(),
|
||||
"user ANTHROPIC_MODEL must be stripped even without a canonical model"
|
||||
);
|
||||
}
|
||||
|
||||
/// F2: non-Claude runtimes must NOT strip model keys from launch.env — the
|
||||
/// model authority stripping is Claude-specific (BUZZ_ACP_MODEL is the
|
||||
/// spawn authority for other runtimes and rides policy_env there).
|
||||
#[test]
|
||||
fn launch_block_non_claude_preserves_user_model_env() {
|
||||
let record = record(); // goose command
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([("BUZZ_ACP_MODEL".to_string(), "user-model".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: Some("model"),
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// goose puts canonical in policy_env, and the user launch.env value is
|
||||
// preserved (later-wins is the intended goose behavior).
|
||||
assert_eq!(launch["policy_env"]["BUZZ_ACP_MODEL"], "model");
|
||||
assert_eq!(launch["env"]["BUZZ_ACP_MODEL"], "user-model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_claude_runtime_injects_effort_level_when_set() {
|
||||
// I-4: remote parity — record.effort_level → BUZZ_ACP_EFFORT_LEVEL in policy_env.
|
||||
let mut record = record();
|
||||
record.effort_level = Some("high".to_string());
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"], "high",
|
||||
"claude remote must receive BUZZ_ACP_EFFORT_LEVEL when effort_level is set"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launch_block_does_not_inject_effort_level_when_absent() {
|
||||
// I-4: no BUZZ_ACP_EFFORT_LEVEL in policy_env when record.effort_level is None.
|
||||
let record = record(); // effort_level is None by default
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"policy_env must NOT contain BUZZ_ACP_EFFORT_LEVEL when effort_level is None"
|
||||
);
|
||||
}
|
||||
|
||||
/// B5 remote parity: when a canonical effort_level is persisted, a conflicting
|
||||
/// user-supplied BUZZ_ACP_EFFORT_LEVEL in descriptor.env must NOT shadow it.
|
||||
/// The canonical value in policy_env (tier 1) must win in the final build_env
|
||||
/// output — the key must be absent from launch.env (tier 2) so tier 1 is
|
||||
/// authoritative.
|
||||
#[test]
|
||||
fn launch_block_canonical_effort_strips_user_env_collision() {
|
||||
let mut record = record();
|
||||
record.effort_level = Some("high".to_string());
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
// User-supplied conflicting value in descriptor.env.
|
||||
env: BTreeMap::from([("BUZZ_ACP_EFFORT_LEVEL".to_string(), "low".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Canonical must be in policy_env (tier 1).
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"], "high",
|
||||
"canonical effort must be in policy_env when record.effort_level is Some"
|
||||
);
|
||||
// Conflicting user value must be absent from launch.env (tier 2) so it
|
||||
// cannot shadow the canonical tier-1 value in build_env.
|
||||
assert!(
|
||||
launch["env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"user BUZZ_ACP_EFFORT_LEVEL must be stripped from launch.env when canonical is present"
|
||||
);
|
||||
}
|
||||
|
||||
/// B5 remote parity: when no canonical effort is persisted (effort_level is
|
||||
/// None), a user-supplied BUZZ_ACP_EFFORT_LEVEL in descriptor.env survives
|
||||
/// into launch.env — passthrough preserved for startup seeding.
|
||||
#[test]
|
||||
fn launch_block_user_effort_env_survives_when_no_canonical_value() {
|
||||
let record = record(); // effort_level is None
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "claude".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::from([("BUZZ_ACP_EFFORT_LEVEL".to_string(), "low".to_string())]),
|
||||
};
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// No canonical — key must NOT appear in policy_env.
|
||||
assert!(
|
||||
launch["policy_env"]["BUZZ_ACP_EFFORT_LEVEL"].is_null(),
|
||||
"policy_env must NOT contain BUZZ_ACP_EFFORT_LEVEL when effort_level is None"
|
||||
);
|
||||
// User value must survive in launch.env so the harness can use it.
|
||||
assert_eq!(
|
||||
launch["env"]["BUZZ_ACP_EFFORT_LEVEL"], "low",
|
||||
"user-supplied effort must survive in launch.env when no canonical value"
|
||||
);
|
||||
}
|
||||
|
||||
/// OpenClaw descriptor: `launch.policy_env["BUZZ_ACP_AGENTS"]` must be "5"
|
||||
/// even when the record's requested parallelism is 10. This is the direct
|
||||
/// `launch.policy_env` seam test — the executable contract for remote providers.
|
||||
#[test]
|
||||
fn launch_block_openclaw_over_cap_policy_env_is_capped() {
|
||||
let mut record = record();
|
||||
record.agent_command = "openclaw".into();
|
||||
record.parallelism = 10; // above the OpenClaw spawn-time cap
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be capped at {} for OpenClaw, not 10",
|
||||
crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM
|
||||
);
|
||||
}
|
||||
|
||||
/// Uncapped harness (goose): `launch.policy_env["BUZZ_ACP_AGENTS"]` passes
|
||||
/// the requested value through unchanged.
|
||||
#[test]
|
||||
fn launch_block_goose_policy_env_is_not_capped() {
|
||||
let mut record = record();
|
||||
record.parallelism = 8;
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"], "8",
|
||||
"goose: policy_env[BUZZ_ACP_AGENTS] must pass through requested value 8"
|
||||
);
|
||||
}
|
||||
|
||||
/// deploy_payload_json: legacy top-level `parallelism` is the effective value
|
||||
/// derived from the descriptor, not `record.agent_command`.
|
||||
///
|
||||
/// Stale-persona scenario: `record.agent_command` is "goose" (created before
|
||||
/// the user switched the persona to OpenClaw), but the live descriptor resolves
|
||||
/// OpenClaw. Both `launch.policy_env["BUZZ_ACP_AGENTS"]` and the legacy
|
||||
/// top-level `parallelism` must be the effective OpenClaw value (5), not the
|
||||
/// record's stale Goose identity (requested 10).
|
||||
#[test]
|
||||
fn deploy_payload_json_stale_goose_record_live_openclaw_descriptor_both_capped() {
|
||||
let mut record = record();
|
||||
// Stale agent_command from record creation — persona has since switched to OpenClaw.
|
||||
record.agent_command = "goose".into();
|
||||
record.parallelism = 10;
|
||||
// Resolved descriptor reflects the live persona (OpenClaw).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let cap = crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM;
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
cap.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be capped at {cap} for live OpenClaw descriptor"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], cap,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be {cap}"
|
||||
);
|
||||
}
|
||||
|
||||
/// Inverse stale-persona scenario: `record.agent_command` is "openclaw"
|
||||
/// (created before the user switched the persona to Goose), but the live
|
||||
/// descriptor resolves Goose. Both projections must be the uncapped requested
|
||||
/// value (4), not the old OpenClaw cap.
|
||||
#[test]
|
||||
fn deploy_payload_json_stale_openclaw_record_live_goose_descriptor_both_uncapped() {
|
||||
let mut record = record();
|
||||
// Stale agent_command from record creation — persona has since switched to Goose.
|
||||
record.agent_command = "openclaw".into();
|
||||
record.parallelism = 4;
|
||||
// Resolved descriptor reflects the live persona (Goose).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "goose".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
"4",
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must pass through requested 4 for live Goose descriptor"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], 4,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be 4 (uncapped)"
|
||||
);
|
||||
}
|
||||
|
||||
/// Explicit agent_command_override direction: record has an explicit override
|
||||
/// pinning OpenClaw while the persona default is Goose. The override wins
|
||||
/// via the descriptor — both projections must be capped at the OpenClaw limit.
|
||||
#[test]
|
||||
fn deploy_payload_json_explicit_openclaw_override_both_capped() {
|
||||
let mut record = record();
|
||||
// Explicit override: user pinned OpenClaw on this agent.
|
||||
record.agent_command_override = Some("openclaw".into());
|
||||
record.agent_command = "goose".into(); // persona default, overridden
|
||||
record.parallelism = 10;
|
||||
// Descriptor reflects the resolved override (OpenClaw wins).
|
||||
let descriptor = EffectiveHarnessDescriptor {
|
||||
command: "openclaw".into(),
|
||||
args: vec![],
|
||||
env: BTreeMap::new(),
|
||||
};
|
||||
let cap = crate::managed_agents::parallelism::OPENCLAW_MAX_PARALLELISM;
|
||||
|
||||
let launch = build_launch_block(
|
||||
&record,
|
||||
&descriptor,
|
||||
&[],
|
||||
&[],
|
||||
None,
|
||||
LaunchExperimentContext {
|
||||
effective_model: None,
|
||||
|
||||
shared_instructions_enabled: true,
|
||||
},
|
||||
"owner-hex",
|
||||
)
|
||||
.unwrap();
|
||||
let effective_parallelism =
|
||||
crate::managed_agents::effective_parallelism(&descriptor.command, record.parallelism);
|
||||
let payload = deploy_payload_json(
|
||||
&record,
|
||||
"wss://relay.example".to_string(),
|
||||
DeployProjections {
|
||||
effective_model: None,
|
||||
effective_provider: None,
|
||||
effective_prompt: None,
|
||||
effective_parallelism,
|
||||
owner_only_access: false,
|
||||
},
|
||||
BTreeMap::new(),
|
||||
launch.clone(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
launch["policy_env"]["BUZZ_ACP_AGENTS"],
|
||||
cap.to_string(),
|
||||
"launch.policy_env[BUZZ_ACP_AGENTS] must be {cap} for explicit OpenClaw override"
|
||||
);
|
||||
assert_eq!(
|
||||
payload["parallelism"], cap,
|
||||
"legacy top-level parallelism must match launch.policy_env — both must be {cap}"
|
||||
);
|
||||
}
|
||||
}
|
||||
#[path = "agents/agents_deploy_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
use super::agent_env::{build_buzz_agent_provider_defaults, idle_pool_sleep_env};
|
||||
|
||||
use super::claude_config::{apply_claude_model_env, apply_effort_env};
|
||||
use super::shared_instructions::resolve_and_apply_assigned_shared_instructions_env;
|
||||
use crate::{
|
||||
managed_agents::{
|
||||
append_log_marker, known_acp_runtime, login_shell_path, managed_agent_log_path,
|
||||
@@ -13,28 +10,22 @@ use crate::{
|
||||
},
|
||||
util::now_iso,
|
||||
};
|
||||
|
||||
use super::claude_config::{apply_claude_model_env, apply_effort_env};
|
||||
use super::shared_instructions::resolve_and_apply_assigned_shared_instructions_env;
|
||||
use std::collections::HashMap;
|
||||
use tauri::{AppHandle, Manager};
|
||||
mod path;
|
||||
pub(crate) use super::access_policy::{build_respond_to_env_with_policy, RespondToEnv};
|
||||
pub(in crate::managed_agents) use path::build_augmented_path;
|
||||
pub(crate) use path::{compose_path_entries, should_skip_claude_executable, should_use_inherited};
|
||||
|
||||
pub(crate) use super::access_policy::{build_respond_to_env_with_policy, RespondToEnv};
|
||||
|
||||
mod metadata;
|
||||
pub(crate) use metadata::{
|
||||
apply_agent_display_env, resolve_session_title, runtime_metadata_env_vars,
|
||||
DISPLAY_NAME_ENV_VAR, SESSION_TITLE_ENV_VAR,
|
||||
};
|
||||
|
||||
mod stop;
|
||||
pub(crate) use stop::managed_agent_runtime_keys;
|
||||
pub use stop::{stop_managed_agent_process, stop_managed_agent_workspace_pair};
|
||||
|
||||
mod sweep;
|
||||
pub(crate) use sweep::sweep_untracked_bundle_harnesses;
|
||||
|
||||
mod process;
|
||||
#[cfg(test)]
|
||||
use process::{
|
||||
@@ -45,7 +36,6 @@ pub(crate) use process::{
|
||||
current_instance_id, process_belongs_to_us, process_has_buzz_marker, process_is_running,
|
||||
terminate_process, terminate_untracked_pair_runtime, valid_agent_runtime_receipt,
|
||||
};
|
||||
|
||||
mod orphan_sweep;
|
||||
#[cfg(target_os = "macos")]
|
||||
use orphan_sweep::proc_pidinfo;
|
||||
@@ -57,7 +47,6 @@ pub(crate) use orphan_sweep::{
|
||||
use orphan_sweep::{BSDInfo, PROC_PIDTBSDINFO};
|
||||
#[cfg(unix)]
|
||||
use process::resolve_pgids_and_kill;
|
||||
|
||||
mod instance_reaper;
|
||||
pub(crate) use instance_reaper::reap_dead_instance_agents;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::managed_agents::known_acp_runtime;
|
||||
|
||||
#[path = "cli_tests.rs"]
|
||||
mod cli_tests;
|
||||
|
||||
|
||||
@@ -697,316 +697,4 @@ fn exact_single_tag_value<'a>(event: &'a Event, name: &str) -> Option<&'a str> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nostr::{EventBuilder, Tag, Timestamp};
|
||||
|
||||
fn note(keys: &Keys, slug: &str, content: &str, created_at: u64) -> Event {
|
||||
EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), content)
|
||||
.tags([
|
||||
Tag::parse(["d", slug]).unwrap(),
|
||||
Tag::parse(["title", &format!("Title {slug}")]).unwrap(),
|
||||
Tag::parse(["summary", &format!("Summary {slug}")]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(created_at))
|
||||
.sign_with_keys(keys)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assigned_shared_instruction_env_is_canonical() {
|
||||
let coordinate = format!("30023:{}:review", "a".repeat(64));
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
command.env(ASSIGNED_SHARED_INSTRUCTIONS_ENV, "user-supplied");
|
||||
apply_assigned_shared_instructions_env(&mut command, std::slice::from_ref(&coordinate));
|
||||
let env = command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.and_then(|(_, value)| value)
|
||||
.and_then(|value| value.to_str());
|
||||
assert_eq!(env, Some(coordinate.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_assigned_shared_instruction_env_uses_live_definition() {
|
||||
let stale = format!("30023:{}:revoked", "a".repeat(64));
|
||||
let current = format!("30023:{}:kept", "b".repeat(64));
|
||||
let record: super::super::ManagedAgentRecord = serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "agent",
|
||||
"name": "agent",
|
||||
"persona_id": "persona",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 300,
|
||||
"parallelism": 1,
|
||||
"assigned_shared_instructions": [stale.clone()],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let definition: super::super::AgentDefinition = serde_json::from_value(serde_json::json!({
|
||||
"id": "persona",
|
||||
"display_name": "Persona",
|
||||
"system_prompt": "prompt",
|
||||
"name_pool": [],
|
||||
"is_builtin": false,
|
||||
"is_active": true,
|
||||
"assigned_shared_instructions": [current.clone()],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
|
||||
let definitions = [definition];
|
||||
let assigned = resolve_and_apply_assigned_shared_instructions_env(
|
||||
&mut command,
|
||||
&record,
|
||||
&definitions,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(assigned, definitions[0].assigned_shared_instructions);
|
||||
|
||||
let env = command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.and_then(|(_, value)| value)
|
||||
.and_then(|value| value.to_str());
|
||||
assert_eq!(env, Some(current.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_shared_instructions_remove_env_and_effective_assignment() {
|
||||
let coordinate = format!("30023:{}:kept", "a".repeat(64));
|
||||
let record: super::super::ManagedAgentRecord = serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "agent",
|
||||
"name": "agent",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 300,
|
||||
"parallelism": 1,
|
||||
"assigned_shared_instructions": [coordinate],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
command.env(ASSIGNED_SHARED_INSTRUCTIONS_ENV, "user-supplied");
|
||||
|
||||
let assigned =
|
||||
resolve_and_apply_assigned_shared_instructions_env(&mut command, &record, &[], false)
|
||||
.unwrap();
|
||||
|
||||
assert!(assigned.is_empty());
|
||||
assert!(command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.is_some_and(|(_, value)| value.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_exact_coordinate_and_deduplicates() {
|
||||
let key = "a".repeat(64);
|
||||
let coordinate = format!("30023:{key}:design-engineering");
|
||||
assert_eq!(
|
||||
validate_assigned_shared_instructions(vec![coordinate.clone(), coordinate.clone()])
|
||||
.unwrap(),
|
||||
vec![coordinate]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_noncanonical_coordinates() {
|
||||
let key = "a".repeat(64);
|
||||
for invalid in [
|
||||
"design-engineering".to_string(),
|
||||
format!("30175:{key}:design-engineering"),
|
||||
format!("30023:{key}:design\nengineering"),
|
||||
format!("30023:{key}:Design-Engineering"),
|
||||
format!("30023:{key}:design/engineering"),
|
||||
format!("30023:{}:design-engineering", "A".repeat(64)),
|
||||
"30023:npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp3d0u5:design-engineering".to_string(),
|
||||
] {
|
||||
assert!(
|
||||
parse_shared_instruction_coordinate(&invalid).is_err(),
|
||||
"{invalid:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn projects_mine_only_latest_heads_with_explicit_compatibility() {
|
||||
let owner = Keys::generate();
|
||||
let stranger = Keys::generate();
|
||||
let old = note(&owner, "design-engineering", "old body", 10);
|
||||
let current = note(&owner, "design-engineering", "current body", 20);
|
||||
let invalid_name = note(&owner, "Design_skill", "body", 30);
|
||||
let missing_summary = EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), "body")
|
||||
.tags([
|
||||
Tag::parse(["d", "missing-summary"]).unwrap(),
|
||||
Tag::parse(["title", "Missing summary"]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(40))
|
||||
.sign_with_keys(&owner)
|
||||
.unwrap();
|
||||
let foreign = note(&stranger, "foreign", "body", 50);
|
||||
|
||||
let covers = shared_instruction_covers_from_events(
|
||||
&owner.public_key().to_hex(),
|
||||
vec![old, current, invalid_name, missing_summary, foreign],
|
||||
);
|
||||
|
||||
assert_eq!(covers.len(), 3);
|
||||
assert_eq!(covers[0].slug, "missing-summary");
|
||||
assert!(!covers[0].compatible);
|
||||
assert_eq!(
|
||||
covers[0].incompatibilities[0].code,
|
||||
SharedInstructionIncompatibilityCode::MissingDescription
|
||||
);
|
||||
assert_eq!(covers[1].slug, "Design_skill");
|
||||
assert!(!covers[1].compatible);
|
||||
assert_eq!(
|
||||
covers[1].incompatibilities[0].code,
|
||||
SharedInstructionIncompatibilityCode::InvalidName
|
||||
);
|
||||
assert_eq!(covers[2].slug, "design-engineering");
|
||||
assert!(covers[2].compatible);
|
||||
assert!(covers[2].incompatibilities.is_empty());
|
||||
assert_eq!(covers[2].updated_at, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validation_rejects_instruction_name_edge_cases_and_empty_body() {
|
||||
for slug in ["", "-skill", "skill-", "two--hyphens", "with_underscore"] {
|
||||
let reasons =
|
||||
shared_instruction_incompatibilities(slug, Some("Useful summary"), "body");
|
||||
assert!(reasons
|
||||
.iter()
|
||||
.any(|reason| reason.code == SharedInstructionIncompatibilityCode::InvalidName));
|
||||
}
|
||||
let reasons = shared_instruction_incompatibilities("valid-name", Some("summary"), "\n");
|
||||
assert_eq!(
|
||||
reasons[0].code,
|
||||
SharedInstructionIncompatibilityCode::EmptyBody
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_query_filters_do_not_admit_author_slug_cross_products() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let coordinates = [
|
||||
format!("30023:{}:alpha", alpha.public_key().to_hex()),
|
||||
format!("30023:{}:beta", beta.public_key().to_hex()),
|
||||
]
|
||||
.iter()
|
||||
.map(|value| parse_shared_instruction_coordinate(value).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let filters = exact_coordinate_filters(&coordinates);
|
||||
|
||||
assert_eq!(filters.len(), 2);
|
||||
assert_eq!(
|
||||
filters[0]["authors"],
|
||||
serde_json::json!([alpha.public_key().to_hex()])
|
||||
);
|
||||
assert_eq!(filters[0]["#d"], serde_json::json!(["alpha"]));
|
||||
assert_eq!(filters[0]["limit"], serde_json::json!(1));
|
||||
assert_eq!(
|
||||
filters[1]["authors"],
|
||||
serde_json::json!([beta.public_key().to_hex()])
|
||||
);
|
||||
assert_eq!(filters[1]["#d"], serde_json::json!(["beta"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_only_exact_requested_signer_and_slug() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let coordinate = format!("30023:{}:design-engineering", alpha.public_key().to_hex());
|
||||
let wrong_author_same_slug = note(&beta, "design-engineering", "wrong author", 20);
|
||||
let right_author_wrong_slug = note(&alpha, "other", "wrong slug", 30);
|
||||
let expected = note(&alpha, "design-engineering", "trusted body", 10);
|
||||
|
||||
let resolved = resolved_heads_from_events(
|
||||
std::slice::from_ref(&coordinate),
|
||||
vec![
|
||||
wrong_author_same_slug,
|
||||
right_author_wrong_slug,
|
||||
expected.clone(),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(resolved.len(), 1);
|
||||
assert_eq!(resolved[0].coordinate, coordinate);
|
||||
assert_eq!(resolved[0].publisher, alpha.public_key().to_hex());
|
||||
assert_eq!(resolved[0].slug, "design-engineering");
|
||||
assert_eq!(resolved[0].content, "trusted body");
|
||||
assert_eq!(
|
||||
resolved[0].summary.as_deref(),
|
||||
Some("Summary design-engineering")
|
||||
);
|
||||
assert_eq!(resolved[0].event_id, expected.id.to_hex());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selects_newest_verified_head_and_preserves_assignment_order() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let alpha_coordinate = format!("30023:{}:alpha", alpha.public_key().to_hex());
|
||||
let beta_coordinate = format!("30023:{}:beta", beta.public_key().to_hex());
|
||||
let old_alpha = note(&alpha, "alpha", "old", 10);
|
||||
let new_alpha = note(&alpha, "alpha", "new", 20);
|
||||
let beta_note = note(&beta, "beta", "beta", 15);
|
||||
|
||||
let resolved = resolved_heads_from_events(
|
||||
&[beta_coordinate.clone(), alpha_coordinate.clone()],
|
||||
vec![old_alpha, new_alpha, beta_note],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
resolved
|
||||
.iter()
|
||||
.map(|skill| skill.coordinate.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![beta_coordinate.as_str(), alpha_coordinate.as_str()]
|
||||
);
|
||||
assert_eq!(resolved[1].content, "new");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_tampered_oversize_and_ambiguous_coordinate_events() {
|
||||
let keys = Keys::generate();
|
||||
let coordinate = format!("30023:{}:skill", keys.public_key().to_hex());
|
||||
let mut tampered = note(&keys, "skill", "original", 10);
|
||||
tampered.content = "tampered".to_string();
|
||||
let oversize = note(
|
||||
&keys,
|
||||
"skill",
|
||||
&"x".repeat(MAX_SHARED_INSTRUCTION_BODY_BYTES + 1),
|
||||
20,
|
||||
);
|
||||
let ambiguous = EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), "ambiguous")
|
||||
.tags([
|
||||
Tag::parse(["d", "skill"]).unwrap(),
|
||||
Tag::parse(["d", "skill"]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(30))
|
||||
.sign_with_keys(&keys)
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
resolved_heads_from_events(&[coordinate], vec![tampered, oversize, ambiguous])
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
use super::*;
|
||||
use nostr::{EventBuilder, Tag, Timestamp};
|
||||
|
||||
fn note(keys: &Keys, slug: &str, content: &str, created_at: u64) -> Event {
|
||||
EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), content)
|
||||
.tags([
|
||||
Tag::parse(["d", slug]).unwrap(),
|
||||
Tag::parse(["title", &format!("Title {slug}")]).unwrap(),
|
||||
Tag::parse(["summary", &format!("Summary {slug}")]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(created_at))
|
||||
.sign_with_keys(keys)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assigned_shared_instruction_env_is_canonical() {
|
||||
let coordinate = format!("30023:{}:review", "a".repeat(64));
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
command.env(ASSIGNED_SHARED_INSTRUCTIONS_ENV, "user-supplied");
|
||||
apply_assigned_shared_instructions_env(&mut command, std::slice::from_ref(&coordinate));
|
||||
let env = command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.and_then(|(_, value)| value)
|
||||
.and_then(|value| value.to_str());
|
||||
assert_eq!(env, Some(coordinate.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_assigned_shared_instruction_env_uses_live_definition() {
|
||||
let stale = format!("30023:{}:revoked", "a".repeat(64));
|
||||
let current = format!("30023:{}:kept", "b".repeat(64));
|
||||
let record: super::super::ManagedAgentRecord = serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "agent",
|
||||
"name": "agent",
|
||||
"persona_id": "persona",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 300,
|
||||
"parallelism": 1,
|
||||
"assigned_shared_instructions": [stale.clone()],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let definition: super::super::AgentDefinition = serde_json::from_value(serde_json::json!({
|
||||
"id": "persona",
|
||||
"display_name": "Persona",
|
||||
"system_prompt": "prompt",
|
||||
"name_pool": [],
|
||||
"is_builtin": false,
|
||||
"is_active": true,
|
||||
"assigned_shared_instructions": [current.clone()],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
|
||||
let definitions = [definition];
|
||||
let assigned = resolve_and_apply_assigned_shared_instructions_env(
|
||||
&mut command,
|
||||
&record,
|
||||
&definitions,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(assigned, definitions[0].assigned_shared_instructions);
|
||||
|
||||
let env = command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.and_then(|(_, value)| value)
|
||||
.and_then(|value| value.to_str());
|
||||
assert_eq!(env, Some(current.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabled_shared_instructions_remove_env_and_effective_assignment() {
|
||||
let coordinate = format!("30023:{}:kept", "a".repeat(64));
|
||||
let record: super::super::ManagedAgentRecord = serde_json::from_value(serde_json::json!({
|
||||
"pubkey": "agent",
|
||||
"name": "agent",
|
||||
"private_key_nsec": "nsec1fake",
|
||||
"relay_url": "wss://relay.example",
|
||||
"acp_command": "buzz-acp",
|
||||
"agent_command": "goose",
|
||||
"agent_args": [],
|
||||
"mcp_command": "",
|
||||
"turn_timeout_seconds": 300,
|
||||
"parallelism": 1,
|
||||
"assigned_shared_instructions": [coordinate],
|
||||
"created_at": "now",
|
||||
"updated_at": "now"
|
||||
}))
|
||||
.unwrap();
|
||||
let mut command = std::process::Command::new("buzz-acp");
|
||||
command.env(ASSIGNED_SHARED_INSTRUCTIONS_ENV, "user-supplied");
|
||||
|
||||
let assigned =
|
||||
resolve_and_apply_assigned_shared_instructions_env(&mut command, &record, &[], false)
|
||||
.unwrap();
|
||||
|
||||
assert!(assigned.is_empty());
|
||||
assert!(command
|
||||
.get_envs()
|
||||
.find(|(key, _)| *key == ASSIGNED_SHARED_INSTRUCTIONS_ENV)
|
||||
.is_some_and(|(_, value)| value.is_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_exact_coordinate_and_deduplicates() {
|
||||
let key = "a".repeat(64);
|
||||
let coordinate = format!("30023:{key}:design-engineering");
|
||||
assert_eq!(
|
||||
validate_assigned_shared_instructions(vec![coordinate.clone(), coordinate.clone()])
|
||||
.unwrap(),
|
||||
vec![coordinate]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_noncanonical_coordinates() {
|
||||
let key = "a".repeat(64);
|
||||
for invalid in [
|
||||
"design-engineering".to_string(),
|
||||
format!("30175:{key}:design-engineering"),
|
||||
format!("30023:{key}:design\nengineering"),
|
||||
format!("30023:{key}:Design-Engineering"),
|
||||
format!("30023:{key}:design/engineering"),
|
||||
format!("30023:{}:design-engineering", "A".repeat(64)),
|
||||
"30023:npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp3d0u5:design-engineering"
|
||||
.to_string(),
|
||||
] {
|
||||
assert!(
|
||||
parse_shared_instruction_coordinate(&invalid).is_err(),
|
||||
"{invalid:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn projects_mine_only_latest_heads_with_explicit_compatibility() {
|
||||
let owner = Keys::generate();
|
||||
let stranger = Keys::generate();
|
||||
let old = note(&owner, "design-engineering", "old body", 10);
|
||||
let current = note(&owner, "design-engineering", "current body", 20);
|
||||
let invalid_name = note(&owner, "Design_skill", "body", 30);
|
||||
let missing_summary = EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), "body")
|
||||
.tags([
|
||||
Tag::parse(["d", "missing-summary"]).unwrap(),
|
||||
Tag::parse(["title", "Missing summary"]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(40))
|
||||
.sign_with_keys(&owner)
|
||||
.unwrap();
|
||||
let foreign = note(&stranger, "foreign", "body", 50);
|
||||
|
||||
let covers = shared_instruction_covers_from_events(
|
||||
&owner.public_key().to_hex(),
|
||||
vec![old, current, invalid_name, missing_summary, foreign],
|
||||
);
|
||||
|
||||
assert_eq!(covers.len(), 3);
|
||||
assert_eq!(covers[0].slug, "missing-summary");
|
||||
assert!(!covers[0].compatible);
|
||||
assert_eq!(
|
||||
covers[0].incompatibilities[0].code,
|
||||
SharedInstructionIncompatibilityCode::MissingDescription
|
||||
);
|
||||
assert_eq!(covers[1].slug, "Design_skill");
|
||||
assert!(!covers[1].compatible);
|
||||
assert_eq!(
|
||||
covers[1].incompatibilities[0].code,
|
||||
SharedInstructionIncompatibilityCode::InvalidName
|
||||
);
|
||||
assert_eq!(covers[2].slug, "design-engineering");
|
||||
assert!(covers[2].compatible);
|
||||
assert!(covers[2].incompatibilities.is_empty());
|
||||
assert_eq!(covers[2].updated_at, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validation_rejects_instruction_name_edge_cases_and_empty_body() {
|
||||
for slug in ["", "-skill", "skill-", "two--hyphens", "with_underscore"] {
|
||||
let reasons = shared_instruction_incompatibilities(slug, Some("Useful summary"), "body");
|
||||
assert!(reasons
|
||||
.iter()
|
||||
.any(|reason| reason.code == SharedInstructionIncompatibilityCode::InvalidName));
|
||||
}
|
||||
let reasons = shared_instruction_incompatibilities("valid-name", Some("summary"), "\n");
|
||||
assert_eq!(
|
||||
reasons[0].code,
|
||||
SharedInstructionIncompatibilityCode::EmptyBody
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_query_filters_do_not_admit_author_slug_cross_products() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let coordinates = [
|
||||
format!("30023:{}:alpha", alpha.public_key().to_hex()),
|
||||
format!("30023:{}:beta", beta.public_key().to_hex()),
|
||||
]
|
||||
.iter()
|
||||
.map(|value| parse_shared_instruction_coordinate(value).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let filters = exact_coordinate_filters(&coordinates);
|
||||
|
||||
assert_eq!(filters.len(), 2);
|
||||
assert_eq!(
|
||||
filters[0]["authors"],
|
||||
serde_json::json!([alpha.public_key().to_hex()])
|
||||
);
|
||||
assert_eq!(filters[0]["#d"], serde_json::json!(["alpha"]));
|
||||
assert_eq!(filters[0]["limit"], serde_json::json!(1));
|
||||
assert_eq!(
|
||||
filters[1]["authors"],
|
||||
serde_json::json!([beta.public_key().to_hex()])
|
||||
);
|
||||
assert_eq!(filters[1]["#d"], serde_json::json!(["beta"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_only_exact_requested_signer_and_slug() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let coordinate = format!("30023:{}:design-engineering", alpha.public_key().to_hex());
|
||||
let wrong_author_same_slug = note(&beta, "design-engineering", "wrong author", 20);
|
||||
let right_author_wrong_slug = note(&alpha, "other", "wrong slug", 30);
|
||||
let expected = note(&alpha, "design-engineering", "trusted body", 10);
|
||||
|
||||
let resolved = resolved_heads_from_events(
|
||||
std::slice::from_ref(&coordinate),
|
||||
vec![
|
||||
wrong_author_same_slug,
|
||||
right_author_wrong_slug,
|
||||
expected.clone(),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(resolved.len(), 1);
|
||||
assert_eq!(resolved[0].coordinate, coordinate);
|
||||
assert_eq!(resolved[0].publisher, alpha.public_key().to_hex());
|
||||
assert_eq!(resolved[0].slug, "design-engineering");
|
||||
assert_eq!(resolved[0].content, "trusted body");
|
||||
assert_eq!(
|
||||
resolved[0].summary.as_deref(),
|
||||
Some("Summary design-engineering")
|
||||
);
|
||||
assert_eq!(resolved[0].event_id, expected.id.to_hex());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selects_newest_verified_head_and_preserves_assignment_order() {
|
||||
let alpha = Keys::generate();
|
||||
let beta = Keys::generate();
|
||||
let alpha_coordinate = format!("30023:{}:alpha", alpha.public_key().to_hex());
|
||||
let beta_coordinate = format!("30023:{}:beta", beta.public_key().to_hex());
|
||||
let old_alpha = note(&alpha, "alpha", "old", 10);
|
||||
let new_alpha = note(&alpha, "alpha", "new", 20);
|
||||
let beta_note = note(&beta, "beta", "beta", 15);
|
||||
|
||||
let resolved = resolved_heads_from_events(
|
||||
&[beta_coordinate.clone(), alpha_coordinate.clone()],
|
||||
vec![old_alpha, new_alpha, beta_note],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
resolved
|
||||
.iter()
|
||||
.map(|skill| skill.coordinate.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![beta_coordinate.as_str(), alpha_coordinate.as_str()]
|
||||
);
|
||||
assert_eq!(resolved[1].content, "new");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_tampered_oversize_and_ambiguous_coordinate_events() {
|
||||
let keys = Keys::generate();
|
||||
let coordinate = format!("30023:{}:skill", keys.public_key().to_hex());
|
||||
let mut tampered = note(&keys, "skill", "original", 10);
|
||||
tampered.content = "tampered".to_string();
|
||||
let oversize = note(
|
||||
&keys,
|
||||
"skill",
|
||||
&"x".repeat(MAX_SHARED_INSTRUCTION_BODY_BYTES + 1),
|
||||
20,
|
||||
);
|
||||
let ambiguous = EventBuilder::new(Kind::Custom(SHARED_INSTRUCTION_KIND), "ambiguous")
|
||||
.tags([
|
||||
Tag::parse(["d", "skill"]).unwrap(),
|
||||
Tag::parse(["d", "skill"]).unwrap(),
|
||||
])
|
||||
.custom_created_at(Timestamp::from(30))
|
||||
.sign_with_keys(&keys)
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
resolved_heads_from_events(&[coordinate], vec![tampered, oversize, ambiguous]).is_empty()
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
||||
|
||||
import type {
|
||||
AcpRuntimeCatalogEntry,
|
||||
CreatePersonaInput,
|
||||
@@ -91,7 +90,6 @@ import {
|
||||
runtimeDropdownAction,
|
||||
usePendingHarnessSelection,
|
||||
} from "./addCustomHarness";
|
||||
|
||||
type AgentDefinitionDialogProps = {
|
||||
open: boolean;
|
||||
embedded?: boolean;
|
||||
@@ -115,11 +113,9 @@ type AgentDefinitionDialogProps = {
|
||||
/** Extra create-mode submit gate (e.g. incomplete provider config). */
|
||||
createSubmitBlocked?: boolean;
|
||||
};
|
||||
|
||||
export type AgentDefinitionSubmitOptions = {
|
||||
publishCatalogUpdates: boolean;
|
||||
};
|
||||
|
||||
export function AgentDefinitionDialog({
|
||||
open,
|
||||
embedded = false,
|
||||
@@ -202,7 +198,6 @@ export function AgentDefinitionDialog({
|
||||
!hasText(initialValues.runtime) &&
|
||||
(hasText(initialValues.model) || hasText(initialValues.provider)),
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
onDirtyChange?.(hasUserChanges);
|
||||
}, [hasUserChanges, onDirtyChange]);
|
||||
|
||||
@@ -40,13 +40,10 @@ import type {
|
||||
GitBashPrerequisite,
|
||||
RuntimeConfigSurface,
|
||||
} from "@/shared/api/types";
|
||||
|
||||
export * from "@/shared/api/tauriChannels";
|
||||
export { sendChannelMessage } from "@/shared/api/tauriMessages";
|
||||
export { getEventById, getEventsByIds } from "@/shared/api/tauriEvents";
|
||||
|
||||
type RawPresenceLookup = Record<string, PresenceStatus>;
|
||||
|
||||
type RawAddChannelMembersResult = {
|
||||
added: string[];
|
||||
errors: Array<{
|
||||
@@ -54,7 +51,6 @@ type RawAddChannelMembersResult = {
|
||||
error: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
type RawFeedItem = {
|
||||
id: string;
|
||||
kind: number;
|
||||
@@ -67,7 +63,6 @@ type RawFeedItem = {
|
||||
tags: string[][];
|
||||
category: HomeFeedResponse["feed"]["mentions"][number]["category"];
|
||||
};
|
||||
|
||||
type RawHomeFeedResponse = {
|
||||
feed: {
|
||||
mentions: RawFeedItem[];
|
||||
|
||||
Reference in New Issue
Block a user