feat: define orchestrator cleanup ownership
This commit is contained in:
@@ -1438,6 +1438,28 @@ mod tests {
|
||||
assert!(resolved.manifest.feature.workspace_worker_discovery.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_orchestrator_keeps_cleanup_tool_providers_enabled() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
let resolved = ProfileResolver::new()
|
||||
.with_workspace_base(tmp.path())
|
||||
.resolve(
|
||||
&ProfileSelector::source_named(ProfileRegistrySource::Builtin, "orchestrator"),
|
||||
ProfileResolveOptions::with_worker_name("orchestrator-worker"),
|
||||
)
|
||||
.unwrap();
|
||||
let feature = resolved.manifest.feature;
|
||||
|
||||
assert!(feature.worker.enabled);
|
||||
assert!(!feature.worker.direct_spawn);
|
||||
assert!(feature.manage_workdir.enabled);
|
||||
assert!(feature.merge_request.show);
|
||||
assert!(feature.merge_request.readiness_check);
|
||||
assert!(feature.merge_request.complete);
|
||||
assert!(!feature.merge_request.open);
|
||||
assert!(!feature.merge_request.review);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn profile_resolution_requires_runtime_worker_name() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
@@ -920,4 +920,22 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_orchestrator_cleanup_policy_renders_with_common_includes() {
|
||||
let rendered = PromptCatalog::builtins_only()
|
||||
.unwrap()
|
||||
.render_name("role.orchestrator", Value::UNDEFINED)
|
||||
.unwrap();
|
||||
|
||||
assert!(rendered.contains("This policy governs naming only"));
|
||||
assert!(rendered.contains("Coder cleanup is a separate post-completion decision"));
|
||||
assert!(rendered.contains("perform one cleanup pass before ending the orchestration turn"));
|
||||
assert!(rendered.contains("Never predeclare `delete_on_completion`"));
|
||||
assert!(rendered.contains("call `WorkerStop`"));
|
||||
assert!(rendered.contains("call `WorkerRemove`"));
|
||||
assert!(rendered.contains("only then call `WorkdirDelete`"));
|
||||
assert!(rendered.contains("`CurrentAssignment` means unassign and reread"));
|
||||
assert!(!rendered.contains("{% include"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use agen::llm_client::{ClientError, LlmClient, Request};
|
||||
use agen::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
|
||||
use async_trait::async_trait;
|
||||
use futures::{Stream, StreamExt};
|
||||
use manifest::{ProfileRegistrySource, ProfileResolveOptions, ProfileResolver, ProfileSelector};
|
||||
use session_store::{CombinedStore, FsWorkerStore};
|
||||
use session_store::{FsStore, LogEntry};
|
||||
use workdir::{
|
||||
@@ -248,6 +249,14 @@ async fn make_worker_with_pwd_manifest_and_workspace_context(
|
||||
workspace_context: WorkerWorkspaceContext,
|
||||
) -> (Worker<MockClient, TestStore>, std::path::PathBuf) {
|
||||
let manifest = WorkerManifest::from_toml(manifest_toml).unwrap();
|
||||
make_worker_with_manifest_and_workspace_context(client, manifest, workspace_context).await
|
||||
}
|
||||
|
||||
async fn make_worker_with_manifest_and_workspace_context(
|
||||
client: MockClient,
|
||||
manifest: WorkerManifest,
|
||||
workspace_context: WorkerWorkspaceContext,
|
||||
) -> (Worker<MockClient, TestStore>, std::path::PathBuf) {
|
||||
let store_tmp = tempfile::tempdir().unwrap();
|
||||
let store = CombinedStore::new(
|
||||
FsStore::new(store_tmp.path()).unwrap(),
|
||||
@@ -783,6 +792,37 @@ permission = "write"
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn builtin_orchestrator_exposes_worker_remove_and_workdir_delete() {
|
||||
let workspace = tempfile::tempdir().unwrap();
|
||||
let resolved = ProfileResolver::new()
|
||||
.with_workspace_base(workspace.path())
|
||||
.resolve(
|
||||
&ProfileSelector::source_named(ProfileRegistrySource::Builtin, "orchestrator"),
|
||||
ProfileResolveOptions::with_worker_name("orchestrator-worker"),
|
||||
)
|
||||
.unwrap();
|
||||
let workspace_context =
|
||||
WorkerWorkspaceContext::with_client(None, Arc::new(NoopWorkspaceClient));
|
||||
let client = MockClient::new(simple_text_events());
|
||||
let client_for_assert = client.clone();
|
||||
let (worker, _pwd) = make_worker_with_manifest_and_workspace_context(
|
||||
client,
|
||||
resolved.manifest,
|
||||
workspace_context,
|
||||
)
|
||||
.await;
|
||||
let handle = spawn_controller(worker).await;
|
||||
|
||||
handle.send(Method::run_text("Hello")).await.unwrap();
|
||||
wait_for_status(&handle, WorkerStatus::Idle).await;
|
||||
let request = wait_for_captured_request(&client_for_assert).await;
|
||||
let installed = request_tool_names(&request);
|
||||
|
||||
assert!(installed.iter().any(|name| name == "WorkerRemove"));
|
||||
assert!(installed.iter().any(|name| name == "WorkdirDelete"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn worker_and_sub_worker_features_install_one_canonical_control_surface() {
|
||||
let manifest = r#"
|
||||
|
||||
Reference in New Issue
Block a user