@sema-agent/server 7.43.0 → 7.44.0
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/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- package/dist/capabilities/scenario-alias.js +0 -61
package/dist/trace/artifacts.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
/** Line count of a tool-arg string ("" = 0; no trailing-newline inflation). */
|
|
2
1
|
function lines(v) {
|
|
3
2
|
if (typeof v !== "string" || v.length === 0)
|
|
4
3
|
return 0;
|
|
5
4
|
return v.split("\n").length;
|
|
6
5
|
}
|
|
7
|
-
// Q6 (core 1.161) CC names。5.0.0 RB-476:折叠面退役——本投影跑在历史事件日志上,pre-rename 旧行
|
|
8
|
-
// (如 1.171 时代的 "MultiEdit")不再折到 canonical:旧名行按原名滑过 FILE_TOOLS 判定=不进 artifacts
|
|
9
|
-
// 归类(诚实历史,读面不再兜旧名;耐久面按 [2364] 令牺牲)。
|
|
10
6
|
const FILE_TOOLS = new Set(["Write", "Edit", "NotebookEdit"]);
|
|
11
7
|
const GIT_PUSH_RE = /\bgit\b[^;|&]*\bpush\b\s*(.*)/;
|
|
12
|
-
/** Project the durable event log into artifacts. Events must be in seq order (getEvents guarantees it). */
|
|
13
8
|
export function projectArtifacts(events, run) {
|
|
14
|
-
// Pair tool_start args with the matching tool_end by toolCallId — only a SUCCESSFUL call (isError false)
|
|
15
|
-
// produces an artifact (a failed write/push produced nothing).
|
|
16
9
|
const starts = new Map();
|
|
17
10
|
const byKey = new Map();
|
|
18
11
|
for (const ev of events) {
|
|
@@ -26,33 +19,25 @@ export function projectArtifacts(events, run) {
|
|
|
26
19
|
const start = starts.get(d.toolCallId);
|
|
27
20
|
if (!start)
|
|
28
21
|
continue;
|
|
29
|
-
starts.delete(d.toolCallId);
|
|
30
|
-
const toolName = start.toolName;
|
|
22
|
+
starts.delete(d.toolCallId);
|
|
23
|
+
const toolName = start.toolName;
|
|
31
24
|
if (FILE_TOOLS.has(toolName)) {
|
|
32
|
-
// Write/Edit key the write target on `file_path`. core 5.1.0([2390])收窄 schema 为 `file_path` 单形,
|
|
33
|
-
// 但**门读侧 over-read 保留**是同批 KEEP 裁定(fail-closed 方向)——这里是耐久历史行的读侧([2373] D 类),
|
|
34
|
-
// pre-1.169 emit/旧 durable checkpoint 仍带 `path`,回落臂是对自己旧数据的容忍,不是对上游新帧的兼容。
|
|
35
|
-
// 再回落 NotebookEdit 的 `notebook_path`(core 1.163)。三键全缺 → 非带路径调用。
|
|
36
25
|
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;
|
|
37
26
|
if (!path)
|
|
38
27
|
continue;
|
|
39
|
-
// Hunk-level line stats from the call args themselves (zero new storage; args already redacted).
|
|
40
|
-
// Edit is batch-capable (core 1.202: an `edits[]` array — also the shape of a persisted legacy MultiEdit
|
|
41
|
-
// row, folded onto "Edit" above): with a batch, sum each edit's new_string/old_string lines; a single
|
|
42
|
-
// edit keeps the flat new_string/old_string fields.
|
|
43
28
|
const edits = Array.isArray(start.args["edits"]) ? start.args["edits"] : [];
|
|
44
29
|
const add = toolName === "Write" ? lines(start.args["content"])
|
|
45
30
|
: toolName === "NotebookEdit" ? lines(start.args["new_source"])
|
|
46
31
|
: edits.length > 0 ? edits.reduce((s, e) => s + lines(e["new_string"]), 0)
|
|
47
|
-
: lines(start.args["new_string"]);
|
|
48
|
-
const del = toolName !== "Edit" ? 0
|
|
32
|
+
: lines(start.args["new_string"]);
|
|
33
|
+
const del = toolName !== "Edit" ? 0
|
|
49
34
|
: edits.length > 0 ? edits.reduce((s, e) => s + lines(e["old_string"]), 0)
|
|
50
35
|
: lines(start.args["old_string"]);
|
|
51
36
|
const key = `file:${path}`;
|
|
52
37
|
const prev = byKey.get(key);
|
|
53
38
|
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 });
|
|
54
39
|
}
|
|
55
|
-
else if (toolName === "Bash") {
|
|
40
|
+
else if (toolName === "Bash") {
|
|
56
41
|
const command = typeof start.args["command"] === "string" ? start.args["command"] : "";
|
|
57
42
|
const m = GIT_PUSH_RE.exec(command);
|
|
58
43
|
if (!m)
|
|
@@ -1,109 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `engine_notice` wire 腿(#310,设计稿 = 黑板 [4630],core 表态 [4631] / cli 表态 [4634])——
|
|
3
|
-
* core `EngineNotice` 的**第二终点**:按 sessionId 路由到那条会话的事件投影(SSE + durable 账本)。
|
|
4
|
-
*
|
|
5
|
-
* ## 为什么是白名单而不是全族上 wire
|
|
6
|
-
* `RunnerDeps.onNotice` 是 **deps 级单 sink**(一部署一只),`EngineNotice` 上**没有 runId**——
|
|
7
|
-
* 归属只能靠 `detail.sessionId`。于是:
|
|
8
|
-
* · `config.*` 族一个都不带 sessionId ⇒ 结构性无处投(投给谁都是猜);
|
|
9
|
-
* · core 侧**按 sink 去重**的码(`config.read_face_deployment_clamped` / `config.tool_model_gate_*`)
|
|
10
|
-
* 一旦上 per-session 流,语义当场翻面:共享 sink 意味着整进程只发一次,第二条会话的用户看到的是
|
|
11
|
-
* 「随机缺席」而不是「没发生」;
|
|
12
|
-
* · 运维码(`config.env_timeout_discarded` 一族)推给终端用户 = 跨租户串台面。
|
|
13
|
-
* 白名单里的三码,core 侧的去重单位分别是 **session / harvest / prepared-leg**(不是 sink),所以它们
|
|
14
|
-
* 上 per-session 流不产生上面第二条的翻面——这正是白名单避开去重陷阱的判据,不是随手挑的三个码。
|
|
15
|
-
*
|
|
16
|
-
* ## 缺 sessionId 的白名单码:如实不投
|
|
17
|
-
* 三码的 `detail.sessionId` 在 core 类型上是**可选**的(部分铸点确无 session 语境)。缺席时本腿
|
|
18
|
-
* **不投**(fail-closed 方向 = 宁缺席不串台;猜一个"当前活跃会话"就是串台的定义)。日志终点仍逐字
|
|
19
|
-
* 保留 ⇒ 运维观察面零回退,事实一条不丢。
|
|
20
|
-
*
|
|
21
|
-
* ## 白名单的演化机制(设计稿 ④)—— **注册表已到货(core 5.47/5.48)**
|
|
22
|
-
* core [4631] 认领的 `NOTICE_AUDIENCE` **码级注册表**(code → "user"|"operator";缺席读 `"operator"`,
|
|
23
|
-
* 保守默认)已随 5.47/5.48 到货,`EngineNotice.sessionId` 顶层键亦然。#292 提货批的处置是
|
|
24
|
-
* **消费它当上界,而不是当场把本表整只退役**:
|
|
25
|
-
* · 本表是**投递可行性**的判定(有没有 sessionId 归属键、core 侧的去重单位是不是 sink),
|
|
26
|
-
* `NOTICE_AUDIENCE` 是**受众**的判定(这条码是给谁看的)——两者是合取,不是同一件事;
|
|
27
|
-
* · 于是机器门(`test/engine-notice-wire.test.ts` ⑥)现在**双向**咬:白名单里出现一个 core 判
|
|
28
|
-
* `"operator"` 的码 ⇒ 红(本仓不许自造第二份受众语义);core 判 `"user"` 的码没入册也没明拒 ⇒ 红。
|
|
29
|
-
* · 真正的整表退役条件 = 上游把「归属键在不在」也纳入注册表(那时本表退化成一次查表),届时删。
|
|
30
|
-
* 🔴 固定动作不变:**每一次 core 提货批**对表 core `EngineNotice` 码册的新增码,三选一登记
|
|
31
|
-
* (入册 / 明拒 + 理由 / 申裁),并在 `docs/core-consumption/LEDGER.json` 的该批行里留痕。
|
|
32
|
-
* 漏对表的后果不是报错而是**静默缺席**:新码永远不上 wire,消费端(cli)无从知道该码存在。
|
|
33
|
-
*/
|
|
34
1
|
import { redactSecrets } from "./redact.js";
|
|
35
2
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
36
|
-
/**
|
|
37
|
-
* 上 wire 的通告码 —— **显式闭集常量表**(设计稿 ①,起步三码)。
|
|
38
|
-
*
|
|
39
|
-
* 三码同族:都是「这条 session 的记忆姿态」的披露,resume 之后仍然相关 ⇒ 也进 durable 账本
|
|
40
|
-
* (cli 断连补看走既有 events 重放腿,[4634](ii))。
|
|
41
|
-
*/
|
|
42
3
|
export const ENGINE_NOTICE_WIRE_CODES = [
|
|
43
|
-
/** design/178 §3:本会话记忆越过一次性 POLLUTED 态。core 去重单位 = **session**。`detail: { reason, sessionId? }` */
|
|
44
4
|
"memory.session_polluted",
|
|
45
|
-
/** design/178 §3:被污染会话的 harvest 执行了容纳。core 去重单位 = **harvest**(检查点收与终局收是两件事)。
|
|
46
|
-
* `detail: { count, moved, escalated, reason?, sessionId? }` —— 🔴 `moved` 与 `escalated` **不可相减**
|
|
47
|
-
* (就地墓碑同时计入两者,core 顶注);消费端并列呈现,不做算术。 */
|
|
48
5
|
"memory.harvest_quarantined",
|
|
49
|
-
/** design/324 #324①:`memoryDelegationEvidence:"attested-only"` 下,一次静态面本会打的污染标记被豁免。
|
|
50
|
-
* core 去重单位 = **prepared leg**。`detail: { reason, subagentType?, sessionId? }` */
|
|
51
6
|
"memory.delegation_static_mark_waived",
|
|
52
|
-
/** design/336 §4/§6.3(core 5.47/5.48 到货,#292 提货批对表入册):**instruction-hold 生命周期**三码。
|
|
53
|
-
* 同族三条都是「这条 session 的记忆此刻处在什么姿态」的披露,与既有三码同一条判据:
|
|
54
|
-
* · core `NOTICE_AUDIENCE` 明列 **"user"**(到货的码级注册表,见本文件顶注的演化机制);
|
|
55
|
-
* · 铸点在 `memoryHoldNotices(report, sessionId)`,`detail.sessionId` 随 harvest 报告一起给 ⇒ 投得出去;
|
|
56
|
-
* · core 去重单位 = **harvest**(检查点收与终局收是两件事),不是 sink ⇒ 上 per-session 流不翻面。
|
|
57
|
-
* `detail: { count, paths, sessionId? }`(paths 已 neutralize + 截 20 条)。 */
|
|
58
7
|
"memory.hold_opened",
|
|
59
|
-
/** 同族:被扣住的 instruction 条目在写者会话干净结算(或宿主阀门放行)后重走全套门并提交。
|
|
60
|
-
* `detail: { count, paths, sessionId? }` */
|
|
61
8
|
"memory.hold_released",
|
|
62
|
-
/** 同族:被扣住的条目移交控制面隔离区。`detail: { count, disposed: [{ path, terminal }], sessionId? }`
|
|
63
|
-
* —— 🔴 `terminal:"expired"` 是**超时不是定罪**(core 铸文逐字如此),消费端不得渲染成裁决语气。 */
|
|
64
9
|
"memory.hold_disposed",
|
|
65
10
|
];
|
|
66
11
|
const WIRE_CODES = new Set(ENGINE_NOTICE_WIRE_CODES);
|
|
67
|
-
/** 白名单谓词(单点):路由与门都读这一个,不许第二处手抄码串。 */
|
|
68
12
|
export function isEngineNoticeWireCode(code) {
|
|
69
13
|
return WIRE_CODES.has(code);
|
|
70
14
|
}
|
|
71
|
-
/**
|
|
72
|
-
* 归属键抽取 —— `detail.sessionId` 提升为顶层(设计稿 ②:归属键一等化)。
|
|
73
|
-
*
|
|
74
|
-
* 非串 / 空串一律按**缺席**处理(不铸 `"undefined"` 这种看起来合法的假值——`compactionOutcomeEventData`
|
|
75
|
-
* 的同款缺键守卫纪律)。core [4631] 的顶层 `EngineNotice.sessionId` 到货后,这里先读顶层再回落 detail
|
|
76
|
-
* (两处同值,additive 零 BREAKING),届时本函数是唯一改动点。
|
|
77
|
-
*/
|
|
78
15
|
export function engineNoticeSessionId(notice) {
|
|
79
|
-
const top = notice.sessionId;
|
|
16
|
+
const top = notice.sessionId;
|
|
80
17
|
if (typeof top === "string" && top.length > 0)
|
|
81
18
|
return top;
|
|
82
19
|
const fromDetail = notice.detail?.sessionId;
|
|
83
20
|
return typeof fromDetail === "string" && fromDetail.length > 0 ? fromDetail : undefined;
|
|
84
21
|
}
|
|
85
|
-
/** 自由文本(message / detail 里的串)的长度上限。`workspaceChangedEventData` 的 300 是**路径**级 bound;
|
|
86
|
-
* 通告的 `reason` 是一整句话(core 侧已 neutralize + bound),这里给它一个不腰斩正常句子的上限。 */
|
|
87
22
|
const NOTICE_TEXT_MAX = 1000;
|
|
88
|
-
/** detail 递归消毒的结构上限。三码的真 detail 都是 ≤5 键的扁平对象 ⇒ 生产上永不触顶;
|
|
89
|
-
* 上限存在的理由是**未来码**(以及被污染输入)不得把任意大小的对象推上 wire。 */
|
|
90
23
|
const DETAIL_MAX_DEPTH = 4;
|
|
91
24
|
const DETAIL_MAX_KEYS = 32;
|
|
92
25
|
const DETAIL_MAX_ITEMS = 32;
|
|
93
|
-
/**
|
|
94
|
-
* `detail` 消毒(设计稿 ②:`redactSecrets` + 尺寸 bound;`workspaceChangedEventData` 先例)。
|
|
95
|
-
*
|
|
96
|
-
* core 已 neutralize 三码的 `reason`(工具名/子代类型是 host/模型可控输入),**server 按纪律再过一遍**
|
|
97
|
-
* ——§E1 的既有姿态:上 wire 的自由文本一律经本仓的脱敏器,不因为上游说过一次就免检。
|
|
98
|
-
*
|
|
99
|
-
* 契约(逐条,门在 `test/engine-notice-wire.test.ts`):
|
|
100
|
-
* · 串 ⇒ `redactSecrets` + 截到 {@link NOTICE_TEXT_MAX};
|
|
101
|
-
* · 有限 number / boolean / null ⇒ 逐字(harvest 的 count/moved/escalated 是判据数字,不许变形);
|
|
102
|
-
* · 非有限 number(NaN/Infinity)⇒ **丢键**(JSON 里它们会变成 `null`,一个看起来合法的假读数);
|
|
103
|
-
* · 数组 ⇒ 逐项消毒,超 {@link DETAIL_MAX_ITEMS} 截断;对象 ⇒ 逐键消毒,超 {@link DETAIL_MAX_KEYS} 丢尾键;
|
|
104
|
-
* · 深度超 {@link DETAIL_MAX_DEPTH} ⇒ 该子树丢弃;
|
|
105
|
-
* · 其余(function / symbol / bigint / undefined)⇒ 丢键(JSON 不可承载或语义不明)。
|
|
106
|
-
*/
|
|
107
26
|
export function sanitizeNoticeDetail(detail) {
|
|
108
27
|
const out = sanitizeValue(detail ?? {}, 0);
|
|
109
28
|
return (out ?? {});
|
|
@@ -142,15 +61,8 @@ function sanitizeValue(v, depth) {
|
|
|
142
61
|
}
|
|
143
62
|
return rec;
|
|
144
63
|
}
|
|
145
|
-
return undefined;
|
|
64
|
+
return undefined;
|
|
146
65
|
}
|
|
147
|
-
/**
|
|
148
|
-
* `engine_notice` 载荷构造器(三条终点腿同源:live SSE / durable 账本 / 未来的任何第四条腿)。
|
|
149
|
-
*
|
|
150
|
-
* 与 `trace/project.ts` 的 `*EventData` 族同纪律(白名单挑键、禁 `{...notice}`),但**不住在那个文件里**:
|
|
151
|
-
* 那一族的入参全是 core `TaskEvent` 的臂(有 `wire-whitelist-exhaustiveness` 的臂集编译门看着),
|
|
152
|
-
* 而 `EngineNotice` 不是 `TaskEvent` —— 混进去会让那道门的语义变成"两个不同来源的联合",判别力反而降。
|
|
153
|
-
*/
|
|
154
66
|
export function engineNoticeEventData(notice, sessionId, nowMs) {
|
|
155
67
|
return {
|
|
156
68
|
code: notice.code,
|
|
@@ -161,34 +73,12 @@ export function engineNoticeEventData(notice, sessionId, nowMs) {
|
|
|
161
73
|
};
|
|
162
74
|
}
|
|
163
75
|
let nextLegId = 1;
|
|
164
|
-
/**
|
|
165
|
-
* sessionId → 该会话活跃 run 腿的投递口。**进程内**(`defaultSubagentTailBus` 同款姿势):
|
|
166
|
-
* `onNotice` 是同进程的同步回调,通告与它要投的那条腿必然同副本,跨副本路由这件事结构上不存在。
|
|
167
|
-
*
|
|
168
|
-
* 🔴 跨 session 隔离靠的是 **Map 键的精确串相等**,不是任何「最近活跃」回落 —— 缺席就是缺席(G5)。
|
|
169
|
-
*
|
|
170
|
-
* 🔴 **同 session 的跨代隔离靠 legId「最新代独占」**(#310 codex 对抗复审 R1-[high],验真后修)。
|
|
171
|
-
* 病(真窗,本仓每一处 in-flight 登记都为它写过 identity-guard):run 行在**流体内**就已 setTerminal /
|
|
172
|
-
* setSuspended,而本腿的注销在 `finally` —— 中间那一窗里,同一条 session 上的**下一条腿**(快速续跑 /
|
|
173
|
-
* 紧接着的新提交)已经注册好了自己的口。若按「会话内全量扇出」投,新腿的一条通告会**同时**落进:
|
|
174
|
-
* · 旧腿那条已 end 的 SSE(顶多记一次 fail-open,无害),以及
|
|
175
|
-
* · **旧 taskId 的账本** —— 一条不属于那条 run 的、终态之后的行;resume 复用同 taskId 时还会与新腿
|
|
176
|
-
* 抢同一个 `(task_id, seq)` 域。这不是跨租户泄露,是**同租户跨 run 的账本污染**,同样必须关死。
|
|
177
|
-
* 药:每次 `registerLeg` 铸一个单调 legId,`route` **只投最新代**;旧代的口留在表里(它自己的注销仍
|
|
178
|
-
* 按身份精确删,不会误删新代),但一帧都收不到。方向 = fail-closed(宁可旧腿少一帧,不可新腿的事实
|
|
179
|
-
* 写进旧腿的账)。
|
|
180
|
-
*/
|
|
181
76
|
export class EngineNoticeRouter {
|
|
182
77
|
legs = new Map();
|
|
183
|
-
/**
|
|
184
|
-
* 登记**一条腿**的全部口(live / durable 作为**一代**同进同出)。返回注销函数(幂等,身份精确删)。
|
|
185
|
-
*
|
|
186
|
-
* 每只口各自 try 隔离在 {@link route} 里,单口抛不牵连同腿另一口。
|
|
187
|
-
*/
|
|
188
78
|
registerLeg(sessionId, sinks) {
|
|
189
79
|
const leg = { legId: nextLegId++, sinks: [...sinks] };
|
|
190
80
|
const list = this.legs.get(sessionId) ?? [];
|
|
191
|
-
list.push(leg);
|
|
81
|
+
list.push(leg);
|
|
192
82
|
this.legs.set(sessionId, list);
|
|
193
83
|
let done = false;
|
|
194
84
|
return () => {
|
|
@@ -198,39 +88,31 @@ export class EngineNoticeRouter {
|
|
|
198
88
|
const cur = this.legs.get(sessionId);
|
|
199
89
|
if (!cur)
|
|
200
90
|
return;
|
|
201
|
-
const at = cur.indexOf(leg);
|
|
91
|
+
const at = cur.indexOf(leg);
|
|
202
92
|
if (at >= 0)
|
|
203
93
|
cur.splice(at, 1);
|
|
204
94
|
if (cur.length === 0)
|
|
205
95
|
this.legs.delete(sessionId);
|
|
206
96
|
};
|
|
207
97
|
}
|
|
208
|
-
/** 单口腿的便捷形(测试与单终点腿用)。 */
|
|
209
98
|
register(sessionId, sink) {
|
|
210
99
|
return this.registerLeg(sessionId, [sink]);
|
|
211
100
|
}
|
|
212
|
-
/** 诊断/门用:某会话此刻**最新代**有几只口在听(旧代不计——它们收不到帧)。 */
|
|
213
101
|
sinkCount(sessionId) {
|
|
214
102
|
const list = this.legs.get(sessionId);
|
|
215
103
|
return list && list.length > 0 ? list[list.length - 1].sinks.length : 0;
|
|
216
104
|
}
|
|
217
|
-
/** 诊断/门用:某会话此刻有几代腿在表里(>1 = 正处在换代窗内)。 */
|
|
218
105
|
legCount(sessionId) {
|
|
219
106
|
return this.legs.get(sessionId)?.length ?? 0;
|
|
220
107
|
}
|
|
221
|
-
/**
|
|
222
|
-
* 分流器的 wire 半场。返回**真投出去的口数**(0 = 没投:非白名单码 / 缺 sessionId / 该会话无活跃腿)。
|
|
223
|
-
*
|
|
224
|
-
* 单只口抛错**不吃掉同腿的其它口**(fleet bus 订阅者隔离同理由),并按 F 类登记留痕。
|
|
225
|
-
*/
|
|
226
108
|
route(notice, nowMs = Date.now()) {
|
|
227
109
|
if (!isEngineNoticeWireCode(notice.code))
|
|
228
110
|
return 0;
|
|
229
111
|
const sessionId = engineNoticeSessionId(notice);
|
|
230
112
|
if (sessionId === undefined)
|
|
231
|
-
return 0;
|
|
113
|
+
return 0;
|
|
232
114
|
const list = this.legs.get(sessionId);
|
|
233
|
-
const leg = list && list.length > 0 ? list[list.length - 1] : undefined;
|
|
115
|
+
const leg = list && list.length > 0 ? list[list.length - 1] : undefined;
|
|
234
116
|
if (!leg || leg.sinks.length === 0)
|
|
235
117
|
return 0;
|
|
236
118
|
const row = engineNoticeEventData(notice, sessionId, nowMs);
|
|
@@ -247,18 +129,7 @@ export class EngineNoticeRouter {
|
|
|
247
129
|
return delivered;
|
|
248
130
|
}
|
|
249
131
|
}
|
|
250
|
-
/** 进程单例(`defaultSubagentTailBus` 同款):分流器与 run 腿直接 import,不穿长参数列表;测试自 new 独立实例。 */
|
|
251
132
|
export const defaultEngineNoticeRouter = new EngineNoticeRouter();
|
|
252
|
-
/**
|
|
253
|
-
* run 腿的注册助手 —— 三条腿(sync stream / bg / resume-verify)用**同一个**形,免得各写一份漂。
|
|
254
|
-
*
|
|
255
|
-
* `sessionId` 缺席(adhoc 无会话腿)⇒ 返回 no-op 注销函数,一个字节不注册(顶注的 fail-closed 方向)。
|
|
256
|
-
* `live` / `durable` 各自可缺席:bg 腿没有 live SSE(消费方走 events tail),ephemeral sync 腿没有账本。
|
|
257
|
-
*
|
|
258
|
-
* 🔴 两口注册成**两只独立 sink**(不是一只闭包里顺序调两次):route 的隔离粒度是 sink,合成一只会让
|
|
259
|
-
* live 写(断连的 socket、JSON.stringify 抛)吃掉同一拍的 durable 落账 —— 而 durable 那半正是断连之后
|
|
260
|
-
* 唯一还看得见这条通告的地方(G3),两者的失败必须互不牵连。
|
|
261
|
-
*/
|
|
262
133
|
export function registerEngineNoticeLeg(opts) {
|
|
263
134
|
const { sessionId, live, durable } = opts;
|
|
264
135
|
if (sessionId === undefined || sessionId.length === 0)
|
|
@@ -266,9 +137,6 @@ export function registerEngineNoticeLeg(opts) {
|
|
|
266
137
|
const sinks = [...(live ? [live] : []), ...(durable ? [durable] : [])];
|
|
267
138
|
if (sinks.length === 0)
|
|
268
139
|
return () => undefined;
|
|
269
|
-
// 🔴 两口登记成**同一代**(`registerLeg` 一次调用)而不是两次 `register`:代是"腿"的属性,拆成两代
|
|
270
|
-
// 会让换代时旧腿的一只口先被超代、另一只还没 —— 半代状态没有任何正确语义。口的失败隔离是 `route`
|
|
271
|
-
// 里的 per-sink try(与代无关),两者是正交的两件事。
|
|
272
140
|
return (opts.router ?? defaultEngineNoticeRouter).registerLeg(sessionId, sinks);
|
|
273
141
|
}
|
|
274
142
|
//# sourceMappingURL=engine-notice-wire.js.map
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { redactSecrets } from "./redact.js";
|
|
2
2
|
import { toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
3
3
|
import { NotifiedKeys, taskNotificationStreamKey } from "../orchestration/workflow-completion-inbox.js";
|
|
4
|
-
/**
|
|
5
|
-
* **单写串行链**的可复用形(#310 codex 对抗复审 R1-[high],验真后修)—— `seq` 的**分配发生在链步内**,
|
|
6
|
-
* 于是「分配序 == 发起序 == 提交序」。
|
|
7
|
-
*
|
|
8
|
-
* 病(实测形,`LedgerSink` 内部早有这条纪律的内联版、其顶注 [1.211 codex H2] 逐字记着它):裸写口
|
|
9
|
-
* (`(type, data) => rs.appendEvent(taskId, ++seq, type, data)`)在**同步分配 seq、立刻发起 insert**。
|
|
10
|
-
* 主循环 await 自己的写,所以主循环内部有序;但只要有**一个 fire-and-forget 写者**(子代 forward 帧、
|
|
11
|
-
* #310 的通告口),它的 N 号 insert 可能在池化 SQL 后端上晚于后发的 N+1 号提交。events tail 的读法是
|
|
12
|
-
* `getEvents(id, afterSeq)` —— 读到 N+1 就把游标推过 N,**那一行此后永远不会被投递**(重连也不会,
|
|
13
|
-
* 游标只前进)。行在库里,消费端结构性看不见。
|
|
14
|
-
*
|
|
15
|
-
* 药:所有写口共用一条 promise 链,`++seq` 在链步内取。链上一步失败**不断链**(catch → undefined),
|
|
16
|
-
* 调用方仍拿到自己那一步的真实结果(await 者照常收到 reject)——与 `LedgerSink` 内联版逐字同语义。
|
|
17
|
-
*
|
|
18
|
-
* ⚠️ 用它的前提是**这条腿的全部写口都走它**(混用一个绕开链的写口 = 病灶原样保留)。
|
|
19
|
-
*/
|
|
20
4
|
export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
21
5
|
let seq = startSeq;
|
|
22
6
|
let chain = Promise.resolve();
|
|
@@ -29,49 +13,35 @@ export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
|
29
13
|
export function createLedgerSink(opts) {
|
|
30
14
|
const keys = opts.notifiedKeys ?? new NotifiedKeys();
|
|
31
15
|
let seq = 0;
|
|
32
|
-
// [1.211 codex H2] 单写串行链:seq 的「分配」在链步内发生 ⇒ 分配序 == durable 提交序。没有它,
|
|
33
|
-
// onForwardEvent 的 fire-and-forget 写与主循环的 awaited 写交错时,高 seq 可先落盘对 events tail 可见,
|
|
34
|
-
// 迟到的低 seq 在读方游标(afterSeq)前进后被永久遗漏。链上一步失败不断链(catch → undefined),
|
|
35
|
-
// 调用方拿到的是自己那步的真实结果(await 者照常收到 reject)。
|
|
36
16
|
let chain = Promise.resolve();
|
|
37
17
|
let text = "";
|
|
38
18
|
let reasoning = "";
|
|
39
|
-
// E18 resume-at: the turn's FIRST text_delta eventId = the message's stable per-message resume handle,
|
|
40
|
-
// stamped on the durable `text` event (ONE handle per message even when a mid-turn tool_start flushes the
|
|
41
|
-
// text early). Latched on the first DEFINED eventId of the turn (`??=` — a later part after a tool must not
|
|
42
|
-
// re-latch), cleared at turn_end — the exact `TurnAnchorCapture.firstTextEventId` semantics. (The bg leg's
|
|
43
|
-
// anchor tracks the same value for its own anchor-put; both latches see the same events in the same order,
|
|
44
|
-
// so the stamps agree byte-for-byte — the anchor's extra `turnHadTool` state never feeds the stamp.)
|
|
45
19
|
let textEventId;
|
|
46
|
-
// #245 S1:活性打点(顶注契约:两打点位之一;抛错吞掉,绝不拖账本/事件循环下水)。
|
|
47
20
|
const beat = () => {
|
|
48
21
|
try {
|
|
49
22
|
opts.onActivity?.();
|
|
50
23
|
}
|
|
51
24
|
catch {
|
|
52
|
-
/* 分诊打点失败只丢判别材料 */
|
|
53
25
|
}
|
|
54
26
|
};
|
|
55
27
|
const append = (type, data) => {
|
|
56
|
-
beat();
|
|
28
|
+
beat();
|
|
57
29
|
const step = chain.then(() => opts.appendEvent(++seq, type, data));
|
|
58
30
|
chain = step.then(() => undefined, () => undefined);
|
|
59
31
|
return step;
|
|
60
32
|
};
|
|
61
33
|
const flush = async () => {
|
|
62
|
-
// Thinking precedes content within a turn → flush a buffered reasoning block FIRST (redacted).
|
|
63
34
|
if (reasoning) {
|
|
64
35
|
await append("reasoning", { text: redactSecrets(reasoning) });
|
|
65
36
|
reasoning = "";
|
|
66
37
|
}
|
|
67
38
|
if (text) {
|
|
68
|
-
|
|
69
|
-
await append("text", { text, ...(textEventId ? { eventId: textEventId } : {}) }); // persist first; clear only on success so a failed write doesn't drop it
|
|
39
|
+
await append("text", { text, ...(textEventId ? { eventId: textEventId } : {}) });
|
|
70
40
|
text = "";
|
|
71
41
|
}
|
|
72
42
|
};
|
|
73
43
|
const onEvent = async (ev) => {
|
|
74
|
-
beat();
|
|
44
|
+
beat();
|
|
75
45
|
switch (ev.type) {
|
|
76
46
|
case "text_delta": {
|
|
77
47
|
const td = ev;
|
|
@@ -80,104 +50,57 @@ export function createLedgerSink(opts) {
|
|
|
80
50
|
break;
|
|
81
51
|
}
|
|
82
52
|
case "reasoning_delta":
|
|
83
|
-
// Persist the agent's thinking for the trace UI (core [R57]: reasoning IS on the live stream but NOT in
|
|
84
|
-
// the metadata Tracer — capturing it is the service's call). Gated by TRACE_THINKING; redacted on flush.
|
|
85
53
|
if (opts.persistThinking)
|
|
86
54
|
reasoning += ev.delta;
|
|
87
55
|
break;
|
|
88
56
|
case "tool_start":
|
|
89
57
|
await flush();
|
|
90
|
-
// E1+E2 (shell-host contract): redacted args + identity via the shared whitelist builder — identical
|
|
91
|
-
// persisted shape across every leg.
|
|
92
58
|
await append("tool_start", toolStartEventData(ev));
|
|
93
59
|
break;
|
|
94
60
|
case "tool_end":
|
|
95
61
|
await flush();
|
|
96
|
-
// E1: redacted model-facing output (+truncated, core size-bound) + E2 identity, via the shared builder.
|
|
97
62
|
await append("tool_end", toolEndEventData(ev));
|
|
98
63
|
break;
|
|
99
64
|
case "status":
|
|
100
|
-
// S4 (SILENT-FALLBACK P0-a): persist the brain-layer liveness observation. core marks the live frame
|
|
101
|
-
// EPHEMERAL (it never replays it) — this durable row is OUR observation record so async/replay readers
|
|
102
|
-
// can attribute a stalled turn. flush() first (review MED-2): a reconnect can fire MID-TEXT — without
|
|
103
|
-
// the flush the already-streamed text lands AFTER this row and the durable timeline inverts.
|
|
104
|
-
// design/158 B2: durable row type aligned to the live frame name ("status", not "brain_status") — the
|
|
105
|
-
// two legs were emitting the SAME logical event under two different `type` strings, and the SDK's
|
|
106
|
-
// public `AgentEvent` union only declared "status" (a durable-leg reader saw a frame outside its own
|
|
107
|
-
// public type). 写新读旧:这里只管写新;**存量行救不了**(任何旧部署的账本里都躺着 `brain_status`
|
|
108
|
-
// 行),所以重放边界配了一次性归一 —— `normalizeRunEventType`(trace/project.ts),唯一调用点是
|
|
109
|
-
// task_run SSE 的 `formatEvent`(routes/runs.ts)。两半缺一不可:只改写入侧的话,存量行重放时
|
|
110
|
-
// 仍会漏出公开联合之外的名字。无 migration、无回填(读边界归一比改历史行便宜且不可逆风险为零)。
|
|
111
65
|
await flush();
|
|
112
66
|
await append("status", brainStatusEventData(ev));
|
|
113
67
|
break;
|
|
114
68
|
case "context_usage":
|
|
115
|
-
// core 1.414 一等分支(server [1669]⑥ 要的上下文用量面)。每个压缩边界上报一次 ⇒ 一次任务多条,
|
|
116
|
-
// 消费方取最后一条为当前值。两条口径见 `contextUsageEventData` 旁注(别把 windowTokens 当模型上下文)。
|
|
117
69
|
await flush();
|
|
118
70
|
await append("context_usage", contextUsageEventData(ev));
|
|
119
71
|
break;
|
|
120
72
|
case "compacted":
|
|
121
73
|
await flush();
|
|
122
|
-
// MF-18 (1.149) trigger/tokensBefore + core 1.219 attachedFiles/preserved_segment via the SHARED
|
|
123
|
-
// whitelist builder — the shell renders CC's post-compact `Read {path}` cards + the divider from these.
|
|
124
74
|
await append("compacted", compactedEventData(ev));
|
|
125
75
|
break;
|
|
126
76
|
case "diagnostics":
|
|
127
|
-
// core 1.220 (design/121): NEW LSP diagnostics at a turn boundary — the shell's render source for CC's
|
|
128
|
-
// "Found N new diagnostic issues" row. §E1: language-server output is UNTRUSTED RAW → builder redacts.
|
|
129
77
|
await flush();
|
|
130
78
|
await append("diagnostics", diagnosticsEventData(ev));
|
|
131
79
|
break;
|
|
132
80
|
case "steering_injected":
|
|
133
|
-
// [1550]/[1552]: core's mid-run system-reminder injection (todo/file-change/date-roll/skills-delta/…) —
|
|
134
|
-
// the shell's render source for CC's steering-attachment row. §E1: preview is UNTRUSTED free text →
|
|
135
|
-
// builder redacts. Host/self-session only — NOT mirrored into onForwardEvent (a delegated child's own
|
|
136
|
-
// reminders are its internal bookkeeping, not host-relevant progress like tool_start/task_progress).
|
|
137
81
|
await flush();
|
|
138
82
|
await append("steering_injected", steeringInjectedEventData(ev));
|
|
139
83
|
break;
|
|
140
84
|
case "compaction_outcome":
|
|
141
|
-
// [2373]A-2/C-2:此前 durable 双腿零 case ⇒ 回放即消失(与 [1622] label / [1611] workflowRunId
|
|
142
|
-
// 同族)。共享 builder(§E1 脱敏)三腿同源;差集门 durable-append-arm-parity 看守。
|
|
143
85
|
await flush();
|
|
144
86
|
await append("compaction_outcome", compactionOutcomeEventData(ev));
|
|
145
87
|
break;
|
|
146
88
|
case "workspace_changed":
|
|
147
|
-
// [1559]二 core 裁定:design/99 §E13 旧臂,L1 门扩臂时首次撞见。durable 记账与其余内容型臂
|
|
148
|
-
// 同处置(轨迹回放时「何时 cd 到了哪」是合法历史事实,「不当持久态渲染」是 LIVE 消费端纪律,
|
|
149
|
-
// 不是不许落账)——共享白名单构造器 + §E1 redact。
|
|
150
89
|
await flush();
|
|
151
90
|
await append("workspace_changed", workspaceChangedEventData(ev));
|
|
152
91
|
break;
|
|
153
92
|
case "wiring_manifest":
|
|
154
|
-
// 🔴 core 5.14.0 design/173:装配自证清单。账本行**同样**要剥 `governance` 段——durable 行可经
|
|
155
|
-
// `GET /v1/runs/:id/events` 重放给同一批租户订阅者,是与 sync 腿完全相同的泄露面,所以用**同一个**
|
|
156
|
-
// 构造器(两腿分头挑键就是下一次泄露的种子)。core 契约:no projection ⇒ do not disclose。
|
|
157
93
|
await flush();
|
|
158
94
|
await append("wiring_manifest", wiringManifestEventData(ev));
|
|
159
95
|
break;
|
|
160
96
|
case "human_input":
|
|
161
|
-
// core 5.14.0 design/171:人类输入生命周期账本(谁/经哪条载体/投递成没成)。落账是本臂的
|
|
162
|
-
// 正当用途——「这条 run 是谁喂的」正是事后对账要的历史事实;身份串的脱敏在共享构造器里。
|
|
163
97
|
await flush();
|
|
164
98
|
await append("human_input", humanInputEventData(ev));
|
|
165
99
|
break;
|
|
166
100
|
case "task_progress":
|
|
167
|
-
// core breakpoint⑤: a subagent's live progress tick → an INLINE "subagent working" card for the tailing
|
|
168
|
-
// client (S2-a). Shared whitelist+redact builder (+ E2 identity for the exact concurrent-tick binding).
|
|
169
101
|
await append("task_progress", taskProgressEventData(ev));
|
|
170
102
|
break;
|
|
171
103
|
case "task_notification": {
|
|
172
|
-
// core 1.202 (design/115 P2): a background task finished while this harness was live — persist the
|
|
173
|
-
// display projection so a tailing client renders it (summary/result are UNTRUSTED free text → shared
|
|
174
|
-
// builder redacts). core [784]④a+④b: seq-folded shared key + skip keys this leg already delivered
|
|
175
|
-
// (start-of-leg inbox drain or observer arm) — core's pend-drain replays a double-parked idle arrival
|
|
176
|
-
// as a stream event; appending it again doubles the frame in the durable tail. codex F1: a key claimed
|
|
177
|
-
// by a fire-and-forget arm may have FAILED to land — await the claim's outcome; false ⇒ write anyway
|
|
178
|
-
// (this stream replay is the notification's last copy on this leg) and promote the key with THIS
|
|
179
|
-
// write's outcome. The claim promise is registered before the awaited append so a concurrent observer
|
|
180
|
-
// callback can't double-claim mid-write.
|
|
181
104
|
await flush();
|
|
182
105
|
const tn = ev.notification;
|
|
183
106
|
const tnKey = tn?.task_id ? taskNotificationStreamKey({ task_type: tn.task_type, task_id: tn.task_id, status: String(tn.status), seq: tn.seq }) : undefined;
|
|
@@ -185,26 +108,21 @@ export function createLedgerSink(opts) {
|
|
|
185
108
|
if (tnPrior === undefined || !(await tnPrior)) {
|
|
186
109
|
const write = append("task_notification", taskNotificationEventData(ev));
|
|
187
110
|
if (tnKey !== undefined)
|
|
188
|
-
keys.set(tnKey, write.then(() => true, () => false));
|
|
111
|
+
keys.set(tnKey, write.then(() => true, () => false));
|
|
189
112
|
await write;
|
|
190
113
|
}
|
|
191
114
|
break;
|
|
192
115
|
}
|
|
193
116
|
case "turn_end": {
|
|
194
117
|
await flush();
|
|
195
|
-
// core 1.76 (service [41]/core [R59]): per-turn usage rides turn_end.usage — persist it for TraceTurn.tokens.
|
|
196
118
|
const usage = ev.usage;
|
|
197
|
-
await append("turn_end", turnEndEventData(ev));
|
|
198
|
-
textEventId = undefined;
|
|
119
|
+
await append("turn_end", turnEndEventData(ev));
|
|
120
|
+
textEventId = undefined;
|
|
199
121
|
break;
|
|
200
122
|
}
|
|
201
|
-
// `done` / `message_committed` / unknown: deliberate no-ops — see the interface doc.
|
|
202
123
|
}
|
|
203
124
|
};
|
|
204
125
|
const onForwardEvent = (e) => {
|
|
205
|
-
// 1.78 (review HIGH) + C1 (core 1.219, spec.forwardSubagentEvents): a delegated child's lifecycle rides the
|
|
206
|
-
// forward sink (each stamped parentToolCallId — the shell nests them under the delegation card). Same
|
|
207
|
-
// shared builders as the top stream; fire-and-forget (`++seq` is sync → unique seqs vs the awaited loop).
|
|
208
126
|
const t = e.type;
|
|
209
127
|
if (t === "task_progress") {
|
|
210
128
|
void append("task_progress", taskProgressEventData(e)).catch(() => undefined);
|
|
@@ -216,15 +134,8 @@ export function createLedgerSink(opts) {
|
|
|
216
134
|
void append("tool_end", toolEndEventData(e)).catch(() => undefined);
|
|
217
135
|
}
|
|
218
136
|
};
|
|
219
|
-
// #255:第五席的写口 —— 一行,但**位置**是它的全部:`append` 在这里被**同步**调用,序号槽在回调进入
|
|
220
|
-
// 的那一刻就占住(理由与判据全文见接口上的 doc 注)。别为了「与 onEvent 同形」把它改写成
|
|
221
|
-
// `onEvent({type:"status",…})`:那一次 `await flush()` 正是被修掉的病。
|
|
222
137
|
const appendStatus = (ev) => append("status", brainStatusEventData(ev));
|
|
223
|
-
const appendParked = (kind, result) =>
|
|
224
|
-
// Never the capability checkpointToken — only the non-secret gate (search [18] Q1b)。
|
|
225
|
-
// [4913]:结果若已被 graftParkToolCallId 补过待批 toolCallId(调用方在 park 点先 graft),随行投影;
|
|
226
|
-
// 缺席(tool-less park / graft 未接 / 读失败)= 键不铸([1995]② OMITTED 契约,不编 null)。
|
|
227
|
-
append(kind, {
|
|
138
|
+
const appendParked = (kind, result) => append(kind, {
|
|
228
139
|
gate: result?.checkpointGate ?? null,
|
|
229
140
|
...(typeof result?.toolCallId === "string" ? { toolCallId: result.toolCallId } : {}),
|
|
230
141
|
});
|