@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,11 +1,12 @@
|
|
|
1
1
|
import { type AgentMessage, type CompactionSettings, type Session, type ThinkingLevel } from "../internal/harness.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type Message, type Model, type Tool } from "../internal/llm.js";
|
|
3
3
|
import type { ContextWindowOverlay } from "./context-settings.js";
|
|
4
4
|
import type { PostCompactContext, PreCompactContext, PreCompactResult } from "./hooks.js";
|
|
5
5
|
import type { TraceEvent } from "./trace.js";
|
|
6
6
|
import type { Brain } from "./types.js";
|
|
7
7
|
import type { TaskEvent, TaskEventIdentity } from "./task-event.js";
|
|
8
8
|
import type { CompactionEffect } from "./frame-settlement.js";
|
|
9
|
+
import type { MintedAttachmentFrame } from "./user-attachment.js";
|
|
9
10
|
/**
|
|
10
11
|
* Default summarization focus, applied when a task does not provide `compaction.instructions`.
|
|
11
12
|
* Addresses the common fidelity failure where summaries drop specific facts.
|
|
@@ -101,6 +102,32 @@ export interface CompactionForkContext {
|
|
|
101
102
|
* eligibility gate refuses a snapshot from a different model (see the engine-side twin's doc). */
|
|
102
103
|
modelId?: string;
|
|
103
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* What a compaction pass reports at the moment it commits ({@link MaybeCompactOptions.onStarted}) — and the
|
|
107
|
+
* whole content of its `compaction_started` wire frame. `pass` is minted HERE, by the one function every lane
|
|
108
|
+
* runs, so no lane can number its own passes; the frame that ends the pass carries the same value.
|
|
109
|
+
*/
|
|
110
|
+
export interface CompactionPassStart {
|
|
111
|
+
readonly pass: string;
|
|
112
|
+
/** The trigger this pass runs under — the value it hands the `preCompact` hook. */
|
|
113
|
+
readonly trigger: "auto" | "manual" | "forced";
|
|
114
|
+
/** Engine clock, epoch ms, at the commit. */
|
|
115
|
+
readonly startedAt: number;
|
|
116
|
+
}
|
|
117
|
+
/** What a landed compaction asks its restore for ({@link MaybeCompactOptions.workingFileAttachments}). */
|
|
118
|
+
export interface CompactionRestoreAsk {
|
|
119
|
+
/** The files to re-read, most recent first — already without the ones the context the summary leaves still shows. */
|
|
120
|
+
readonly candidates: readonly string[];
|
|
121
|
+
readonly maxFiles: number;
|
|
122
|
+
/** What one file may deliver, in its own text (before the Read's line numbers — the unit `maxCharsPerFile` counts),
|
|
123
|
+
* and all of them together, in the file contents the frames send (line numbers included — the unit of the
|
|
124
|
+
* window's share); an image costs the engine estimate's fixed weight × `charsPerToken` in both. */
|
|
125
|
+
readonly perFileChars: number;
|
|
126
|
+
readonly totalChars: number;
|
|
127
|
+
readonly charsPerToken: number;
|
|
128
|
+
/** The reads the context the summary leaves still shows (canonical keys) — the restore dedups against them. */
|
|
129
|
+
readonly preserveKeys: readonly string[];
|
|
130
|
+
}
|
|
104
131
|
export interface MaybeCompactOptions {
|
|
105
132
|
/** Disclosure channel for CONTAINED host-callback failures in this scope (the RB-463
|
|
106
133
|
* isolation primitive's bounded first-failure per site). Absent ⇒ failures are counted only. */
|
|
@@ -267,31 +294,26 @@ export interface MaybeCompactOptions {
|
|
|
267
294
|
*/
|
|
268
295
|
forceUnderThreshold?: boolean;
|
|
269
296
|
/**
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* a
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* compaction). Absent (default) = current behavior, paths-only.
|
|
280
|
-
* Pick order (design/71 P2-① resolved the LONGRUN-2b limitation): `maxFiles` picks the most
|
|
281
|
-
* RECENTLY touched files first (`CompactionDetails.modifiedFilesByRecency`, recency threaded
|
|
282
|
-
* through the engine fileOps accumulator); alphabetical `modifiedFiles` remains the fallback for
|
|
283
|
-
* details persisted before the field existed.
|
|
297
|
+
* The post-compaction restore: after a summary lands, re-read up to `maxFiles`
|
|
298
|
+
* of the files the conversation had read (or, without read tracking, modified) that the context the summary leaves
|
|
299
|
+
* no longer shows, and append each as an attachment frame — its own engine-note message after the compaction entry
|
|
300
|
+
* (summary, kept tail, restored files: the reference's post-compact order, cli296.js:249517 `hookResults`). Why: without it the model spends ≈2.3 extra read round-trips per
|
|
301
|
+
* compaction re-fetching what it just lost (LONGRUN-2). Bounded: a per-file cap in the file's own characters and a
|
|
302
|
+
* total, in the file contents the frames send (line numbers included), that self-scales to ~15% of the window; a
|
|
303
|
+
* file over either is a frame that names it and says it is too large, never part of its contents. The post measurement counts the frames, so the anti-thrash floor stays truthful. Absent ⇒ no restore.
|
|
304
|
+
* Pick order: most recently READ first (`recentlyReadFiles`), else most recently modified
|
|
305
|
+
* (`CompactionDetails.modifiedFilesByRecency`), else the alphabetical `modifiedFiles` of older details.
|
|
284
306
|
*/
|
|
285
307
|
workingFileAttachments?: {
|
|
286
|
-
/**
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
/** Max
|
|
308
|
+
/** Re-read the candidates and mint their frames — the engine's one read of a file for the model, deduplicated against
|
|
309
|
+
* the context the summary leaves (`preserveKeys` = the reads that context still shows). Side-effect free: each frame
|
|
310
|
+
* carries the commit its delivery owes, run here once the frame is in the transcript. Wired by the Runner. */
|
|
311
|
+
restore: (ask: CompactionRestoreAsk) => Promise<ReadonlyArray<MintedAttachmentFrame>>;
|
|
312
|
+
/** A minted restore frame the transcript would not take (not delivered, nothing committed) — the operator's line. */
|
|
313
|
+
undelivered?: (label: string, reason: string) => void;
|
|
314
|
+
/** Max files to restore. Default 3. */
|
|
293
315
|
maxFiles?: number;
|
|
294
|
-
/** Per-file
|
|
316
|
+
/** Per-file cap in the file's own characters (≈4 chars/token). Default 16_000 (~4k tokens). */
|
|
295
317
|
maxCharsPerFile?: number;
|
|
296
318
|
/**
|
|
297
319
|
* CC-parity selection set: the files the task has READ, most recent
|
|
@@ -313,9 +335,9 @@ export interface MaybeCompactOptions {
|
|
|
313
335
|
instructionSourcePaths?: ReadonlyArray<string>;
|
|
314
336
|
/**
|
|
315
337
|
* `recentlyReadFiles` yields CANONICAL keys (resolveKey
|
|
316
|
-
* output — the same coordinate `ReadFileState` is keyed in
|
|
317
|
-
*
|
|
318
|
-
*
|
|
338
|
+
* output — the same coordinate `ReadFileState` is keyed in, and the one an attachment frame's recorded
|
|
339
|
+
* read carries), but `instructionSourcePaths` and the kept tail's Read tool calls (raw model-typed
|
|
340
|
+
* arguments) do NOT share that coordinate — a model-typed relative path and its
|
|
319
341
|
* canonical form are different strings, so a plain `Set.has()` between them silently never matches
|
|
320
342
|
* even for the identical file. Optional callback (present exactly when there's a containment root
|
|
321
343
|
* to resolve against — i.e. hands enabled) that canonicalizes a raw path the SAME way the hands
|
|
@@ -340,29 +362,18 @@ export interface MaybeCompactOptions {
|
|
|
340
362
|
isDedupStubResult?: (resultText: string) => boolean;
|
|
341
363
|
};
|
|
342
364
|
/**
|
|
343
|
-
* Fires ONCE per LANDED compaction (after `appendCompaction` committed the new baseline
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* `workingFileAttachments` deliberately — the invalidation is owed even when
|
|
348
|
-
*
|
|
365
|
+
* Fires ONCE per LANDED compaction (after `appendCompaction` committed the new baseline and the restore frames were
|
|
366
|
+
* appended), immediately followed by the delivered restore frames' commits — the read state's clear and the restore's
|
|
367
|
+
* entries land together, after the baseline; a compaction that does not land touches neither. The Runner wires this to
|
|
368
|
+
* the read-state invalidation (`applyContextShrinkToReadFileState`): the summary just replaced the history the
|
|
369
|
+
* read-dedup stubs point at. Kept OUTSIDE `workingFileAttachments` deliberately — the invalidation is owed even when
|
|
370
|
+
* the restore is off. Best-effort: a throwing callback must not fail the landed compaction.
|
|
349
371
|
*
|
|
350
|
-
* `preserveReadState`:
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
* `maybeCompact` deliberately skipped re-attaching, for EITHER exclusion reason (kept-tail-visible,
|
|
354
|
-
* or matches a declared instruction source). Without this the read-state clear (see
|
|
355
|
-
* `applyContextShrinkToReadFileState`) would wipe them anyway, defeating both the read-before-edit gate
|
|
356
|
-
* and the next read's dedup for exactly the files this optimization was supposed to leave untouched.
|
|
357
|
-
* (The instruction-source half of this was missing in an earlier revision: `instructionSources` and
|
|
358
|
-
* `seededFiles` are independent `ProjectMemoryLoad` fields — a path can be declared in the former
|
|
359
|
-
* without ever being seeded via the latter, so an instruction-excluded file the model explicitly Read
|
|
360
|
-
* has a live, non-seeded entry that needs the SAME preservation as a kept-tail one.)
|
|
372
|
+
* `preserveReadState`: canonical-coordinate paths whose entry survives the clear — every file the context the summary
|
|
373
|
+
* leaves still shows (a kept-tail read or attachment frame) or that a declared instruction source re-seeds; the restore
|
|
374
|
+
* deduplicates against the same set.
|
|
361
375
|
*/
|
|
362
|
-
onApplied?: (
|
|
363
|
-
path: string;
|
|
364
|
-
content: string;
|
|
365
|
-
}>, preserveReadState?: ReadonlyArray<string>) => void;
|
|
376
|
+
onApplied?: (preserveReadState: ReadonlyArray<string>) => void;
|
|
366
377
|
/**
|
|
367
378
|
* #1036 — THE COMMIT-BEAT EFFECT SINK: what this compaction did to the transcript, reported
|
|
368
379
|
* once, right after the `appendCompaction` that landed it. `summarizedEntryIds` = every entry id
|
|
@@ -432,7 +443,7 @@ export interface MaybeCompactOptions {
|
|
|
432
443
|
* Inputs:
|
|
433
444
|
* - `messagesToSummarize`: the message range that would be summarized this boundary.
|
|
434
445
|
* - `previousSummary`: the prior compaction's summary (present on the UPDATE/iterative-merge path).
|
|
435
|
-
* - `modifiedFiles`: files the summarized range modified, newest-first (same source the
|
|
446
|
+
* - `modifiedFiles`: files the summarized range modified, newest-first (same source the restore's
|
|
436
447
|
* attachments use), so a provider can decide whether the reused summary is still representative.
|
|
437
448
|
*/
|
|
438
449
|
summaryProvider?: (input: {
|
|
@@ -482,6 +493,17 @@ export interface MaybeCompactOptions {
|
|
|
482
493
|
* not optional there, so a preCompact `block` is IGNORED on "forced").
|
|
483
494
|
*/
|
|
484
495
|
trigger?: "auto" | "manual" | "forced";
|
|
496
|
+
/**
|
|
497
|
+
* The pass has COMMITTED: the trigger gate passed, a valid cut point exists and no `preCompact` handler
|
|
498
|
+
* blocked it, and nothing has yet consulted the summary provider or called the model. Fired exactly once per
|
|
499
|
+
* pass — a retry inside the summary call is the same pass — and never for a pass that ends before this point
|
|
500
|
+
* (under threshold, held under the floor, disabled, nothing to compact, blocked, or cut by its own signal while
|
|
501
|
+
* the `preCompact` hook ran). A pass that fired it ends
|
|
502
|
+
* in `compacted: true` or a throw, so the caller that put a frame on the wire here owes the matching end.
|
|
503
|
+
* Observe-only: a throw — or the rejection of an `async` callback, which this seat does not await — is
|
|
504
|
+
* contained and never reaches the pass.
|
|
505
|
+
*/
|
|
506
|
+
onStarted?: (start: CompactionPassStart) => void;
|
|
485
507
|
/**
|
|
486
508
|
* design/134 (CC PreCompact parity) — fired AFTER the trigger gate and a CONFIRMED valid cut point
|
|
487
509
|
* (so every invocation corresponds to a compaction that would actually happen), BEFORE the
|
|
@@ -553,6 +575,10 @@ export declare function maybeCompact(opts: MaybeCompactOptions): Promise<{
|
|
|
553
575
|
* nothing to do looked identical to one that never wanted to run; the caller's outcome event
|
|
554
576
|
* (`compaction_outcome{outcome:"noop"}`) reads this flag. */
|
|
555
577
|
noop?: true;
|
|
578
|
+
/** The id of the pass this result concludes — the value {@link MaybeCompactOptions.onStarted} was handed.
|
|
579
|
+
* Set exactly when `compacted` is true: every other return of this function ends before the pass commits,
|
|
580
|
+
* and a pass that commits and does not land THROWS (the caller learned the id from the start callback). */
|
|
581
|
+
pass?: string;
|
|
556
582
|
tokensBefore?: number;
|
|
557
583
|
/** The §25.2 STRUCTURAL pre/post delta in ONE coordinate — the only subtractable quantity here.
|
|
558
584
|
* Absent ⇒ the post measurement failed and no delta was taken. */
|
|
@@ -594,7 +620,7 @@ export declare function maybeCompact(opts: MaybeCompactOptions): Promise<{
|
|
|
594
620
|
* consult → clamp dry run + 门A/门B gating (everything before the summary call). `summaryMs` = the
|
|
595
621
|
* summary LLM leg (`compact()`: serialization → clamp → completion, incl. any PTL retries) — ABSENT
|
|
596
622
|
* on a provider-reuse pass (no LLM call happened; its provider consult time sits in `prepareMs`).
|
|
597
|
-
* `persistMs` =
|
|
623
|
+
* `persistMs` = restore reads → session rewrite (`appendCompaction`) → restore frames → post measurement →
|
|
598
624
|
* observers. The phases tile the pass exactly: prepareMs + (summaryMs ?? 0) + persistMs ===
|
|
599
625
|
* durationMs. `ptlRetries` = reactive prompt-too-long retries burned inside this pass's summary
|
|
600
626
|
* call(s) (both split-turn legs accumulate into the one counter; 0 on provider reuse). Set only when
|
|
@@ -669,6 +695,8 @@ export declare function maybeCompact(opts: MaybeCompactOptions): Promise<{
|
|
|
669
695
|
/** What a landed compaction hands the wire frame. Structural, so both the full `maybeCompact` result
|
|
670
696
|
* and the settle lane's narrower `EndOfTaskCompaction` satisfy it without either importing the other. */
|
|
671
697
|
export interface CompactedFrameSource {
|
|
698
|
+
/** The pass this landing concludes (see {@link MaybeCompactOptions.onStarted}). */
|
|
699
|
+
pass?: string;
|
|
672
700
|
tokensBefore?: number;
|
|
673
701
|
freedTokens?: number;
|
|
674
702
|
postTriggerTokens?: number;
|
|
@@ -703,6 +731,34 @@ export interface CompactedFrameSource {
|
|
|
703
731
|
export declare function mintCompactedEvent(comp: CompactedFrameSource, trigger: "auto" | "manual" | "forced", identity: TaskEventIdentity): Extract<TaskEvent, {
|
|
704
732
|
type: "compacted";
|
|
705
733
|
}>;
|
|
734
|
+
/**
|
|
735
|
+
* THE mint of the `compaction_started` wire frame — the opening half of the pair whose closing half is the
|
|
736
|
+
* `compacted` frame above (or a `compaction_outcome` that carries the same `pass`). One function, three
|
|
737
|
+
* lanes, as the landing's: the frame is the start report itself plus the identity envelope, so a lane that
|
|
738
|
+
* wants to announce a pass can only announce the one `maybeCompact` committed.
|
|
739
|
+
*/
|
|
740
|
+
export declare function mintCompactionStartedEvent(start: CompactionPassStart, identity: TaskEventIdentity): Extract<TaskEvent, {
|
|
741
|
+
type: "compaction_started";
|
|
742
|
+
}>;
|
|
743
|
+
/**
|
|
744
|
+
* One compaction pass's account on the wire: the `onStarted` seat to hand `maybeCompact`, and the id the frame
|
|
745
|
+
* that ENDS the pass must carry. A lane makes one per pass, hands `onStarted` to the pass, and spreads
|
|
746
|
+
* {@link CompactionPassReport.end} into every `compaction_outcome` the pass can end with after it committed — a
|
|
747
|
+
* pass that threw before it committed leaves it empty, which is exactly "no start was announced, so no `pass`
|
|
748
|
+
* names it". The landing needs no spread: `maybeCompact` returns the id and `mintCompactedEvent` reads it.
|
|
749
|
+
*/
|
|
750
|
+
export interface CompactionPassReport {
|
|
751
|
+
readonly onStarted: (start: CompactionPassStart) => void;
|
|
752
|
+
/** The announced pass's id; `undefined` until a start went on the wire. */
|
|
753
|
+
readonly pass: string | undefined;
|
|
754
|
+
/** `{ pass }` once a start was announced, `{}` before — for the frame that ends the pass. */
|
|
755
|
+
readonly end: {
|
|
756
|
+
pass?: string;
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
export declare function compactionPassReport(sink: {
|
|
760
|
+
push(event: TaskEvent): void;
|
|
761
|
+
}, ident: () => TaskEventIdentity): CompactionPassReport;
|
|
706
762
|
/**
|
|
707
763
|
* How many cross-session message frames the summarized prefix held: the engine-note user messages
|
|
708
764
|
* whose text is the drain's `<cross-session-message …>` envelope, before the kept tail begins. The
|
|
@@ -737,7 +793,7 @@ export declare function countSummarizedCrossSessionMessages(branch: ReadonlyArra
|
|
|
737
793
|
* 5. (COMPACTION-LIVE-AUDIT D-1, evaluated BEFORE rule 3) a TRIM-FORCED landing with
|
|
738
794
|
* `freedTokens ≤ 0` → negative-yield: BACKOFF ON. The trim layer deceives the usage-anchored
|
|
739
795
|
* estimate down into the sawtooth trough (live: est 18807 on a ~55k session), the forced pass
|
|
740
|
-
* finds little compressible history, and summary +
|
|
796
|
+
* finds little compressible history, and summary + restore frames make the transcript
|
|
741
797
|
* LARGER (live: 18807→44609, 12679→35214). `freedTokens` is the structural pre/post delta
|
|
742
798
|
* (clamped ≥0, so ≤0 means "freed nothing") — orthogonal to rule 2/3's threshold test, which
|
|
743
799
|
* misses this shape because the bloated post (44609) can still sit UNDER the threshold (44800),
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { CROSS_SESSION_MESSAGE_TAG } from "../agents/cross-session-envelope.js";
|
|
2
|
-
import { DEFAULT_CHARS_PER_TOKEN, DEFAULT_CLAMP_TOLERANCE, DEFAULT_COMPACTION_SETTINGS, CompactionError, compact, computeFileLists, dryRunSummarizationClamp, estimateContextTokens, estimateTokens, formatFileOperations, formatPersistedOutputRefs, prepareCompaction, shouldCompact, } from "../internal/harness.js";
|
|
2
|
+
import { DEFAULT_CHARS_PER_TOKEN, DEFAULT_CLAMP_TOLERANCE, DEFAULT_COMPACTION_SETTINGS, CompactionError, compact, computeFileLists, dryRunSummarizationClamp, estimateContextTokens, estimateTokens, formatFileOperations, formatPersistedOutputRefs, prepareCompaction, shouldCompact, uuidv7, } from "../internal/harness.js";
|
|
3
3
|
import { fileArgPath } from "./tool-registry.js";
|
|
4
|
+
import { userAttachmentOf } from "../internal/llm.js";
|
|
4
5
|
import { contextEditFrontier, resolveTriggerWindow } from "./context-edit.js";
|
|
5
6
|
import { selectCompactionEpoch } from "../prompt-assembly/epoch.js";
|
|
6
7
|
import { brainToRuntime } from "./runtime.js";
|
|
7
8
|
import { defuseFenceMarkers, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
8
|
-
import { createSafeNotifier } from "./safe-notify.js";
|
|
9
|
+
import { createSafeNotifier, observeThenableRejection } from "./safe-notify.js";
|
|
10
|
+
import { thrownText } from "./thrown-value.js";
|
|
9
11
|
export const DEFAULT_COMPACTION_INSTRUCTIONS = "Preserve verbatim every code, identifier, name, number, file path, error message, credential " +
|
|
10
12
|
"reference, and explicit user instruction or decision mentioned anywhere in the conversation. " +
|
|
11
13
|
"When in doubt, keep the specific detail rather than generalizing it.";
|
|
@@ -18,10 +20,6 @@ export function sanitizeCompactionInstructions(text) {
|
|
|
18
20
|
? cps.slice(0, COMPACTION_INSTRUCTIONS_MAX_CHARS).join("")
|
|
19
21
|
: defused;
|
|
20
22
|
}
|
|
21
|
-
const WORKING_FILE_BREAKOUT_TAGS = ["working-file", "summary"];
|
|
22
|
-
function escapeWorkingFilePathAttr(path) {
|
|
23
|
-
return path.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/[\r\n]+/g, " ");
|
|
24
|
-
}
|
|
25
23
|
const COMPACTION_MANUAL_CANCEL_FLAG = "semaCompactionManualCancel";
|
|
26
24
|
export function isCompactionManualCancel(err) {
|
|
27
25
|
return (typeof err === "object" && err !== null && err[COMPACTION_MANUAL_CANCEL_FLAG] === true);
|
|
@@ -152,6 +150,12 @@ export async function maybeCompact(opts) {
|
|
|
152
150
|
? `${specInstructions}\n\n${hookSanitized}`
|
|
153
151
|
: hookSanitized
|
|
154
152
|
: specInstructions;
|
|
153
|
+
const signalAtCommit = opts.signal;
|
|
154
|
+
if (signalAtCommit?.aborted === true) {
|
|
155
|
+
throw Object.assign(new CompactionError("aborted", "compaction cancelled before the pass committed — nothing was summarized or persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
|
|
156
|
+
}
|
|
157
|
+
const pass = uuidv7();
|
|
158
|
+
notifier.notify(() => observeThenableRejection(opts.onStarted?.({ pass, trigger, startedAt: Date.now() }), notifier, "compaction.onStarted"), "compaction.onStarted");
|
|
155
159
|
const maxReuse = opts.maxConsecutiveProviderReuse ?? 3;
|
|
156
160
|
const forceRealSummary = maxReuse > 0 && (opts.consecutiveProviderReuse ?? 0) >= maxReuse;
|
|
157
161
|
let providerSummary;
|
|
@@ -330,10 +334,15 @@ export async function maybeCompact(opts) {
|
|
|
330
334
|
details = res.value.details;
|
|
331
335
|
}
|
|
332
336
|
const persistStartAt = summaryEndAt ?? Date.now();
|
|
333
|
-
let
|
|
334
|
-
const attachedFiles = [];
|
|
335
|
-
const attachedComplete = [];
|
|
337
|
+
let restoreFrames = [];
|
|
336
338
|
const att = opts.workingFileAttachments;
|
|
339
|
+
const undelivered = (label, reason) => {
|
|
340
|
+
try {
|
|
341
|
+
att?.undelivered?.(label, reason);
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
}
|
|
345
|
+
};
|
|
337
346
|
const recentlyRead = att?.recentlyReadFiles?.() ?? [];
|
|
338
347
|
const rawCandidateFiles = recentlyRead.length > 0 ? recentlyRead : (details?.modifiedFilesByRecency ?? details?.modifiedFiles);
|
|
339
348
|
const maxFilesForSelection = Math.max(1, att?.maxFiles ?? 3);
|
|
@@ -346,6 +355,9 @@ export async function maybeCompact(opts) {
|
|
|
346
355
|
const dedupStub = att?.isDedupStubResult;
|
|
347
356
|
for (let i = firstKeptIdx; i < branch.length; i++) {
|
|
348
357
|
const entry = branch[i];
|
|
358
|
+
const frame = entry?.type === "message" ? userAttachmentOf(entry.message) : undefined;
|
|
359
|
+
if (frame?.observation !== undefined && (frame.outcome === "attached" || frame.outcome === "partial"))
|
|
360
|
+
keptTailReadPathsRaw.add(frame.observation.key);
|
|
349
361
|
if (entry.type !== "message" || entry.message.role !== "assistant")
|
|
350
362
|
continue;
|
|
351
363
|
const msg = entry.message;
|
|
@@ -426,44 +438,13 @@ export async function maybeCompact(opts) {
|
|
|
426
438
|
const maxFiles = maxFilesForSelection;
|
|
427
439
|
const perFileCap = Math.max(200, att.maxCharsPerFile ?? 16_000);
|
|
428
440
|
const windowShareChars = windowKnown ? Math.floor(window * 0.15) * cpt : Number.POSITIVE_INFINITY;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
const r = await att.readFile(path);
|
|
438
|
-
if (typeof r === "string")
|
|
439
|
-
content = r;
|
|
440
|
-
else if (r !== null && typeof r === "object")
|
|
441
|
-
withheldPattern = r.withheld.pattern;
|
|
442
|
-
}
|
|
443
|
-
catch {
|
|
444
|
-
content = null;
|
|
445
|
-
}
|
|
446
|
-
if (withheldPattern !== undefined) {
|
|
447
|
-
blocks.push(`<working-file path="${escapeWorkingFilePathAttr(path)}" withheld="content withheld: matches the sensitive-path read deny list (pattern ${escapeWorkingFilePathAttr(withheldPattern)})"/>`);
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
|
-
if (content === null)
|
|
451
|
-
continue;
|
|
452
|
-
const cap = Math.min(perFileCap, remaining);
|
|
453
|
-
const wasClipped = content.length > cap;
|
|
454
|
-
const clipped = wasClipped
|
|
455
|
-
? `${content.slice(0, cap)}\n[... ${content.length - cap} more characters truncated — read the file for the rest]`
|
|
456
|
-
: content;
|
|
457
|
-
remaining -= clipped.length;
|
|
458
|
-
blocks.push(`<working-file path="${escapeWorkingFilePathAttr(path)}">\n${sanitizeUntrustedText(clipped, WORKING_FILE_BREAKOUT_TAGS)}\n</working-file>`);
|
|
459
|
-
attachedFiles.push({ path, chars: Math.min(content.length, cap), truncated: wasClipped });
|
|
460
|
-
if (!wasClipped)
|
|
461
|
-
attachedComplete.push({ path, content });
|
|
462
|
-
}
|
|
463
|
-
if (blocks.length > 0) {
|
|
464
|
-
summaryWithAttachments +=
|
|
465
|
-
"\n\nCurrent on-disk contents of files touched in the summarized work (re-read at compaction time — trust these over any excerpts in the summary above):\n" +
|
|
466
|
-
blocks.join("\n");
|
|
441
|
+
try {
|
|
442
|
+
restoreFrames = await att.restore({ candidates: candidateFiles, maxFiles, perFileChars: perFileCap, totalChars: Math.min(maxFiles * perFileCap, windowShareChars), charsPerToken: cpt, preserveKeys: excludedReadStatePreserveKeys });
|
|
443
|
+
}
|
|
444
|
+
catch (err) {
|
|
445
|
+
restoreFrames = [];
|
|
446
|
+
for (const path of candidateFiles.slice(0, maxFiles))
|
|
447
|
+
undelivered(path, `the restore failed: ${thrownText(err)}`);
|
|
467
448
|
}
|
|
468
449
|
}
|
|
469
450
|
let preChars = 0;
|
|
@@ -478,7 +459,7 @@ export async function maybeCompact(opts) {
|
|
|
478
459
|
if (opts.signal?.aborted === true) {
|
|
479
460
|
throw Object.assign(new Error("compaction cancelled before commit — the abort signal fired during the summary call; nothing was persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
|
|
480
461
|
}
|
|
481
|
-
await opts.session.appendCompaction(
|
|
462
|
+
await opts.session.appendCompaction(summary, firstKeptEntryId, summaryTokensBefore, {
|
|
482
463
|
...(details ?? {}),
|
|
483
464
|
...(restatedEpoch !== undefined ? { promptEpoch: restatedEpoch } : {}),
|
|
484
465
|
...(restatedListings !== undefined ? { announcedListings: restatedListings } : {}),
|
|
@@ -496,6 +477,26 @@ export async function maybeCompact(opts) {
|
|
|
496
477
|
catch {
|
|
497
478
|
}
|
|
498
479
|
}
|
|
480
|
+
const delivered = [];
|
|
481
|
+
for (const f of restoreFrames) {
|
|
482
|
+
try {
|
|
483
|
+
await opts.session.appendMessage({ role: "user", content: [...f.seed.content], timestamp: Date.now(), provenance: "engine-note", attachment: f.seed.attachment });
|
|
484
|
+
delivered.push(f);
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
for (const g of restoreFrames.slice(delivered.length))
|
|
488
|
+
undelivered(g.seed.attachment.label, `the transcript did not take the restore frame: ${thrownText(err)}`);
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
opts.onApplied?.(excludedReadStatePreserveKeys);
|
|
494
|
+
for (const f of delivered)
|
|
495
|
+
f.commit?.();
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
}
|
|
499
|
+
const attachedFiles = delivered.flatMap(({ seed: { attachment: a } }) => ((a.outcome === "attached" || a.outcome === "partial") && a.dataBlocks.end > a.dataBlocks.start ? [{ path: a.label, chars: a.chars, truncated: a.truncated }] : []));
|
|
499
500
|
if (opts.gitRestate !== undefined) {
|
|
500
501
|
try {
|
|
501
502
|
await opts.gitRestate.land();
|
|
@@ -510,11 +511,6 @@ export async function maybeCompact(opts) {
|
|
|
510
511
|
catch {
|
|
511
512
|
}
|
|
512
513
|
}
|
|
513
|
-
try {
|
|
514
|
-
opts.onApplied?.(attachedComplete, excludedReadStatePreserveKeys);
|
|
515
|
-
}
|
|
516
|
-
catch {
|
|
517
|
-
}
|
|
518
514
|
if (ca !== undefined && restatedEpoch !== undefined) {
|
|
519
515
|
try {
|
|
520
516
|
ca.apply(restatedEpoch.identity);
|
|
@@ -555,6 +551,7 @@ export async function maybeCompact(opts) {
|
|
|
555
551
|
return {
|
|
556
552
|
contextUsage,
|
|
557
553
|
compacted: true,
|
|
554
|
+
pass,
|
|
558
555
|
tokensBefore: summaryTokensBefore,
|
|
559
556
|
freedTokens,
|
|
560
557
|
triggerTokens: tokens,
|
|
@@ -585,6 +582,7 @@ export function mintCompactedEvent(comp, trigger, identity) {
|
|
|
585
582
|
return {
|
|
586
583
|
type: "compacted",
|
|
587
584
|
trigger,
|
|
585
|
+
...(comp.pass !== undefined ? { pass: comp.pass } : {}),
|
|
588
586
|
tokensBefore: comp.tokensBefore ?? 0,
|
|
589
587
|
...(comp.freedTokens !== undefined ? { freedTokens: comp.freedTokens } : {}),
|
|
590
588
|
...(comp.postTriggerTokens !== undefined ? { tokensAfter: comp.postTriggerTokens } : {}),
|
|
@@ -601,6 +599,24 @@ export function mintCompactedEvent(comp, trigger, identity) {
|
|
|
601
599
|
...identity,
|
|
602
600
|
};
|
|
603
601
|
}
|
|
602
|
+
export function mintCompactionStartedEvent(start, identity) {
|
|
603
|
+
return { type: "compaction_started", trigger: start.trigger, pass: start.pass, startedAt: start.startedAt, ...identity };
|
|
604
|
+
}
|
|
605
|
+
export function compactionPassReport(sink, ident) {
|
|
606
|
+
let pass;
|
|
607
|
+
return {
|
|
608
|
+
onStarted: (start) => {
|
|
609
|
+
sink.push(mintCompactionStartedEvent(start, ident()));
|
|
610
|
+
pass = start.pass;
|
|
611
|
+
},
|
|
612
|
+
get pass() {
|
|
613
|
+
return pass;
|
|
614
|
+
},
|
|
615
|
+
get end() {
|
|
616
|
+
return pass !== undefined ? { pass } : {};
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
}
|
|
604
620
|
export function countSummarizedCrossSessionMessages(branch, firstKeptEntryId) {
|
|
605
621
|
const firstKeptIdx = branch.findIndex((e) => e.id === firstKeptEntryId);
|
|
606
622
|
const summarized = firstKeptIdx >= 0 ? branch.slice(0, firstKeptIdx) : branch;
|
|
@@ -47,14 +47,16 @@ export interface DerivedDenyRule {
|
|
|
47
47
|
* The effective READ-deny table as the classifier's deny lines — one line per row, the row's reach in the
|
|
48
48
|
* engine's own `Read(...)` path-rule grammar.
|
|
49
49
|
*
|
|
50
|
-
*
|
|
50
|
+
* An UNANCHORED read-deny row is a run of path SEGMENTS matched anywhere in a path — the entry itself and everything under
|
|
51
51
|
* it — and its `*` never crosses a `/` (read-deny.ts: `.ssh` refuses `~/.ssh/id_rsa` and `/srv/x/.ssh/config`
|
|
52
52
|
* alike; a `**` segment matches exactly one segment). The rule grammar reaches the path a pattern names and
|
|
53
53
|
* everything under it, so the line is `//**` + `/` + the row with every run of stars written `*` (one segment,
|
|
54
54
|
* as in the row): `.ssh` ⇒ `Read(//**\/.ssh)`, `**\/secrets/**` ⇒ `Read(//**\/*\/secrets/*)`, `*` (every
|
|
55
55
|
* path) ⇒ `Read(//**\/*)`. A row that names no segment at all (`""`, `/`) is not stated. A HOME-ANCHORED row
|
|
56
56
|
* (`~/<run>`, read-deny.ts `READ_DENY_HOME_WORD`) is the rule grammar's home word with the same reach:
|
|
57
|
-
* `~/.sema/settings.json` ⇒ `Read(~/.sema/settings.json)
|
|
57
|
+
* `~/.sema/settings.json` ⇒ `Read(~/.sema/settings.json)`; a ROOTED row (`/etc/shadow`, anchored at the filesystem
|
|
58
|
+
* root) is the rule grammar's absolute path: `Read(//etc/shadow)`. Which of the three a row is, is the one judge's
|
|
59
|
+
* answer (`readDenyRowAnchor`), asked here as everywhere a row is read.
|
|
58
60
|
*
|
|
59
61
|
* The text of a row can come from a task (a spawned task's author included) and it is spliced into a trusted
|
|
60
62
|
* prompt, so a row is stated as a rule and nothing else: every character the grammar or the prompt must not
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AUTO_MODE_DEFAULT_WINDOW_MAX_CHARS, AUTO_MODE_DEFAULT_WINDOW_MAX_ENTRIES, AUTO_MODE_DEFAULTS_SENTINEL } from "./auto-mode-defaults.js";
|
|
2
2
|
import { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./auto-mode-prompt-assets.js";
|
|
3
3
|
import { cutEnginePrefix, cutEngineSegments, flattenableUserText } from "./untrusted-text.js";
|
|
4
|
-
import { readDenyPatternRun } from "../tools/fs/read-deny.js";
|
|
4
|
+
import { readDenyPatternRun, readDenyRowAnchor } from "../tools/fs/read-deny.js";
|
|
5
5
|
import { renderContentBlock, renderUserAttachmentView, userAttachmentOf } from "../internal/llm.js";
|
|
6
6
|
export { AUTO_MODE_DEFAULTS_SENTINEL } from "./auto-mode-defaults.js";
|
|
7
7
|
function mergeRuleSection(user, defaultsInner) {
|
|
@@ -36,12 +36,13 @@ export function readDenyClassifierRules(entries, rules = []) {
|
|
|
36
36
|
out.push(line);
|
|
37
37
|
};
|
|
38
38
|
for (const { pattern, caseSensitive } of entries) {
|
|
39
|
-
const {
|
|
39
|
+
const { run } = readDenyPatternRun(pattern);
|
|
40
40
|
const segments = run.split("/").filter((seg) => seg.length > 0);
|
|
41
41
|
if (segments.length === 0)
|
|
42
42
|
continue;
|
|
43
43
|
const stated = statedPattern(segments.join("/"));
|
|
44
|
-
|
|
44
|
+
const anchor = readDenyRowAnchor(pattern);
|
|
45
|
+
push({ rule: anchor === "home" ? `Read(~/${stated})` : anchor === "root" ? `Read(//${stated})` : `Read(//**/${stated})`, ...(caseSensitive !== true && /[A-Za-z]/.test(stated) ? { anyCase: true } : {}) });
|
|
45
46
|
}
|
|
46
47
|
for (const { tool, pattern } of rules) {
|
|
47
48
|
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(tool) || pattern.length === 0)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ReceiptFault } from "./mods/kernel/receive.js";
|
|
1
2
|
/**
|
|
2
3
|
* design/80 D-1 §2 (slice 1a.2) — the engine-only **vetted canonical serializer** used to mint a stable,
|
|
3
4
|
* opaque {@link boundInputHashOf | boundInputHash} over a pending tool call's arguments.
|
|
@@ -60,3 +61,71 @@ export declare const UNCANONICALIZABLE = "<uncanonicalizable>";
|
|
|
60
61
|
* The hex digest is fixed-length and opaque — exactly what the operator sees / the D-G signer signs.
|
|
61
62
|
*/
|
|
62
63
|
export declare function boundInputHashOf(value: unknown): string;
|
|
64
|
+
/**
|
|
65
|
+
* The {@link boundInputHashOf} digest of `value` when an approval can be bound to it ({@link bindableValueOf}), else `undefined` —
|
|
66
|
+
* the digest a license is compared by, one only those bytes have. Over the bindable domain the canonical form is exact (no
|
|
67
|
+
* sentinel token stands for part of it), so the digest is the bytes; outside it there is none to give.
|
|
68
|
+
*/
|
|
69
|
+
export declare function exactBoundInputHashOf(value: unknown): string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Why a value is outside the bindable domain: its top is not the payload's shape, a refusal of the receipt it is read by, or one of
|
|
72
|
+
* JSON's own five — a number that is not finite, a hole in a list, a named member on a list, an `undefined` list element, one
|
|
73
|
+
* object met twice.
|
|
74
|
+
*/
|
|
75
|
+
export type BindingFault = ReceiptFault | {
|
|
76
|
+
readonly kind: "not-container" | "not-finite" | "hole" | "list-member" | "undefined-element" | "shared";
|
|
77
|
+
readonly path: readonly string[];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* THE judge of the BINDABLE domain — the values an approval can be bound to, and so the only values with an exact digest: plain
|
|
81
|
+
* JSON data (records, dense lists, strings, finite numbers, booleans, `null`; a record member that is `undefined` is kept as it
|
|
82
|
+
* is, as absent from JSON) under a top of the payload's own shape (`top`: a call's arguments are a RECORD — the default, and the
|
|
83
|
+
* only shape an exact digest is taken of; a question's answers are a LIST), a tree (no object met twice), at most 256 levels of
|
|
84
|
+
* containers. Read by the engine's one receipt of a caller's value in {@link BINDING_RECEIPT} (nothing of the caller's runs: a
|
|
85
|
+
* getter, a hidden or symbol-keyed member, a Proxy, a function, a symbol, a bigint, a Map / Set / Date / binary or any other kind
|
|
86
|
+
* of object, a cycle, nesting past the levels — each refused), then JSON's own five on the receipt's frozen copy. Ok ⇒ that copy.
|
|
87
|
+
*/
|
|
88
|
+
export declare function bindableValueOf(value: unknown, top?: BindingTop): {
|
|
89
|
+
readonly ok: true;
|
|
90
|
+
readonly value: unknown;
|
|
91
|
+
} | {
|
|
92
|
+
readonly ok: false;
|
|
93
|
+
readonly fault: BindingFault;
|
|
94
|
+
};
|
|
95
|
+
/** The top a bound payload has: a call's arguments are a record, a question's answers a list. */
|
|
96
|
+
export type BindingTop = "record" | "list";
|
|
97
|
+
/** THE capture of a caller-supplied payload the engine persists and later compares (a durable decide's edit — a record —, a
|
|
98
|
+
* question's answers — a list): the judge's receipt ({@link bindableValueOf}) kept in the form a durable store's JSON round trip
|
|
99
|
+
* hands back ({@link jsonFormOf}). */
|
|
100
|
+
export declare function capturedJsonOf(value: unknown, top?: BindingTop): {
|
|
101
|
+
readonly ok: true;
|
|
102
|
+
readonly value: unknown;
|
|
103
|
+
} | {
|
|
104
|
+
readonly ok: false;
|
|
105
|
+
readonly fault: BindingFault;
|
|
106
|
+
};
|
|
107
|
+
/** One clause naming a binding fault, its path rooted at `args` (`value` is what the judge was given: for a value that is not
|
|
108
|
+
* data, its `typeof` is read at the fault's place). The text holds the value's own member names: contain it to show it. */
|
|
109
|
+
export declare function describeBindingFault(value: unknown, fault: BindingFault): string;
|
|
110
|
+
/**
|
|
111
|
+
* Recursion-depth ceiling. Makes {@link encode} TOTAL against the two ways a naive recursive walk throws:
|
|
112
|
+
* a CIRCULAR reference (infinite recursion → `Maximum call stack size`) and pathological DEEP nesting (a
|
|
113
|
+
* RangeError before the JS stack limit). At/below this depth a deterministic sentinel is emitted instead of
|
|
114
|
+
* recursing — so {@link boundInputHashOf} can never throw. This is load-bearing (MAJOR-4): digests are read after a remote
|
|
115
|
+
* VM is paused (the park's target mint compares one), where a throw would skip the unpause compensation and leak the VM.
|
|
116
|
+
* 256 is far below the engine's stack limit yet far deeper than any real tool-arg payload. It is also the bindable domain's
|
|
117
|
+
* bound ({@link BINDING_RECEIPT}), so no value with an exact digest meets the sentinel.
|
|
118
|
+
*/
|
|
119
|
+
export declare const MAX_DEPTH = 256;
|
|
120
|
+
/** Canonical JSON (recursively sorted keys, no whitespace) — the erasure protocol's ONE comparison
|
|
121
|
+
* and hash basis: `selectHash` complains bind to it, and evidence rows are written/compared in this
|
|
122
|
+
* form so a re-serialized import (key order changed by a middle layer) still compares equal. The memory
|
|
123
|
+
* export bundle's section hashes are sha256 over it, and a backend that hashes or compares the same
|
|
124
|
+
* records calls this function — the bytes are the contract, so there is no second copy to keep in step.
|
|
125
|
+
*
|
|
126
|
+
* Not {@link canonicalize}: that one emits a type-tagged, length-prefixed form that is not JSON and is
|
|
127
|
+
* never compared across runtimes; this one emits JSON text for JSON-shaped input (an `undefined` member
|
|
128
|
+
* omitted, an `undefined` / function / symbol array element as `null`, a scalar through `JSON.stringify`,
|
|
129
|
+
* an object read by its own enumerable keys with no `toJSON` call). The two answer different questions
|
|
130
|
+
* and their outputs are not interchangeable. */
|
|
131
|
+
export declare function canonicalJsonStringify(value: unknown): string;
|