@sema-agent/core 7.55.0 → 7.57.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 +1054 -0
- package/LICENSE +1 -1
- package/dist/agents/cascade.js +1 -1
- package/dist/agents/cc-peer-directory.js +1 -0
- package/dist/agents/child-model-seat.d.ts +0 -11
- package/dist/agents/child-model-seat.js +0 -3
- package/dist/agents/list-agents-tool.d.ts +3 -1
- package/dist/agents/list-agents-tool.js +7 -7
- package/dist/agents/org-delivery-gate.js +3 -4
- package/dist/agents/peer-directory.d.ts +22 -4
- package/dist/agents/peer-directory.js +24 -2
- package/dist/agents/peer-held-queue.d.ts +69 -49
- package/dist/agents/peer-held-queue.js +255 -106
- package/dist/agents/peer-session-drain.js +65 -45
- package/dist/agents/repair-loop.js +2 -2
- package/dist/agents/send-message-tool.js +7 -6
- package/dist/agents/subagent.d.ts +6 -4
- package/dist/agents/subagent.js +72 -68
- package/dist/agents/tool-filter.d.ts +7 -5
- package/dist/agents/tool-filter.js +12 -9
- package/dist/agents/verify.d.ts +3 -2
- package/dist/agents/verify.js +3 -3
- package/dist/brain/anthropic.js +45 -80
- package/dist/brain/media-degrade.d.ts +18 -7
- package/dist/brain/media-degrade.js +13 -2
- package/dist/brain/model-capability.d.ts +37 -0
- package/dist/brain/model-capability.js +34 -0
- package/dist/brain/model-presets.d.ts +2 -8
- package/dist/brain/model-presets.js +1 -6
- package/dist/brain/open-responses.js +23 -34
- package/dist/brain/openai.js +25 -96
- package/dist/brain/provider-dialect.d.ts +3 -2
- package/dist/brain/provider-dialect.js +2 -2
- package/dist/brain/reasoning-request.d.ts +96 -0
- package/dist/brain/reasoning-request.js +174 -0
- package/dist/brain/reasoning.d.ts +11 -11
- package/dist/brain/reasoning.js +4 -3
- package/dist/brain/request-params.d.ts +13 -4
- package/dist/brain/request-params.js +21 -5
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/brain/stream-engine.d.ts +9 -0
- package/dist/brain/stream-engine.js +24 -10
- package/dist/brain/stream-shared.d.ts +5 -4
- package/dist/brain/stream-shared.js +4 -4
- package/dist/core/a2a.d.ts +2 -1
- package/dist/core/a2a.js +19 -13
- package/dist/core/agent-definition.d.ts +10 -0
- package/dist/core/allow-entry.d.ts +23 -23
- package/dist/core/allow-entry.js +42 -46
- package/dist/core/allow-rule-shadow.d.ts +3 -3
- package/dist/core/approval-object.d.ts +21 -5
- package/dist/core/approval-object.js +44 -17
- package/dist/core/ask-origin.d.ts +66 -20
- package/dist/core/ask-origin.js +63 -23
- package/dist/core/ask-question.d.ts +51 -8
- package/dist/core/ask-question.js +3 -4
- package/dist/core/ask-unresolvable-notice.d.ts +8 -3
- package/dist/core/ask-unresolvable-notice.js +16 -2
- package/dist/core/auto-compaction.d.ts +71 -6
- package/dist/core/auto-compaction.js +42 -26
- package/dist/core/background-agent-store.d.ts +6 -2
- package/dist/core/background-agent-store.js +1 -1
- package/dist/core/checkpoint-generation.d.ts +53 -0
- package/dist/core/checkpoint-generation.js +35 -0
- package/dist/core/checkpoint-queries.d.ts +180 -0
- package/dist/core/checkpoint-queries.js +272 -0
- package/dist/core/checkpoint-requirements.d.ts +19 -1
- package/dist/core/checkpoint-requirements.js +6 -0
- package/dist/core/checkpoint-store.d.ts +105 -53
- package/dist/core/checkpoint-store.js +43 -20
- package/dist/core/cross-boundary-taint.d.ts +6 -5
- package/dist/core/cross-boundary-taint.js +5 -5
- package/dist/core/decision-receipt.d.ts +37 -3
- package/dist/core/decision-receipt.js +17 -17
- package/dist/core/delegation-not-started.d.ts +6 -0
- package/dist/core/delegation-not-started.js +17 -0
- package/dist/core/engine-attestation.d.ts +93 -0
- package/dist/core/engine-attestation.js +70 -0
- package/dist/core/engine-capabilities.d.ts +4 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +32 -12
- package/dist/core/engine-notice.js +6 -0
- package/dist/core/file-history-store.d.ts +104 -22
- package/dist/core/file-history-store.js +37 -19
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +22 -10
- package/dist/core/gate-lanes.js +73 -65
- package/dist/core/gate-outcome.d.ts +26 -5
- package/dist/core/gate-outcome.js +26 -0
- package/dist/core/governance-codes.d.ts +5 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +19 -18
- package/dist/core/hooks.js +3 -1
- package/dist/core/host-floor.d.ts +128 -0
- package/dist/core/host-floor.js +206 -0
- package/dist/core/host-target.d.ts +38 -3
- package/dist/core/host-target.js +38 -5
- package/dist/core/mailbox-store.d.ts +62 -1
- package/dist/core/mailbox-store.js +59 -0
- package/dist/core/mcp-name-judge.d.ts +46 -0
- package/dist/core/mcp-name-judge.js +61 -0
- package/dist/core/mcp-probe.d.ts +1 -1
- package/dist/core/mcp-probe.js +2 -5
- package/dist/core/mcp.d.ts +5 -1
- package/dist/core/mcp.js +70 -64
- package/dist/core/memory-engine/consolidation-driver.js +4 -3
- package/dist/core/memory-engine/delegation-settlement.js +15 -24
- package/dist/core/memory-engine/distiller.js +26 -17
- package/dist/core/memory-engine/engine.js +4 -4
- package/dist/core/memory-engine/layout.d.ts +60 -8
- package/dist/core/memory-engine/layout.js +70 -8
- package/dist/core/model-seat.d.ts +10 -3
- package/dist/core/mods/classic-events.d.ts +67 -0
- package/dist/core/mods/classic-events.js +1 -0
- package/dist/core/mods/dollar.d.ts +13 -0
- package/dist/core/mods/extension-call.d.ts +31 -0
- package/dist/core/mods/extension-call.js +43 -0
- package/dist/core/mods/kernel/dispatch.d.ts +20 -3
- package/dist/core/mods/kernel/dispatch.js +140 -69
- package/dist/core/mods/kernel/events.d.ts +47 -11
- package/dist/core/mods/kernel/events.js +66 -42
- package/dist/core/mods/kernel/index.d.ts +4 -4
- package/dist/core/mods/kernel/index.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +39 -5
- package/dist/core/mods/kernel/receive.js +290 -17
- package/dist/core/mods/kernel/registration.d.ts +33 -2
- package/dist/core/mods/kernel/registration.js +6 -7
- package/dist/core/mods/kernel/site-rules.d.ts +44 -16
- package/dist/core/mods/kernel/site-rules.js +24 -42
- package/dist/core/mods/spec-seats.d.ts +69 -0
- package/dist/core/mods/spec-seats.js +114 -0
- package/dist/core/mods/stations.d.ts +28 -8
- package/dist/core/mods/stations.js +29 -13
- package/dist/core/mods/tool-call.d.ts +79 -0
- package/dist/core/mods/tool-call.js +152 -0
- package/dist/core/namespaced-rule-name.d.ts +32 -38
- package/dist/core/namespaced-rule-name.js +29 -36
- package/dist/core/parent-spec-seat.d.ts +6 -1
- package/dist/core/parent-spec-seat.js +2 -0
- package/dist/core/park-selfcheck.js +3 -0
- package/dist/core/permission-rule-consent.d.ts +24 -3
- package/dist/core/permission-rule-consent.js +136 -41
- package/dist/core/permission-rule-model.d.ts +57 -5
- package/dist/core/permission-rule-model.js +90 -31
- package/dist/core/permission-rule-org.d.ts +6 -2
- package/dist/core/permission-rule-org.js +8 -4
- package/dist/core/permission-rule-provider.d.ts +5 -2
- package/dist/core/permission-rule-provider.js +41 -11
- package/dist/core/permission-rule-store.d.ts +3 -2
- package/dist/core/permission-rule-store.js +11 -2
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rule-syntax.d.ts +5 -4
- package/dist/core/permission-rule-syntax.js +2 -2
- package/dist/core/permission-rules.d.ts +4 -4
- package/dist/core/permission-rules.js +11 -20
- package/dist/core/persisted-rule-arms.d.ts +2 -2
- package/dist/core/persisted-rule-arms.js +10 -12
- package/dist/core/principal-name.d.ts +20 -0
- package/dist/core/principal-name.js +22 -0
- package/dist/core/prompt-section-seat.js +4 -6
- package/dist/core/protocol-http-auth.d.ts +40 -5
- package/dist/core/protocol-http-auth.js +168 -4
- package/dist/core/protocol-naming.d.ts +20 -0
- package/dist/core/protocol-naming.js +20 -3
- package/dist/core/read-only-shell.d.ts +20 -5
- package/dist/core/read-only-shell.js +29 -14
- package/dist/core/remote-env.d.ts +37 -1
- package/dist/core/remote-env.js +11 -0
- package/dist/core/resume-startup-cause.d.ts +24 -2
- package/dist/core/resume-startup-cause.js +20 -1
- package/dist/core/retired-keys.d.ts +16 -0
- package/dist/core/retired-keys.js +16 -4
- package/dist/core/rewrite-rejudge.d.ts +60 -0
- package/dist/core/rewrite-rejudge.js +36 -0
- package/dist/core/roles.d.ts +28 -1
- package/dist/core/roles.js +81 -26
- package/dist/core/rule-lane-reads.d.ts +20 -15
- package/dist/core/rule-lane-reads.js +45 -17
- package/dist/core/rule-owner.d.ts +3 -3
- package/dist/core/rule-owner.js +3 -2
- package/dist/core/runner/announce-once-ledger.d.ts +14 -0
- package/dist/core/runner/announce-once-ledger.js +5 -0
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/call-hook-stations.d.ts +3 -2
- package/dist/core/runner/caller-roster.d.ts +16 -4
- package/dist/core/runner/caller-roster.js +33 -6
- package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
- package/dist/core/runner/capability-withheld-seat.js +24 -0
- package/dist/core/runner/classifier-ladder.d.ts +7 -9
- package/dist/core/runner/classifier-ladder.js +3 -3
- package/dist/core/runner/compact-session.d.ts +10 -0
- package/dist/core/runner/compact-session.js +202 -0
- package/dist/core/runner/compaction-call-options.d.ts +2 -2
- package/dist/core/runner/compaction-seams.d.ts +21 -1
- package/dist/core/runner/compaction-seams.js +11 -8
- package/dist/core/runner/construction-doors.js +3 -0
- package/dist/core/runner/contracts.d.ts +50 -40
- package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
- package/dist/core/runner/cross-boundary-lane.js +40 -27
- package/dist/core/runner/denial-limit-arms.d.ts +2 -2
- package/dist/core/runner/denial-limit-arms.js +1 -1
- package/dist/core/runner/derived-route-fallback.d.ts +13 -0
- package/dist/core/runner/derived-route-fallback.js +6 -0
- package/dist/core/runner/env-capability-census.d.ts +3 -2
- package/dist/core/runner/env-capability-census.js +9 -3
- package/dist/core/runner/file-history-request.d.ts +18 -0
- package/dist/core/runner/file-history-request.js +21 -13
- package/dist/core/runner/file-history-restore.d.ts +45 -0
- package/dist/core/runner/file-history-restore.js +46 -0
- package/dist/core/runner/gate-exit.d.ts +3 -3
- package/dist/core/runner/gate-exit.js +4 -3
- package/dist/core/runner/image.d.ts +7 -17
- package/dist/core/runner/image.js +9 -60
- package/dist/core/runner/permission-rule-lanes.d.ts +11 -11
- package/dist/core/runner/permission-rule-lanes.js +39 -17
- package/dist/core/runner/person-path-rows.d.ts +12 -9
- package/dist/core/runner/person-path-rows.js +18 -7
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
- package/dist/core/runner/prepare-ask-lane.js +5 -2
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
- package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
- package/dist/core/runner/prepare-config-doors.d.ts +35 -38
- package/dist/core/runner/prepare-config-doors.js +46 -28
- package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
- package/dist/core/runner/prepare-defer-classify.js +7 -8
- package/dist/core/runner/prepare-file-history.d.ts +48 -8
- package/dist/core/runner/prepare-file-history.js +7 -39
- package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
- package/dist/core/runner/prepare-gate-stations.js +10 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +5 -9
- package/dist/core/runner/prepare-hands-readface.js +17 -14
- package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
- package/dist/core/runner/prepare-inherited-gate.js +5 -3
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +7 -7
- package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
- package/dist/core/runner/prepare-policy-chain.js +67 -76
- package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
- package/dist/core/runner/prepare-prompt-assembly.js +10 -8
- package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
- package/dist/core/runner/prepare-prompt-inputs.js +3 -5
- package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
- package/dist/core/runner/prepare-protocol-tools.js +3 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-safety-scan.js +0 -17
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
- package/dist/core/runner/prepare-suspend-saga.js +5 -6
- package/dist/core/runner/prepare-task.d.ts +5 -2
- package/dist/core/runner/prepare-task.js +48 -43
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +20 -4
- package/dist/core/runner/prepare-tool-disclosure-mount.js +33 -23
- package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
- package/dist/core/runner/prepare-turn-wiring.js +2 -7
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
- package/dist/core/runner/prepare-wiring-manifest.js +3 -3
- package/dist/core/runner/resume-admission.js +1 -1
- package/dist/core/runner/resume-apply.js +11 -12
- package/dist/core/runner/resume-checkpoint-screen.js +3 -0
- package/dist/core/runner/resume-claim.d.ts +4 -2
- package/dist/core/runner/resume-claim.js +15 -8
- package/dist/core/runner/retired-runner-deps.js +1 -0
- package/dist/core/runner/rewind-files.d.ts +12 -0
- package/dist/core/runner/rewind-files.js +90 -0
- package/dist/core/runner/run-attachment-seats.js +2 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -1
- package/dist/core/runner/run-brain-sinks.js +4 -2
- package/dist/core/runner/run-harness-handlers.js +12 -4
- package/dist/core/runner/run-leg.d.ts +1 -1
- package/dist/core/runner/run-leg.js +40 -39
- package/dist/core/runner/run-notification-lane.d.ts +2 -0
- package/dist/core/runner/run-notification-lane.js +2 -2
- package/dist/core/runner/run-recovery-lanes.js +3 -4
- package/dist/core/runner/run-settle-and-teardown.js +7 -12
- package/dist/core/runner/run-terminal-adoption.js +3 -4
- package/dist/core/runner/run-turn-boundary.js +4 -15
- package/dist/core/runner/runtask.d.ts +10 -0
- package/dist/core/runner/runtask.js +35 -42
- package/dist/core/runner/send-message-continuation.js +1 -1
- package/dist/core/runner/session-read-file-states.d.ts +15 -0
- package/dist/core/runner/session-read-file-states.js +28 -0
- package/dist/core/runner/session-rule-policy.js +4 -3
- package/dist/core/runner/session-verb-doors.d.ts +28 -0
- package/dist/core/runner/session-verb-doors.js +48 -0
- package/dist/core/runner/session-write-ledger.d.ts +30 -0
- package/dist/core/runner/session-write-ledger.js +101 -0
- package/dist/core/runner/shell-env-withheld.d.ts +33 -0
- package/dist/core/runner/shell-env-withheld.js +51 -0
- package/dist/core/runner/skills-seat.js +6 -2
- package/dist/core/runner/stream-settle-backstop.js +12 -15
- package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
- package/dist/core/runner/sub-agent-deny-lists.js +25 -17
- package/dist/core/runner/synthetic-tools.d.ts +6 -0
- package/dist/core/runner/synthetic-tools.js +4 -1
- package/dist/core/runner/teardown-bounded.d.ts +1 -0
- package/dist/core/runner/teardown-bounded.js +1 -0
- package/dist/core/runner/tool-disclosure.d.ts +10 -12
- package/dist/core/runner/tool-disclosure.js +1 -3
- package/dist/core/runner/tool-end-body.d.ts +1 -1
- package/dist/core/runner/tool-end-body.js +10 -9
- package/dist/core/runner/tool-not-executed.d.ts +5 -0
- package/dist/core/runner/tool-not-executed.js +11 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -0
- package/dist/core/runner/tool-occurrence.js +7 -0
- package/dist/core/runner/turn-attachments.d.ts +33 -15
- package/dist/core/runner/turn-attachments.js +62 -37
- package/dist/core/runner-deps.d.ts +7 -7
- package/dist/core/safety-axis-vocab.d.ts +6 -4
- package/dist/core/safety-axis-vocab.js +6 -5
- package/dist/core/safety-merge-corpus.js +11 -3
- package/dist/core/secret-env.d.ts +30 -3
- package/dist/core/secret-env.js +47 -8
- package/dist/core/select-model.js +3 -3
- package/dist/core/session-policy-store.d.ts +32 -15
- package/dist/core/session-policy-store.js +156 -36
- package/dist/core/session-store.d.ts +29 -10
- package/dist/core/session-store.js +51 -19
- package/dist/core/session.d.ts +82 -16
- package/dist/core/session.js +53 -0
- package/dist/core/shell-read-silence.d.ts +11 -12
- package/dist/core/shell-read-silence.js +9 -5
- package/dist/core/shell-run-candidates.js +3 -1
- package/dist/core/shell-wrapper-projection.d.ts +1 -1
- package/dist/core/shell-wrapper-projection.js +1 -1
- package/dist/core/shell-wrapper-table.d.ts +14 -7
- package/dist/core/shell-wrapper-table.js +5 -4
- package/dist/core/side-query.js +10 -1
- package/dist/core/skill-grant.d.ts +7 -2
- package/dist/core/skill-grant.js +5 -0
- package/dist/core/skills-directory.js +6 -2
- package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +141 -2
- package/dist/core/store-contracts/file-history-store-contract.js +40 -1
- package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
- package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
- package/dist/core/store-contracts/peer-directory-contract.js +14 -2
- package/dist/core/store-contracts/session-repo-contract.js +51 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
- package/dist/core/store-contracts/session-store-contract.js +150 -14
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +3 -3
- package/dist/core/task-event.d.ts +32 -4
- package/dist/core/task-notification.d.ts +16 -12
- package/dist/core/task-registry-agent.d.ts +8 -4
- package/dist/core/task-registry-agent.js +14 -8
- package/dist/core/task-registry-shared.d.ts +35 -6
- package/dist/core/task-registry-shared.js +11 -0
- package/dist/core/task-registry.d.ts +10 -1
- package/dist/core/task-registry.js +12 -2
- package/dist/core/task-result.d.ts +18 -0
- package/dist/core/task-spec.d.ts +18 -13
- package/dist/core/tighten-task-spec.js +2 -1
- package/dist/core/tool-catalog-entries.d.ts +23 -0
- package/dist/core/tool-catalog-entries.js +14 -2
- package/dist/core/tool-check-reading.d.ts +11 -0
- package/dist/core/tool-check-reading.js +11 -6
- package/dist/core/tool-model-gate.d.ts +2 -2
- package/dist/core/tool-name-aliases.d.ts +48 -18
- package/dist/core/tool-name-aliases.js +36 -19
- package/dist/core/tool-name-readings.d.ts +6 -32
- package/dist/core/tool-name-readings.js +2 -9
- package/dist/core/tool-policy.d.ts +78 -204
- package/dist/core/tool-policy.js +152 -204
- package/dist/core/tool-result-store.js +3 -0
- package/dist/core/tool-roster.d.ts +14 -19
- package/dist/core/tool-roster.js +11 -44
- package/dist/core/tool-spec-members.js +7 -2
- package/dist/core/tool-spec.d.ts +19 -11
- package/dist/core/tools.js +49 -9
- package/dist/core/trace.d.ts +6 -3
- package/dist/core/trace.js +2 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/untrusted-egress.d.ts +20 -0
- package/dist/core/untrusted-egress.js +77 -3
- package/dist/core/user-attachment.d.ts +8 -1
- package/dist/core/user-attachment.js +64 -4
- package/dist/core/wiring-manifest.d.ts +9 -0
- package/dist/core/wiring-manifest.js +1 -0
- package/dist/core/workflow-journal-store.js +1 -1
- package/dist/engine/compaction/compaction.js +3 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
- package/dist/engine/execution-env/node-execution-env.js +11 -2
- package/dist/engine/harness/agent-harness.d.ts +32 -6
- package/dist/engine/harness/agent-harness.js +65 -9
- package/dist/engine/harness/types.d.ts +29 -2
- package/dist/engine/llm/types.d.ts +28 -11
- package/dist/engine/loop/agent-loop.d.ts +23 -4
- package/dist/engine/loop/agent-loop.js +42 -30
- package/dist/engine/loop/types.d.ts +16 -6
- package/dist/engine/session/memory-repo.d.ts +9 -2
- package/dist/engine/session/memory-repo.js +11 -1
- package/dist/engine/session/repo-utils.d.ts +6 -5
- package/dist/engine/session/repo-utils.js +14 -6
- package/dist/index.d.ts +34 -17
- package/dist/index.js +22 -11
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/harness.d.ts +2 -1
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +6 -4
- package/dist/orchestration/run-workflow-tool.js +5 -3
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +36 -18
- package/dist/primitives/credential-ref.d.ts +89 -0
- package/dist/primitives/credential-ref.js +125 -0
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/prompt-assembly/artifact.d.ts +2 -2
- package/dist/prompt-assembly/artifact.js +5 -3
- package/dist/prompt-assembly/assemble.d.ts +3 -2
- package/dist/prompt-assembly/assemble.js +1 -1
- package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
- package/dist/prompt-assembly/catalog/schema.js +34 -2
- package/dist/prompt-assembly/catalog/sections.js +0 -1
- package/dist/prompt-assembly/composer.d.ts +3 -1
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/prompt-assembly/overlay.js +3 -3
- package/dist/prompt-assembly/renderers.d.ts +1 -1
- package/dist/prompt-assembly/renderers.js +0 -3
- package/dist/prompt-assembly/role-base.d.ts +15 -0
- package/dist/prompt-assembly/role-base.js +9 -0
- package/dist/prompt-assembly/select.d.ts +39 -14
- package/dist/prompt-assembly/select.js +47 -16
- package/dist/prompt-assembly/sugar.d.ts +17 -11
- package/dist/prompt-assembly/sugar.js +8 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
- package/dist/prompt-assembly/tool-catalog.js +114 -4
- package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
- package/dist/prompt-assembly/turn-snapshot.js +0 -3
- package/dist/prompt-assembly/types.d.ts +0 -7
- package/dist/scenarios/full-body.d.ts +11 -11
- package/dist/scenarios/full-body.js +4 -3
- package/dist/shell/lex.js +10 -1
- package/dist/stores/file/adoption/adopt.js +4 -3
- package/dist/stores/file/adoption/marker.js +3 -2
- package/dist/stores/file/checkpoint-store.d.ts +21 -4
- package/dist/stores/file/checkpoint-store.js +38 -7
- package/dist/stores/file/file-history-store.js +18 -11
- package/dist/stores/file/index.js +2 -1
- package/dist/stores/file/mailbox-store.d.ts +2 -1
- package/dist/stores/file/mailbox-store.js +26 -1
- package/dist/stores/file/permission-rule-adopt.js +4 -3
- package/dist/stores/file/permission-rule-store.js +11 -5
- package/dist/stores/file/session-store.d.ts +29 -6
- package/dist/stores/file/session-store.js +42 -50
- package/dist/tools/artifact/artifact-tool.js +3 -2
- package/dist/tools/fs/bash-program-position.d.ts +19 -2
- package/dist/tools/fs/bash-program-position.js +56 -9
- package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
- package/dist/tools/fs/bash-readonly-classifier.js +5 -10
- package/dist/tools/fs/fs-bash.js +15 -8
- package/dist/tools/fs/fs-glob.d.ts +86 -0
- package/dist/tools/fs/fs-glob.js +226 -0
- package/dist/tools/fs/fs-read.js +14 -14
- package/dist/tools/fs/fs-search-tools.js +7 -7
- package/dist/tools/fs/pattern-kill-guard.d.ts +23 -0
- package/dist/tools/fs/pattern-kill-guard.js +429 -0
- package/dist/tools/fs/pdf.d.ts +9 -6
- package/dist/tools/fs/pdf.js +3 -3
- package/dist/tools/fs/program-read-model.d.ts +57 -7
- package/dist/tools/fs/program-read-model.js +11 -1
- package/dist/tools/fs/program-read-model.rows.js +78 -21
- package/dist/tools/fs/read-deny-home.js +3 -2
- package/dist/tools/fs/removal-targets.d.ts +17 -7
- package/dist/tools/fs/removal-targets.js +47 -20
- package/dist/tools/fs/search.d.ts +10 -0
- package/dist/tools/fs/search.js +20 -26
- package/dist/tools/fs/shell-read-argv.js +89 -12
- package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
- package/dist/tools/fs/shell-read-bindings.js +41 -0
- package/dist/tools/fs/shell-read-check.d.ts +10 -0
- package/dist/tools/fs/shell-read-check.js +13 -20
- package/dist/tools/fs/shell-read-environment.d.ts +5 -1
- package/dist/tools/fs/shell-read-environment.js +3 -2
- package/dist/tools/fs/shell-read-establish.d.ts +15 -0
- package/dist/tools/fs/shell-read-establish.js +19 -20
- package/dist/tools/fs/shell-read-identity.d.ts +12 -9
- package/dist/tools/fs/shell-read-identity.js +9 -4
- package/dist/tools/fs/shell-read-plan.js +24 -16
- package/dist/tools/fs/shell-read-start.d.ts +6 -1
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
- package/dist/tools/fs/shell-read-write-targets.js +2 -3
- package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
- package/dist/tools/fs/shell-reentry-text.js +40 -2
- package/dist/tools/todo.js +63 -63
- package/dist/tools/web.d.ts +19 -14
- package/dist/tools/web.js +46 -61
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +221 -7
- package/wire-changes/core-stores-sql@7.57.0.json +29 -0
- package/wire-changes/core@7.56.0.json +3891 -0
- package/wire-changes/core@7.57.0.json +1487 -0
- package/wire-changes/mods-kernel@7.56.0.json +303 -0
- package/wire-changes/mods-kernel@7.57.0.json +29 -0
- package/wire-changes/primitives@7.57.0.json +245 -0
|
@@ -293,10 +293,39 @@ export async function fileHistoryStoreContract(make, runAssertion) {
|
|
|
293
293
|
assert.deepEqual(await store.annulTrack("sc", join(dir, "opaque2.txt"), dir), { ok: true });
|
|
294
294
|
await writeFile(join(dir, "opaque.txt"), "agent-edited");
|
|
295
295
|
const r = await store.restore("sc", "b0", env, dir);
|
|
296
|
-
assert.equal(r.refused.some((f) => f.reason.includes("base_unavailable")), true, `the kept marker must still refuse a below-base restore: ${JSON.stringify(r)}`);
|
|
296
|
+
assert.equal(r.refused.some((f) => f.reason.includes("base_unavailable") && f.class === "base_unavailable"), true, `the kept marker must still refuse a below-base restore, classed base_unavailable: ${JSON.stringify(r)}`);
|
|
297
297
|
assert.equal(await readFile(join(dir, "opaque.txt"), "utf8"), "agent-edited", "never overwritten with a fake baseline");
|
|
298
298
|
});
|
|
299
299
|
});
|
|
300
|
+
run("annulTrack's proof read that cannot re-read the path judged nothing: track_failed (aborted when the signal fired), no permanence, the record kept — never the history law's conflict", async () => {
|
|
301
|
+
await withTree(async (dir, env) => {
|
|
302
|
+
const store = make();
|
|
303
|
+
await writeFile(join(dir, "f.txt"), "pristine");
|
|
304
|
+
await writeFile(join(dir, "g.txt"), "pristine");
|
|
305
|
+
assert.deepEqual(await store.trackEdit("sc", join(dir, "f.txt"), env, dir), { ok: true, minted: true });
|
|
306
|
+
assert.deepEqual(await store.trackEdit("sc", join(dir, "g.txt"), env, dir), { ok: true, minted: true });
|
|
307
|
+
const unreadable = envWithFailingRead(env, async () => ({ ok: false, error: { code: "unknown", message: "transport gone" } }));
|
|
308
|
+
const unjudged = await store.annulTrack("sc", join(dir, "f.txt"), dir, { env: unreadable });
|
|
309
|
+
assert.equal(unjudged.ok, false, "an unread proof never retracts");
|
|
310
|
+
if (!unjudged.ok) {
|
|
311
|
+
assert.equal(unjudged.error.code, "track_failed", `a proof that could not be read is the verb's failure, not the law: ${JSON.stringify(unjudged)}`);
|
|
312
|
+
assert.equal(unjudged.error.permanence, undefined, "an env read error is not the store's own storage fault — unjudged");
|
|
313
|
+
}
|
|
314
|
+
const aborted = new AbortController();
|
|
315
|
+
aborted.abort();
|
|
316
|
+
const cut = await store.annulTrack("sc", join(dir, "g.txt"), dir, { env, signal: aborted.signal });
|
|
317
|
+
assert.equal(cut.ok, false, "a proof read cut by the signal never retracts");
|
|
318
|
+
if (!cut.ok)
|
|
319
|
+
assert.equal(cut.error.code, "aborted", `the signal fired: ${JSON.stringify(cut)}`);
|
|
320
|
+
assert.deepEqual(await store.snapshot("sc", "b1", env, dir), { ok: true });
|
|
321
|
+
await writeFile(join(dir, "f.txt"), "diverged");
|
|
322
|
+
await writeFile(join(dir, "g.txt"), "diverged");
|
|
323
|
+
const r = await store.restore("sc", "b1", env, dir);
|
|
324
|
+
assert.equal(r.outcome, "complete");
|
|
325
|
+
assert.equal(await readFile(join(dir, "f.txt"), "utf8"), "pristine", "the unjudged retraction left the record intact");
|
|
326
|
+
assert.equal(await readFile(join(dir, "g.txt"), "utf8"), "pristine", "the aborted retraction left the record intact");
|
|
327
|
+
});
|
|
328
|
+
});
|
|
300
329
|
run("annulTrack refuses what is no longer a mint: a boundary-referenced record is history (typed conflict, record intact)", async () => {
|
|
301
330
|
await withTree(async (dir, env) => {
|
|
302
331
|
const store = make();
|
|
@@ -444,9 +473,18 @@ export async function fileHistoryStoreContract(make, runAssertion) {
|
|
|
444
473
|
throw Object.assign(new Error("source blob unreadable"), { code: "EACCES" });
|
|
445
474
|
});
|
|
446
475
|
assert.equal(thrown.ok, false);
|
|
476
|
+
if (!thrown.ok)
|
|
477
|
+
assert.equal(thrown.error.code, "adopt_failed", "a source whose read throws cannot supply a referenced blob");
|
|
447
478
|
if (!thrown.ok)
|
|
448
479
|
assertPermanenceWord(thrown.error, "importHistory whose source fetch threw");
|
|
449
480
|
assert.equal(await store.canRestore("sc", "b2"), false);
|
|
481
|
+
const wrongBytes = await store.importHistory("sc", missingBlob, async () => new TextEncoder().encode("bytes that are not the content this address names"));
|
|
482
|
+
assert.equal(wrongBytes.ok, false);
|
|
483
|
+
if (!wrongBytes.ok)
|
|
484
|
+
assert.equal(wrongBytes.error.code, "adopt_failed", "a source whose bytes fail their content address cannot supply a referenced blob");
|
|
485
|
+
if (!wrongBytes.ok)
|
|
486
|
+
assertPermanenceWord(wrongBytes.error, "importHistory whose source served the wrong bytes");
|
|
487
|
+
assert.equal(await store.canRestore("sc", "b2"), false);
|
|
450
488
|
const duplicated = wireEnvelope({
|
|
451
489
|
formatVersion: "file-history/1",
|
|
452
490
|
tracked: [
|
|
@@ -700,6 +738,7 @@ export async function fileHistoryStoreContract(make, runAssertion) {
|
|
|
700
738
|
const r = await store.restore("sc", "b1", env, dir);
|
|
701
739
|
assert.equal(r.outcome, "partial", JSON.stringify(r));
|
|
702
740
|
assert.equal(r.refused.length, 2, "both kind mismatches are refused, each by name");
|
|
741
|
+
assert.deepEqual(r.refused.map((f) => f.class), ["link_safety", "link_safety"], `a kind mismatch is a link-safety refusal: ${JSON.stringify(r.refused)}`);
|
|
703
742
|
assert.equal(await readFile(join(outside, "victim.txt"), "utf8"), "OUTSIDE-UNTOUCHED", "a leaf link is never written THROUGH");
|
|
704
743
|
assert.deepEqual(r.filesChanged, []);
|
|
705
744
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { strict as assert } from "node:assert";
|
|
2
|
-
import { MAILBOX_INVALID_PEER_META_CODE, MAILBOX_TOMBSTONED_RECIPIENT_CODE } from "../mailbox-store.js";
|
|
2
|
+
import { MAILBOX_INVALID_PEER_META_CODE, MAILBOX_INVALID_DECISION_MOVE_CODE, MAILBOX_TOMBSTONED_RECIPIENT_CODE } from "../mailbox-store.js";
|
|
3
3
|
import { beginContract } from "./contract-harness.js";
|
|
4
4
|
import { PRINCIPAL_INBOX_HANDLE } from "../../agents/cross-session-ref.js";
|
|
5
5
|
import { mintCrossPrincipalRecord } from "../../agents/org-delivery-gate.js";
|
|
@@ -183,6 +183,54 @@ export async function mailboxStoreContract(mk, runAssertion) {
|
|
|
183
183
|
const again = await s.claimLease(S, "a1", "w2", 1_000, 20_000);
|
|
184
184
|
assert.deepEqual(again.messages[0].peerMeta, { fromMode: "bypass", fromSession: "sess_1" }, "重投的记录必须是原样");
|
|
185
185
|
});
|
|
186
|
+
run("#972b hold decision:CAS 一胜一负、负者拿到真值;不受租约围栏;每个租约快照都带它", async (make) => {
|
|
187
|
+
const s = make();
|
|
188
|
+
await s.append(S, "a1", msg("m1"));
|
|
189
|
+
await s.append(S, "a1", msg("m2"));
|
|
190
|
+
const held = await s.claimLease(S, "a1", "holder", 60_000, 10_000);
|
|
191
|
+
assert.equal(held.messages[0].decision, undefined, "从未 held 的记录没有 decision");
|
|
192
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, undefined, "held"), { ok: true });
|
|
193
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, undefined, "held"), { ok: false, current: "held" }, "同一步再走一次:负者拿到当前值");
|
|
194
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, "held", "denied"), { ok: true }, "不持租约的一方也能落人的决定");
|
|
195
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, "held", "approved"), { ok: false, current: "denied" }, "后到的答复输给先到的决定");
|
|
196
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 2, "held", "approved"), { ok: false, current: "unset" }, "未 held 的记录答 unset");
|
|
197
|
+
const snap = await s.claimLease(S, "a1", "holder", 60_000, 11_000);
|
|
198
|
+
assert.deepEqual(snap.messages.map((m) => [m.seq, m.decision]), [[1, "denied"], [2, undefined]], "租约快照带每条记录的 decision");
|
|
199
|
+
await s.ack(S, "a1", "holder", 1);
|
|
200
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, "denied", "denied").catch((e) => e.code), MAILBOX_INVALID_DECISION_MOVE_CODE, "终局不再移动(先于存在性判)");
|
|
201
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, "held", "approved"), { ok: false, current: "gone" }, "ack 掉的记录答 gone");
|
|
202
|
+
});
|
|
203
|
+
run("#972b decision 律:只向前走,终局不动;坏词 / 坏 seq / 非法边先于任何副作用被拒(带码)", async (make) => {
|
|
204
|
+
const s = make();
|
|
205
|
+
await s.append(S, "a1", msg("m1"));
|
|
206
|
+
const codeOf = async (p) => {
|
|
207
|
+
try {
|
|
208
|
+
await p;
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
return e.code;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
for (const [label, seq, expect, next] of [
|
|
216
|
+
["unset → approved", 1, undefined, "approved"],
|
|
217
|
+
["unset → delivered", 1, undefined, "delivered"],
|
|
218
|
+
["held → held", 1, "held", "held"],
|
|
219
|
+
["held → dropped", 1, "held", "dropped"],
|
|
220
|
+
["delivered → denied", 1, "delivered", "denied"],
|
|
221
|
+
["denied → approved", 1, "denied", "approved"],
|
|
222
|
+
["unknown word", 1, undefined, "consumed"],
|
|
223
|
+
["seq 0", 0, undefined, "held"],
|
|
224
|
+
["seq 1.5", 1.5, undefined, "held"],
|
|
225
|
+
]) {
|
|
226
|
+
assert.equal(await codeOf(s.moveDecision(S, "a1", seq, expect, next)), MAILBOX_INVALID_DECISION_MOVE_CODE, label);
|
|
227
|
+
}
|
|
228
|
+
const snap = await s.claimLease(S, "a1", "w", 60_000, 10_000);
|
|
229
|
+
assert.equal(snap.messages[0].decision, undefined, "被拒的调用零副作用");
|
|
230
|
+
for (const [from, to] of [[undefined, "held"], ["held", "approved"], ["approved", "delivered"], ["delivered", "dropped"]]) {
|
|
231
|
+
assert.deepEqual(await s.moveDecision(S, "a1", 1, from, to), { ok: true }, `${String(from)} → ${to}`);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
186
234
|
await settle();
|
|
187
235
|
}
|
|
188
236
|
export async function mailboxAckOwnershipContract(mk, runAssertion) {
|
|
@@ -9,7 +9,7 @@ export interface PeerDirectoryContractHooks {
|
|
|
9
9
|
runAssertion?: ContractAssertionRunner;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* The directory contract.
|
|
12
|
+
* The directory contract. Five readings, each the reason the engine can do something:
|
|
13
13
|
* 1. **scope wall** — a listing is the ACCESSOR's scope only; the cross-principal wall's mechanical
|
|
14
14
|
* seat is this filter, so a row leaking across scopes is a tenant leak, not a display bug;
|
|
15
15
|
* 2. **the full set, copies** — live, dead AND deleted rows are all listed (a `name [ref]` is minted
|
|
@@ -18,6 +18,11 @@ export interface PeerDirectoryContractHooks {
|
|
|
18
18
|
* 3. **resolution feeds on the listing** — the engine's own resolver, over the rows as listed, finds
|
|
19
19
|
* a live row by name, still finds a dead one, and answers `deleted` for a tombstone;
|
|
20
20
|
* 4. **restore is CAS-on-absent** (only where the host implements it) — an absent row is restored and
|
|
21
|
-
* then listed; a present row is never overwritten (`false`, the existing row byte-unchanged)
|
|
21
|
+
* then listed; a present row is never overwritten (`false`, the existing row byte-unchanged);
|
|
22
|
+
* 5. **every listed row is one the engine's reader accepts** — the engine reads a listing through
|
|
23
|
+
* `readPeerSessionRecord` and one refused row faults the WHOLE listing (dropping it would resize refs and
|
|
24
|
+
* change resolution over the full set), so a row that does not say `where`, or a non-local row carrying a
|
|
25
|
+
* machine-bound member, takes the directory's peer lane down. (How a host decides `where` is its own;
|
|
26
|
+
* the kit does not require the written value back.)
|
|
22
27
|
*/
|
|
23
28
|
export declare function peerDirectoryContract(mk: () => PeerDirectory, hooks: PeerDirectoryContractHooks): Promise<void>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { strict as assert } from "node:assert";
|
|
2
|
-
import { resolvePeerSessions } from "../../agents/peer-directory.js";
|
|
2
|
+
import { readPeerSessionRecord, resolvePeerSessions } from "../../agents/peer-directory.js";
|
|
3
3
|
import { beginContract } from "./contract-harness.js";
|
|
4
4
|
export const PEER_DIRECTORY_CONTRACT_SCOPE = "peer-kit-A";
|
|
5
5
|
function row(name, sessionId, over = {}) {
|
|
6
|
-
return { schemaVersion: 1, sessionId, scope: PEER_DIRECTORY_CONTRACT_SCOPE, name, startedAt: 1_000, updatedAt: 2_000, liveness: "live", ...over };
|
|
6
|
+
return { schemaVersion: 1, sessionId, scope: PEER_DIRECTORY_CONTRACT_SCOPE, name, startedAt: 1_000, updatedAt: 2_000, liveness: "live", where: "hosted", ...over };
|
|
7
7
|
}
|
|
8
8
|
async function withDirs(mk, fn) {
|
|
9
9
|
const live = [];
|
|
@@ -78,5 +78,17 @@ export async function peerDirectoryContract(mk, hooks) {
|
|
|
78
78
|
assert.equal(current.liveness, "live");
|
|
79
79
|
assert.equal(current.updatedAt, 9_000, "the existing row is byte-unchanged by a losing restore");
|
|
80
80
|
});
|
|
81
|
+
run("every listed row is one the engine's row reader accepts (live, dead and deleted alike)", async (make) => {
|
|
82
|
+
const d = make();
|
|
83
|
+
await hooks.write(d, row("alpha", "sess-a"));
|
|
84
|
+
await hooks.write(d, row("beta", "sess-b", { liveness: "dead", diedAt: 3_000 }));
|
|
85
|
+
await hooks.write(d, row("gamma", "sess-c", { liveness: "deleted", diedAt: 3_000 }));
|
|
86
|
+
const listed = await d.listPeerSessions({ scope: S });
|
|
87
|
+
assert.equal(listed.length, 3);
|
|
88
|
+
for (const r of listed) {
|
|
89
|
+
const read = readPeerSessionRecord(r);
|
|
90
|
+
assert.ok(read.ok, `listed row ${r.sessionId} is refused by the engine's reader (${read.ok ? "" : `${read.reason}${read.field !== undefined ? `: ${read.field}` : ""}`})`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
81
93
|
await settle();
|
|
82
94
|
}
|
|
@@ -73,6 +73,44 @@ export async function sessionRepoContract(make, runAssertion) {
|
|
|
73
73
|
assert.deepEqual(after.map((e) => e.parentId), [null, "e1"]);
|
|
74
74
|
assert.equal((await repo.exportEntries(A)).length, 2, "importing into C must not disturb the donor session");
|
|
75
75
|
});
|
|
76
|
+
run("list answers each row once, with its owner cell; a row's lastActiveAt, where the repo records it, is a finite time that a later write or touch never moves back", async () => {
|
|
77
|
+
const repo = make();
|
|
78
|
+
const B = "0198fa00-0000-7000-8000-00000000000b";
|
|
79
|
+
await (await repo.create({ id: A, owner: "kit-alice" })).getStorage().appendEntry(SESSION_ENTRY("e1", null));
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
81
|
+
await (await repo.create({ id: B })).getStorage().appendEntry(SESSION_ENTRY("e1", null));
|
|
82
|
+
let rows = await repo.list();
|
|
83
|
+
for (const id of [A, B])
|
|
84
|
+
assert.equal(rows.filter((r) => r.id === id).length, 1, `row ${id} is listed once`);
|
|
85
|
+
const rowA = rows.find((r) => r.id === A);
|
|
86
|
+
const rowB = rows.find((r) => r.id === B);
|
|
87
|
+
assert.equal(rowA.owner ?? null, "kit-alice", "a listed row carries its owner cell");
|
|
88
|
+
assert.equal(rowB.owner ?? null, null);
|
|
89
|
+
const timeOf = (id) => {
|
|
90
|
+
const row = rows.find((r) => r.id === id);
|
|
91
|
+
return row.lastActiveAt ?? Date.parse(row.createdAt);
|
|
92
|
+
};
|
|
93
|
+
if (rowA.lastActiveAt !== undefined && rowB.lastActiveAt !== undefined) {
|
|
94
|
+
assert.ok(Number.isFinite(rowA.lastActiveAt) && Number.isFinite(rowB.lastActiveAt), "a recorded activity time is a finite epoch-ms number");
|
|
95
|
+
assert.ok(rowB.lastActiveAt >= rowA.lastActiveAt, "the row written later is not listed as older");
|
|
96
|
+
const before = rowA.lastActiveAt;
|
|
97
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
98
|
+
await (await repo.open({ id: A, createdAt: "" })).getStorage().appendEntry(SESSION_ENTRY("e2", "e1"));
|
|
99
|
+
rows = await repo.list();
|
|
100
|
+
assert.ok(timeOf(A) >= before && timeOf(A) >= rowB.lastActiveAt, "a write moves its row's time forward, past the rows written before it");
|
|
101
|
+
}
|
|
102
|
+
if (repo.touch === undefined)
|
|
103
|
+
return;
|
|
104
|
+
const latest = Math.max(timeOf(A), timeOf(B));
|
|
105
|
+
const older = timeOf(A) <= timeOf(B) ? A : B;
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
107
|
+
await repo.touch(older);
|
|
108
|
+
rows = await repo.list();
|
|
109
|
+
const touched = rows.find((r) => r.id === older).lastActiveAt;
|
|
110
|
+
assert.ok(touched !== undefined && Number.isFinite(touched), "a touched row lists a recorded time");
|
|
111
|
+
assert.ok(touched >= latest, "a touch moves its row's time forward, past the rows active before it");
|
|
112
|
+
await repo.touch("0198fa00-0000-7000-8000-0000000000ff");
|
|
113
|
+
});
|
|
76
114
|
run("the owner cell round-trips: create({id, owner}) records it and open() reads it back; a create naming no owner records null", async () => {
|
|
77
115
|
const repo = make();
|
|
78
116
|
const owned = await repo.create({ id: A, owner: "kit-alice" });
|
|
@@ -82,6 +120,19 @@ export async function sessionRepoContract(make, runAssertion) {
|
|
|
82
120
|
await repo.create({ id: B });
|
|
83
121
|
assert.equal((await (await repo.open({ id: B, createdAt: "" })).getMetadata()).owner ?? null, null, "no owner named ⇒ anonymous");
|
|
84
122
|
});
|
|
123
|
+
run("a create or fork whose owner is no principal name (the empty string, a blank string, a string holding a control or invisible character) is refused and leaves no row", async () => {
|
|
124
|
+
const repo = make();
|
|
125
|
+
for (const owner of ["", " \t ", "ali\u0000ce", "\u200b"])
|
|
126
|
+
await assert.rejects(() => repo.create({ id: A, owner }), `create with owner ${JSON.stringify(owner)}`);
|
|
127
|
+
await assert.rejects(() => repo.open({ id: A, createdAt: "" }), "the refused creates stored nothing");
|
|
128
|
+
const src = await repo.create({ id: A, owner: "kit-alice" });
|
|
129
|
+
await src.getStorage().appendEntry(SESSION_ENTRY("e1", null));
|
|
130
|
+
const B = "0198fa00-0000-7000-8000-00000000000b";
|
|
131
|
+
for (const owner of ["", " \t ", "ali\u0000ce", "\u200b"])
|
|
132
|
+
await assert.rejects(() => repo.fork({ id: A, createdAt: "" }, { id: B, owner }), `fork with owner ${JSON.stringify(owner)}`);
|
|
133
|
+
await assert.rejects(() => repo.open({ id: B, createdAt: "" }), "the refused forks stored nothing");
|
|
134
|
+
assert.equal((await (await repo.open({ id: A, createdAt: "" })).getMetadata()).owner, "kit-alice", "the source row is untouched");
|
|
135
|
+
});
|
|
85
136
|
run("create({id, owner: Y}) onto an existing row owned by X reopens it untouched: the row keeps X, and the session it returns carries X", async () => {
|
|
86
137
|
const repo = make();
|
|
87
138
|
const first = await repo.create({ id: A, owner: "kit-x" });
|
|
@@ -18,7 +18,8 @@ import { type ContractAssertionRunner } from "./contract-harness.js";
|
|
|
18
18
|
* clock seam), what `release` does to an ordinary session's live set (`size` is best-effort and a durable
|
|
19
19
|
* `list` may still show the history), a durable backend's crash recovery, and a delete that fails half-way.
|
|
20
20
|
*
|
|
21
|
-
* Semantics since @sema-agent/core 7.
|
|
21
|
+
* Semantics since @sema-agent/core 7.56.0: the list reads the store's rows (a reopened store lists them), pages by the
|
|
22
|
+
* `(lastActiveAt, sessionId)` keyset, filters by the row's owner, and refuses a bad query through `readSessionListQuery`.
|
|
22
23
|
*/
|
|
23
24
|
export interface SessionStoreContractHooks {
|
|
24
25
|
/** Delete `sessionId`'s session ROW through the backend's own deletion path (history and all), so that a later
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { strict as assert } from "node:assert";
|
|
2
2
|
import { uuidv7 } from "../../internal/harness.js";
|
|
3
|
-
import { hasSessionFork, isSessionConflict } from "../session.js";
|
|
3
|
+
import { SESSION_LIST_LIMITS, hasSessionFork, isSessionConflict } from "../session.js";
|
|
4
4
|
import { readMember } from "../thrown-value.js";
|
|
5
5
|
import { receiptRefusal, receiveOwnProperties } from "../own-property-receipt.js";
|
|
6
6
|
import { beginContract } from "./contract-harness.js";
|
|
@@ -483,7 +483,7 @@ async function runSessionStoreContract(make, hooks) {
|
|
|
483
483
|
const sf = await store.fork(settled);
|
|
484
484
|
assert.deepEqual(await pathIds((await readBack(store, sf))), ["u1", "a1"], "a settled text turn forks whole");
|
|
485
485
|
});
|
|
486
|
-
faceRun("[list] list projects each
|
|
486
|
+
faceRun("[list] list projects each session row once, newest-first by lastActiveAt, and a touch counts as activity", ["list"], async (store) => {
|
|
487
487
|
const [a, b, c] = [freshId(), freshId(), freshId()];
|
|
488
488
|
await store.acquire(a);
|
|
489
489
|
await tick();
|
|
@@ -494,7 +494,7 @@ async function runSessionStoreContract(make, hooks) {
|
|
|
494
494
|
assertNewestFirst(rows);
|
|
495
495
|
for (const id of [a, b, c])
|
|
496
496
|
assert.equal(rows.filter((r) => r.sessionId === id).length, 1, `session ${id} is listed exactly once`);
|
|
497
|
-
assertActivityOrder(rows, [c, b, a], "
|
|
497
|
+
assertActivityOrder(rows, [c, b, a], "a session created later is more recent");
|
|
498
498
|
for (const r of rows)
|
|
499
499
|
assert.ok(r.createdAt === undefined || (typeof r.createdAt === "string" && r.createdAt !== ""), "createdAt is a real timestamp or absent, never an empty placeholder");
|
|
500
500
|
const before = rowOf(rows, a).lastActiveAt;
|
|
@@ -513,25 +513,148 @@ async function runSessionStoreContract(make, hooks) {
|
|
|
513
513
|
assert.equal(rowOf(rows, forkedId)?.forkedFrom, src, "the fork's row carries its lineage");
|
|
514
514
|
assert.equal(rowOf(rows, src)?.forkedFrom, undefined, "the source is no fork");
|
|
515
515
|
});
|
|
516
|
-
faceRun("[list] noteTaskRun lands on the summary
|
|
516
|
+
faceRun("[list] noteTaskRun lands on the summary; a call without a run id clears lastTaskRunId; an unknown id never throws", ["noteTaskRun"], async (store) => {
|
|
517
517
|
await store.noteTaskRun(freshId(), "kit-task", "kit-run");
|
|
518
518
|
if (typeof store.list !== "function")
|
|
519
519
|
return;
|
|
520
|
-
const
|
|
520
|
+
const a = freshId();
|
|
521
521
|
await store.acquire(a);
|
|
522
|
-
await tick();
|
|
523
|
-
await store.acquire(b);
|
|
524
|
-
await tick();
|
|
525
522
|
await store.noteTaskRun(a, "task-1", "run-1");
|
|
526
523
|
let rows = await store.list();
|
|
527
524
|
assert.equal(rowOf(rows, a)?.lastTaskId, "task-1");
|
|
528
525
|
assert.equal(rowOf(rows, a)?.lastTaskRunId, "run-1");
|
|
529
|
-
assertActivityOrder(rows, [a, b], "a run is activity: the session that just ran is the most recently active");
|
|
530
526
|
await store.noteTaskRun(a, "task-2");
|
|
531
527
|
rows = await store.list();
|
|
532
528
|
assert.equal(rowOf(rows, a)?.lastTaskId, "task-2");
|
|
533
529
|
assert.equal(rowOf(rows, a)?.lastTaskRunId, undefined, "the two seats describe one run: a newer task with no run id must not keep the older run's id");
|
|
534
530
|
});
|
|
531
|
+
faceRun("[list] the list reads the rows, not a cache: sessions are listed after their cached view is dropped and on a store reopened over the same rows (a restart), newest first", ["list"], async (store, open) => {
|
|
532
|
+
const [a, b] = [freshId(), freshId()];
|
|
533
|
+
await append((await store.acquire(a)).session, userEntry("e1", null));
|
|
534
|
+
await tick();
|
|
535
|
+
await append((await store.acquire(b)).session, userEntry("e1", null));
|
|
536
|
+
if (typeof store.forget === "function") {
|
|
537
|
+
await store.forget(a);
|
|
538
|
+
assert.ok(rowOf(await store.list({ limit: SESSION_LIST_LIMITS.max }), a) !== undefined, "a session whose cached view was dropped is still a row");
|
|
539
|
+
}
|
|
540
|
+
const second = await open(hooks.reopen(store));
|
|
541
|
+
const rows = await second.list({ limit: SESSION_LIST_LIMITS.max });
|
|
542
|
+
assertNewestFirst(rows);
|
|
543
|
+
assertActivityOrder(rows, [b, a], "a restart keeps the activity order the rows recorded");
|
|
544
|
+
});
|
|
545
|
+
faceRun("[list] a touch is recorded on the row: the touched session is still the most recent on a store reopened over the same rows (a restart)", ["list"], async (store, open) => {
|
|
546
|
+
const [a, b] = [freshId(), freshId()];
|
|
547
|
+
await append((await store.acquire(a)).session, userEntry("e1", null));
|
|
548
|
+
await tick();
|
|
549
|
+
await append((await store.acquire(b)).session, userEntry("e1", null));
|
|
550
|
+
await tick();
|
|
551
|
+
await store.touch(a);
|
|
552
|
+
const second = await open(hooks.reopen(store));
|
|
553
|
+
assertActivityOrder(await second.list({ limit: SESSION_LIST_LIMITS.max }), [a, b], "the touch outlives the process that made it");
|
|
554
|
+
});
|
|
555
|
+
faceRun("[list] a cached view of an occupant the listed row does not name lends it nothing: after another instance deleted the row and registered the id to another owner, the row lists without the old occupant's run", ["list", "noteTaskRun", "ownership", "replica"], async (store, open) => {
|
|
556
|
+
const id = freshId();
|
|
557
|
+
const other = await open(hooks.replica(store));
|
|
558
|
+
await store.register(id, "kit-alice");
|
|
559
|
+
await store.acquire(id);
|
|
560
|
+
await store.noteTaskRun(id, "alice-task", "alice-run");
|
|
561
|
+
await other.acquire(id);
|
|
562
|
+
await hooks.deleteSession(other, id);
|
|
563
|
+
await other.register(id, "kit-bob");
|
|
564
|
+
const row = rowOf(await store.list({ owner: "kit-bob", limit: SESSION_LIST_LIMITS.max }), id);
|
|
565
|
+
assert.ok(row !== undefined, "the new owner's row is listed");
|
|
566
|
+
assert.equal(row.lastTaskId, undefined, "the previous occupant's run is not lent to the new owner's row");
|
|
567
|
+
assert.equal(row.lastTaskRunId, undefined);
|
|
568
|
+
});
|
|
569
|
+
faceRun("[list] paging survives a dropped cache: a session whose cached view is dropped between two pages is not read again", ["list", "ownership", "forget"], async (store) => {
|
|
570
|
+
const owner = `kit-forget-${uuidv7().slice(-12)}`;
|
|
571
|
+
const ids = [freshId(), freshId(), freshId()];
|
|
572
|
+
for (const id of ids) {
|
|
573
|
+
await store.register(id, owner);
|
|
574
|
+
await tick();
|
|
575
|
+
}
|
|
576
|
+
for (const id of ids)
|
|
577
|
+
await store.acquire(id);
|
|
578
|
+
const first = await store.list({ owner, limit: 1 });
|
|
579
|
+
assert.equal(first.length, 1);
|
|
580
|
+
const top = first[0];
|
|
581
|
+
await store.forget(top.sessionId);
|
|
582
|
+
const rest = await store.list({ owner, after: { lastActiveAt: top.lastActiveAt, sessionId: top.sessionId } });
|
|
583
|
+
assert.ok(!rest.some((r) => r.sessionId === top.sessionId), "the first page's row is not on the next page");
|
|
584
|
+
assert.equal(rest.length, ids.length - 1, "and every other row is");
|
|
585
|
+
});
|
|
586
|
+
faceRun("[list] owner filters by the row's owner cell: an owner's rows only; with includeUnowned the unowned rows too; no owner = every owner's rows", ["list", "ownership"], async (store) => {
|
|
587
|
+
const [alice, bob] = [`kit-alice-${uuidv7().slice(-12)}`, `kit-bob-${uuidv7().slice(-12)}`];
|
|
588
|
+
const [a1, a2, b1, u1] = [freshId(), freshId(), freshId(), freshId()];
|
|
589
|
+
await store.register(a1, alice);
|
|
590
|
+
await store.register(a2, alice);
|
|
591
|
+
await store.register(b1, bob);
|
|
592
|
+
await store.acquire(u1);
|
|
593
|
+
const ids = (rows) => new Set(rows.map((r) => r.sessionId));
|
|
594
|
+
const own = ids(await store.list({ owner: alice, limit: SESSION_LIST_LIMITS.max }));
|
|
595
|
+
assert.ok(own.has(a1) && own.has(a2), "the owner's rows are listed");
|
|
596
|
+
assert.ok(!own.has(b1) && !own.has(u1), "another owner's row and an unowned row are not");
|
|
597
|
+
const withUnowned = ids(await store.list({ owner: alice, includeUnowned: true, limit: SESSION_LIST_LIMITS.max }));
|
|
598
|
+
assert.ok(withUnowned.has(a1) && withUnowned.has(a2) && withUnowned.has(u1), "includeUnowned adds the unowned rows");
|
|
599
|
+
assert.ok(!withUnowned.has(b1), "and never another owner's");
|
|
600
|
+
const all = ids(await store.list({ limit: SESSION_LIST_LIMITS.max }));
|
|
601
|
+
for (const id of [a1, a2, b1, u1])
|
|
602
|
+
assert.ok(all.has(id), `no owner filter lists every owner's rows (${id})`);
|
|
603
|
+
});
|
|
604
|
+
faceRun("[list] keyset paging reads each row once: pages cut with limit and the after cursor, concatenated, are the one-page list — ties ordered by session id, descending", ["list", "ownership"], async (store) => {
|
|
605
|
+
const owner = `kit-pager-${uuidv7().slice(-12)}`;
|
|
606
|
+
const ids = [freshId(), freshId(), freshId(), freshId(), freshId()];
|
|
607
|
+
for (const id of ids)
|
|
608
|
+
await store.register(id, owner);
|
|
609
|
+
const whole = await store.list({ owner, limit: SESSION_LIST_LIMITS.max });
|
|
610
|
+
assert.deepEqual(new Set(whole.map((r) => r.sessionId)), new Set(ids), "the owner's five rows");
|
|
611
|
+
for (let i = 1; i < whole.length; i++) {
|
|
612
|
+
const [prev, row] = [whole[i - 1], whole[i]];
|
|
613
|
+
assert.ok(prev.lastActiveAt > row.lastActiveAt || (prev.lastActiveAt === row.lastActiveAt && prev.sessionId > row.sessionId), `row ${i} follows row ${i - 1} in (lastActiveAt, sessionId) descending order`);
|
|
614
|
+
}
|
|
615
|
+
const paged = [];
|
|
616
|
+
let after;
|
|
617
|
+
for (let pages = 0; pages < 10; pages++) {
|
|
618
|
+
const page = await store.list({ owner, limit: 2, ...(after !== undefined ? { after } : {}) });
|
|
619
|
+
assert.ok(page.length <= 2, "a page holds at most limit rows");
|
|
620
|
+
if (page.length === 0)
|
|
621
|
+
break;
|
|
622
|
+
paged.push(...page.map((r) => r.sessionId));
|
|
623
|
+
const last = page[page.length - 1];
|
|
624
|
+
after = { lastActiveAt: last.lastActiveAt, sessionId: last.sessionId };
|
|
625
|
+
}
|
|
626
|
+
assert.deepEqual(paged, whole.map((r) => r.sessionId), "the pages, in order, are the one-page list: no row twice, none skipped");
|
|
627
|
+
});
|
|
628
|
+
faceRun("[list] a query without limit reads the default page; an explicit limit reads that many", ["list", "ownership"], async (store) => {
|
|
629
|
+
const owner = `kit-page-${uuidv7().slice(-12)}`;
|
|
630
|
+
const total = SESSION_LIST_LIMITS.default + 1;
|
|
631
|
+
for (let i = 0; i < total; i++)
|
|
632
|
+
await store.register(freshId(), owner);
|
|
633
|
+
assert.equal((await store.list({ owner })).length, SESSION_LIST_LIMITS.default, `no limit = the first ${SESSION_LIST_LIMITS.default} rows`);
|
|
634
|
+
assert.equal((await store.list({ owner, limit: total })).length, total);
|
|
635
|
+
assert.equal((await store.list({ owner, limit: 1 })).length, 1);
|
|
636
|
+
});
|
|
637
|
+
faceRun("[list] a bad query is refused config.invalid_argument, never read as a default: a limit out of 1..max or not an integer, a member of the wrong type, includeUnowned without owner, a malformed cursor, a member the store does not read", ["list"], async (store) => {
|
|
638
|
+
const bad = [
|
|
639
|
+
["limit 0", { limit: 0 }],
|
|
640
|
+
["a negative limit", { limit: -1 }],
|
|
641
|
+
["a fractional limit", { limit: 1.5 }],
|
|
642
|
+
["a limit past the bound", { limit: SESSION_LIST_LIMITS.max + 1 }],
|
|
643
|
+
["a limit spelled as a string", { limit: "10" }],
|
|
644
|
+
["a NaN limit", { limit: Number.NaN }],
|
|
645
|
+
["an owner that is not a string", { owner: 7 }],
|
|
646
|
+
["includeUnowned that is not a boolean", { owner: "kit-x", includeUnowned: "yes" }],
|
|
647
|
+
["includeUnowned without owner", { includeUnowned: true }],
|
|
648
|
+
["a cursor without a session id", { after: { lastActiveAt: 1 } }],
|
|
649
|
+
["a cursor whose time is not a finite number", { after: { lastActiveAt: Number.POSITIVE_INFINITY, sessionId: "x" } }],
|
|
650
|
+
["a cursor carrying another member", { after: { lastActiveAt: 1, sessionId: "x", page: 2 } }],
|
|
651
|
+
["a member the store does not read", { kitUnreadFilter: "x" }],
|
|
652
|
+
["a query that is not an object", 7],
|
|
653
|
+
];
|
|
654
|
+
for (const [what, query] of bad) {
|
|
655
|
+
await rejectsWithCode(() => Reflect.apply(store.list, store, [query]), "config.invalid_argument", `list(${what})`);
|
|
656
|
+
}
|
|
657
|
+
});
|
|
535
658
|
faceRun("[placements] a placed session stays off the host list — before and after a restart, also when read back with require-existing", ["placements"], async (store, open) => {
|
|
536
659
|
const placed = freshId();
|
|
537
660
|
const plain = freshId();
|
|
@@ -716,16 +839,29 @@ async function runSessionStoreContract(make, hooks) {
|
|
|
716
839
|
await store.register(acquired, "kit-carol");
|
|
717
840
|
assert.equal(await ownerOf(store, acquired, "a row acquire created"), null, "there is no claiming of a row that exists");
|
|
718
841
|
if (declaresPlacements(store)) {
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
842
|
+
for (const owner of [`kit-claimant-${freshId()}`, null]) {
|
|
843
|
+
const placed = freshId();
|
|
844
|
+
await store.acquire(placed, { placement: placementFor() });
|
|
845
|
+
const recorded = await ownerOf(store, placed, "a placed row");
|
|
846
|
+
await store.register(placed, owner);
|
|
847
|
+
assert.equal(await ownerOf(store, placed, "a placed row after a register"), recorded, `a register carrying ${owner === null ? "null" : "an owner"} left the placed row's owner as its placing write recorded it`);
|
|
848
|
+
}
|
|
849
|
+
const sequenced = freshId();
|
|
850
|
+
await store.acquire(sequenced, { placement: placementFor() });
|
|
851
|
+
const recordedSeq = await ownerOf(store, sequenced, "a placed row (sequence)");
|
|
852
|
+
await store.register(sequenced, null);
|
|
853
|
+
await store.register(sequenced, `kit-claimant-${freshId()}`);
|
|
854
|
+
assert.equal(await ownerOf(store, sequenced, "a placed row after two registers"), recordedSeq, "two registers in sequence (null, then a name) left the placed row's owner as its placing write recorded it");
|
|
723
855
|
}
|
|
724
856
|
});
|
|
725
|
-
faceRun("[ownership] a FIRST register whose owner is neither a
|
|
857
|
+
faceRun("[ownership] a FIRST register whose owner is neither a principal name nor null is refused loudly and leaves no row behind — a blank string, or one holding a control or invisible character, names nobody", ["ownership"], async (store) => {
|
|
726
858
|
const id = freshId();
|
|
727
859
|
await thrownBy(() => registerUntyped(store, id, undefined), "a first register with owner undefined");
|
|
728
860
|
await thrownBy(() => registerUntyped(store, id, 42), "a first register with a numeric owner");
|
|
861
|
+
await thrownBy(() => registerUntyped(store, id, ""), "a first register with the empty string as owner");
|
|
862
|
+
await thrownBy(() => registerUntyped(store, id, " \t "), "a first register with a blank string as owner");
|
|
863
|
+
await thrownBy(() => registerUntyped(store, id, "ali\u0000ce"), "a first register with a control character inside the owner");
|
|
864
|
+
await thrownBy(() => registerUntyped(store, id, "\u200b"), "a first register with an invisible character as owner");
|
|
729
865
|
assert.equal(await headOf(store, id), undefined, "the refused writes stored nothing");
|
|
730
866
|
await store.register(id, "kit-carol");
|
|
731
867
|
assert.equal(await ownerOf(store, id, "the first well-formed register"), "kit-carol", "the id is still ownable");
|
package/dist/core/stub-env.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export declare class StubExecutionEnv implements ExecutionEnv {
|
|
|
14
14
|
readonly externalContentTarget?: boolean;
|
|
15
15
|
/** `ExecutionEnv.cdPath`: the stub runs no shell, so no shell receives a `CDPATH`. */
|
|
16
16
|
readonly cdPath: readonly string[];
|
|
17
|
+
/** `ExecutionEnv.withheldEnv`: no shell child, so nothing is withheld from one. */
|
|
18
|
+
readonly withheldEnv: readonly [];
|
|
17
19
|
constructor(cwd?: string);
|
|
18
20
|
private fsErr;
|
|
19
21
|
absolutePath(path: string): Promise<Result<string, FileError>>;
|
package/dist/core/stub-env.js
CHANGED
|
@@ -134,7 +134,7 @@ function createProbeJudge(layers, kind) {
|
|
|
134
134
|
}
|
|
135
135
|
let read;
|
|
136
136
|
try {
|
|
137
|
-
read = refuseOutOfContractDecision(d);
|
|
137
|
+
read = refuseOutOfContractDecision(d, { call: req });
|
|
138
138
|
}
|
|
139
139
|
catch (err) {
|
|
140
140
|
cannot(layer, "threw", describeThrown(err));
|
|
@@ -144,7 +144,7 @@ function createProbeJudge(layers, kind) {
|
|
|
144
144
|
cannot(layer, "rewritten", "the layer would rewrite the call's arguments, so its answer is not about this call");
|
|
145
145
|
}
|
|
146
146
|
if (read.action === "ask") {
|
|
147
|
-
ask(layer, read.message, ancestorOwned || ruleClearanceOf(ownedClearanceFacts(read), {}).mandated);
|
|
147
|
+
ask(layer, read.message, ancestorOwned || ruleClearanceOf(ownedClearanceFacts(read, req), {}).mandated);
|
|
148
148
|
return undefined;
|
|
149
149
|
}
|
|
150
150
|
if (read.action !== "deny")
|
|
@@ -182,7 +182,7 @@ function createProbeJudge(layers, kind) {
|
|
|
182
182
|
}
|
|
183
183
|
if (layers.persistedRuleLane !== undefined && !spent("persisted_rules")) {
|
|
184
184
|
const read = await readPersistedRuleLane(layers.persistedRuleLane, req, layers.signal, left());
|
|
185
|
-
const tightened = applyPersistedTightening({ action: "allow" }, read).tightened;
|
|
185
|
+
const tightened = applyPersistedTightening({ action: "allow" }, read, req).tightened;
|
|
186
186
|
if (tightened === "deny")
|
|
187
187
|
return { verdict: "deny", layer: "persisted_rules", ...judged };
|
|
188
188
|
if (tightened === "ask")
|
|
@@ -269,6 +269,15 @@ export type HumanInputDelivery = "applied" | "queued" | "parked_for_wake" | "blo
|
|
|
269
269
|
* re-listing is what keeps the two faces from drifting into two vocabularies.
|
|
270
270
|
*/
|
|
271
271
|
export type DelegationTaskType = Extract<TaskNotificationPayload["task_type"], "background_agent" | "workflow">;
|
|
272
|
+
/**
|
|
273
|
+
* Who asked for a tool call no model message carried: an extension's own call (`$.tool.call`), by its registration name.
|
|
274
|
+
* A display and audit fact only — the call runs under the run's principal, rules, mode and approver, and the name decides
|
|
275
|
+
* nothing. Carried by the call's `tool_start` / `tool_end` and by the approval card an ask for it puts to the person.
|
|
276
|
+
*/
|
|
277
|
+
export interface ExtensionRequester {
|
|
278
|
+
readonly kind: "extension";
|
|
279
|
+
readonly name: string;
|
|
280
|
+
}
|
|
272
281
|
/** Streaming events surfaced from a running task (for live UIs). */
|
|
273
282
|
export type TaskEvent = ({
|
|
274
283
|
type: "text_delta";
|
|
@@ -282,9 +291,12 @@ export type TaskEvent = ({
|
|
|
282
291
|
* the provider's `content_block_stop`), and this event is that same boundary surfaced on the TaskEvent
|
|
283
292
|
* wire.
|
|
284
293
|
*
|
|
285
|
-
* `content` = the
|
|
286
|
-
* segment
|
|
287
|
-
*
|
|
294
|
+
* `content` = the FULL text of the completed segment as the brain closed it — a consumer commits
|
|
295
|
+
* the segment from it instead of trusting its own delta stitching. It is not a promise about the
|
|
296
|
+
* committed message: when the turn finalizes the brain may still trim a degenerate cut's looped tail,
|
|
297
|
+
* add engine notes as blocks of their own, or (opt-in) rewrite text it read as tool calls. The final
|
|
298
|
+
* answer's one authority is `TaskResult.result`, and `TaskResult.resultEntryIds` names the committed
|
|
299
|
+
* messages it was read from. UNTRUSTED model output for
|
|
288
300
|
* display only, same contract as `text_delta`. Emitted only for a segment that holds bytes: an
|
|
289
301
|
* empty text block closes silently (a boundary with no segment would render phantom rows).
|
|
290
302
|
*
|
|
@@ -315,6 +327,9 @@ export type TaskEvent = ({
|
|
|
315
327
|
* ran is the paired `tool_end.notExecuted`); absent on every start the loop announced itself.
|
|
316
328
|
*/
|
|
317
329
|
recovered?: true;
|
|
330
|
+
/** An extension's own call (`$.tool.call`): who asked for it. Absent on every call a model message carried. The call is
|
|
331
|
+
* not part of the conversation — no tool-result message follows it into the transcript. */
|
|
332
|
+
requestedBy?: ExtensionRequester;
|
|
318
333
|
} & TaskEventIdentity) | ({
|
|
319
334
|
/**
|
|
320
335
|
* A LIVENESS TICK for a tool call that is still running. Emitted on the run's own queue between this
|
|
@@ -564,8 +579,18 @@ export type TaskEvent = ({
|
|
|
564
579
|
* ABSENT means only that no such evidence exists — never "it ran": a call closed with its outcome unknown
|
|
565
580
|
* (a reconcile at the next process start, a call interrupted mid-execution) carries no mark, because
|
|
566
581
|
* telling a consumer it did not run could invite a replay of a write that already took effect.
|
|
582
|
+
* One more source of that evidence: an extension at `tool.call` answered for the call in place of its body (its own
|
|
583
|
+
* result, or its refusal) — the body was never called; {@link answeredBy} names it.
|
|
567
584
|
*/
|
|
568
585
|
notExecuted?: true;
|
|
586
|
+
/**
|
|
587
|
+
* The extension (its registration name) that answered for this call at `tool.call` in place of the tool's body — a
|
|
588
|
+
* result of its own, or a refusal — so the body never ran (`notExecuted` is set beside it). Absent on every call
|
|
589
|
+
* whose body ran or that no extension answered.
|
|
590
|
+
*/
|
|
591
|
+
answeredBy?: string;
|
|
592
|
+
/** The same member as the paired `tool_start`'s: an extension's own call, and who asked for it. */
|
|
593
|
+
requestedBy?: ExtensionRequester;
|
|
569
594
|
/**
|
|
570
595
|
* design/99 §E1 — `true` exactly when {@link output} is not the content the tool returned: text was cut at the cap
|
|
571
596
|
* (the string, or the block at the cut, carries the marker; the stream's later blocks left), a media block was
|
|
@@ -831,6 +856,9 @@ export type TaskEvent = ({
|
|
|
831
856
|
* on the model lane). [c209-C]: the listing family's FIRST-FRAME deliveries (initial roster /
|
|
832
857
|
* `<skills>` block riding the first user message, not a steer) emit the same echo frames.
|
|
833
858
|
*
|
|
859
|
+
* `mcp_unavailable`: the declared MCP servers that did not connect for this message — echoed where the notice rides
|
|
860
|
+
* (a fresh leg's first user message; a resumed leg's continuation). It used to ride `tools_delta`.
|
|
861
|
+
*
|
|
834
862
|
* `git_status` (env-tail migration, additive member): the git-status frame — the turn-dynamic
|
|
835
863
|
* git facts' carrier since they left the system prompt. Emitted at the frame's append RECEIPT
|
|
836
864
|
* (first-frame / resume-continuation / compaction re-assert deliveries alike). Its `preview`
|
|
@@ -843,7 +871,7 @@ export type TaskEvent = ({
|
|
|
843
871
|
* echo; the retired `plan_mode` member was the echo of the opt-in planning reminder they replaced.
|
|
844
872
|
*/
|
|
845
873
|
type: "steering_injected";
|
|
846
|
-
source: "limit_approach" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "output_style" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "total_tokens_reminder" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools" | "final_verification" | "git_status";
|
|
874
|
+
source: "limit_approach" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "output_style" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "total_tokens_reminder" | "background_tasks" | "tools_delta" | "mcp_unavailable" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools" | "final_verification" | "git_status";
|
|
847
875
|
preview: string;
|
|
848
876
|
} & TaskEventIdentity) | ({
|
|
849
877
|
/**
|