9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
372 lines
9.1 KiB
Rust
372 lines
9.1 KiB
Rust
//! End-to-end tests for the env var flow introduced in PRs #783 and #794.
|
|
//!
|
|
//! These tests exercise the full pack-resolve pipeline and verify that:
|
|
//! - Goose personas emit GOOSE_PROVIDER, GOOSE_MODEL, GOOSE_TEMPERATURE
|
|
//! - Buzz-agent personas emit BUZZ_AGENT_MODEL, BUZZ_AGENT_PROVIDER
|
|
//! - The import filter strips derived provider/model keys but preserves knobs
|
|
//! - Multi-runtime packs produce correct per-persona env var prefixes
|
|
//! - Models without a provider prefix emit only the model key (no provider)
|
|
|
|
use std::collections::BTreeMap;
|
|
use std::fs;
|
|
|
|
use buzz_persona::resolve::resolve_pack;
|
|
|
|
const DERIVED_PROVIDER_MODEL_ENV_KEYS: &[&str] = &[
|
|
"GOOSE_MODEL",
|
|
"GOOSE_PROVIDER",
|
|
"BUZZ_AGENT_MODEL",
|
|
"BUZZ_AGENT_PROVIDER",
|
|
];
|
|
|
|
fn filter_derived(env_vars: Vec<(String, String)>) -> BTreeMap<String, String> {
|
|
env_vars
|
|
.into_iter()
|
|
.filter(|(k, _)| {
|
|
!DERIVED_PROVIDER_MODEL_ENV_KEYS
|
|
.iter()
|
|
.any(|d| d.eq_ignore_ascii_case(k))
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_pack_goose_persona_emits_correct_runtime_env_vars() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path();
|
|
|
|
fs::create_dir_all(root.join(".plugin")).unwrap();
|
|
fs::create_dir_all(root.join("agents")).unwrap();
|
|
|
|
fs::write(
|
|
root.join(".plugin/plugin.json"),
|
|
r#"{
|
|
"id": "com.test.e2e-env",
|
|
"name": "E2E Env Test",
|
|
"version": "1.0.0",
|
|
"personas": ["agents/bot.persona.md"],
|
|
"defaults": {}
|
|
}"#,
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(
|
|
root.join("agents/bot.persona.md"),
|
|
r#"---
|
|
name: "bot"
|
|
display_name: "Bot"
|
|
description: "Test bot"
|
|
model: "databricks:goose-claude-4-6-opus"
|
|
temperature: 0.7
|
|
---
|
|
You are a test bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
let pack = resolve_pack(root).unwrap();
|
|
let persona = &pack.personas[0];
|
|
|
|
let env: std::collections::HashMap<_, _> = persona
|
|
.runtime_env_vars
|
|
.iter()
|
|
.map(|(k, v)| (k.as_str(), v.as_str()))
|
|
.collect();
|
|
|
|
assert_eq!(
|
|
env.get("GOOSE_PROVIDER"),
|
|
Some(&"databricks"),
|
|
"should emit GOOSE_PROVIDER=databricks"
|
|
);
|
|
assert_eq!(
|
|
env.get("GOOSE_MODEL"),
|
|
Some(&"goose-claude-4-6-opus"),
|
|
"should emit GOOSE_MODEL=goose-claude-4-6-opus"
|
|
);
|
|
assert_eq!(
|
|
env.get("GOOSE_TEMPERATURE"),
|
|
Some(&"0.7"),
|
|
"should emit GOOSE_TEMPERATURE=0.7"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_pack_buzz_agent_persona_emits_buzz_agent_vars() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path();
|
|
|
|
fs::create_dir_all(root.join(".plugin")).unwrap();
|
|
fs::create_dir_all(root.join("agents")).unwrap();
|
|
|
|
fs::write(
|
|
root.join(".plugin/plugin.json"),
|
|
r#"{
|
|
"id": "com.test.e2e-env",
|
|
"name": "E2E Env Test",
|
|
"version": "1.0.0",
|
|
"personas": ["agents/bot.persona.md"],
|
|
"defaults": {}
|
|
}"#,
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(
|
|
root.join("agents/bot.persona.md"),
|
|
r#"---
|
|
name: "bot"
|
|
display_name: "Bot"
|
|
description: "Test bot"
|
|
runtime: "buzz-agent"
|
|
model: "openai:gpt-4o"
|
|
---
|
|
You are a test bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
let pack = resolve_pack(root).unwrap();
|
|
let persona = &pack.personas[0];
|
|
|
|
let env: std::collections::HashMap<_, _> = persona
|
|
.runtime_env_vars
|
|
.iter()
|
|
.map(|(k, v)| (k.as_str(), v.as_str()))
|
|
.collect();
|
|
|
|
assert_eq!(
|
|
env.get("BUZZ_AGENT_MODEL"),
|
|
Some(&"gpt-4o"),
|
|
"should emit BUZZ_AGENT_MODEL=gpt-4o"
|
|
);
|
|
assert_eq!(
|
|
env.get("BUZZ_AGENT_PROVIDER"),
|
|
Some(&"openai"),
|
|
"should emit BUZZ_AGENT_PROVIDER=openai"
|
|
);
|
|
|
|
// Must NOT contain GOOSE_* keys
|
|
assert!(
|
|
!env.contains_key("GOOSE_MODEL"),
|
|
"buzz-agent runtime must not emit GOOSE_MODEL"
|
|
);
|
|
assert!(
|
|
!env.contains_key("GOOSE_PROVIDER"),
|
|
"buzz-agent runtime must not emit GOOSE_PROVIDER"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn import_filter_strips_derived_preserves_knobs() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path();
|
|
|
|
fs::create_dir_all(root.join(".plugin")).unwrap();
|
|
fs::create_dir_all(root.join("agents")).unwrap();
|
|
|
|
fs::write(
|
|
root.join(".plugin/plugin.json"),
|
|
r#"{
|
|
"id": "com.test.e2e-env",
|
|
"name": "E2E Env Test",
|
|
"version": "1.0.0",
|
|
"personas": ["agents/bot.persona.md"],
|
|
"defaults": {}
|
|
}"#,
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(
|
|
root.join("agents/bot.persona.md"),
|
|
r#"---
|
|
name: "bot"
|
|
display_name: "Bot"
|
|
description: "Test bot"
|
|
model: "databricks:goose-claude-4-6-opus"
|
|
temperature: 0.7
|
|
---
|
|
You are a test bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
let pack = resolve_pack(root).unwrap();
|
|
let persona = &pack.personas[0];
|
|
|
|
// Apply the import filter (mirrors desktop import_persona_pack logic).
|
|
let filtered = filter_derived(persona.runtime_env_vars.clone());
|
|
|
|
// Derived provider/model keys must be stripped.
|
|
assert!(
|
|
!filtered.contains_key("GOOSE_MODEL"),
|
|
"GOOSE_MODEL must be stripped by import filter"
|
|
);
|
|
assert!(
|
|
!filtered.contains_key("GOOSE_PROVIDER"),
|
|
"GOOSE_PROVIDER must be stripped by import filter"
|
|
);
|
|
|
|
// Knob keys must survive.
|
|
assert_eq!(
|
|
filtered.get("GOOSE_TEMPERATURE").map(|s| s.as_str()),
|
|
Some("0.7"),
|
|
"GOOSE_TEMPERATURE must survive the import filter"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn full_pipeline_two_runtimes_different_env_vars() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path();
|
|
|
|
fs::create_dir_all(root.join(".plugin")).unwrap();
|
|
fs::create_dir_all(root.join("agents")).unwrap();
|
|
|
|
fs::write(
|
|
root.join(".plugin/plugin.json"),
|
|
r#"{
|
|
"id": "com.test.e2e-env",
|
|
"name": "E2E Env Test",
|
|
"version": "1.0.0",
|
|
"personas": [
|
|
"agents/goose-bot.persona.md",
|
|
"agents/buzz-bot.persona.md"
|
|
],
|
|
"defaults": {}
|
|
}"#,
|
|
)
|
|
.unwrap();
|
|
|
|
// Goose persona (default runtime)
|
|
fs::write(
|
|
root.join("agents/goose-bot.persona.md"),
|
|
r#"---
|
|
name: "goose-bot"
|
|
display_name: "Goose Bot"
|
|
description: "A goose runtime bot"
|
|
model: "anthropic:claude-sonnet-4-20250514"
|
|
---
|
|
You are a goose bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
// Buzz-agent persona
|
|
fs::write(
|
|
root.join("agents/buzz-bot.persona.md"),
|
|
r#"---
|
|
name: "buzz-bot"
|
|
display_name: "Buzz Bot"
|
|
description: "A buzz-agent runtime bot"
|
|
runtime: "buzz-agent"
|
|
model: "openai:gpt-4o"
|
|
---
|
|
You are a buzz bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
let pack = resolve_pack(root).unwrap();
|
|
assert_eq!(pack.personas.len(), 2);
|
|
|
|
let goose = pack
|
|
.personas
|
|
.iter()
|
|
.find(|p| p.name == "goose-bot")
|
|
.expect("goose-bot should exist");
|
|
let buzz = pack
|
|
.personas
|
|
.iter()
|
|
.find(|p| p.name == "buzz-bot")
|
|
.expect("buzz-bot should exist");
|
|
|
|
// Goose persona gets GOOSE_* env vars
|
|
let goose_env: std::collections::HashMap<_, _> = goose
|
|
.runtime_env_vars
|
|
.iter()
|
|
.map(|(k, v)| (k.as_str(), v.as_str()))
|
|
.collect();
|
|
assert_eq!(goose_env.get("GOOSE_PROVIDER"), Some(&"anthropic"));
|
|
assert_eq!(
|
|
goose_env.get("GOOSE_MODEL"),
|
|
Some(&"claude-sonnet-4-20250514")
|
|
);
|
|
assert!(
|
|
!goose_env.contains_key("BUZZ_AGENT_MODEL"),
|
|
"goose persona must not emit BUZZ_AGENT_MODEL"
|
|
);
|
|
assert!(
|
|
!goose_env.contains_key("BUZZ_AGENT_PROVIDER"),
|
|
"goose persona must not emit BUZZ_AGENT_PROVIDER"
|
|
);
|
|
|
|
// Buzz-agent persona gets BUZZ_AGENT_* env vars
|
|
let buzz_env: std::collections::HashMap<_, _> = buzz
|
|
.runtime_env_vars
|
|
.iter()
|
|
.map(|(k, v)| (k.as_str(), v.as_str()))
|
|
.collect();
|
|
assert_eq!(buzz_env.get("BUZZ_AGENT_MODEL"), Some(&"gpt-4o"));
|
|
assert_eq!(buzz_env.get("BUZZ_AGENT_PROVIDER"), Some(&"openai"));
|
|
assert!(
|
|
!buzz_env.contains_key("GOOSE_MODEL"),
|
|
"buzz-agent persona must not emit GOOSE_MODEL"
|
|
);
|
|
assert!(
|
|
!buzz_env.contains_key("GOOSE_PROVIDER"),
|
|
"buzz-agent persona must not emit GOOSE_PROVIDER"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn model_without_provider_prefix_emits_model_only() {
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let root = tmp.path();
|
|
|
|
fs::create_dir_all(root.join(".plugin")).unwrap();
|
|
fs::create_dir_all(root.join("agents")).unwrap();
|
|
|
|
fs::write(
|
|
root.join(".plugin/plugin.json"),
|
|
r#"{
|
|
"id": "com.test.e2e-env",
|
|
"name": "E2E Env Test",
|
|
"version": "1.0.0",
|
|
"personas": ["agents/bot.persona.md"],
|
|
"defaults": {}
|
|
}"#,
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(
|
|
root.join("agents/bot.persona.md"),
|
|
r#"---
|
|
name: "bot"
|
|
display_name: "Bot"
|
|
description: "Test bot"
|
|
model: "gpt-4o"
|
|
---
|
|
You are a test bot.
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
let pack = resolve_pack(root).unwrap();
|
|
let persona = &pack.personas[0];
|
|
|
|
let env: std::collections::HashMap<_, _> = persona
|
|
.runtime_env_vars
|
|
.iter()
|
|
.map(|(k, v)| (k.as_str(), v.as_str()))
|
|
.collect();
|
|
|
|
assert_eq!(
|
|
env.get("GOOSE_MODEL"),
|
|
Some(&"gpt-4o"),
|
|
"should emit GOOSE_MODEL=gpt-4o"
|
|
);
|
|
assert!(
|
|
!env.contains_key("GOOSE_PROVIDER"),
|
|
"model without colon prefix must NOT emit GOOSE_PROVIDER"
|
|
);
|
|
}
|