Update roster fixtures and redact live provider keys (T90)

This commit is contained in:
2026-11-12 08:56:03 +00:00
parent d6e3158b80
commit 7d22f03b63
8 changed files with 29 additions and 34 deletions
-1
View File
@@ -38402,7 +38402,6 @@ async function readTestConfig(fs2) {
}
async function writeTestConfig(fs2, value2) {
const { roster, ...config } = value2;
await fs2.mkdir(directory);
for (const entry2 of await fs2.list(directory)) if (entry2.name.endsWith(".md")) await fs2.remove(`${directory}/${entry2.name}`);
for (const entry2 of roster) {
const { name, prompt, path: _path, ...fields } = entry2;
+1 -1
View File
@@ -38360,7 +38360,7 @@ async function openStorage(path) {
var textOf = (content) => typeof content === "string" ? content : (content ?? []).filter((part) => part.type === "text").map((part) => part.text).join("\n");
function answerFor(rules, transcript) {
const system = JSON.stringify(transcript.messages.filter((message) => message.role === "system"));
const role = /P3 role:([a-z]+)/.exec(system)?.[1];
const role = /P3 role:([a-zA-Z0-9_-]+)/.exec(system)?.[1];
const last = transcript.messages.findLast((message) => message.role !== "system");
const rule = rules.find((rule2) => rule2.role === role && (!rule2.match.kind || rule2.match.kind === last?.role) && textOf(last?.content).includes(rule2.match.text));
if (!rule) throw new Error(`No scripted rule for ${role}: ${JSON.stringify(last)}`);
-1
View File
@@ -15,7 +15,6 @@ export async function readTestConfig(fs:any) {
}
export async function writeTestConfig(fs:any, value:any) {
const {roster,...config}=value;
await fs.mkdir(directory);
for (const entry of await fs.list(directory)) if (entry.name.endsWith('.md')) await fs.remove(`${directory}/${entry.name}`);
for (const entry of roster) {
const {name,prompt,path: _path,...fields}=entry;
+1 -1
View File
@@ -5,7 +5,7 @@ export type Rule = { id: string; role: string; match: { kind?: string; text: str
export const textOf = (content: any): string => typeof content === 'string' ? content : (content ?? []).filter((part: any) => part.type === 'text').map((part: any) => part.text).join('\n');
export function answerFor(rules: Rule[], transcript: any) {
const system = JSON.stringify(transcript.messages.filter((message: any) => message.role === 'system'));
const role = /P3 role:([a-z]+)/.exec(system)?.[1];
const role = /P3 role:([a-zA-Z0-9_-]+)/.exec(system)?.[1];
const last = transcript.messages.findLast((message: any) => message.role !== 'system');
const rule = rules.find(rule => rule.role === role && (!rule.match.kind || rule.match.kind === last?.role) && textOf(last?.content).includes(rule.match.text));
if (!rule) throw new Error(`No scripted rule for ${role}: ${JSON.stringify(last)}`);
-1
View File
@@ -37462,7 +37462,6 @@ async function readTestConfig(fs2) {
}
async function writeTestConfig(fs2, value2) {
const { roster, ...config } = value2;
await fs2.mkdir(directory);
for (const entry2 of await fs2.list(directory)) if (entry2.name.endsWith(".md")) await fs2.remove(`${directory}/${entry2.name}`);
for (const entry2 of roster) {
const { name, prompt, path: _path, ...fields } = entry2;
+8 -2
View File
@@ -148,7 +148,8 @@ pub async fn run_module_with_input(
receiver: input::Receiver,
source: &str,
) -> anyhow::Result<()> {
let provider_config = config::Config::read(&world.root).await?;
let config_root = world.root.clone();
let provider_config = config::Config::read(&config_root).await?;
let loader = std::rc::Rc::new(loader::Loader {
root: world.root.clone(),
modules: Default::default(),
@@ -232,9 +233,14 @@ pub async fn run_module_with_input(
Ok::<_, anyhow::Error>(())
}
.await;
let current_config = config::Config::read(&config_root).await.unwrap_or_default();
result.map_err(|error| {
let mut text = error.to_string();
for provider in provider_config.providers.values() {
for provider in provider_config
.providers
.values()
.chain(current_config.providers.values())
{
if !provider.api_key.is_empty() {
text = text.replace(&provider.api_key, "[redacted]");
}
+6 -12
View File
@@ -50,23 +50,17 @@ fn prepare(dir: &Path) -> anyhow::Result<()> {
repo.join("extensions/probe/server.ts"),
"export default host => { globalThis.dreamHost=host; globalThis.dreamService=host.need({name:'dream'}); globalThis.dreamSubagents=host.need({name:'subagents'}); globalThis.dreamAutomations=host.need({name:'automations'}); return {name:'probe'}; }",
)?;
let mut roster: Vec<serde_json::Value> = ["mainAgent", "coordinator", "worker", "reviewer"].into_iter().map(|role| serde_json::json!({
let roster: Vec<serde_json::Value> = ["mainAgent", "coordinator", "worker", "reviewer"].into_iter().map(|role| serde_json::json!({
"name":role, "description":format!("P3 {role}"), "model":"faux/faux-1",
"isolate":"none", "resident":role == "mainAgent", "prompt":format!("P3 role:{role}"),
"denyTools":if role == "worker" || role == "reviewer" {vec!["subagent"]} else {vec![]}
})).collect();
let defaults: serde_json::Value =
serde_yaml_ng::from_str(include_str!("../../../config/config.yaml"))?;
let mut pass = defaults["roster"]
.as_array()
.unwrap()
.iter()
.find(|entry| entry["name"] == "dream-pass")
.unwrap()
.clone();
pass["model"] = serde_json::json!("faux/faux-1");
roster.push(pass);
crate::common::write_config(dir, "mainAgent", serde_json::json!(roster))?;
std::fs::write(
disk.join("etc/sausage/roster/dream-pass.md"),
include_str!("../../../config/roster/dream-pass.md")
.replace("openai/gpt-6.1-sol", "faux/faux-1"),
)?;
let demo = disk.join("src/demo");
std::fs::create_dir_all(&demo)?;
std::fs::write(demo.join("README.md"), "P3 demo\n")?;
+13 -15
View File
@@ -146,7 +146,7 @@ async fn provider_child() -> anyhow::Result<()> {
};
let dir = std::path::Path::new(&dir);
let source = format!(
"globalThis.providerOnly = true; const provider = (await Deno.core.ops.op_model_providers()).test; if (provider.base_url !== 'https://provider.invalid' || provider.api_key !== 'faux-private-token') throw new Error('Wrong provider config');\n{}",
"globalThis.providerOnly = true; const configuredTestProvider = (await Deno.core.ops.op_model_providers()).test; if (configuredTestProvider.base_url !== 'https://provider.invalid' || configuredTestProvider.api_key !== 'faux-private-token') throw new Error('Wrong provider config');\n{}",
include_str!("../../js/durable-test-bundle.js")
);
run_module(
@@ -158,11 +158,15 @@ async fn provider_child() -> anyhow::Result<()> {
let error = run_module(
World::open(dir)?,
sausage::process::exec(World::open(dir)?)?,
"throw new Error((await Deno.core.ops.op_model_providers()).test.api_key)",
r#"const changedProviderConfig = await Deno.core.ops.op_model_providers();
changedProviderConfig.test.api_key = 'next-private-token';
await Deno.core.ops.op_file('write', '/etc/sausage/config.yaml', [...new TextEncoder().encode(JSON.stringify({providers:changedProviderConfig}))], null);
throw new Error(changedProviderConfig.test.api_key + ' faux-private-token')"#,
)
.await
.unwrap_err();
assert!(!error.to_string().contains("faux-private-token"));
assert!(!error.to_string().contains("next-private-token"));
assert!(error.to_string().contains("[redacted]"));
Ok(())
}
@@ -172,16 +176,16 @@ fn provider_config_ignores_environment() -> anyhow::Result<()> {
let dir = std::env::temp_dir().join(format!("sausage-durable-provider-{}", std::process::id()));
let settings = dir.join("world/etc/sausage");
std::fs::create_dir_all(&settings)?;
std::fs::write(
settings.join("config.yaml"),
"providers:\n test:\n base_url: https://provider.invalid\n api_key: faux-private-token\n",
)?;
for start in 0..2 {
std::fs::write(
settings.join("config.yaml"),
"providers:\n test:\n base_url: https://provider.invalid\n api_key: faux-private-token\n",
)?;
let status = std::process::Command::new(std::env::current_exe()?)
.args(["--exact", "durable::provider_child", "--nocapture"])
.env("DURABLE_PROVIDER_DIR", &dir)
.env(
"PI_PROVIDER_BASE_URL",
"OPENAI_BASE_URL",
if start == 0 {
"https://provider.invalid"
} else {
@@ -189,7 +193,7 @@ fn provider_config_ignores_environment() -> anyhow::Result<()> {
},
)
.env(
"PI_PROVIDER_API_KEY",
"OPENAI_API_KEY",
if start == 0 {
"faux-private-token"
} else {
@@ -200,13 +204,7 @@ fn provider_config_ignores_environment() -> anyhow::Result<()> {
assert!(status.success());
}
let cred = Cred::open(&dir.join("host"))?;
assert_eq!(
cred.item_list()?
.iter()
.filter(|i| i.name == "llm-provider")
.count(),
0
);
assert!(cred.item_list()?.is_empty());
for file in [
"host/cred.sqlite",
"host/cred.sqlite-wal",