@sema-agent/core 7.48.0 → 7.49.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/CHANGELOG.md +418 -0
- package/README.md +2 -2
- package/dist/agents/cascade.d.ts +2 -5
- package/dist/agents/child-failure.d.ts +20 -0
- package/dist/agents/child-failure.js +28 -0
- package/dist/agents/cross-session-ref.d.ts +11 -3
- package/dist/agents/cross-session-ref.js +6 -0
- package/dist/agents/cumulative-stats.d.ts +12 -15
- package/dist/agents/cumulative-stats.js +1 -1
- package/dist/agents/extra-tool-names.js +1 -1
- package/dist/agents/inherited-tool-pool.d.ts +17 -13
- package/dist/agents/inherited-tool-pool.js +4 -3
- package/dist/agents/peer-session-drain.d.ts +3 -2
- package/dist/agents/peer-session-drain.js +5 -4
- package/dist/agents/send-message-tool.js +2 -9
- package/dist/agents/subagent.d.ts +10 -29
- package/dist/agents/subagent.js +65 -53
- package/dist/agents/suspend-guard.d.ts +1 -1
- package/dist/agents/tool-filter.d.ts +76 -65
- package/dist/agents/tool-filter.js +122 -92
- package/dist/agents/verify.d.ts +4 -7
- package/dist/agents/verify.js +6 -7
- package/dist/bench/metrics.d.ts +1 -2
- package/dist/brain/anthropic.js +133 -79
- package/dist/brain/errors.d.ts +53 -6
- package/dist/brain/errors.js +22 -2
- package/dist/brain/input-too-long.d.ts +40 -19
- package/dist/brain/input-too-long.js +3 -16
- package/dist/brain/open-responses.js +19 -10
- package/dist/brain/openai.js +123 -32
- package/dist/brain/provider-dialect.d.ts +214 -0
- package/dist/brain/provider-dialect.js +186 -0
- package/dist/brain/request-params.d.ts +27 -8
- package/dist/brain/request-params.js +7 -12
- package/dist/brain/request-route.d.ts +84 -0
- package/dist/brain/request-route.js +41 -0
- package/dist/brain/retry.d.ts +8 -0
- package/dist/brain/retry.js +10 -4
- package/dist/brain/route-adjudicator.d.ts +7 -0
- package/dist/brain/route-adjudicator.js +5 -1
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +11 -0
- package/dist/brain/stream-engine.d.ts +52 -1
- package/dist/brain/stream-engine.js +81 -24
- package/dist/brain/stream-shared.d.ts +57 -11
- package/dist/brain/stream-shared.js +28 -2
- package/dist/core/a2a.d.ts +1 -0
- package/dist/core/agent-config-dir.js +3 -2
- package/dist/core/allow-entry.d.ts +21 -12
- package/dist/core/allow-entry.js +38 -31
- package/dist/core/arg-summary.d.ts +17 -24
- package/dist/core/arg-summary.js +169 -68
- package/dist/core/ask-origin.d.ts +42 -24
- package/dist/core/ask-origin.js +18 -13
- package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/auto-mode-prompt.d.ts +11 -1
- package/dist/core/auto-mode-prompt.js +13 -10
- package/dist/core/auto-mode-rebuild.d.ts +7 -0
- package/dist/core/auto-mode-rebuild.js +4 -1
- package/dist/core/canonical-json.d.ts +3 -0
- package/dist/core/canonical-json.js +2 -1
- package/dist/core/checkpoint-requirements.d.ts +892 -0
- package/dist/core/checkpoint-requirements.js +333 -0
- package/dist/core/checkpoint-store.d.ts +94 -65
- package/dist/core/checkpoint-store.js +14 -26
- package/dist/core/child-clamp-seats.d.ts +228 -69
- package/dist/core/child-clamp-seats.js +211 -17
- package/dist/core/classifier-unavailable-arm.d.ts +5 -1
- package/dist/core/classifier-unavailable-arm.js +3 -3
- package/dist/core/compliance.d.ts +3 -0
- package/dist/core/compliance.js +9 -4
- package/dist/core/credential-vocabulary.d.ts +140 -0
- package/dist/core/credential-vocabulary.js +131 -0
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/effective-path-target.d.ts +73 -16
- package/dist/core/effective-path-target.js +63 -33
- package/dist/core/engine-notice.d.ts +32 -7
- package/dist/core/file-history-store.js +2 -2
- package/dist/core/fs-write-gate-policy.d.ts +4 -0
- package/dist/core/fs-write-gate-policy.js +22 -5
- package/dist/core/gate-bounded-await.d.ts +28 -13
- package/dist/core/gate-bounded-await.js +41 -4
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +24 -25
- package/dist/core/gate-lanes.js +16 -15
- package/dist/core/gate-outcome.d.ts +20 -5
- package/dist/core/gate-outcome.js +5 -0
- package/dist/core/governance-codes.d.ts +11 -4
- package/dist/core/governance-codes.js +14 -3
- package/dist/core/hooks.d.ts +4 -0
- package/dist/core/locked-config.d.ts +8 -0
- package/dist/core/locked-config.js +14 -2
- package/dist/core/lsp.js +3 -5
- package/dist/core/mailbox-store.d.ts +3 -4
- package/dist/core/mcp-connection-pool.d.ts +75 -0
- package/dist/core/mcp-connection-pool.js +128 -0
- package/dist/core/mcp-failure.d.ts +2 -1
- package/dist/core/mcp-failure.js +13 -2
- package/dist/core/mcp.d.ts +4 -0
- package/dist/core/mcp.js +70 -43
- package/dist/core/memory-engine/content-origin.js +2 -14
- package/dist/core/memory-engine/engine.d.ts +32 -22
- package/dist/core/memory-engine/engine.js +103 -55
- package/dist/core/memory-engine/file-backend.d.ts +13 -30
- package/dist/core/memory-engine/file-backend.js +37 -252
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +139 -9
- package/dist/core/memory-engine/layout.js +350 -7
- package/dist/core/memory-engine/scope-contract.d.ts +10 -0
- package/dist/core/memory-engine/scope-contract.js +8 -0
- package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
- package/dist/core/memory-engine/session-incarnation.js +5 -2
- package/dist/core/memory-engine/types.d.ts +10 -1
- package/dist/core/memory.js +5 -17
- package/dist/core/model-seat.d.ts +4 -4
- package/dist/core/model-seat.js +1 -1
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +19 -0
- package/dist/core/namespaced-rule-name.d.ts +29 -0
- package/dist/core/namespaced-rule-name.js +52 -0
- package/dist/core/park-selfcheck.d.ts +1 -1
- package/dist/core/park-selfcheck.js +16 -6
- package/dist/core/path-guard-rows.d.ts +99 -0
- package/dist/core/path-guard-rows.js +45 -0
- package/dist/core/path-identity.d.ts +22 -16
- package/dist/core/path-identity.js +10 -10
- package/dist/core/path-rule-binding.d.ts +2 -1
- package/dist/core/path-rule-binding.js +3 -1
- package/dist/core/pause-registry.d.ts +16 -2
- package/dist/core/pause-registry.js +6 -0
- package/dist/core/permission-rule-consent.js +0 -7
- package/dist/core/permission-rule-model.d.ts +68 -24
- package/dist/core/permission-rule-model.js +105 -24
- package/dist/core/permission-rule-store.js +2 -2
- package/dist/core/permission-rules.d.ts +3 -30
- package/dist/core/permission-rules.js +4 -54
- package/dist/core/read-root-candidate.d.ts +1 -3
- package/dist/core/read-root-candidate.js +4 -15
- package/dist/core/real-approval.d.ts +4 -3
- package/dist/core/retired-keys.d.ts +13 -0
- package/dist/core/retired-keys.js +14 -0
- package/dist/core/roles.d.ts +2 -3
- package/dist/core/roles.js +15 -6
- package/dist/core/runner/assemble-result.d.ts +0 -7
- package/dist/core/runner/assemble-result.js +19 -31
- package/dist/core/runner/caller-roster.d.ts +78 -0
- package/dist/core/runner/caller-roster.js +219 -0
- package/dist/core/runner/checkpoint-scope.d.ts +16 -16
- package/dist/core/runner/checkpoint-scope.js +2 -2
- package/dist/core/runner/child-tree.js +2 -2
- package/dist/core/runner/contracts.d.ts +68 -35
- package/dist/core/runner/decide-continuation.d.ts +51 -3
- package/dist/core/runner/decide-continuation.js +76 -21
- package/dist/core/runner/denial-limit-arms.d.ts +17 -5
- package/dist/core/runner/denial-limit-arms.js +11 -9
- package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
- package/dist/core/runner/extra-body-dropped-seat.js +22 -0
- package/dist/core/runner/finish-reason-seat.d.ts +9 -0
- package/dist/core/runner/finish-reason-seat.js +40 -0
- package/dist/core/runner/gate-exit.d.ts +44 -32
- package/dist/core/runner/gate-exit.js +112 -25
- package/dist/core/runner/inherited-ask-grants.js +6 -4
- package/dist/core/runner/mcp-redial.d.ts +3 -3
- package/dist/core/runner/mcp-redial.js +3 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
- package/dist/core/runner/permission-rule-lanes.js +5 -4
- package/dist/core/runner/prepare-artifact.d.ts +4 -0
- package/dist/core/runner/prepare-artifact.js +2 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
- package/dist/core/runner/prepare-ask-lane.js +12 -6
- package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
- package/dist/core/runner/prepare-boundary-parks.js +4 -7
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
- package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
- package/dist/core/runner/prepare-config-doors.d.ts +9 -9
- package/dist/core/runner/prepare-config-doors.js +10 -5
- package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
- package/dist/core/runner/prepare-defer-classify.js +5 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-delegation-surface.js +3 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
- package/dist/core/runner/prepare-gate-stations.js +9 -7
- package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
- package/dist/core/runner/prepare-hands-readface.js +7 -7
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
- package/dist/core/runner/prepare-inherited-gate.js +14 -15
- package/dist/core/runner/prepare-listings.d.ts +7 -24
- package/dist/core/runner/prepare-listings.js +4 -5
- package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
- package/dist/core/runner/prepare-memory-engine-session.js +4 -3
- package/dist/core/runner/prepare-memory.d.ts +6 -0
- package/dist/core/runner/prepare-memory.js +13 -13
- package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
- package/dist/core/runner/prepare-offload-wrappers.js +3 -3
- package/dist/core/runner/prepare-park-ask.d.ts +7 -8
- package/dist/core/runner/prepare-park-ask.js +17 -10
- package/dist/core/runner/prepare-policy-chain.js +24 -44
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +3 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -4
- package/dist/core/runner/prepare-run-refs.d.ts +3 -0
- package/dist/core/runner/prepare-run-refs.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
- package/dist/core/runner/prepare-suspend-saga.js +28 -12
- package/dist/core/runner/prepare-task.d.ts +1 -1
- package/dist/core/runner/prepare-task.js +67 -56
- package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
- package/dist/core/runner/prepare-wiring-manifest.js +5 -8
- package/dist/core/runner/resume-apply.js +7 -14
- package/dist/core/runner/resume-checkpoint-screen.js +11 -4
- package/dist/core/runner/resume-internals-and-config.js +2 -2
- package/dist/core/runner/resume-policy-outcome.js +5 -32
- package/dist/core/runner/resume-review-outcome.js +4 -1
- package/dist/core/runner/retired-runner-deps.d.ts +6 -0
- package/dist/core/runner/retired-runner-deps.js +10 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -0
- package/dist/core/runner/run-brain-sinks.js +5 -2
- package/dist/core/runner/run-harness-handlers.js +27 -34
- package/dist/core/runner/run-leg.d.ts +0 -2
- package/dist/core/runner/run-leg.js +32 -33
- package/dist/core/runner/run-terminal-adoption.js +4 -3
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-rule-policy.js +5 -5
- package/dist/core/runner/stream-settle-backstop.js +7 -4
- package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
- package/dist/core/runner/sub-agent-deny-lists.js +111 -80
- package/dist/core/runner/terminal-account.d.ts +48 -0
- package/dist/core/runner/terminal-account.js +186 -0
- package/dist/core/runner/tool-end-body.d.ts +54 -17
- package/dist/core/runner/tool-end-body.js +27 -2
- package/dist/core/runner/tool-face-overlay.d.ts +3 -1
- package/dist/core/runner/tool-face-overlay.js +6 -4
- package/dist/core/runner/tool-occurrence.d.ts +106 -0
- package/dist/core/runner/tool-occurrence.js +123 -0
- package/dist/core/runner/tool-progress-lane.d.ts +16 -8
- package/dist/core/runner/tool-progress-lane.js +25 -34
- package/dist/core/runner/turn-attachments.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +21 -9
- package/dist/core/runner/write-protection-station.js +20 -17
- package/dist/core/runner-deps.d.ts +12 -22
- package/dist/core/secret-env.d.ts +16 -5
- package/dist/core/secret-env.js +23 -63
- package/dist/core/sensitive-path-policy.d.ts +19 -18
- package/dist/core/sensitive-path-policy.js +73 -49
- package/dist/core/session-reconcile.d.ts +3 -0
- package/dist/core/session-reconcile.js +5 -4
- package/dist/core/session-store.d.ts +5 -0
- package/dist/core/session-store.js +12 -0
- package/dist/core/session.d.ts +13 -0
- package/dist/core/shared-memory/normalize.d.ts +17 -4
- package/dist/core/shared-memory/normalize.js +7 -7
- package/dist/core/shell-lexer.js +5 -4
- package/dist/core/skill-grant.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +2 -2
- package/dist/core/task-event.d.ts +59 -5
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +42 -9
- package/dist/core/terminal-cause.d.ts +94 -11
- package/dist/core/tighten-task-spec.d.ts +5 -4
- package/dist/core/tighten-task-spec.js +20 -25
- package/dist/core/tool-catalog-entries.d.ts +5 -7
- package/dist/core/tool-catalog-entries.js +14 -15
- package/dist/core/tool-face.d.ts +47 -0
- package/dist/core/tool-face.js +5 -0
- package/dist/core/tool-model-gate.d.ts +5 -5
- package/dist/core/tool-name-aliases.d.ts +26 -2
- package/dist/core/tool-name-aliases.js +13 -0
- package/dist/core/tool-name-list.d.ts +30 -0
- package/dist/core/tool-name-list.js +55 -0
- package/dist/core/tool-name-readings.d.ts +1 -9
- package/dist/core/tool-name-readings.js +1 -3
- package/dist/core/tool-policy.d.ts +195 -85
- package/dist/core/tool-policy.js +165 -380
- package/dist/core/tool-registry.d.ts +44 -1
- package/dist/core/tool-registry.js +26 -0
- package/dist/core/tool-roster.d.ts +19 -1
- package/dist/core/tool-roster.js +21 -2
- package/dist/core/tool-spec-members.d.ts +45 -0
- package/dist/core/tool-spec-members.js +169 -0
- package/dist/core/tool-spec.d.ts +46 -8
- package/dist/core/tools.d.ts +6 -2
- package/dist/core/tools.js +8 -4
- package/dist/core/untrusted-egress.js +29 -26
- package/dist/core/untrusted-text.d.ts +13 -10
- package/dist/core/untrusted-text.js +6 -44
- package/dist/core/workflow-journal-store.d.ts +4 -1
- package/dist/core/write-protect.d.ts +65 -29
- package/dist/core/write-protect.js +235 -177
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
- package/dist/engine/execution-env/node-execution-env.js +16 -38
- package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
- package/dist/engine/execution-env/symlink-chain.js +32 -0
- package/dist/engine/harness/types.d.ts +7 -0
- package/dist/engine/llm/tool-turns.d.ts +3 -0
- package/dist/engine/llm/tool-turns.js +1 -0
- package/dist/engine/llm/types.d.ts +59 -23
- package/dist/engine/loop/agent-loop.js +16 -2
- package/dist/engine/session/memory-repo.js +11 -3
- package/dist/engine/session/repo-utils.d.ts +8 -0
- package/dist/engine/session/repo-utils.js +13 -0
- package/dist/index.d.ts +20 -23
- package/dist/index.js +17 -20
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/governance-baseline-validity.js +1 -1
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +16 -35
- package/dist/orchestration/run-workflow-tool.js +38 -78
- package/dist/orchestration/workflow-governance.d.ts +21 -25
- package/dist/orchestration/workflow-governance.js +38 -78
- package/dist/orchestration/workflow-primitives.d.ts +7 -22
- package/dist/orchestration/workflow-primitives.js +5 -12
- package/dist/orchestration/workflow-types.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +61 -11
- package/dist/orchestration/workflow.js +189 -117
- package/dist/scenarios/full-body.d.ts +1 -1
- package/dist/shell/lex.d.ts +0 -21
- package/dist/shell/lex.js +250 -68
- package/dist/shell/shell-words.d.ts +35 -0
- package/dist/shell/shell-words.js +65 -0
- package/dist/stores/file/checkpoint-store.d.ts +5 -5
- package/dist/stores/file/checkpoint-store.js +5 -2
- package/dist/stores/file/index.d.ts +0 -8
- package/dist/stores/file/index.js +0 -12
- package/dist/stores/file/session-store.d.ts +3 -0
- package/dist/stores/file/session-store.js +44 -19
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/bash-program-position.d.ts +10 -3
- package/dist/tools/fs/bash-program-position.js +21 -9
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/bash-readonly-classifier.js +8 -7
- package/dist/tools/fs/containment-face.d.ts +4 -0
- package/dist/tools/fs/containment-face.js +3 -0
- package/dist/tools/fs/fs-shared.d.ts +10 -0
- package/dist/tools/fs/fs-shared.js +18 -0
- package/dist/tools/fs/fs-write.js +4 -2
- package/dist/tools/fs/index.d.ts +1 -1
- package/dist/tools/fs/program-read-model.d.ts +39 -18
- package/dist/tools/fs/program-read-model.js +29 -19
- package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
- package/dist/tools/fs/program-read-model.rows.js +5 -5
- package/dist/tools/fs/read-deny-home.d.ts +33 -47
- package/dist/tools/fs/read-deny-home.js +35 -49
- package/dist/tools/fs/read-deny.d.ts +23 -22
- package/dist/tools/fs/read-deny.js +114 -89
- package/dist/tools/fs/removal-targets.d.ts +56 -23
- package/dist/tools/fs/removal-targets.js +65 -87
- package/dist/tools/fs/safety.d.ts +29 -22
- package/dist/tools/fs/safety.js +17 -11
- package/dist/tools/fs/search.js +10 -8
- package/dist/tools/fs/shell-read-argv.js +1 -1
- package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
- package/dist/tools/fs/shell-read-bindings.js +324 -86
- package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
- package/dist/tools/fs/shell-read-builtins.js +43 -0
- package/dist/tools/fs/shell-read-check.d.ts +15 -1
- package/dist/tools/fs/shell-read-check.js +51 -42
- package/dist/tools/fs/shell-read-establish.js +6 -6
- package/dist/tools/fs/shell-read-functions.d.ts +22 -0
- package/dist/tools/fs/shell-read-functions.js +29 -0
- package/dist/tools/fs/shell-read-judge.d.ts +48 -18
- package/dist/tools/fs/shell-read-judge.js +33 -4
- package/dist/tools/fs/shell-read-plan.d.ts +12 -6
- package/dist/tools/fs/shell-read-plan.js +118 -113
- package/dist/tools/fs/shell-read-start.d.ts +29 -6
- package/dist/tools/fs/shell-read-start.js +16 -9
- package/dist/tools/fs/shell-read-word.js +4 -0
- package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
- package/dist/tools/fs/shell-read-workdir.js +281 -0
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
- package/dist/tools/fs/shell-read-write-targets.js +14 -5
- package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
- package/dist/tools/fs/shell-reentry-text.js +3 -11
- package/dist/tools/task-list.d.ts +1 -2
- package/dist/tools/web.js +1 -1
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +107 -143
- package/wire-changes/core@7.49.0.json +4765 -0
- package/dist/agents/teacher.d.ts +0 -159
- package/dist/agents/teacher.js +0 -577
- package/dist/agents/team.d.ts +0 -226
- package/dist/agents/team.js +0 -257
- package/dist/core/strategy-store.d.ts +0 -238
- package/dist/core/strategy-store.js +0 -253
- package/dist/orchestration/builtin-workflows.d.ts +0 -133
- package/dist/orchestration/builtin-workflows.js +0 -159
- package/dist/scenarios/env.d.ts +0 -40
- package/dist/scenarios/env.js +0 -39
- package/dist/scenarios/scenario-registry.d.ts +0 -110
- package/dist/scenarios/scenario-registry.js +0 -140
- package/dist/scenarios/teacher-quickstart.d.ts +0 -40
- package/dist/scenarios/teacher-quickstart.js +0 -12
- package/dist/stores/cc/lockfile.d.ts +0 -10
- package/dist/stores/cc/lockfile.js +0 -98
- package/dist/stores/cc/mailbox-store.d.ts +0 -20
- package/dist/stores/cc/mailbox-store.js +0 -255
- package/dist/stores/cc/roster-adapter.d.ts +0 -12
- package/dist/stores/cc/roster-adapter.js +0 -117
- package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
- package/dist/stores/cc/sidecar-transcript.js +0 -264
- package/dist/stores/cc/task-list-store.d.ts +0 -2
- package/dist/stores/cc/task-list-store.js +0 -125
- package/dist/stores/file/strategy-store.d.ts +0 -97
- package/dist/stores/file/strategy-store.js +0 -341
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { MODEL_OUTPUT_INVALID_CAUSES } from "../../internal/llm.js";
|
|
2
|
+
import { isProviderEchoShape } from "../../brain/errors.js";
|
|
3
|
+
import { isProviderCondition, isProviderConditionSource } from "../../brain/provider-dialect.js";
|
|
4
|
+
import { admittedRequestRoute } from "../../brain/request-route.js";
|
|
5
|
+
import { readMember } from "../thrown-value.js";
|
|
6
|
+
import { redactSecrets } from "../untrusted-egress.js";
|
|
7
|
+
import { isSensitiveName, looksLikeCredentialValue } from "../secret-env.js";
|
|
8
|
+
import { isSensitiveRecordKey } from "../credential-vocabulary.js";
|
|
9
|
+
export function providerVerdictOf(final) {
|
|
10
|
+
const condition = readMember(final, "providerCondition");
|
|
11
|
+
const source = readMember(final, "providerConditionSource");
|
|
12
|
+
if (!isProviderCondition(condition) || !isProviderConditionSource(source))
|
|
13
|
+
return {};
|
|
14
|
+
const resetAtMs = readMember(final, "providerResetAtMs");
|
|
15
|
+
return { providerCondition: condition, providerConditionSource: source, ...(typeof resetAtMs === "number" && Number.isFinite(resetAtMs) ? { providerResetAtMs: resetAtMs } : {}) };
|
|
16
|
+
}
|
|
17
|
+
export function requestRouteOfMessage(final) {
|
|
18
|
+
return admittedRequestRoute(readMember(final, "apiErrorRoute"));
|
|
19
|
+
}
|
|
20
|
+
const MODEL_OUTPUT_INVALID_CAUSE_SET = new Set(MODEL_OUTPUT_INVALID_CAUSES);
|
|
21
|
+
const countOf = (v) => (typeof v === "number" && Number.isInteger(v) && v >= 0 ? v : undefined);
|
|
22
|
+
export function modelOutputInvalidOfMessage(final) {
|
|
23
|
+
const account = readMember(final, "modelOutputInvalid");
|
|
24
|
+
const cause = readMember(account, "cause");
|
|
25
|
+
if (!MODEL_OUTPUT_INVALID_CAUSE_SET.has(cause))
|
|
26
|
+
return undefined;
|
|
27
|
+
const limit = cause === "truncated" ? readMember(account, "outputLimit") : undefined;
|
|
28
|
+
const capStop = readMember(limit, "capStop");
|
|
29
|
+
if (typeof capStop !== "boolean")
|
|
30
|
+
return { cause: cause };
|
|
31
|
+
const outputTokens = countOf(readMember(limit, "outputTokens"));
|
|
32
|
+
const capTokens = countOf(readMember(limit, "capTokens"));
|
|
33
|
+
const outputLimit = { capStop, ...(outputTokens !== undefined ? { outputTokens } : {}), ...(capTokens !== undefined ? { capTokens } : {}) };
|
|
34
|
+
return { cause: cause, outputLimit };
|
|
35
|
+
}
|
|
36
|
+
const CODED_DETAIL_DEPTH = 4;
|
|
37
|
+
const CODED_DETAIL_ENTRIES = 64;
|
|
38
|
+
const CODED_DETAIL_STRING = 4_096;
|
|
39
|
+
const CODED_DETAIL_VALUES = 256;
|
|
40
|
+
const CODED_DETAIL_CHARS = 16_384;
|
|
41
|
+
const REDACTED = "[redacted]";
|
|
42
|
+
const INDEX_KEY_RE = /^(?:0|[1-9][0-9]*)$/;
|
|
43
|
+
function carriesCredential(text) {
|
|
44
|
+
return looksLikeCredentialValue(text) || redactSecrets(text) !== text;
|
|
45
|
+
}
|
|
46
|
+
const NAME_CHARS = 128;
|
|
47
|
+
function namesCredential(name) {
|
|
48
|
+
return name.length <= NAME_CHARS && (isSensitiveName(name) || isSensitiveRecordKey(name));
|
|
49
|
+
}
|
|
50
|
+
const NAME_POSITION_KEYS = new Set(["name", "key", "header", "field"]);
|
|
51
|
+
const VALUE_POSITION_KEYS = new Set(["value", "val"]);
|
|
52
|
+
function charge(budget, chars) {
|
|
53
|
+
if (budget.values >= CODED_DETAIL_VALUES || budget.chars + chars > CODED_DETAIL_CHARS)
|
|
54
|
+
return false;
|
|
55
|
+
budget.values++;
|
|
56
|
+
budget.chars += chars;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
function leafOf(keyContext, read, depth, budget) {
|
|
60
|
+
if (keyContext !== undefined && namesCredential(keyContext))
|
|
61
|
+
return charge(budget, REDACTED.length) ? REDACTED : undefined;
|
|
62
|
+
const value = read();
|
|
63
|
+
if (value === null || typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value)))
|
|
64
|
+
return charge(budget, 0) ? value : undefined;
|
|
65
|
+
if (typeof value === "string") {
|
|
66
|
+
if (value.length > CODED_DETAIL_STRING)
|
|
67
|
+
return undefined;
|
|
68
|
+
const shown = carriesCredential(value) ? REDACTED : value;
|
|
69
|
+
return charge(budget, shown.length) ? shown : undefined;
|
|
70
|
+
}
|
|
71
|
+
if (typeof value !== "object" || depth >= CODED_DETAIL_DEPTH)
|
|
72
|
+
return undefined;
|
|
73
|
+
let isArray;
|
|
74
|
+
try {
|
|
75
|
+
if (ArrayBuffer.isView(value))
|
|
76
|
+
return undefined;
|
|
77
|
+
isArray = Array.isArray(value);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
if (!isArray)
|
|
83
|
+
return recordOf(value, depth, budget);
|
|
84
|
+
const length = readMember(value, "length");
|
|
85
|
+
if (typeof length !== "number" || !Number.isInteger(length) || length < 0 || length > CODED_DETAIL_ENTRIES)
|
|
86
|
+
return undefined;
|
|
87
|
+
if (!charge(budget, 0))
|
|
88
|
+
return undefined;
|
|
89
|
+
const items = [];
|
|
90
|
+
const handed = Array.from({ length }, (_, i) => readMember(value, String(i)));
|
|
91
|
+
for (let i = 0; i < length; i++) {
|
|
92
|
+
const before = handed[i - 1];
|
|
93
|
+
const item = leafOf(typeof before === "string" && namesCredential(before) ? before : keyContext, () => handed[i], depth + 1, budget);
|
|
94
|
+
if (item === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
items.push(item);
|
|
97
|
+
}
|
|
98
|
+
return items;
|
|
99
|
+
}
|
|
100
|
+
function pairedNameOf(value, keys, read) {
|
|
101
|
+
if (!keys.some((k) => VALUE_POSITION_KEYS.has(k.toLowerCase())))
|
|
102
|
+
return undefined;
|
|
103
|
+
let named;
|
|
104
|
+
for (const key of keys) {
|
|
105
|
+
if (!NAME_POSITION_KEYS.has(key.toLowerCase()))
|
|
106
|
+
continue;
|
|
107
|
+
const name = readMember(value, key);
|
|
108
|
+
read.set(key, name);
|
|
109
|
+
if (named === undefined && typeof name === "string" && namesCredential(name))
|
|
110
|
+
named = name;
|
|
111
|
+
}
|
|
112
|
+
return named;
|
|
113
|
+
}
|
|
114
|
+
function recordOf(value, depth, budget) {
|
|
115
|
+
let keys;
|
|
116
|
+
try {
|
|
117
|
+
keys = Object.keys(value);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
if (keys.length > CODED_DETAIL_ENTRIES || (keys.length > 0 && keys.every((k) => INDEX_KEY_RE.test(k))) || !charge(budget, 0))
|
|
123
|
+
return undefined;
|
|
124
|
+
const nameMembers = new Map();
|
|
125
|
+
const paired = pairedNameOf(value, keys, nameMembers);
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const key of keys) {
|
|
128
|
+
if (!isProviderEchoShape(key) || carriesCredential(key) || budget.chars + key.length > CODED_DETAIL_CHARS)
|
|
129
|
+
continue;
|
|
130
|
+
const charsBefore = budget.chars;
|
|
131
|
+
budget.chars += key.length;
|
|
132
|
+
const context = paired !== undefined && VALUE_POSITION_KEYS.has(key.toLowerCase()) ? paired : key;
|
|
133
|
+
const admitted = leafOf(context, () => (nameMembers.has(key) ? nameMembers.get(key) : readMember(value, key)), depth + 1, budget);
|
|
134
|
+
if (admitted === undefined)
|
|
135
|
+
budget.chars = charsBefore;
|
|
136
|
+
else
|
|
137
|
+
Object.defineProperty(out, key, { value: admitted, enumerable: true, writable: true, configurable: true });
|
|
138
|
+
}
|
|
139
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
140
|
+
}
|
|
141
|
+
function detailRecordOf(detail) {
|
|
142
|
+
try {
|
|
143
|
+
if (detail === null || typeof detail !== "object" || Array.isArray(detail) || ArrayBuffer.isView(detail))
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
return recordOf(detail, 0, { values: 0, chars: 0 });
|
|
150
|
+
}
|
|
151
|
+
function codedFailureDetailOf(link) {
|
|
152
|
+
const detail = detailRecordOf(readMember(link, "detail"));
|
|
153
|
+
return detail === undefined ? undefined : { kind: "coded", detail };
|
|
154
|
+
}
|
|
155
|
+
export function errorCodeOf(err) {
|
|
156
|
+
return codedLinkOf(err)?.code;
|
|
157
|
+
}
|
|
158
|
+
function codedLinkOf(err) {
|
|
159
|
+
let cur = err;
|
|
160
|
+
let fallback;
|
|
161
|
+
for (let depth = 0; cur !== null && cur !== undefined && typeof cur === "object" && depth < 8; depth++) {
|
|
162
|
+
const code = readMember(cur, "code");
|
|
163
|
+
if (typeof code === "string" && code) {
|
|
164
|
+
if (code !== "unknown") {
|
|
165
|
+
return { code, link: cur };
|
|
166
|
+
}
|
|
167
|
+
fallback ??= { code, link: cur };
|
|
168
|
+
}
|
|
169
|
+
cur = readMember(cur, "cause");
|
|
170
|
+
}
|
|
171
|
+
return fallback;
|
|
172
|
+
}
|
|
173
|
+
export function thrownFailureOf(err, text) {
|
|
174
|
+
const message = redactSecrets(text);
|
|
175
|
+
const coded = codedLinkOf(err);
|
|
176
|
+
if (coded === undefined)
|
|
177
|
+
return { message };
|
|
178
|
+
const detail = codedFailureDetailOf(coded.link);
|
|
179
|
+
return { code: coded.code, message, ...(detail !== undefined ? { detail } : {}) };
|
|
180
|
+
}
|
|
181
|
+
export function completedTerminalOf(final) {
|
|
182
|
+
const finishReasonUnknown = readMember(final, "finishReasonUnknown");
|
|
183
|
+
return typeof finishReasonUnknown === "string" && isProviderEchoShape(finishReasonUnknown)
|
|
184
|
+
? { kind: "completed", detail: { kind: "finish_reason_unknown", finishReasonUnknown } }
|
|
185
|
+
: { kind: "completed" };
|
|
186
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What the run loop derives from a tool call's
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* What the run loop derives from a tool call's occurrence (`tool-occurrence.ts`), in every leg that opens or
|
|
3
|
+
* closes one: the `tool_start` and `tool_end` frames (the ONE start projection and the ONE end projection the
|
|
4
|
+
* live loop, the resumed batch and both reconciles go through, with the frame body), the `toolResult`
|
|
5
|
+
* transcript message the resume engine closes pending calls with, the thin
|
|
5
6
|
* `response` digest the post-tool-batch observer is handed, and the canonical write-tool → reminder-window
|
|
6
7
|
* family the attachment reducer keys on when a write tool ends.
|
|
7
8
|
*
|
|
@@ -13,6 +14,8 @@
|
|
|
13
14
|
*/
|
|
14
15
|
import { type AgentMessage } from "../../internal/harness.js";
|
|
15
16
|
import type { GateOutcome } from "../gate-outcome.js";
|
|
17
|
+
import type { TaskEvent, TaskEventIdentity } from "../types.js";
|
|
18
|
+
import type { OccurrenceStart, ToolOccurrenceTable } from "./tool-occurrence.js";
|
|
16
19
|
import { type McpDelivered } from "../mcp-failure.js";
|
|
17
20
|
import type { RecoveredOrphan } from "../session-reconcile.js";
|
|
18
21
|
import { type StructuredProjector } from "./tool-output-projection.js";
|
|
@@ -33,8 +36,8 @@ export declare function toolEndBodyFrom(result: unknown, isError: boolean,
|
|
|
33
36
|
* set alone would silently drop every declared caller card and never announce. */
|
|
34
37
|
structured: StructuredProjector,
|
|
35
38
|
/** The gate's record of the pass that admitted or refused this call, supplied by the CALLER of this
|
|
36
|
-
* projection — the
|
|
37
|
-
*
|
|
39
|
+
* projection — the end projection ({@link emitSettled}) reads it off the call's occurrence (its latest gate
|
|
40
|
+
* record). Deliberately a parameter and never derived from `result`: a tool's own `details`
|
|
38
41
|
* (which post-tool hooks may also replace) is writable by layers that adjudicate nothing, so reading
|
|
39
42
|
* provenance out of it would let a failing tool claim a person approved it. Omitted ⇒ the call never
|
|
40
43
|
* went through the gate (see the `tool_end.gate` doc, the one home). */
|
|
@@ -54,21 +57,55 @@ gatedCallIdOfRun?: string): {
|
|
|
54
57
|
gatedCallId?: string;
|
|
55
58
|
gate?: GateOutcome;
|
|
56
59
|
};
|
|
60
|
+
/** A frame of one tool call before the leg stamps its identity. */
|
|
61
|
+
export type OccurrenceFrame = Omit<Extract<TaskEvent, {
|
|
62
|
+
type: "tool_start";
|
|
63
|
+
}>, keyof TaskEventIdentity> | Omit<Extract<TaskEvent, {
|
|
64
|
+
type: "tool_end";
|
|
65
|
+
}>, keyof TaskEventIdentity>;
|
|
66
|
+
/** Where an occurrence's frames go: the leg's push (it stamps the identity and picks the queue) and its card projector. */
|
|
67
|
+
export interface OccurrenceFrames {
|
|
68
|
+
push(frame: OccurrenceFrame): void;
|
|
69
|
+
structured: StructuredProjector;
|
|
70
|
+
}
|
|
71
|
+
/** The START projection: the call's occurrence opens and its start frame goes out. Every leg that announces a call
|
|
72
|
+
* comes through here (the live loop's `tool_execution_start`, the resumed leg's approved call). */
|
|
73
|
+
export declare function announceToolCall(table: ToolOccurrenceTable, start: OccurrenceStart, frames: Pick<OccurrenceFrames, "push">): void;
|
|
74
|
+
/** How a call ended, as the station closing it knows it. */
|
|
75
|
+
export interface OccurrenceEnd {
|
|
76
|
+
/** The harness result (or the exact text the closing station records). */
|
|
77
|
+
result: unknown;
|
|
78
|
+
isError: boolean;
|
|
79
|
+
/** POSITIVE evidence the call never executed — the loop's own mark on a call it closed without running it, or the
|
|
80
|
+
* reconcile's never-started class. Absent = no such evidence, never "it ran" (see `tool_end.notExecuted`). */
|
|
81
|
+
notExecuted?: true;
|
|
82
|
+
/** The call is closed by an interruption rather than a result of its own. */
|
|
83
|
+
interrupted?: true;
|
|
84
|
+
/** See {@link toolEndBodyFrom}'s parameter of the same name. */
|
|
85
|
+
gatedCallIdOfRun?: string;
|
|
86
|
+
}
|
|
87
|
+
/** What the end projection decided, for the readers that ride beside the frame (the trace row, the row's record). */
|
|
88
|
+
export interface SettledOccurrence {
|
|
89
|
+
/** The latest gate record — the call's disposition (absent when no gate exit saw it). */
|
|
90
|
+
gate?: GateOutcome;
|
|
91
|
+
/** The tool's own error bit, or a refusal recorded after the gate: the engine's record wins over the tool's word. */
|
|
92
|
+
isError: boolean;
|
|
93
|
+
}
|
|
57
94
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
95
|
+
* The END projection — the ONE mint of `tool_end`, for every station that closes a call: the live loop's
|
|
96
|
+
* `tool_execution_end`, the resumed leg's resolution, an interrupted run's reconcile and the reconcile replayed at
|
|
97
|
+
* the next process start. It reads the occurrence and nothing else: `gate` is its latest gate record, `isError` is
|
|
98
|
+
* the tool's bit or the refusal that record names, and `notExecuted` rides only on the station's positive evidence.
|
|
61
99
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* disagreed. The projection goes through the same {@link toolEndBodyFrom} every live tool result uses, so
|
|
66
|
-
* `output` = the persisted model-facing text and `errorCode` = the persisted `details.errorKind`
|
|
67
|
-
* (`interrupted_never_started` / `interrupted_outcome_unknown`) — a consumer discriminates on the code
|
|
68
|
-
* instead of prose-matching. No `structured`: the reconcile mints no CC card (no `details.type`), which the
|
|
69
|
-
* leg's projector already enforces.
|
|
100
|
+
* A call whose start never went out on this stream (a call the loop never reached, a call announced by a dead
|
|
101
|
+
* process) gets its start minted here first, marked `recovered` and carrying the input the closing station holds —
|
|
102
|
+
* every end is preceded by a start with the same id. `start` opens the occurrence only when this leg holds none.
|
|
70
103
|
*/
|
|
71
|
-
export declare function
|
|
104
|
+
export declare function emitSettled(table: ToolOccurrenceTable, start: OccurrenceStart, end: OccurrenceEnd, frames: OccurrenceFrames): SettledOccurrence;
|
|
105
|
+
/** The end of a call an interrupted run's reconcile closed: the persisted `[INTERRUPTED]` text is the body and its
|
|
106
|
+
* `errorKind` the frame's `errorCode` (no card — the reconcile mints none), and the never-started class is the
|
|
107
|
+
* positive evidence `notExecuted` needs. One reading for both reconciling legs (the live abort, the next start). */
|
|
108
|
+
export declare function reconciledEnd(orphan: Pick<RecoveredOrphan, "text" | "errorKind">): OccurrenceEnd;
|
|
72
109
|
/** task #51 F2/F3 — the CANONICAL write-tool → reminder-window mapping (CC qFm :480253-480254
|
|
73
110
|
* `a.name === bD || a.name === hF` = TaskCreate/TaskUpdate; BFm :480217-480219 = TodoWrite). Live
|
|
74
111
|
* deployment-alias resolution happens at the call sites (run-local `writeFamilyOf` over the mounted
|
|
@@ -52,8 +52,33 @@ export function toolEndBodyFrom(result, isError, structured, gate, gatedCallIdOf
|
|
|
52
52
|
...(gate !== undefined ? { gate } : {}),
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const startFrameOf = (o, recovered) => ({ type: "tool_start", toolCallId: o.toolCallId, toolName: o.spelledName, ...(o.label !== undefined ? { label: o.label } : {}), args: o.args, ...(recovered ? { recovered: true } : {}) });
|
|
56
|
+
export function announceToolCall(table, start, frames) {
|
|
57
|
+
table.open(start);
|
|
58
|
+
frames.push(startFrameOf(start, false));
|
|
59
|
+
table.noteStartEmitted(start.toolCallId);
|
|
60
|
+
}
|
|
61
|
+
export function emitSettled(table, start, end, frames) {
|
|
62
|
+
const occ = table.ensure(start);
|
|
63
|
+
if (!occ.startEmitted)
|
|
64
|
+
frames.push(startFrameOf(occ, true));
|
|
65
|
+
const gate = occ.gateRounds.at(-1);
|
|
66
|
+
const isError = end.isError || gate?.disposition.kind === "denied";
|
|
67
|
+
table.close(occ.toolCallId, end.interrupted === true ? "interrupted" : "settled");
|
|
68
|
+
frames.push({
|
|
69
|
+
type: "tool_end",
|
|
70
|
+
toolCallId: occ.toolCallId,
|
|
71
|
+
toolName: occ.spelledName,
|
|
72
|
+
...(occ.label !== undefined ? { label: occ.label } : {}),
|
|
73
|
+
isError,
|
|
74
|
+
...toolEndBodyFrom(end.result, isError, frames.structured, gate, end.gatedCallIdOfRun),
|
|
75
|
+
...(gate?.disposition.kind === "denied" && occ.wireName !== undefined ? { wireName: occ.wireName } : {}),
|
|
76
|
+
...(end.notExecuted === true ? { notExecuted: true } : {}),
|
|
77
|
+
});
|
|
78
|
+
return { ...(gate !== undefined ? { gate } : {}), isError };
|
|
79
|
+
}
|
|
80
|
+
export function reconciledEnd(orphan) {
|
|
81
|
+
return { result: { content: orphan.text, details: { code: orphan.errorKind } }, isError: true, interrupted: true, ...(orphan.errorKind === "interrupted_never_started" ? { notExecuted: true } : {}) };
|
|
57
82
|
}
|
|
58
83
|
export function writeFamilyOfCanonical(name) {
|
|
59
84
|
if (name === TASK_CREATE_TOOL_NAME || name === TASK_UPDATE_TOOL_NAME)
|
|
@@ -21,7 +21,9 @@ import { type EngineNotice } from "../engine-notice.js";
|
|
|
21
21
|
export declare const APPROVAL_CARD_REQUIRED_KEYS: Readonly<Record<ToolApprovalCard, readonly string[]>>;
|
|
22
22
|
export type McpToolFace = NonNullable<McpServerSpec["toolFaces"]>[string];
|
|
23
23
|
/** Why an overlay is refused — a closed reason list, each a distinct declaration mistake. */
|
|
24
|
-
export declare function toolFaceProblem(face: McpToolFace, schema: AgentTool["parameters"]
|
|
24
|
+
export declare function toolFaceProblem(face: McpToolFace, schema: AgentTool["parameters"], tool?: {
|
|
25
|
+
readonly toolName: string;
|
|
26
|
+
}): string | undefined;
|
|
25
27
|
export interface ApplyToolFacesInput {
|
|
26
28
|
/** The materialized tools of ONE server (namespaced names). */
|
|
27
29
|
tools: readonly AgentTool[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MCP_NAMESPACE } from "../protocol-table.js";
|
|
2
2
|
import { mintNamespacePrefix } from "../protocol-naming.js";
|
|
3
|
-
import { TOOL_APPROVAL_CARDS, TOOL_FAMILIES, TOOL_PATH_ABSENCES, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_LIST, TOOL_KEY_MAX_CHARS, } from "../tool-face.js";
|
|
4
|
-
import { inputKeysOf } from "../tool-roster.js";
|
|
3
|
+
import { RESERVED_APPROVAL_CARDS, TOOL_APPROVAL_CARDS, TOOL_FAMILIES, TOOL_PATH_ABSENCES, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_LIST, TOOL_KEY_MAX_CHARS, } from "../tool-face.js";
|
|
4
|
+
import { engineCardOf, inputKeysOf } from "../tool-roster.js";
|
|
5
5
|
import { deliverEngineNotice } from "../engine-notice.js";
|
|
6
6
|
export const APPROVAL_CARD_REQUIRED_KEYS = Object.freeze({
|
|
7
7
|
"file-edit": ["file_path"],
|
|
@@ -13,7 +13,7 @@ export const APPROVAL_CARD_REQUIRED_KEYS = Object.freeze({
|
|
|
13
13
|
question: [],
|
|
14
14
|
generic: [],
|
|
15
15
|
});
|
|
16
|
-
export function toolFaceProblem(face, schema) {
|
|
16
|
+
export function toolFaceProblem(face, schema, tool) {
|
|
17
17
|
const { keys, scalar } = inputKeysOf(schema);
|
|
18
18
|
const top = new Set(keys.map((k) => k.name));
|
|
19
19
|
if (face.family !== undefined && !TOOL_FAMILIES.includes(face.family))
|
|
@@ -60,6 +60,8 @@ export function toolFaceProblem(face, schema) {
|
|
|
60
60
|
if (card !== undefined) {
|
|
61
61
|
if (!TOOL_APPROVAL_CARDS.includes(card))
|
|
62
62
|
return `renderHints.approvalCard ${JSON.stringify(card)} is outside the closed set`;
|
|
63
|
+
if (RESERVED_APPROVAL_CARDS.includes(card) && (tool === undefined || engineCardOf(tool) !== card))
|
|
64
|
+
return `renderHints.approvalCard ${JSON.stringify(card)} is reserved for the engine's own tool that owns it; a declared tool takes another card or none`;
|
|
63
65
|
const missing = APPROVAL_CARD_REQUIRED_KEYS[card].filter((k) => !top.has(k));
|
|
64
66
|
if (missing.length > 0)
|
|
65
67
|
return `renderHints.approvalCard ${JSON.stringify(card)} needs ${missing.join(", ")} on the tool's schema`;
|
|
@@ -119,7 +121,7 @@ export function applyMcpToolFaces(input) {
|
|
|
119
121
|
if (raw === undefined || face === undefined)
|
|
120
122
|
return t;
|
|
121
123
|
const hit = { raw, face };
|
|
122
|
-
const problem = toolFaceProblem(hit.face, t.parameters);
|
|
124
|
+
const problem = toolFaceProblem(hit.face, t.parameters, { toolName: t.name });
|
|
123
125
|
if (problem !== undefined) {
|
|
124
126
|
const key = `invalid:${t.name}`;
|
|
125
127
|
if (!input.announced.has(key)) {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE TOOL CALL ATTEMPT, ONE RECORD — the occurrence.
|
|
3
|
+
*
|
|
4
|
+
* A tool call on one leg (one `toolCallId`, one attempt) has a single record here, and everything the engine
|
|
5
|
+
* says about the call is read off it: the `tool_start` / `tool_end` frames (projected in `tool-end-body.ts`), the
|
|
6
|
+
* `tool_progress` heartbeat (`tool-progress-lane.ts`), the trace row's `ok`, and the resumed leg's
|
|
7
|
+
* `executionOutcome` filing. The record has three parts:
|
|
8
|
+
*
|
|
9
|
+
* - the EXECUTION LIFE, monotonic: `announced` (the start frame is out) → `executing` (the engine started the
|
|
10
|
+
* tool body itself — the resumed leg; on a live leg the loop starts the body and the runner does not observe
|
|
11
|
+
* that moment, so a live call stays `announced`) → `settled` or `interrupted`. Leaving a terminal state is an
|
|
12
|
+
* engine defect and throws;
|
|
13
|
+
* - the WAIT ON A PERSON, re-entrant: every ask put to the person's seat for this call counts one entry and one
|
|
14
|
+
* exit (several rounds of one gate pass, a confirmation asked during the execution) — a count, never a bit,
|
|
15
|
+
* because the waits nest and overlap;
|
|
16
|
+
* - the GATE ROUNDS: one record per gate exit for this call, and one more when a station AFTER the gate refuses
|
|
17
|
+
* it (the shell read admission that re-establishes what the gate judged, a resumed leg's belts). The latest
|
|
18
|
+
* record is the call's disposition: a refusal after the gate is a refusal, never a tool failure under an
|
|
19
|
+
* `allowed` record.
|
|
20
|
+
*
|
|
21
|
+
* WHAT IS NOT HERE: frames, clocks of a lane, the deny observer. This module is the record and its transitions;
|
|
22
|
+
* the projections read it. A durable park that crosses legs is two occurrences on two tables (the parking leg's,
|
|
23
|
+
* the resumed leg's), joined by the checkpoint row the resumed leg was opened from — never by a field here.
|
|
24
|
+
*/
|
|
25
|
+
import type { DeniedBy, GateOutcome } from "../gate-outcome.js";
|
|
26
|
+
/** The one clock the occurrence's heartbeat facts are stamped on. MONOTONIC for the reason the progress lane
|
|
27
|
+
* states: every reading is subtracted from another, and a wall-clock step backwards would silence the beat. A
|
|
28
|
+
* host without `performance` falls back to the wall clock and inherits its rollback behaviour. */
|
|
29
|
+
export declare const occurrenceClock: () => number;
|
|
30
|
+
/** Where a call's execution life stands — see the module header for the order. */
|
|
31
|
+
export type OccurrenceLife = "announced" | "executing" | "settled" | "interrupted";
|
|
32
|
+
/** What opens an occurrence: the facts its start frame carries. */
|
|
33
|
+
export interface OccurrenceStart {
|
|
34
|
+
readonly toolCallId: string;
|
|
35
|
+
/** The name the frames carry — the model's spelling on a live leg, the parked row's spelling on a resumed one. */
|
|
36
|
+
readonly spelledName: string;
|
|
37
|
+
/** The name of the tool the call dispatches to on the live roster — the name every gate station judged (absent when
|
|
38
|
+
* the station opening the record does not know it). */
|
|
39
|
+
readonly wireName?: string;
|
|
40
|
+
/** The tool's display label, when it differs from the name. */
|
|
41
|
+
readonly label?: string;
|
|
42
|
+
/** The arguments the start frame carries (for a recovered start: the call's own input as the transcript holds it). */
|
|
43
|
+
readonly args: unknown;
|
|
44
|
+
}
|
|
45
|
+
/** The record, as its readers see it. Written only through {@link ToolOccurrenceTable}. */
|
|
46
|
+
export interface ToolOccurrence extends OccurrenceStart {
|
|
47
|
+
/** 1 for the first attempt of this id on this table, counting re-announcements of a reused id. */
|
|
48
|
+
readonly attempt: number;
|
|
49
|
+
readonly life: OccurrenceLife;
|
|
50
|
+
/** How many asks put to the person for this call are open right now. */
|
|
51
|
+
readonly awaitingUser: number;
|
|
52
|
+
/** One outcome per gate exit, plus one per refusal after the gate; the last one is the call's disposition. */
|
|
53
|
+
readonly gateRounds: readonly GateOutcome[];
|
|
54
|
+
/** The input the latest gate exit decided on, as a FROZEN snapshot (absent when no gate saw the call). */
|
|
55
|
+
readonly finalInput?: unknown;
|
|
56
|
+
/** The call's start frame is out on this leg. */
|
|
57
|
+
readonly startEmitted: boolean;
|
|
58
|
+
/** When the call was announced, on {@link occurrenceClock} — the heartbeat's elapsed origin. */
|
|
59
|
+
readonly startedAt: number;
|
|
60
|
+
/** The last moment anything was heard from the call (a frame for it, or its return from a wait on the person). */
|
|
61
|
+
readonly lastHeardAt: number;
|
|
62
|
+
/** The heartbeat covers it. Cleared when the loop leaves the call behind at a turn end with no end of its own:
|
|
63
|
+
* the record stays (a later settlement must still know its start frame went out) but no beat describes it. */
|
|
64
|
+
readonly beating: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** The table of one leg's occurrences — the record's only writer. */
|
|
67
|
+
export interface ToolOccurrenceTable {
|
|
68
|
+
/** The live (unsettled) attempt for this id, if any. */
|
|
69
|
+
get(toolCallId: string): ToolOccurrence | undefined;
|
|
70
|
+
/** Every live attempt, in the order they were opened. */
|
|
71
|
+
live(): readonly ToolOccurrence[];
|
|
72
|
+
/** Open a new attempt. A live earlier attempt for the same id is superseded: the loop left it behind without an
|
|
73
|
+
* end (a reused id can only be re-announced after its earlier call stopped producing events), and nothing can
|
|
74
|
+
* settle it any more. */
|
|
75
|
+
open(start: OccurrenceStart): ToolOccurrence;
|
|
76
|
+
/** The live attempt for this id, opened from `start` when there is none — a call the engine is told about
|
|
77
|
+
* before it was announced (a frame the loop's own start never preceded). */
|
|
78
|
+
ensure(start: OccurrenceStart): ToolOccurrence;
|
|
79
|
+
/** The call's start frame is out. */
|
|
80
|
+
noteStartEmitted(toolCallId: string): void;
|
|
81
|
+
/** The engine starts the tool body. */
|
|
82
|
+
execute(toolCallId: string): void;
|
|
83
|
+
/** A gate exit for this call: its record and the input it decided on (frozen by the gate's exit). */
|
|
84
|
+
gateRound(toolCallId: string, outcome: GateOutcome, finalInput?: unknown): void;
|
|
85
|
+
/** A station after the gate refused the call: one more gate record, minted as a veto of whatever the latest one
|
|
86
|
+
* settled (a person's yes stays on the settlement; the refusing layer is the disposition). Returns the record. */
|
|
87
|
+
refuse(toolCallId: string, layer: DeniedBy): GateOutcome;
|
|
88
|
+
/** An ask for this call is put to the person: the count rises, and the returned `resumeFromUser` lowers it once
|
|
89
|
+
* (a second call is a no-op). The pair is bound to THIS attempt — a return after the call ended, or after a
|
|
90
|
+
* reused id re-opened, touches nothing — and an ask for a call this leg does not hold counts nothing: the wait
|
|
91
|
+
* is the person's, and no bookkeeping here may turn their answer into a failure. */
|
|
92
|
+
awaitUser(toolCallId: string): () => void;
|
|
93
|
+
/** The one bracket every asker uses: the count rises before `ask` puts its question and lowers when the answer
|
|
94
|
+
* settles, either way. Returns `ask`'s own value, so the asker awaits exactly what it awaited before; a synchronous
|
|
95
|
+
* answer (or anything that is not a promise) was no wait at all. */
|
|
96
|
+
whileAwaitingUser<T>(toolCallId: string, ask: () => T): T;
|
|
97
|
+
/** A frame for the call went out: its silence clock restarts. */
|
|
98
|
+
heard(toolCallId: string): void;
|
|
99
|
+
/** The call ended: it leaves the table and the record is returned for the end projection. */
|
|
100
|
+
close(toolCallId: string, life: "settled" | "interrupted"): ToolOccurrence | undefined;
|
|
101
|
+
/** The heartbeat stops covering every live attempt (turn end, leg teardown). Records stay. */
|
|
102
|
+
quiesce(): void;
|
|
103
|
+
/** Called whenever an attempt opens (the heartbeat arms its timer). One listener — the leg's one lane. */
|
|
104
|
+
onOpen(listener: () => void): void;
|
|
105
|
+
}
|
|
106
|
+
export declare function createToolOccurrenceTable(): ToolOccurrenceTable;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { mintGateOutcome } from "./gate-exit.js";
|
|
2
|
+
export const occurrenceClock = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
3
|
+
const TERMINAL = { announced: false, executing: false, settled: true, interrupted: true };
|
|
4
|
+
export function createToolOccurrenceTable() {
|
|
5
|
+
const byId = new Map();
|
|
6
|
+
const attempts = new Map();
|
|
7
|
+
let listener;
|
|
8
|
+
const held = (toolCallId, verb) => {
|
|
9
|
+
const occ = byId.get(toolCallId);
|
|
10
|
+
if (occ === undefined)
|
|
11
|
+
throw new Error(`tool occurrence: ${verb} for call "${toolCallId}", which this leg does not hold`);
|
|
12
|
+
return occ;
|
|
13
|
+
};
|
|
14
|
+
const open = (start) => {
|
|
15
|
+
const attempt = (attempts.get(start.toolCallId) ?? 0) + 1;
|
|
16
|
+
attempts.set(start.toolCallId, attempt);
|
|
17
|
+
const now = occurrenceClock();
|
|
18
|
+
const occ = {
|
|
19
|
+
toolCallId: start.toolCallId,
|
|
20
|
+
spelledName: start.spelledName,
|
|
21
|
+
...(start.wireName !== undefined ? { wireName: start.wireName } : {}),
|
|
22
|
+
...(start.label !== undefined ? { label: start.label } : {}),
|
|
23
|
+
args: start.args,
|
|
24
|
+
attempt,
|
|
25
|
+
life: "announced",
|
|
26
|
+
awaitingUser: 0,
|
|
27
|
+
gateRounds: [],
|
|
28
|
+
startEmitted: false,
|
|
29
|
+
startedAt: now,
|
|
30
|
+
lastHeardAt: now,
|
|
31
|
+
beating: true,
|
|
32
|
+
};
|
|
33
|
+
byId.delete(start.toolCallId);
|
|
34
|
+
byId.set(start.toolCallId, occ);
|
|
35
|
+
listener?.();
|
|
36
|
+
return occ;
|
|
37
|
+
};
|
|
38
|
+
const awaitUser = (toolCallId) => {
|
|
39
|
+
const occ = byId.get(toolCallId);
|
|
40
|
+
if (occ === undefined)
|
|
41
|
+
return () => { };
|
|
42
|
+
occ.awaitingUser += 1;
|
|
43
|
+
let returned = false;
|
|
44
|
+
return () => {
|
|
45
|
+
if (returned)
|
|
46
|
+
return;
|
|
47
|
+
returned = true;
|
|
48
|
+
if (byId.get(toolCallId) !== occ)
|
|
49
|
+
return;
|
|
50
|
+
occ.awaitingUser -= 1;
|
|
51
|
+
if (occ.awaitingUser === 0)
|
|
52
|
+
occ.lastHeardAt = occurrenceClock();
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
awaitUser,
|
|
57
|
+
whileAwaitingUser(toolCallId, ask) {
|
|
58
|
+
const resumeFromUser = awaitUser(toolCallId);
|
|
59
|
+
let answer;
|
|
60
|
+
try {
|
|
61
|
+
answer = ask();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
resumeFromUser();
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
if (answer instanceof Promise)
|
|
68
|
+
answer.then(resumeFromUser, resumeFromUser);
|
|
69
|
+
else
|
|
70
|
+
resumeFromUser();
|
|
71
|
+
return answer;
|
|
72
|
+
},
|
|
73
|
+
get: (toolCallId) => byId.get(toolCallId),
|
|
74
|
+
live: () => [...byId.values()],
|
|
75
|
+
open,
|
|
76
|
+
ensure: (start) => byId.get(start.toolCallId) ?? open(start),
|
|
77
|
+
noteStartEmitted(toolCallId) {
|
|
78
|
+
held(toolCallId, "a start frame").startEmitted = true;
|
|
79
|
+
},
|
|
80
|
+
execute(toolCallId) {
|
|
81
|
+
const occ = held(toolCallId, "execute");
|
|
82
|
+
if (occ.life !== "announced")
|
|
83
|
+
throw new Error(`tool occurrence: call "${toolCallId}" (attempt ${occ.attempt}) cannot start executing from "${occ.life}"`);
|
|
84
|
+
occ.life = "executing";
|
|
85
|
+
},
|
|
86
|
+
gateRound(toolCallId, outcome, finalInput) {
|
|
87
|
+
const occ = held(toolCallId, "a gate round");
|
|
88
|
+
occ.gateRounds.push(outcome);
|
|
89
|
+
if (finalInput !== undefined)
|
|
90
|
+
occ.finalInput = finalInput;
|
|
91
|
+
},
|
|
92
|
+
refuse(toolCallId, layer) {
|
|
93
|
+
const occ = held(toolCallId, "a refusal");
|
|
94
|
+
const latest = occ.gateRounds.at(-1);
|
|
95
|
+
const round = mintGateOutcome({ deniedBy: layer, ...(latest?.settlement !== undefined && latest.origin !== undefined ? { settled: { settlement: latest.settlement, origin: latest.origin } } : {}) });
|
|
96
|
+
occ.gateRounds.push(round);
|
|
97
|
+
return round;
|
|
98
|
+
},
|
|
99
|
+
heard(toolCallId) {
|
|
100
|
+
const occ = byId.get(toolCallId);
|
|
101
|
+
if (occ !== undefined)
|
|
102
|
+
occ.lastHeardAt = occurrenceClock();
|
|
103
|
+
},
|
|
104
|
+
close(toolCallId, life) {
|
|
105
|
+
const occ = byId.get(toolCallId);
|
|
106
|
+
if (occ === undefined)
|
|
107
|
+
return undefined;
|
|
108
|
+
if (TERMINAL[occ.life])
|
|
109
|
+
throw new Error(`tool occurrence: call "${toolCallId}" (attempt ${occ.attempt}) is already ${occ.life}`);
|
|
110
|
+
occ.life = life;
|
|
111
|
+
occ.beating = false;
|
|
112
|
+
byId.delete(toolCallId);
|
|
113
|
+
return occ;
|
|
114
|
+
},
|
|
115
|
+
quiesce() {
|
|
116
|
+
for (const occ of byId.values())
|
|
117
|
+
occ.beating = false;
|
|
118
|
+
},
|
|
119
|
+
onOpen(l) {
|
|
120
|
+
listener = l;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|