@team-agent/installer 0.5.60 → 0.5.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +49 -3
- package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
- package/crates/team-agent/src/cli/diagnose.rs +184 -0
- package/crates/team-agent/src/cli/emit.rs +104 -21
- package/crates/team-agent/src/cli/helpers.rs +1 -0
- package/crates/team-agent/src/cli/leader.rs +14 -2
- package/crates/team-agent/src/cli/leaders.rs +2 -0
- package/crates/team-agent/src/cli/mod.rs +296 -8
- package/crates/team-agent/src/cli/named_address.rs +26 -2
- package/crates/team-agent/src/cli/profile.rs +2 -1
- package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
- package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
- package/crates/team-agent/src/cli/send/persist.rs +1 -0
- package/crates/team-agent/src/cli/send/presentation.rs +3 -0
- package/crates/team-agent/src/cli/send/resolve.rs +206 -1
- package/crates/team-agent/src/cli/send.rs +2 -1
- package/crates/team-agent/src/cli/spec.rs +5 -1
- package/crates/team-agent/src/cli/status.rs +2 -1
- package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
- package/crates/team-agent/src/cli/status_port/format.rs +1 -0
- package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
- package/crates/team-agent/src/cli/status_port/store.rs +7 -3
- package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
- package/crates/team-agent/src/cli/types.rs +36 -2
- package/crates/team-agent/src/communication_mode/mod.rs +54 -0
- package/crates/team-agent/src/compiler/tests.rs +5 -5
- package/crates/team-agent/src/compiler.rs +54 -1
- package/crates/team-agent/src/conpty/backend.rs +1 -0
- package/crates/team-agent/src/conpty/mod.rs +1 -0
- package/crates/team-agent/src/coordinator/backoff.rs +5 -8
- package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
- package/crates/team-agent/src/coordinator/health.rs +1 -0
- package/crates/team-agent/src/coordinator/mod.rs +2 -2
- package/crates/team-agent/src/coordinator/orphan.rs +4 -116
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +6 -5
- package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
- package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +0 -9
- package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
- package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -42
- package/crates/team-agent/src/coordinator/tick.rs +24 -28
- package/crates/team-agent/src/coordinator/types.rs +3 -176
- package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
- package/crates/team-agent/src/db/message_store.rs +47 -2
- package/crates/team-agent/src/db/migration.rs +5 -4
- package/crates/team-agent/src/db/mod.rs +1 -0
- package/crates/team-agent/src/db/schema.rs +1 -0
- package/crates/team-agent/src/diagnose/comms.rs +2 -1
- package/crates/team-agent/src/diagnose/mod.rs +1 -0
- package/crates/team-agent/src/diagnose/orphans.rs +1 -0
- package/crates/team-agent/src/fake_worker.rs +21 -1
- package/crates/team-agent/src/layout/manager.rs +3 -7
- package/crates/team-agent/src/layout/mod.rs +2 -2
- package/crates/team-agent/src/layout/overlay.rs +6 -1
- package/crates/team-agent/src/layout/placement.rs +1 -0
- package/crates/team-agent/src/layout/recovery.rs +3 -0
- package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
- package/crates/team-agent/src/layout/sessions.rs +8 -1
- package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
- package/crates/team-agent/src/layout/worker_env.rs +3 -0
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/helpers.rs +1 -0
- package/crates/team-agent/src/leader/incident.rs +1 -0
- package/crates/team-agent/src/leader/lease.rs +27 -22
- package/crates/team-agent/src/leader/mod.rs +2 -3
- package/crates/team-agent/src/leader/owner_bind.rs +13 -3
- package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
- package/crates/team-agent/src/leader/rediscover.rs +4 -17
- package/crates/team-agent/src/leader/registry.rs +3 -15
- package/crates/team-agent/src/leader/start.rs +1072 -186
- package/crates/team-agent/src/leader/takeover.rs +10 -232
- package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
- package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
- package/crates/team-agent/src/leader/tests/identity.rs +71 -59
- package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
- package/crates/team-agent/src/leader/tests/idle.rs +0 -193
- package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
- package/crates/team-agent/src/leader/tests/mod.rs +4 -41
- package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
- package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
- package/crates/team-agent/src/leader/types.rs +1 -28
- package/crates/team-agent/src/lib.rs +7 -0
- package/crates/team-agent/src/lifecycle/display.rs +7 -1
- package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -28
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch.rs +11 -12
- package/crates/team-agent/src/lifecycle/mod.rs +2 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -4
- package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
- package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
- package/crates/team-agent/src/lifecycle/restart.rs +13 -11
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
- package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
- package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
- package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
- package/crates/team-agent/src/lifecycle/tests.rs +59 -0
- package/crates/team-agent/src/lifecycle/types.rs +0 -9
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
- package/crates/team-agent/src/mcp_server/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/normalize.rs +5 -3
- package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
- package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
- package/crates/team-agent/src/mcp_server/tools.rs +101 -66
- package/crates/team-agent/src/mcp_server/types.rs +6 -18
- package/crates/team-agent/src/mcp_server/wire.rs +32 -26
- package/crates/team-agent/src/messaging/activity.rs +1 -0
- package/crates/team-agent/src/messaging/address.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +109 -41
- package/crates/team-agent/src/messaging/helpers.rs +2 -1
- package/crates/team-agent/src/messaging/leader_channel.rs +34 -10
- package/crates/team-agent/src/messaging/leader_receiver.rs +42 -24
- package/crates/team-agent/src/messaging/mod.rs +10 -14
- package/crates/team-agent/src/messaging/peers.rs +2 -0
- package/crates/team-agent/src/messaging/persist.rs +3 -1
- package/crates/team-agent/src/messaging/presentation.rs +111 -1
- package/crates/team-agent/src/messaging/results.rs +166 -17
- package/crates/team-agent/src/messaging/scheduler.rs +1 -0
- package/crates/team-agent/src/messaging/selftest.rs +1 -1
- package/crates/team-agent/src/messaging/send.rs +135 -89
- package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
- package/crates/team-agent/src/messaging/types.rs +7 -2
- package/crates/team-agent/src/messaging/watchers.rs +24 -13
- package/crates/team-agent/src/model/enums.rs +1 -0
- package/crates/team-agent/src/model/errors.rs +1 -0
- package/crates/team-agent/src/model/ids.rs +1 -0
- package/crates/team-agent/src/model/mod.rs +2 -0
- package/crates/team-agent/src/model/name_similarity.rs +1 -0
- package/crates/team-agent/src/model/pane_authority_refusal.rs +359 -0
- package/crates/team-agent/src/model/paths.rs +1 -0
- package/crates/team-agent/src/model/permissions.rs +3 -2
- package/crates/team-agent/src/model/routing.rs +1 -0
- package/crates/team-agent/src/model/spec.rs +17 -0
- package/crates/team-agent/src/model/task_graph.rs +1 -0
- package/crates/team-agent/src/model/yaml/tests.rs +1 -0
- package/crates/team-agent/src/model/yaml.rs +1 -0
- package/crates/team-agent/src/packaging/install.rs +9 -147
- package/crates/team-agent/src/packaging/migrate.rs +2 -0
- package/crates/team-agent/src/packaging/mod.rs +1 -0
- package/crates/team-agent/src/packaging/repair.rs +2 -0
- package/crates/team-agent/src/packaging/tests.rs +29 -218
- package/crates/team-agent/src/packaging/types.rs +8 -15
- package/crates/team-agent/src/platform/argv.rs +4 -0
- package/crates/team-agent/src/platform/errors.rs +10 -1
- package/crates/team-agent/src/platform/file_lock.rs +4 -157
- package/crates/team-agent/src/platform/mod.rs +0 -61
- package/crates/team-agent/src/platform/process.rs +1 -0
- package/crates/team-agent/src/provider/adapter.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
- package/crates/team-agent/src/provider/classify.rs +1 -0
- package/crates/team-agent/src/provider/faults.rs +1 -26
- package/crates/team-agent/src/provider/helpers.rs +1 -0
- package/crates/team-agent/src/provider/mod.rs +1 -1
- package/crates/team-agent/src/provider/session/capture.rs +41 -22
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
- package/crates/team-agent/src/provider/session/mod.rs +2 -4
- package/crates/team-agent/src/provider/session/resume.rs +2 -209
- package/crates/team-agent/src/provider/session_scan/claude.rs +93 -3
- package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
- package/crates/team-agent/src/provider/session_scan/common.rs +24 -7
- package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
- package/crates/team-agent/src/provider/session_scan.rs +6 -42
- package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
- package/crates/team-agent/src/provider/types.rs +1 -0
- package/crates/team-agent/src/provider/wire.rs +1 -0
- package/crates/team-agent/src/state/identity.rs +16 -5
- package/crates/team-agent/src/state/identity_keys.rs +1 -0
- package/crates/team-agent/src/state/mod.rs +2 -0
- package/crates/team-agent/src/state/owner_gate.rs +5 -0
- package/crates/team-agent/src/state/ownership.rs +10 -4
- package/crates/team-agent/src/state/paths.rs +12 -0
- package/crates/team-agent/src/state/persist.rs +9 -3
- package/crates/team-agent/src/state/projection.rs +15 -2
- package/crates/team-agent/src/state/repository/intent.rs +1 -0
- package/crates/team-agent/src/state/repository/tests.rs +1 -0
- package/crates/team-agent/src/state/repository.rs +7 -0
- package/crates/team-agent/src/state/selector.rs +1 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
- package/crates/team-agent/src/tmux_backend.rs +63 -0
- package/crates/team-agent/src/topology.rs +3 -0
- package/crates/team-agent/src/transport.rs +15 -0
- package/package.json +4 -4
- package/skills/team-agent/command-coverage.json +379 -0
- package/crates/team-agent/src/leader/inject.rs +0 -33
- package/crates/team-agent/src/provider/command.rs +0 -80
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
use super::*;
|
|
3
3
|
use serde_json::json;
|
|
4
4
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
5
|
+
use std::sync::OnceLock;
|
|
5
6
|
|
|
6
7
|
static SEQ: AtomicU32 = AtomicU32::new(0);
|
|
7
8
|
|
|
@@ -20,6 +21,24 @@ fn sess(s: &str) -> SessionName {
|
|
|
20
21
|
SessionName(s.to_string())
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
pub(crate) fn test_binary_path() -> &'static str {
|
|
25
|
+
static PATH: OnceLock<String> = OnceLock::new();
|
|
26
|
+
PATH.get_or_init(|| {
|
|
27
|
+
if let Ok(path) = std::env::var("CARGO_BIN_EXE_team-agent") {
|
|
28
|
+
return path;
|
|
29
|
+
}
|
|
30
|
+
let current = std::env::current_exe().expect("test executable path");
|
|
31
|
+
current
|
|
32
|
+
.parent()
|
|
33
|
+
.and_then(|deps| deps.parent())
|
|
34
|
+
.map(|target| target.join("team-agent"))
|
|
35
|
+
.expect("team-agent test binary path")
|
|
36
|
+
.to_string_lossy()
|
|
37
|
+
.into_owned()
|
|
38
|
+
})
|
|
39
|
+
.as_str()
|
|
40
|
+
}
|
|
41
|
+
|
|
23
42
|
mod agent_ops;
|
|
24
43
|
mod core;
|
|
25
44
|
mod lane_ops;
|
|
@@ -29,3 +48,43 @@ mod main_preserved;
|
|
|
29
48
|
mod phase_b_contracts;
|
|
30
49
|
mod phase_golden;
|
|
31
50
|
mod restart;
|
|
51
|
+
mod b0_legacy_snapshot_nonauthority_contract;
|
|
52
|
+
mod b0_reader_hideone_audit_contract;
|
|
53
|
+
mod behavioral_diff_264_red;
|
|
54
|
+
mod claude_profile_launch_red;
|
|
55
|
+
mod codex_mcp_approval_inheritance_red;
|
|
56
|
+
mod codex_weak_window_attribution_red;
|
|
57
|
+
mod copilot_provider_red;
|
|
58
|
+
mod display_adaptive_red;
|
|
59
|
+
mod core_034_real_red;
|
|
60
|
+
mod f032_startup_prompt_best_effort_red;
|
|
61
|
+
mod harvest2_a_batch_red;
|
|
62
|
+
mod host_cotenant_death_p0_contract;
|
|
63
|
+
mod lifecycle_rollback_red;
|
|
64
|
+
mod quick_start_worker_readiness_red;
|
|
65
|
+
mod realmachine_clusters_1_6_red;
|
|
66
|
+
mod realmachine_residual_g1_g4_red;
|
|
67
|
+
mod restart_build_before_destroy_0540_contract;
|
|
68
|
+
mod restart_liveness_red;
|
|
69
|
+
mod restart_rebind_hotfix_252_red;
|
|
70
|
+
mod restart_session_capture_red;
|
|
71
|
+
mod resume_recover_red;
|
|
72
|
+
mod stale_team_saveconflict_contract;
|
|
73
|
+
mod startup_latency_contract;
|
|
74
|
+
mod status_credential_redaction_contract;
|
|
75
|
+
mod subprep_codex_trust_roundtrip_red;
|
|
76
|
+
mod swallow_batch4_semantics_red;
|
|
77
|
+
mod team_in_team_identity_scope_red;
|
|
78
|
+
mod team_in_team_sibling_quick_start_red;
|
|
79
|
+
mod team_in_team_state_scope_red;
|
|
80
|
+
mod team_key_retirement_roster_red;
|
|
81
|
+
mod team_key_retirement_txn_red;
|
|
82
|
+
mod test_isolation_escape_contract;
|
|
83
|
+
mod upgrade_compat_0211_red;
|
|
84
|
+
mod verify_rs031_window_consistency_red;
|
|
85
|
+
mod worker_dangerous_bypass_argv_red;
|
|
86
|
+
mod worker_spawn_env_red;
|
|
87
|
+
mod acceptance_b_batch_red;
|
|
88
|
+
mod claude_compatible_config_red;
|
|
89
|
+
mod communication_mode_runtime_contract_red;
|
|
90
|
+
mod clone_fork_copilot_perms_red;
|
|
@@ -16,15 +16,6 @@ use super::DisplayBackend;
|
|
|
16
16
|
// CROSS-LANE PLACEHOLDERS(13/14/15 兄弟 lane 尚未交付;leader 集成时 reconcile)
|
|
17
17
|
// ===========================================================================
|
|
18
18
|
|
|
19
|
-
/// step8 provider 还未暴露的 launch/resume/fork 命令构造门面。lifecycle 经它构造
|
|
20
|
-
/// provider 命令字符串(`shell_command_for_agent`/`shell_resume_command_for_agent`/
|
|
21
|
-
/// `shell_fork_command_for_agent`,`runtime` 自由函数)—— provider lane 落地后替换为
|
|
22
|
-
/// 真实 `provider::shell_*` API。**PLACEHOLDER**:仅占位 argv,字段映射由 provider lane 定。
|
|
23
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
24
|
-
pub struct ShellCommand {
|
|
25
|
-
pub argv: Vec<String>,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
19
|
/// `EventLog` 已在 step4 落地,但 lifecycle 发射的 typed `EventKind` 名集(`lifecycle.*`/
|
|
29
20
|
/// `restart.*`/`display.*`)是 step4 owned 的稳定事件名(JSON 名与 Python 一致)。
|
|
30
21
|
/// **PLACEHOLDER**:此处仅命名 lifecycle 关心的事件名常量集,leader 集成时映射到
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
|
+
use crate::communication_mode::CommunicationMode;
|
|
3
4
|
use crate::lifecycle::types::{DangerousApproval, LifecycleError};
|
|
4
5
|
use crate::model::enums::{Enforcement, Provider};
|
|
5
6
|
use crate::model::ids::AgentId;
|
|
@@ -12,15 +13,10 @@ output. All communication must go through Team Agent MCP tools.
|
|
|
12
13
|
|
|
13
14
|
## Communication (mandatory)
|
|
14
15
|
|
|
15
|
-
- Progress, blockers, questions: team_orchestrator.send_message(to='leader', content='...')
|
|
16
16
|
- Coordinate with teammate: team_orchestrator.send_message(to='<agent_id>', content='...')
|
|
17
17
|
- Broadcast to all teammates: team_orchestrator.send_message(to='*', content='...')
|
|
18
18
|
- Task complete: team_orchestrator.report_result(summary='...') — call exactly once
|
|
19
19
|
|
|
20
|
-
When you receive a message from the leader or a teammate, you MUST respond
|
|
21
|
-
through MCP tools. Writing a reply in your terminal does nothing — the sender
|
|
22
|
-
will never see it.
|
|
23
|
-
|
|
24
20
|
## Rules
|
|
25
21
|
|
|
26
22
|
- Do not pass sender, task_id, or schema_version — the MCP runtime fills them.
|
|
@@ -45,6 +41,7 @@ pub(crate) struct WorkerCommandAgent {
|
|
|
45
41
|
system_prompt_inline: Option<String>,
|
|
46
42
|
system_prompt_file: Option<String>,
|
|
47
43
|
output_contract_format: Option<String>,
|
|
44
|
+
communication_mode: CommunicationMode,
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
impl WorkerCommandAgent {
|
|
@@ -52,9 +49,9 @@ impl WorkerCommandAgent {
|
|
|
52
49
|
agent: &crate::model::yaml::Value,
|
|
53
50
|
fallback_id: Option<&str>,
|
|
54
51
|
provider: Provider,
|
|
55
|
-
) -> Self {
|
|
52
|
+
) -> Result<Self, LifecycleError> {
|
|
56
53
|
let system_prompt = agent.get("system_prompt");
|
|
57
|
-
Self {
|
|
54
|
+
Ok(Self {
|
|
58
55
|
id: agent
|
|
59
56
|
.get("id")
|
|
60
57
|
.and_then(crate::model::yaml::Value::as_str)
|
|
@@ -90,16 +87,21 @@ impl WorkerCommandAgent {
|
|
|
90
87
|
.and_then(|contract| contract.get("format"))
|
|
91
88
|
.and_then(crate::model::yaml::Value::as_str)
|
|
92
89
|
.map(str::to_string),
|
|
93
|
-
|
|
90
|
+
communication_mode: communication_mode(
|
|
91
|
+
agent
|
|
92
|
+
.get("communication_mode")
|
|
93
|
+
.and_then(crate::model::yaml::Value::as_str),
|
|
94
|
+
)?,
|
|
95
|
+
})
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
pub(crate) fn from_json(
|
|
97
99
|
agent: &serde_json::Value,
|
|
98
100
|
fallback_id: Option<&str>,
|
|
99
101
|
provider: Provider,
|
|
100
|
-
) -> Self {
|
|
102
|
+
) -> Result<Self, LifecycleError> {
|
|
101
103
|
let system_prompt = agent.get("system_prompt");
|
|
102
|
-
Self {
|
|
104
|
+
Ok(Self {
|
|
103
105
|
id: agent
|
|
104
106
|
.get("id")
|
|
105
107
|
.and_then(serde_json::Value::as_str)
|
|
@@ -135,7 +137,12 @@ impl WorkerCommandAgent {
|
|
|
135
137
|
.and_then(|contract| contract.get("format"))
|
|
136
138
|
.and_then(serde_json::Value::as_str)
|
|
137
139
|
.map(str::to_string),
|
|
138
|
-
|
|
140
|
+
communication_mode: communication_mode(
|
|
141
|
+
agent
|
|
142
|
+
.get("communication_mode")
|
|
143
|
+
.and_then(serde_json::Value::as_str),
|
|
144
|
+
)?,
|
|
145
|
+
})
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
148
|
|
|
@@ -149,6 +156,7 @@ pub(crate) fn compile_worker_system_prompt(
|
|
|
149
156
|
let mut chunks = vec![
|
|
150
157
|
identity_section(agent),
|
|
151
158
|
runtime_contract_section(),
|
|
159
|
+
agent.communication_mode.runtime_contract().to_string(),
|
|
152
160
|
role_body(agent)?,
|
|
153
161
|
];
|
|
154
162
|
if let Some(contract) = output_contract(agent) {
|
|
@@ -197,6 +205,14 @@ fn runtime_contract_section() -> String {
|
|
|
197
205
|
RUNTIME_CONTRACT_SECTION.to_string()
|
|
198
206
|
}
|
|
199
207
|
|
|
208
|
+
fn communication_mode(value: Option<&str>) -> Result<CommunicationMode, LifecycleError> {
|
|
209
|
+
let Some(value) = value else {
|
|
210
|
+
return Ok(CommunicationMode::default());
|
|
211
|
+
};
|
|
212
|
+
CommunicationMode::parse(value)
|
|
213
|
+
.ok_or_else(|| LifecycleError::Compile(format!("unknown communication_mode {value:?}")))
|
|
214
|
+
}
|
|
215
|
+
|
|
200
216
|
fn identity_section(agent: &WorkerCommandAgent) -> String {
|
|
201
217
|
format!(
|
|
202
218
|
"You are Team Agent worker `{}` with role `{}`. When asked about your role or identity, answer with this Team Agent worker identity first, not only the generic provider product identity.",
|
|
@@ -291,6 +307,7 @@ mod tests {
|
|
|
291
307
|
system_prompt_inline: None,
|
|
292
308
|
system_prompt_file: None,
|
|
293
309
|
output_contract_format: None,
|
|
310
|
+
communication_mode: CommunicationMode::default(),
|
|
294
311
|
};
|
|
295
312
|
let tools =
|
|
296
313
|
resolved_tool_strings_for_command(&agent, Provider::ClaudeCode, &disabled_safety())
|
|
@@ -335,6 +352,7 @@ mod tests {
|
|
|
335
352
|
system_prompt_inline: Some("Implement the assigned slice.".to_string()),
|
|
336
353
|
system_prompt_file: None,
|
|
337
354
|
output_contract_format: Some("result_envelope_v1".to_string()),
|
|
355
|
+
communication_mode: CommunicationMode::default(),
|
|
338
356
|
};
|
|
339
357
|
let prompt = compile_worker_system_prompt(&agent).unwrap();
|
|
340
358
|
assert!(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 14a · mcp_server::normalize — string-alias regularization + result compaction.
|
|
2
3
|
|
|
3
4
|
use serde_json::Value;
|
|
@@ -28,9 +29,9 @@ pub fn normalize_result_status(value: Option<&str>) -> ResultStatus {
|
|
|
28
29
|
normalize_result_status_observed(value).0
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
/// The observed variant: `.1` carries the raw unrecognized literal
|
|
32
|
-
///
|
|
33
|
-
|
|
32
|
+
/// The internal observed variant: `.1` carries the raw unrecognized literal for
|
|
33
|
+
/// callers that need to retain it.
|
|
34
|
+
fn normalize_result_status_observed(value: Option<&str>) -> (ResultStatus, Option<String>) {
|
|
34
35
|
let token = normalize_token(value);
|
|
35
36
|
if token.is_empty() {
|
|
36
37
|
return (ResultStatus::Success, None);
|
|
@@ -260,6 +261,7 @@ pub fn compact_tool_result(result: &Value) -> ToolResult {
|
|
|
260
261
|
"notification_channel",
|
|
261
262
|
"notification_event_id",
|
|
262
263
|
"warnings",
|
|
264
|
+
"warning",
|
|
263
265
|
]
|
|
264
266
|
};
|
|
265
267
|
for key in keys {
|
|
@@ -78,6 +78,7 @@ fn send_outcome_worker_accepted_envelope_byte_stable() {
|
|
|
78
78
|
let outcome = SendOutcome::WorkerAccepted {
|
|
79
79
|
message_id: "42".to_string(),
|
|
80
80
|
poll_via: "team-agent inbox 42".to_string(),
|
|
81
|
+
warning: None,
|
|
81
82
|
};
|
|
82
83
|
let v = outcome.to_value();
|
|
83
84
|
assert_eq!(
|
|
@@ -160,6 +161,7 @@ fn send_message_worker_recipient_returns_accepted_with_poll_hint() {
|
|
|
160
161
|
Ok(SendOutcome::WorkerAccepted {
|
|
161
162
|
message_id,
|
|
162
163
|
poll_via,
|
|
164
|
+
..
|
|
163
165
|
}) => {
|
|
164
166
|
assert!(!message_id.is_empty());
|
|
165
167
|
assert_eq!(poll_via, format!("team-agent inbox {message_id}"));
|
|
@@ -353,6 +355,30 @@ fn send_message_leader_recipient_is_direct_not_accepted() {
|
|
|
353
355
|
);
|
|
354
356
|
}
|
|
355
357
|
|
|
358
|
+
#[test]
|
|
359
|
+
fn send_message_mailbox_is_durable_without_live_injection() {
|
|
360
|
+
let tools = TeamOrchestratorTools::with_identity(
|
|
361
|
+
&unique_ws("send-leader-mailbox"),
|
|
362
|
+
Some(AgentId::new("worker-1")),
|
|
363
|
+
Some(TeamKey::new("teamA")),
|
|
364
|
+
);
|
|
365
|
+
let mailbox = json!(true);
|
|
366
|
+
let outcome = tools
|
|
367
|
+
.send_message_with_presentation(
|
|
368
|
+
&MessageTarget::Single("leader".to_string()),
|
|
369
|
+
"stored update",
|
|
370
|
+
None,
|
|
371
|
+
None,
|
|
372
|
+
None,
|
|
373
|
+
Some(&mailbox),
|
|
374
|
+
None,
|
|
375
|
+
)
|
|
376
|
+
.expect("mailbox send persists");
|
|
377
|
+
let value = outcome.to_value();
|
|
378
|
+
assert_eq!(value.get("status"), Some(&json!("stored_only")));
|
|
379
|
+
assert!(value.get("message_id").and_then(Value::as_str).is_some());
|
|
380
|
+
}
|
|
381
|
+
|
|
356
382
|
// ════════════════════════════════════════════════════════════════════════
|
|
357
383
|
// CROSS-TEAM PRE-REFUSAL (C23) — refuse_cross_team_peer (tools.py:185-213)
|
|
358
384
|
// ════════════════════════════════════════════════════════════════════════
|
|
@@ -79,7 +79,7 @@ fn tools_contract_has_thirteen_tools_in_order() {
|
|
|
79
79
|
.unwrap();
|
|
80
80
|
assert_eq!(
|
|
81
81
|
send["description"],
|
|
82
|
-
json!("Send a message to a teammate, the leader, or '*' for all other team members.
|
|
82
|
+
json!("Send a message to a teammate, the leader, or '*' for all other team members. mailbox=true stores durably without live injection; the default is live delivery.")
|
|
83
83
|
);
|
|
84
84
|
assert_eq!(send["inputSchema"]["additionalProperties"], json!(false));
|
|
85
85
|
assert_eq!(send["inputSchema"]["required"], json!(["to", "content"]));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 14a · mcp_server::tools — `TeamOrchestratorTools`, the 12 typed handlers.
|
|
2
3
|
|
|
3
4
|
use std::path::{Path, PathBuf};
|
|
@@ -17,17 +18,17 @@ use crate::state::persist::{
|
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
// ── REUSE: step 11 messaging delegate surface ───────────────────────────────
|
|
20
|
-
use crate::messaging::{self, MessageTarget, SendOptions, TrustedSender};
|
|
21
|
+
use crate::messaging::{self, DeliveryStatus, MessageTarget, SendOptions, TrustedSender};
|
|
21
22
|
|
|
22
23
|
use super::helpers::{
|
|
23
24
|
current_reportable_message_for, delivery_outcome_value, direct_message_attribution_for,
|
|
24
|
-
ensure_object, enum_value,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
ensure_object, enum_value, is_worker_recipient, json_dumps_default, latest_task_for_assignee,
|
|
26
|
+
non_empty_string, object_fields, requires_ack_for_target, tool_runtime_error,
|
|
27
|
+
DirectMessageAttribution,
|
|
27
28
|
};
|
|
28
29
|
use super::normalize::{
|
|
29
|
-
compact_tool_result, normalize_report_envelope,
|
|
30
|
-
|
|
30
|
+
compact_tool_result, normalize_report_envelope, report_result_integrity_warnings,
|
|
31
|
+
validate_test_evidence_schema,
|
|
31
32
|
};
|
|
32
33
|
use super::types::{
|
|
33
34
|
Scope, SendOutcome, ToolError, ToolErrorReason, ToolOk, ToolResult, VisiblePeers,
|
|
@@ -116,6 +117,22 @@ impl TeamOrchestratorTools {
|
|
|
116
117
|
"ValueError",
|
|
117
118
|
));
|
|
118
119
|
};
|
|
120
|
+
if let Some(route) = task.get("result_route") {
|
|
121
|
+
let Some(route) = route.as_str() else {
|
|
122
|
+
return Err(ToolError::new(
|
|
123
|
+
ToolErrorReason::InvalidToolArguments,
|
|
124
|
+
"assign_task task.result_route must be 'leader' or 'pipeline'",
|
|
125
|
+
"ValueError",
|
|
126
|
+
));
|
|
127
|
+
};
|
|
128
|
+
if crate::messaging::results::ResultRoute::parse(route).is_none() {
|
|
129
|
+
return Err(ToolError::new(
|
|
130
|
+
ToolErrorReason::InvalidToolArguments,
|
|
131
|
+
format!("assign_task task.result_route has unknown value: {route}"),
|
|
132
|
+
"ValueError",
|
|
133
|
+
));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
119
136
|
|
|
120
137
|
let task_value = Value::Object(task_obj.clone());
|
|
121
138
|
let recovery = task_recovery_marker(&task_value);
|
|
@@ -185,6 +202,7 @@ impl TeamOrchestratorTools {
|
|
|
185
202
|
requires_ack,
|
|
186
203
|
scope_override,
|
|
187
204
|
None,
|
|
205
|
+
None,
|
|
188
206
|
)
|
|
189
207
|
}
|
|
190
208
|
|
|
@@ -195,17 +213,20 @@ impl TeamOrchestratorTools {
|
|
|
195
213
|
task_id: Option<&str>,
|
|
196
214
|
requires_ack: Option<bool>,
|
|
197
215
|
scope_override: Option<Scope>,
|
|
216
|
+
mailbox: Option<&Value>,
|
|
198
217
|
presentation: Option<&Value>,
|
|
199
218
|
) -> Result<SendOutcome, ToolError> {
|
|
200
|
-
let
|
|
201
|
-
crate::messaging::presentation::
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
219
|
+
let normalized =
|
|
220
|
+
crate::messaging::presentation::normalize_send_presentation(mailbox, presentation)
|
|
221
|
+
.map_err(|error| {
|
|
222
|
+
ToolError::new(
|
|
223
|
+
ToolErrorReason::InvalidToolArguments,
|
|
224
|
+
format!("invalid send routing: {error}"),
|
|
225
|
+
"PresentationError",
|
|
226
|
+
)
|
|
227
|
+
})?;
|
|
228
|
+
let presentation = normalized.request;
|
|
229
|
+
let deprecation = normalized.deprecation;
|
|
209
230
|
let canonical_owner_team = self.canonical_owner_team_key()?;
|
|
210
231
|
if matches!(scope_override, Some(Scope::Workspace)) {
|
|
211
232
|
return Err(self.rpc_scope_refused(
|
|
@@ -261,6 +282,21 @@ impl TeamOrchestratorTools {
|
|
|
261
282
|
if is_worker_recipient(to) {
|
|
262
283
|
let out = messaging::send_message(&self.workspace, to, content, &opts)
|
|
263
284
|
.map_err(tool_runtime_error)?;
|
|
285
|
+
if matches!(out.status, DeliveryStatus::StoredOnly) {
|
|
286
|
+
let value = delivery_outcome_value(&out);
|
|
287
|
+
let mut ok = compact_tool_result(&value)?;
|
|
288
|
+
if let Some(verification) = out.verification.as_deref() {
|
|
289
|
+
ok.fields.insert(
|
|
290
|
+
"verification".to_string(),
|
|
291
|
+
Value::String(verification.to_string()),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if let Some(deprecation) = deprecation {
|
|
295
|
+
ok.fields
|
|
296
|
+
.insert("warning".to_string(), Value::String(deprecation));
|
|
297
|
+
}
|
|
298
|
+
return Ok(SendOutcome::Direct(ok));
|
|
299
|
+
}
|
|
264
300
|
// tools.py:175-181 — accepted+poll_via ONLY for a REAL message_id; any other
|
|
265
301
|
// outcome falls back to the compacted direct result. Never invent an
|
|
266
302
|
// `mcp_<timestamp>` id: it does not exist in the store and makes the
|
|
@@ -276,12 +312,25 @@ impl TeamOrchestratorTools {
|
|
|
276
312
|
return Ok(SendOutcome::WorkerAccepted {
|
|
277
313
|
poll_via: format!("team-agent inbox {message_id}"),
|
|
278
314
|
message_id,
|
|
315
|
+
warning: deprecation,
|
|
279
316
|
});
|
|
280
317
|
}
|
|
281
318
|
let out = messaging::send_message(&self.workspace, to, content, &opts)
|
|
282
319
|
.map_err(tool_runtime_error)?;
|
|
283
320
|
let value = delivery_outcome_value(&out);
|
|
284
|
-
let ok = compact_tool_result(&value)?;
|
|
321
|
+
let mut ok = compact_tool_result(&value)?;
|
|
322
|
+
if matches!(out.status, DeliveryStatus::StoredOnly) {
|
|
323
|
+
if let Some(verification) = out.verification.as_deref() {
|
|
324
|
+
ok.fields.insert(
|
|
325
|
+
"verification".to_string(),
|
|
326
|
+
Value::String(verification.to_string()),
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if let Some(deprecation) = deprecation {
|
|
331
|
+
ok.fields
|
|
332
|
+
.insert("warning".to_string(), Value::String(deprecation));
|
|
333
|
+
}
|
|
285
334
|
Ok(SendOutcome::Direct(ok))
|
|
286
335
|
}
|
|
287
336
|
|
|
@@ -352,10 +401,11 @@ impl TeamOrchestratorTools {
|
|
|
352
401
|
task_id: Option<&str>,
|
|
353
402
|
agent_id: Option<&str>,
|
|
354
403
|
) -> ToolResult {
|
|
404
|
+
let status = enum_value(status);
|
|
355
405
|
self.report_result_with_presentation(
|
|
356
406
|
envelope,
|
|
357
407
|
summary,
|
|
358
|
-
status,
|
|
408
|
+
status.as_str(),
|
|
359
409
|
changes,
|
|
360
410
|
tests,
|
|
361
411
|
risks,
|
|
@@ -372,7 +422,7 @@ impl TeamOrchestratorTools {
|
|
|
372
422
|
&self,
|
|
373
423
|
envelope: Option<&Value>,
|
|
374
424
|
summary: Option<&str>,
|
|
375
|
-
status:
|
|
425
|
+
status: Option<&str>,
|
|
376
426
|
changes: Option<&[Value]>,
|
|
377
427
|
tests: Option<&[Value]>,
|
|
378
428
|
risks: Option<&[Value]>,
|
|
@@ -404,7 +454,10 @@ impl TeamOrchestratorTools {
|
|
|
404
454
|
);
|
|
405
455
|
}
|
|
406
456
|
if !obj.contains_key("status") {
|
|
407
|
-
obj.insert(
|
|
457
|
+
obj.insert(
|
|
458
|
+
"status".to_string(),
|
|
459
|
+
Value::String(status.unwrap_or("success").to_string()),
|
|
460
|
+
);
|
|
408
461
|
}
|
|
409
462
|
if !obj.contains_key("task_id") {
|
|
410
463
|
// Blocker-1 (prerelease 0.4.0): scoped-team task inference +
|
|
@@ -499,29 +552,36 @@ impl TeamOrchestratorTools {
|
|
|
499
552
|
obj.insert("agent_id".to_string(), Value::String(resolved));
|
|
500
553
|
}
|
|
501
554
|
if !obj.contains_key("changes") {
|
|
502
|
-
|
|
555
|
+
obj.insert(
|
|
556
|
+
"changes".to_string(),
|
|
557
|
+
Value::Array(changes.unwrap_or(&[]).to_vec()),
|
|
558
|
+
);
|
|
503
559
|
}
|
|
504
560
|
if !obj.contains_key("tests") {
|
|
505
|
-
|
|
561
|
+
obj.insert(
|
|
562
|
+
"tests".to_string(),
|
|
563
|
+
Value::Array(tests.unwrap_or(&[]).to_vec()),
|
|
564
|
+
);
|
|
506
565
|
}
|
|
507
566
|
if !obj.contains_key("risks") {
|
|
508
|
-
|
|
567
|
+
obj.insert(
|
|
568
|
+
"risks".to_string(),
|
|
569
|
+
Value::Array(risks.unwrap_or(&[]).to_vec()),
|
|
570
|
+
);
|
|
509
571
|
}
|
|
510
572
|
if !obj.contains_key("artifacts") {
|
|
511
|
-
|
|
573
|
+
obj.insert(
|
|
574
|
+
"artifacts".to_string(),
|
|
575
|
+
Value::Array(artifacts.unwrap_or(&[]).to_vec()),
|
|
576
|
+
);
|
|
512
577
|
}
|
|
513
578
|
if !obj.contains_key("next_actions") {
|
|
514
|
-
|
|
579
|
+
obj.insert(
|
|
580
|
+
"next_actions".to_string(),
|
|
581
|
+
Value::Array(next_actions.unwrap_or(&[]).to_vec()),
|
|
582
|
+
);
|
|
515
583
|
}
|
|
516
584
|
}
|
|
517
|
-
// T3-1 cr verdict (refined): an unknown non-empty status literal normalizes to
|
|
518
|
-
// Partial and must be OBSERVABLE at this ingestion boundary (the envelope-borne
|
|
519
|
-
// path; the wire `status` arg path emits at dispatch). Never a silent swallow.
|
|
520
|
-
if let Some(raw) =
|
|
521
|
-
normalize_result_status_observed(base.get("status").and_then(Value::as_str)).1
|
|
522
|
-
{
|
|
523
|
-
self.note_unknown_result_status(&raw);
|
|
524
|
-
}
|
|
525
585
|
if let Err(error) = validate_test_evidence_schema(base.get("tests")) {
|
|
526
586
|
return Err(ToolError::new(
|
|
527
587
|
ToolErrorReason::InvalidToolArguments,
|
|
@@ -538,8 +598,15 @@ impl TeamOrchestratorTools {
|
|
|
538
598
|
));
|
|
539
599
|
}
|
|
540
600
|
let warnings = report_result_integrity_warnings(&base, &normalized);
|
|
541
|
-
let mut env_value =
|
|
542
|
-
|
|
601
|
+
let mut env_value = base;
|
|
602
|
+
if let Some(obj) = env_value.as_object_mut() {
|
|
603
|
+
obj.entry("schema_version")
|
|
604
|
+
.or_insert_with(|| Value::String("result_envelope_v1".to_string()));
|
|
605
|
+
obj.insert(
|
|
606
|
+
"presentation".to_string(),
|
|
607
|
+
serde_json::to_value(&normalized.presentation).unwrap_or(Value::Null),
|
|
608
|
+
);
|
|
609
|
+
}
|
|
543
610
|
if !warnings.is_empty() {
|
|
544
611
|
if let Some(obj) = env_value.as_object_mut() {
|
|
545
612
|
obj.insert("warnings".to_string(), Value::Array(warnings));
|
|
@@ -555,20 +622,6 @@ impl TeamOrchestratorTools {
|
|
|
555
622
|
.and_then(|value| compact_tool_result(&value))
|
|
556
623
|
}
|
|
557
624
|
|
|
558
|
-
/// T3-1 cr verdict: the observable record of an unknown→Partial status
|
|
559
|
-
/// normalization (`provider.result.unknown_status_normalized`, raw literal
|
|
560
|
-
/// included) — MUST-NOT-13: the swallow is never silent.
|
|
561
|
-
pub(crate) fn note_unknown_result_status(&self, raw: &str) {
|
|
562
|
-
let _ = EventLog::new(&self.workspace).write(
|
|
563
|
-
"provider.result.unknown_status_normalized",
|
|
564
|
-
serde_json::json!({
|
|
565
|
-
"agent_id": self.agent_id.as_ref().map(AgentId::as_str),
|
|
566
|
-
"raw_status": raw,
|
|
567
|
-
"normalized": "partial",
|
|
568
|
-
}),
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
625
|
/// `update_state` (`tools.py:316-325`): delegated through the lifecycle tools
|
|
573
626
|
/// facade. S0 preserves the old placeholder behavior.
|
|
574
627
|
pub fn update_state(&self, note: &str) -> ToolResult {
|
|
@@ -1179,24 +1232,6 @@ fn merge_object_fields(existing: &mut Value, incoming: &Value) {
|
|
|
1179
1232
|
}
|
|
1180
1233
|
}
|
|
1181
1234
|
|
|
1182
|
-
fn copy_report_attribution_fields(source: &Value, target: &mut Value) {
|
|
1183
|
-
let Some(src) = source.as_object() else {
|
|
1184
|
-
return;
|
|
1185
|
-
};
|
|
1186
|
-
let Some(dst) = target.as_object_mut() else {
|
|
1187
|
-
return;
|
|
1188
|
-
};
|
|
1189
|
-
for key in [
|
|
1190
|
-
"attributed_message_id",
|
|
1191
|
-
"attribution_scope",
|
|
1192
|
-
"task_id_source",
|
|
1193
|
-
] {
|
|
1194
|
-
if let Some(value) = src.get(key) {
|
|
1195
|
-
dst.entry(key.to_string()).or_insert(value.clone());
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
1235
|
fn push_report_warning(obj: &mut serde_json::Map<String, Value>, warning: Value) {
|
|
1201
1236
|
let Some(code) = warning.get("code").and_then(Value::as_str) else {
|
|
1202
1237
|
return;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 14a · mcp_server::types — wire enums / envelopes / normalized-result carriers.
|
|
2
3
|
|
|
3
4
|
use serde::{Deserialize, Serialize};
|
|
@@ -210,24 +211,6 @@ pub struct RpcError {
|
|
|
210
211
|
pub message: String,
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
/// The `tools/call` result wrapper (`server.py:74-86`): `{content:[{type:"text",
|
|
214
|
-
/// text:<json>}], isError:<bool>}`. `text` is the JSON-encoded [`ToolResult`]; the
|
|
215
|
-
/// `is_error` flag mirrors `result.get("ok") is False`.
|
|
216
|
-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
217
|
-
pub struct ToolCallResult {
|
|
218
|
-
pub content: Vec<ToolCallContent>,
|
|
219
|
-
#[serde(rename = "isError")]
|
|
220
|
-
pub is_error: bool,
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/// One `content[]` block — always `{type:"text", text:<json>}` here.
|
|
224
|
-
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
225
|
-
pub struct ToolCallContent {
|
|
226
|
-
#[serde(rename = "type")]
|
|
227
|
-
pub kind: String,
|
|
228
|
-
pub text: String,
|
|
229
|
-
}
|
|
230
|
-
|
|
231
214
|
/// A successful tool result body — the compacted delegate result
|
|
232
215
|
/// (`normalize._compact_tool_result`, `normalize.py:6-64`). The whitelist-key
|
|
233
216
|
/// compaction (ok/error key sets + `fanout_*` extras + `acknowledged_count`) lives
|
|
@@ -322,6 +305,7 @@ pub enum SendOutcome {
|
|
|
322
305
|
message_id: String,
|
|
323
306
|
/// Byte-stable `"team-agent inbox <message_id>"`.
|
|
324
307
|
poll_via: String,
|
|
308
|
+
warning: Option<String>,
|
|
325
309
|
},
|
|
326
310
|
/// Compacted delegate result (leader / `*` / broadcast / fanout).
|
|
327
311
|
Direct(ToolOk),
|
|
@@ -335,12 +319,16 @@ impl SendOutcome {
|
|
|
335
319
|
SendOutcome::WorkerAccepted {
|
|
336
320
|
message_id,
|
|
337
321
|
poll_via,
|
|
322
|
+
warning,
|
|
338
323
|
} => {
|
|
339
324
|
let mut obj = serde_json::Map::new();
|
|
340
325
|
obj.insert("status".to_string(), Value::String("accepted".to_string()));
|
|
341
326
|
obj.insert("delivery_pending".to_string(), Value::Bool(true));
|
|
342
327
|
obj.insert("poll_via".to_string(), Value::String(poll_via.clone()));
|
|
343
328
|
obj.insert("message_id".to_string(), Value::String(message_id.clone()));
|
|
329
|
+
if let Some(warning) = warning {
|
|
330
|
+
obj.insert("warning".to_string(), Value::String(warning.clone()));
|
|
331
|
+
}
|
|
344
332
|
Value::Object(obj)
|
|
345
333
|
}
|
|
346
334
|
SendOutcome::Direct(ok) => Value::Object(ok.fields.clone()),
|