@sema-agent/server 1.323.0 → 2.0.1
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/dist/approval-hmac.d.ts +40 -0
- package/dist/approval-hmac.js +67 -0
- package/dist/approval.d.ts +31 -0
- package/dist/approval.js +72 -4
- package/dist/audit.d.ts +26 -0
- package/dist/audit.js +40 -1
- package/dist/auth-bridge.d.ts +10 -0
- package/dist/auth-bridge.js +47 -4
- package/dist/auth-keys.d.ts +19 -0
- package/dist/auth-keys.js +13 -0
- package/dist/bake-runner/main.d.ts +5 -0
- package/dist/bake-runner/main.js +43 -4
- package/dist/bake-runner/protocol.d.ts +57 -0
- package/dist/bake-runner/protocol.js +58 -3
- package/dist/bake-runner/runner.d.ts +54 -0
- package/dist/bake-runner/runner.js +87 -5
- package/dist/bench/l8/artifact.d.ts +63 -0
- package/dist/bench/l8/artifact.js +61 -2
- package/dist/bench/l8/escape.d.ts +36 -0
- package/dist/bench/l8/escape.js +25 -0
- package/dist/bench/l8/index.d.ts +14 -0
- package/dist/bench/l8/index.js +14 -0
- package/dist/bench/l8/probes.d.ts +74 -0
- package/dist/bench/l8/probes.js +60 -0
- package/dist/bench/l8/run-probes.d.ts +43 -0
- package/dist/bench/l8/run-probes.js +45 -2
- package/dist/bench/s1/arms.d.ts +126 -0
- package/dist/bench/s1/arms.js +188 -13
- package/dist/bench/s1/live-deps.d.ts +66 -0
- package/dist/bench/s1/live-deps.js +249 -11
- package/dist/bench/s1/oracle.d.ts +49 -0
- package/dist/bench/s1/oracle.js +36 -1
- package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
- package/dist/bench/s1/repair-oracle-adapter.js +30 -0
- package/dist/bench/s1/reviewer.d.ts +38 -0
- package/dist/bench/s1/reviewer.js +34 -0
- package/dist/bench/s1/row.d.ts +77 -0
- package/dist/bench/s1/row.js +62 -0
- package/dist/bench/s1/run-firm.d.ts +47 -0
- package/dist/bench/s1/run-firm.js +70 -4
- package/dist/bench/s1/runner-ctx.d.ts +71 -0
- package/dist/bench/s1/runner-ctx.js +36 -0
- package/dist/bench/s1/tasks.d.ts +108 -0
- package/dist/bench/s1/tasks.js +115 -0
- package/dist/boot/budget-tracing.d.ts +48 -0
- package/dist/boot/budget-tracing.js +86 -0
- package/dist/boot/config-center.d.ts +62 -0
- package/dist/boot/config-center.js +995 -0
- package/dist/boot/coordinators.d.ts +33 -0
- package/dist/boot/coordinators.js +97 -0
- package/dist/boot/execution-env.d.ts +26 -0
- package/dist/boot/execution-env.js +370 -0
- package/dist/boot/leader.d.ts +27 -0
- package/dist/boot/leader.js +81 -0
- package/dist/boot/reapers.d.ts +53 -0
- package/dist/boot/reapers.js +252 -0
- package/dist/boot/resolve-spec.d.ts +70 -0
- package/dist/boot/resolve-spec.js +1072 -0
- package/dist/boot/runner-deps.d.ts +101 -0
- package/dist/boot/runner-deps.js +343 -0
- package/dist/boot/runtime-caps.d.ts +21 -0
- package/dist/boot/runtime-caps.js +62 -0
- package/dist/boot/session-faces.d.ts +57 -0
- package/dist/boot/session-faces.js +157 -0
- package/dist/boot/shutdown.d.ts +50 -0
- package/dist/boot/shutdown.js +129 -0
- package/dist/boot/stores.d.ts +32 -0
- package/dist/boot/stores.js +361 -0
- package/dist/boot/workflow-orchestration.d.ts +46 -0
- package/dist/boot/workflow-orchestration.js +150 -0
- package/dist/boot-reclaim.d.ts +19 -0
- package/dist/boot-reclaim.js +20 -0
- package/dist/brain.d.ts +25 -0
- package/dist/brain.js +61 -1
- package/dist/budget.d.ts +66 -0
- package/dist/budget.js +128 -4
- package/dist/capabilities/builtin-tools.d.ts +3 -0
- package/dist/capabilities/builtin-tools.js +3 -0
- package/dist/capabilities/center-plugins.d.ts +17 -1
- package/dist/capabilities/center-plugins.js +45 -4
- package/dist/capabilities/center-prompts.d.ts +46 -0
- package/dist/capabilities/center-prompts.js +57 -3
- package/dist/capabilities/code-review-council.d.ts +28 -0
- package/dist/capabilities/code-review-council.js +40 -7
- package/dist/capabilities/collab-wire.d.ts +2 -0
- package/dist/capabilities/collab-workflows.d.ts +7 -0
- package/dist/capabilities/collab-workflows.js +44 -1
- package/dist/capabilities/oa-tools.d.ts +6 -0
- package/dist/capabilities/oa-tools.js +10 -0
- package/dist/capabilities/prompt.d.ts +14 -0
- package/dist/capabilities/prompt.js +14 -0
- package/dist/capabilities/prompts/code-review.d.ts +14 -0
- package/dist/capabilities/prompts/code-review.js +14 -0
- package/dist/capabilities/prompts/identity.d.ts +6 -0
- package/dist/capabilities/prompts/identity.js +6 -0
- package/dist/capabilities/prompts/team.d.ts +4 -0
- package/dist/capabilities/prompts/team.js +4 -0
- package/dist/capabilities/repo-tools.d.ts +11 -0
- package/dist/capabilities/repo-tools.js +8 -0
- package/dist/capabilities/sandbox-file-send.d.ts +95 -0
- package/dist/capabilities/sandbox-file-send.js +91 -3
- package/dist/capabilities/scenarios.d.ts +130 -0
- package/dist/capabilities/scenarios.js +180 -7
- package/dist/capabilities/select-environment-tool.d.ts +7 -0
- package/dist/capabilities/select-environment-tool.js +30 -0
- package/dist/capabilities/send-user-file-tool.d.ts +33 -0
- package/dist/capabilities/send-user-file-tool.js +65 -1
- package/dist/capabilities/skills.d.ts +29 -0
- package/dist/capabilities/skills.js +13 -2
- package/dist/capabilities/team.d.ts +22 -0
- package/dist/capabilities/team.js +22 -2
- package/dist/capabilities/tool-defer.d.ts +26 -0
- package/dist/capabilities/tool-defer.js +3 -0
- package/dist/config-center/apply-effective.d.ts +65 -0
- package/dist/config-center/apply-effective.js +204 -12
- package/dist/config-center/http-client.d.ts +34 -0
- package/dist/config-center/http-client.js +68 -0
- package/dist/config-center/restart-signal.d.ts +22 -0
- package/dist/config-center/restart-signal.js +39 -0
- package/dist/config-center/skills-mcp.d.ts +20 -1
- package/dist/config-center/skills-mcp.js +42 -7
- package/dist/config-center/types.d.ts +92 -1
- package/dist/config-lkg.d.ts +12 -0
- package/dist/config-lkg.js +41 -0
- package/dist/config-provider.d.ts +78 -0
- package/dist/config-provider.js +165 -2
- package/dist/config-types.d.ts +585 -1
- package/dist/config.d.ts +78 -2
- package/dist/config.js +874 -301
- package/dist/degenerate-instrument.d.ts +38 -0
- package/dist/degenerate-instrument.js +55 -3
- package/dist/elicitation.d.ts +39 -0
- package/dist/elicitation.js +87 -3
- package/dist/env-facts.d.ts +61 -0
- package/dist/env-facts.js +73 -7
- package/dist/fleet/fleet-bus.d.ts +185 -0
- package/dist/fleet/fleet-bus.js +333 -27
- package/dist/fleet/subagent-tail-bus.d.ts +11 -0
- package/dist/fleet/subagent-tail-bus.js +33 -2
- package/dist/fleet-client.d.ts +38 -0
- package/dist/fleet-client.js +44 -9
- package/dist/fleet-lease.d.ts +46 -0
- package/dist/fleet-lease.js +73 -5
- package/dist/hooks/branch-transcript.d.ts +8 -0
- package/dist/hooks/branch-transcript.js +33 -0
- package/dist/hooks/cc-stop-prompt.d.ts +42 -0
- package/dist/hooks/cc-stop-prompt.js +43 -1
- package/dist/hooks/hook-llm.d.ts +15 -0
- package/dist/hooks/hook-llm.js +47 -0
- package/dist/hooks/hook-runner.d.ts +89 -0
- package/dist/hooks/hook-runner.js +327 -18
- package/dist/http/idempotency.d.ts +31 -0
- package/dist/http/idempotency.js +34 -0
- package/dist/http/principal-gate.d.ts +17 -0
- package/dist/http/principal-gate.js +35 -3
- package/dist/http/route-ctx.d.ts +36 -0
- package/dist/http/routes/approvals-assistant.d.ts +25 -0
- package/dist/http/routes/approvals-assistant.js +253 -23
- package/dist/http/routes/attachments.js +22 -4
- package/dist/http/routes/capabilities.d.ts +7 -0
- package/dist/http/routes/capabilities.js +202 -1
- package/dist/http/routes/fleet.d.ts +6 -0
- package/dist/http/routes/fleet.js +94 -5
- package/dist/http/routes/images.d.ts +17 -0
- package/dist/http/routes/images.js +222 -14
- package/dist/http/routes/leader.d.ts +7 -0
- package/dist/http/routes/leader.js +10 -0
- package/dist/http/routes/memory-policy.d.ts +6 -0
- package/dist/http/routes/memory-policy.js +38 -6
- package/dist/http/routes/notify-wake.d.ts +10 -0
- package/dist/http/routes/notify-wake.js +19 -3
- package/dist/http/routes/observability.d.ts +6 -0
- package/dist/http/routes/observability.js +19 -2
- package/dist/http/routes/runs.d.ts +15 -0
- package/dist/http/routes/runs.js +464 -41
- package/dist/http/routes/session-sync.d.ts +15 -0
- package/dist/http/routes/session-sync.js +229 -19
- package/dist/http/routes/sessions-list.d.ts +6 -0
- package/dist/http/routes/sessions-list.js +35 -4
- package/dist/http/routes/sessions.d.ts +14 -0
- package/dist/http/routes/sessions.js +176 -31
- package/dist/http/routes/side-query.d.ts +8 -0
- package/dist/http/routes/side-query.js +26 -1
- package/dist/http/routes/tasks.d.ts +18 -0
- package/dist/http/routes/tasks.js +501 -38
- package/dist/http/routes/trace-usage.d.ts +10 -0
- package/dist/http/routes/trace-usage.js +66 -14
- package/dist/http/routes/workflows.d.ts +12 -0
- package/dist/http/routes/workflows.js +180 -19
- package/dist/http/run-meta.d.ts +11 -0
- package/dist/http/run-meta.js +6 -0
- package/dist/http/send.d.ts +19 -0
- package/dist/http/send.js +11 -0
- package/dist/http/server.d.ts +255 -0
- package/dist/http/server.js +921 -75
- package/dist/http/sse-log.d.ts +15 -0
- package/dist/http/sse-log.js +16 -0
- package/dist/http/tar.d.ts +9 -0
- package/dist/http/tar.js +21 -5
- package/dist/http/wire-gate.d.ts +9 -0
- package/dist/http/wire-gate.js +9 -0
- package/dist/http/wire-types.d.ts +187 -0
- package/dist/http/workspace-content.d.ts +8 -0
- package/dist/http/workspace-content.js +10 -0
- package/dist/images/bake-validate.d.ts +63 -0
- package/dist/images/bake-validate.js +71 -1
- package/dist/images/manifest.d.ts +19 -0
- package/dist/images/manifest.js +6 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +10 -5
- package/dist/key-resolver.d.ts +23 -0
- package/dist/key-resolver.js +27 -2
- package/dist/leader/diffout.d.ts +23 -0
- package/dist/leader/diffout.js +8 -1
- package/dist/leader/diffup.d.ts +32 -0
- package/dist/leader/diffup.js +43 -0
- package/dist/leader/endpoint.d.ts +20 -0
- package/dist/leader/endpoint.js +25 -2
- package/dist/leader/fanout.d.ts +60 -0
- package/dist/leader/fanout.js +29 -3
- package/dist/leader/grader-env-factory.d.ts +74 -0
- package/dist/leader/grader-env-factory.js +62 -3
- package/dist/leader/leader.d.ts +97 -0
- package/dist/leader/leader.js +151 -4
- package/dist/leader/merge.d.ts +94 -0
- package/dist/leader/merge.js +112 -9
- package/dist/leader/planner.d.ts +52 -0
- package/dist/leader/planner.js +47 -3
- package/dist/leader/repair-oracle.d.ts +61 -0
- package/dist/leader/repair-oracle.js +59 -1
- package/dist/leader/repair-wire.d.ts +78 -0
- package/dist/leader/repair-wire.js +79 -2
- package/dist/leader/wire.d.ts +79 -0
- package/dist/leader/wire.js +255 -8
- package/dist/lsp/e2b-bridge.d.ts +16 -0
- package/dist/lsp/e2b-bridge.js +32 -4
- package/dist/lsp/e2b-manager.d.ts +10 -0
- package/dist/lsp/e2b-manager.js +18 -2
- package/dist/lsp/lsp-frames.d.ts +12 -0
- package/dist/lsp/lsp-frames.js +12 -0
- package/dist/lsp/manager.d.ts +12 -0
- package/dist/lsp/manager.js +35 -2
- package/dist/lsp/types.d.ts +10 -0
- package/dist/lsp/ws-transport.d.ts +12 -0
- package/dist/lsp/ws-transport.js +53 -5
- package/dist/lsp-evict.d.ts +14 -0
- package/dist/lsp-evict.js +15 -1
- package/dist/main.js +530 -2129
- package/dist/memory-export.d.ts +1 -0
- package/dist/memory-export.js +4 -0
- package/dist/memory-scope.d.ts +49 -0
- package/dist/memory-scope.js +87 -4
- package/dist/memory-sync-client.d.ts +24 -0
- package/dist/memory-sync-client.js +41 -2
- package/dist/memory-sync.d.ts +23 -0
- package/dist/memory-sync.js +70 -1
- package/dist/model-select.d.ts +39 -0
- package/dist/model-select.js +42 -1
- package/dist/observability/cost-quota.d.ts +20 -0
- package/dist/observability/cost-quota.js +4 -0
- package/dist/observability/cost-taxonomy.d.ts +45 -0
- package/dist/observability/cost-taxonomy.js +34 -0
- package/dist/observability/logger.d.ts +1 -0
- package/dist/observability/logger.js +6 -0
- package/dist/observability/metrics.d.ts +13 -0
- package/dist/observability/metrics.js +63 -0
- package/dist/observability/otel-exporter.d.ts +9 -0
- package/dist/observability/otel-exporter.js +11 -3
- package/dist/observability/principal-context.d.ts +9 -0
- package/dist/observability/principal-context.js +9 -0
- package/dist/observability/prompt-manifest.d.ts +37 -0
- package/dist/observability/prompt-manifest.js +35 -1
- package/dist/observability/rate-limit.d.ts +10 -0
- package/dist/observability/rate-limit.js +1 -0
- package/dist/observability/tool-trace.d.ts +24 -0
- package/dist/observability/tool-trace.js +41 -1
- package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
- package/dist/orchestration/hardened-vm-runner.js +119 -4
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
- package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
- package/dist/orchestration/hardened-vm-worker.js +27 -0
- package/dist/orchestration/subagent-steer.d.ts +44 -0
- package/dist/orchestration/subagent-steer.js +45 -1
- package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
- package/dist/orchestration/workflow-agent-steer.js +80 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
- package/dist/orchestration/workflow-completion-inbox.js +283 -32
- package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
- package/dist/orchestration/workflow-notify-journal.js +187 -13
- package/dist/parked-decide.d.ts +61 -0
- package/dist/parked-decide.js +58 -1
- package/dist/per-task-image.d.ts +54 -0
- package/dist/per-task-image.js +41 -0
- package/dist/plan-cache-probe.d.ts +35 -0
- package/dist/plan-cache-probe.js +18 -3
- package/dist/plugins/approval-exemption-store.d.ts +7 -0
- package/dist/plugins/approval-exemption-store.js +28 -2
- package/dist/plugins/approval-store-sql.d.ts +64 -0
- package/dist/plugins/approval-store-sql.js +32 -0
- package/dist/plugins/background-agent-store-sql.d.ts +55 -0
- package/dist/plugins/background-agent-store-sql.js +91 -4
- package/dist/plugins/background-shell-support.d.ts +98 -0
- package/dist/plugins/background-shell-support.js +117 -13
- package/dist/plugins/blob-backend.d.ts +104 -0
- package/dist/plugins/blob-backend.js +163 -6
- package/dist/plugins/breaker-state-sql.d.ts +65 -1
- package/dist/plugins/breaker-state-sql.js +46 -8
- package/dist/plugins/caching-session-store.d.ts +42 -0
- package/dist/plugins/caching-session-store.js +63 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
- package/dist/plugins/checkpoint-store-sql.js +239 -11
- package/dist/plugins/file-outcome-sink.d.ts +4 -0
- package/dist/plugins/file-outcome-sink.js +9 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
- package/dist/plugins/file-resume-anchor-store.js +43 -4
- package/dist/plugins/file-run-store.d.ts +90 -0
- package/dist/plugins/file-run-store.js +145 -13
- package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
- package/dist/plugins/file-snapshot-store-sql.js +178 -10
- package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
- package/dist/plugins/file-workflow-journal-store.js +10 -0
- package/dist/plugins/fork-routing-session-store.d.ts +47 -0
- package/dist/plugins/fork-routing-session-store.js +51 -3
- package/dist/plugins/host-platform.d.ts +69 -0
- package/dist/plugins/host-platform.js +81 -2
- package/dist/plugins/image-bake-store-sql.d.ts +136 -1
- package/dist/plugins/image-bake-store-sql.js +241 -7
- package/dist/plugins/image-index-sql.d.ts +46 -0
- package/dist/plugins/image-index-sql.js +113 -4
- package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
- package/dist/plugins/k8s-bg-scripts.js +88 -4
- package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
- package/dist/plugins/k8s-exec-protocol.js +41 -0
- package/dist/plugins/local-checkpoint-store.d.ts +40 -0
- package/dist/plugins/local-checkpoint-store.js +86 -7
- package/dist/plugins/local-session-store.d.ts +157 -0
- package/dist/plugins/local-session-store.js +289 -34
- package/dist/plugins/local-task-attachment-store.js +14 -2
- package/dist/plugins/mailbox-store-sql.d.ts +38 -0
- package/dist/plugins/mailbox-store-sql.js +39 -6
- package/dist/plugins/memory-engine-pg.d.ts +30 -0
- package/dist/plugins/memory-engine-pg.js +122 -4
- package/dist/plugins/memory-engine-tidb.d.ts +26 -0
- package/dist/plugins/memory-engine-tidb.js +115 -5
- package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
- package/dist/plugins/memory-engine-vector-util.js +5 -0
- package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
- package/dist/plugins/memory-resume-anchor-store.js +17 -0
- package/dist/plugins/memory-run-store.d.ts +63 -0
- package/dist/plugins/memory-run-store.js +73 -8
- package/dist/plugins/memory-session-policy-store.d.ts +17 -0
- package/dist/plugins/memory-session-policy-store.js +17 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
- package/dist/plugins/memory-sync-store-pg.js +45 -2
- package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
- package/dist/plugins/memory-sync-store-tidb.js +31 -1
- package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
- package/dist/plugins/outcome-ledger-sql.js +97 -3
- package/dist/plugins/pg-approval-store.d.ts +7 -0
- package/dist/plugins/pg-approval-store.js +7 -0
- package/dist/plugins/pg-breaker-state.d.ts +6 -0
- package/dist/plugins/pg-breaker-state.js +6 -0
- package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
- package/dist/plugins/pg-checkpoint-store.js +8 -0
- package/dist/plugins/pg-cost-quota.d.ts +17 -0
- package/dist/plugins/pg-cost-quota.js +6 -0
- package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/pg-file-snapshot-store.js +6 -0
- package/dist/plugins/pg-image-bake.d.ts +9 -0
- package/dist/plugins/pg-image-bake.js +9 -0
- package/dist/plugins/pg-image-index.d.ts +9 -0
- package/dist/plugins/pg-image-index.js +9 -0
- package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
- package/dist/plugins/pg-outcome-ledger.js +9 -0
- package/dist/plugins/pg-pool.d.ts +50 -0
- package/dist/plugins/pg-pool.js +78 -0
- package/dist/plugins/pg-query.d.ts +11 -0
- package/dist/plugins/pg-rate-limiter.d.ts +23 -0
- package/dist/plugins/pg-rate-limiter.js +12 -2
- package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/pg-resume-anchor-store.js +5 -0
- package/dist/plugins/pg-run-store.d.ts +7 -0
- package/dist/plugins/pg-run-store.js +7 -0
- package/dist/plugins/pg-safe-json.d.ts +13 -0
- package/dist/plugins/pg-safe-json.js +40 -4
- package/dist/plugins/pg-session-policy-store.d.ts +5 -0
- package/dist/plugins/pg-session-policy-store.js +5 -0
- package/dist/plugins/pg-session-storage.d.ts +72 -0
- package/dist/plugins/pg-session-storage.js +152 -20
- package/dist/plugins/pg-session-store.d.ts +10 -0
- package/dist/plugins/pg-session-store.js +10 -0
- package/dist/plugins/pg-tool-result-store.d.ts +7 -0
- package/dist/plugins/pg-tool-result-store.js +7 -0
- package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-journal-store.js +7 -0
- package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-run-store.js +7 -0
- package/dist/plugins/posix-shell-fs.d.ts +3 -0
- package/dist/plugins/posix-shell-fs.js +31 -1
- package/dist/plugins/remote-env-adb.d.ts +25 -0
- package/dist/plugins/remote-env-adb.js +95 -12
- package/dist/plugins/remote-env-e2b.d.ts +146 -0
- package/dist/plugins/remote-env-e2b.js +371 -40
- package/dist/plugins/remote-env-file-error.d.ts +34 -0
- package/dist/plugins/remote-env-file-error.js +37 -0
- package/dist/plugins/remote-env-host.d.ts +151 -0
- package/dist/plugins/remote-env-host.js +468 -70
- package/dist/plugins/remote-env-k8s.d.ts +135 -0
- package/dist/plugins/remote-env-k8s.js +318 -32
- package/dist/plugins/remote-env-local-docker.d.ts +65 -0
- package/dist/plugins/remote-env-local-docker.js +149 -24
- package/dist/plugins/remote-env-ssh.d.ts +35 -0
- package/dist/plugins/remote-env-ssh.js +117 -20
- package/dist/plugins/remote-scratchpad.d.ts +38 -0
- package/dist/plugins/remote-scratchpad.js +32 -2
- package/dist/plugins/remote-shell.d.ts +22 -0
- package/dist/plugins/remote-shell.js +27 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
- package/dist/plugins/resume-anchor-store-sql.js +11 -0
- package/dist/plugins/roster-store-sql.d.ts +27 -0
- package/dist/plugins/roster-store-sql.js +54 -0
- package/dist/plugins/run-store-sql.d.ts +194 -0
- package/dist/plugins/run-store-sql.js +210 -9
- package/dist/plugins/s3-presign.d.ts +20 -0
- package/dist/plugins/s3-presign.js +49 -2
- package/dist/plugins/scheduler-support.d.ts +12 -0
- package/dist/plugins/scheduler-support.js +75 -3
- package/dist/plugins/send-file-ledger.d.ts +15 -0
- package/dist/plugins/send-file-ledger.js +53 -4
- package/dist/plugins/send-user-file.d.ts +77 -0
- package/dist/plugins/send-user-file.js +92 -4
- package/dist/plugins/session-policy-store-sql.d.ts +15 -0
- package/dist/plugins/session-policy-store-sql.js +75 -3
- package/dist/plugins/session-store.d.ts +45 -0
- package/dist/plugins/session-store.js +51 -0
- package/dist/plugins/sql-driver.d.ts +77 -0
- package/dist/plugins/sql-driver.js +4 -0
- package/dist/plugins/sql-escape.d.ts +8 -0
- package/dist/plugins/sql-escape.js +8 -0
- package/dist/plugins/sql-row-helpers.d.ts +25 -0
- package/dist/plugins/sql-row-helpers.js +25 -0
- package/dist/plugins/store-backend.d.ts +103 -0
- package/dist/plugins/store-backend.js +120 -27
- package/dist/plugins/store-contracts.d.ts +62 -0
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +60 -0
- package/dist/plugins/task-attachment-store.js +49 -3
- package/dist/plugins/task-list-store-sql.d.ts +25 -0
- package/dist/plugins/task-list-store-sql.js +21 -0
- package/dist/plugins/tidb-approval-store.d.ts +6 -0
- package/dist/plugins/tidb-approval-store.js +6 -0
- package/dist/plugins/tidb-breaker-state.d.ts +5 -0
- package/dist/plugins/tidb-breaker-state.js +5 -0
- package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
- package/dist/plugins/tidb-checkpoint-store.js +7 -0
- package/dist/plugins/tidb-cost-quota.d.ts +6 -0
- package/dist/plugins/tidb-cost-quota.js +1 -0
- package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/tidb-file-snapshot-store.js +6 -0
- package/dist/plugins/tidb-image-bake.d.ts +8 -0
- package/dist/plugins/tidb-image-bake.js +8 -0
- package/dist/plugins/tidb-image-index.d.ts +8 -0
- package/dist/plugins/tidb-image-index.js +8 -0
- package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
- package/dist/plugins/tidb-outcome-ledger.js +10 -0
- package/dist/plugins/tidb-pool.d.ts +56 -0
- package/dist/plugins/tidb-pool.js +181 -1
- package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
- package/dist/plugins/tidb-rate-limiter.js +5 -2
- package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/tidb-resume-anchor-store.js +5 -0
- package/dist/plugins/tidb-run-store.d.ts +7 -0
- package/dist/plugins/tidb-run-store.js +7 -0
- package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
- package/dist/plugins/tidb-session-policy-store.js +5 -0
- package/dist/plugins/tidb-session-storage.d.ts +43 -0
- package/dist/plugins/tidb-session-storage.js +62 -3
- package/dist/plugins/tidb-session-store.d.ts +142 -0
- package/dist/plugins/tidb-session-store.js +264 -16
- package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
- package/dist/plugins/tidb-tool-result-store.js +7 -0
- package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/tidb-workflow-journal-store.js +7 -0
- package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
- package/dist/plugins/tidb-workflow-run-store.js +8 -0
- package/dist/plugins/tool-result-store-sql.d.ts +58 -0
- package/dist/plugins/tool-result-store-sql.js +38 -2
- package/dist/plugins/web-search.d.ts +35 -0
- package/dist/plugins/web-search.js +45 -9
- package/dist/plugins/workflow-journal-limits.d.ts +10 -0
- package/dist/plugins/workflow-journal-limits.js +10 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
- package/dist/plugins/workflow-journal-store-sql.js +58 -2
- package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
- package/dist/plugins/workflow-run-store-sql.js +84 -6
- package/dist/plugins/worktree-isolation.d.ts +45 -0
- package/dist/plugins/worktree-isolation.js +105 -6
- package/dist/plugins/write-behind-counter.d.ts +56 -1
- package/dist/plugins/write-behind-counter.js +53 -14
- package/dist/principal-jwt.d.ts +24 -0
- package/dist/principal-jwt.js +60 -5
- package/dist/project-memory.d.ts +22 -0
- package/dist/project-memory.js +144 -15
- package/dist/prompts-domain-validate.d.ts +28 -0
- package/dist/prompts-domain-validate.js +42 -1
- package/dist/question.d.ts +33 -0
- package/dist/question.js +69 -2
- package/dist/resource-suspend.d.ts +21 -0
- package/dist/resource-suspend.js +16 -0
- package/dist/router/route-orchestration.d.ts +78 -0
- package/dist/router/route-orchestration.js +77 -0
- package/dist/run-local.d.ts +32 -0
- package/dist/run-local.js +172 -8
- package/dist/runs.d.ts +189 -4
- package/dist/runs.js +465 -24
- package/dist/runtime-caps-resolver.d.ts +106 -0
- package/dist/runtime-caps-resolver.js +89 -4
- package/dist/runtime-governance.d.ts +84 -0
- package/dist/runtime-governance.js +127 -1
- package/dist/sandbox-pkg-source.d.ts +23 -0
- package/dist/sandbox-pkg-source.js +37 -0
- package/dist/sealed-key.d.ts +54 -0
- package/dist/sealed-key.js +68 -3
- package/dist/security.d.ts +108 -0
- package/dist/security.js +145 -6
- package/dist/sema-registry.d.ts +21 -0
- package/dist/sema-registry.js +21 -0
- package/dist/session-leaf-bus.d.ts +31 -0
- package/dist/session-leaf-bus.js +32 -0
- package/dist/session-sync-content.d.ts +46 -0
- package/dist/session-sync-content.js +47 -1
- package/dist/session-sync-kernel.d.ts +89 -0
- package/dist/session-sync-kernel.js +48 -3
- package/dist/session-sync.d.ts +125 -0
- package/dist/session-sync.js +181 -8
- package/dist/session-titler.d.ts +26 -0
- package/dist/session-titler.js +41 -7
- package/dist/session-watch.d.ts +53 -1
- package/dist/session-watch.js +73 -9
- package/dist/sighup-idle.d.ts +30 -0
- package/dist/sighup-idle.js +12 -1
- package/dist/spec-fields.d.ts +91 -3
- package/dist/spec-fields.js +116 -4
- package/dist/task-cwd.d.ts +50 -0
- package/dist/task-cwd.js +68 -1
- package/dist/task-mcp.d.ts +47 -0
- package/dist/task-mcp.js +29 -0
- package/dist/task-settings.d.ts +175 -0
- package/dist/task-settings.js +226 -11
- package/dist/task-workflow.d.ts +67 -0
- package/dist/task-workflow.js +75 -8
- package/dist/tool-approval.d.ts +91 -0
- package/dist/tool-approval.js +215 -0
- package/dist/trace/artifacts.d.ts +9 -0
- package/dist/trace/artifacts.js +30 -5
- package/dist/trace/core-keyset-guard.d.ts +18 -0
- package/dist/trace/ledger-sink.d.ts +43 -0
- package/dist/trace/ledger-sink.js +64 -5
- package/dist/trace/project.d.ts +133 -0
- package/dist/trace/project.js +189 -2
- package/dist/trace/redact.d.ts +19 -0
- package/dist/trace/redact.js +66 -9
- package/dist/usage-analytics.d.ts +26 -0
- package/dist/usage-analytics.js +26 -3
- package/package.json +1 -1
package/dist/tool-approval.js
CHANGED
|
@@ -1,31 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [816]/[820]② tool-approval bridge — the SERVICE side of core's `RunnerDeps.onAsk` seam (core `tool-policy.ts`
|
|
3
|
+
* `resolveAsk`, 1.290's sync-ask leg). The SIBLING of {@link import("./question.js").QuestionCoordinator}: onQuestion
|
|
4
|
+
* routes the agent's AskUserQuestion tool to a live human; THIS routes a policy `ask` DECISION (e.g. the
|
|
5
|
+
* `createFsWriteGatePolicy` fs-write gate, an ask-list rule, or a non-durable safety ask) to the live human as a
|
|
6
|
+
* CC-parity three-choice card (Yes / Yes-allow-all-session / No).
|
|
7
|
+
*
|
|
8
|
+
* Wire shape (mirrors question end to end): core adjudicates a tool call `ask` → `resolveAsk(req, onAsk)` calls this
|
|
9
|
+
* coordinator's `ask` → we mint a pending entry + emit a `tool_approval` SSE frame on the run's live stream → the
|
|
10
|
+
* shell renders the three-choice card → `POST /v1/tool-approvals/:id/respond` settles the parked promise →
|
|
11
|
+
* `resolveAsk` maps our boolean to allow/deny. RESPOND BODY selection rationale: the question precedent's body is
|
|
12
|
+
* core's own QuestionAnswer (a structured multi-answer object) because core FENCES its semantics; an approval has no
|
|
13
|
+
* core-side answer object — `OnAsk` resolves to a BARE boolean — so the wire body is a minimal closed enum
|
|
14
|
+
* `{decision: "allow" | "allow_session" | "deny"}` mapping 1:1 onto the CC card's three choices (no free text = no
|
|
15
|
+
* fence needed; "allow_session" carries the Yes-allow-all intent that a boolean cannot).
|
|
16
|
+
*
|
|
17
|
+
* Session state ([820]② "桥内会话态"): `allow_session` remembers a per-CAPABILITY grant keyed by
|
|
18
|
+
* `[owner, sessionId, category]` — every LATER ask in that (owner, session) whose tool maps to the SAME category
|
|
19
|
+
* auto-allows WITHOUT a card (CC 207: "Yes, allow all edits during this session"). The category collapses the
|
|
20
|
+
* fs-WRITE tool family (Write/Edit/NotebookEdit, canonical space) into ONE bucket `"fs-write"`; any OTHER tool is
|
|
21
|
+
* its OWN bucket `"tool:<canonical>"`. 🔴 A `allow_session` on a NON-fs-write ask (an irreversible-Bash safety ask,
|
|
22
|
+
* an ask-list rule on another tool) therefore unlocks ONLY that same tool for the session — it must NEVER unlock the
|
|
23
|
+
* fs-write family (the "approve a cheap ask once → all future Write/Edit auto-allowed" escalation, 三路复审 A 组 修2).
|
|
24
|
+
* The key is scoped to the VERIFIED owner too, so a session id shared across principals cannot inherit another's
|
|
25
|
+
* grant. This is the cheapest mid-task implementation; a mode SWITCH (default → acceptEdits) still goes through the
|
|
26
|
+
* shell's intent on the next task ([820] table).
|
|
27
|
+
*
|
|
28
|
+
* 🔒 FAIL-CLOSED everywhere (the inverse of question's headless default — an unanswered QUESTION lets the model
|
|
29
|
+
* proceed; an unanswered APPROVAL must NOT let the write proceed): TTL expiry ⇒ false; run abort / client
|
|
30
|
+
* disconnect ⇒ false. Since [879] G1 (core 1.295 OnAsk 三值化) the "no reachable human" class returns
|
|
31
|
+
* "unavailable" instead of false — no ALS context AND no bound-closure broker hit(1.258 起 bg/嵌套子代经
|
|
32
|
+
* spec.onAsk 的 bound 闭包 + streams broker 直达宿主活流,「无 ctx」只剩 durable-submit/headless resume
|
|
33
|
+
* 残余腿)and emit failure
|
|
34
|
+
* (card never delivered, and only when this catch is the first settler — a human verdict that raced in during the
|
|
35
|
+
* await keeps its boolean) ⇒ "unavailable" → core durable-parks (or fail-closed denies without a checkpoint). core's
|
|
36
|
+
* `resolveAsk` maps false to a deny WITH the ask message, so the model can re-route (deny + continue turn, [819]⑤).
|
|
37
|
+
* Owner gate on respond = the VERIFIED principal (gatedPrincipal at the HTTP layer), 404 without an existence oracle
|
|
38
|
+
* — same posture as question/elicit. The frame's model-authored surfaces (message + args) are secret-REDACTED and
|
|
39
|
+
* size-bounded before they are streamed (same redact-at-write contract as question; the args are shown to a human,
|
|
40
|
+
* never re-fed to a model). No throttle (unlike question): an approval breach-default would be a DENY (task failure),
|
|
41
|
+
* and asks are turn-blocking by construction — the TTL bounds the human-side exposure instead.
|
|
42
|
+
*/
|
|
1
43
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
44
|
import { uuidv7, canonicalToolName } from "@sema-agent/core";
|
|
3
45
|
import { redactDeep, redactSecrets } from "./trace/redact.js";
|
|
46
|
+
/** Size bound on the redacted args payload in a `tool_approval` frame (parity with question's MAX_QUESTIONS_BYTES).
|
|
47
|
+
* Over the cap ⇒ the frame still goes out WITHOUT args (`argsOmitted: true`) — unlike a question (undisplayable ⇒
|
|
48
|
+
* headless default is safe), an approval must still reach the human: toolName+message suffice to decide, and the
|
|
49
|
+
* fail-safe decision on blind args is the human's No. */
|
|
4
50
|
const MAX_APPROVAL_ARGS_BYTES = 16384;
|
|
51
|
+
/** How long an unanswered approval waits before it DENIES (fail-closed — the human walked away; don't hold core). */
|
|
5
52
|
const DEFAULT_APPROVAL_TTL_MS = 5 * 60_000;
|
|
53
|
+
/** Bound on the remembered allow-all grants (insertion-order evict — a long-lived worker must not grow unbounded). */
|
|
6
54
|
const MAX_ALLOW_SESSIONS = 4096;
|
|
55
|
+
/** The fs-write tool family the session allow-all collapses into ONE capability bucket (canonical space — a
|
|
56
|
+
* legacy-alias rule or a durable-resume replay carrying a pre-rename toolName still matches; MultiEdit canonicalizes
|
|
57
|
+
* to Edit). Mirrors core's PATH_WRITE_TOOLS + NotebookEdit (the same set `createFsWriteGatePolicy` gates); NOT
|
|
58
|
+
* exported by core's index, so the names are pinned here deliberately. */
|
|
7
59
|
const FS_WRITE_TOOLS = new Set(["Write", "Edit", "NotebookEdit"].map(canonicalToolName));
|
|
60
|
+
/** The session allow-all CAPABILITY CATEGORY for a tool (修2): the fs-write family shares one bucket ("fs-write" —
|
|
61
|
+
* a yes-to-edits covers Write/Edit/NotebookEdit alike, CC 207 semantics); every other tool is its OWN bucket
|
|
62
|
+
* ("tool:<canonical>") so an allow_session on it never grants anything beyond that same tool — a low-risk ask must
|
|
63
|
+
* not become a session-wide write unlock. Canonical space in, category out. */
|
|
8
64
|
function sessionAllowCategory(toolName) {
|
|
9
65
|
const canonical = canonicalToolName(toolName);
|
|
10
66
|
return FS_WRITE_TOOLS.has(canonical) ? "fs-write" : `tool:${canonical}`;
|
|
11
67
|
}
|
|
68
|
+
/** The allow-all grant key (修2): owner + sessionId + capability category, JSON-tuple-encoded so no segment can
|
|
69
|
+
* ambiguate the boundary with the next (an owner or sessionId containing a separator can't forge another key).
|
|
70
|
+
* Owner rides VERBATIM (null = auth-off/anonymous, its own scope) so a session id shared across principals never
|
|
71
|
+
* leaks a grant across tenants. */
|
|
12
72
|
function sessionAllowKey(owner, sessionId, category) {
|
|
13
73
|
return JSON.stringify([owner, sessionId, category]);
|
|
14
74
|
}
|
|
75
|
+
/** Validate the respond body — the closed three-choice enum (rationale in the module header). */
|
|
15
76
|
export function parseToolApprovalResponse(body) {
|
|
16
77
|
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
17
78
|
return { ok: false, error: "body must be an object" };
|
|
18
79
|
const d = body.decision;
|
|
19
80
|
if (d === "allow" || d === "allow_session" || d === "deny") {
|
|
81
|
+
// [1458] ctrl+g 编辑放行:allow 族可带 updatedInput(编辑后的 args 整体替换形,durable /decide 腿
|
|
82
|
+
// 同名位既有语义);deny 带=无意义,忽略不 400(宽收)。
|
|
20
83
|
const u = body.updatedInput;
|
|
21
84
|
return { ok: true, value: d, ...(d !== "deny" && u !== undefined ? { updatedInput: u } : {}) };
|
|
22
85
|
}
|
|
23
86
|
return { ok: false, error: 'decision must be one of "allow" | "allow_session" | "deny"' };
|
|
24
87
|
}
|
|
88
|
+
/** @deprecated design/158 N22: renamed to {@link parseToolApprovalResponse} — unifies the HITL trio's parse-fn
|
|
89
|
+
* vocabulary (`parseQuestionResponse` / `parseElicitationResponse` / `parseToolApprovalResponse`, all "the
|
|
90
|
+
* human's reply body"; `ToolApprovalDecision` itself is unchanged — it names the allow/deny VALUE, not the
|
|
91
|
+
* parse function). Kept as a compat alias. */
|
|
25
92
|
export const parseToolApprovalDecision = parseToolApprovalResponse;
|
|
93
|
+
/** [1550] RB-39② 兑现:判别式换 core 1.378 显式键 `fromSubagent`(委派子代 gate 发起的 ask 恒带,受信
|
|
94
|
+
* internals 事实——worker 不可伪造/不可抑制)。取代 [1546] MED-1 的「在场 ∧ ≠ 宿主 sessionId」权宜式
|
|
95
|
+
* (旧判别式靠 ctx.sessionId 参与推导,sessionless adhoc 场景无法区分;显式键不依赖 ctx,恒定准确)。 */
|
|
26
96
|
function isChildAsk(req) {
|
|
27
97
|
return req.fromSubagent === true;
|
|
28
98
|
}
|
|
99
|
+
/** redactDeep + size-bound the UNTRUSTED tool args before they are streamed. Over the cap / unserializable ⇒
|
|
100
|
+
* undefined (frame rides argsOmitted — see MAX_APPROVAL_ARGS_BYTES). */
|
|
29
101
|
function boundArgs(args) {
|
|
30
102
|
const redacted = redactDeep(args);
|
|
31
103
|
try {
|
|
@@ -37,19 +109,55 @@ function boundArgs(args) {
|
|
|
37
109
|
}
|
|
38
110
|
return { args: redacted, omitted: false };
|
|
39
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Coordinates the live tool-approval HITL for the singleton runner. Process-local + same-replica (the pending map is
|
|
114
|
+
* in memory, like QuestionCoordinator): a respond that lands on another replica finds nothing → 404. Present (passed
|
|
115
|
+
* into `RunnerDeps.onAsk` + the respond route) ONLY when `TOOL_APPROVAL_ENABLED` — absent ⇒ core's `resolveAsk`
|
|
116
|
+
* keeps its headless auto-deny for every ask ([819]⑤ fail-closed default, zero behavior change).
|
|
117
|
+
*
|
|
118
|
+
* G1 interplay (core 1.290 sync-ask knob, prepare-task): with an onAsk present, a NON-safety ask with NO per-task
|
|
119
|
+
* `durableApproval` skips the durable park and resolves on this sync leg (zero checkpoint, CC-interactive latency).
|
|
120
|
+
* A durable-approval deployment (`DURABLE_APPROVAL=true` sets spec.durableApproval on every task) keeps parking every
|
|
121
|
+
* ask durably — this bridge then only serves legs where the park machinery is absent. Safety asks (irreversible/
|
|
122
|
+
* egress) always keep the durable park when a checkpointStore exists (core's condition, not ours).
|
|
123
|
+
*/
|
|
40
124
|
export class ToolApprovalCoordinator {
|
|
41
125
|
als = new AsyncLocalStorage();
|
|
42
126
|
pending = new Map();
|
|
127
|
+
/** Per-capability session grants — keys = sessionAllowKey(owner, sessionId, category) (修2; bounded). */
|
|
43
128
|
allowAllSessions = new Set();
|
|
129
|
+
/** [1546] HIGH-1(broker)→[1559]四 core 产品裁定「多活集合+广播+首决胜出」:per-(owner, host-session)
|
|
130
|
+
* 的**当前活跃连接集合**——boundAsk 闭包只携身份,emit 时广播给该 key 下**全部**活连接(宿主重连/
|
|
131
|
+
* attach 新 SSE 时 runWithContext 各自注册进同一集合,谁也不覆盖谁);查无活连接 = "unavailable"
|
|
132
|
+
* (G1 回路)。旧单指针形的缺口(file-backed local mode 无单活跃 run 409 守卫时,两个真正并发的
|
|
133
|
+
* runWithContext 会让后到者的指针覆盖先到者,先到连接的卡静默不可达——core 点名与「1.334 标已告知
|
|
134
|
+
* 须以投递确认为前提」同族)已随本集合改造解:后到者只是加入集合,不挤走先到者。首个 respond()
|
|
135
|
+
* 经 `pending` map 天然 CAS 胜出(第二个 respond() 撞 id 已被删 → 404),其余连接靠 completion 帧
|
|
136
|
+
* 收 dismiss 通知(见 askBroadcast)。 */
|
|
44
137
|
streams = new Map();
|
|
45
138
|
ttlMs;
|
|
46
139
|
constructor(ttlMs = DEFAULT_APPROVAL_TTL_MS) {
|
|
47
140
|
this.ttlMs = ttlMs;
|
|
48
141
|
}
|
|
142
|
+
/** Broker key:宿主 session 优先(retained/续聊子代跨 SSE 找得到新流),sessionless adhoc 退 taskId。
|
|
143
|
+
* 并发审查加固:显式维度前缀(`"session"`/`"adhoc"`)分隔两个取值域,不再靠 `task:` 字符串前缀"祈祷"
|
|
144
|
+
* 不会跟一个真实 sessionId 字面重合——此前形式 `sessionId ?? "task:"+taskId` 里,若某会话的
|
|
145
|
+
* sessionId 恰好等于另一条 adhoc 流的 `"task:"+taskId`,两者会算出同一把 key(现网因 taskId 由
|
|
146
|
+
* 服务端 uuidv7 铸造、请求到达前不可预知而几乎不可达,但维度未加标签是编码层面的真实缺口)。 */
|
|
49
147
|
streamKey(owner, sessionId, taskId) {
|
|
50
148
|
return sessionId !== undefined ? JSON.stringify(["session", owner, sessionId]) : JSON.stringify(["adhoc", owner, taskId]);
|
|
51
149
|
}
|
|
150
|
+
/** Run `fn` with the per-run approval context ambient. On exit, notify every pending broadcast ask that this
|
|
151
|
+
* ctx is no longer a live target — an ask only dies once ALL its targets are gone (fail-closed backstop, the
|
|
152
|
+
* inverse of question's release-unanswered — but no longer a blunt "any one target exits ⇒ kill it" rule,
|
|
153
|
+
* see {@link PendingApproval.onTargetGone}).
|
|
154
|
+
* [1535] 注意([1539] core 点名的火):委派子代的 ask 经 {@link boundAsk} 落 pending 时不带
|
|
155
|
+
* `targetCtxs`/`onTargetGone`(只有 `originTaskId === undefined` 的宿主自身条目才带)——session-scoped
|
|
156
|
+
* bg 子代活过宿主 turn 时其未决卡不被这里触碰(TTL/abortSignal 仍兜底)。 */
|
|
52
157
|
runWithContext(ctx, fn) {
|
|
158
|
+
// broker 注册([1559]四 多活集合):本流加入该 (owner, session) 的活跃连接集合;退出时只摘除自己
|
|
159
|
+
// ——同 key 下真正并发的其余连接不受影响(这正是本车要修的「单指针后到覆盖先到」缺口:旧形
|
|
160
|
+
// `streams.set(key, ctx)` 会让后到者的注册整个替换掉先到者,先到连接从此收不到任何卡)。
|
|
53
161
|
const key = this.streamKey(ctx.owner, ctx.sessionId, ctx.taskId);
|
|
54
162
|
let set = this.streams.get(key);
|
|
55
163
|
if (!set) {
|
|
@@ -66,6 +174,11 @@ export class ToolApprovalCoordinator {
|
|
|
66
174
|
liveSet.delete(ctx);
|
|
67
175
|
if (liveSet.size === 0)
|
|
68
176
|
this.streams.delete(key);
|
|
177
|
+
// [1559]四独立复审①(HIGH)修:不再拿单个 `originCtx === ctx` 当清扫判据——多活集合下 `originCtx`
|
|
178
|
+
// 只是广播目标里任意一个成员,跟"这次 ask 到底是不是这条连接的执行栈在等它"没有必然关系,单独
|
|
179
|
+
// 靠它判死会误杀仍有其他活连接(甚至真正在等应答的那条)在场的未决卡。改为:只通知那些把本 ctx
|
|
180
|
+
// 列为广播目标之一的条目(`targetCtxs?.has(ctx)`——子代 ask 从不设 targetCtxs,天然免疫),
|
|
181
|
+
// 由 `askBroadcast` 内部的 liveConnections 倒计时决定是不是"全体目标都没了"才真正判死。
|
|
69
182
|
for (const [, p] of [...this.pending]) {
|
|
70
183
|
if (p.targetCtxs?.has(ctx))
|
|
71
184
|
p.onTargetGone?.(ctx);
|
|
@@ -73,15 +186,31 @@ export class ToolApprovalCoordinator {
|
|
|
73
186
|
}
|
|
74
187
|
});
|
|
75
188
|
}
|
|
189
|
+
/** 测试/可观测性钩子:该 (owner, session/taskId) broker key 下当前活跃连接数——断言多连接注册/清扫
|
|
190
|
+
* 行为时用,免得伸手进私有内部状态。 */
|
|
76
191
|
liveConnectionCount(owner, sessionId, taskId) {
|
|
77
192
|
return this.streams.get(this.streamKey(owner, sessionId, taskId))?.size ?? 0;
|
|
78
193
|
}
|
|
194
|
+
/** `RunnerDeps.onAsk`. core's resolveAsk calls this for each policy `ask` on the sync leg. [879] G1 三值化
|
|
195
|
+
* (core 1.295):boolean = 人的决定;`"unavailable"` = 本 ask 到达时刻判无活人可同步送达 —— core 以
|
|
196
|
+
* approverUnavailable 回路把这只 ask 交回 suspendAsk 走 durable park(park 设施缺席的部署 core 自己
|
|
197
|
+
* fail-closed deny)。1.199 的「durable 部署不 wire onAsk」止血就此撤除:恒 wire,park 与 live 卡两全。
|
|
198
|
+
* Arrow property so it can be passed as `onAsk: coordinator.ask` with `this` bound. */
|
|
79
199
|
ask = async (req, signal) => {
|
|
80
200
|
const ctx = this.als.getStore();
|
|
201
|
+
// No run context (background/workflow/headless/durable-submit leg — [820]④) = nobody to render the card ⇒
|
|
202
|
+
// "unavailable"(交 durable park),不再把「无人可问」翻译成 deny(1.295 前无三值只能 fail-closed)。
|
|
81
203
|
if (!ctx)
|
|
82
204
|
return "unavailable";
|
|
83
205
|
return this.askBroadcast([ctx], req, signal);
|
|
84
206
|
};
|
|
207
|
+
/** [1535] server 半场(审批链战役,[1539] 定谳断点①的修;[1546] HIGH-1 broker 形):宿主 sync
|
|
208
|
+
* streaming 腿在装配点以本闭包挂 `spec.onAsk`;core 继承链(parentConstraints 冻结
|
|
209
|
+
* `spec.onAsk ?? deps.onAsk`,1.294 起)把它逐 ancestor 冻给每个委派子代——子代(bg/嵌套孙代)的
|
|
210
|
+
* 权限 ask 不再依赖 ALS,直达宿主 live 流的审批卡。**闭包只携身份**(owner/taskId/sessionId),
|
|
211
|
+
* emit 时经 broker 取该 (owner, session) 的「当前」活跃流(宿主重连/续聊的新 SSE 自动接卡;
|
|
212
|
+
* internalsSnapshot 冻结的闭包因此永不携死流)。查无活流 = "unavailable"(G1 回路:durable 部署
|
|
213
|
+
* park;inherited plain-ask 的 park 回路 = core RB-39①,落地前该臂 = deny,与 1.257 前行为一致)。 */
|
|
85
214
|
boundAsk = (identity) => {
|
|
86
215
|
return (req, signal) => {
|
|
87
216
|
const set = this.streams.get(this.streamKey(identity.owner, identity.sessionId, identity.taskId));
|
|
@@ -91,13 +220,31 @@ export class ToolApprovalCoordinator {
|
|
|
91
220
|
return this.askBroadcast(live, req, signal);
|
|
92
221
|
};
|
|
93
222
|
};
|
|
223
|
+
/** 广播版裁决路径——`ask()`(ALS,恒单元素数组)与 `boundAsk`([1559]四多活集合,可能多元素)共用。
|
|
224
|
+
* 全体 `ctxs` 保证同一 (owner, sessionId)(streamKey 分组不变式;单元素数组平凡成立)。
|
|
225
|
+
*
|
|
226
|
+
* [1559]三 emit-race 加固(回黑板 [1558]三1,core 确认方向):「等 emit 完成」与「等
|
|
227
|
+
* TTL/abort/respond 三选一落定」显式 race——`emit` 的类型契约允许异步实现(durable-append 目标),
|
|
228
|
+
* 若挂死,旧形 `await ctx.emit(...)` 会让整条 ask 乃至调用方 turn 一起卡死,TTL/abort 定时器虽已
|
|
229
|
+
* 触发也无人读取其结果。核心不变式:race 由非人类结局(TTL/abort)先赢、且 emit 广播尚未有任何一路
|
|
230
|
+
* 确认完成时,不可扣一个武断的「deny」终局(不知道卡是否曾送达任何人)——按 G1 回路交
|
|
231
|
+
* "unavailable"。人类 respond() 落地的裁决永远照旧信任、不受本判据影响:它只可能在 approvalId 已经
|
|
232
|
+
* 送达某个客户端之后发生(respond 需要客户端手上有这个 id),这是 outcome==="allowed"/"denied" 与
|
|
233
|
+
* "expired"(TTL/abort/run-exit-cleanup/emit 广播全灭四类共用)的天然分野。 */
|
|
94
234
|
async askBroadcast(ctxs, req, signal) {
|
|
95
235
|
if (signal?.aborted)
|
|
96
236
|
return false;
|
|
237
|
+
// 连接级存活过滤:单连接(ask() 的 ALS 语义,今日 100% 生产流量)沿用「这条连接已经死了 ⇒ false」的
|
|
238
|
+
// 原判(entry 时刻检查,零行为变化)。多活集合(boundAsk 广播)下,entry 时已死的目标不计入广播——
|
|
239
|
+
// 若全体目标 entry 时已死,同样直接 false(单连接场景的自然推广:数组退化成 1 个已死 ctx 时结果
|
|
240
|
+
// 相同)。
|
|
97
241
|
const aliveCtxs = ctxs.filter((c) => !c.abortSignal?.aborted);
|
|
98
242
|
if (aliveCtxs.length === 0)
|
|
99
243
|
return false;
|
|
100
244
|
const primary = aliveCtxs[0];
|
|
245
|
+
// Session allow-all (CC "Yes, allow all edits during this session"): keyed [owner, sessionId, category] — the
|
|
246
|
+
// asking tool's OWN capability category must have been granted in THIS owner's session (修2; module header).
|
|
247
|
+
// 多活集合下 owner/sessionId 对全体 ctxs 恒同(streamKey 分组保证),primary 取值代表整个集合安全。
|
|
101
248
|
if (primary.sessionId && this.allowAllSessions.has(sessionAllowKey(primary.owner, primary.sessionId, sessionAllowCategory(req.toolName)))) {
|
|
102
249
|
return true;
|
|
103
250
|
}
|
|
@@ -129,6 +276,18 @@ export class ToolApprovalCoordinator {
|
|
|
129
276
|
signal.addEventListener("abort", onTaskAbort, { once: true });
|
|
130
277
|
abortListeners.push([signal, onTaskAbort]);
|
|
131
278
|
}
|
|
279
|
+
// 目标存活倒计时(single source of truth):单连接沿用「这条连接死 = 无人可送达 = 判死」的今日语义
|
|
280
|
+
// (数组退化成 1 时,一路"消失"即到零);多活集合改「全体目标都消失才判死」——any-of(哪一条先掉线
|
|
281
|
+
// 就杀)会重现 core 点名的「单指针覆盖」同族 bug:一条连接消失不该杀死仍有其他活连接在场、可能仍会
|
|
282
|
+
// 被响应的卡。**[1559]四独立复审①(HIGH)修**:「消失」现在统一有两条喂入路径——(a)该 ctx 自己的
|
|
283
|
+
// abortSignal 触发(下方监听器),(b)该 ctx 的 `runWithContext` 作用域退出,不论是正常返回还是抛出
|
|
284
|
+
// (`runWithContext` 的 finally 经 `targetCtxs`/`onTargetGone` 回调这里,见下方 pending.set)——此前
|
|
285
|
+
// 两条路径完全独立、互不知情:(b)是靠 `originCtx === ctx` 单独判定,而 `originCtx` 在多活集合下只是
|
|
286
|
+
// 目标数组里任意一个成员(通常是最先注册的那条),跟"是不是这条连接的执行栈真的在等这次 ask"没有
|
|
287
|
+
// 必然关系——一条完全不相关、只是恰好也在同一 (owner,session) 广播集合里的连接,处理完它自己另一个
|
|
288
|
+
// 无关的请求正常退出,就会单独触发把整条 ask 误杀,即便真正在等它的那条连接分毫未动、仍然存活。
|
|
289
|
+
// `goneCtxs` 去重:同一个 ctx 理论上可能同时/先后触发 (a)(b) 两条路径(abort 通常伴随其作用域跟着
|
|
290
|
+
// 退出),避免重复扣减。
|
|
132
291
|
let liveConnections = aliveCtxs.length;
|
|
133
292
|
const goneCtxs = new Set();
|
|
134
293
|
const onTargetGone = (c) => {
|
|
@@ -146,6 +305,10 @@ export class ToolApprovalCoordinator {
|
|
|
146
305
|
c.abortSignal.addEventListener("abort", onCtxAbort, { once: true });
|
|
147
306
|
abortListeners.push([c.abortSignal, onCtxAbort]);
|
|
148
307
|
}
|
|
308
|
+
// Register BEFORE emitting so a (fast) respond can never miss the entry. 子代 ask 的生存期挂子代
|
|
309
|
+
// (originTaskId 在场 = 不被宿主 finally 清扫烧;[1539] 注意事项,判别式 = isChildAsk 顶注)——同理,
|
|
310
|
+
// 子代 ask 从不设 targetCtxs/onTargetGone(任何宿主 ctx 的 runWithContext 退出都不该碰它,只有它
|
|
311
|
+
// 自己的 TTL/abortSignal 才作数;上面的 aliveCtxs abort 倒计时仍照常适用于它自己的连接级 abort)。
|
|
149
312
|
const child = isChildAsk(req);
|
|
150
313
|
this.pending.set(id, {
|
|
151
314
|
settle,
|
|
@@ -161,7 +324,11 @@ export class ToolApprovalCoordinator {
|
|
|
161
324
|
type: "tool_approval",
|
|
162
325
|
approvalId: id,
|
|
163
326
|
toolName: req.toolName,
|
|
327
|
+
// [1939]:core 的 tool-call id 逐字透传(AskRequest.toolCallId 是必填);理由见字段顶注。
|
|
164
328
|
...(typeof req.toolCallId === "string" && req.toolCallId !== "" ? { toolCallId: req.toolCallId } : {}),
|
|
329
|
+
// 帧上 sourceTaskId/fromSubagent/sourceAgentName 只出**子代** ask(server 侧判别收口,现判别
|
|
330
|
+
// 键 = req.fromSubagent[core RB-39② 显式受信键]——sourceTaskId 仍旁随传但不再是判别式,复审
|
|
331
|
+
// F2 案:core 对宿主 ask 也恒填 sourceTaskId=宿主 sessionId,裸透传会让每张宿主卡被误判子代)。
|
|
165
332
|
...(child
|
|
166
333
|
? {
|
|
167
334
|
sourceTaskId: req.sourceTaskId,
|
|
@@ -172,6 +339,10 @@ export class ToolApprovalCoordinator {
|
|
|
172
339
|
message: typeof req.message === "string" ? redactDeep(req.message) : "",
|
|
173
340
|
...(bounded.omitted ? { argsOmitted: true } : { args: bounded.args }),
|
|
174
341
|
};
|
|
342
|
+
// 每路 emit 独立兜底(catch 而非任其抛出/reject 冒泡)——一路失败不拖垮整个广播的判定;`emitOne`
|
|
343
|
+
// 因此**永不** reject(同时吸收同步 throw 与异步 rejection),`Promise.all` 也就永不 reject,
|
|
344
|
+
// 下面的 `Promise.race` 才能安全地把它当"正常完成"的一端,不会把某一路的失败错误地冒泡成
|
|
345
|
+
// askBroadcast 自身的未捕获异常。
|
|
175
346
|
const emitOne = async (c) => {
|
|
176
347
|
try {
|
|
177
348
|
await c.emit(frame);
|
|
@@ -181,33 +352,66 @@ export class ToolApprovalCoordinator {
|
|
|
181
352
|
return false;
|
|
182
353
|
}
|
|
183
354
|
};
|
|
355
|
+
// 🔴 [1575] F2 修(cli 复查,红先行确认真红):旧形完成帧广播是"调用序"跟着 `await allowedP`
|
|
356
|
+
// 走,不是"落盘序"——respond() 可能在某条连接自己的 OPEN emit 尚未落盘完成时就已经 settle(TTL/
|
|
357
|
+
// abort/emit-race 三选一显式 race 就是为了让这成为可能),而 complete 帧当时是立即 fire-and-forget
|
|
358
|
+
// 广播给全体 aliveCtxs,不等每条连接自己的 OPEN 是否已经落盘——异步/durable-append 型 emit 目标
|
|
359
|
+
// (本改造自述要服务的场景)下,慢连接会看到 complete 先于 open 落盘,回放/转录面呈现「永不 dismiss
|
|
360
|
+
// 的悬卡」或「丢失的 dismiss」。修复:**每条连接的 complete 帧显式排在该连接自己的 OPEN emit 落定
|
|
361
|
+
// 之后**(用 per-ctx 的 openP 建 Map,不是笼统一个 aliveCtxs.map)——旧注释钉过的「Emit the OPEN
|
|
362
|
+
// frame AWAITED (ordering ahead of the completion frame...)」不变式对多活广播的每一条连接分别成立,
|
|
363
|
+
// 不因为广播整体不再阻塞返回就失效。
|
|
184
364
|
const openByCtx = new Map(aliveCtxs.map((c) => [c, emitOne(c)]));
|
|
185
365
|
const emitAllP = (async () => {
|
|
186
366
|
const results = await Promise.all(openByCtx.values());
|
|
187
367
|
const anySucceeded = results.some(Boolean);
|
|
368
|
+
// ⚠️ 竞态门(cross-review 抓获,原单连接形已有的不变式,广播形延续):respond/abort 可能在 emit
|
|
369
|
+
// 广播完成前已经 settle(entry 先于 emit 注册)。emit 随后才判定全灭时,已有的人类 boolean 裁决/
|
|
370
|
+
// abort 终局必须保持——只有本判定是第一个 settle 者(done 仍 false)才算「卡从未送达任何人」。
|
|
188
371
|
if (!anySucceeded && !done) {
|
|
189
372
|
emitFailed = true;
|
|
190
373
|
settle(false, "expired");
|
|
191
374
|
}
|
|
192
375
|
emitSettled = true;
|
|
193
376
|
})();
|
|
377
|
+
// [1559]三:emit 完成 vs TTL/abort/respond 三选一落定——显式 race,不让挂死的 emit 独占执行权。
|
|
194
378
|
await Promise.race([emitAllP, allowedP]);
|
|
195
379
|
const settled = await allowedP;
|
|
380
|
+
// Completion breadcrumb (card dismiss) — fire-and-forget to every target that actually got the OPEN frame
|
|
381
|
+
// (aliveCtxs — a ctx filtered out at entry as already-dead never saw `tool_approval` in the first place, so
|
|
382
|
+
// it has nothing to dismiss), so a slow/hung emit never delays returning to core AND every connection in
|
|
383
|
+
// the set learns the card resolved elsewhere([1559]四「其余连接收 resolved/dismissed 通知」的直接落点——
|
|
384
|
+
// 单连接场景退化为原来的一次 emit)。**per-ctx 链在该 ctx 自己的 openP 之后**(F2 修的落点)——
|
|
385
|
+
// `openByCtx.get(c)!` 永不 reject(emitOne 内部已吸收),所以不需要额外 `.catch` 才能继续链下去;
|
|
386
|
+
// `.then(() => c.emit(...))` 包一层是必须的:该 ctx 的 complete emit 若同步 throw,要先转成
|
|
387
|
+
// rejection 才能被后面的 `.catch` 接住,否则会在此处同步抛出、跳过 catch。
|
|
196
388
|
for (const c of aliveCtxs) {
|
|
197
389
|
void openByCtx
|
|
198
390
|
.get(c)
|
|
199
391
|
.then(() => c.emit({ type: "tool_approval_complete", approvalId: id, outcome: lastOutcome }))
|
|
200
392
|
.catch(() => undefined);
|
|
201
393
|
}
|
|
394
|
+
// emit 全灭 = 卡从未送达任何人(≠人拒绝/TTL 走人)——同属「无活人可达」类 ⇒ "unavailable" 交 durable
|
|
395
|
+
// park。
|
|
202
396
|
if (emitFailed)
|
|
203
397
|
return "unavailable";
|
|
398
|
+
// emit 广播尚未有任何一路确认完成(既非成功也非已知失败)就被 TTL/abort 抢先判定 ⇒ 无法确认卡是否
|
|
399
|
+
// 曾送达任何人,不可扣一个武断的「deny」终局——按 G1 回路交 "unavailable"(同 emit 失败同一处置,
|
|
400
|
+
// core [1559]三 确认方向)。respond() 落地的人类裁决(outcome allowed/denied)不受影响,原因见本
|
|
401
|
+
// 方法顶注。
|
|
204
402
|
if (!emitSettled && lastOutcome === "expired")
|
|
205
403
|
return "unavailable";
|
|
404
|
+
// [1458] updatedInput 前向兼容形:allow+编辑到位 → 以 `{allow:true, updatedInput}` 对象形返回——
|
|
405
|
+
// 旧 core(≤1.356 resolveAsk 折叠 `ok ? ALLOW`)把对象当 truthy=allow(行为=现状,编辑忽略,壳侧
|
|
406
|
+
// 版本门挡假 UI);core 放宽 OnAsk 认对象臂后(黑板转单)编辑即生效。deny 恒返 false(falsy 纪律)。
|
|
206
407
|
if (settled.allowed && settled.updatedInput !== undefined) {
|
|
207
408
|
return { allow: true, updatedInput: settled.updatedInput };
|
|
208
409
|
}
|
|
209
410
|
return settled.allowed;
|
|
210
411
|
}
|
|
412
|
+
/** `POST /v1/tool-approvals/:id/respond` — settle a parked approval with the shell's decision. Owner-gated with a
|
|
413
|
+
* 404 (no existence oracle), body validated first (400 is existence-independent) — question/steer parity. The HTTP
|
|
414
|
+
* layer owns auth (gatedPrincipal + REQUIRE_PRINCIPAL) before calling. */
|
|
211
415
|
respond(id, principal, body) {
|
|
212
416
|
const parsed = parseToolApprovalResponse(body);
|
|
213
417
|
if (!parsed.ok)
|
|
@@ -216,10 +420,18 @@ export class ToolApprovalCoordinator {
|
|
|
216
420
|
if (!entry || (entry.owner !== null && entry.owner !== principal)) {
|
|
217
421
|
return { status: 404, body: { error: "no pending tool approval for this id (settled, expired, or not on this replica)", errorCode: "tool_approval.not_pending" } };
|
|
218
422
|
}
|
|
423
|
+
// PAIR-REVIEW [1392]②:ack 带 rememberApplied 诚实回显——allow_session 且**真记了**(sessionId 在,
|
|
424
|
+
// grant 落桥内店)= true;allow_session 但无 sessionId(adhoc 无会话,记不了)= false(壳不得渲染
|
|
425
|
+
// 「本 session 全放行」);普通 allow/deny 不涉 remember = 字段省略。durable decide 腿的同名回显
|
|
426
|
+
// (server.ts:4326)语义对齐。
|
|
219
427
|
let rememberApplied;
|
|
220
428
|
if (parsed.value === "allow_session")
|
|
221
429
|
rememberApplied = Boolean(entry.sessionId);
|
|
222
430
|
if (parsed.value === "allow_session" && entry.sessionId) {
|
|
431
|
+
// Bounded remember (insertion-order evict). 修2 scope: the grant is keyed by THIS ask's own capability
|
|
432
|
+
// category — a Write/Edit-family ask unlocks the fs-write family for the (owner, session); ANY other tool's
|
|
433
|
+
// allow_session unlocks only that same tool. A cheap non-write ask can therefore never become a session-wide
|
|
434
|
+
// write unlock (the pre-fix behavior: bare-sessionId key + remember-regardless-of-tool).
|
|
223
435
|
if (this.allowAllSessions.size >= MAX_ALLOW_SESSIONS) {
|
|
224
436
|
const oldest = this.allowAllSessions.values().next().value;
|
|
225
437
|
if (oldest !== undefined)
|
|
@@ -229,8 +441,11 @@ export class ToolApprovalCoordinator {
|
|
|
229
441
|
}
|
|
230
442
|
const allowed = parsed.value !== "deny";
|
|
231
443
|
entry.settle(allowed, allowed ? "allowed" : "denied", parsed.updatedInput);
|
|
444
|
+
// updatedInputForwarded=server 已透传(是否被引擎消费取决于 core OnAsk 对象臂是否在——诚实措辞,
|
|
445
|
+
// 不称 applied;cli 版本门+core 单落地后全链生效)。
|
|
232
446
|
return { status: 200, body: { approvalId: id, delivery: "applied", decision: parsed.value, ...(rememberApplied !== undefined ? { rememberApplied } : {}), ...(parsed.updatedInput !== undefined && allowed ? { updatedInputForwarded: true } : {}) } };
|
|
233
447
|
}
|
|
448
|
+
/** Test/observability hooks. */
|
|
234
449
|
pendingCount() {
|
|
235
450
|
return this.pending.size;
|
|
236
451
|
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import type { RunEvent } from "../plugins/store-contracts.js";
|
|
2
2
|
export interface TraceArtifact {
|
|
3
|
+
/** Stable within the task: `<taskId>:<n>` in first-seen order — safe as a UI key + dedupe handle. */
|
|
3
4
|
id: string;
|
|
4
5
|
taskId: string;
|
|
6
|
+
/** Work-view correlation (omitted when the run has none) — lets the client group a job's artifacts. */
|
|
5
7
|
jobId?: string;
|
|
6
8
|
kind: "file" | "git-push";
|
|
9
|
+
/** file: the workspace-relative path. git-push: the refspec tail (e.g. "origin HEAD:branch") or the command. */
|
|
7
10
|
ref: string;
|
|
8
11
|
summary?: string;
|
|
12
|
+
/** file only (additive, P2 workspace "what changed how much"): HUNK-level line counts summed over the
|
|
13
|
+
* successful contributing calls — write_file counts its content lines as additions; edit_file counts
|
|
14
|
+
* new_string lines as additions + old_string lines as deletions. NOT a git diff (no patch bodies in the
|
|
15
|
+
* log); when a real patch store lands these move to the reserved `diff` kind with a patchRef. */
|
|
9
16
|
additions?: number;
|
|
10
17
|
deletions?: number;
|
|
18
|
+
/** ts of the LAST successful contributing tool call. */
|
|
11
19
|
createdAt: string;
|
|
12
20
|
}
|
|
21
|
+
/** Project the durable event log into artifacts. Events must be in seq order (getEvents guarantees it). */
|
|
13
22
|
export declare function projectArtifacts(events: readonly RunEvent[], run: {
|
|
14
23
|
taskId: string;
|
|
15
24
|
jobId?: string | null;
|
package/dist/trace/artifacts.js
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trace.artifacts (M2) — project "what the agent produced" from the durable event log.
|
|
3
|
+
*
|
|
4
|
+
* Deterministic projection, no new write path: artifacts are DERIVED from the already-persisted
|
|
5
|
+
* tool_start/tool_end pairs (S2 log), so they exist for every historical run and cannot drift from execution.
|
|
6
|
+
* v1 produces two kinds:
|
|
7
|
+
* - `file` — a successful `Write` / `Edit` call (deduped per path; the summary counts edits).
|
|
8
|
+
* - `git-push` — a successful `bash` call whose command contains `git push` (ref = the parsed refspec tail).
|
|
9
|
+
* `diff` is declared in the wire schema but NOT produced in v1 (we don't capture patch bodies in the log) —
|
|
10
|
+
* consumers must treat kinds as an open set. Args in the log are already secret-redacted at persist time.
|
|
11
|
+
*/
|
|
1
12
|
import { canonicalToolName } from "@sema-agent/core";
|
|
13
|
+
/** Line count of a tool-arg string ("" = 0; no trailing-newline inflation). */
|
|
2
14
|
function lines(v) {
|
|
3
15
|
if (typeof v !== "string" || v.length === 0)
|
|
4
16
|
return 0;
|
|
5
17
|
return v.split("\n").length;
|
|
6
18
|
}
|
|
19
|
+
// Q6 (core 1.161) CC names, CANONICAL only — this projection runs over HISTORICAL event logs, so `canonicalToolName`
|
|
20
|
+
// folds persisted pre-rename rows (a 1.171-era "MultiEdit" start) onto their canonical spelling ("Edit") at read time.
|
|
21
|
+
// core 1.202 retired MultiEdit into an Edit alias; Edit itself now carries an optional `edits[]` batch.
|
|
7
22
|
const FILE_TOOLS = new Set(["Write", "Edit", "NotebookEdit"]);
|
|
8
23
|
const GIT_PUSH_RE = /\bgit\b[^;|&]*\bpush\b\s*(.*)/;
|
|
24
|
+
/** Project the durable event log into artifacts. Events must be in seq order (getEvents guarantees it). */
|
|
9
25
|
export function projectArtifacts(events, run) {
|
|
26
|
+
// Pair tool_start args with the matching tool_end by toolCallId — only a SUCCESSFUL call (isError false)
|
|
27
|
+
// produces an artifact (a failed write/push produced nothing).
|
|
10
28
|
const starts = new Map();
|
|
11
29
|
const byKey = new Map();
|
|
12
30
|
for (const ev of events) {
|
|
@@ -20,25 +38,32 @@ export function projectArtifacts(events, run) {
|
|
|
20
38
|
const start = starts.get(d.toolCallId);
|
|
21
39
|
if (!start)
|
|
22
40
|
continue;
|
|
23
|
-
starts.delete(d.toolCallId);
|
|
24
|
-
const toolName = canonicalToolName(start.toolName);
|
|
41
|
+
starts.delete(d.toolCallId); // each call contributes at most once
|
|
42
|
+
const toolName = canonicalToolName(start.toolName); // fold persisted pre-rename rows (e.g. "MultiEdit") onto CC canonical
|
|
25
43
|
if (FILE_TOOLS.has(toolName)) {
|
|
44
|
+
// Write/Edit key the write target on `file_path` (core 1.169 batch-B renamed `path`→`file_path`, dual-accept) —
|
|
45
|
+
// try it FIRST, fall back to `path` (a pre-1.169 emit or durable checkpoint still carries the old name), then
|
|
46
|
+
// NotebookEdit's `notebook_path` (core 1.163; unchanged by batch-B). Missing all three → not a path-bearing call.
|
|
26
47
|
const path = typeof start.args["file_path"] === "string" ? start.args["file_path"] : typeof start.args["path"] === "string" ? start.args["path"] : typeof start.args["notebook_path"] === "string" ? start.args["notebook_path"] : undefined;
|
|
27
48
|
if (!path)
|
|
28
49
|
continue;
|
|
50
|
+
// Hunk-level line stats from the call args themselves (zero new storage; args already redacted).
|
|
51
|
+
// Edit is batch-capable (core 1.202: an `edits[]` array — also the shape of a persisted legacy MultiEdit
|
|
52
|
+
// row, folded onto "Edit" above): with a batch, sum each edit's new_string/old_string lines; a single
|
|
53
|
+
// edit keeps the flat new_string/old_string fields.
|
|
29
54
|
const edits = Array.isArray(start.args["edits"]) ? start.args["edits"] : [];
|
|
30
55
|
const add = toolName === "Write" ? lines(start.args["content"])
|
|
31
56
|
: toolName === "NotebookEdit" ? lines(start.args["new_source"])
|
|
32
57
|
: edits.length > 0 ? edits.reduce((s, e) => s + lines(e["new_string"]), 0)
|
|
33
|
-
: lines(start.args["new_string"]);
|
|
34
|
-
const del = toolName !== "Edit" ? 0
|
|
58
|
+
: lines(start.args["new_string"]); // Edit (single)
|
|
59
|
+
const del = toolName !== "Edit" ? 0 // Write/NotebookEdit carry no old_string (NotebookEdit delete-mode → 0 add 0 del = a touched count)
|
|
35
60
|
: edits.length > 0 ? edits.reduce((s, e) => s + lines(e["old_string"]), 0)
|
|
36
61
|
: lines(start.args["old_string"]);
|
|
37
62
|
const key = `file:${path}`;
|
|
38
63
|
const prev = byKey.get(key);
|
|
39
64
|
byKey.set(key, { kind: "file", ref: path, count: (prev?.count ?? 0) + 1, ts: ev.ts, add: (prev?.add ?? 0) + add, del: (prev?.del ?? 0) + del });
|
|
40
65
|
}
|
|
41
|
-
else if (toolName === "Bash") {
|
|
66
|
+
else if (toolName === "Bash") { // Q6 (core 1.161): was "bash"; canonical fold above is identity for it today
|
|
42
67
|
const command = typeof start.args["command"] === "string" ? start.args["command"] : "";
|
|
43
68
|
const m = GIT_PUSH_RE.exec(command);
|
|
44
69
|
if (!m)
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1 键集机器门([1549] 方法论倡议 server 认领件;clay 令 2026-07-23「不能永远编码有限→复审补漏」)。
|
|
3
|
+
*
|
|
4
|
+
* 病族:**投影白名单剥键**——core 给源类型加 additive 新键,server 的列投影/白名单静默丢,直到穿透
|
|
5
|
+
* 审查才被人肉抓。已四案:RosterEntry.model([1532])、task_progress.status / TaskNotificationPayload
|
|
6
|
+
* 四键 / BackgroundChildEvent.usage+transcriptId([1543] 族B)、SDK 0.0.72 fleet meta 剥键。
|
|
7
|
+
*
|
|
8
|
+
* 机制:对每个「core 源类型 → server 投影」面声明**已处置键集** = PROJECTED(真透传)∪ EXCLUDED
|
|
9
|
+
* (显式记账不透传,理由必写)。`Exclude<keyof 源, 已处置>` 约束为 never——**升 core 后源类型出新键
|
|
10
|
+
* ⇒ 本文件 tsc 红**(新键必须被「透传」或「记账排除」二选一处置,不再有静默第三态)。
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ 执行点 = `tsc --noEmit`(发车门 1):vitest 走 esbuild 转译不查类型、test/ 不在 tsc project——
|
|
13
|
+
* 所以本文件必须留在 src/ 下。写作时自证过:临时从 PROJECTED 删一键 → tsc 红。
|
|
14
|
+
*
|
|
15
|
+
* 维护:core 新键到来时,transparently 透传的加进对应 PROJECTED 并去实现投影;有意不上 wire 的加进
|
|
16
|
+
* EXCLUDED 并写一行理由。谁改投影(project.ts / fleet-bus.ts / roster-store-sql.ts)谁同步本文件。
|
|
17
|
+
*/
|
|
1
18
|
import type { TaskNotificationPayload, BackgroundChildEvent, RosterEntry, AskRequest, TaskEvent } from "@sema-agent/core";
|
|
19
|
+
/** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。 */
|
|
2
20
|
type AssertAllKeysHandled<T extends never> = T;
|
|
3
21
|
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId";
|
|
4
22
|
type _GuardNotification = AssertAllKeysHandled<Exclude<keyof TaskNotificationPayload, NotificationProjected>>;
|
|
@@ -1,22 +1,65 @@
|
|
|
1
1
|
import { NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
2
|
+
/**
|
|
3
|
+
* LedgerSink — the SINGLE "stream event → durable runs-ledger" projection, shared by the background leg
|
|
4
|
+
* (runs.ts `runInBackground`) and the sync `/v1/tasks/stream` detach lane (server.ts, `x-detach-on-disconnect`).
|
|
5
|
+
*
|
|
6
|
+
* [900]①/[906]③: the sync leg historically persisted only createRun+setTerminal — its events ledger stayed
|
|
7
|
+
* EMPTY, so after a detach the shell could only poll the terminal row. Feeding the same sink on the detach
|
|
8
|
+
* lane makes `GET /v1/runs/:id/events` replay the full stream in the EXACT bg-leg vocabulary (the ledger
|
|
9
|
+
* consumer binds to these type/data shapes — a second copy of this switch would drift into a false ledger,
|
|
10
|
+
* so never fork it).
|
|
11
|
+
*
|
|
12
|
+
* Scope: only the PURE transform lives here — text/reasoning coalescing, redaction, the per-run monotone
|
|
13
|
+
* `seq`, and the type/data whitelist shapes. Everything leg-specific stays with the caller: rewind anchors,
|
|
14
|
+
* fleet rows, metrics, model-usage deltas (E8), checkpoint parking and run-row settles. `done` and
|
|
15
|
+
* `message_committed` are deliberately NO-OPS in {@link LedgerSink.onEvent} — the bg leg must interleave
|
|
16
|
+
* model-usage writes between the text flush and the terminal event (it drives {@link LedgerSink.appendParked}
|
|
17
|
+
* / {@link LedgerSink.appendDone} itself), and message_committed is a session-tree concern (replay walks the
|
|
18
|
+
* persisted tree; it is never a ledger row).
|
|
19
|
+
*/
|
|
2
20
|
export interface LedgerSink {
|
|
21
|
+
/** Seq-stamped raw append — for a leg's out-of-band rows (elicitation/question frames, model_usage deltas,
|
|
22
|
+
* suggestions, `failed`) that must share this run's single seq counter. Redaction is the CALLER's duty on
|
|
23
|
+
* this raw door (every existing site already redacts); the typed doors below redact internally. */
|
|
3
24
|
append(type: string, data: unknown): Promise<void>;
|
|
25
|
+
/** Flush the buffered turn text/reasoning. Thinking precedes content within a turn → a buffered reasoning
|
|
26
|
+
* block flushes FIRST (redacted; core [R57]: CoT may carry reasoned-about secrets — TRACE_THINKING gates
|
|
27
|
+
* capture). The `text` row is stamped with the turn's first text eventId (E18 per-message resume handle,
|
|
28
|
+
* additive/tolerate-absent). Buffers clear only AFTER a successful write (a failed write drops nothing). */
|
|
4
29
|
flush(): Promise<void>;
|
|
30
|
+
/** The shared stream-switch projection (all non-terminal events). `done` / `message_committed` / unknown
|
|
31
|
+
* future types are no-ops (whitelist discipline — never a raw spread into the ledger). */
|
|
5
32
|
onEvent(ev: {
|
|
6
33
|
type: string;
|
|
7
34
|
}): Promise<void>;
|
|
35
|
+
/** Forward-sink (subagent) events → ledger, bg-leg posture: fire-and-forget with SYNCHRONOUS seq allocation
|
|
36
|
+
* (sink-vs-loop appends get unique seqs), same whitelist+redact builders (forwarded events are UNTRUSTED
|
|
37
|
+
* RAW — §E1). Child text/reasoning deltas are deliberately NOT persisted per-chunk (a child's turn text has
|
|
38
|
+
* no durable turn row; the tool cards + task_progress ticks are the durable projection). */
|
|
8
39
|
onForwardEvent(e: {
|
|
9
40
|
type?: string;
|
|
10
41
|
}): void;
|
|
42
|
+
/** Park event (durable F4 suspend / design/80 D-B review pause): ONLY the non-secret `checkpointGate` is
|
|
43
|
+
* persisted — never the capability `checkpointToken` (search [18] Q1b). */
|
|
11
44
|
appendParked(kind: "suspended" | "needs_review", result: unknown): Promise<void>;
|
|
45
|
+
/** Terminal `done` event. `result` must already be checkpoint-token-stripped (and, on the bg leg,
|
|
46
|
+
* model-usage-attached) by the caller. */
|
|
12
47
|
appendDone(result: unknown): Promise<void>;
|
|
48
|
+
/** Convenience for the sync detach lane (no model-usage interleave there): flush, then project the result
|
|
49
|
+
* to its park/terminal event exactly like the bg leg's done case. `result` must already be stripped. */
|
|
13
50
|
onDone(result: {
|
|
14
51
|
status?: string;
|
|
15
52
|
}): Promise<void>;
|
|
16
53
|
}
|
|
17
54
|
export declare function createLedgerSink(opts: {
|
|
55
|
+
/** The seq-stamped durable append — typically `(seq, type, data) => runStore.appendEvent(taskId, seq, type, data)`. */
|
|
18
56
|
appendEvent: (seq: number, type: string, data: unknown) => Promise<void>;
|
|
57
|
+
/** TRACE_THINKING gate: reasoning deltas are buffered (later redacted+persisted) only when true (core [R57] —
|
|
58
|
+
* persisting CoT is a deployment decision). Both legs pass the SAME config source (`config.traceThinking`). */
|
|
19
59
|
persistThinking: boolean;
|
|
60
|
+
/** task_notification dedup ledger (core [784]④a seq-folded keys). The bg leg passes its per-leg instance
|
|
61
|
+
* (shared with its observer/drain arms so no arm double-appends a key another arm delivered); a leg with no
|
|
62
|
+
* other durable arms (sync detach lane) omits it and gets a private instance. */
|
|
20
63
|
notifiedKeys?: NotifiedKeys;
|
|
21
64
|
}): LedgerSink;
|
|
22
65
|
//# sourceMappingURL=ledger-sink.d.ts.map
|