@sema-agent/core 7.52.0 → 7.54.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 +470 -0
- package/LICENSE +3 -1
- package/README.md +3 -1
- package/dist/agents/cross-session-envelope.d.ts +8 -0
- package/dist/agents/cross-session-envelope.js +6 -0
- package/dist/agents/cross-session-judge.d.ts +21 -1
- package/dist/agents/cross-session-judge.js +8 -0
- package/dist/agents/cross-session-ref.d.ts +5 -0
- package/dist/agents/cross-session-ref.js +1 -0
- package/dist/agents/org-delivery-gate.d.ts +122 -0
- package/dist/agents/org-delivery-gate.js +69 -0
- package/dist/agents/peer-held-queue.d.ts +9 -4
- package/dist/agents/peer-held-queue.js +6 -5
- package/dist/agents/peer-session-drain.d.ts +35 -6
- package/dist/agents/peer-session-drain.js +271 -182
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +6 -5
- package/dist/agents/subagent.js +117 -83
- package/dist/agents/tool-filter.d.ts +25 -4
- package/dist/agents/tool-filter.js +13 -3
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +4 -4
- package/dist/brain/model-presets.js +2 -1
- package/dist/brain/route-adjudicator.d.ts +6 -0
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +33 -14
- package/dist/core/allow-entry.d.ts +3 -1
- package/dist/core/allow-entry.js +3 -2
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +106 -50
- package/dist/core/auto-compaction.js +69 -53
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +60 -36
- package/dist/core/checkpoint-store.js +7 -6
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/compliance.js +3 -1
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +28 -6
- package/dist/core/effective-path-target.js +28 -2
- package/dist/core/engine-notice.d.ts +47 -4
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +13 -4
- package/dist/core/gate-lanes.js +41 -34
- package/dist/core/gate-outcome.d.ts +18 -9
- package/dist/core/governance-codes.d.ts +9 -2
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hands-band-screen.d.ts +7 -0
- package/dist/core/hands-band-screen.js +32 -0
- package/dist/core/hooks.d.ts +21 -19
- package/dist/core/hooks.js +6 -5
- package/dist/core/locked-config.d.ts +110 -31
- package/dist/core/locked-config.js +155 -42
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +152 -17
- package/dist/core/mcp-server-spec.js +223 -40
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +59 -54
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +9 -6
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +16 -26
- package/dist/core/mode-policy.js +5 -18
- package/dist/core/mods/kernel/dispatch.js +13 -15
- package/dist/core/mods/kernel/events.d.ts +9 -6
- package/dist/core/mods/kernel/events.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +41 -11
- package/dist/core/mods/kernel/receive.js +124 -54
- package/dist/core/mods/kernel/site-rules.d.ts +80 -15
- package/dist/core/mods/kernel/site-rules.js +232 -40
- package/dist/core/mods/stations.d.ts +0 -6
- package/dist/core/mods/stations.js +0 -7
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +71 -2
- package/dist/core/own-property-receipt.d.ts +13 -0
- package/dist/core/own-property-receipt.js +3 -1
- package/dist/core/parent-spec-seat.d.ts +12 -15
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +87 -15
- package/dist/core/permission-rule-model.js +87 -8
- package/dist/core/permission-rule-org.d.ts +200 -33
- package/dist/core/permission-rule-org.js +217 -91
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +8 -2
- package/dist/core/retired-keys.js +12 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +34 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +77 -34
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
- package/dist/core/runner/permission-rule-lanes.js +22 -10
- package/dist/core/runner/person-path-rows.d.ts +5 -3
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +58 -15
- package/dist/core/runner/prepare-config-doors.js +167 -146
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +8 -7
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +3 -2
- package/dist/core/runner/prepare-listings.d.ts +1 -1
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
- package/dist/core/runner/prepare-memory-engine-session.js +19 -6
- package/dist/core/runner/prepare-memory.d.ts +3 -2
- package/dist/core/runner/prepare-memory.js +6 -2
- package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
- package/dist/core/runner/prepare-offload-wrappers.js +2 -1
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -19
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +6 -4
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-assembly.js +20 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
- package/dist/core/runner/prepare-prompt-inputs.js +6 -3
- package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
- package/dist/core/runner/prepare-protocol-tools.js +19 -12
- package/dist/core/runner/prepare-question-face.d.ts +4 -2
- package/dist/core/runner/prepare-question-face.js +4 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +22 -19
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
- package/dist/core/runner/prepare-wiring-manifest.js +9 -6
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +16 -14
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
- package/dist/core/runner/resume-internals-and-config.js +3 -8
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +97 -43
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +21 -9
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
- package/dist/core/runner/sub-agent-deny-lists.js +7 -5
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +37 -22
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +44 -6
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +7 -7
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +67 -23
- package/dist/core/tool-policy.js +72 -60
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +23 -0
- package/dist/core/untrusted-text.js +10 -10
- package/dist/core/user-attachment.d.ts +56 -2
- package/dist/core/user-attachment.js +139 -56
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +10 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +17 -5
- package/dist/engine/loop/types.d.ts +7 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +37 -17
- package/dist/index.js +31 -14
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/artifact-store.d.ts +44 -9
- package/dist/prompt-assembly/artifact-store.js +38 -12
- package/dist/prompt-assembly/artifact.d.ts +12 -11
- package/dist/prompt-assembly/artifact.js +52 -21
- package/dist/prompt-assembly/assemble.d.ts +2 -0
- package/dist/prompt-assembly/assemble.js +2 -1
- package/dist/prompt-assembly/catalog/index.js +2 -1
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/composer.d.ts +2 -0
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/overlay.d.ts +21 -11
- package/dist/prompt-assembly/overlay.js +57 -19
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +41 -4
- package/dist/prompts/default.d.ts +1 -12
- package/dist/prompts/default.js +0 -3
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +14 -3
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5651 -5457
- package/wire-changes/core@7.53.0.json +1968 -0
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { mailboxCrossProcessMountVerdict } from "../core/mailbox-store.js";
|
|
2
2
|
import { decodeEngineFrame, ENGINE_FRAME_CODEC_VERSION, renderTaskNotificationXml, taskNotificationDedupKey } from "../core/task-notification.js";
|
|
3
3
|
import { createFrameSettlement, toolResultReceiptKey } from "../core/frame-settlement.js";
|
|
4
|
+
import { PRINCIPAL_INBOX_HANDLE } from "./cross-session-ref.js";
|
|
5
|
+
import { isGateMintedRecord, principalInboxConsumerOf } from "./org-delivery-gate.js";
|
|
4
6
|
import { deliverEngineNotice } from "../core/types.js";
|
|
5
7
|
import { buildCrossSessionEnvelope, CrossSessionCodecError, encodePeerAddress } from "./cross-session-envelope.js";
|
|
6
|
-
import { judgeCrossSessionInbound, resolveCrossSessionInboundSetting } from "./cross-session-judge.js";
|
|
8
|
+
import { judgeCrossSessionInbound, principalInboundLayers, resolveCrossSessionInboundSetting } from "./cross-session-judge.js";
|
|
7
9
|
import { judgePeerAdmission, peerAxisToken, resolvePeerLaneConfig } from "./peer-admission.js";
|
|
8
10
|
import { isPeerSessionId, PEER_SESSION_ID_GRAMMAR, peerSessionBoxHandle } from "./peer-directory.js";
|
|
9
11
|
import { inlineUntrusted } from "../core/untrusted-text.js";
|
|
@@ -16,6 +18,10 @@ import { routePeerDeliveryReceipt, routePeerDroppedReceipt, routePeerIdleNotice
|
|
|
16
18
|
import { thrownText } from "../core/thrown-value.js";
|
|
17
19
|
export const PEER_DRAIN_LEASE_TTL_MS = 5 * 60_000;
|
|
18
20
|
export const PEER_SESSION_ID_UNGRAMMATICAL_CODE = "peer.session_id_ungrammatical";
|
|
21
|
+
export const PRINCIPAL_INBOX_UNMINTED_CAUSE = "not_minted_by_delivery_gate";
|
|
22
|
+
export function terminalsDrainPrincipalInbox(deps) {
|
|
23
|
+
return principalInboxConsumerOf(deps).kind === "terminals";
|
|
24
|
+
}
|
|
19
25
|
export function judgePeerLaneMount(deps, sessionId) {
|
|
20
26
|
if (deps.peerDirectory === undefined)
|
|
21
27
|
return undefined;
|
|
@@ -52,26 +58,37 @@ export function judgeSessionBoxDrain(deps, leg) {
|
|
|
52
58
|
export const PEER_RESUPPLY_CAP = 1;
|
|
53
59
|
export function createPeerSessionDrain(opts) {
|
|
54
60
|
const { mailbox, sessionId, runId, scope } = opts;
|
|
55
|
-
const boxHandle = peerSessionBoxHandle(sessionId);
|
|
56
61
|
const storedSessionAddress = (fromSession) => fromSession !== undefined && isPeerSessionId(fromSession) ? peerSessionBoxHandle(fromSession) : undefined;
|
|
57
62
|
const drainOwner = `drain:${runId}`;
|
|
58
63
|
const recipientKey = peerAxisToken(scope, "s", sessionId);
|
|
59
64
|
const ttl = opts.leaseTtlMs ?? PEER_DRAIN_LEASE_TTL_MS;
|
|
60
65
|
const TERMINAL_DISPOSITIONS = new Set(["committed", "resupply_exhausted", "terminal"]);
|
|
61
66
|
const isTerminalDisposition = (d) => d !== undefined && TERMINAL_DISPOSITIONS.has(d.kind);
|
|
62
|
-
const
|
|
63
|
-
|
|
67
|
+
const clockOpt = opts.clock !== undefined ? { clock: opts.clock } : {};
|
|
68
|
+
const mintLane = (kind) => {
|
|
69
|
+
const boxHandle = kind === "session" ? peerSessionBoxHandle(sessionId) : PRINCIPAL_INBOX_HANDLE;
|
|
70
|
+
return {
|
|
71
|
+
kind,
|
|
72
|
+
boxHandle,
|
|
73
|
+
label: kind === "session" ? "this session's box" : "this principal's inbox",
|
|
74
|
+
ledger: new Map(),
|
|
75
|
+
ackedUpTo: undefined,
|
|
76
|
+
disclosedHeld: new Set(),
|
|
77
|
+
held: peerHeldQueueFor(scope, sessionId, kind === "session" ? clockOpt : { ...clockOpt, box: boxHandle }),
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const lanes = opts.principalInbox === true ? [mintLane("session"), mintLane("principal")] : [mintLane("session")];
|
|
81
|
+
const sessionLane = lanes[0];
|
|
82
|
+
const boxHandle = sessionLane.boxHandle;
|
|
64
83
|
const seam = opts.settlement ?? createFrameSettlement();
|
|
65
|
-
const disclosedHeld = new Set();
|
|
66
84
|
let inFlight = Promise.resolve();
|
|
67
85
|
let noticeRound = 0;
|
|
68
86
|
let currentRound;
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const disclose = (disposition, cause, m, heldNote) => deliverEngineNotice(opts.onNotice, {
|
|
87
|
+
const idleMachine = peerIdleMachineFor(scope, sessionId, clockOpt);
|
|
88
|
+
const disclose = (lane, disposition, cause, m, heldNote) => deliverEngineNotice(opts.onNotice, {
|
|
72
89
|
code: "peer.inbound_disposition",
|
|
73
|
-
message: `cross-session message seq ${m.seq} in
|
|
74
|
-
? `HELD${heldNote !== undefined ? ` (${heldNote})` : " (it entered this session's held queue and STAYS IN THE BOX \u2014 the box is that queue's durable seat, so it is not acked until it settles; it is re-judged at every boundary, released or refused with a receipt to the sender, and expires with a receipt under dialogExpiry)"}`
|
|
90
|
+
message: `cross-session message seq ${m.seq} in ${lane.label} was ${disposition === "held"
|
|
91
|
+
? `HELD${heldNote !== undefined ? ` (${heldNote})` : lane.kind === "session" ? " (it entered this session's held queue and STAYS IN THE BOX \u2014 the box is that queue's durable seat, so it is not acked until it settles; it is re-judged at every boundary, released or refused with a receipt to the sender, and expires with a receipt under dialogExpiry)" : " (it entered this session's held queue for the principal inbox and STAYS IN THE BOX until it settles; it is re-judged at every boundary. The sender is another principal: no receipt reaches it from here \u2014 the delivery gate's receipt is its record)"}`
|
|
75
92
|
: disposition === "refused"
|
|
76
93
|
? "refused by this session's crossSessionInbound setting"
|
|
77
94
|
: disposition === "resupply_exhausted"
|
|
@@ -81,20 +98,23 @@ export function createPeerSessionDrain(opts) {
|
|
|
81
98
|
: disposition === "notice_user_only"
|
|
82
99
|
? "surfaced to the user only (a notice whose sender this session's parity would hold; the model did not read it)"
|
|
83
100
|
: "refused by the inbound admission gate"}: ${cause}`,
|
|
84
|
-
detail: { disposition, cause, seq: m.seq, box: boxHandle, ...(m.peerMeta?.fromSession !== undefined ? { fromSession: m.peerMeta.fromSession } : {}), sessionId, runId },
|
|
101
|
+
detail: { disposition, cause, seq: m.seq, box: lane.boxHandle, ...(m.peerMeta?.fromSession !== undefined ? { fromSession: m.peerMeta.fromSession } : {}), sessionId, runId },
|
|
85
102
|
});
|
|
86
103
|
const readFacts = () => {
|
|
87
|
-
const
|
|
88
|
-
return { setting, selfModeClass: opts.selfModeClass() };
|
|
104
|
+
const layers = opts.settingLayers() ?? {};
|
|
105
|
+
return { setting: resolveCrossSessionInboundSetting(layers), principalSetting: resolveCrossSessionInboundSetting(principalInboundLayers(layers)), selfModeClass: opts.selfModeClass() };
|
|
89
106
|
};
|
|
90
|
-
const judgeMeta = (facts, meta) =>
|
|
107
|
+
const judgeMeta = (facts, meta) => meta?.fromScope !== undefined
|
|
108
|
+
? judgeCrossSessionInbound({ setting: facts.principalSetting, selfModeClass: facts.selfModeClass, sender: { fromScope: meta.fromScope } })
|
|
109
|
+
: judgeCrossSessionInbound({ setting: facts.setting, selfModeClass: facts.selfModeClass, sender: { ...(meta?.fromMode !== undefined ? { fromMode: meta.fromMode } : {}), selfSent: meta?.fromSession !== undefined && meta.fromSession.toLowerCase() === sessionId.toLowerCase() } });
|
|
91
110
|
const route = () => ({
|
|
92
111
|
mailbox,
|
|
93
112
|
scope,
|
|
94
113
|
self: { sessionId, ...(opts.selfName?.() !== undefined ? { name: opts.selfName() } : {}), modeClass: opts.selfModeClass },
|
|
95
114
|
...(opts.onError !== undefined ? { onError: opts.onError } : {}),
|
|
96
115
|
});
|
|
97
|
-
const buildPeerMessagePayload = (m) => {
|
|
116
|
+
const buildPeerMessagePayload = (lane, m) => {
|
|
117
|
+
const { boxHandle } = lane;
|
|
98
118
|
const meta = m.peerMeta;
|
|
99
119
|
const fields = {
|
|
100
120
|
from: encodePeerAddress(storedSessionAddress(meta?.fromSession) ?? (m.from ?? "unknown")),
|
|
@@ -126,8 +146,9 @@ export function createPeerSessionDrain(opts) {
|
|
|
126
146
|
crossSessionNotice: { kind, text },
|
|
127
147
|
_sema_provenance: { kind: "cross_session_notice", from: encodePeerAddress(storedSessionAddress(m.peerMeta?.fromSession) ?? (m.from ?? "unknown")), taskId: boxHandle, seq: m.seq, ...(m.peerMeta !== undefined ? { peerMeta: { ...m.peerMeta } } : {}) },
|
|
128
148
|
});
|
|
129
|
-
const
|
|
130
|
-
|
|
149
|
+
const receiptAddress = (lane, entry) => (lane.kind === "session" ? entry.peerMeta?.fromSession : undefined);
|
|
150
|
+
const receipt = (lane) => (entry, state) => {
|
|
151
|
+
const to = receiptAddress(lane, entry);
|
|
131
152
|
if (to === undefined)
|
|
132
153
|
return;
|
|
133
154
|
if (state === "dropped")
|
|
@@ -135,41 +156,42 @@ export function createPeerSessionDrain(opts) {
|
|
|
135
156
|
else
|
|
136
157
|
void routePeerDeliveryReceipt(route(), to, state, entry.seq);
|
|
137
158
|
};
|
|
138
|
-
const heldSink = (live) => ({
|
|
159
|
+
const heldSink = (lane, live) => ({
|
|
139
160
|
judge: (entry) => judgeMeta(readFacts(), entry.peerMeta),
|
|
140
161
|
...(live
|
|
141
162
|
? {
|
|
142
163
|
inject: (entry) => {
|
|
143
164
|
if (currentRound === undefined)
|
|
144
165
|
return "deferred";
|
|
145
|
-
const payload = buildPeerMessagePayload(entry);
|
|
166
|
+
const payload = buildPeerMessagePayload(lane, entry);
|
|
146
167
|
if (currentRound.deliver(payload, "next") === "deferred")
|
|
147
168
|
return "deferred";
|
|
148
|
-
noteDelivered(entry.seq, 1, payload, currentRound.carrier);
|
|
169
|
+
noteDelivered(lane, entry.seq, 1, payload, currentRound.carrier);
|
|
149
170
|
return undefined;
|
|
150
171
|
},
|
|
151
172
|
}
|
|
152
173
|
: {}),
|
|
153
|
-
receipt,
|
|
174
|
+
receipt: receipt(lane),
|
|
154
175
|
onHeld: (entry, count, cause, reannounce) => {
|
|
155
|
-
if (!reannounce && disclosedHeld.has(entry.seq))
|
|
176
|
+
if (!reannounce && lane.disclosedHeld.has(entry.seq))
|
|
156
177
|
return;
|
|
157
|
-
disclosedHeld.add(entry.seq);
|
|
158
|
-
disclose("held", cause, entry, reannounce ? `still held; its cause moved to ${cause} (${count} held)` : undefined);
|
|
178
|
+
lane.disclosedHeld.add(entry.seq);
|
|
179
|
+
disclose(lane, "held", cause, entry, reannounce ? `still held; its cause moved to ${cause} (${count} held)` : undefined);
|
|
159
180
|
},
|
|
160
181
|
onSettled: (entry, settlement, reason, count) => {
|
|
161
|
-
if (entry.box === boxHandle && settlement !== "delivered")
|
|
162
|
-
ledger.set(entry.seq, { kind: "terminal", why: `held_${settlement}` });
|
|
182
|
+
if (entry.box === lane.boxHandle && settlement !== "delivered")
|
|
183
|
+
lane.ledger.set(entry.seq, { kind: "terminal", why: `held_${settlement}` });
|
|
184
|
+
const replyTo = receiptAddress(lane, entry);
|
|
163
185
|
deliverEngineNotice(opts.onNotice, {
|
|
164
186
|
code: "peer.held_settled",
|
|
165
|
-
message: `held cross-session message seq ${entry.seq} left this session's held queue: ${settlement} (${reason}); ${count} still held${settlement === "expired" && reason === "evicted" ? " — the held queue was full, so the oldest entry was expired to make room" : ""}. The sender ${
|
|
166
|
-
detail: { settlement, reason, seq: entry.seq, box: boxHandle, ...(entry.peerMeta?.fromSession !== undefined ? { fromSession: entry.peerMeta.fromSession } : {}), heldCount: count, sessionId, runId },
|
|
187
|
+
message: `held cross-session message seq ${entry.seq} left this session's held queue: ${settlement} (${reason}); ${count} still held${settlement === "expired" && reason === "evicted" ? " — the held queue was full, so the oldest entry was expired to make room" : ""}. The sender ${replyTo !== undefined ? "was sent a receipt" : "has no reply address and was not told"}.`,
|
|
188
|
+
detail: { settlement, reason, seq: entry.seq, box: lane.boxHandle, ...(entry.peerMeta?.fromSession !== undefined ? { fromSession: entry.peerMeta.fromSession } : {}), heldCount: count, sessionId, runId },
|
|
167
189
|
});
|
|
168
190
|
},
|
|
169
191
|
});
|
|
170
192
|
let dialogExpiryMs = resolveCrossSessionDialogExpiry(undefined).ms;
|
|
171
193
|
let dialogExpiryAnnounced = false;
|
|
172
|
-
const bindHeld = (live) => {
|
|
194
|
+
const bindHeld = (lane, live) => {
|
|
173
195
|
try {
|
|
174
196
|
const resolved = resolveCrossSessionDialogExpiry(opts.dialogExpiry?.());
|
|
175
197
|
dialogExpiryMs = resolved.ms;
|
|
@@ -181,67 +203,84 @@ export function createPeerSessionDrain(opts) {
|
|
|
181
203
|
catch (e) {
|
|
182
204
|
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-dialog-expiry" });
|
|
183
205
|
}
|
|
184
|
-
held.configure({ sink: heldSink(live), dialogExpiryMs });
|
|
206
|
+
lane.held.configure({ sink: heldSink(lane, live), dialogExpiryMs });
|
|
185
207
|
};
|
|
186
|
-
|
|
208
|
+
for (const lane of lanes)
|
|
209
|
+
bindHeld(lane, true);
|
|
187
210
|
idleMachine.target.configure({
|
|
188
211
|
notify: (sub, notice) => void routePeerIdleNotice(route(), sub.requester, notice),
|
|
189
212
|
judge: (sub) => judgeMeta(readFacts(), { ...(sub.fromMode !== undefined ? { fromMode: sub.fromMode } : {}), ...(sub.selfSent ? { fromSession: sessionId } : {}) }),
|
|
190
|
-
heldCount: () => held.size(),
|
|
213
|
+
heldCount: () => lanes.reduce((n, lane) => n + lane.held.size(), 0),
|
|
191
214
|
...(opts.lastTurnText !== undefined ? { lastTurnText: opts.lastTurnText } : {}),
|
|
192
215
|
});
|
|
193
216
|
idleMachine.requester.configure({
|
|
194
217
|
expired: (o) => void routePeerIdleNotice(route(), sessionId, { kind: "expired", label: o.label }),
|
|
195
218
|
});
|
|
196
|
-
const adoptHeldDecisions = () => {
|
|
197
|
-
const decided = held.decisions();
|
|
219
|
+
const adoptHeldDecisions = (lane) => {
|
|
220
|
+
const decided = lane.held.decisions();
|
|
198
221
|
if (decided.size === 0)
|
|
199
222
|
return;
|
|
200
223
|
for (const [seq, settlement] of decided) {
|
|
201
|
-
if (ackedUpTo !== undefined && seq <= ackedUpTo)
|
|
224
|
+
if (lane.ackedUpTo !== undefined && seq <= lane.ackedUpTo)
|
|
202
225
|
continue;
|
|
203
|
-
const mine = ledger.get(seq);
|
|
226
|
+
const mine = lane.ledger.get(seq);
|
|
204
227
|
if (mine !== undefined && mine.kind !== "held")
|
|
205
228
|
continue;
|
|
206
|
-
ledger.set(seq, { kind: "terminal", why: `held_${settlement}` });
|
|
229
|
+
lane.ledger.set(seq, { kind: "terminal", why: `held_${settlement}` });
|
|
207
230
|
}
|
|
208
231
|
};
|
|
209
|
-
const reconcileHeld = (lease) => {
|
|
210
|
-
held.reconcile(new Set(lease.messages.map((m) => m.seq)));
|
|
232
|
+
const reconcileHeld = (lane, lease) => {
|
|
233
|
+
lane.held.reconcile(new Set(lease.messages.map((m) => m.seq)));
|
|
211
234
|
let queued;
|
|
212
|
-
for (const [seq, d] of ledger) {
|
|
235
|
+
for (const [seq, d] of lane.ledger) {
|
|
213
236
|
if (d.kind !== "held")
|
|
214
237
|
continue;
|
|
215
|
-
queued ??= new Set(held.list().filter((e) => e.box === boxHandle).map((e) => e.seq));
|
|
238
|
+
queued ??= new Set(lane.held.list().filter((e) => e.box === lane.boxHandle).map((e) => e.seq));
|
|
216
239
|
if (!queued.has(seq))
|
|
217
|
-
ledger.delete(seq);
|
|
240
|
+
lane.ledger.delete(seq);
|
|
218
241
|
}
|
|
219
242
|
};
|
|
220
243
|
const wantsCompactionEffects = () => {
|
|
221
|
-
for (const
|
|
222
|
-
|
|
223
|
-
|
|
244
|
+
for (const lane of lanes)
|
|
245
|
+
for (const d of lane.ledger.values())
|
|
246
|
+
if (d.kind === "delivered" || d.kind === "committed")
|
|
247
|
+
return true;
|
|
224
248
|
return false;
|
|
225
249
|
};
|
|
226
|
-
const noteDelivered = (seq, attempt, payload, carrier) => {
|
|
250
|
+
const noteDelivered = (lane, seq, attempt, payload, carrier) => {
|
|
227
251
|
const own = taskNotificationDedupKey(payload);
|
|
228
252
|
const key = carrier === undefined ? own : `${carrier}|${own}`;
|
|
229
|
-
ledger.set(seq, { kind: "delivered", attempt, key, payload });
|
|
253
|
+
lane.ledger.set(seq, { kind: "delivered", attempt, key, payload });
|
|
254
|
+
currentRound?.tally(lane, attempt);
|
|
255
|
+
if (carrier === undefined && payload._sema_provenance?.peerMeta?.fromScope !== undefined) {
|
|
256
|
+
try {
|
|
257
|
+
opts.markExternalContent?.(`a letter from another principal (cross-principal message seq ${seq} in ${lane.boxHandle}) was delivered into this session`);
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-external-mark" });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
230
263
|
seam.awaiting.set(key, carrier === undefined ? { carrier: own } : { carrier, frameText: renderTaskNotificationXml(payload) });
|
|
231
264
|
};
|
|
232
|
-
const deriveAckPrefix = (messages) => {
|
|
265
|
+
const deriveAckPrefix = (lane, messages) => {
|
|
233
266
|
let prefix;
|
|
234
267
|
for (const m of messages) {
|
|
235
|
-
if (ackedUpTo !== undefined && m.seq <= ackedUpTo)
|
|
268
|
+
if (lane.ackedUpTo !== undefined && m.seq <= lane.ackedUpTo)
|
|
236
269
|
continue;
|
|
237
|
-
if (!isTerminalDisposition(ledger.get(m.seq)))
|
|
270
|
+
if (!isTerminalDisposition(lane.ledger.get(m.seq)))
|
|
238
271
|
break;
|
|
239
272
|
prefix = m.seq;
|
|
240
273
|
}
|
|
241
274
|
return prefix;
|
|
242
275
|
};
|
|
243
276
|
const settleLocally = () => {
|
|
244
|
-
|
|
277
|
+
const landed = seam.compactions.splice(0);
|
|
278
|
+
for (const lane of lanes)
|
|
279
|
+
settleLaneLocally(lane, landed);
|
|
280
|
+
};
|
|
281
|
+
const settleLaneLocally = (lane, landed) => {
|
|
282
|
+
const { ledger, boxHandle } = lane;
|
|
283
|
+
adoptHeldDecisions(lane);
|
|
245
284
|
const hostWithheldSeqs = [];
|
|
246
285
|
if (seam.receipts.size > 0 || seam.withheld.size > 0 || seam.hostWithheld.size > 0) {
|
|
247
286
|
for (const [seq, d] of ledger) {
|
|
@@ -269,7 +308,7 @@ export function createPeerSessionDrain(opts) {
|
|
|
269
308
|
if (hostWithheldSeqs.length > 0) {
|
|
270
309
|
opts.onError?.(new Error(`${hostWithheldSeqs.length} cross-session message frame(s) (seq ${hostWithheldSeqs.join(", ")}) could not be found in this session's ReadInbox result as a postToolUse hook rewrote it (removed, truncated or reshaped beyond whitespace) — settled as the host's decision: they leave ${boxHandle} and are not handed over again`), { phase: "degraded", sessionId, classification: "peer-inbox-host-withheld" });
|
|
271
310
|
}
|
|
272
|
-
for (const effect of
|
|
311
|
+
for (const effect of landed) {
|
|
273
312
|
for (const [seq, d] of ledger) {
|
|
274
313
|
if (d.kind !== "committed")
|
|
275
314
|
continue;
|
|
@@ -281,23 +320,24 @@ export function createPeerSessionDrain(opts) {
|
|
|
281
320
|
for (const [seq, d] of ledger) {
|
|
282
321
|
if (d.kind === "invalidated" && d.attempt > PEER_RESUPPLY_CAP) {
|
|
283
322
|
const meta = d.payload._sema_provenance?.peerMeta;
|
|
284
|
-
disclose("resupply_exhausted", `attempt ${d.attempt} of ${PEER_RESUPPLY_CAP + 1} was summarized away too`, { seq, ...(meta !== undefined ? { peerMeta: meta } : {}) });
|
|
323
|
+
disclose(lane, "resupply_exhausted", `attempt ${d.attempt} of ${PEER_RESUPPLY_CAP + 1} was summarized away too`, { seq, ...(meta !== undefined ? { peerMeta: meta } : {}) });
|
|
285
324
|
ledger.set(seq, { kind: "resupply_exhausted" });
|
|
286
325
|
}
|
|
287
326
|
}
|
|
288
327
|
};
|
|
289
|
-
const ackSettledPrefix = async (lease) => {
|
|
328
|
+
const ackSettledPrefix = async (lane, lease) => {
|
|
329
|
+
const { held, ledger, boxHandle } = lane;
|
|
290
330
|
const decided = held.decisions();
|
|
291
331
|
if (decided.size > 0) {
|
|
292
332
|
const live = new Set(lease.messages.map((m) => m.seq));
|
|
293
333
|
held.forgetDecisions([...decided.keys()].filter((seq) => !live.has(seq)));
|
|
294
334
|
}
|
|
295
|
-
const prefix = deriveAckPrefix(lease.messages);
|
|
296
|
-
if (prefix !== undefined && (ackedUpTo === undefined || prefix > ackedUpTo)) {
|
|
335
|
+
const prefix = deriveAckPrefix(lane, lease.messages);
|
|
336
|
+
if (prefix !== undefined && (lane.ackedUpTo === undefined || prefix > lane.ackedUpTo)) {
|
|
297
337
|
try {
|
|
298
338
|
const result = await mailbox.ack(scope, boxHandle, drainOwner, prefix);
|
|
299
339
|
if (result.acked) {
|
|
300
|
-
ackedUpTo = prefix;
|
|
340
|
+
lane.ackedUpTo = prefix;
|
|
301
341
|
const gone = [];
|
|
302
342
|
for (const seq of [...ledger.keys()]) {
|
|
303
343
|
if (seq > prefix)
|
|
@@ -308,7 +348,7 @@ export function createPeerSessionDrain(opts) {
|
|
|
308
348
|
held.forgetDecisions(gone);
|
|
309
349
|
}
|
|
310
350
|
else {
|
|
311
|
-
opts.onError?.(new Error(`the session box ${boxHandle} refused this leg's ack up to seq ${prefix}: the drain lease is no longer held by ${drainOwner} (it expired and another cycle claimed it). The records stay parked and the lease holder re-serves them.`), { phase: "degraded", sessionId, classification: "peer-box-ack" });
|
|
351
|
+
opts.onError?.(new Error(`the ${lane.kind === "session" ? "session box" : "principal inbox"} ${boxHandle} refused this leg's ack up to seq ${prefix}: the drain lease is no longer held by ${drainOwner} (it expired and another cycle claimed it). The records stay parked and the lease holder re-serves them.`), { phase: "degraded", sessionId, classification: "peer-box-ack" });
|
|
312
352
|
}
|
|
313
353
|
}
|
|
314
354
|
catch (e) {
|
|
@@ -321,8 +361,8 @@ export function createPeerSessionDrain(opts) {
|
|
|
321
361
|
const kind = meta.kind;
|
|
322
362
|
const stateFits = notice !== undefined && (kind === "idle_notice" ? isPeerIdleNoticeKind(notice.state) : isPeerDeliveryReceiptState(notice.state));
|
|
323
363
|
if (!stateFits) {
|
|
324
|
-
disclose("notice_unrouted", `kind=${kind}${notice === undefined ? " without a typed notice" : ` with state=${inlineUntrusted(notice.state, 32)}`}`, m);
|
|
325
|
-
currentRound.dispose(m.seq, `notice_unrouted:${kind}`);
|
|
364
|
+
disclose(sessionLane, "notice_unrouted", `kind=${kind}${notice === undefined ? " without a typed notice" : ` with state=${inlineUntrusted(notice.state, 32)}`}`, m);
|
|
365
|
+
currentRound.dispose(sessionLane, m.seq, `notice_unrouted:${kind}`);
|
|
326
366
|
return;
|
|
327
367
|
}
|
|
328
368
|
let text;
|
|
@@ -341,22 +381,22 @@ export function createPeerSessionDrain(opts) {
|
|
|
341
381
|
}
|
|
342
382
|
const judged = judgeMeta(facts, meta);
|
|
343
383
|
if (judged.verdict === "refuse") {
|
|
344
|
-
disclose("refused", `${judged.cause} (a ${kind})`, m);
|
|
384
|
+
disclose(sessionLane, "refused", `${judged.cause} (a ${kind})`, m);
|
|
345
385
|
}
|
|
346
386
|
else if (judged.verdict === "hold") {
|
|
347
|
-
disclose("notice_user_only", `${judged.cause}: ${text}`, m);
|
|
387
|
+
disclose(sessionLane, "notice_user_only", `${judged.cause}: ${text}`, m);
|
|
348
388
|
}
|
|
349
389
|
else {
|
|
350
|
-
currentRound.batch.push({ payload: buildNoticePayload(m, kind, text), priority: "next", urgent: false, seq: m.seq, attempt: 1 });
|
|
390
|
+
currentRound.batch.push({ lane: sessionLane, payload: buildNoticePayload(m, kind, text), priority: "next", urgent: false, seq: m.seq, attempt: 1 });
|
|
351
391
|
return;
|
|
352
392
|
}
|
|
353
|
-
currentRound.dispose(m.seq, judged.verdict === "refuse" ? "refused" : "notice_user_only");
|
|
393
|
+
currentRound.dispose(sessionLane, m.seq, judged.verdict === "refuse" ? "refused" : "notice_user_only");
|
|
354
394
|
};
|
|
355
395
|
const settleSubscription = (facts, m, meta) => {
|
|
356
396
|
const requester = meta.fromSession;
|
|
357
397
|
if (requester === undefined) {
|
|
358
|
-
disclose("notice_unrouted", "kind=idle_subscription without a reply address (fromSession)", m);
|
|
359
|
-
currentRound.dispose(m.seq, "subscription_unaddressed");
|
|
398
|
+
disclose(sessionLane, "notice_unrouted", "kind=idle_subscription without a reply address (fromSession)", m);
|
|
399
|
+
currentRound.dispose(sessionLane, m.seq, "subscription_unaddressed");
|
|
360
400
|
return;
|
|
361
401
|
}
|
|
362
402
|
const sub = { requester, ...(m.from !== undefined ? { requesterName: m.from } : {}), ...(meta.fromMode !== undefined ? { fromMode: meta.fromMode } : {}), selfSent: requester.toLowerCase() === sessionId.toLowerCase(), requestedAt: m.sentAt };
|
|
@@ -368,22 +408,22 @@ export function createPeerSessionDrain(opts) {
|
|
|
368
408
|
if (facts.setting.value === "refuse") {
|
|
369
409
|
void routePeerIdleNotice(route(), requester, { kind: "unavailable" });
|
|
370
410
|
announce("refused", idleMachine.target.size());
|
|
371
|
-
currentRound.dispose(m.seq, "subscription_refused");
|
|
411
|
+
currentRound.dispose(sessionLane, m.seq, "subscription_refused");
|
|
372
412
|
return;
|
|
373
413
|
}
|
|
374
414
|
const outcome = idleMachine.target.subscribe(sub);
|
|
375
415
|
if (outcome === "full")
|
|
376
416
|
void routePeerIdleNotice(route(), requester, { kind: "unavailable" });
|
|
377
417
|
announce(outcome, idleMachine.target.size());
|
|
378
|
-
currentRound.dispose(m.seq, `subscription_${outcome}`);
|
|
418
|
+
currentRound.dispose(sessionLane, m.seq, `subscription_${outcome}`);
|
|
379
419
|
};
|
|
380
|
-
const countWaiting = (lease) => {
|
|
420
|
+
const countWaiting = (lane, lease) => {
|
|
381
421
|
if (lease === null)
|
|
382
422
|
return { pending: 0, urgent: 0 };
|
|
383
423
|
const waiting = lease.messages.filter((m) => {
|
|
384
|
-
if (ackedUpTo !== undefined && m.seq <= ackedUpTo)
|
|
424
|
+
if (lane.ackedUpTo !== undefined && m.seq <= lane.ackedUpTo)
|
|
385
425
|
return false;
|
|
386
|
-
const d = ledger.get(m.seq);
|
|
426
|
+
const d = lane.ledger.get(m.seq);
|
|
387
427
|
return d === undefined || d.kind === "invalidated";
|
|
388
428
|
});
|
|
389
429
|
return { pending: waiting.length, urgent: waiting.filter((m) => m.peerMeta?.urgent === true).length };
|
|
@@ -395,9 +435,20 @@ export function createPeerSessionDrain(opts) {
|
|
|
395
435
|
carrier;
|
|
396
436
|
charBudget;
|
|
397
437
|
injected = 0;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
438
|
+
tallies = new Map();
|
|
439
|
+
tally(lane, attempt) {
|
|
440
|
+
const t = this.tallies.get(lane) ?? { fresh: 0, resupplied: 0 };
|
|
441
|
+
if (attempt > 1)
|
|
442
|
+
t.resupplied += 1;
|
|
443
|
+
else
|
|
444
|
+
t.fresh += 1;
|
|
445
|
+
this.tallies.set(lane, t);
|
|
446
|
+
}
|
|
447
|
+
deliveredIn(lane) {
|
|
448
|
+
return this.tallies.get(lane) ?? { fresh: 0, resupplied: 0 };
|
|
449
|
+
}
|
|
450
|
+
dispose(lane, seq, why) {
|
|
451
|
+
lane.ledger.set(seq, { kind: "terminal", why });
|
|
401
452
|
}
|
|
402
453
|
batch = [];
|
|
403
454
|
chars = 0;
|
|
@@ -437,20 +488,29 @@ export function createPeerSessionDrain(opts) {
|
|
|
437
488
|
catch {
|
|
438
489
|
}
|
|
439
490
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
491
|
+
const claims = [];
|
|
492
|
+
for (const lane of lanes) {
|
|
493
|
+
try {
|
|
494
|
+
claims.push({ lane, lease: await mailbox.claimLease(scope, lane.boxHandle, drainOwner, ttl) });
|
|
495
|
+
}
|
|
496
|
+
catch (e) {
|
|
497
|
+
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-claim" });
|
|
498
|
+
}
|
|
443
499
|
}
|
|
444
|
-
|
|
445
|
-
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-claim" });
|
|
500
|
+
if (claims.length === 0)
|
|
446
501
|
return { pending: 0, urgent: 0 };
|
|
447
|
-
}
|
|
502
|
+
const waitingAcross = () => claims.reduce((sum, { lane, lease }) => {
|
|
503
|
+
const c = countWaiting(lane, lease);
|
|
504
|
+
return { pending: sum.pending + c.pending, urgent: sum.urgent + c.urgent };
|
|
505
|
+
}, { pending: 0, urgent: 0 });
|
|
448
506
|
if (pass.settle)
|
|
449
507
|
settleLocally();
|
|
450
|
-
if (pass.settle
|
|
451
|
-
|
|
508
|
+
if (pass.settle)
|
|
509
|
+
for (const { lane, lease } of claims)
|
|
510
|
+
if (lease !== null)
|
|
511
|
+
await ackSettledPrefix(lane, lease);
|
|
452
512
|
if (!pass.deliver)
|
|
453
|
-
return
|
|
513
|
+
return waitingAcross();
|
|
454
514
|
let facts;
|
|
455
515
|
let admissionConfig;
|
|
456
516
|
try {
|
|
@@ -464,92 +524,104 @@ export function createPeerSessionDrain(opts) {
|
|
|
464
524
|
currentRound = round;
|
|
465
525
|
try {
|
|
466
526
|
idleMachine.target.sweep();
|
|
467
|
-
|
|
527
|
+
const leased = claims.filter((c) => c.lease !== null);
|
|
528
|
+
if (leased.length === 0)
|
|
468
529
|
return { pending: 0, urgent: 0 };
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
530
|
+
for (const { lane, lease } of leased) {
|
|
531
|
+
bindHeld(lane, true);
|
|
532
|
+
reconcileHeld(lane, lease);
|
|
533
|
+
lane.held.rejudge();
|
|
534
|
+
}
|
|
472
535
|
try {
|
|
473
|
-
for (const
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
const attempt = prior.attempt + 1;
|
|
480
|
-
round.batch.push({ payload: { ...prior.payload, attempt, resupplied: true }, priority: "next", urgent: false, seq: m.seq, attempt });
|
|
481
|
-
}
|
|
482
|
-
adoptHeldDecisions();
|
|
483
|
-
for (const m of lease.messages) {
|
|
484
|
-
if (ackedUpTo !== undefined && m.seq <= ackedUpTo)
|
|
485
|
-
continue;
|
|
486
|
-
if (ledger.has(m.seq))
|
|
487
|
-
continue;
|
|
488
|
-
if (round.spent)
|
|
489
|
-
break;
|
|
490
|
-
const meta = m.peerMeta;
|
|
491
|
-
if (m.hopChain !== undefined) {
|
|
492
|
-
const verdict = judgePeerAdmission(scope, recipientKey, { senderKey: meta?.senderKey, body: m.content, prospectiveChain: m.hopChain, ownTokens: opts.ownTokens(), seq: m.seq }, admissionConfig, undefined, "drain");
|
|
493
|
-
if (!verdict.ok) {
|
|
494
|
-
if (verdict.reason === "rate_limited") {
|
|
495
|
-
if (!disclosedHeld.has(m.seq)) {
|
|
496
|
-
disclosedHeld.add(m.seq);
|
|
497
|
-
disclose("held", verdict.reason, m, "it stays in the box; the inbound admission bucket is empty and it is re-judged at a later boundary once the bucket refills");
|
|
498
|
-
}
|
|
499
|
-
break;
|
|
500
|
-
}
|
|
501
|
-
disclose("admission_refused", verdict.reason, m);
|
|
502
|
-
round.dispose(m.seq, `admission_refused:${verdict.reason}`);
|
|
536
|
+
for (const { lane, lease } of leased) {
|
|
537
|
+
const { ledger, disclosedHeld, held, boxHandle } = lane;
|
|
538
|
+
const ackedUpTo = lane.ackedUpTo;
|
|
539
|
+
for (const m of lease.messages) {
|
|
540
|
+
const prior = ledger.get(m.seq);
|
|
541
|
+
if (prior === undefined || prior.kind !== "invalidated")
|
|
503
542
|
continue;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
if (meta?.kind === "idle_notice" || meta?.kind === "delivery_notice") {
|
|
511
|
-
settleNoticeRecord(facts, m, meta);
|
|
512
|
-
continue;
|
|
543
|
+
if (round.spent)
|
|
544
|
+
break;
|
|
545
|
+
const attempt = prior.attempt + 1;
|
|
546
|
+
round.batch.push({ lane, payload: { ...prior.payload, attempt, resupplied: true }, priority: "next", urgent: false, seq: m.seq, attempt });
|
|
513
547
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (
|
|
517
|
-
|
|
548
|
+
adoptHeldDecisions(lane);
|
|
549
|
+
for (const m of lease.messages) {
|
|
550
|
+
if (ackedUpTo !== undefined && m.seq <= ackedUpTo)
|
|
551
|
+
continue;
|
|
552
|
+
if (ledger.has(m.seq))
|
|
553
|
+
continue;
|
|
554
|
+
if (round.spent)
|
|
518
555
|
break;
|
|
556
|
+
const meta = m.peerMeta;
|
|
557
|
+
if (lane.kind === "principal" && !isGateMintedRecord(meta)) {
|
|
558
|
+
disclose(lane, "admission_refused", PRINCIPAL_INBOX_UNMINTED_CAUSE, m);
|
|
559
|
+
round.dispose(lane, m.seq, `admission_refused:${PRINCIPAL_INBOX_UNMINTED_CAUSE}`);
|
|
560
|
+
continue;
|
|
519
561
|
}
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
|
|
562
|
+
if (m.hopChain !== undefined) {
|
|
563
|
+
const verdict = judgePeerAdmission(scope, recipientKey, { senderKey: meta?.senderKey, body: m.content, prospectiveChain: m.hopChain, ownTokens: opts.ownTokens(), seq: m.seq }, admissionConfig, undefined, "drain");
|
|
564
|
+
if (!verdict.ok) {
|
|
565
|
+
if (verdict.reason === "rate_limited") {
|
|
566
|
+
if (!disclosedHeld.has(m.seq)) {
|
|
567
|
+
disclosedHeld.add(m.seq);
|
|
568
|
+
disclose(lane, "held", verdict.reason, m, "it stays in the box; the inbound admission bucket is empty and it is re-judged at a later boundary once the bucket refills");
|
|
569
|
+
}
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
disclose(lane, "admission_refused", verdict.reason, m);
|
|
573
|
+
round.dispose(lane, m.seq, `admission_refused:${verdict.reason}`);
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (meta?.kind === "idle_subscription") {
|
|
578
|
+
settleSubscription(facts, m, meta);
|
|
523
579
|
continue;
|
|
524
580
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
const sameTree = meta?.fromRoot !== undefined && meta.fromRoot.toLowerCase() === sessionId.toLowerCase();
|
|
529
|
-
if (!sameTree) {
|
|
530
|
-
const judged = judgeMeta(facts, meta);
|
|
531
|
-
if (judged.verdict === "refuse") {
|
|
532
|
-
disclose("refused", judged.cause, m);
|
|
533
|
-
round.dispose(m.seq, `refused:${judged.cause}`);
|
|
581
|
+
if (meta?.kind === "idle_notice" || meta?.kind === "delivery_notice") {
|
|
582
|
+
settleNoticeRecord(facts, m, meta);
|
|
534
583
|
continue;
|
|
535
584
|
}
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
if (!
|
|
539
|
-
|
|
585
|
+
if (meta?.kind === "engine_frame") {
|
|
586
|
+
const decoded = decodeEngineFrame(m.content);
|
|
587
|
+
if (!decoded.ok && decoded.reason === "newer") {
|
|
588
|
+
opts.onError?.(new Error(`engine_frame record seq ${m.seq} in ${boxHandle} carries codec version ${decoded.codecVersion}; this engine reads up to ${ENGINE_FRAME_CODEC_VERSION} — the box stops at that record until an engine that reads it drains the session`), { phase: "degraded", sessionId, classification: "peer-box-engine-frame" });
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
if (!decoded.ok) {
|
|
592
|
+
disclose(lane, "notice_unrouted", `kind=engine_frame (${decoded.detail})`, m);
|
|
593
|
+
round.dispose(lane, m.seq, `engine_frame_malformed:${decoded.detail}`);
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
round.batch.push({ lane, payload: decoded.payload, priority: decoded.priority, urgent: false, seq: m.seq, attempt: 1 });
|
|
540
597
|
continue;
|
|
541
598
|
}
|
|
599
|
+
const sameTree = meta?.fromRoot !== undefined && meta.fromRoot.toLowerCase() === sessionId.toLowerCase();
|
|
600
|
+
if (!sameTree) {
|
|
601
|
+
const judged = judgeMeta(facts, meta);
|
|
602
|
+
if (judged.verdict === "refuse") {
|
|
603
|
+
disclose(lane, "refused", judged.cause, m);
|
|
604
|
+
round.dispose(lane, m.seq, `refused:${judged.cause}`);
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
if (judged.verdict === "hold") {
|
|
608
|
+
held.hold({ seq: m.seq, box: boxHandle, content: m.content, ...(m.from !== undefined ? { from: m.from } : {}), sentAt: m.sentAt, ...(m.hopChain !== undefined ? { hopChain: [...m.hopChain] } : {}), ...(meta !== undefined ? { peerMeta: { ...meta } } : {}), cause: judged.cause });
|
|
609
|
+
if (!ledger.has(m.seq))
|
|
610
|
+
ledger.set(m.seq, { kind: "held" });
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
let payload;
|
|
615
|
+
try {
|
|
616
|
+
payload = buildPeerMessagePayload(lane, m);
|
|
617
|
+
}
|
|
618
|
+
catch (e) {
|
|
619
|
+
disclose(lane, "refused", `record fields cannot be rendered canonically (${e instanceof CrossSessionCodecError ? e.code : thrownText(e)})`, m);
|
|
620
|
+
round.dispose(lane, m.seq, "uncanonical_fields");
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
round.batch.push({ lane, payload, priority: "next", urgent: meta?.urgent === true, seq: m.seq, attempt: 1 });
|
|
542
624
|
}
|
|
543
|
-
let payload;
|
|
544
|
-
try {
|
|
545
|
-
payload = buildPeerMessagePayload(m);
|
|
546
|
-
}
|
|
547
|
-
catch (e) {
|
|
548
|
-
disclose("refused", `record fields cannot be rendered canonically (${e instanceof CrossSessionCodecError ? e.code : thrownText(e)})`, m);
|
|
549
|
-
round.dispose(m.seq, "uncanonical_fields");
|
|
550
|
-
continue;
|
|
551
|
-
}
|
|
552
|
-
round.batch.push({ payload, priority: "next", urgent: meta?.urgent === true, seq: m.seq, attempt: 1 });
|
|
553
625
|
}
|
|
554
626
|
}
|
|
555
627
|
finally {
|
|
@@ -563,13 +635,15 @@ export function createPeerSessionDrain(opts) {
|
|
|
563
635
|
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-inject" });
|
|
564
636
|
break;
|
|
565
637
|
}
|
|
566
|
-
noteDelivered(item.seq, item.attempt, item.payload, round.carrier);
|
|
567
|
-
if (item.attempt > 1)
|
|
568
|
-
round.resupplied += 1;
|
|
638
|
+
noteDelivered(item.lane, item.seq, item.attempt, item.payload, round.carrier);
|
|
569
639
|
}
|
|
570
640
|
}
|
|
571
|
-
const
|
|
572
|
-
|
|
641
|
+
for (const { lane, lease } of leased) {
|
|
642
|
+
const counts = countWaiting(lane, lease);
|
|
643
|
+
if (counts.pending === 0 || round.out !== undefined)
|
|
644
|
+
continue;
|
|
645
|
+
const { boxHandle } = lane;
|
|
646
|
+
const delivered = round.deliveredIn(lane);
|
|
573
647
|
noticeRound += 1;
|
|
574
648
|
try {
|
|
575
649
|
opts.inject({
|
|
@@ -578,7 +652,7 @@ export function createPeerSessionDrain(opts) {
|
|
|
578
652
|
status: "event",
|
|
579
653
|
seq: noticeRound,
|
|
580
654
|
summary: `inbox notice: ${counts.pending} cross-session message(s) waiting`,
|
|
581
|
-
inboxNotice: { pending: counts.pending, delivered:
|
|
655
|
+
inboxNotice: { pending: counts.pending, delivered: delivered.fresh, ...(delivered.resupplied > 0 ? { resupplied: delivered.resupplied } : {}), ...(counts.urgent > 0 ? { urgent: counts.urgent } : {}), box: boxHandle },
|
|
582
656
|
_sema_provenance: { kind: "inbox_notice", from: boxHandle, taskId: `inbox:${boxHandle}`, seq: noticeRound },
|
|
583
657
|
}, { priority: "next" });
|
|
584
658
|
}
|
|
@@ -586,7 +660,7 @@ export function createPeerSessionDrain(opts) {
|
|
|
586
660
|
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-inject" });
|
|
587
661
|
}
|
|
588
662
|
}
|
|
589
|
-
return
|
|
663
|
+
return waitingAcross();
|
|
590
664
|
}
|
|
591
665
|
finally {
|
|
592
666
|
currentRound = undefined;
|
|
@@ -613,20 +687,33 @@ export function createPeerSessionDrain(opts) {
|
|
|
613
687
|
return settled.then(() => ({ delivered: out, pending: counts.pending, urgent: counts.urgent }));
|
|
614
688
|
};
|
|
615
689
|
const finishOnce = async () => {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
690
|
+
const claimed = [];
|
|
691
|
+
for (const lane of lanes) {
|
|
692
|
+
try {
|
|
693
|
+
claimed.push({ lane, lease: await mailbox.claimLease(scope, lane.boxHandle, drainOwner, ttl) });
|
|
694
|
+
}
|
|
695
|
+
catch (e) {
|
|
696
|
+
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-claim" });
|
|
697
|
+
}
|
|
624
698
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
699
|
+
if (claimed.length > 0) {
|
|
700
|
+
try {
|
|
701
|
+
settleLocally();
|
|
702
|
+
for (const { lane, lease } of claimed)
|
|
703
|
+
if (lease !== null)
|
|
704
|
+
await ackSettledPrefix(lane, lease);
|
|
705
|
+
}
|
|
706
|
+
catch (e) {
|
|
707
|
+
opts.onError?.(e, { phase: "degraded", sessionId, classification: "peer-box-claim" });
|
|
708
|
+
}
|
|
628
709
|
}
|
|
629
|
-
|
|
710
|
+
for (const lane of lanes) {
|
|
711
|
+
lane.held.detachLeg();
|
|
712
|
+
try {
|
|
713
|
+
await mailbox.releaseLease(scope, lane.boxHandle, drainOwner);
|
|
714
|
+
}
|
|
715
|
+
catch {
|
|
716
|
+
}
|
|
630
717
|
}
|
|
631
718
|
};
|
|
632
719
|
const finish = () => {
|
|
@@ -642,16 +729,18 @@ export function createPeerSessionDrain(opts) {
|
|
|
642
729
|
if (p === null || typeof p !== "object" || typeof p.task_id !== "string" || typeof p.status !== "string")
|
|
643
730
|
return false;
|
|
644
731
|
const key = taskNotificationDedupKey(p);
|
|
645
|
-
for (const
|
|
646
|
-
|
|
647
|
-
|
|
732
|
+
for (const lane of lanes)
|
|
733
|
+
for (const d of lane.ledger.values())
|
|
734
|
+
if (d.kind === "delivered" && d.key === key)
|
|
735
|
+
return true;
|
|
648
736
|
return false;
|
|
649
737
|
},
|
|
650
738
|
finish,
|
|
651
739
|
wantsCompactionEffects,
|
|
652
740
|
busy: () => idleMachine.target.busy(),
|
|
653
741
|
idle: (finishedAt) => idleMachine.target.idle(finishedAt),
|
|
654
|
-
held,
|
|
742
|
+
held: sessionLane.held,
|
|
743
|
+
...(lanes[1] !== undefined ? { principalHeld: lanes[1].held } : {}),
|
|
655
744
|
idleMachine,
|
|
656
745
|
};
|
|
657
746
|
}
|
|
@@ -684,7 +773,7 @@ export function peerLaneSendMessageSeats(args) {
|
|
|
684
773
|
};
|
|
685
774
|
}
|
|
686
775
|
export function listAgentsMountable(face) {
|
|
687
|
-
return face.
|
|
776
|
+
return face.leaves({ name: LIST_AGENTS_TOOL_NAME, aliases: [LIST_AGENTS_TOOL_ALIAS] }) && listAgentsNameFree(face.specTools);
|
|
688
777
|
}
|
|
689
778
|
function listAgentsNameFree(specTools) {
|
|
690
779
|
return !specTools.some((t) => t.name === LIST_AGENTS_TOOL_NAME || t.name === LIST_AGENTS_TOOL_ALIAS || t.aliases?.includes(LIST_AGENTS_TOOL_NAME) || t.aliases?.includes(LIST_AGENTS_TOOL_ALIAS));
|
|
@@ -692,8 +781,6 @@ function listAgentsNameFree(specTools) {
|
|
|
692
781
|
export function mountListAgents(args) {
|
|
693
782
|
if (!listAgentsNameFree(args.specTools))
|
|
694
783
|
return undefined;
|
|
695
|
-
args.toolEffects.set(LIST_AGENTS_TOOL_NAME, "read");
|
|
696
|
-
args.toolEffects.set(LIST_AGENTS_TOOL_ALIAS, "read");
|
|
697
784
|
return createListAgentsTool({
|
|
698
785
|
...(args.peerDirectory !== undefined ? { peerDirectory: args.peerDirectory } : {}),
|
|
699
786
|
...(args.freshWindowMs !== undefined ? { freshWindowMs: args.freshWindowMs } : {}),
|
|
@@ -754,6 +841,7 @@ export function bindPeerLaneDrain(harness, args) {
|
|
|
754
841
|
sessionId: args.sessionId,
|
|
755
842
|
runId: args.runId,
|
|
756
843
|
scope: args.scope,
|
|
844
|
+
...(terminalsDrainPrincipalInbox(deps) ? { principalInbox: true } : {}),
|
|
757
845
|
inject: args.inject,
|
|
758
846
|
...(deps.peerLane !== undefined ? { lane: deps.peerLane } : {}),
|
|
759
847
|
ownTokens: args.ownTokens,
|
|
@@ -765,6 +853,7 @@ export function bindPeerLaneDrain(harness, args) {
|
|
|
765
853
|
...(args.settlement !== undefined ? { settlement: args.settlement } : {}),
|
|
766
854
|
...(args.parked !== undefined ? { parked: args.parked } : {}),
|
|
767
855
|
...(args.lastTurnText !== undefined ? { lastTurnText: args.lastTurnText } : {}),
|
|
856
|
+
...(args.markExternalContent !== undefined ? { markExternalContent: args.markExternalContent } : {}),
|
|
768
857
|
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
769
858
|
...(deps.onError !== undefined ? { onError: deps.onError } : {}),
|
|
770
859
|
});
|