@sema-agent/core 7.13.0 → 7.15.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 +110 -0
- package/dist/agents/subagent.d.ts +4 -9
- package/dist/agents/subagent.js +16 -12
- package/dist/agents/teacher.js +1 -1
- package/dist/brain/reasoning.d.ts +23 -0
- package/dist/brain/reasoning.js +35 -4
- package/dist/brain/stream-engine.js +35 -17
- package/dist/brain/timeout.d.ts +25 -4
- package/dist/brain/timeout.js +1 -1
- package/dist/core/ask-origin.d.ts +30 -11
- package/dist/core/ask-origin.js +10 -5
- package/dist/core/auto-mode.d.ts +3 -3
- package/dist/core/checkpoint-seat.d.ts +18 -0
- package/dist/core/checkpoint-seat.js +6 -0
- package/dist/core/checkpoint-store.d.ts +23 -31
- package/dist/core/checkpoint-store.js +7 -4
- package/dist/core/engine-notice.d.ts +3 -1
- package/dist/core/env-knob-announce.d.ts +16 -0
- package/dist/core/env-knob-announce.js +14 -0
- package/dist/core/gate-fold.js +2 -0
- package/dist/core/gate-lanes.js +21 -12
- package/dist/core/gate-outcome.d.ts +42 -3
- package/dist/core/gate-outcome.js +22 -0
- package/dist/core/governance-codes.js +1 -1
- package/dist/core/hooks.d.ts +9 -19
- package/dist/core/hooks.js +6 -4
- package/dist/core/mcp.d.ts +3 -2
- package/dist/core/mcp.js +5 -11
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/runner/advertised-writable-dirs.d.ts +74 -0
- package/dist/core/runner/advertised-writable-dirs.js +48 -0
- package/dist/core/runner/assemble-result.d.ts +5 -0
- package/dist/core/runner/contracts.d.ts +2 -2
- package/dist/core/runner/denial-limit-arms.d.ts +7 -9
- package/dist/core/runner/denial-limit-arms.js +8 -10
- package/dist/core/runner/gate-exit.d.ts +15 -3
- package/dist/core/runner/gate-exit.js +6 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +3 -1
- package/dist/core/runner/permission-rule-lanes.js +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +34 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +47 -12
- package/dist/core/runner/prepare-defer-classify.d.ts +1 -1
- package/dist/core/runner/prepare-defer-classify.js +12 -10
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -5
- package/dist/core/runner/prepare-gate-stations.js +2 -2
- package/dist/core/runner/prepare-hands-readface.d.ts +18 -12
- package/dist/core/runner/prepare-hands-readface.js +32 -43
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -5
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +31 -34
- package/dist/core/runner/prepare-memory.js +73 -51
- package/dist/core/runner/prepare-park-ask.d.ts +5 -6
- package/dist/core/runner/prepare-park-ask.js +3 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +2 -2
- package/dist/core/runner/prepare-policy-chain.js +7 -4
- package/dist/core/runner/prepare-prompt-inputs.d.ts +4 -0
- package/dist/core/runner/prepare-prompt-inputs.js +2 -2
- package/dist/core/runner/prepare-question-face.d.ts +10 -8
- package/dist/core/runner/prepare-question-face.js +1 -3
- package/dist/core/runner/prepare-safety-scan.js +1 -1
- package/dist/core/runner/prepare-task.js +60 -53
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +1 -1
- package/dist/core/runner/run-compaction-machinery.js +2 -0
- package/dist/core/runner/run-harness-handlers.js +3 -1
- package/dist/core/runner/stream-settle-backstop.js +1 -1
- package/dist/core/runner/tool-defer-gate.d.ts +86 -0
- package/dist/core/runner/tool-defer-gate.js +57 -0
- package/dist/core/runner/tool-disclosure.d.ts +0 -36
- package/dist/core/runner/tool-disclosure.js +0 -43
- package/dist/core/runner-deps.d.ts +16 -9
- package/dist/core/runtime-caps.d.ts +21 -0
- package/dist/core/runtime-caps.js +5 -1
- package/dist/core/task-event.d.ts +11 -2
- package/dist/core/task-registry-shared.js +8 -6
- package/dist/core/task-result.d.ts +15 -0
- package/dist/core/task-spec.d.ts +8 -2
- package/dist/core/terminal-cause.d.ts +6 -2
- package/dist/core/tool-policy.d.ts +34 -28
- package/dist/core/tool-policy.js +29 -5
- package/dist/core/tool-roster.js +2 -0
- package/dist/core/tool-spec.d.ts +20 -16
- package/dist/core/types.d.ts +3 -2
- package/dist/core/types.js +1 -0
- package/dist/core/wiring-manifest.d.ts +16 -9
- package/dist/core/wiring-manifest.js +8 -3
- package/dist/index.d.ts +7 -6
- package/dist/index.js +5 -4
- package/dist/orchestration/run-workflow-tool.d.ts +8 -8
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +4 -3
- package/dist/orchestration/workflow-primitives.js +3 -3
- package/dist/orchestration/workflow-types.d.ts +14 -0
- package/dist/orchestration/workflow.d.ts +41 -4
- package/dist/orchestration/workflow.js +23 -5
- package/dist/tools/fs/fs-bash.d.ts +41 -0
- package/dist/tools/fs/fs-bash.js +86 -29
- package/dist/tools/fs/fs-shared.js +9 -3
- package/dist/tools/fs/read-deny.d.ts +24 -8
- package/dist/tools/fs/read-deny.js +20 -1
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +29 -1
package/dist/index.d.ts
CHANGED
|
@@ -93,7 +93,7 @@ export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core
|
|
|
93
93
|
export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
|
|
94
94
|
export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
95
95
|
export type { InvariantKind, FunctionContract, Invariant, InvariantViolation, CheckResult, } from "./core/property-harness.js";
|
|
96
|
-
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
96
|
+
export { bashReversibilityProbe, bashReadBoundaryProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
97
97
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
|
|
98
98
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
99
99
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, type ReadDenyEntry, type ReadDenyMatcher, type NormalizedReadDenyEntry, type ReadDenyBuiltinTier, type ReadDenyBuiltinRow, type ReadDenyBuiltinConfig, } from "./tools/fs/index.js";
|
|
@@ -138,7 +138,7 @@ export { parkedToolIdentity } from "./core/tool-roster.js";
|
|
|
138
138
|
export { type ToolCallIdentity } from "./core/fs-write-gate-policy.js";
|
|
139
139
|
export { type RuleFaceView, catalogRuleFaceView } from "./core/permission-rules.js";
|
|
140
140
|
export { DURABLE_HISTORY_NAMES } from "./engine/compaction/utils.js";
|
|
141
|
-
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, type SubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, type AutoModeArmReason, type WiringManifest, type WiringManifestMcpEntry, type WiringFacts, type WiringLegKind, type AskSeamForm, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
|
|
141
|
+
export { describeStaticWiring, deriveWiringManifest, deriveAskEffective, resolveDeclaredDurability, resolveSubagentTranscriptTier, type SubagentTranscriptTier, resolveAskSeamForm, resolveQuestionSeam, countElicitOptIns, AUTO_MODE_ARM_REASONS, type AutoModeArmReason, type AutoModeArmFact, type WiringManifest, type WiringManifestMcpEntry, type WiringFacts, type WiringLegKind, type AskSeamForm, type AskEffective, type QuestionChannelState, type SeamProvenance, type ParkLaneReason, type ManifestDurability, type StaticWiringDeps, type StaticWiringSpec, } from "./core/wiring-manifest.js";
|
|
142
142
|
export { probeParkRoundTrip, durableParkGapOf, durableParkGapFor, PARK_SELFCHECK_SCOPE_PREFIX, type ParkSelfCheckResult, type ParkProbeFinding, type ParkProbeFindingCode, } from "./core/park-selfcheck.js";
|
|
143
143
|
export { type StoreDurability } from "./core/checkpoint-store.js";
|
|
144
144
|
export { type StoreFidelity } from "./core/checkpoint-store.js";
|
|
@@ -164,8 +164,9 @@ export { createSchedulerTools, type SchedulerToolContext, SCHEDULE_WAKEUP_TOOL_N
|
|
|
164
164
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, type AutonomousLoopPromptOptions, } from "./tools/loop-tick.js";
|
|
165
165
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
166
166
|
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
167
|
-
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL } from "./core/ask-origin.js";
|
|
168
|
-
export {
|
|
167
|
+
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL, RULE_STORE_UNREADABLE_KINDS, type RuleStoreUnreadable, isRuleStoreUnreadable } from "./core/ask-origin.js";
|
|
168
|
+
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
|
|
169
|
+
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, screenGateOutcome } from "./core/gate-outcome.js";
|
|
169
170
|
export { type AskCarry } from "./core/hooks.js";
|
|
170
171
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
|
171
172
|
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, type AutoModeUnavailableCause, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
|
|
@@ -228,7 +229,7 @@ export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore
|
|
|
228
229
|
export { stripEngineMetadata } from "./internal/llm.js";
|
|
229
230
|
export { EVENT_PROMPT_REGISTRY, eventDefaultOn, type CompiledEventPrompt, type CompiledMessageInjection, type EventDedupe, type EventDefaultPolicy } from "./prompt-assembly/event-registry.js";
|
|
230
231
|
export type { CompiledSection, ComposedPrompt, PackSectionDeclaration, PromptCacheClass, PromptCarrier, PromptMutability, PromptOwner, PromptPack, PromptRenderCadence, PromptRuntimeFacts, PromptSlot, PromptTrust, SectionRenderInputs, } from "./prompt-assembly/types.js";
|
|
231
|
-
export { type ReasoningIntensity, type ReasoningResolution, type ResolvedReasoning, type ReasoningFormat, DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffExpressible, declaredOffSpelling, type OffCapabilityModel, resolveReasoningProfile, type ReasoningTier, type ReasoningProfileFlags, } from "./brain/reasoning.js";
|
|
232
|
+
export { type ReasoningIntensity, type ReasoningResolution, type ResolvedReasoning, type ReasoningFormat, DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, reasoningEffortLevelsOf, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffExpressible, declaredOffSpelling, type OffCapabilityModel, resolveReasoningProfile, type ReasoningTier, type ReasoningProfileFlags, } from "./brain/reasoning.js";
|
|
232
233
|
export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, type ScenarioId, type CodeReviewMode, type ScenarioProfile, type RunScenarioOptions, type RunScenarioResult, } from "./scenarios/scenario-registry.js";
|
|
233
234
|
export { teacherMode, TEACHER_PROFILE, type TeacherModePair, type TeacherProfile, } from "./scenarios/teacher-quickstart.js";
|
|
234
235
|
export { loadOrchestrationEnv, DEFAULT_REASONING_INTENSITY, type OrchestrationMode, type OrchestrationEnv, } from "./scenarios/env.js";
|
|
@@ -317,7 +318,7 @@ export { ROUTE_ADJUDICATION_CONFORMANCE_CORPUS, type RouteAdjudicationVector } f
|
|
|
317
318
|
export { type BrainTimeoutConfig } from "./brain/timeout.js";
|
|
318
319
|
export { createAssistantMessageEventStream } from "./internal/llm.js";
|
|
319
320
|
export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
|
|
320
|
-
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, TrackFileEditHook, TrackEditRequest, TrackEditResult, FileEditedHook, FileEditedNotice, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, ResumePreflightInfo, ResumePreflightVerdict, EngineNotice, RuntimeCaps, BackgroundChildEvent, DelegationLifecycleEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, TerminalCause, PausedCause, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolInputVerdict, ToolInputValidationContext, ReversibilityVerdict, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
|
|
321
|
+
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, TrackFileEditHook, TrackEditRequest, TrackEditResult, FileEditedHook, FileEditedNotice, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, ResumePreflightInfo, ResumePreflightVerdict, EngineNotice, RuntimeCaps, BackgroundChildEvent, DelegationLifecycleEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, TerminalCause, PausedCause, EffectiveMemoryScopes, RemoteEnvFailureNote, TaskSpec, ShellGateDoctrine, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolInputVerdict, ToolInputValidationContext, ReversibilityVerdict, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
|
|
321
322
|
export { Type } from "typebox";
|
|
322
323
|
export type { TSchema, Static } from "typebox";
|
|
323
324
|
export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
|
package/dist/index.js
CHANGED
|
@@ -72,7 +72,7 @@ export { runExecGate } from "./core/exec-gate.js";
|
|
|
72
72
|
export { sanitizeUntrustedText, delimitUntrusted, inlineUntrusted } from "./core/untrusted-text.js";
|
|
73
73
|
export { mintReminderMark, isValidReminderMark, openSystemReminder, mintSystemReminder, reminderMarkDeclaration } from "./core/reminder-mint.js";
|
|
74
74
|
export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
|
|
75
|
-
export { bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
75
|
+
export { bashReversibilityProbe, bashReadBoundaryProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
|
|
76
76
|
export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
|
|
77
77
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
78
78
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, } from "./tools/fs/index.js";
|
|
@@ -138,8 +138,9 @@ export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTIN
|
|
|
138
138
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
|
|
139
139
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
140
140
|
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
141
|
-
export { ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL } from "./core/ask-origin.js";
|
|
142
|
-
export {
|
|
141
|
+
export { ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL, RULE_STORE_UNREADABLE_KINDS, isRuleStoreUnreadable } from "./core/ask-origin.js";
|
|
142
|
+
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
|
|
143
|
+
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
|
|
143
144
|
export {} from "./core/hooks.js";
|
|
144
145
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
145
146
|
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
|
|
@@ -186,7 +187,7 @@ export { buildTurnPromptSnapshot, loweringRecordFor, LOWERING_VERSION, PREFIX_IN
|
|
|
186
187
|
export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, } from "./prompt-assembly/artifact-store.js";
|
|
187
188
|
export { stripEngineMetadata } from "./internal/llm.js";
|
|
188
189
|
export { EVENT_PROMPT_REGISTRY, eventDefaultOn } from "./prompt-assembly/event-registry.js";
|
|
189
|
-
export { DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffExpressible, declaredOffSpelling, resolveReasoningProfile, } from "./brain/reasoning.js";
|
|
190
|
+
export { DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, reasoningEffortLevelsOf, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffExpressible, declaredOffSpelling, resolveReasoningProfile, } from "./brain/reasoning.js";
|
|
190
191
|
export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, } from "./scenarios/scenario-registry.js";
|
|
191
192
|
export { teacherMode, TEACHER_PROFILE, } from "./scenarios/teacher-quickstart.js";
|
|
192
193
|
export { loadOrchestrationEnv, DEFAULT_REASONING_INTENSITY, } from "./scenarios/env.js";
|
|
@@ -277,7 +277,7 @@ export interface RunWorkflowToolDeps {
|
|
|
277
277
|
* tighten-only ruling; the workflow lane was the remaining gap — a read-only host's workflow
|
|
278
278
|
* children spawned with full write hands). Filled ONLY when the clamp is ON (`true`), exactly
|
|
279
279
|
* like the ctx seat, so an unclamped deployment's mount gains no key. Known at prepare-time
|
|
280
|
-
* (frozen TaskSpec snapshot — no lazy getter needed, the `
|
|
280
|
+
* (frozen TaskSpec snapshot — no lazy getter needed, the `parentCheckpointStore` shape). */
|
|
281
281
|
parentHandsReadOnly?: true;
|
|
282
282
|
/** #345 ③ — the HOST task's hard-headless clamp (`interactiveTools: false`), same carriage rules
|
|
283
283
|
* as `parentHandsReadOnly` above: only the DISABLING value travels, mirroring the subagent lane's
|
|
@@ -352,13 +352,13 @@ export interface RunWorkflowToolDeps {
|
|
|
352
352
|
autoModeReview?: () => {
|
|
353
353
|
decider: import("../core/auto-mode.js").AutoModeDecider;
|
|
354
354
|
} | undefined;
|
|
355
|
-
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
|
|
355
|
+
/** The HOST run's RESOLVED checkpoint seat — the store object the host parks in, else the word `"disabled"`
|
|
356
|
+
* (the same two-state value the delegation ctx carries as `ToolExecuteContext.checkpointStoreForChildren`;
|
|
357
|
+
* `ctx` wins on a rich-ctx mount). Every agent this workflow spawns inherits it verbatim unless its own
|
|
358
|
+
* spec (baseline / trusted script) pinned a store — and `"disabled"` lands unconditionally (a removal the
|
|
359
|
+
* baseline must not undo); see `buildWorkflowPrimitives`. A dep for the same reason as `forwardEvent`/
|
|
360
|
+
* `inheritedGateForChildren`: the auto-mounted tool's execute ctx is minimal `{toolCallId, signal}`. */
|
|
361
|
+
parentCheckpointStore?: import("../core/checkpoint-store.js").CheckpointStore | "disabled";
|
|
362
362
|
/** #235 — the deployment's structured notice sink (`RunnerDeps.onNotice`), forwarded into the governed
|
|
363
363
|
* build so the fields a script's agent spec wrote that did NOT reach the child are announced instead of
|
|
364
364
|
* vanishing (`workflow.governance_key_stripped`). #505 ① — the same seat now also carries the OPTIONS
|
|
@@ -488,7 +488,7 @@ export async function createRunWorkflowTool(d) {
|
|
|
488
488
|
}
|
|
489
489
|
: governance;
|
|
490
490
|
const scriptFn = (wfCtx) => {
|
|
491
|
-
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, principal, ctx.
|
|
491
|
+
const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, principal, ctx.checkpointStoreForChildren ?? d.parentCheckpointStore, d.parentReadFace, d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false);
|
|
492
492
|
return d.scriptRunner.run({ scriptSource: script, primitives, scriptArgs: effectiveArgs, signal: wfCtx.signal }).then((r) => r.result);
|
|
493
493
|
};
|
|
494
494
|
if (ctx.signal?.aborted) {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { Model } from "../internal/llm.js";
|
|
16
16
|
import type { TaskSpec, WorkflowGovernanceBaseline } from "../core/types.js";
|
|
17
|
+
import type { CheckpointStore } from "../core/checkpoint-store.js";
|
|
17
18
|
import type { WorkflowAgentHandle, WorkflowRunContext } from "./workflow.js";
|
|
18
19
|
import type { WorkflowPrimitives } from "./workflow-script-runner.js";
|
|
19
20
|
import { type WorkflowChildCaps } from "./workflow-governance.js";
|
|
@@ -36,9 +37,9 @@ export interface WorkflowGovernance {
|
|
|
36
37
|
* — filling them here ran ahead of the fold and made the fold's "when unset" guard permanently false.
|
|
37
38
|
*/
|
|
38
39
|
export declare function buildWorkflowPrimitives(ctx: WorkflowRunContext, governance?: WorkflowGovernance, onAgentSpawn?: (handle: WorkflowAgentHandle) => void, parentPrincipal?: string,
|
|
39
|
-
/**
|
|
40
|
-
*
|
|
41
|
-
|
|
40
|
+
/** The host run's RESOLVED checkpoint seat — the store object it parks in, else the word `"disabled"`.
|
|
41
|
+
* Every agent this workflow spawns inherits it; see the injection below. */
|
|
42
|
+
parentCheckpointStore?: CheckpointStore | "disabled",
|
|
42
43
|
/** 5.30 merge-rescan (design/199 parity gap) — the host run's RESOLVED read-face containment
|
|
43
44
|
* (post deps/org/mount resolution, not the raw spec value). `TaskSpec.readFace`'s own JSDoc
|
|
44
45
|
* promises "roots pins this task, and via the tighten-only clamp, its whole delegation subtree" —
|
|
@@ -65,7 +65,7 @@ function formatResourceClampNote(notes) {
|
|
|
65
65
|
const parts = notes.map((n) => `${n.field}: requested ${n.requested === undefined ? "unset" : n.requested} → applied ${n.applied}`);
|
|
66
66
|
return `workflow governance tightened this agent's resource limits (${parts.join("; ")})`;
|
|
67
67
|
}
|
|
68
|
-
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentPrincipal,
|
|
68
|
+
export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentPrincipal, parentCheckpointStore, parentReadFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff) {
|
|
69
69
|
const agent = (spec, opts) => {
|
|
70
70
|
if (typeof spec === "string")
|
|
71
71
|
spec = { objective: spec };
|
|
@@ -77,8 +77,8 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentPri
|
|
|
77
77
|
if (childSpec.principal === undefined && parentPrincipal !== undefined) {
|
|
78
78
|
childSpec.principal = parentPrincipal;
|
|
79
79
|
}
|
|
80
|
-
if (
|
|
81
|
-
childSpec.checkpointStore =
|
|
80
|
+
if (parentCheckpointStore !== undefined && (parentCheckpointStore === "disabled" || childSpec.checkpointStore === undefined)) {
|
|
81
|
+
childSpec.checkpointStore = parentCheckpointStore;
|
|
82
82
|
}
|
|
83
83
|
if (parentReadFace) {
|
|
84
84
|
const pf = parentReadFace();
|
|
@@ -328,6 +328,20 @@ export interface WorkflowRun {
|
|
|
328
328
|
rev?: number;
|
|
329
329
|
/** Set when `status === "failed"`: the error the script threw. */
|
|
330
330
|
error?: string;
|
|
331
|
+
/** #688 C4 (additive) — the MACHINE code of the failure that ended the run, in the same vocabulary as
|
|
332
|
+
* {@link WorkflowAgentRun.errorCode} (`workflow.*` for the orchestration's own refusals, a task's terminal code
|
|
333
|
+
* for a child's failure), so a consumer branches here and never on `error`'s text. Attribution, in order:
|
|
334
|
+
* 1. the thrown value's own string `code` — the run SUSPENDED on a parked agent ⇒ `workflow.agent_parked`
|
|
335
|
+
* (whatever the body threw after the park), a refused spawn ⇒ `workflow.agent_blocked`, the budget /
|
|
336
|
+
* nesting / schema / stall / max-agents refusals ⇒ their `WorkflowBudgetExceededError`… codes, a body that
|
|
337
|
+
* re-threw a typed error ⇒ that error's code;
|
|
338
|
+
* 2. otherwise the FIRST failed agent record carrying a code (earliest `endedAt`, spawn order on a tie) —
|
|
339
|
+
* the body gave up after a child failed and threw in its own words; with several failed children the
|
|
340
|
+
* first to fail is the one taken (a body that threw for an unrelated reason beside a failed child still
|
|
341
|
+
* reads that child's code — `error` keeps the body's own sentence);
|
|
342
|
+
* 3. absent — a body that threw a codeless error with no failed child on the record.
|
|
343
|
+
* Absent on `completed` runs (their per-agent failures ride `agentFailures` + each `WorkflowAgentRun.errorCode`). */
|
|
344
|
+
errorCode?: string;
|
|
331
345
|
/** The script's RETURN VALUE, bounded + redacted at completion time (same egress
|
|
332
346
|
* discipline as the notifier `result`), so a terminal `TaskOutput` poll can hand the
|
|
333
347
|
* model the result instead of sending it in poll circles. Absent on failed runs and runs recorded by
|
|
@@ -547,10 +547,47 @@ export interface WorkflowHandle<T> {
|
|
|
547
547
|
}
|
|
548
548
|
/** Cap on items a single `parallel`/`pipeline` call accepts (matches the CC Workflow tool). */
|
|
549
549
|
export declare const MAX_WORKFLOW_ITEMS = 4096;
|
|
550
|
-
/**
|
|
551
|
-
*
|
|
552
|
-
*
|
|
553
|
-
|
|
550
|
+
/**
|
|
551
|
+
* CC `MTy` (206-pretty.js:17501680; 198 `F0m`): no tool activity for this long marks the attempt STALLED
|
|
552
|
+
* (progress-based, unlike the governance perAgentTimeoutSec hard cap, which still bounds each attempt).
|
|
553
|
+
* `<= 0` DISABLES the watchdog (CC arms only `if (ae > 0)`, :17477830).
|
|
554
|
+
*
|
|
555
|
+
* DERIVED, not a number of its own (#682): an OUTER, COARSER clock must never fire before the engine's
|
|
556
|
+
* own. This watchdog does not re-send a model call — it aborts the attempt and restarts the whole agent
|
|
557
|
+
* on a FRESH session, so tool effects from before the stall can be repeated. The engine, one layer down,
|
|
558
|
+
* already answers a silent provider call the cheap way: it re-sends that ONE call. So the floor here is
|
|
559
|
+
* what a single provider call may legitimately occupy while producing NOTHING — the connect wait plus the
|
|
560
|
+
* first-token wait ({@link STALL_CONNECT_MS} + {@link STALL_FIRST_TOKEN_MS}). It was a hand-written
|
|
561
|
+
* 180_000 and CC-same until the first-token bound rose to 600s past it (measured: the same silent call
|
|
562
|
+
* then produced two agent runs on two sessions instead of one run with a re-sent call), which is the
|
|
563
|
+
* systematic inversion a derived value cannot re-open: raise or lower the engine's bound and this follows.
|
|
564
|
+
*
|
|
565
|
+
* WHAT THIS IS NOT (measured, adversarial round — do not read the sum as a proof of ordering). The two
|
|
566
|
+
* clocks do not start together and this one does not reset per inner retry, so it can still fire first:
|
|
567
|
+
* this timer starts before the Runner prepares the attempt (an execution-env factory, a hook, a store
|
|
568
|
+
* read all run inside this window and outside the engine's), and the first-token timer only starts once
|
|
569
|
+
* headers arrive — so the margin by which the inner deadline can land AFTER this one is preparation plus
|
|
570
|
+
* the connect time actually spent, less the {@link STALL_CONNECT_MS} this window already budgets for it
|
|
571
|
+
* (40s of preparation and instant headers puts the first inner deadline 10s past this timer). An engine retry does not re-arm this timer either, so two silent provider attempts
|
|
572
|
+
* exceed it by construction. The derivation removes the case that was guaranteed to invert; it does not
|
|
573
|
+
* make inversion impossible. A deployment that wants the old aggression passes `stallMs` explicitly, and
|
|
574
|
+
* a deployment that wants a real guarantee must set it from its own preparation budget.
|
|
575
|
+
*/
|
|
576
|
+
export declare const WORKFLOW_AGENT_STALL_MS: number;
|
|
577
|
+
/**
|
|
578
|
+
* The "took suspiciously long" half of the throttle-shaped-degradation predicate (CC `Nt`,
|
|
579
|
+
* 206-pretty.js:17487400, which spells it `MTy * 0.5` = 90s). It used to be computed from the stall
|
|
580
|
+
* window here too, and that was safe only while the window was CC's own 180_000 — the moment the window
|
|
581
|
+
* became derived from the engine's bounds (#682/#693) the same expression silently moved the throttle
|
|
582
|
+
* threshold 90s → 315s, and a 2-minute empty answer that used to earn a 45s-sleep-and-retry was simply
|
|
583
|
+
* returned. Two unrelated meanings were riding one number. This is the second meaning, at CC's own
|
|
584
|
+
* value, so the progress window can move without touching it.
|
|
585
|
+
*
|
|
586
|
+
* Still a MINIMUM with the window, not a replacement for it: a deployment that shortens `stallMs` below
|
|
587
|
+
* this is asking for a tighter agent, and a throttle threshold above its own stall window could never
|
|
588
|
+
* fire. So the effective threshold is `min(stallMs / 2, this)` — one rule, both directions.
|
|
589
|
+
*/
|
|
590
|
+
export declare const WORKFLOW_THROTTLE_SLOW_MS = 90000;
|
|
554
591
|
/** CC `j_d` (206-pretty.js:17501680; 198 `Mxl`): max stalled-attempt retries per `ctx.agent` call
|
|
555
592
|
* (initial + 5 = 6 attempts). */
|
|
556
593
|
export declare const WORKFLOW_AGENT_MAX_RETRIES = 5;
|
|
@@ -21,6 +21,7 @@ import { OUTPUT_TOOL_NAME } from "../core/runner/synthetic-tools.js";
|
|
|
21
21
|
import { compileOutputSchema } from "../core/runner/strict-output-schema.js";
|
|
22
22
|
import { WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentBlockedError, WorkflowAgentParkedError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowMaxAgentsError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } from "./workflow-types.js";
|
|
23
23
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
24
|
+
import { STALL_CONNECT_MS, STALL_FIRST_TOKEN_MS } from "../brain/timeout.js";
|
|
24
25
|
export * from "./workflow-types.js";
|
|
25
26
|
const MAX_TRANSCRIPT_CHARS = 4000;
|
|
26
27
|
const WORKFLOW_RESULT_MAX = 4000;
|
|
@@ -149,6 +150,7 @@ export function workflowAgentCallKey(ordinal, spec, opts) {
|
|
|
149
150
|
signal: undefined,
|
|
150
151
|
taskId: undefined,
|
|
151
152
|
sessionId: undefined,
|
|
153
|
+
checkpointStore: undefined,
|
|
152
154
|
tools: spec.tools?.map((t) => t.name).slice().sort(),
|
|
153
155
|
mcp: spec.mcp?.map((m) => m.name).slice().sort(),
|
|
154
156
|
outputSchema: opts.schema ?? spec.outputSchema,
|
|
@@ -278,7 +280,8 @@ function assertFanOutOptionsShape(v, position) {
|
|
|
278
280
|
`Nothing was run.`);
|
|
279
281
|
}
|
|
280
282
|
}
|
|
281
|
-
export const WORKFLOW_AGENT_STALL_MS =
|
|
283
|
+
export const WORKFLOW_AGENT_STALL_MS = STALL_CONNECT_MS + STALL_FIRST_TOKEN_MS;
|
|
284
|
+
export const WORKFLOW_THROTTLE_SLOW_MS = 90_000;
|
|
282
285
|
export const WORKFLOW_AGENT_MAX_RETRIES = 5;
|
|
283
286
|
export const WORKFLOW_AGENT_THROTTLE_BACKOFF_MS = 45_000;
|
|
284
287
|
function readLegPendingApproval(result, announce) {
|
|
@@ -1604,7 +1607,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1604
1607
|
result.structuredOutput === undefined &&
|
|
1605
1608
|
(result.stats.outputTokens ?? Number.POSITIVE_INFINITY) < 50 &&
|
|
1606
1609
|
lastStopReason === undefined &&
|
|
1607
|
-
durationMs > stallMs * 0.5;
|
|
1610
|
+
durationMs > Math.min(stallMs * 0.5, WORKFLOW_THROTTLE_SLOW_MS);
|
|
1608
1611
|
if (degraded && attempts === 1 && !throttleRetried && drive === undefined) {
|
|
1609
1612
|
throttleRetried = true;
|
|
1610
1613
|
lastAttemptReason = "throttled";
|
|
@@ -1689,7 +1692,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1689
1692
|
...(err instanceof WorkflowAgentBlockedError ? { code: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } : err instanceof WorkflowBudgetExceededError ? { code: err.code } : {}),
|
|
1690
1693
|
message: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500),
|
|
1691
1694
|
},
|
|
1692
|
-
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1695
|
+
stats: { turns: 0, tokens: 0, costMicroUsd: 0, usageMissing: true },
|
|
1693
1696
|
}, label).catch(() => undefined);
|
|
1694
1697
|
if (!((err instanceof WorkflowBudgetExceededError || err instanceof WorkflowAgentParkedError) && rec.startedAt === undefined))
|
|
1695
1698
|
await journaled;
|
|
@@ -1801,7 +1804,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1801
1804
|
sessionId: "",
|
|
1802
1805
|
terminal: { kind: "failed", code: refusal.code, message: boundedRedactedSummary(refusal.message, 500) },
|
|
1803
1806
|
result: boundedRedactedSummary(refusal.message, 500),
|
|
1804
|
-
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1807
|
+
stats: { turns: 0, tokens: 0, costMicroUsd: 0, usageMissing: true },
|
|
1805
1808
|
}).catch(() => undefined);
|
|
1806
1809
|
throw refusal;
|
|
1807
1810
|
}
|
|
@@ -1875,7 +1878,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1875
1878
|
sessionId: "",
|
|
1876
1879
|
terminal: { kind: "failed", code: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, message: boundedRedactedSummary(err.message, 500) },
|
|
1877
1880
|
result: boundedRedactedSummary(err.message, 500),
|
|
1878
|
-
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1881
|
+
stats: { turns: 0, tokens: 0, costMicroUsd: 0, usageMissing: true },
|
|
1879
1882
|
}).catch(() => undefined);
|
|
1880
1883
|
}
|
|
1881
1884
|
recordFailed();
|
|
@@ -2224,6 +2227,21 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
2224
2227
|
err = parkedError();
|
|
2225
2228
|
run.error = err instanceof Error ? err.message : String(err);
|
|
2226
2229
|
closeAbandonedAgents(run.endedAt);
|
|
2230
|
+
{
|
|
2231
|
+
let thrownCode;
|
|
2232
|
+
try {
|
|
2233
|
+
thrownCode = err !== null && (typeof err === "object" || typeof err === "function") ? err.code : undefined;
|
|
2234
|
+
}
|
|
2235
|
+
catch {
|
|
2236
|
+
thrownCode = undefined;
|
|
2237
|
+
}
|
|
2238
|
+
const firstFailed = run.agents
|
|
2239
|
+
.filter((a) => a.status === "failed" && typeof a.errorCode === "string" && a.errorCode !== "")
|
|
2240
|
+
.sort((a, b) => (a.endedAt ?? Number.POSITIVE_INFINITY) - (b.endedAt ?? Number.POSITIVE_INFINITY))[0];
|
|
2241
|
+
const code = typeof thrownCode === "string" && thrownCode !== "" ? thrownCode : firstFailed?.errorCode;
|
|
2242
|
+
if (code !== undefined)
|
|
2243
|
+
run.errorCode = code;
|
|
2244
|
+
}
|
|
2227
2245
|
restampPhaseFailures();
|
|
2228
2246
|
const failedRunFailures = countAgentFailures();
|
|
2229
2247
|
if (failedRunFailures > 0)
|
|
@@ -56,6 +56,47 @@ import { type BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
|
|
|
56
56
|
* that adds nothing the reader cannot already see.
|
|
57
57
|
*/
|
|
58
58
|
export declare function bashReversibilityProbe(allow?: readonly string[], boundary?: BashReadonlyRootBoundary | (() => BashReadonlyRootBoundary | undefined)): (args: unknown) => ReversibilityVerdict;
|
|
59
|
+
/**
|
|
60
|
+
* The READ-BOUNDARY seat of the full shell: a `ToolSpec.reversibilityProbe` that answers exactly ONE
|
|
61
|
+
* question — does the deployment's read boundary object to where this command reads? — and nothing about
|
|
62
|
+
* the command's shape. It is the shell face of the rule every read face obeys: the structured readers
|
|
63
|
+
* (Read/Grep/Glob) refuse a deny-listed or out-of-root target; the shell reader gets a MANDATED ask for the
|
|
64
|
+
* same target. The engine installs it on Bash and Monitor whenever a real writable shell is mounted and the
|
|
65
|
+
* shellGate doctrine adds no residual-risk classifier of its own (`shellGate:"off"`, the default); under
|
|
66
|
+
* `"classify"` the doctrine installs {@link bashReversibilityProbe} instead, which composes THIS judgment
|
|
67
|
+
* with the read-only shape classifier, and under `"always"` the tier itself is the mandate and no probe runs.
|
|
68
|
+
* The boundary is therefore judged under every doctrine; the doctrine decides only what happens to the
|
|
69
|
+
* residual shell risk.
|
|
70
|
+
*
|
|
71
|
+
* The verdict, in the probe vocabulary the gate reads (`reversible` here means "the boundary raised no
|
|
72
|
+
* question — the seat vouches the call may run"):
|
|
73
|
+
* · the boundary DECLARED an objection — a deny-listed operand, a recursive walk under the deny judge, an
|
|
74
|
+
* operand outside the roots — ⇒ `{ reversible: false, mandated: true }` (+ the recursive-reach `cause`);
|
|
75
|
+
* · the boundary could NOT READ where the command reads — an unexpanded glob operand (the compound face
|
|
76
|
+
* reports it as undecided), a `~`-rooted operand with no home declared, a working-directory move the walk
|
|
77
|
+
* cannot model — ⇒ `{ reversible: false }` (fail-closed; a plain ask, which a stored allow rule may retire —
|
|
78
|
+
* the seat did not declare anything, it declined to guess);
|
|
79
|
+
* · otherwise ⇒ `{ reversible: true }`. This includes every command whose SHAPE the read faces refuse whole
|
|
80
|
+
* (an unlisted program, a redirection, a substitution, a segment that is not a reader): those shapes carry
|
|
81
|
+
* no read-face verdict, so this seat has no question to ask — the residual is the doctrine's, and under
|
|
82
|
+
* `"off"` the doctrine asks nothing. `run_in_background` is likewise not this seat's question (it changes
|
|
83
|
+
* WHEN the command runs, never WHERE it reads).
|
|
84
|
+
*
|
|
85
|
+
* Reach = the read faces' reach, and nothing wider: the compound face walks the operands of a command whose
|
|
86
|
+
* every segment is a listed reader, and the bounded poll-loop face walks a loop body of listed readers. A
|
|
87
|
+
* read hidden in a shape the faces refuse whole (`cat x | <unlisted>`, `$(cat x)`, `cat $DIR/x`, a launcher
|
|
88
|
+
* `env cat x`, a path-prefixed `/bin/cat x`) is not seen here — deny-listed or out-of-root alike — exactly
|
|
89
|
+
* the shapes the `"classify"` doctrine exists to ask about. The text-level containment gate the classify
|
|
90
|
+
* seat consults on its demotion arms is deliberately not consulted here ({@link boundaryDeclared}: it may
|
|
91
|
+
* add a mandate to an ask, never originate one). The poll-loop face reports its refusal as one sentence,
|
|
92
|
+
* so the boundary's share of it is read by removing the boundary's judging seats
|
|
93
|
+
* ({@link pollLoopBoundaryVerdict}).
|
|
94
|
+
*
|
|
95
|
+
* The reader set is the engine's classify set ({@link BASH_CLASSIFY_DEFAULT_ALLOW}) — here it is NOT an
|
|
96
|
+
* auto-allow list but the set of programs whose operands the faces read; a wider set means more reads are
|
|
97
|
+
* judged, never that more runs are vouched.
|
|
98
|
+
*/
|
|
99
|
+
export declare function bashReadBoundaryProbe(boundary: BashReadonlyRootBoundary | (() => BashReadonlyRootBoundary | undefined)): (args: unknown) => ReversibilityVerdict;
|
|
59
100
|
/**
|
|
60
101
|
* design/199 D-6 — the FULL shell's contract id, single-sourced: both shell faces share the wire
|
|
61
102
|
* name "Bash", so this id is the ONE structural discriminator between the write-capable shell and
|
package/dist/tools/fs/fs-bash.js
CHANGED
|
@@ -25,40 +25,100 @@ function operandFamily(paths) {
|
|
|
25
25
|
export function bashReversibilityProbe(allow, boundary) {
|
|
26
26
|
const allowSet = new Set(allow ?? BASH_CLASSIFY_DEFAULT_ALLOW);
|
|
27
27
|
return (args) => {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
if (typeof command !== "string")
|
|
28
|
+
const command = shellCommandOf(args);
|
|
29
|
+
if (command === undefined)
|
|
31
30
|
return { reversible: false };
|
|
32
31
|
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const backgrounded =
|
|
32
|
+
const boundaryGate = (verdict) => readBoundaryMandate(command, allowSet, resolved, verdict);
|
|
33
|
+
const outOfRootGate = () => readBoundaryMandate(command, allowSet, resolved, {});
|
|
34
|
+
const backgrounded = isBackgroundShellCall(args);
|
|
36
35
|
const detailed = classifyCompoundReadonlyDetailed(command, allowSet, resolved);
|
|
37
36
|
if (backgrounded)
|
|
38
37
|
return { reversible: false, ...boundaryGate(detailed) };
|
|
39
38
|
if (detailed.reason === undefined) {
|
|
40
39
|
if (detailed.undecidedPaths !== undefined && detailed.undecidedPaths.length > 0) {
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
const others = detailed.undecidedPaths.filter((p) => !recursiveSet.has(p));
|
|
45
|
-
return {
|
|
46
|
-
reversible: false,
|
|
47
|
-
...boundaryGate(detailed),
|
|
48
|
-
cause: {
|
|
49
|
-
code: RECURSIVE_READ_CAUSE_CODE,
|
|
50
|
-
roots: operandFamily(recursive),
|
|
51
|
-
...(others.length > 0 ? { further: operandFamily(others) } : {}),
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
40
|
+
const cause = recursiveReadCause(detailed);
|
|
41
|
+
if (cause !== undefined)
|
|
42
|
+
return { reversible: false, ...boundaryGate(detailed), cause };
|
|
55
43
|
return { reversible: false, ...outOfRootGate() };
|
|
56
44
|
}
|
|
57
45
|
return { reversible: true };
|
|
58
46
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
const loopRefusal = classifyBoundedReadonlyPollLoop(command, allowSet, resolved);
|
|
48
|
+
if (loopRefusal === undefined)
|
|
49
|
+
return { reversible: true };
|
|
50
|
+
return { reversible: false, ...(pollLoopBoundaryVerdict(command, allowSet, resolved, loopRefusal) === "declared" ? { mandated: true } : boundaryGate(detailed)) };
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function attributeRefusal(face, resolved, fullRefusal) {
|
|
54
|
+
if (resolved === undefined)
|
|
55
|
+
return "shape";
|
|
56
|
+
const { denyMatch: _deny, ...withoutDenyJudge } = resolved;
|
|
57
|
+
const opened = face({ ...withoutDenyJudge, face: "open" });
|
|
58
|
+
if (opened === undefined || opened !== fullRefusal)
|
|
59
|
+
return "declared";
|
|
60
|
+
return face(undefined) === opened ? "shape" : "unread";
|
|
61
|
+
}
|
|
62
|
+
function pollLoopBoundaryVerdict(command, allowSet, resolved, fullRefusal) {
|
|
63
|
+
return attributeRefusal((b) => classifyBoundedReadonlyPollLoop(command, allowSet, b), resolved, fullRefusal);
|
|
64
|
+
}
|
|
65
|
+
function boundaryDeclared(verdict) {
|
|
66
|
+
return denyJudgeSpoke(verdict) || verdict.outOfRootRead === true;
|
|
67
|
+
}
|
|
68
|
+
function denyJudgeSpoke(verdict) {
|
|
69
|
+
return verdict.readDenied === true || (verdict.recursiveReadPaths !== undefined && verdict.recursiveReadPaths.length > 0);
|
|
70
|
+
}
|
|
71
|
+
function shellCommandOf(args) {
|
|
72
|
+
const command = args?.command;
|
|
73
|
+
return typeof command === "string" ? command : undefined;
|
|
74
|
+
}
|
|
75
|
+
function isBackgroundShellCall(args) {
|
|
76
|
+
return args?.run_in_background === true;
|
|
77
|
+
}
|
|
78
|
+
function readBoundaryMandate(command, allowSet, resolved, verdict) {
|
|
79
|
+
if (denyJudgeSpoke(verdict))
|
|
80
|
+
return { mandated: true };
|
|
81
|
+
return resolved !== undefined && classifyOutOfRootReadGate(command, allowSet, resolved).gated ? { mandated: true } : {};
|
|
82
|
+
}
|
|
83
|
+
function recursiveReadCause(detailed) {
|
|
84
|
+
const recursive = detailed.recursiveReadPaths;
|
|
85
|
+
if (recursive === undefined || recursive.length === 0)
|
|
86
|
+
return undefined;
|
|
87
|
+
const recursiveSet = new Set(recursive);
|
|
88
|
+
const others = (detailed.undecidedPaths ?? []).filter((p) => !recursiveSet.has(p));
|
|
89
|
+
return {
|
|
90
|
+
code: RECURSIVE_READ_CAUSE_CODE,
|
|
91
|
+
roots: operandFamily(recursive),
|
|
92
|
+
...(others.length > 0 ? { further: operandFamily(others) } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function bashReadBoundaryProbe(boundary) {
|
|
96
|
+
const allowSet = new Set(BASH_CLASSIFY_DEFAULT_ALLOW);
|
|
97
|
+
return (args) => {
|
|
98
|
+
const command = shellCommandOf(args);
|
|
99
|
+
if (command === undefined)
|
|
100
|
+
return { reversible: false };
|
|
101
|
+
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
102
|
+
if (resolved === undefined)
|
|
103
|
+
return { reversible: true };
|
|
104
|
+
const detailed = classifyCompoundReadonlyDetailed(command, allowSet, resolved);
|
|
105
|
+
if (boundaryDeclared(detailed)) {
|
|
106
|
+
const cause = recursiveReadCause(detailed);
|
|
107
|
+
return { reversible: false, mandated: true, ...(cause !== undefined ? { cause } : {}) };
|
|
108
|
+
}
|
|
109
|
+
if (detailed.reason === undefined) {
|
|
110
|
+
return detailed.undecidedPaths !== undefined && detailed.undecidedPaths.length > 0 ? { reversible: false } : { reversible: true };
|
|
111
|
+
}
|
|
112
|
+
const compound = attributeRefusal((b) => classifyCompoundReadonlyDetailed(command, allowSet, b).reason, resolved, detailed.reason);
|
|
113
|
+
if (compound === "declared")
|
|
114
|
+
return { reversible: false, mandated: true };
|
|
115
|
+
if (compound === "unread")
|
|
116
|
+
return { reversible: false };
|
|
117
|
+
const loopRefusal = classifyBoundedReadonlyPollLoop(command, allowSet, resolved);
|
|
118
|
+
if (loopRefusal === undefined)
|
|
119
|
+
return { reversible: true };
|
|
120
|
+
const loop = pollLoopBoundaryVerdict(command, allowSet, resolved, loopRefusal);
|
|
121
|
+
return loop === "shape" ? { reversible: true } : loop === "declared" ? { reversible: false, mandated: true } : { reversible: false };
|
|
62
122
|
};
|
|
63
123
|
}
|
|
64
124
|
export { FULL_SHELL_CONTRACT_ID } from "../../core/tool-catalog-entries.js";
|
|
@@ -563,13 +623,10 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
563
623
|
})),
|
|
564
624
|
}),
|
|
565
625
|
isConcurrencySafe: (args) => {
|
|
566
|
-
const
|
|
567
|
-
if (
|
|
568
|
-
return false;
|
|
569
|
-
const bg = args.run_in_background;
|
|
570
|
-
if (bg === true)
|
|
626
|
+
const command = shellCommandOf(args);
|
|
627
|
+
if (command === undefined || isBackgroundShellCall(args))
|
|
571
628
|
return false;
|
|
572
|
-
return coarseReadonlyCheck(
|
|
629
|
+
return coarseReadonlyCheck(command, new Set(BASH_READONLY_DEFAULT_ALLOW)) === undefined;
|
|
573
630
|
},
|
|
574
631
|
execute: async (args, ctx) => {
|
|
575
632
|
const { command, timeout, run_in_background, description } = args;
|
|
@@ -6,6 +6,7 @@ import { shellQuote } from "./search.js";
|
|
|
6
6
|
import { isNotebookPath } from "./notebook.js";
|
|
7
7
|
import { sharpImageDownsampler } from "../../core/mcp.js";
|
|
8
8
|
import { deliverEngineNotice } from "../../core/types.js";
|
|
9
|
+
import { announceEnvKnob } from "../../core/env-knob-announce.js";
|
|
9
10
|
import { openSystemReminder } from "../../core/reminder-mint.js";
|
|
10
11
|
export const MAX_READ_BYTES = 256 * 1024;
|
|
11
12
|
export const SLICED_READ_MAX_BYTES = 64 * 1024 * 1024;
|
|
@@ -181,10 +182,15 @@ export function bashTimeoutCapsSec(caps) {
|
|
|
181
182
|
const BASH_DEFAULT_MAX_OUTPUT_CHARS = 30_000;
|
|
182
183
|
const BASH_MAX_OUTPUT_CHARS_CEILING = 150_000;
|
|
183
184
|
export function bashMaxOutputChars() {
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
185
|
+
const rawEnv = process.env.BASH_MAX_OUTPUT_LENGTH;
|
|
186
|
+
if (rawEnv === undefined || rawEnv.trim() === "")
|
|
186
187
|
return BASH_DEFAULT_MAX_OUTPUT_CHARS;
|
|
187
|
-
|
|
188
|
+
const raw = Number(rawEnv);
|
|
189
|
+
if (!Number.isInteger(raw) || raw <= 0) {
|
|
190
|
+
announceEnvKnob(`BASH_MAX_OUTPUT_LENGTH=${rawEnv} was ignored — it is not a positive whole number of characters. Using ${BASH_DEFAULT_MAX_OUTPUT_CHARS} instead.`);
|
|
191
|
+
return BASH_DEFAULT_MAX_OUTPUT_CHARS;
|
|
192
|
+
}
|
|
193
|
+
return Math.min(raw, BASH_MAX_OUTPUT_CHARS_CEILING);
|
|
188
194
|
}
|
|
189
195
|
export const FILE_PATH_PARAMS = {
|
|
190
196
|
file_path: Type.String({ description: "File path (within the configured root)." }),
|
|
@@ -65,7 +65,7 @@ export interface ReadDenyMatcher {
|
|
|
65
65
|
* exactly one. Unknown tier names refuse loudly (#123) — this array is the validation source and the
|
|
66
66
|
* admin-face vocabulary, never re-spelled downstream.
|
|
67
67
|
*/
|
|
68
|
-
export declare const READ_DENY_BUILTIN_TIERS: readonly ["credentials", "shell-history", "browser", "wallet"];
|
|
68
|
+
export declare const READ_DENY_BUILTIN_TIERS: readonly ["credentials", "shell-history", "browser", "wallet", "agent-config"];
|
|
69
69
|
/** One member of {@link READ_DENY_BUILTIN_TIERS}. */
|
|
70
70
|
export type ReadDenyBuiltinTier = (typeof READ_DENY_BUILTIN_TIERS)[number];
|
|
71
71
|
/**
|
|
@@ -90,17 +90,33 @@ export interface ReadDenyBuiltinRow {
|
|
|
90
90
|
* and a false refusal on a fixture is the cheap direction (deny errs strict).
|
|
91
91
|
*
|
|
92
92
|
* NOT listed, deliberately: `.env`/`.env.*` (ruled out — workspace material; the WRITE guard still
|
|
93
|
-
* covers them
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* `.
|
|
97
|
-
* (transcript integrity policy owns it with an ask on the write
|
|
93
|
+
* covers them; the ENGINE's own `.env` under its data root is a different file and IS listed, see the
|
|
94
|
+
* agent-config tier); `*.pem`/`*.key`/`*.p12`/`*.pfx` (repo certificates/test keys are routinely
|
|
95
|
+
* READ — refusing them breaks ordinary work, the write guard covers the mutation direction);
|
|
96
|
+
* `.git/hooks`/`.git/config` (reads are harmless; writes are the escalation and stay guarded); the
|
|
97
|
+
* engine's own data root as a WHOLE (transcript integrity policy owns it with an ask on the write
|
|
98
|
+
* face, and the memory library the model is told to read and edit lives under it).
|
|
99
|
+
*
|
|
100
|
+
* agent-config tier — the agent's OWN configuration files whose `env` / server blocks carry API keys
|
|
101
|
+
* in cleartext (the shell's `settings.json` env block, a project `.mcp.json` server env, the engine
|
|
102
|
+
* host's data-root `.env`). A structured read of one of these used to land the key verbatim in the
|
|
103
|
+
* tool result and therefore in the session record. Rows name FILES, not the config DIRECTORIES:
|
|
104
|
+
* `.sema`/`.claude` also hold agents, skills, hooks and (under the shell's layout,
|
|
105
|
+
* `~/.sema/engine-data`) the engine data root with the memory library — material the model reads
|
|
106
|
+
* and edits as ordinary work, and a directory-wide row would need a data-root passthrough (one more
|
|
107
|
+
* rule) to keep it readable. The write face guards the directories (`sensitive-path-policy.ts`): a
|
|
108
|
+
* write there is self-authorization; a read of a non-credential file there is debugging. Token
|
|
109
|
+
* STORES of the same tooling (`.credentials.json`, `.codex/auth.json`, …) are credentials rows, not
|
|
110
|
+
* agent-config rows: a deployment that switches this tier off to debug its agent configuration must
|
|
111
|
+
* not also expose the OAuth stores beside it.
|
|
98
112
|
*/
|
|
99
113
|
export declare const READ_FACE_BUILTIN_DENY_TABLE: readonly ReadDenyBuiltinRow[];
|
|
100
114
|
/**
|
|
101
115
|
* The DEFAULT tier selection (#245 ruling ②): every tier EXCEPT `shell-history` — history files are
|
|
102
|
-
* unrestricted unless a deployment opts the tier in. Derived, not re-listed: a
|
|
103
|
-
*
|
|
116
|
+
* unrestricted unless a deployment opts the tier in. Derived, not re-listed: a tier added to the
|
|
117
|
+
* closed set is default-ON unless this expression is deliberately revisited (`agent-config` joined
|
|
118
|
+
* default-ON this way: an unconfigured deployment refuses the agent's own key-bearing settings files;
|
|
119
|
+
* a deployment that debugs agent configuration selects `tiers` without it).
|
|
104
120
|
*/
|
|
105
121
|
export declare const READ_DENY_DEFAULT_TIERS: readonly ReadDenyBuiltinTier[];
|
|
106
122
|
/**
|