@sema-agent/core 7.30.1 → 7.31.1
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 +284 -0
- package/dist/agents/cross-session-judge.d.ts +4 -12
- package/dist/agents/cross-session-judge.js +4 -11
- package/dist/agents/peer-session-drain.js +0 -5
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +1 -0
- package/dist/agents/subagent.js +1 -0
- package/dist/core/ask-origin.d.ts +6 -0
- package/dist/core/ask-origin.js +10 -0
- package/dist/core/checkpoint-store.d.ts +14 -0
- package/dist/core/checkpoint-store.js +1 -0
- package/dist/core/engine-notice.d.ts +4 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +4 -0
- package/dist/core/memory-engine/data-plane.d.ts +3 -1
- package/dist/core/memory-engine/data-plane.js +1 -1
- package/dist/core/memory-engine/delegation-settlement.d.ts +44 -3
- package/dist/core/memory-engine/delegation-settlement.js +38 -3
- package/dist/core/memory-engine/engine.d.ts +133 -27
- package/dist/core/memory-engine/engine.js +452 -151
- package/dist/core/memory-engine/entry-scan.d.ts +23 -0
- package/dist/core/memory-engine/entry-scan.js +55 -0
- package/dist/core/memory-engine/file-backend.d.ts +31 -23
- package/dist/core/memory-engine/file-backend.js +174 -100
- package/dist/core/memory-engine/layer-observations.d.ts +109 -0
- package/dist/core/memory-engine/layer-observations.js +148 -0
- package/dist/core/memory-engine/layout.d.ts +40 -4
- package/dist/core/memory-engine/layout.js +43 -7
- package/dist/core/memory-engine/types.d.ts +26 -2
- package/dist/core/parent-spec-seat.d.ts +4 -1
- package/dist/core/parent-spec-seat.js +2 -0
- package/dist/core/park-selfcheck.js +1 -0
- package/dist/core/runner/announce-once-ledger.d.ts +26 -0
- package/dist/core/runner/announce-once-ledger.js +37 -0
- package/dist/core/runner/contracts.d.ts +22 -5
- package/dist/core/runner/denial-limit-arms.d.ts +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +0 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +1 -3
- package/dist/core/runner/prepare-file-history.d.ts +13 -15
- package/dist/core/runner/prepare-file-history.js +57 -43
- package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
- package/dist/core/runner/prepare-listings.d.ts +3 -1
- package/dist/core/runner/prepare-listings.js +2 -2
- package/dist/core/runner/prepare-memory.js +16 -5
- package/dist/core/runner/prepare-park-ask.js +27 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +8 -1
- package/dist/core/runner/prepare-prompt-inputs.js +5 -3
- package/dist/core/runner/prepare-task.js +7 -5
- package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -0
- package/dist/core/runner/prepare-wiring-manifest.js +2 -1
- package/dist/core/runner/run-attachment-seats.js +1 -1
- package/dist/core/runner/run-leg.js +61 -52
- package/dist/core/runner/run-settle-and-teardown.js +4 -0
- package/dist/core/runner/run-turn-boundary.js +6 -6
- package/dist/core/runner/turn-attachments.d.ts +6 -6
- package/dist/core/runner-deps.d.ts +3 -1
- package/dist/core/secret-env.d.ts +12 -1
- package/dist/core/secret-env.js +27 -2
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +2 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +22 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +17 -8
- package/dist/core/tool-spec.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +10 -0
- package/dist/core/wiring-manifest.js +7 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +6 -0
- package/dist/engine/execution-env/node-execution-env.js +15 -17
- package/dist/engine/harness/agent-harness.js +7 -5
- package/dist/engine/lsp/node-lsp-manager.d.ts +4 -0
- package/dist/engine/lsp/node-lsp-manager.js +10 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/fs/shell-read-plan.d.ts +2 -2
- package/dist/tools/fs/shell-read-plan.js +15 -10
- package/dist/tools/fs/shell-read-word.d.ts +5 -4
- package/dist/tools/fs/shell-read-word.js +3 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +7 -1
- package/wire-changes/core@7.31.0.json +705 -0
- package/wire-changes/core@7.31.1.json +189 -0
|
@@ -27,7 +27,8 @@ import type { LockedPreflight } from "../locked-config.js";
|
|
|
27
27
|
import type { MaterializedMcp } from "../mcp.js";
|
|
28
28
|
import type { ResolvedRole } from "../roles.js";
|
|
29
29
|
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
30
|
-
import type {
|
|
30
|
+
import type { SessionTreeEntry } from "../../internal/harness-types.js";
|
|
31
|
+
import type { DateAnchorRead, PrepareResume, PromptFeatureFlags, RunInternals, ToolFaceSnapshot } from "./contracts.js";
|
|
31
32
|
import type { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
|
|
32
33
|
import { type GitStatusLaneRef } from "./git-status-frame.js";
|
|
33
34
|
import { type ContextWindowOverlay } from "../context-settings.js";
|
|
@@ -99,6 +100,10 @@ export interface PreparePromptInputsInput {
|
|
|
99
100
|
advertisedWritableDirs?: AdvertisedWritableDirs;
|
|
100
101
|
/** borrowed-readonly — the acquired session's id (operator-line context). */
|
|
101
102
|
sessionId: string;
|
|
103
|
+
/** borrowed-readonly — the acquired session; only `getBranch` is read (the date anchor). */
|
|
104
|
+
session: {
|
|
105
|
+
getBranch(): Promise<ReadonlyArray<SessionTreeEntry>>;
|
|
106
|
+
};
|
|
102
107
|
/** borrowed-readonly — the deployment's window overlay for this leg, as it reads at PREPARE. The prompt's
|
|
103
108
|
* context-management sentence must not claim mid-task summarization a deployment has turned off for this
|
|
104
109
|
* model; the seat is live, so a later swap's effect on the SENTENCE lands at the next prepare while its
|
|
@@ -123,6 +128,8 @@ export interface PreparePromptInputsResult {
|
|
|
123
128
|
tzValid: boolean;
|
|
124
129
|
/** owned — the client's declared zone as given (paired with `tzValid`; unvalidated on its own). */
|
|
125
130
|
userTz: string | undefined;
|
|
131
|
+
/** owned — the session's date anchor as read here; `envFacts.date` is its prefix date when present. */
|
|
132
|
+
dateAnchor: DateAnchorRead | undefined;
|
|
126
133
|
/** owned — the git-status lane's run-local state (empty on a hands-less leg); the run loop and the checkpoint
|
|
127
134
|
* serializer mutate its fields from here on (`announced`, `mirrorOwed`, …; the frame's receipt rides the leg's shared `Prepared.frameReceipts`). */
|
|
128
135
|
gitStatusRef: GitStatusLaneRef;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { defaultPromptProvider, formatLocalDate, isValidTimeZone } from "../../prompts/default.js";
|
|
2
2
|
import { isIsolated } from "../remote-env.js";
|
|
3
|
+
import { readDateAnchor } from "./announce-once-ledger.js";
|
|
3
4
|
import { probeGitStatusLane } from "./git-status-frame.js";
|
|
4
5
|
import { fenceMcpServerInstructions } from "./turn-attachments.js";
|
|
5
6
|
const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
|
|
6
7
|
import { compactionEnabled } from "../context-settings.js";
|
|
7
8
|
export async function preparePromptInputs(input) {
|
|
8
|
-
const { spec, deps, failClosedReason, lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, advertisedWritableDirs } = input;
|
|
9
|
+
const { spec, deps, failClosedReason, lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, session, advertisedWritableDirs } = input;
|
|
9
10
|
const provider = spec.promptProvider ?? deps.promptProvider ?? defaultPromptProvider;
|
|
10
11
|
const promptPolicyEnabled = Boolean(lockedPreflight.toolPolicy);
|
|
11
12
|
const promptHooks = spec.hooks ?? deps.hooks;
|
|
@@ -37,7 +38,8 @@ export async function preparePromptInputs(input) {
|
|
|
37
38
|
: undefined;
|
|
38
39
|
const userTz = spec.clientContext?.timeZone;
|
|
39
40
|
const tzValid = userTz !== undefined && isValidTimeZone(userTz);
|
|
40
|
-
const
|
|
41
|
+
const dateAnchor = await readDateAnchor(session);
|
|
42
|
+
const envFacts = { date: dateAnchor?.current?.prefixDate ?? formatLocalDate(new Date(), tzValid ? userTz : undefined), modelId: model.id };
|
|
41
43
|
if (tzValid)
|
|
42
44
|
envFacts.timeZone = userTz;
|
|
43
45
|
if (spec.clientContext?.userEmail)
|
|
@@ -141,5 +143,5 @@ export async function preparePromptInputs(input) {
|
|
|
141
143
|
taskRoot: taskRootFinal,
|
|
142
144
|
onDegrade: (reason) => deps.onError?.(new Error(`env git snapshot degraded — ${reason}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" }),
|
|
143
145
|
});
|
|
144
|
-
return { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, gitStatusRef };
|
|
146
|
+
return { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, dateAnchor, gitStatusRef };
|
|
145
147
|
}
|
|
@@ -283,7 +283,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
283
283
|
let shellGatedTools = new Set();
|
|
284
284
|
refuseRequireExistingWithoutSession(spec);
|
|
285
285
|
refuseRegistryScopeMismatch(spec, internals);
|
|
286
|
-
const { acquired, session, conflictRef, wakeRecovered
|
|
286
|
+
const { acquired, session, conflictRef, wakeRecovered } = await prepareAcquireReconcile({ sessions, spec, resume, toolEffects, ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
|
|
287
287
|
const sessionId = acquired.sessionId;
|
|
288
288
|
const onceLedger = await loadAnnounceOnceLedger(session, resume?.seed.announcedListings, deps.onError);
|
|
289
289
|
const hostTaskId = spec.taskId ?? sessionId;
|
|
@@ -382,7 +382,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
382
382
|
const ownedEnv = ownedEnvSeat.current;
|
|
383
383
|
const { taskRootFinal, rebaseRestoredPath } = await prepareWorkspaceRestore({ ownedEnv, deps, spec, internals, resume, taskRootInitial, abortController, sessionId });
|
|
384
384
|
const { canonical: taskRootCanonical } = await resolveTaskRootCanonical({ env: executionEnv, given: taskRootFinal, onNotice: deps.onNotice, sessionId, runId });
|
|
385
|
-
const { trackFileEdit, fileHistoryBoundary, restoredFilePaths, rewindNotes, fileHistoryEnabled, historyScope, historyRoot, historyFs } = await prepareFileHistory({ deps, spec, internals, executionEnv, taskRootFinal, handsEnabled, sessionId, session,
|
|
385
|
+
const { trackFileEdit, fileHistoryBoundary, restoredFilePaths, rewindNotes, fileHistoryEnabled, fileHistoryFact, historyScope, historyRoot, historyFs } = await prepareFileHistory({ deps, spec, internals, executionEnv, taskRootFinal, handsEnabled, sessionId, session, abortController });
|
|
386
386
|
const { noteFileEdited, editedFilesSnapshot, harnessRef, toolProgressRef, skillScope, forwardEvent, reviewRequestRef, requestReview, stopRequestedRef, requestStopAfterTurn, planModeRef, enterPlanMode, subagentRetain, worktreeIsolation } = prepareRunRefs({ spec, internals, executionEnv, taskRootFinal });
|
|
387
387
|
const legContextOverlay = () => runnerSelf?.contextOverlayOf?.(harnessRef.current?.getModelRef() ?? resolvedRole.modelRef);
|
|
388
388
|
let resolvedReadFace;
|
|
@@ -521,6 +521,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
521
521
|
governedProvenance: orgGovernedProvenance,
|
|
522
522
|
},
|
|
523
523
|
});
|
|
524
|
+
if (memoryEngineSession !== undefined)
|
|
525
|
+
rollback.push(() => memoryEngineSession.release());
|
|
524
526
|
memoryAdmittedOrgScopesRef.current = memoryAdmittedOrgScopes;
|
|
525
527
|
ownOrgVerdictRef.current = memoryOwnOrgVerdict ?? priorOwnOrgVerdict;
|
|
526
528
|
if (internals?.ownOrgAdmissionRef !== undefined && ownOrgVerdictRef.current !== undefined) {
|
|
@@ -594,7 +596,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
594
596
|
}
|
|
595
597
|
const projectContext = await prepareProjectContext({ deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume, skillListingBudget: doors.skillListingBudget });
|
|
596
598
|
const { memoryBlock: memoryBlockWithProject, instructionSources, projectInstructionContent, hasSkillManifest, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted } = projectContext;
|
|
597
|
-
const { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, gitStatusRef } = await preparePromptInputs({ spec, deps, contextOverlay: legContextOverlay(), failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
|
|
599
|
+
const { provider, featureFlags, userSystemPrompt, userAppendSystemPrompt, mcpInstructionsBlock, envFacts, tzValid, userTz, dateAnchor, gitStatusRef } = await preparePromptInputs({ spec, deps, contextOverlay: legContextOverlay(), failClosedReason: selfOrchestrationFailClosedReason(spec, deps), lockedPreflight, selfOrchestrationActive, executionEnv, reminderMark, resolvedReadFace, resolvedWriteFace, toolFaceSnapshot, promptProfile, fableMitigations, internals, thinking, ownedEnv, delegation, resolvedRole, mcp, model, externalContentTargetActive, resume, handsEnabled, taskRootFinal, additionalRootsCanonical, additionalReadRootsCanonical, sessionId, session, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}) });
|
|
598
600
|
const { deferred, memoryBlock, toolSearch: toolSearchPolicy } = prepareDeferClassify({ spec, deps, roster, toolFaceSnapshot, handsEnabled, fullShellReachable, promptProfile, model, mcp, a2a, sharedMemoryPairMounted, memoryEnginePairMounted, memoryBlock: memoryBlockWithProject, memoryRecallSegment, onceLedger, sessionId });
|
|
599
601
|
prepareMemoryEngineSession({ memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef });
|
|
600
602
|
const { systemPromptSeat, renderWithDate, systemBlocks, promptManifest, epochDeclaredSections, epochArtifactDigestForSnapshot, buildAssembleInputs, centerAdoptionRef } = await preparePromptAssembly({ session, deps, internals, resume, provider, userSystemPrompt, userAppendSystemPrompt, featureFlags, mcpInstructionsBlock, memoryBlock, envFacts, promptProfile, fableMitigations, tools, model, sessionId, reminderMark, onceLedger });
|
|
@@ -608,7 +610,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
608
610
|
declaredCards: toolRoster.entries.flatMap((e) => e.renderHints?.resultCards ?? []),
|
|
609
611
|
onUndeclared: (type) => deliverEngineNotice(deps.onNotice, { code: "config.tool_card_undeclared", message: `a tool minted a \`details.type\` card ${JSON.stringify(type)} its definition never declared — dropped from tool_end.structured (declare it on the definition's catalog row or the caller's renderHints.resultCards)`, detail: { type, sessionId, runId } }),
|
|
610
612
|
});
|
|
611
|
-
const { agentListing, announcedListingsRef, dateChange } = prepareListings({ spec, tools, onceLedger, sessionId, toolFaceSnapshot, activeTools, resume, skillsListing, listingBudget: doors.skillListingBudget, listingRideRef, renderWithDate, envFacts, tzValid, userTz });
|
|
613
|
+
const { agentListing, announcedListingsRef, dateChange } = prepareListings({ spec, tools, onceLedger, sessionId, toolFaceSnapshot, activeTools, resume, skillsListing, listingBudget: doors.skillListingBudget, listingRideRef, renderWithDate, envFacts, tzValid, userTz, dateAnchor });
|
|
612
614
|
const lastBrainContextRef = {};
|
|
613
615
|
const requestLossyRef = { current: false };
|
|
614
616
|
const staleOffloadWrittenRefs = new Set();
|
|
@@ -707,7 +709,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
707
709
|
}
|
|
708
710
|
}
|
|
709
711
|
const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
|
|
710
|
-
const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtectionCheck, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: shellReadCheck !== undefined, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, sessionBox });
|
|
712
|
+
const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtectionCheck, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: shellReadCheck !== undefined, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, fileHistoryFact, sessionBox });
|
|
711
713
|
if (fileHistoryBoundary !== undefined) {
|
|
712
714
|
harness.on("tool_call", async () => {
|
|
713
715
|
await fileHistoryBoundary.settle();
|
|
@@ -118,6 +118,7 @@ export interface PrepareWiringManifestInput {
|
|
|
118
118
|
readDenyBuiltinTiersActive: readonly string[];
|
|
119
119
|
/** borrowed-readonly — from the LSP phase's manager fold: gates the manifest's LSP section (absent ⇒ byte-identical manifest). */ lspManagerWired: boolean;
|
|
120
120
|
/** borrowed-readonly — from the LSP phase: is the diagnostics lane live? The `lane` word's only input. */ lspDiagnosticsLive: boolean;
|
|
121
|
+
/** borrowed-readonly — from the file-history phase's one fold of the two off switches: the manifest's word, relayed. */ fileHistoryFact: NonNullable<WiringManifest["fileHistory"]>;
|
|
121
122
|
/** borrowed-readonly — the arming outcome the caps phase minted (the manifest's auto-mode face). */
|
|
122
123
|
autoModeArmReason: AutoModeArmFact;
|
|
123
124
|
/** borrowed-readonly — the frozen preflight; only `mcp` (the declared servers the manifest face joins). */
|
|
@@ -116,7 +116,7 @@ function announceDurableGateUnavailable(args) {
|
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
export function prepareWiringManifest(input) {
|
|
119
|
-
const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive } = input;
|
|
119
|
+
const { spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive, fileHistoryFact } = input;
|
|
120
120
|
const onAsk = spec.onAsk ?? deps.onAsk;
|
|
121
121
|
const handWriteTools = toolRoster.entries.filter((e) => e.mountedBy === "hands" && (e.effect === "write" || e.effect === "idempotent")).map((e) => e.name);
|
|
122
122
|
const hasEffectAwareGate = Boolean(policyLayers.length > 0 || (hooks?.preToolUse !== undefined && !preToolUseObservational));
|
|
@@ -218,6 +218,7 @@ export function prepareWiringManifest(input) {
|
|
|
218
218
|
tools: toolRoster,
|
|
219
219
|
hooks: wiredHookEntries(hooks, spec.hooks !== undefined ? "spec" : "deps", preToolUseObservational),
|
|
220
220
|
...(lspManagerWired ? { lsp: deriveLspSeam(toolRoster.entries.some((e) => e.contract.contractId === LSP_CONTRACT_ID), lspDiagnosticsLive) } : {}),
|
|
221
|
+
fileHistory: fileHistoryFact,
|
|
221
222
|
});
|
|
222
223
|
peerLaneRefs.askEffective = wiringManifest.ask.effective;
|
|
223
224
|
const sessionBoxBound = sessionBox !== undefined && internals?.onTaskNotification !== undefined ? sessionBox : undefined;
|
|
@@ -14,7 +14,7 @@ export async function runAttachmentSeats(input) {
|
|
|
14
14
|
const listingsLive = (rs.attach.agentListingOn && prepared.agentListing !== undefined) || (rs.attach.skillsListingOn && prepared.skillsListing !== undefined);
|
|
15
15
|
const backgroundTasksLive = (rs.attach.attachmentsCfg?.backgroundTasks ?? eventDefaultOn("background_tasks")) === true;
|
|
16
16
|
rs.attach.attachState = rs.attach.attachmentsCfg !== undefined || listingsLive || backgroundTasksLive ? createAttachmentState() : undefined;
|
|
17
|
-
rs.attach.dateState = prepared.dateChange !== undefined ? { announcedDate: prepared.dateChange.legDate } : undefined;
|
|
17
|
+
rs.attach.dateState = prepared.dateChange !== undefined ? { announcedDate: prepared.dateChange.anchor?.current?.announcedDate ?? prepared.dateChange.legDate } : undefined;
|
|
18
18
|
rs.attach.instrProbe = runner.deps.probeInstructionSources;
|
|
19
19
|
rs.attach.instrState =
|
|
20
20
|
rs.attach.instrProbe !== undefined && prepared.instructionSources !== undefined && prepared.instructionSources.length > 0
|
|
@@ -30,7 +30,7 @@ import { nextHumanInputSeq } from "./steer-admission.js";
|
|
|
30
30
|
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
31
31
|
import { toolEndBodyFrom, toolResultMsg } from "./tool-end-body.js";
|
|
32
32
|
import { announceListingTruncation } from "../skill-listing-budget.js";
|
|
33
|
-
import { attachmentEnvelopeTags, commitAgentListing, commitSkillsListing, reduceToolEnd, renderAgentListingFrame, renderOrphanedBackgroundTasks, renderSkillsListingFrame, stampWriteAnchor } from "./turn-attachments.js";
|
|
33
|
+
import { attachmentEnvelopeTags, collectDateChange, commitAgentListing, commitSkillsListing, reduceToolEnd, renderAgentListingFrame, renderOrphanedBackgroundTasks, renderSkillsListingFrame, stampWriteAnchor } from "./turn-attachments.js";
|
|
34
34
|
import { flushOwedAnnouncedSnapshot } from "./announce-once-ledger.js";
|
|
35
35
|
import { asThrownError, thrownMarksOf, thrownText } from "../thrown-value.js";
|
|
36
36
|
import { ruleSourcePhrase } from "../rule-denial-sentence.js";
|
|
@@ -235,22 +235,6 @@ export async function runLeg(input) {
|
|
|
235
235
|
...ident(),
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
|
-
if (resume !== undefined)
|
|
239
|
-
resume.decisionDelivered = true;
|
|
240
|
-
if (gitResumeDelivered !== undefined) {
|
|
241
|
-
const delivered = gitResumeDelivered;
|
|
242
|
-
prepared.gitStatusRef.protectedText = delivered.wrapped;
|
|
243
|
-
prepared.frameReceipts.pending.push({
|
|
244
|
-
source: "git_status",
|
|
245
|
-
text: continuation,
|
|
246
|
-
commit: (entryId) => {
|
|
247
|
-
prepared.gitStatusRef.announced = { kind: delivered.kind, hash: delivered.hash, entryId };
|
|
248
|
-
queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[delivered.kind], ...ident() });
|
|
249
|
-
rs.attach.attachmentsInjected += 1;
|
|
250
|
-
prepared.gitStatusRef.mirrorOwed = { kind: delivered.kind, hash: delivered.hash, entryId };
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
238
|
const pending = resume.cp.pendingAction;
|
|
255
239
|
const rejectionHalt = pending.kind === "tool_approval" && resume.outcome.gate === "policy_ask"
|
|
256
240
|
? maybeHumanRejectionHalt({ gate: resume.outcome.gateOutcome, isDelegatedChild, toolName: pending.toolName, toolCallId: pending.toolCallId })
|
|
@@ -258,18 +242,36 @@ export async function runLeg(input) {
|
|
|
258
242
|
if (rejectionHalt !== undefined && pending.kind === "tool_approval")
|
|
259
243
|
prepared.batchHaltRef.current = { rejectedToolCallId: pending.toolCallId };
|
|
260
244
|
prepared.undeliveredContinuationRef.current = { parkedSteers: resumeFrames.map(({ entry }) => entry).filter((e) => !withheldSteerIds.has(e.inputId)), orphanTasks };
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
245
|
+
if (!prepared.abortController.signal.aborted) {
|
|
246
|
+
if (resume !== undefined)
|
|
247
|
+
resume.decisionDelivered = true;
|
|
248
|
+
if (gitResumeDelivered !== undefined) {
|
|
249
|
+
const delivered = gitResumeDelivered;
|
|
250
|
+
prepared.gitStatusRef.protectedText = delivered.wrapped;
|
|
251
|
+
prepared.frameReceipts.pending.push({
|
|
252
|
+
source: "git_status",
|
|
253
|
+
text: continuation,
|
|
254
|
+
commit: (entryId) => {
|
|
255
|
+
prepared.gitStatusRef.announced = { kind: delivered.kind, hash: delivered.hash, entryId };
|
|
256
|
+
queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[delivered.kind], ...ident() });
|
|
257
|
+
rs.attach.attachmentsInjected += 1;
|
|
258
|
+
prepared.gitStatusRef.mirrorOwed = { kind: delivered.kind, hash: delivered.hash, entryId };
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
final = await withBrainSinks(() => prepared.harness.prompt(continuation, {
|
|
263
|
+
engineSegments,
|
|
264
|
+
settleUnansweredToolCalls: rejectionHalt !== undefined ? { halt: rejectionHalt } : {},
|
|
265
|
+
onDelivered: () => {
|
|
266
|
+
prepared.undeliveredContinuationRef.current = { parkedSteers: [], orphanTasks: [] };
|
|
267
|
+
for (const e of appliedEvents)
|
|
268
|
+
queue.push(e);
|
|
269
|
+
},
|
|
270
|
+
}));
|
|
271
|
+
await flushGitMirror();
|
|
272
|
+
if (prepared.gitStatusRef.announced?.pending === true)
|
|
273
|
+
await prepared.gitStatusRef.reassert?.();
|
|
274
|
+
}
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
else {
|
|
@@ -339,6 +341,10 @@ export async function runLeg(input) {
|
|
|
339
341
|
}
|
|
340
342
|
}
|
|
341
343
|
const firstFrames = [];
|
|
344
|
+
const legToday = rs.attach.dateState !== undefined ? prepared.dateChange.today() : undefined;
|
|
345
|
+
const dateFrame = legToday !== undefined ? collectDateChange(rs.attach.dateState, legToday) : undefined;
|
|
346
|
+
if (dateFrame !== undefined)
|
|
347
|
+
firstFrames.push({ source: "date_change", body: dateFrame.body, commit: () => void (rs.attach.dateState.announcedDate = legToday), disclose: () => undefined });
|
|
342
348
|
if (rs.attach.attachState !== undefined) {
|
|
343
349
|
const attach = rs.attach.attachState;
|
|
344
350
|
if (rs.attach.agentListingOn && prepared.agentListing !== undefined) {
|
|
@@ -350,6 +356,7 @@ export async function runLeg(input) {
|
|
|
350
356
|
body: frame.text,
|
|
351
357
|
commit: () => {
|
|
352
358
|
commitAgentListing(attach, listing.entries, listing.models);
|
|
359
|
+
prepared.frameReceipts.listingSnapshotOwed = true;
|
|
353
360
|
prepared.announcedListingsRef.agents = listing.entries.map((e) => e.name);
|
|
354
361
|
if (listing.models !== undefined)
|
|
355
362
|
prepared.announcedListingsRef.models = [...listing.models];
|
|
@@ -367,15 +374,16 @@ export async function runLeg(input) {
|
|
|
367
374
|
body: frame.text,
|
|
368
375
|
commit: () => {
|
|
369
376
|
commitSkillsListing(attach, listing.entries);
|
|
377
|
+
prepared.frameReceipts.listingSnapshotOwed = true;
|
|
370
378
|
prepared.announcedListingsRef.skills = listing.entries.map((e) => e.name);
|
|
371
379
|
},
|
|
372
380
|
disclose: () => announceListingTruncation(runner.deps.onNotice, { listing: "skills", total: frame.listed, nameOnly: frame.nameOnly, dropped: frame.dropped, budget: listing.budget, sessionId: prepared.sessionId }),
|
|
373
381
|
});
|
|
374
382
|
}
|
|
375
383
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
384
|
+
}
|
|
385
|
+
if (firstFrames.length > 0) {
|
|
386
|
+
effectiveObjective = `${firstFrames.map((f) => mintSystemReminder(sanitizeUntrustedText(f.body, attachmentEnvelopeTags(f.source)), prepared.reminderMark)).join("\n")}\n${effectiveObjective}`;
|
|
379
387
|
}
|
|
380
388
|
if (composeApprovalPostureDirective(prepared.approvalPosture) !== undefined) {
|
|
381
389
|
const postureDirective = composeApprovalPostureDirective(prepared.approvalPosture, await statedReminderBodiesOf(prepared.session, prepared.reminderMark));
|
|
@@ -451,32 +459,33 @@ export async function runLeg(input) {
|
|
|
451
459
|
f.commit();
|
|
452
460
|
queue.push({ type: "steering_injected", source: f.source, preview: redactThenCut(f.body, 220), ...ident() });
|
|
453
461
|
rs.attach.attachmentsInjected += 1;
|
|
454
|
-
prepared.frameReceipts.listingSnapshotOwed = true;
|
|
455
462
|
f.disclose();
|
|
456
463
|
},
|
|
457
464
|
});
|
|
458
465
|
}
|
|
459
466
|
const enginePrefixChars = effectiveObjective.length - projectedObjective.length;
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
467
|
+
if (!prepared.abortController.signal.aborted) {
|
|
468
|
+
queue.push({
|
|
469
|
+
...buildHumanInputEvent({
|
|
470
|
+
carrier: "objective",
|
|
471
|
+
source: "objective",
|
|
472
|
+
delivery: "applied",
|
|
473
|
+
sessionSeq: nextHumanInputSeq(prepared.harness),
|
|
474
|
+
...(objectiveActor !== undefined ? { actor: objectiveActor } : {}),
|
|
475
|
+
...(objectiveActor?.issuer !== undefined ? { issuer: objectiveActor.issuer } : {}),
|
|
476
|
+
...(spec.principal !== undefined ? { principal: spec.principal } : {}),
|
|
477
|
+
}),
|
|
478
|
+
...ident(),
|
|
479
|
+
});
|
|
480
|
+
final = await withBrainSinks(() => prepared.harness.prompt(effectiveObjective, {
|
|
481
|
+
...(images && images.length > 0 ? { images } : {}),
|
|
482
|
+
...(enginePrefixChars > 0 ? { enginePrefixChars } : {}),
|
|
466
483
|
...(objectiveActor !== undefined ? { actor: objectiveActor } : {}),
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
final = await withBrainSinks(() => prepared.harness.prompt(effectiveObjective, {
|
|
473
|
-
...(images && images.length > 0 ? { images } : {}),
|
|
474
|
-
...(enginePrefixChars > 0 ? { enginePrefixChars } : {}),
|
|
475
|
-
...(objectiveActor !== undefined ? { actor: objectiveActor } : {}),
|
|
476
|
-
}));
|
|
477
|
-
await flushGitMirror();
|
|
478
|
-
if (prepared.gitStatusRef.announced?.pending === true)
|
|
479
|
-
await prepared.gitStatusRef.reassert?.();
|
|
484
|
+
}));
|
|
485
|
+
await flushGitMirror();
|
|
486
|
+
if (prepared.gitStatusRef.announced?.pending === true)
|
|
487
|
+
await prepared.gitStatusRef.reassert?.();
|
|
488
|
+
}
|
|
480
489
|
}
|
|
481
490
|
}
|
|
482
491
|
loopLatch.ended = true;
|
|
@@ -19,6 +19,7 @@ import { resumeDecisionWasNegative } from "./decide-continuation.js";
|
|
|
19
19
|
import { drainForwardedFramesBeforeDone, forwardsSubagentEvents } from "./prepare-run-refs.js";
|
|
20
20
|
import { generatePromptSuggestions } from "./prompt-suggestions.js";
|
|
21
21
|
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
22
|
+
import { owedDateAnchor } from "./announce-once-ledger.js";
|
|
22
23
|
import { autoRunConsolidationFromRecommendation, autoRunOnRecommendationEffective, scopeHasUnconsumedRecommendation } from "./memory-consolidation-driver.js";
|
|
23
24
|
import { amendTerminal, terminalProjection } from "./terminal-projection.js";
|
|
24
25
|
import { mintCompactedEvent } from "../auto-compaction.js";
|
|
@@ -293,6 +294,9 @@ export async function runSettleAndTeardown(input) {
|
|
|
293
294
|
}
|
|
294
295
|
finally {
|
|
295
296
|
settleOwedUserInput(owedUserInput, !prepared.suspendProgressRef.executedApproved, { taskId: spec.taskId ?? prepared.sessionId, sessionId: prepared.sessionId, runId: prepared.runId }, runner.deps.onNotice);
|
|
297
|
+
const writeDateAnchor = owedDateAnchor(prepared.session, prepared.dateChange, rs.attach.dateState);
|
|
298
|
+
if (writeDateAnchor !== undefined)
|
|
299
|
+
await settleTeardownLeg(writeDateAnchor, "date anchor (settle leg)", (e) => runner.deps.onError?.(e, { phase: "degraded", sessionId: prepared.sessionId }));
|
|
296
300
|
const ownedEnvDying = prepared.ownedEnv !== undefined &&
|
|
297
301
|
hasDestroy(prepared.ownedEnv) &&
|
|
298
302
|
isIsolated(prepared.ownedEnv) &&
|
|
@@ -211,7 +211,7 @@ export function createTurnBoundary(input) {
|
|
|
211
211
|
}
|
|
212
212
|
let boundaryAttachmentBytes = 0;
|
|
213
213
|
let attachmentsPayload;
|
|
214
|
-
const
|
|
214
|
+
const receiptCommits = [];
|
|
215
215
|
if ((rs.attach.dateState !== undefined ||
|
|
216
216
|
rs.attach.instrState !== undefined ||
|
|
217
217
|
rs.attach.sizeGuidelineState !== undefined ||
|
|
@@ -382,7 +382,7 @@ export function createTurnBoundary(input) {
|
|
|
382
382
|
if (agentListingDue && due.some((a) => a.source === "agent_listing")) {
|
|
383
383
|
const listing = prepared.agentListing;
|
|
384
384
|
const frame = renderAgentListingFrame(attachState, listing.entries, listing.toolName, listing.models, listing.budget);
|
|
385
|
-
|
|
385
|
+
receiptCommits.push({
|
|
386
386
|
source: "agent_listing",
|
|
387
387
|
commit: () => {
|
|
388
388
|
commitAgentListing(attachState, listing.entries, listing.models);
|
|
@@ -397,7 +397,7 @@ export function createTurnBoundary(input) {
|
|
|
397
397
|
if (skillsListingDue && due.some((a) => a.source === "skills_listing")) {
|
|
398
398
|
const listing = prepared.skillsListing;
|
|
399
399
|
const frame = renderSkillsListingFrame(attachState, listing.entries, listing.budget);
|
|
400
|
-
|
|
400
|
+
receiptCommits.push({
|
|
401
401
|
source: "skills_listing",
|
|
402
402
|
commit: () => {
|
|
403
403
|
commitSkillsListing(attachState, listing.entries);
|
|
@@ -410,12 +410,12 @@ export function createTurnBoundary(input) {
|
|
|
410
410
|
if (announcedOnceDirty)
|
|
411
411
|
prepared.frameReceipts.listingSnapshotOwed = true;
|
|
412
412
|
}
|
|
413
|
-
if (rs.attach.dateState !== undefined && rs.turn.lastTurnHadToolCalls) {
|
|
413
|
+
if (rs.attach.dateState !== undefined && rs.turn.lastTurnHadToolCalls && !prepared.frameReceipts.pending.some((r) => r.source === "date_change")) {
|
|
414
414
|
const today = prepared.dateChange.today();
|
|
415
415
|
const cand = collectDateChange(rs.attach.dateState, today);
|
|
416
416
|
if (cand !== undefined) {
|
|
417
417
|
due.unshift(cand);
|
|
418
|
-
rs.attach.dateState.announcedDate = today;
|
|
418
|
+
receiptCommits.push({ source: "date_change", commit: () => void (rs.attach.dateState.announcedDate = today) });
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
if (rs.attach.sizeGuidelineState !== undefined && rs.turn.lastTurnHadToolCalls) {
|
|
@@ -496,7 +496,7 @@ export function createTurnBoundary(input) {
|
|
|
496
496
|
}
|
|
497
497
|
if ((attachmentsPayload !== undefined || batchContextBlock !== undefined) && prepared.batchHaltRef.current === undefined) {
|
|
498
498
|
const payload = attachmentsPayload !== undefined && batchContextBlock !== undefined ? `${attachmentsPayload}\n${batchContextBlock}` : (attachmentsPayload ?? batchContextBlock);
|
|
499
|
-
for (const c of
|
|
499
|
+
for (const c of receiptCommits)
|
|
500
500
|
prepared.frameReceipts.pending.push({ source: c.source, text: payload, commit: c.commit });
|
|
501
501
|
void prepared.harness.steer(payload, { engineMinted: true }).catch(() => {
|
|
502
502
|
prepared.frameReceipts.pending = prepared.frameReceipts.pending.filter((r) => r.text !== payload);
|
|
@@ -309,10 +309,10 @@ export interface AttachmentState {
|
|
|
309
309
|
* A1-R — the date_change lane's OWN state, deliberately NOT an
|
|
310
310
|
* {@link AttachmentState} member: allocating that for a date-only run would activate the cadence
|
|
311
311
|
* content scan + projection reducers on every non-opted run (the reopen's exact finding). Two
|
|
312
|
-
* fields, zero reducers. `announcedDate` starts at the
|
|
313
|
-
* commits it (the producer below is pure)
|
|
314
|
-
* fixed ~140-byte item, so no clipping face exists
|
|
315
|
-
*
|
|
312
|
+
* fields, zero reducers. `announcedDate` starts at the session anchor's announced date; the RUN LOOP
|
|
313
|
+
* commits it (the producer below is pure) on the carrying message's receipt — the date block rides ABOVE
|
|
314
|
+
* the 8KB bundle cap as a fixed ~140-byte item, so no clipping face exists (contrast tools_delta's
|
|
315
|
+
* drain-on-intact, which lives inside the capped bundle).
|
|
316
316
|
*/
|
|
317
317
|
export interface DateChangeState {
|
|
318
318
|
announcedDate: string;
|
|
@@ -663,11 +663,11 @@ export declare function renderToolSearchUsageReminder(undiscovered: readonly str
|
|
|
663
663
|
export declare function renderDateChange(newDate: string): string;
|
|
664
664
|
/**
|
|
665
665
|
* A1-R — the date_change producer (CC attachments.ts:1400-1443 parity): the system-prefix
|
|
666
|
-
* date is FROZEN for the
|
|
666
|
+
* date is FROZEN for the session segment (upstream: "cached for the duration of the conversation" — re-rendering
|
|
667
667
|
* the prefix at midnight costs ~920K effective tokens per overnight session, upstream's own comment);
|
|
668
668
|
* when the boundary-time LOCAL date walks away from the last announced one, the model is told at the
|
|
669
669
|
* TAIL instead. String INEQUALITY (backward NTP jumps announce too). PURE — the caller commits
|
|
670
|
-
* `state.announcedDate = today` when
|
|
670
|
+
* `state.announcedDate = today` when the carrying message's receipt settles (see {@link DateChangeState}).
|
|
671
671
|
*/
|
|
672
672
|
export declare function collectDateChange(state: DateChangeState, today: string): TurnAttachment | undefined;
|
|
673
673
|
/**
|
|
@@ -520,7 +520,7 @@ export interface RunnerDeps {
|
|
|
520
520
|
/**
|
|
521
521
|
* design/381 — the per-edited-file rewind history backend (CC FileHistory topology; replaces the
|
|
522
522
|
* E19 whole-tree `fileSnapshotStore`). WIRING IS THE OPT-IN (DV-9, the reference's own SDK
|
|
523
|
-
* posture): with a store present, every Edit/Write/NotebookEdit first-touch is backed up before
|
|
523
|
+
* posture): with a store present (and {@link fileHistoryCapture} not `"off"`), every Edit/Write/NotebookEdit first-touch is backed up before
|
|
524
524
|
* the byte changes, every turn mints a history boundary keyed by its own initial session entry
|
|
525
525
|
* ("file state when this turn began"), and a {@link TaskSpec.resumeAt}+{@link TaskSpec.restoreFiles}
|
|
526
526
|
* (or {@link TaskSpec.rewindFilesTo}) run converges the tracked set back to a boundary. Omitted ⇒
|
|
@@ -534,6 +534,8 @@ export interface RunnerDeps {
|
|
|
534
534
|
* key earns on a filesystem-capable run (`classification: "file-history-no-store"`).
|
|
535
535
|
*/
|
|
536
536
|
fileHistoryStore?: import("./file-history-store.js").FileHistoryStore | "disabled";
|
|
537
|
+
/** The deployment's CAPTURE switch, apart from the store seat: `"off"` (the only word, and only beside a wired store; anything else refuses prepare, `config.invalid_file_history_capture`) ⇒ no run records — no first-touch record, no turn boundary, no fork carry, no liveness advisory, manifest `fileHistory: "disabled"` — while a wired {@link fileHistoryStore} still serves {@link TaskSpec.restoreFiles} / {@link TaskSpec.rewindFilesTo} from what it already holds. */
|
|
538
|
+
fileHistoryCapture?: "off";
|
|
537
539
|
/**
|
|
538
540
|
* design/381 DV-14 (终审落锤) — what an Edit/Write/NotebookEdit does when its FIRST-TOUCH history
|
|
539
541
|
* record cannot be persisted (`FileHistoryStore.trackEdit` answered `{ok:false}` = NO durable
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
* per-adapter concern (each exec env owns how it composes its child env); only the secret PATTERN is shared.
|
|
18
18
|
*/
|
|
19
19
|
import type { RedactionConfidence, RedactionSource } from "./arg-summary.js";
|
|
20
|
+
import { type EngineNotice } from "./engine-notice.js";
|
|
20
21
|
/** Which rule classified a key as secret-shaped — the env arm's `kind` vocabulary. */
|
|
21
|
-
export type SecretEnvFindingKind = "suffix-rule" | "exact-name";
|
|
22
|
+
export type SecretEnvFindingKind = "suffix-rule" | "namespace-rule" | "exact-name";
|
|
22
23
|
/** One env entry the `scrub` policy dropped: the key (the VALUE is never carried — this record is meant
|
|
23
24
|
* to be loggable), the rule that classified it, how strong that claim is, and the minting module. */
|
|
24
25
|
export interface SecretEnvFinding {
|
|
@@ -42,3 +43,13 @@ export declare function isSecretEnvKey(key: string): boolean;
|
|
|
42
43
|
* dropped and why, read it back after the call. Omitting it leaves this function byte-for-byte what it
|
|
43
44
|
* was before the channel existed. */
|
|
44
45
|
export declare function scrubSecretEnv(env: NodeJS.ProcessEnv, findings?: SecretEnvFinding[]): NodeJS.ProcessEnv;
|
|
46
|
+
/** Test seam: never called by production code. */
|
|
47
|
+
export declare function __resetSecretEnvScrubNoticeAnnouncement(): void;
|
|
48
|
+
/**
|
|
49
|
+
* The ONE disclosure point for a scrub's withheld keys. Routed through {@link deliverEngineNotice} — the
|
|
50
|
+
* engine's one notice throat — so a wired `onNotice` seat REPLACES the console line exactly as every
|
|
51
|
+
* other `EngineNotice` does, and an absent seat prints the same words `console.warn` always printed here.
|
|
52
|
+
* `detail.names` carries every withheld key. Once per PROCESS, never per call or per site; an EMPTY
|
|
53
|
+
* findings array is a no-op.
|
|
54
|
+
*/
|
|
55
|
+
export declare function announceSecretEnvScrub(onNotice: ((notice: EngineNotice) => void) | undefined, findings: readonly SecretEnvFinding[]): void;
|
package/dist/core/secret-env.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { deliverEngineNotice } from "./engine-notice.js";
|
|
1
2
|
const TOKEN_COUNT_WORDS = ["MAX", "OUTPUT", "INPUT", "THINKING", "NUM", "TOTAL"];
|
|
2
|
-
const
|
|
3
|
+
const CREDENTIAL_WORD = `KEY|KEYS|TOKEN|(?<!(?:^|_)(?:${TOKEN_COUNT_WORDS.join("|")})_)TOKENS|SECRET|SECRETS|PASSWORD|PASSWORDS|PASSWD|CREDENTIAL|CREDENTIALS|PRIVATEKEY|APIKEY`;
|
|
4
|
+
const SECRET_ENV_RE = new RegExp(`(^|_)(${CREDENTIAL_WORD})(?:_(?:\\d+|ID))?$`, "i");
|
|
5
|
+
const SEMA_NAMESPACE_SECRET_RE = new RegExp(`^SEMA_(?:.*_)?(?:${CREDENTIAL_WORD})(?:_|$)`, "is");
|
|
3
6
|
const SECRET_ENV_EXACT_NAMES = new Set([
|
|
4
7
|
"DATABASE_URL", "CONNECTION_STRING", "DSN", "NPM_AUTH",
|
|
5
8
|
"PGPASSWORD", "MYSQL_PWD", "SSHPASS", "GPG_PASSPHRASE", "GH_PAT", "GITHUB_PAT",
|
|
@@ -7,10 +10,15 @@ const SECRET_ENV_EXACT_NAMES = new Set([
|
|
|
7
10
|
]);
|
|
8
11
|
const NON_SECRET_ENV_EXACT_NAMES = new Set([
|
|
9
12
|
"PARTITION_KEY", "SORT_KEY", "RANGE_KEY", "IDEMPOTENCY_KEY", "CACHE_KEY", "ROUTING_KEY",
|
|
13
|
+
"DB_FOREIGN_KEYS", "JSON_SORT_KEYS",
|
|
14
|
+
"MAX_NEW_TOKENS", "MAX_COMPLETION_TOKENS", "AIDER_MAP_TOKENS", "AIDER_MAX_CHAT_HISTORY_TOKENS",
|
|
15
|
+
"MAX_BATCH_PREFILL_TOKENS", "MAX_WAITING_TOKENS", "MAX_TOP_N_TOKENS", "RATE_LIMIT_TOKENS",
|
|
16
|
+
"PROMPT_TOKENS", "CONTEXT_TOKENS",
|
|
10
17
|
]);
|
|
11
18
|
const SECRET_ENV_KIND_CONFIDENCE = {
|
|
12
19
|
"exact-name": "high",
|
|
13
20
|
"suffix-rule": "medium",
|
|
21
|
+
"namespace-rule": "medium",
|
|
14
22
|
};
|
|
15
23
|
export function classifyExactEnvName(key, credentialNames, exemptNames) {
|
|
16
24
|
const upper = key.toUpperCase();
|
|
@@ -26,7 +34,9 @@ function classifySecretEnvKey(key) {
|
|
|
26
34
|
return "exact-name";
|
|
27
35
|
if (byExactName === "exempt")
|
|
28
36
|
return undefined;
|
|
29
|
-
|
|
37
|
+
if (SECRET_ENV_RE.test(key))
|
|
38
|
+
return "suffix-rule";
|
|
39
|
+
return SEMA_NAMESPACE_SECRET_RE.test(key) ? "namespace-rule" : undefined;
|
|
30
40
|
}
|
|
31
41
|
export function isSecretEnvKey(key) {
|
|
32
42
|
return classifySecretEnvKey(key) !== undefined;
|
|
@@ -45,3 +55,18 @@ export function scrubSecretEnv(env, findings) {
|
|
|
45
55
|
}
|
|
46
56
|
return out;
|
|
47
57
|
}
|
|
58
|
+
let secretEnvScrubNoticeAnnounced = false;
|
|
59
|
+
export function __resetSecretEnvScrubNoticeAnnouncement() {
|
|
60
|
+
secretEnvScrubNoticeAnnounced = false;
|
|
61
|
+
}
|
|
62
|
+
export function announceSecretEnvScrub(onNotice, findings) {
|
|
63
|
+
if (findings.length === 0 || secretEnvScrubNoticeAnnounced)
|
|
64
|
+
return;
|
|
65
|
+
secretEnvScrubNoticeAnnounced = true;
|
|
66
|
+
const names = findings.map((f) => f.key);
|
|
67
|
+
deliverEngineNotice(onNotice, {
|
|
68
|
+
code: "config.secret_env_scrubbed",
|
|
69
|
+
message: `secret_env_scrubbed: ${findings.length} env key(s) withheld from a spawned child's environment (${names.join(", ")}) — once per process; wire onNotice for the structured form`,
|
|
70
|
+
detail: { names },
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -50,6 +50,7 @@ export declare const EXPECTED_LISTBYSCOPE_SUMMARIES: ({
|
|
|
50
50
|
toolCallId: string;
|
|
51
51
|
toolName: string;
|
|
52
52
|
toolInput: string;
|
|
53
|
+
mandated: boolean;
|
|
53
54
|
origin: string;
|
|
54
55
|
spentMicroUsd?: undefined;
|
|
55
56
|
} | {
|
|
@@ -66,5 +67,6 @@ export declare const EXPECTED_LISTBYSCOPE_SUMMARIES: ({
|
|
|
66
67
|
toolCallId?: undefined;
|
|
67
68
|
toolName?: undefined;
|
|
68
69
|
toolInput?: undefined;
|
|
70
|
+
mandated?: undefined;
|
|
69
71
|
origin?: undefined;
|
|
70
72
|
})[];
|
|
@@ -343,6 +343,26 @@ export async function checkpointStoreContract(make, runAssertion) {
|
|
|
343
343
|
assert.equal("previewWithheld" in byId.get("pw-absent"), false, "absent must project the key OMITTED, not null/empty");
|
|
344
344
|
assert.equal("previewWithheld" in byId.get("pw-bogus"), false, "an out-of-contract spelling must read as absent, never project verbatim");
|
|
345
345
|
});
|
|
346
|
+
run("#1079 mandated presence bit: a row's `true` survives + projects; absent stays absent; an out-of-contract `false` or string reads as absent", async () => {
|
|
347
|
+
const store = make();
|
|
348
|
+
const asserted = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "md-true" });
|
|
349
|
+
asserted.pendingAction.mandated = true;
|
|
350
|
+
const absent = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "md-absent" });
|
|
351
|
+
const falsed = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "md-false" });
|
|
352
|
+
falsed.pendingAction.mandated = false;
|
|
353
|
+
const stringed = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "md-string" });
|
|
354
|
+
stringed.pendingAction.mandated = "yes";
|
|
355
|
+
for (const cp of [asserted, absent, falsed, stringed])
|
|
356
|
+
await store.put(cp.token, cp);
|
|
357
|
+
const back = (await store.get(asserted.token)).pendingAction;
|
|
358
|
+
assert.equal(back.mandated, true, "the row's mandated bit must survive the round-trip verbatim");
|
|
359
|
+
assert.equal("mandated" in (await store.get(absent.token)).pendingAction, false, "an absent bit must stay OMITTED on the row");
|
|
360
|
+
const byId = new Map((await store.listByScope("tenant-a")).map((s) => [s.sessionId, s]));
|
|
361
|
+
assert.equal(byId.get("md-true")?.mandated, true);
|
|
362
|
+
assert.equal("mandated" in byId.get("md-absent"), false, "absent must project the key OMITTED, not null/false");
|
|
363
|
+
assert.equal("mandated" in byId.get("md-false"), false, "a written false is out-of-contract and must read as absent, never project");
|
|
364
|
+
assert.equal("mandated" in byId.get("md-string"), false, "a non-boolean spelling must read as absent, never project verbatim");
|
|
365
|
+
});
|
|
346
366
|
await settle();
|
|
347
367
|
}
|
|
348
368
|
const sortByToken = (a, b) => a.token.localeCompare(b.token);
|
|
@@ -367,6 +387,7 @@ export async function checkpointListByScopeSummaries(store) {
|
|
|
367
387
|
pendingAction: {
|
|
368
388
|
kind: "tool_approval",
|
|
369
389
|
origin: "policy",
|
|
390
|
+
mandated: true,
|
|
370
391
|
toolCallId: "call-pr",
|
|
371
392
|
toolName: "open_pr",
|
|
372
393
|
args: { repo: "x" },
|
|
@@ -406,6 +427,7 @@ export const EXPECTED_LISTBYSCOPE_SUMMARIES = [
|
|
|
406
427
|
toolCallId: "call-pr",
|
|
407
428
|
toolName: "open_pr",
|
|
408
429
|
toolInput: '{"repo":"x"}',
|
|
430
|
+
mandated: true,
|
|
409
431
|
origin: "policy",
|
|
410
432
|
},
|
|
411
433
|
{
|
|
@@ -402,7 +402,7 @@ export interface TaskResult {
|
|
|
402
402
|
* ignores the field is unchanged. A rewind that could NOT be delivered as asked is NOT a note — it is a
|
|
403
403
|
* terminal failure (`rewind_snapshot.unresolvable` / `rewind.store_unconfigured` /
|
|
404
404
|
* `rewind.restore_failed` / `rewind.invalid_spec` / `rewind.rewind_files_retired` /
|
|
405
|
-
* `rewind.conflicting_targets` / `rewind.child_scope_unsupported`).
|
|
405
|
+
* `rewind.conflicting_targets` / `rewind.child_scope_unsupported` / `rewind.capture_disabled`).
|
|
406
406
|
*
|
|
407
407
|
* - `conversation_only` — {@link TaskSpec.resumeAt} branched the transcript WITHOUT
|
|
408
408
|
* {@link TaskSpec.restoreFiles}, so the working tree was deliberately left where it was (CC's
|