@sema-agent/core 7.42.1 → 7.44.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 +173 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/agents/subagent.js +5 -3
- package/dist/agents/teacher.js +1 -1
- package/dist/agents/verify.js +2 -0
- package/dist/brain/errors.d.ts +23 -2
- package/dist/brain/errors.js +26 -2
- package/dist/brain/stream-engine.d.ts +2 -1
- package/dist/brain/stream-engine.js +10 -9
- package/dist/core/allow-entry.d.ts +50 -31
- package/dist/core/allow-entry.js +100 -37
- package/dist/core/ask-origin.d.ts +16 -5
- package/dist/core/ask-origin.js +11 -3
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/ask-unresolvable-notice.js +1 -1
- package/dist/core/auto-mode.d.ts +5 -4
- package/dist/core/auto-mode.js +3 -1
- package/dist/core/checkpoint-store.d.ts +44 -20
- package/dist/core/checkpoint-store.js +10 -16
- package/dist/core/child-clamp-seats.d.ts +15 -1
- package/dist/core/child-clamp-seats.js +6 -2
- package/dist/core/classifier-unavailable-arm.d.ts +42 -23
- package/dist/core/classifier-unavailable-arm.js +14 -3
- package/dist/core/decision-receipt.js +2 -0
- package/dist/core/engine-notice.d.ts +16 -14
- package/dist/core/engine-notice.js +4 -3
- package/dist/core/gate-lanes.js +37 -29
- package/dist/core/governance-codes.d.ts +4 -3
- package/dist/core/governance-codes.js +1 -0
- package/dist/core/hooks.d.ts +6 -1
- package/dist/core/hooks.js +3 -0
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/memory-engine/engine.js +7 -14
- package/dist/core/memory-engine/file-backend.d.ts +2 -2
- package/dist/core/memory-engine/file-backend.js +5 -7
- package/dist/core/memory-engine/layout.d.ts +37 -4
- package/dist/core/memory-engine/layout.js +34 -5
- package/dist/core/mode-policy.d.ts +5 -4
- package/dist/core/mode-policy.js +4 -0
- package/dist/core/permission-rule-consent.d.ts +3 -2
- package/dist/core/permission-rule-consent.js +25 -20
- package/dist/core/permission-rule-model.d.ts +47 -7
- package/dist/core/permission-rule-model.js +80 -6
- package/dist/core/permission-rules.d.ts +8 -2
- package/dist/core/permission-rules.js +26 -9
- package/dist/core/runner/classifier-ladder.d.ts +10 -8
- package/dist/core/runner/classifier-ladder.js +3 -1
- package/dist/core/runner/contracts.d.ts +1 -16
- package/dist/core/runner/denial-limit-arms.d.ts +25 -8
- package/dist/core/runner/denial-limit-arms.js +24 -10
- package/dist/core/runner/gate-exit.js +2 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +2 -2
- package/dist/core/runner/permission-rule-lanes.js +8 -2
- package/dist/core/runner/prepare-ask-lane.d.ts +3 -0
- package/dist/core/runner/prepare-ask-lane.js +2 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -2
- package/dist/core/runner/prepare-config-doors.d.ts +3 -0
- package/dist/core/runner/prepare-config-doors.js +6 -5
- package/dist/core/runner/prepare-gate-stations.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -5
- package/dist/core/runner/prepare-inherited-gate.js +5 -3
- package/dist/core/runner/prepare-park-ask.d.ts +4 -4
- package/dist/core/runner/prepare-park-ask.js +2 -4
- package/dist/core/runner/prepare-policy-chain.d.ts +7 -1
- package/dist/core/runner/prepare-policy-chain.js +59 -38
- package/dist/core/runner/prepare-project-context.js +6 -2
- package/dist/core/runner/prepare-task.js +6 -6
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -5
- package/dist/core/runner/prepare-wiring-manifest.js +8 -9
- package/dist/core/runner/resume-checkpoint-screen.js +1 -1
- package/dist/core/runner/runtask.js +1 -5
- package/dist/core/runner/steer-admission.d.ts +10 -11
- package/dist/core/runner/steer-admission.js +6 -8
- package/dist/core/runner/stream-steer-verb.d.ts +5 -4
- package/dist/core/runner/stream-steer-verb.js +6 -8
- package/dist/core/runner/synthetic-tools.d.ts +3 -2
- package/dist/core/runner/synthetic-tools.js +1 -1
- package/dist/core/session-policy-store.d.ts +3 -3
- package/dist/core/session-policy-store.js +18 -4
- package/dist/core/skill-grant-binding.d.ts +44 -0
- package/dist/core/skill-grant-binding.js +22 -0
- package/dist/core/skill-grant.d.ts +59 -28
- package/dist/core/skill-grant.js +96 -23
- package/dist/core/steer-replay.d.ts +46 -0
- package/dist/core/steer-replay.js +22 -0
- package/dist/core/task-event.d.ts +3 -2
- package/dist/core/task-spec.d.ts +14 -1
- package/dist/core/task-stream.d.ts +12 -6
- package/dist/core/tighten-task-spec.d.ts +2 -0
- package/dist/core/tighten-task-spec.js +3 -0
- package/dist/core/tool-errors.d.ts +2 -2
- package/dist/core/tool-name-aliases.d.ts +35 -5
- package/dist/core/tool-name-aliases.js +29 -4
- package/dist/core/tool-policy.d.ts +10 -0
- package/dist/core/tool-policy.js +9 -2
- package/dist/core/tool-spec.d.ts +7 -0
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/wiring-manifest.d.ts +56 -14
- package/dist/core/wiring-manifest.js +29 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -4
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +3 -1
- package/dist/orchestration/workflow-primitives.js +6 -6
- package/dist/orchestration/workflow-types.d.ts +5 -0
- package/dist/orchestration/workflow.d.ts +3 -2
- package/dist/orchestration/workflow.js +14 -6
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +21 -5
- package/wire-changes/core@7.43.0.json +985 -0
- package/wire-changes/core@7.44.0.json +469 -0
|
@@ -11,6 +11,7 @@ import { deliverEngineNotice } from "../engine-notice.js";
|
|
|
11
11
|
import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
12
12
|
import { skillLoadReading } from "./skill-base-dir.js";
|
|
13
13
|
import { RosterBuilder } from "../tool-roster.js";
|
|
14
|
+
import { mountedToolNames } from "../tool-name-aliases.js";
|
|
14
15
|
import { asThrownError } from "../thrown-value.js";
|
|
15
16
|
export async function prepareProjectContext(input) {
|
|
16
17
|
const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillGrants, allowedTools, allowedToolTables, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume, skillListingBudget } = input;
|
|
@@ -88,7 +89,10 @@ export async function prepareProjectContext(input) {
|
|
|
88
89
|
const frozenSkillGrants = readFrozenSkillGrants(resume?.seed.skillGrants);
|
|
89
90
|
if (frozenSkillGrants === undefined)
|
|
90
91
|
throw new Error("the resumed checkpoint's skill-grant section does not read as grant rows — refusing to seed the run without the refusals it carries (the resume screen refuses this row before the claim)");
|
|
91
|
-
const
|
|
92
|
+
const mounted = () => mountedToolNames(tools);
|
|
93
|
+
skillGrants.bindMountedNames(mounted);
|
|
94
|
+
skillGrants.bindSkills(skillSpecs, SKILL_TOOL_NAME);
|
|
95
|
+
const inert = seedAllowEntryTables(allowedToolTables, { skillInert: seedSkillGrants(skillGrants, { skills: skillSpecs, userInvokedSkills: spec.userInvokedSkills, inherited: [...(internals?.inheritedSkillGrants ?? []), ...frozenSkillGrants] }), inherited: internals?.inheritedAllowedTools, request: allowedTools, deployment: deps.allowedTools }, mounted());
|
|
92
96
|
if (inert.length > 0)
|
|
93
97
|
deliverEngineNotice(deps.onNotice, allowedToolsNotGrantedNotice(inert, sessionId));
|
|
94
98
|
if (skillSpecs.length > 0) {
|
|
@@ -99,7 +103,7 @@ export async function prepareProjectContext(input) {
|
|
|
99
103
|
}
|
|
100
104
|
roster.mount(createSkillTool(skillSpecs, skillGrants), { source: "builtin", mountedBy: "optional" });
|
|
101
105
|
}
|
|
102
|
-
const skillSeatOf = skillSeatReader(skillSpecs);
|
|
106
|
+
const skillSeatOf = skillSeatReader(skillSpecs, mounted);
|
|
103
107
|
const sharedMemoryProvider = deps.sharedMemoryStores;
|
|
104
108
|
let sharedMemoryPairMounted = false;
|
|
105
109
|
if (sharedMemoryProvider !== undefined) {
|
|
@@ -407,7 +407,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
407
407
|
let readDenyAdditionsNormalized = [];
|
|
408
408
|
let handsLessResolvedFace;
|
|
409
409
|
let handsLessResolvedWriteFace;
|
|
410
|
-
const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, skillGrantCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
|
|
410
|
+
const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, permissionMode, commitModeSeats, endModeCeiling, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, ancestorSessionRulesRef, ancestorRulesNow, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, writeFaceCheckpointSection, skillGrantCheckpointSection, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, carrierWriteFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, askSeat: doors.askSeat, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, mountsCallerTool, promptProfile, resolvedInteractionPosture, permissionModeSeat, handsEnabled, reportUsage, harnessRef, skillGrants, requestAllowedTools: allowedToolTables.request, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDeciderRef.current, autoModeDenialTracking: () => autoModeDenialTrackingRef.current, autoModeArming: () => autoModeArmingRef.current, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, resolvedWriteFace: () => resolvedWriteFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, handsLessResolvedWriteFace: () => handsLessResolvedWriteFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
|
|
411
411
|
bindPermissionModeSeat(permissionMode);
|
|
412
412
|
const announceRuleStoreSkipped = ruleStoreUnreadableNotice(deps.onNotice, { sessionId, runId });
|
|
413
413
|
const persistedPathRowsRead = persistedPathRowsOfTask({ deps, principal: spec.principal, sessionId, root: taskRootFinal, home: executionEnv.homeDir, taskId: hostTaskId, handsEnabled, signals: [abortController.signal, ...(spec.signal !== undefined ? [spec.signal] : [])], onUnread: announceRuleStoreSkipped });
|
|
@@ -415,7 +415,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
415
415
|
const effectivePathDenyRules = [...toolPolicyPathDenyRules([lockedPreflight.toolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]), ...persistedPathRows.denyRows];
|
|
416
416
|
const writeProtectionJudgeRef = {};
|
|
417
417
|
const writeGuards = { protection: () => writeProtectionJudgeRef.current, target: toolPolicyWriteTargetGuard([lockedPreflight.toolPolicy, ...(inheritedParentConstraints ?? []).map((c) => c.policy)]) };
|
|
418
|
-
const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDeciderRef, autoModeDenialTrackingRef, autoModeArmingRef, armAutoMode, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef,
|
|
418
|
+
const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDeciderRef, autoModeDenialTrackingRef, autoModeArmingRef, armAutoMode, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, askSeat: doors.askSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, parentSpecSeat, carrierReadFace, carrierWriteFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, permissionMode, readDenyEntries: () => ({ entries: readDenyMatcher?.entries ?? [], ruleRows: effectivePathDenyRules }), peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
|
|
419
419
|
const tools = roster.tools;
|
|
420
420
|
const pausedRef = {};
|
|
421
421
|
const undeliveredContinuationRef = { current: { parkedSteers: [], orphanTasks: [] } };
|
|
@@ -733,8 +733,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
733
733
|
releaseSignal = () => sig.removeEventListener("abort", onExternalAbort);
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
|
-
const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider: () => autoModeDeciderRef.current, permissionMode, scratchpadDir: spec.envFacts?.scratchpadDir, toolRosterDeltas: rosterSeat, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
|
|
737
|
-
const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtection, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: handsReadFace.shellReadStationArmed, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef,
|
|
736
|
+
const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, announceRuleStoreSkipped, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider: () => autoModeDeciderRef.current, permissionMode, scratchpadDir: spec.envFacts?.scratchpadDir, toolRosterDeltas: rosterSeat, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
|
|
737
|
+
const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, writeProtection, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace, sessionBoxBound } = prepareWiringManifest({ spec, deps, askSeat: doors.askSeat, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, taskRootFinal, mcp, irreversibleTools, egressTools, shellReadStationArmed: handsReadFace.shellReadStationArmed, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, harness, pausedRef, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive: handsReadFace.readDenyBuiltinTiersActive, lspManagerWired, lspDiagnosticsLive: lspDiagnostics !== undefined, fileHistoryFact, sessionBox });
|
|
738
738
|
const writeProtectionCheck = writeProtection?.check;
|
|
739
739
|
writeProtectionJudgeRef.current = writeProtection?.judgeTarget;
|
|
740
740
|
if (fileHistoryBoundary !== undefined) {
|
|
@@ -743,10 +743,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
743
743
|
return undefined;
|
|
744
744
|
});
|
|
745
745
|
}
|
|
746
|
-
const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
|
|
746
|
+
const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, advertisedWritableDirs, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, grantBindingOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking: autoModeDenialTrackingRef, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash, grantReadRoot: handsReadFace.grantReadRoot });
|
|
747
747
|
const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, writeFaceCheckpointSection, skillGrantCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, undeliveredContinuationRef, inheritedParentConstraints, seedInheritedGate, ancestorRulesNow, inheritedShellGate, permissionMode, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
|
|
748
748
|
const { suspendForResource, suspendForPlatformLimit, suspendForReview } = prepareBoundaryParks({ saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter });
|
|
749
|
-
const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf,
|
|
749
|
+
const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, advertisedWritableDirs, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedTools, irreversibilityTier, toolMarkSources, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, grantBindingOf, now, humanReviewRef, abortController, harness, pausedRef });
|
|
750
750
|
const seatInputsFor = skillGateWiring({ tools, skillToolName: SKILL_TOOL_NAME, seatOf: skillSeatOf, mode: () => permissionMode.current, lane: skillGrantLane, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.skill_allowed", version: 1, taskId: hostTaskId, ...info, entries: [...info.entries], ts: Date.now() })), allowEntries: { deploymentAllows: { ...allowEntryLanes.deployment, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "deployment", ...info, entries: [...info.entries], ts: Date.now() })) }, requestAllows: { ...allowEntryLanes.request, onAllowed: (info) => emitTrace(deps.tracer, () => ({ kind: "permission.allowed_tools_allowed", version: 1, taskId: hostTaskId, source: "request", ...info, entries: [...info.entries], ts: Date.now() })) } } });
|
|
751
751
|
const { approvedCallScreen } = prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, readDenyInForce: () => ({ tiers: handsReadFace.readDenyBuiltinTiersActive, rows: [...readDenyAdditionsNormalized.map((e) => e.pattern), ...handsReadFaceInput.pathDenyRules.filter((r) => r.faces.includes("read")).map((r) => r.rule)] }), hookEnvFace, writeProtectionCheck, shellReadCheck, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider: autoModeDeciderRef, autoModeDenialTracking: autoModeDenialTrackingRef, askRoute: { ...wiringManifest.ask, effective: askSeatEffective(wiringManifest) }, permissionMode, toolMarkSources, ...(deps.a2a?.isolatePeers === true ? { a2aIsolatePeers: true } : {}), ancestorArbitrations, runId, stopForDenialLimit, permissionRuleLane, seatInputsFor, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash, frameSettlement });
|
|
752
752
|
const postureFrameRef = { report: (err) => deps.onError?.(err, { phase: "degraded", sessionId }) };
|
|
@@ -36,12 +36,12 @@ import { type AutoModeArmFact, type WiringManifest, type WiringManifestMcpEntry
|
|
|
36
36
|
import { type PermissionModeController } from "../mode-policy.js";
|
|
37
37
|
import type { AnnounceOnceSink, Prepared, PrepareResume, RunInternals, UsageGovernance } from "./contracts.js";
|
|
38
38
|
export interface PrepareWiringManifestInput {
|
|
39
|
-
/** borrowed-readonly — the REBOUND spec. Read: `
|
|
39
|
+
/** borrowed-readonly — the REBOUND spec. Read: `onQuestion` (the question seam), `handsReadOnly` / `tools` (the ungated scan),
|
|
40
40
|
* `resourceSuspend` (the task-axis lane), `durableApproval` / `principal` (the synthesis and the notice), `interactiveTools` /
|
|
41
41
|
* `mcp` / `checkpointStore` (manifest cells and the notice's cause), `enablePlanMode` (the gate-machinery predicate's
|
|
42
42
|
* plan-mode term). Never mutated. */
|
|
43
|
-
spec: Pick<TaskSpec, "
|
|
44
|
-
/** borrowed-readonly — the deployment seats, whole: `
|
|
43
|
+
spec: Pick<TaskSpec, "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode" | "hooks" | "peerPresence">;
|
|
44
|
+
/** borrowed-readonly — the deployment seats, whole: `onError` (the warning), `executionEnv`
|
|
45
45
|
* (the hook-env predicate), `checkpointStore` (durable infra), the manifest's dozen wiring facts (`backgroundAgentStore`,
|
|
46
46
|
* `permissionRuleStore`, `permissionRuleSyncWired`, `onBackgroundChildEvent`, `lockedConfig`, `compliancePostureResolver`,
|
|
47
47
|
* `memoryScopeAdmission`, `retentionPolicy`, `onElicit`), `onNotice`, the write-protection judge's compile seats
|
|
@@ -141,8 +141,9 @@ export interface PrepareWiringManifestInput {
|
|
|
141
141
|
harness: AgentHarness;
|
|
142
142
|
/** borrowed-readonly — the durable-suspend holder; the drain's parked predicate reads `token` at run time. Not written here. */
|
|
143
143
|
pausedRef: Prepared["pausedRef"];
|
|
144
|
-
/** borrowed-readonly — the
|
|
145
|
-
|
|
144
|
+
/** borrowed-readonly — the run's approval seat as the config doors froze it: the gate's approver and the notice's facts (its
|
|
145
|
+
* value), the manifest's ask cell (its form and provenance). */
|
|
146
|
+
askSeat: import("../wiring-manifest.js").AskSeat;
|
|
146
147
|
/** borrowed-readonly — the LIVE half of the inherited chain (the notice reads its content mandates). */
|
|
147
148
|
liveInheritedGate: RunInternals["inheritedGate"];
|
|
148
149
|
/** borrowed-readonly — the effective delegation facts (the identity's isDelegatedChild). */
|
|
@@ -11,7 +11,7 @@ import { inlineUntrusted } from "../untrusted-text.js";
|
|
|
11
11
|
import { mountWriteProtection } from "./write-protection-station.js";
|
|
12
12
|
import { autoRunOnRecommendationEffective } from "./memory-consolidation-driver.js";
|
|
13
13
|
import { GLOBAL_USAGE_KEY, usageRetryAfterMs, windowsGovernCost } from "../usage-window-store.js";
|
|
14
|
-
import { LSP_CONTRACT_ID, askSeatEffective, countElicitOptIns, deriveHandsSeam, deriveLspSeam, deriveWiringManifest,
|
|
14
|
+
import { LSP_CONTRACT_ID, askSeatEffective, countElicitOptIns, deriveHandsSeam, deriveLspSeam, deriveWiringManifest, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam, resolveSubagentTranscriptTier } from "../wiring-manifest.js";
|
|
15
15
|
import { modePolicyOf } from "../mode-policy.js";
|
|
16
16
|
import { DEFAULT_IRREVERSIBLE_SCOPE } from "./checkpoint-scope.js";
|
|
17
17
|
export function mcpManifestEntries(entries, statuses) {
|
|
@@ -102,9 +102,9 @@ function announceDurableGateUnavailable(args) {
|
|
|
102
102
|
message: `Durable approval gate mandated but unavailable: ${source === "force_durable_gate" ? "the runtime entitlement forceDurableGate is in force for this principal" : "this task opted into durable approval (durableApproval) with no live approver seat"}, ` +
|
|
103
103
|
`but ${cause === "task_store_disabled" ? 'this task disabled the checkpoint store (checkpointStore: "disabled")' : "this deployment wired no checkpoint store"}, ` +
|
|
104
104
|
`so no interactive ask of this task can be parked for a durable answer. Asks resolve on the live chain instead ` +
|
|
105
|
-
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : args.blanketAllow ? 'a blanket "allow" posture answers ordinary permission asks without judgment (a mandated ask is refused)' : "permission asks are denied fail-closed —
|
|
105
|
+
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : args.blanketAllow ? 'a blanket "allow" posture answers ordinary permission asks without judgment (a mandated ask is refused)' : "permission asks are denied fail-closed — nobody in this run can be asked to approve them"}; ` +
|
|
106
106
|
`${liveQuestionFace ? "a live question face answers AskUserQuestion in-stream" : args.liveQuestionFace ? "AskUserQuestion is withheld from the live face by an inherited durable mandate and refused" : "AskUserQuestion has no live face and is refused"}) ` +
|
|
107
|
-
`and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store" : "Wire a checkpoint store on this deployment"}, or ${source === "force_durable_gate" ? "withdraw the entitlement for principals served here" : "give the task a live approver seat (or drop durableApproval)"}.`,
|
|
107
|
+
`and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store" : "Wire a checkpoint store on this deployment"}, or ${source === "force_durable_gate" ? "withdraw the entitlement for principals served here" : args.declaredNone ? 'run the task where a person can be asked (without approvalReach: "none"), or drop durableApproval' : "give the task a live approver seat (or drop durableApproval)"}.`,
|
|
108
108
|
detail: {
|
|
109
109
|
sessionId: args.sessionId,
|
|
110
110
|
runId: args.runId,
|
|
@@ -117,8 +117,8 @@ function announceDurableGateUnavailable(args) {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
export function prepareWiringManifest(input) {
|
|
120
|
-
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, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef,
|
|
121
|
-
const onAsk =
|
|
120
|
+
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, permissionMode, lockedPreflight, peerLaneRefs, frameSettlement, sessionBox, harness, pausedRef, askSeat, liveInheritedGate, delegation, toolRoster, readDenyBuiltinTiersActive, lspManagerWired, shellReadStationArmed, lspDiagnosticsLive, fileHistoryFact } = input;
|
|
121
|
+
const onAsk = askSeat.value;
|
|
122
122
|
const handWriteTools = toolRoster.entries.filter((e) => e.mountedBy === "hands" && (e.effect === "write" || e.effect === "idempotent")).map((e) => e.name);
|
|
123
123
|
const hasEffectAwareGate = Boolean(policyLayers.length > 0 || (hooks?.preToolUse !== undefined && !preToolUseObservational));
|
|
124
124
|
const peerWriteUngated = modePolicyOf(permissionMode.current).unstated === "ask"
|
|
@@ -181,14 +181,13 @@ export function prepareWiringManifest(input) {
|
|
|
181
181
|
const writeProtection = mountWriteProtection({ deps, env: handsEnabled ? executionEnv : undefined, rootPath: taskRootFinal, roster: toolRoster, sessionId, runId });
|
|
182
182
|
const wiringQuestionSeam = resolveQuestionSeam(spec, deps);
|
|
183
183
|
const wiringQuestionStripped = internals?.questionFaceStripped === true;
|
|
184
|
-
const wiringAskSeam = resolveAskSeamForm(spec, deps);
|
|
185
184
|
const wiringManifest = deriveWiringManifest({
|
|
186
185
|
half: "effective",
|
|
187
186
|
leg: resume !== undefined ? "resume" : internals?.isDelegatedChild === true ? "child" : "root",
|
|
188
187
|
teamRole: teamRoleOf({ isDelegatedChild: delegation.isDelegatedChild, ...(internals?.explicitAgentName !== undefined ? { spawnName: internals.explicitAgentName } : {}) }),
|
|
189
188
|
...(spec.peerPresence !== undefined ? { peerPresence: spec.peerPresence } : {}),
|
|
190
|
-
askForm:
|
|
191
|
-
...(
|
|
189
|
+
askForm: askSeat.form,
|
|
190
|
+
...(askSeat.provenance !== undefined ? { askProvenance: askSeat.provenance } : {}),
|
|
192
191
|
questionWired: wiringQuestionSeam.wired,
|
|
193
192
|
...(wiringQuestionSeam.provenance !== undefined ? { questionProvenance: wiringQuestionSeam.provenance } : {}),
|
|
194
193
|
...(wiringQuestionStripped ? { questionStrippedByEngine: true } : {}),
|
|
@@ -254,7 +253,7 @@ export function prepareWiringManifest(input) {
|
|
|
254
253
|
resourceSuspendEligible ||
|
|
255
254
|
platformSuspendArmed ||
|
|
256
255
|
spec.enablePlanMode === true;
|
|
257
|
-
announceDurableGateUnavailable({ onNotice: deps.onNotice, mandate: durableMandateSourceOf({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined, onAsk
|
|
256
|
+
announceDurableGateUnavailable({ onNotice: deps.onNotice, mandate: durableMandateSourceOf({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined, onAsk }), storeWired: checkpointStore !== undefined, taskStoreDisabled: spec.checkpointStore === "disabled", liveApprover: isLiveApproverSeat(onAsk), blanketAllow: onAsk === "allow", declaredNone: askSeat.reach === "none", liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
258
257
|
const hookIdentity = mintHookInvocationIdentity({
|
|
259
258
|
sessionId,
|
|
260
259
|
taskId: hostTaskId,
|
|
@@ -48,7 +48,7 @@ export function resumeCheckpointScreen(input) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
if (readFrozenSkillGrants(cp.state.skillGrants) === undefined)
|
|
51
|
-
throw new CheckpointError("checkpoint.invalid_outcome", "this checkpoint carries a skill-grant section (state.skillGrants) that does not read as grant rows — refusing to resume without the grant rows and refusals it carries
|
|
51
|
+
throw new CheckpointError("checkpoint.invalid_outcome", "this checkpoint carries a skill-grant section (state.skillGrants) that does not read as grant rows under this engine — a damaged section, or a row an earlier release wrote whose entry this release reads as nothing (an entry with a surrounding space, say) — refusing to resume without the grant rows and refusals it carries; the checkpoint stays pending: finish it on a worker of the release that parked it, or expire it", { reason: "skill_grants_damaged" });
|
|
52
52
|
}
|
|
53
53
|
if (realApprovalOrgFact(preCasGateBit) !== undefined && runner.deps.permissionRuleStore?.partitions.org !== true) {
|
|
54
54
|
throw new CheckpointError("checkpoint.unsupported_version", `this checkpoint's approval was minted under organization governance (org ${String(realApprovalOrgFact(preCasGateBit))}, routed as ${String(preCasGateBit?.origin)}) and this worker has no org adjudication wiring (its permission-rule store carries no org partition) — a governed approval may only be redeemed where governance can be enforced; the checkpoint stays pending, resume it on an org-wired worker`, { reason: "governed_unwired" });
|
|
@@ -40,6 +40,7 @@ import { resumeClaim } from "./resume-claim.js";
|
|
|
40
40
|
import { streamSettleBackstop } from "./stream-settle-backstop.js";
|
|
41
41
|
import { streamReap } from "./stream-reap.js";
|
|
42
42
|
import { streamSteerVerb } from "./stream-steer-verb.js";
|
|
43
|
+
import { steeringError } from "./steer-admission.js";
|
|
43
44
|
import { streamLifecycleVerbs } from "./stream-lifecycle-verbs.js";
|
|
44
45
|
import { streamHaltVerbs } from "./stream-halt-verbs.js";
|
|
45
46
|
import { streamModeVerb } from "./stream-mode-verb.js";
|
|
@@ -411,11 +412,6 @@ export class Runner {
|
|
|
411
412
|
locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry, suspendedEnvReaps: this.suspendedEnvReaps,
|
|
412
413
|
}).onRunRejected);
|
|
413
414
|
void settled.then(() => acceptedSteerInputs.clear(), () => acceptedSteerInputs.clear());
|
|
414
|
-
const steeringError = (msg, code = "steering.not_running") => {
|
|
415
|
-
const e = new Error(`cannot steer: ${msg}`);
|
|
416
|
-
e.code = code;
|
|
417
|
-
return e;
|
|
418
|
-
};
|
|
419
415
|
const { reapSuspended } = streamReap({
|
|
420
416
|
live, runner: this.depsSeat,
|
|
421
417
|
locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry, suspendedEnvReaps: this.suspendedEnvReaps,
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Admission bookkeeping for HUMAN INPUTS accepted mid-run: the per-leg ordinal an
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Admission bookkeeping for HUMAN INPUTS accepted mid-run: the per-leg ordinal an accepted input is stamped
|
|
3
|
+
* with, and the acceptance frame's once-only seat. Two accepting arms share the ordinal — the stream's `steer`
|
|
4
|
+
* verb and the run body — which is why it is keyed on the leg's harness in a module-level WeakMap rather than
|
|
5
|
+
* held by either arm: one counter per leg, one ascending sequence across both. Also the stream verbs' typed
|
|
6
|
+
* refusal. (Whether a repeat under a used `inputId` is the same instruction is steer-replay.ts's one judgement,
|
|
7
|
+
* shared with the parked queue.)
|
|
7
8
|
*
|
|
8
9
|
* Run-loop machinery (layer 1), not a driven lane: nothing here takes an Input or hands back a Result, and
|
|
9
10
|
* nothing here reads host state. Named without the `run-` family prefix for that reason.
|
|
10
11
|
*/
|
|
11
|
-
import type {
|
|
12
|
+
import type { SteerReplayRefusalDetail } from "../steer-replay.js";
|
|
12
13
|
export declare function nextHumanInputSeq(key: object): number;
|
|
13
14
|
/** The identity keys a published `queued` frame carried beyond its own `eventId` (`parentToolCallId`, `sourceTaskId`): one fact, stated
|
|
14
15
|
* once by the frame's publisher and handed to whoever mints that input's other frames, so two frames of one input are never stamped
|
|
@@ -19,8 +20,6 @@ export type AcceptanceIdentity = {
|
|
|
19
20
|
};
|
|
20
21
|
export declare function armAcceptance(record: object, publish: () => AcceptanceIdentity): void;
|
|
21
22
|
export declare function announceAcceptance(record: object): AcceptanceIdentity | undefined;
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
* callers colliding on one id must not silently lose the second instruction. */
|
|
26
|
-
export declare function sameAcceptedSteerInput(a: AcceptedSteerInput, b: AcceptedSteerInput): boolean;
|
|
23
|
+
/** The stream verbs' typed refusal: `cannot steer: <msg>`, `code` (`steering.not_running` by default), and the
|
|
24
|
+
* refusal's `detail` when the code carries one (`steering.duplicate_input_id` always does). */
|
|
25
|
+
export declare function steeringError(msg: string, code?: string, detail?: SteerReplayRefusalDetail): Error;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { steerPriorityOf } from "../task-notification.js";
|
|
2
1
|
const humanInputOrdinals = new WeakMap();
|
|
3
2
|
export function nextHumanInputSeq(key) {
|
|
4
3
|
let box = humanInputOrdinals.get(key);
|
|
@@ -16,11 +15,10 @@ export function armAcceptance(record, publish) {
|
|
|
16
15
|
export function announceAcceptance(record) {
|
|
17
16
|
return acceptanceSeats.get(record)?.();
|
|
18
17
|
}
|
|
19
|
-
export function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
a.actor?.issuer === b.actor?.issuer);
|
|
18
|
+
export function steeringError(msg, code = "steering.not_running", detail) {
|
|
19
|
+
const e = new Error(`cannot steer: ${msg}`);
|
|
20
|
+
e.code = code;
|
|
21
|
+
if (detail !== undefined)
|
|
22
|
+
e.detail = detail;
|
|
23
|
+
return e;
|
|
26
24
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PushQueue } from "../push-queue.js";
|
|
2
2
|
import { type TaskEvent, type TaskSpec, type TaskStream } from "../types.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { LiveHandle, RunInternals, RunnerDepsSeat, TaskStreamLiveSeat } from "./contracts.js";
|
|
4
|
+
import { type SteerReplayRecord, type SteerReplayRefusalDetail } from "../steer-replay.js";
|
|
4
5
|
export interface StreamSteerVerbInput {
|
|
5
6
|
/** borrowed-readonly — the task spec (the hooks seat, `principal`, `taskId`). */
|
|
6
7
|
spec: TaskSpec;
|
|
@@ -9,7 +10,7 @@ export interface StreamSteerVerbInput {
|
|
|
9
10
|
/** borrowed-mutable — the stream's event queue: the `human_input` receipt is pushed here on acceptance. */
|
|
10
11
|
queue: PushQueue<TaskEvent>;
|
|
11
12
|
/** borrowed-mutable — this stream's accepted-input dedup domain (the SAME Map the driver clears when the run settles). */
|
|
12
|
-
acceptedSteerInputs: Map<string,
|
|
13
|
+
acceptedSteerInputs: Map<string, SteerReplayRecord>;
|
|
13
14
|
/** borrowed-readonly — the stream's live state: `resultValue` and `handle`, read at each liveness test. */
|
|
14
15
|
live: TaskStreamLiveSeat;
|
|
15
16
|
/** borrowed-readonly — the readiness promise (settles to the live handle, or `undefined` when the run ended first). */
|
|
@@ -18,8 +19,8 @@ export interface StreamSteerVerbInput {
|
|
|
18
19
|
orTimeout: <T>(p: Promise<T>) => Promise<T | undefined>;
|
|
19
20
|
/** borrowed-readonly — the readiness bound in ms; the birth-window poll's deadline reads it too. */
|
|
20
21
|
readyTimeoutMs: number;
|
|
21
|
-
/** borrowed-readonly — the driver's typed steering refusal (`steering.not_running` by default). */
|
|
22
|
-
steeringError: (msg: string, code?: string) => Error;
|
|
22
|
+
/** borrowed-readonly — the driver's typed steering refusal (`steering.not_running` by default; `detail` rides the error). */
|
|
23
|
+
steeringError: (msg: string, code?: string, detail?: SteerReplayRefusalDetail) => Error;
|
|
23
24
|
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`hooks`, `onError`, `onNotice`, after awaits too). */
|
|
24
25
|
runner: RunnerDepsSeat;
|
|
25
26
|
}
|
|
@@ -6,7 +6,8 @@ import { buildHumanInputEvent, frameMidTurnUserInput, projectHumanInput } from "
|
|
|
6
6
|
import { isSystemInjectionPriority, steerPriorityOf, SYSTEM_INJECTION_PRIORITIES } from "../task-notification.js";
|
|
7
7
|
import { deliverEngineNotice } from "../types.js";
|
|
8
8
|
import { inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
|
|
9
|
-
import { announceAcceptance, armAcceptance, nextHumanInputSeq
|
|
9
|
+
import { announceAcceptance, armAcceptance, nextHumanInputSeq } from "./steer-admission.js";
|
|
10
|
+
import { steerReplayRefusal } from "../steer-replay.js";
|
|
10
11
|
import { asThrownError } from "../thrown-value.js";
|
|
11
12
|
export function streamSteerVerb(input) {
|
|
12
13
|
const { spec, internals, queue, acceptedSteerInputs, live, ready, orTimeout, readyTimeoutMs: READY_TIMEOUT_MS, steeringError, runner } = input;
|
|
@@ -43,7 +44,6 @@ export function streamSteerVerb(input) {
|
|
|
43
44
|
};
|
|
44
45
|
let payload;
|
|
45
46
|
let mintsAFrame;
|
|
46
|
-
let replay;
|
|
47
47
|
const publishQueued = (h) => {
|
|
48
48
|
const identity = internals?.parentToolCallId !== undefined ? { parentToolCallId: internals.parentToolCallId, ...(spec.taskId !== undefined ? { sourceTaskId: spec.taskId } : {}) } : {};
|
|
49
49
|
queue.push({
|
|
@@ -66,7 +66,7 @@ export function streamSteerVerb(input) {
|
|
|
66
66
|
if (!mintsAFrame)
|
|
67
67
|
return;
|
|
68
68
|
if (typeof inputId === "string")
|
|
69
|
-
acceptedSteerInputs.set(inputId,
|
|
69
|
+
acceptedSteerInputs.set(inputId, parkRecord);
|
|
70
70
|
announceAcceptance(parkRecord);
|
|
71
71
|
};
|
|
72
72
|
const deliver = async () => {
|
|
@@ -77,16 +77,14 @@ export function streamSteerVerb(input) {
|
|
|
77
77
|
throw steeringError("the task is not running");
|
|
78
78
|
payload = trusted ? formatHookFeedback(projected, h.reminderMark) : frameMidTurnUserInput(projected);
|
|
79
79
|
mintsAFrame = payload.trim().length !== 0;
|
|
80
|
-
replay = { payload, trusted, priority, ...(actor !== undefined ? { actor } : {}) };
|
|
81
80
|
if (typeof inputId === "string") {
|
|
82
81
|
const prior = acceptedSteerInputs.get(inputId);
|
|
83
82
|
if (prior !== undefined) {
|
|
84
83
|
if (live.resultValue !== undefined || h.loop.ended)
|
|
85
84
|
throw steeringError("the task is no longer running");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
85
|
+
const refusal = steerReplayRefusal(prior, parkRecord, { seat: "accepted" });
|
|
86
|
+
if (refusal !== undefined)
|
|
87
|
+
throw steeringError(refusal.message, "steering.duplicate_input_id", refusal.detail);
|
|
90
88
|
return;
|
|
91
89
|
}
|
|
92
90
|
}
|
|
@@ -169,9 +169,10 @@ export declare function renderSkillLinesWithin(skills: ReadonlyArray<SkillListin
|
|
|
169
169
|
*
|
|
170
170
|
* A SUCCESSFUL activation writes the skill's two lists into the run's grant table (`grants`, origin `model`): its
|
|
171
171
|
* `allowed-tools` then run without asking and its `disallowed-tools` are refused for the rest of the run; an unknown skill
|
|
172
|
-
* throws first and writes nothing
|
|
172
|
+
* throws first and writes nothing, as does one whose `disallowed-tools` holds an entry that reads as nothing (the table
|
|
173
|
+
* refuses it: the body is not served, nothing is granted). Activating a skill that declares a list was itself a question (the gate reads this
|
|
173
174
|
* tool's seat off the call's arguments — `Execute skill: <name>`), so a write here always follows a statement. The tool
|
|
174
175
|
* runs ALONE in its batch: a call after it in the same message is judged after the rows exist.
|
|
175
176
|
*/
|
|
176
|
-
export declare function createSkillTool(skills: SkillLike[], grants
|
|
177
|
+
export declare function createSkillTool(skills: SkillLike[], grants: SkillGrantTable): AgentTool;
|
|
177
178
|
export {};
|
|
@@ -188,7 +188,7 @@ export function createSkillTool(skills, grants) {
|
|
|
188
188
|
`(Only skills registered with this deployment are loadable — other products' skills directories are not read. ` +
|
|
189
189
|
`If the user wants one of those here, read its source file and recreate its content for this deployment instead.)`);
|
|
190
190
|
}
|
|
191
|
-
grants
|
|
191
|
+
grants.activate(skill, "model");
|
|
192
192
|
const baseDir = skill.baseDir;
|
|
193
193
|
let body = baseDir !== undefined ? substituteSkillRoot(skill.content, baseDir) : skill.content;
|
|
194
194
|
if (skill.files !== undefined && skill.files.length > 0) {
|
|
@@ -53,7 +53,7 @@ export interface PutRulesOptions {
|
|
|
53
53
|
operator?: boolean;
|
|
54
54
|
}
|
|
55
55
|
/** The {@link SessionPolicyError.detail} of a tool-name refusal: which bucket, which entry, the judgment's word, and the
|
|
56
|
-
*
|
|
56
|
+
* spelling to write instead when the judgment has one (a retired name's 1:1 successor, an unmintable segment's minted name). */
|
|
57
57
|
export interface SessionRuleNameRefusal {
|
|
58
58
|
field: SessionRuleToolNameField;
|
|
59
59
|
name: string;
|
|
@@ -63,8 +63,8 @@ export interface SessionRuleNameRefusal {
|
|
|
63
63
|
/** Typed error from {@link SessionPolicyStore.putRules}. `conflict` = stale `expectedRev`; `loosen_forbidden`
|
|
64
64
|
* = a non-operator write tried to relax the rules; `corrupt` = a backend could not read the erase-surviving
|
|
65
65
|
* rev mark ({@link SessionPolicyStore.deleteBySession}) and refuses rather than stamp an unproven rev; the fourth
|
|
66
|
-
* code = a tool-name bucket names a retired
|
|
67
|
-
* present on that code and only on it. */
|
|
66
|
+
* code = a tool-name bucket names a retired name, a prefix-less `__` name or a peer segment no mint spells
|
|
67
|
+
* ({@link assertSessionRuleNamesCurrent}) — `detail` is present on that code and only on it. */
|
|
68
68
|
export declare class SessionPolicyError extends Error {
|
|
69
69
|
readonly code: "conflict" | "loosen_forbidden" | "corrupt" | "legacy_tool_name";
|
|
70
70
|
readonly detail?: SessionRuleNameRefusal | undefined;
|
|
@@ -40,10 +40,24 @@ export function assertSessionRuleNamesCurrent(rules, mountedToolNames = NO_DECLA
|
|
|
40
40
|
if (verdict.kind === "current")
|
|
41
41
|
continue;
|
|
42
42
|
const quoted = JSON.stringify(name);
|
|
43
|
-
const successor = verdict.kind === "
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const successor = verdict.kind === "unprefixed_namespace" ? undefined : verdict.currentName;
|
|
44
|
+
let message;
|
|
45
|
+
switch (verdict.kind) {
|
|
46
|
+
case "retired":
|
|
47
|
+
message = `session rules ${field} names ${quoted}, a retired tool name (${verdict.guidance}) — with it in place no run of this session could start, so nothing was written.${successor !== undefined ? ` Use the current name ${JSON.stringify(successor)}.` : ""} If this deployment mounts its own tool under ${quoted}, declare it in the store's mountedToolNames.`;
|
|
48
|
+
break;
|
|
49
|
+
case "unprefixed_namespace":
|
|
50
|
+
message = `session rules ${field} names ${quoted}, which carries the "__" namespace separator but no protocol prefix — no tool is named that way (protocol tools are named ${NAMESPACED_NAME_SHAPES}), and with it in place no run of this session could start, so nothing was written.`;
|
|
51
|
+
break;
|
|
52
|
+
case "unmintable_segment":
|
|
53
|
+
message = `session rules ${field} names ${quoted}, which can match no tool (${verdict.guidance}) — with it in place no run of this session could start, so nothing was written.${successor !== undefined ? ` Write ${JSON.stringify(successor)}.` : ""}`;
|
|
54
|
+
break;
|
|
55
|
+
default: {
|
|
56
|
+
const exhaustive = verdict;
|
|
57
|
+
return exhaustive;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new SessionPolicyError("legacy_tool_name", message, { field, name, verdict: verdict.kind, ...(successor !== undefined ? { currentName: successor } : {}) });
|
|
47
61
|
}
|
|
48
62
|
}
|
|
49
63
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a Skill card's approval is bound to, as ONE value: the skill the call names and the two lists approving it releases,
|
|
3
|
+
* in the rule grammar's canonical spelling (de-duplicated, sorted). Its hash is the `boundGrantDigest` a parked approval is
|
|
4
|
+
* judged by, so a reader holds the list a person approved and the binding that covers it as the same fact — the live
|
|
5
|
+
* `AskRequest`, the parked row and the inbox projection all carry it (minted by `skillGrantBindingMembers`).
|
|
6
|
+
*
|
|
7
|
+
* A leaf on purpose: the checkpoint projection reads it at its boundary and may not import the module that mints it (it imports only
|
|
8
|
+
* the hash).
|
|
9
|
+
*/
|
|
10
|
+
export interface BoundSkillGrants {
|
|
11
|
+
/** The skill's name as the loaded table spells it, or `null` when the call names no loaded skill (it grants nothing). */
|
|
12
|
+
readonly skill: string | null;
|
|
13
|
+
/** The skill's `allowed-tools` entries — what approving the activation lets be used without asking. */
|
|
14
|
+
readonly allowedTools: readonly string[];
|
|
15
|
+
/** The skill's `disallowed-tools` entries — what activating it refuses for the rest of the run. */
|
|
16
|
+
readonly disallowedTools: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A stored value read as a {@link BoundSkillGrants}, whole or not at all: a fresh copy of the three members and nothing else,
|
|
20
|
+
* or `undefined` when any member is not of its type. Every member is read ONCE, so the value screened is the value published.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readBoundSkillGrants(raw: unknown): BoundSkillGrants | undefined;
|
|
23
|
+
/** The card members a call to the engine's `Skill` tool carries on every face its card has — empty for any other call. */
|
|
24
|
+
export interface SkillGrantBindingMembers {
|
|
25
|
+
/** The hash of {@link boundGrants}: the binding a parked approval of the card is judged by. */
|
|
26
|
+
boundGrantDigest?: string;
|
|
27
|
+
boundGrants?: BoundSkillGrants;
|
|
28
|
+
}
|
|
29
|
+
/** The leg's binding factory ({@link SkillGrantBindingMembers} for a call over `args`), the one every ask-mint site spreads. */
|
|
30
|
+
export type GrantBindingOf = (call: {
|
|
31
|
+
readonly toolName: string;
|
|
32
|
+
}, args: unknown) => SkillGrantBindingMembers;
|
|
33
|
+
/**
|
|
34
|
+
* The binding members of a stored parked row, as the inbox projection publishes them: the digest when it is a string, and the lists
|
|
35
|
+
* only as the value that digest hashes — {@link readBoundSkillGrants} whole, and equal to the digest by hash. A pair that
|
|
36
|
+
* disagrees, or lists beside no digest, would show an approver one list while the approval binds another: the lists read as absent.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readBoundBinding(row: {
|
|
39
|
+
readonly boundGrantDigest?: unknown;
|
|
40
|
+
readonly boundGrants?: unknown;
|
|
41
|
+
} | undefined): {
|
|
42
|
+
boundGrantDigest?: string;
|
|
43
|
+
boundGrants?: BoundSkillGrants;
|
|
44
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { boundInputHashOf } from "./canonical-json.js";
|
|
2
|
+
export function readBoundSkillGrants(raw) {
|
|
3
|
+
if (typeof raw !== "object" || raw === null)
|
|
4
|
+
return undefined;
|
|
5
|
+
const { skill, allowedTools: allowed, disallowedTools: disallowed } = raw;
|
|
6
|
+
if (skill !== null && typeof skill !== "string")
|
|
7
|
+
return undefined;
|
|
8
|
+
const entries = (list) => {
|
|
9
|
+
if (!Array.isArray(list))
|
|
10
|
+
return undefined;
|
|
11
|
+
const copy = Array.from(list);
|
|
12
|
+
return copy.every((e) => typeof e === "string") ? copy : undefined;
|
|
13
|
+
};
|
|
14
|
+
const allowedTools = entries(allowed);
|
|
15
|
+
const disallowedTools = entries(disallowed);
|
|
16
|
+
return allowedTools !== undefined && disallowedTools !== undefined ? { skill, allowedTools, disallowedTools } : undefined;
|
|
17
|
+
}
|
|
18
|
+
export function readBoundBinding(row) {
|
|
19
|
+
const digest = row?.boundGrantDigest;
|
|
20
|
+
const grants = readBoundSkillGrants(row?.boundGrants);
|
|
21
|
+
return { ...(typeof digest === "string" ? { boundGrantDigest: digest } : {}), ...(grants !== undefined && typeof digest === "string" && boundInputHashOf(grants) === digest ? { boundGrants: grants } : {}) };
|
|
22
|
+
}
|