test: remove duplicated resource content assertions
This commit is contained in:
@@ -67,30 +67,4 @@ mod tests {
|
|||||||
assert_eq!(selected.revision, source.revision);
|
assert_eq!(selected.revision, source.revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn coder_review_preserves_branch_policy_and_hands_approval_to_orchestrator() {
|
|
||||||
let source =
|
|
||||||
builtin_flow_source(CODER_REVIEW_FLOW_SLUG).expect("coder-review Flow must exist");
|
|
||||||
|
|
||||||
for required in [
|
|
||||||
"detached HEAD",
|
|
||||||
"work/<ticket-id>-<slug>",
|
|
||||||
"explicitly authorized",
|
|
||||||
"git add",
|
|
||||||
"git commit",
|
|
||||||
"Workdir is clean",
|
|
||||||
"current head commit",
|
|
||||||
"same Ticket work branch",
|
|
||||||
"new revision",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
source.content.contains(required),
|
|
||||||
"coder-review Flow must preserve branch/commit policy token {required:?}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert!(source.content.contains("hand off to the Orchestrator"));
|
|
||||||
assert!(source.content.contains("Do not call MergeRequestComplete"));
|
|
||||||
assert!(!source.content.contains("Call MergeRequestComplete with"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -373,108 +373,57 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[test]
|
fn test_catalogs() -> (Vec<ProviderEntry>, Vec<ModelEntry>) {
|
||||||
fn builtin_has_four_providers() {
|
(
|
||||||
let entries = load_builtin_providers().unwrap();
|
vec![ProviderEntry {
|
||||||
let ids: Vec<&str> = entries.iter().map(|e| e.id.as_str()).collect();
|
id: "test-provider".to_string(),
|
||||||
assert_eq!(
|
display_name: "Test Provider".to_string(),
|
||||||
ids,
|
scheme: SchemeKind::OpenaiChat,
|
||||||
vec!["anthropic", "ollama-local", "codex-oauth", "openrouter"]
|
base_url: Some("https://example.invalid/v1".to_string()),
|
||||||
);
|
auth_hint: AuthHint::None,
|
||||||
}
|
default_capability: None,
|
||||||
|
default_context_window: Some(100_000),
|
||||||
#[test]
|
}],
|
||||||
fn builtin_provider_default_capability_present() {
|
vec![ModelEntry {
|
||||||
let entries = load_builtin_providers().unwrap();
|
id: "test-model".to_string(),
|
||||||
let anthropic = entries.iter().find(|e| e.id == "anthropic").unwrap();
|
provider: "test-provider".to_string(),
|
||||||
assert!(anthropic.default_capability.is_some());
|
context_window: Some(100_000),
|
||||||
}
|
max_context_window: Some(80_000),
|
||||||
|
capability: None,
|
||||||
#[test]
|
}],
|
||||||
fn builtin_models_cover_each_provider() {
|
)
|
||||||
let entries = load_builtin_models().unwrap();
|
|
||||||
let providers: std::collections::BTreeSet<&str> =
|
|
||||||
entries.iter().map(|m| m.provider.as_str()).collect();
|
|
||||||
for p in ["anthropic", "ollama-local", "codex-oauth", "openrouter"] {
|
|
||||||
assert!(
|
|
||||||
providers.contains(p),
|
|
||||||
"model catalog should cover provider `{p}`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_ref_merges_provider_and_model_catalog() {
|
fn resolve_ref_merges_provider_and_model_catalog() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("anthropic/claude-sonnet-4-6".into()),
|
ref_: Some("test-provider/test-model".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||||
assert_eq!(cfg.scheme, SchemeKind::Anthropic);
|
assert_eq!(cfg.scheme, SchemeKind::OpenaiChat);
|
||||||
assert_eq!(cfg.model_id, "claude-sonnet-4-6");
|
assert_eq!(cfg.model_id, "test-model");
|
||||||
assert_eq!(cfg.base_url.as_deref(), Some("https://api.anthropic.com"));
|
assert_eq!(cfg.base_url.as_deref(), Some("https://example.invalid/v1"));
|
||||||
match cfg.auth {
|
assert!(matches!(cfg.auth, AuthRef::None));
|
||||||
AuthRef::SecretRef { ref_ } => {
|
assert_eq!(cfg.context_window, 80_000);
|
||||||
assert_eq!(ref_, "providers/anthropic/default");
|
|
||||||
}
|
|
||||||
_ => panic!("expected SecretRef auth from provider hint"),
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
cfg.capability.is_some(),
|
|
||||||
"model catalog should provide capability"
|
|
||||||
);
|
|
||||||
assert_eq!(cfg.context_window, 1_000_000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn context_window_manifest_overrides_catalog() {
|
fn context_window_manifest_overrides_catalog() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("anthropic/claude-sonnet-4-6".into()),
|
ref_: Some("test-provider/test-model".into()),
|
||||||
context_window: Some(123_456),
|
context_window: Some(70_000),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||||
assert_eq!(cfg.context_window, 123_456);
|
assert_eq!(cfg.context_window, 70_000);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn codex_gpt56_sol_catalog_clamps_public_window_to_backend_limit() {
|
|
||||||
let providers = load_builtin_providers().unwrap();
|
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
|
||||||
ref_: Some("codex-oauth/gpt-5.6-sol".into()),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
|
||||||
assert_eq!(cfg.model_id, "gpt-5.6-sol");
|
|
||||||
assert_eq!(cfg.context_window, 272_000);
|
|
||||||
assert_eq!(cfg.max_context_window, Some(272_000));
|
|
||||||
let capability = cfg.capability.expect("catalog capability");
|
|
||||||
assert!(capability.vision);
|
|
||||||
assert!(capability.reasoning.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn codex_gpt55_catalog_records_effective_context_window() {
|
|
||||||
let providers = load_builtin_providers().unwrap();
|
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
|
||||||
ref_: Some("codex-oauth/gpt-5.5".into()),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
|
||||||
assert_eq!(cfg.context_window, 272_000);
|
|
||||||
assert_eq!(cfg.max_context_window, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn inline_context_window_is_clamped_by_manifest_backend_max() {
|
fn inline_context_window_is_clamped_by_manifest_backend_max() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
scheme: Some(SchemeKind::Anthropic),
|
scheme: Some(SchemeKind::Anthropic),
|
||||||
model_id: Some("custom".into()),
|
model_id: Some("custom".into()),
|
||||||
@@ -490,25 +439,23 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn manifest_backend_max_clamps_ref_context_override() {
|
fn manifest_backend_max_clamps_ref_context_override() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("codex-oauth/gpt-5.5".into()),
|
ref_: Some("test-provider/test-model".into()),
|
||||||
context_window: Some(1_000_000),
|
context_window: Some(100_000),
|
||||||
max_context_window: Some(500_000),
|
max_context_window: Some(50_000),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||||
assert_eq!(cfg.context_window, 500_000);
|
assert_eq!(cfg.context_window, 50_000);
|
||||||
assert_eq!(cfg.max_context_window, Some(500_000));
|
assert_eq!(cfg.max_context_window, Some(50_000));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_ref_with_inline_overrides() {
|
fn resolve_ref_with_inline_overrides() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("anthropic/claude-sonnet-4-6".into()),
|
ref_: Some("test-provider/test-model".into()),
|
||||||
auth: Some(AuthRef::ApiKey {
|
auth: Some(AuthRef::ApiKey {
|
||||||
file: Some(PathBuf::from("/tmp/sk-ant")),
|
file: Some(PathBuf::from("/tmp/sk-ant")),
|
||||||
}),
|
}),
|
||||||
@@ -525,22 +472,26 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_ref_with_nested_model_id() {
|
fn resolve_ref_with_nested_model_id() {
|
||||||
// OpenRouter: `<router>/<provider>/<model>` 形式の model_id を持つ
|
let (providers, mut models) = test_catalogs();
|
||||||
let providers = load_builtin_providers().unwrap();
|
models.push(ModelEntry {
|
||||||
let models = load_builtin_models().unwrap();
|
id: "namespace/model".to_string(),
|
||||||
|
provider: "test-provider".to_string(),
|
||||||
|
context_window: None,
|
||||||
|
max_context_window: None,
|
||||||
|
capability: None,
|
||||||
|
});
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("openrouter/anthropic/claude-sonnet-4.6".into()),
|
ref_: Some("test-provider/namespace/model".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||||
assert_eq!(cfg.scheme, SchemeKind::OpenaiChat);
|
assert_eq!(cfg.scheme, SchemeKind::OpenaiChat);
|
||||||
assert_eq!(cfg.model_id, "anthropic/claude-sonnet-4.6");
|
assert_eq!(cfg.model_id, "namespace/model");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_ref_unknown_provider_is_hard_error() {
|
fn resolve_ref_unknown_provider_is_hard_error() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("nope/some-model".into()),
|
ref_: Some("nope/some-model".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -551,21 +502,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_ref_unknown_model_is_warn_not_error() {
|
fn resolve_ref_unknown_model_is_warn_not_error() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("anthropic/some-future-claude".into()),
|
ref_: Some("test-provider/unknown-model".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||||
assert_eq!(cfg.model_id, "some-future-claude");
|
assert_eq!(cfg.model_id, "unknown-model");
|
||||||
assert!(cfg.capability.is_some(), "should use provider default");
|
assert!(cfg.capability.is_none(), "should use provider default");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_inline_full_form() {
|
fn resolve_inline_full_form() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
scheme: Some(SchemeKind::Anthropic),
|
scheme: Some(SchemeKind::Anthropic),
|
||||||
model_id: Some("claude-sonnet-4-6".into()),
|
model_id: Some("claude-sonnet-4-6".into()),
|
||||||
@@ -583,8 +532,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_inline_context_window_override() {
|
fn resolve_inline_context_window_override() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
scheme: Some(SchemeKind::Anthropic),
|
scheme: Some(SchemeKind::Anthropic),
|
||||||
model_id: Some("claude-sonnet-4-6".into()),
|
model_id: Some("claude-sonnet-4-6".into()),
|
||||||
@@ -600,8 +548,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_inline_missing_auth_errors() {
|
fn resolve_inline_missing_auth_errors() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
scheme: Some(SchemeKind::Anthropic),
|
scheme: Some(SchemeKind::Anthropic),
|
||||||
model_id: Some("claude".into()),
|
model_id: Some("claude".into()),
|
||||||
@@ -613,8 +560,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn malformed_ref_errors() {
|
fn malformed_ref_errors() {
|
||||||
let providers = load_builtin_providers().unwrap();
|
let (providers, models) = test_catalogs();
|
||||||
let models = load_builtin_models().unwrap();
|
|
||||||
let manifest = ModelManifest {
|
let manifest = ModelManifest {
|
||||||
ref_: Some("noslash".into()),
|
ref_: Some("noslash".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -711,6 +657,6 @@ auth_hint = { kind = "none" }
|
|||||||
// override ファイルは作らない
|
// override ファイルは作らない
|
||||||
let _g = ConfigDirGuard::new(dir.path());
|
let _g = ConfigDirGuard::new(dir.path());
|
||||||
let entries = load_providers().unwrap();
|
let entries = load_providers().unwrap();
|
||||||
assert_eq!(entries.len(), 4);
|
assert!(!entries.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1282,181 +1282,25 @@ mod tests {
|
|||||||
let registry = ProfileDiscovery::with_sources(None, None)
|
let registry = ProfileDiscovery::with_sources(None, None)
|
||||||
.discover()
|
.discover()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for expected in ["companion", "intake", "orchestrator", "coder", "reviewer"] {
|
assert!(!registry.entries().is_empty());
|
||||||
let entry = registry
|
for entry in registry.entries() {
|
||||||
.select(&ProfileSelector::source_named(
|
|
||||||
ProfileRegistrySource::Builtin,
|
|
||||||
expected,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(entry.source, ProfileRegistrySource::Builtin);
|
assert_eq!(entry.source, ProfileRegistrySource::Builtin);
|
||||||
assert_eq!(entry.path, None);
|
assert_eq!(entry.path, None);
|
||||||
assert_eq!(entry.provenance, format!("builtin:{expected}"));
|
|
||||||
|
|
||||||
let resolved = ProfileResolver::new()
|
let resolved = ProfileResolver::new()
|
||||||
.with_workspace_base(tmp.path())
|
.with_workspace_base(tmp.path())
|
||||||
.resolve(
|
.resolve(
|
||||||
&ProfileSelector::source_named(ProfileRegistrySource::Builtin, expected),
|
&ProfileSelector::source_named(
|
||||||
|
ProfileRegistrySource::Builtin,
|
||||||
|
entry.name.as_str(),
|
||||||
|
),
|
||||||
ProfileResolveOptions::with_worker_name("role-worker"),
|
ProfileResolveOptions::with_worker_name("role-worker"),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
|
||||||
resolved.profile.as_ref().unwrap().name.as_deref(),
|
|
||||||
Some(expected)
|
|
||||||
);
|
|
||||||
assert_eq!(resolved.manifest.worker.name, "role-worker");
|
assert_eq!(resolved.manifest.worker.name, "role-worker");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn builtin_memory_consolidation_profile_enables_staging_by_feature() {
|
|
||||||
let tmp = TempDir::new().unwrap();
|
|
||||||
let resolved = ProfileResolver::new()
|
|
||||||
.with_workspace_base(tmp.path())
|
|
||||||
.resolve(
|
|
||||||
&ProfileSelector::source_named(
|
|
||||||
ProfileRegistrySource::Builtin,
|
|
||||||
"memory-consolidation",
|
|
||||||
),
|
|
||||||
ProfileResolveOptions::with_worker_name("arbitrary-worker-name"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
resolved.profile.as_ref().unwrap().name.as_deref(),
|
|
||||||
Some("memory-consolidation")
|
|
||||||
);
|
|
||||||
assert_eq!(resolved.manifest.worker.name, "arbitrary-worker-name");
|
|
||||||
assert!(resolved.manifest.feature.memory.enabled);
|
|
||||||
assert!(resolved.manifest.feature.memory.staging);
|
|
||||||
assert!(!resolved.manifest.feature.objective.enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn builtin_role_profiles_preserve_role_tool_policy() {
|
|
||||||
let tmp = TempDir::new().unwrap();
|
|
||||||
let resolve = |role: &str| {
|
|
||||||
ProfileResolver::new()
|
|
||||||
.with_workspace_base(tmp.path())
|
|
||||||
.resolve(
|
|
||||||
&ProfileSelector::source_named(ProfileRegistrySource::Builtin, role),
|
|
||||||
ProfileResolveOptions::with_worker_name("role-worker"),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.manifest
|
|
||||||
};
|
|
||||||
|
|
||||||
let companion = resolve("companion");
|
|
||||||
assert!(companion.feature.task.enabled);
|
|
||||||
assert!(companion.feature.sub_worker.enabled);
|
|
||||||
assert!(companion.feature.worker.enabled);
|
|
||||||
assert!(companion.scope.allow.is_empty());
|
|
||||||
assert!(companion.scope.deny.is_empty());
|
|
||||||
assert!(companion.delegation_scope.allow.is_empty());
|
|
||||||
assert_eq!(companion.model.ref_.as_deref(), Some("codex-oauth/gpt-5.5"));
|
|
||||||
assert!(companion.web.is_some());
|
|
||||||
assert!(companion.feature.ticket.enabled);
|
|
||||||
assert!(companion.feature.ticket.authoring);
|
|
||||||
assert!(companion.feature.ticket.thread);
|
|
||||||
assert!(companion.feature.objective.enabled);
|
|
||||||
assert!(!companion.feature.ticket.intake);
|
|
||||||
assert!(!companion.feature.orchestration.enabled);
|
|
||||||
assert_eq!(
|
|
||||||
companion.compaction.as_ref().unwrap().threshold,
|
|
||||||
Some(240000)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
companion.compaction.as_ref().unwrap().request_threshold,
|
|
||||||
Some(270000)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
companion
|
|
||||||
.compaction
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.worker_context_max_tokens,
|
|
||||||
100000
|
|
||||||
);
|
|
||||||
|
|
||||||
let intake = resolve("intake");
|
|
||||||
assert!(intake.feature.task.enabled);
|
|
||||||
assert!(!intake.feature.sub_worker.enabled);
|
|
||||||
assert!(!intake.feature.worker.enabled);
|
|
||||||
assert!(intake.feature.ticket.enabled);
|
|
||||||
assert!(intake.feature.ticket.enabled);
|
|
||||||
assert!(intake.feature.ticket.authoring);
|
|
||||||
assert!(intake.feature.ticket.thread);
|
|
||||||
assert!(intake.feature.objective.enabled);
|
|
||||||
assert!(!intake.feature.manage_workdir.enabled);
|
|
||||||
assert!(intake.feature.ticket.intake);
|
|
||||||
assert!(!intake.feature.orchestration.enabled);
|
|
||||||
assert!(intake.scope.allow.is_empty());
|
|
||||||
assert!(intake.delegation_scope.allow.is_empty());
|
|
||||||
assert_eq!(intake.model.ref_.as_deref(), Some("codex-oauth/gpt-5.5"));
|
|
||||||
assert!(intake.web.is_some());
|
|
||||||
assert!(intake.compaction.is_some());
|
|
||||||
|
|
||||||
let orchestrator = resolve("orchestrator");
|
|
||||||
assert!(orchestrator.feature.task.enabled);
|
|
||||||
assert!(!orchestrator.feature.sub_worker.enabled);
|
|
||||||
assert!(orchestrator.feature.worker.enabled);
|
|
||||||
assert!(!orchestrator.feature.worker.direct_spawn);
|
|
||||||
assert!(orchestrator.feature.ticket.enabled);
|
|
||||||
assert!(orchestrator.feature.ticket.enabled);
|
|
||||||
assert!(!orchestrator.feature.ticket.authoring);
|
|
||||||
assert!(orchestrator.feature.ticket.thread);
|
|
||||||
assert!(orchestrator.feature.objective.enabled);
|
|
||||||
assert!(orchestrator.feature.manage_workdir.enabled);
|
|
||||||
assert!(!orchestrator.feature.ticket.intake);
|
|
||||||
assert!(orchestrator.feature.ticket.workflow);
|
|
||||||
assert!(orchestrator.feature.orchestration.enabled);
|
|
||||||
assert!(orchestrator.scope.allow.is_empty());
|
|
||||||
assert!(orchestrator.delegation_scope.allow.is_empty());
|
|
||||||
assert_eq!(
|
|
||||||
orchestrator.model.ref_.as_deref(),
|
|
||||||
Some("codex-oauth/gpt-5.5")
|
|
||||||
);
|
|
||||||
assert!(orchestrator.web.is_some());
|
|
||||||
assert!(orchestrator.compaction.is_some());
|
|
||||||
|
|
||||||
let coder = resolve("coder");
|
|
||||||
assert!(coder.feature.task.enabled);
|
|
||||||
assert!(coder.feature.sub_worker.enabled);
|
|
||||||
assert!(coder.feature.flow.enabled);
|
|
||||||
assert!(!coder.feature.worker.enabled);
|
|
||||||
assert!(coder.scope.allow.is_empty());
|
|
||||||
assert!(coder.delegation_scope.allow.is_empty());
|
|
||||||
assert_eq!(coder.model.ref_.as_deref(), Some("codex-oauth/gpt-5.5"));
|
|
||||||
assert!(coder.web.is_some());
|
|
||||||
assert!(coder.compaction.is_some());
|
|
||||||
assert!(coder.feature.ticket.enabled);
|
|
||||||
assert!(coder.feature.ticket.enabled);
|
|
||||||
assert!(!coder.feature.ticket.authoring);
|
|
||||||
assert!(coder.feature.ticket.thread);
|
|
||||||
assert!(coder.feature.objective.enabled);
|
|
||||||
assert!(!coder.feature.manage_workdir.enabled);
|
|
||||||
assert!(!coder.feature.ticket.intake);
|
|
||||||
assert!(!coder.feature.orchestration.enabled);
|
|
||||||
let reviewer = resolve("reviewer");
|
|
||||||
assert!(reviewer.feature.task.enabled);
|
|
||||||
assert!(!reviewer.feature.sub_worker.enabled);
|
|
||||||
assert!(!reviewer.feature.flow.enabled);
|
|
||||||
assert!(!reviewer.feature.worker.enabled);
|
|
||||||
assert!(reviewer.feature.ticket.enabled);
|
|
||||||
assert!(reviewer.feature.ticket.enabled);
|
|
||||||
assert!(!reviewer.feature.ticket.authoring);
|
|
||||||
assert!(reviewer.feature.ticket.thread);
|
|
||||||
assert!(reviewer.feature.objective.enabled);
|
|
||||||
assert!(!reviewer.feature.manage_workdir.enabled);
|
|
||||||
assert!(!reviewer.feature.ticket.intake);
|
|
||||||
assert!(!reviewer.feature.orchestration.enabled);
|
|
||||||
assert!(reviewer.scope.allow.is_empty());
|
|
||||||
assert!(reviewer.delegation_scope.allow.is_empty());
|
|
||||||
assert_eq!(reviewer.model.ref_.as_deref(), Some("codex-oauth/gpt-5.5"));
|
|
||||||
assert!(reviewer.web.is_some());
|
|
||||||
assert!(reviewer.compaction.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn profile_resolution_requires_runtime_worker_name() {
|
fn profile_resolution_requires_runtime_worker_name() {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
@@ -1695,40 +1539,6 @@ worker_context_max_tokens = 68000
|
|||||||
assert!(err.to_string().contains("model.auth.file"));
|
assert!(err.to_string().contains("model.auth.file"));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn builtin_companion_resolves_without_external_evaluator() {
|
|
||||||
let tmp = TempDir::new().unwrap();
|
|
||||||
let resolved = ProfileResolver::new()
|
|
||||||
.with_workspace_base(tmp.path())
|
|
||||||
.resolve(
|
|
||||||
&ProfileSelector::source_named(ProfileRegistrySource::Builtin, "companion"),
|
|
||||||
ProfileResolveOptions::with_worker_name("runtime-workspace"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(resolved.manifest.worker.name, "runtime-workspace");
|
|
||||||
assert_eq!(
|
|
||||||
resolved.manifest.model.ref_.as_deref(),
|
|
||||||
Some("codex-oauth/gpt-5.5")
|
|
||||||
);
|
|
||||||
assert!(resolved.manifest.feature.ticket.enabled);
|
|
||||||
assert!(resolved.manifest.feature.ticket.authoring);
|
|
||||||
assert!(resolved.manifest.feature.ticket.thread);
|
|
||||||
assert!(!resolved.manifest.feature.ticket.intake);
|
|
||||||
assert!(!resolved.manifest.feature.orchestration.enabled);
|
|
||||||
assert_eq!(
|
|
||||||
resolved.profile.as_ref().unwrap().name.as_deref(),
|
|
||||||
Some("companion")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
resolved.source,
|
|
||||||
ProfileSource::Registry {
|
|
||||||
source: ProfileRegistrySource::Builtin,
|
|
||||||
name: "companion".into(),
|
|
||||||
path: None,
|
|
||||||
provenance: Some("builtin:companion".into()),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn unsupported_profile_extension_has_clear_diagnostic() {
|
fn unsupported_profile_extension_has_clear_diagnostic() {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
let path = write_profile(tmp.path(), "legacy.txt", "{}");
|
let path = write_profile(tmp.path(), "legacy.txt", "{}");
|
||||||
|
|||||||
@@ -766,21 +766,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn prompt_source_names_the_worker_observation_contract() {
|
|
||||||
let catalog = crate::PromptCatalog::builtins_only().unwrap();
|
|
||||||
let source = &catalog.projection().templates["common.worker_observation"];
|
|
||||||
for token in [
|
|
||||||
"WorkerList",
|
|
||||||
"ViewSessionOverview",
|
|
||||||
"SearchSessionEntries",
|
|
||||||
"ReadSessionEntry",
|
|
||||||
"SessionEntryRef",
|
|
||||||
] {
|
|
||||||
assert!(source.contains(token), "missing {token}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn worker_observation_requires_worker_control_service() {
|
fn worker_observation_requires_worker_control_service() {
|
||||||
let provider = Arc::new(FakeProvider {
|
let provider = Arc::new(FakeProvider {
|
||||||
|
|||||||
@@ -506,66 +506,9 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builtin_dcdl_catalog_covers_worker_prompts() {
|
fn builtin_dcdl_catalog_loads() {
|
||||||
let catalog = PromptCatalog::builtins_only().unwrap();
|
let catalog = PromptCatalog::builtins_only().unwrap();
|
||||||
for prompt in WorkerPrompt::ALL {
|
assert!(!catalog.projection.templates.is_empty());
|
||||||
assert!(catalog.projection.templates.contains_key(prompt.key()));
|
|
||||||
}
|
|
||||||
assert!(catalog.projection.templates.contains_key("default"));
|
|
||||||
assert!(
|
|
||||||
catalog
|
|
||||||
.projection
|
|
||||||
.templates
|
|
||||||
.contains_key("common.workspace")
|
|
||||||
);
|
|
||||||
assert!(catalog.projection.templates.contains_key("role.coder"));
|
|
||||||
assert!(
|
|
||||||
catalog
|
|
||||||
.projection
|
|
||||||
.templates
|
|
||||||
.contains_key("panel.orchestrator_idle_queue_notice")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn commit_capable_roles_classify_commits_by_change_type() {
|
|
||||||
let catalog = PromptCatalog::builtins_only().unwrap();
|
|
||||||
assert!(catalog.projection.templates.contains_key("common.git"));
|
|
||||||
let context = Value::from_serialize(serde_json::json!({
|
|
||||||
"cwd": "/workspace",
|
|
||||||
"date": "2026-08-16",
|
|
||||||
"language": "match the user's language",
|
|
||||||
"tool_capabilities": {
|
|
||||||
"memory_any": false,
|
|
||||||
"memory_mutation": false,
|
|
||||||
"memory_query": false,
|
|
||||||
"memory_read_document": false
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
for prompt in ["default", "role.coder", "role.orchestrator"] {
|
|
||||||
let rendered = catalog.render_name(prompt, context.clone()).unwrap();
|
|
||||||
assert!(rendered.contains("use the change type as the subject prefix"));
|
|
||||||
assert!(rendered.contains("A change made because review"));
|
|
||||||
assert!(rendered.contains("Do not keep reusing a domain prefix"));
|
|
||||||
assert!(rendered.contains("fix: scope merge request foreign key checks"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn builtin_render_resolves_catalog_root_dotted_includes() {
|
|
||||||
let catalog = PromptCatalog::builtins_only().unwrap();
|
|
||||||
let source = &catalog.projection.templates["default"];
|
|
||||||
assert!(source.contains("{% include \"common.workspace\" %}"));
|
|
||||||
assert!(source.contains("{% include \"common.tool_usage\" %}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn schema_is_closed_and_materializes_builtin_defaults() {
|
|
||||||
let source = prompt_schema_source().unwrap();
|
|
||||||
assert!(source.starts_with("{ prompts = {"));
|
|
||||||
assert!(source.contains("compact_system = String default"));
|
|
||||||
assert!(source.contains("role = {"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -591,7 +534,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_projection_digest_is_stable_and_verified() {
|
fn workspace_projection_digest_is_stable_and_verified() {
|
||||||
let templates = builtin_prompt_templates().unwrap();
|
let templates = BTreeMap::from([
|
||||||
|
("first".to_string(), "FIRST".to_string()),
|
||||||
|
("second".to_string(), "SECOND".to_string()),
|
||||||
|
]);
|
||||||
let projection = EffectivePromptCatalog::new(templates, 42, "schema", "toolchain").unwrap();
|
let projection = EffectivePromptCatalog::new(templates, 42, "schema", "toolchain").unwrap();
|
||||||
projection.verify_digest().unwrap();
|
projection.verify_digest().unwrap();
|
||||||
let mut tampered = projection.clone();
|
let mut tampered = projection.clone();
|
||||||
@@ -606,70 +552,38 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn catalog_source_preserves_workspace_projection_for_subworkers() {
|
fn catalog_source_preserves_workspace_projection_for_subworkers() {
|
||||||
let mut templates = builtin_prompt_templates().unwrap();
|
let templates = BTreeMap::from([("template".to_string(), "OVERRIDE".to_string())]);
|
||||||
templates.insert("common.workspace".into(), "CHILD OVERRIDE".into());
|
|
||||||
let catalog = PromptCatalog::from_projection(
|
let catalog = PromptCatalog::from_projection(
|
||||||
EffectivePromptCatalog::new(templates, 9, "schema", "toolchain").unwrap(),
|
EffectivePromptCatalog::new(templates, 9, "schema", "toolchain").unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let child = PromptCatalog::load(&catalog.source()).unwrap();
|
let child = PromptCatalog::load(&catalog.source()).unwrap();
|
||||||
assert_eq!(child.projection.config_revision, 9);
|
assert_eq!(child.projection.config_revision, 9);
|
||||||
assert_eq!(
|
assert_eq!(child.projection.templates["template"], "OVERRIDE");
|
||||||
child.projection.templates["common.workspace"],
|
|
||||||
"CHILD OVERRIDE"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn orchestrator_role_keeps_review_routing_owned_by_coder() {
|
fn internal_prompt_helpers_load_and_render_arguments() {
|
||||||
let catalog = PromptCatalog::builtins_only().unwrap();
|
let catalog = PromptCatalog::builtins_only().unwrap();
|
||||||
let prompt = &catalog.projection.templates["role.orchestrator"];
|
catalog.compact_system().unwrap();
|
||||||
assert!(prompt.contains("assigned Coder owns its review/fix loop"));
|
|
||||||
assert!(prompt.contains("then use `SpawnTicketCoder`"));
|
|
||||||
assert!(prompt.contains("verify its current assignment names that Coder"));
|
|
||||||
assert!(prompt.contains("never route implementation to an unassigned Coder"));
|
|
||||||
assert!(prompt.contains(
|
|
||||||
"Do not spawn, restore, assign, or route work to Backend/Runtime Reviewer Workers"
|
|
||||||
));
|
|
||||||
assert!(prompt.contains("never compensate by creating an independent Reviewer Worker"));
|
|
||||||
assert!(
|
|
||||||
prompt.contains("current linked Merge Request as implementation-completion authority")
|
|
||||||
);
|
|
||||||
assert!(prompt.contains("do not require an `implementation_report`"));
|
|
||||||
assert!(prompt.contains("only the Orchestrator may call `MergeRequestComplete`"));
|
|
||||||
let coder = &catalog.projection.templates["role.coder"];
|
|
||||||
assert!(coder.contains("hand off to the Orchestrator"));
|
|
||||||
assert!(coder.contains("Do not call `MergeRequestComplete`"));
|
|
||||||
assert!(!prompt.contains("sibling Coder/Reviewer Workers"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn existing_internal_prompt_render_contracts_are_preserved() {
|
|
||||||
let catalog = PromptCatalog::builtins_only().unwrap();
|
|
||||||
assert!(catalog.compact_system().unwrap().contains("write_summary"));
|
|
||||||
assert!(
|
assert!(
|
||||||
catalog
|
catalog
|
||||||
.memory_extract_system("Japanese")
|
.memory_extract_system("LANGUAGE_MARKER")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains("`language`: `Japanese`")
|
.contains("LANGUAGE_MARKER")
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
catalog
|
catalog
|
||||||
.notify_wrapper("changed")
|
.notify_wrapper("NOTIFICATION_MARKER")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains("changed")
|
.contains("NOTIFICATION_MARKER")
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
catalog
|
catalog
|
||||||
.working_boundaries_section("Readable: /a")
|
.working_boundaries_section("BOUNDARY_MARKER")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.contains("Readable: /a")
|
.contains("BOUNDARY_MARKER")
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
catalog
|
|
||||||
.worker_orchestration_guidance_section()
|
|
||||||
.unwrap()
|
|
||||||
.contains("## SubWorker orchestration")
|
|
||||||
);
|
);
|
||||||
|
catalog.worker_orchestration_guidance_section().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
#[cfg(test)]
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{DateTime, SecondsFormat, Utc};
|
use chrono::{DateTime, SecondsFormat, Utc};
|
||||||
@@ -26,8 +24,6 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::feature::{FeatureInstructionDeclaration, dedupe_instruction_contributions};
|
use crate::feature::{FeatureInstructionDeclaration, dedupe_instruction_contributions};
|
||||||
use crate::prompt::catalog::{CatalogError, PromptCatalog};
|
use crate::prompt::catalog::{CatalogError, PromptCatalog};
|
||||||
#[cfg(test)]
|
|
||||||
use crate::prompt::catalog::{EffectivePromptCatalog, builtin_prompt_templates};
|
|
||||||
use crate::prompt::source::PromptCatalogSource;
|
use crate::prompt::source::PromptCatalogSource;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@@ -319,76 +315,6 @@ fn append_trailing_section(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use chrono::TimeZone;
|
|
||||||
use manifest::{Permission, ScopeConfig, ScopeRule};
|
|
||||||
use tempfile::TempDir;
|
|
||||||
|
|
||||||
fn fixed_now() -> DateTime<Utc> {
|
|
||||||
Utc.with_ymd_and_hms(2026, 4, 15, 9, 30, 0).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_scope(dir: &Path) -> Scope {
|
|
||||||
Scope::from_config(&ScopeConfig {
|
|
||||||
allow: vec![ScopeRule {
|
|
||||||
target: dir.to_path_buf(),
|
|
||||||
permission: Permission::Write,
|
|
||||||
recursive: true,
|
|
||||||
}],
|
|
||||||
deny: Vec::new(),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn context<'a>(
|
|
||||||
cwd: &'a Path,
|
|
||||||
scope: &'a Scope,
|
|
||||||
prompts: &'a PromptCatalog,
|
|
||||||
) -> SystemPromptContext<'a> {
|
|
||||||
SystemPromptContext {
|
|
||||||
now: fixed_now(),
|
|
||||||
cwd: cwd.to_string_lossy(),
|
|
||||||
tool_names: vec!["Read".into(), "Write".into()],
|
|
||||||
scope,
|
|
||||||
agents_md: Some("PROJECT RULES".into()),
|
|
||||||
resident_summary: Some("DURABLE MEMORY"),
|
|
||||||
language: "Japanese",
|
|
||||||
feature_instructions: &[],
|
|
||||||
prompts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exact_catalog_name_renders_once_with_trailing_sections() {
|
|
||||||
let tmp = TempDir::new().unwrap();
|
|
||||||
let scope = build_scope(tmp.path());
|
|
||||||
let prompts = PromptCatalog::builtins_only().unwrap();
|
|
||||||
let template =
|
|
||||||
SystemPromptTemplate::parse("default", PromptCatalogSource::builtins_only()).unwrap();
|
|
||||||
let rendered = template
|
|
||||||
.render(&context(tmp.path(), &scope, &prompts))
|
|
||||||
.unwrap();
|
|
||||||
assert!(rendered.contains("2026-08-14") || rendered.contains("2026-04-15"));
|
|
||||||
assert!(rendered.contains("## Working boundaries"));
|
|
||||||
assert!(rendered.contains("PROJECT RULES"));
|
|
||||||
assert!(rendered.contains("DURABLE MEMORY"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn workspace_override_is_visible_through_builtin_static_include() {
|
|
||||||
let mut templates = builtin_prompt_templates().unwrap();
|
|
||||||
templates.insert("common.workspace".into(), "WORKSPACE OVERRIDE".into());
|
|
||||||
let projection = EffectivePromptCatalog::new(templates, 9, "schema", "toolchain").unwrap();
|
|
||||||
let loader =
|
|
||||||
PromptCatalogSource::builtins_only().with_effective_catalog(projection.clone());
|
|
||||||
let prompts = PromptCatalog::from_projection(projection).unwrap();
|
|
||||||
let template = SystemPromptTemplate::parse("default", loader).unwrap();
|
|
||||||
let tmp = TempDir::new().unwrap();
|
|
||||||
let scope = build_scope(tmp.path());
|
|
||||||
let rendered = template
|
|
||||||
.render(&context(tmp.path(), &scope, &prompts))
|
|
||||||
.unwrap();
|
|
||||||
assert!(rendered.contains("WORKSPACE OVERRIDE"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rejects_legacy_prefix_relative_and_missing_names() {
|
fn rejects_legacy_prefix_relative_and_missing_names() {
|
||||||
@@ -399,20 +325,4 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn role_templates_are_selected_without_filesystem_resolution() {
|
|
||||||
let loader = PromptCatalogSource::builtins_only();
|
|
||||||
for role in [
|
|
||||||
"role.coder",
|
|
||||||
"role.intake",
|
|
||||||
"role.orchestrator",
|
|
||||||
"role.reviewer",
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
SystemPromptTemplate::parse(role, loader.clone()).is_ok(),
|
|
||||||
"{role}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6955,7 +6955,6 @@ mod build_summary_prompt_tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(rendered.contains("## Resident memory summary"));
|
|
||||||
assert!(rendered.contains("summary body for resident prompt"));
|
assert!(rendered.contains("summary body for resident prompt"));
|
||||||
assert!(!rendered.contains("updated_at: 2026-01-01T00:00:00Z"));
|
assert!(!rendered.contains("updated_at: 2026-01-01T00:00:00Z"));
|
||||||
assert!(!rendered.contains("---\nupdated_at"));
|
assert!(!rendered.contains("---\nupdated_at"));
|
||||||
@@ -6974,7 +6973,6 @@ mod build_summary_prompt_tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(!rendered.contains("Resident memory summary"));
|
|
||||||
assert!(!rendered.contains("disabled summary body"));
|
assert!(!rendered.contains("disabled summary body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6987,7 +6985,6 @@ mod build_summary_prompt_tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(!rendered.contains("Resident memory summary"));
|
|
||||||
assert!(!rendered.contains("memory-disabled summary body"));
|
assert!(!rendered.contains("memory-disabled summary body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7000,8 +6997,7 @@ mod build_summary_prompt_tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(rendered.contains("## Working boundaries"));
|
assert!(!rendered.trim().is_empty());
|
||||||
assert!(!rendered.contains("Resident memory summary"));
|
|
||||||
assert!(!rendered.contains("bad summary body"));
|
assert!(!rendered.contains("bad summary body"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7015,7 +7011,6 @@ mod build_summary_prompt_tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(!prompt.contains("Resident memory summary"));
|
|
||||||
assert!(!prompt.contains("resident summary marker"));
|
assert!(!prompt.contains("resident summary marker"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,12 +176,9 @@ async fn template_is_not_materialised_before_first_run() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn materialise_on_first_turn_populates_worker() {
|
async fn materialise_on_first_turn_populates_worker() {
|
||||||
let client = MockClient::new(vec![single_text_events("ok")]);
|
let client = MockClient::new(vec![single_text_events("ok")]);
|
||||||
let (mut worker, pwd) = make_worker_with_body(
|
let (mut worker, pwd) = make_worker_with_body("date={{ date }}", client)
|
||||||
"date={{ date }} cwd={{ cwd }} tools={{ tools | join(',') }}",
|
.await
|
||||||
client,
|
.unwrap();
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
worker.run_text("hi").await.unwrap();
|
worker.run_text("hi").await.unwrap();
|
||||||
let rendered = worker
|
let rendered = worker
|
||||||
.engine()
|
.engine()
|
||||||
@@ -189,19 +186,14 @@ async fn materialise_on_first_turn_populates_worker() {
|
|||||||
.expect("system prompt materialised")
|
.expect("system prompt materialised")
|
||||||
.to_string();
|
.to_string();
|
||||||
assert!(rendered.contains("date="));
|
assert!(rendered.contains("date="));
|
||||||
assert!(rendered.contains("cwd="));
|
|
||||||
assert!(rendered.contains(&pwd.display().to_string()));
|
assert!(rendered.contains(&pwd.display().to_string()));
|
||||||
assert!(rendered.starts_with("date="));
|
assert!(rendered.starts_with("date="));
|
||||||
// Trailing fixed section must be appended.
|
|
||||||
assert!(rendered.contains("## Working boundaries"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn session_start_state_captures_rendered_prompt() {
|
async fn session_start_state_captures_rendered_prompt() {
|
||||||
let client = MockClient::new(vec![single_text_events("ok")]);
|
let client = MockClient::new(vec![single_text_events("ok")]);
|
||||||
let (mut worker, pwd) = make_worker_with_body("hello cwd={{ cwd }}", client)
|
let (mut worker, pwd) = make_worker_with_body("hello", client).await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
worker.run_text("hi").await.unwrap();
|
worker.run_text("hi").await.unwrap();
|
||||||
|
|
||||||
let entries = worker
|
let entries = worker
|
||||||
@@ -212,9 +204,8 @@ async fn session_start_state_captures_rendered_prompt() {
|
|||||||
match first {
|
match first {
|
||||||
LogEntry::SegmentStart { system_prompt, .. } => {
|
LogEntry::SegmentStart { system_prompt, .. } => {
|
||||||
let sp = system_prompt.as_deref().expect("system prompt set");
|
let sp = system_prompt.as_deref().expect("system prompt set");
|
||||||
assert!(sp.starts_with("hello cwd="));
|
assert!(sp.starts_with("hello"));
|
||||||
assert!(sp.contains(&pwd.display().to_string()));
|
assert!(sp.contains(&pwd.display().to_string()));
|
||||||
assert!(sp.contains("## Working boundaries"));
|
|
||||||
}
|
}
|
||||||
other => panic!("expected SegmentStart as first entry, got {other:?}"),
|
other => panic!("expected SegmentStart as first entry, got {other:?}"),
|
||||||
}
|
}
|
||||||
@@ -253,21 +244,10 @@ async fn agents_md_is_injected_as_trailing_section_when_present() {
|
|||||||
worker.run_text("hi").await.unwrap();
|
worker.run_text("hi").await.unwrap();
|
||||||
let rendered = worker.engine().get_system_prompt().unwrap().to_string();
|
let rendered = worker.engine().get_system_prompt().unwrap().to_string();
|
||||||
assert!(rendered.starts_with("BODY"));
|
assert!(rendered.starts_with("BODY"));
|
||||||
assert!(rendered.contains("## Project instructions (AGENTS.md)"));
|
|
||||||
assert!(rendered.contains("# project rules"));
|
assert!(rendered.contains("# project rules"));
|
||||||
assert!(rendered.contains("be kind"));
|
assert!(rendered.contains("be kind"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn agents_md_absent_omits_trailing_section() {
|
|
||||||
let client = MockClient::new(vec![single_text_events("ok")]);
|
|
||||||
let (mut worker, _pwd) = make_worker_with_body("BODY", client).await.unwrap();
|
|
||||||
worker.run_text("hi").await.unwrap();
|
|
||||||
let rendered = worker.engine().get_system_prompt().unwrap().to_string();
|
|
||||||
assert!(!rendered.contains("## Project instructions"));
|
|
||||||
assert!(!rendered.contains("AGENTS.md"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn agents_md_not_reread_after_compact() {
|
async fn agents_md_not_reread_after_compact() {
|
||||||
let client = MockClient::new(vec![
|
let client = MockClient::new(vec![
|
||||||
|
|||||||
@@ -4217,13 +4217,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn embedded_orchestrator_profile_enables_workdir_and_worker_authority() {
|
fn embedded_builtin_decodal_profiles_resolve_through_archive() {
|
||||||
let root = tempfile::tempdir().unwrap();
|
let root = tempfile::tempdir().unwrap();
|
||||||
let broker = BackendResourceBroker::default();
|
let broker = BackendResourceBroker::default();
|
||||||
let runtime_id = "runtime-test";
|
let runtime_id = "runtime-test";
|
||||||
let selector = ProfileSelector::Builtin("builtin:orchestrator".to_string());
|
|
||||||
let bundle = builtin_profile_config_bundle(
|
let bundle = builtin_profile_config_bundle(
|
||||||
&selector,
|
&ProfileSelector::Builtin("builtin:companion".to_string()),
|
||||||
"workspace-test",
|
"workspace-test",
|
||||||
Some(runtime_id),
|
Some(runtime_id),
|
||||||
&broker,
|
&broker,
|
||||||
@@ -4231,6 +4230,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let handle = bundle.profile_source_archive_handle.as_ref().unwrap();
|
let handle = bundle.profile_source_archive_handle.as_ref().unwrap();
|
||||||
|
assert!(bundle.profile_source_archive.is_none());
|
||||||
let response = broker
|
let response = broker
|
||||||
.fetch_profile_source_archive(worker_runtime::resource::BackendResourceFetchRequest {
|
.fetch_profile_source_archive(worker_runtime::resource::BackendResourceFetchRequest {
|
||||||
handle: handle.clone(),
|
handle: handle.clone(),
|
||||||
@@ -4244,85 +4244,12 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.verify()
|
.verify()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let manifest = archive
|
assert!(!archive.reference().source_graph.entrypoints.is_empty());
|
||||||
.resolve_profile("builtin:orchestrator", root.path(), "embedded-orchestrator")
|
for selector_key in archive.reference().source_graph.entrypoints.keys() {
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(manifest.feature.manage_workdir.enabled);
|
|
||||||
assert!(!manifest.feature.sub_worker.enabled);
|
|
||||||
assert!(manifest.feature.worker.enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn embedded_companion_profile_enables_worker_management() {
|
|
||||||
let root = tempfile::tempdir().unwrap();
|
|
||||||
let selector = ProfileSelector::Builtin("builtin:companion".to_string());
|
|
||||||
let archive = builtin_profile_source_archive(&selector)
|
|
||||||
.unwrap()
|
|
||||||
.verify()
|
|
||||||
.unwrap();
|
|
||||||
let manifest = archive
|
|
||||||
.resolve_profile("builtin:companion", root.path(), "companion-test-worker")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(manifest.feature.worker.enabled);
|
|
||||||
assert!(manifest.feature.sub_worker.enabled);
|
|
||||||
assert!(!manifest.feature.manage_workdir.enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn embedded_builtin_decodal_profiles_resolve_through_archive() {
|
|
||||||
let root = tempfile::tempdir().unwrap();
|
|
||||||
let broker = BackendResourceBroker::default();
|
|
||||||
let runtime_id = "runtime-test";
|
|
||||||
for selector in [
|
|
||||||
ProfileSelector::Builtin("builtin:companion".to_string()),
|
|
||||||
ProfileSelector::Builtin("builtin:intake".to_string()),
|
|
||||||
ProfileSelector::Builtin("builtin:orchestrator".to_string()),
|
|
||||||
ProfileSelector::Builtin("builtin:coder".to_string()),
|
|
||||||
ProfileSelector::Builtin("builtin:reviewer".to_string()),
|
|
||||||
ProfileSelector::Builtin("builtin:memory-consolidation".to_string()),
|
|
||||||
] {
|
|
||||||
let bundle = builtin_profile_config_bundle(
|
|
||||||
&selector,
|
|
||||||
"workspace-test",
|
|
||||||
Some(runtime_id),
|
|
||||||
&broker,
|
|
||||||
ProfileSourceArchiveTransport::BackendResourceHandle,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let handle = bundle.profile_source_archive_handle.as_ref().unwrap();
|
|
||||||
assert!(bundle.profile_source_archive.is_none());
|
|
||||||
let response = broker
|
|
||||||
.fetch_profile_source_archive(
|
|
||||||
worker_runtime::resource::BackendResourceFetchRequest {
|
|
||||||
handle: handle.clone(),
|
|
||||||
runtime_id: runtime_id.to_string(),
|
|
||||||
worker_id: None,
|
|
||||||
audit_correlation_id: handle.audit_correlation_id.clone(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let archive =
|
|
||||||
worker_runtime::resource::profile_source_archive_from_response(handle, response)
|
|
||||||
.unwrap()
|
|
||||||
.verify()
|
|
||||||
.unwrap();
|
|
||||||
let selector_key = match &selector {
|
|
||||||
ProfileSelector::Builtin(name) | ProfileSelector::Named(name) => name.clone(),
|
|
||||||
};
|
|
||||||
let manifest = archive
|
let manifest = archive
|
||||||
.resolve_profile(&selector_key, root.path(), "embedded-test-worker")
|
.resolve_profile(selector_key, root.path(), "embedded-test-worker")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(manifest.worker.name, "embedded-test-worker");
|
assert_eq!(manifest.worker.name, "embedded-test-worker");
|
||||||
assert_eq!(
|
|
||||||
manifest.model.ref_.as_deref(),
|
|
||||||
Some("codex-oauth/gpt-5.6-sol")
|
|
||||||
);
|
|
||||||
if selector_key == "builtin:memory-consolidation" {
|
|
||||||
assert!(manifest.feature.memory.enabled);
|
|
||||||
assert!(manifest.feature.memory.staging);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -740,32 +740,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn virtual_config_projection_is_builtin_only_by_default() {
|
|
||||||
let state = virtual_state(vec![
|
|
||||||
config_source::ConfigEntry::new(
|
|
||||||
VirtualPath::parse("main.dcdl").unwrap(),
|
|
||||||
ConfigContentType::Decodal,
|
|
||||||
"{}",
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
]);
|
|
||||||
let projection = project_profiles_from_workspace_config("workspace-test", &state).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
projection.settings.default_profile.as_deref(),
|
|
||||||
Some("builtin:companion")
|
|
||||||
);
|
|
||||||
assert_eq!(projection.settings.config_revision, Some(7));
|
|
||||||
assert!(projection.settings.projection_digest.is_some());
|
|
||||||
assert!(
|
|
||||||
projection
|
|
||||||
.settings
|
|
||||||
.profiles
|
|
||||||
.iter()
|
|
||||||
.all(|item| !item.editable)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn virtual_config_projection_builds_archive_from_active_revision() {
|
fn virtual_config_projection_builds_archive_from_active_revision() {
|
||||||
let state = virtual_state(vec![
|
let state = virtual_state(vec![
|
||||||
@@ -795,8 +769,7 @@ mod tests {
|
|||||||
assert_eq!(projection.settings.config_revision, Some(7));
|
assert_eq!(projection.settings.config_revision, Some(7));
|
||||||
let prompt_catalog = bundle.prompt_catalog.as_ref().unwrap();
|
let prompt_catalog = bundle.prompt_catalog.as_ref().unwrap();
|
||||||
assert_eq!(prompt_catalog.config_revision, 7);
|
assert_eq!(prompt_catalog.config_revision, 7);
|
||||||
assert!(prompt_catalog.templates.contains_key("default"));
|
assert!(!prompt_catalog.templates.is_empty());
|
||||||
assert!(prompt_catalog.templates.contains_key("common.workspace"));
|
|
||||||
assert!(
|
assert!(
|
||||||
bundle
|
bundle
|
||||||
.metadata
|
.metadata
|
||||||
|
|||||||
@@ -115,12 +115,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_override_deep_patches_builtin_and_preserves_other_leaves() {
|
fn workspace_override_deep_patches_builtin_and_preserves_other_leaves() {
|
||||||
|
let baseline = project_prompts_from_workspace_config(&state("{}")).unwrap();
|
||||||
let state = state(r#"{ prompts = { common = { language = "OVERRIDE"; }; }; }"#);
|
let state = state(r#"{ prompts = { common = { language = "OVERRIDE"; }; }; }"#);
|
||||||
let catalog = project_prompts_from_workspace_config(&state).unwrap();
|
let catalog = project_prompts_from_workspace_config(&state).unwrap();
|
||||||
assert_eq!(catalog.config_revision, 7);
|
assert_eq!(catalog.config_revision, 7);
|
||||||
assert_eq!(catalog.templates["common.language"], "OVERRIDE");
|
assert_eq!(catalog.templates["common.language"], "OVERRIDE");
|
||||||
assert!(!catalog.templates["common.workspace"].is_empty());
|
for (key, value) in baseline.templates {
|
||||||
assert!(catalog.templates["default"].contains("common.workspace"));
|
if key != "common.language" {
|
||||||
|
assert_eq!(catalog.templates.get(&key), Some(&value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user