@sema-agent/core 5.7.0 → 5.9.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/agents/cascade.d.ts +1 -1
  3. package/dist/agents/cascade.js +24 -0
  4. package/dist/agents/subagent.d.ts +7 -7
  5. package/dist/agents/subagent.js +74 -33
  6. package/dist/agents/teacher.js +3 -3
  7. package/dist/agents/team.d.ts +1 -1
  8. package/dist/agents/team.js +1 -1
  9. package/dist/agents/verify.js +1 -1
  10. package/dist/brain/anthropic.js +24 -35
  11. package/dist/brain/open-responses.d.ts +11 -0
  12. package/dist/brain/open-responses.js +721 -0
  13. package/dist/brain/openai.js +22 -33
  14. package/dist/brain/request-params.d.ts +1 -0
  15. package/dist/brain/request-params.js +16 -0
  16. package/dist/brain/stream-engine.d.ts +0 -2
  17. package/dist/brain/stream-engine.js +5 -47
  18. package/dist/brain/stream-shared.d.ts +0 -10
  19. package/dist/brain/stream-shared.js +0 -23
  20. package/dist/brain/terminal-cause.d.ts +0 -1
  21. package/dist/brain/terminal-cause.js +0 -3
  22. package/dist/brain/timeout.d.ts +4 -2
  23. package/dist/brain/timeout.js +4 -14
  24. package/dist/config/catalog.d.ts +3 -11
  25. package/dist/config/catalog.js +30 -69
  26. package/dist/config/defaults.d.ts +0 -3
  27. package/dist/config/defaults.js +0 -3
  28. package/dist/core/auto-compaction.d.ts +2 -11
  29. package/dist/core/auto-compaction.js +3 -67
  30. package/dist/core/checkpoint-store.d.ts +10 -8
  31. package/dist/core/checkpoint-store.js +7 -7
  32. package/dist/core/fs-write-gate-policy.js +2 -2
  33. package/dist/core/lsp-diagnostics.d.ts +3 -2
  34. package/dist/core/lsp-diagnostics.js +20 -7
  35. package/dist/core/memory-engine/file-backend.js +20 -17
  36. package/dist/core/memory-engine/layout.d.ts +5 -0
  37. package/dist/core/memory-engine/layout.js +72 -47
  38. package/dist/core/runner/assemble-result.d.ts +3 -8
  39. package/dist/core/runner/assemble-result.js +24 -18
  40. package/dist/core/runner/prepare-task.d.ts +27 -6
  41. package/dist/core/runner/prepare-task.js +209 -144
  42. package/dist/core/runner/runtask.d.ts +0 -2
  43. package/dist/core/runner/runtask.js +228 -266
  44. package/dist/core/runner/session-rule-policy.d.ts +1 -0
  45. package/dist/core/runner/session-rule-policy.js +4 -3
  46. package/dist/core/session-policy-store.d.ts +5 -0
  47. package/dist/core/session-policy-store.js +3 -1
  48. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
  49. package/dist/core/task-registry-agent.d.ts +2 -0
  50. package/dist/core/task-registry-agent.js +33 -1
  51. package/dist/core/task-registry-shared.d.ts +0 -1
  52. package/dist/core/task-registry.d.ts +2 -0
  53. package/dist/core/task-registry.js +9 -1
  54. package/dist/core/tool-errors.js +10 -2
  55. package/dist/core/tool-policy.d.ts +8 -0
  56. package/dist/core/tool-policy.js +11 -0
  57. package/dist/core/trace.d.ts +1 -10
  58. package/dist/core/types.d.ts +27 -30
  59. package/dist/core/usage-window-store.d.ts +39 -0
  60. package/dist/core/usage-window-store.js +115 -0
  61. package/dist/engine/execution-env/node-execution-env.js +0 -22
  62. package/dist/engine/harness/agent-harness.d.ts +1 -7
  63. package/dist/engine/harness/agent-harness.js +16 -53
  64. package/dist/engine/harness/types.d.ts +3 -15
  65. package/dist/engine/llm/types.d.ts +3 -75
  66. package/dist/engine/loop/agent-loop.d.ts +1 -1
  67. package/dist/engine/loop/agent-loop.js +7 -173
  68. package/dist/engine/loop/types.d.ts +1 -18
  69. package/dist/engine/session/repo-utils.d.ts +1 -2
  70. package/dist/engine/session/repo-utils.js +0 -7
  71. package/dist/index.d.ts +13 -7
  72. package/dist/index.js +10 -5
  73. package/dist/internal/llm.d.ts +1 -1
  74. package/dist/orchestration/goal.js +1 -5
  75. package/dist/orchestration/run-workflow-tool.d.ts +1 -1
  76. package/dist/orchestration/run-workflow-tool.js +1 -2
  77. package/dist/orchestration/workflow-governance.d.ts +6 -6
  78. package/dist/orchestration/workflow-governance.js +33 -47
  79. package/dist/orchestration/workflow.js +14 -5
  80. package/dist/prompt-assembly/event-registry.js +2 -3
  81. package/dist/stores/cc/lockfile.js +9 -11
  82. package/dist/stores/cc/mailbox-store.js +49 -38
  83. package/dist/stores/file/index.d.ts +3 -0
  84. package/dist/stores/file/index.js +4 -0
  85. package/dist/stores/file/usage-window-store.d.ts +9 -0
  86. package/dist/stores/file/usage-window-store.js +86 -0
  87. package/dist/tools/fs/fs-bash.d.ts +1 -10
  88. package/dist/tools/fs/fs-bash.js +20 -60
  89. package/dist/tools/fs/index.d.ts +0 -2
  90. package/dist/tools/fs/index.js +1 -2
  91. package/dist/tools/web.js +20 -19
  92. package/package.json +4 -5
  93. package/dist/bin/sema-tb.d.ts +0 -31
  94. package/dist/bin/sema-tb.js +0 -448
  95. package/dist/bin/tb-env.d.ts +0 -2
  96. package/dist/bin/tb-env.js +0 -17
  97. package/dist/brain/walltime.d.ts +0 -1
  98. package/dist/brain/walltime.js +0 -1
  99. package/dist/core/runner/call-cap.d.ts +0 -67
  100. package/dist/core/runner/call-cap.js +0 -145
  101. package/dist/core/runner/cut-kill.d.ts +0 -10
  102. package/dist/core/runner/cut-kill.js +0 -37
@@ -10,13 +10,6 @@ export function createTimestamp() {
10
10
  export function toSession(storage) {
11
11
  return new StoredSession(storage);
12
12
  }
13
- export function getFileSystemResultOrThrow(result, message) {
14
- if (!result.ok) {
15
- const code = result.error.code === "not_found" ? "not_found" : "storage";
16
- throw new SessionError(code, `${message}: ${result.error.message}`, result.error);
17
- }
18
- return result.value;
19
- }
20
13
  function rerootIfHeadless(storage, entries) {
21
14
  const head = entries[0];
22
15
  if (head === undefined || head.parentId === null)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export { Runner, runTask, DEFAULT_MAX_TURNS } from "./core/runner/runtask.js";
1
+ export { Runner, runTask } from "./core/runner/runtask.js";
2
+ export { resolveTaskLimits } from "./core/runner/prepare-task.js";
3
+ export type { BudgetAxis } from "./core/runner/assemble-result.js";
2
4
  export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
3
5
  export type { ResumeTaskConfig } from "./core/runner/runtask.js";
4
6
  export { defineTool } from "./core/tools.js";
@@ -75,7 +77,10 @@ export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW,
75
77
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
76
78
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
77
79
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, type ToolResultStore, type ToolResultSlice, } from "./core/tool-result-store.js";
78
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingWalltimeMs, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, } from "./core/checkpoint-store.js";
80
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
81
+ export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
82
+ export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
83
+ export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
79
84
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
80
85
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
81
86
  export type { FileSnapshotStore, FileSnapshotResult, FileSnapshotError, FileSnapshotBounds } from "./core/file-snapshot-store.js";
@@ -86,7 +91,7 @@ export { brainToRuntime } from "./core/runtime.js";
86
91
  export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
87
92
  export { createFsWriteGatePolicy, type FsWriteGatePolicyOptions } from "./core/fs-write-gate-policy.js";
88
93
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
89
- export { DEFAULT_SUBAGENT_TOOL_NAME, SESSION_BG_DEFAULT_TIMEOUT_SEC } from "./agents/subagent.js";
94
+ export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
90
95
  export { renderTaskNotificationXml, taskNotificationDedupKey, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, } from "./core/task-notification.js";
91
96
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, type SemaTaskType, type SemaTaskStatus, type SemaTaskHandle, type ParkedClaimTicket, type TaskAccess, type UnifiedTaskOutput, type TaskRetrievalStatus, type StopSource, type RegisterMonitorInput, type MonitorTimers, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
92
97
  export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease } from "./core/mailbox-store.js";
@@ -108,7 +113,7 @@ export type { SchedulerCapability, SchedulerErrorCode, ScheduledIntent, Schedule
108
113
  export { createSchedulerTools, type SchedulerToolContext, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
109
114
  export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, type AutonomousLoopPromptOptions, } from "./tools/loop-tick.js";
110
115
  export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
111
- export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, } from "./core/tool-policy.js";
116
+ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, } from "./core/tool-policy.js";
112
117
  export { parseAutoModeResponse, createAutoModeDecider, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassifyFn, type AutoModeClassifyInput, } from "./core/auto-mode.js";
113
118
  export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
114
119
  export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
@@ -146,7 +151,7 @@ export { runSpec, type RunSpecOptions, type RunSpecResult, type RunSpecOracleRep
146
151
  export { isSelfOrchestrationActive, workflowsCapability, selfOrchestrationFailClosedReason, type WorkflowScriptRunner, type WorkflowMeta, type WorkflowPrimitives, } from "./orchestration/workflow-script-runner.js";
147
152
  export { devWorkflowScriptRunner } from "./orchestration/dev-vm-script-runner.js";
148
153
  export { parseWorkflowMeta, splitWorkflowMeta, WorkflowScriptError, workflowScriptReadsClockOrRandom } from "./orchestration/workflow-meta.js";
149
- export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring } from "./orchestration/workflow-sandbox-conformance.js";
154
+ export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, assertWorkflowDeterminism } from "./orchestration/workflow-sandbox-conformance.js";
150
155
  export { WorkflowModelNotAllowedError, type WorkflowAgentSpec } from "./orchestration/workflow-governance.js";
151
156
  export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
152
157
  export { createFileWorkflowScriptStore, mergeWorkflowArgs, type WorkflowScriptStore, type NamedWorkflowResolution, type NamedWorkflowListing, } from "./orchestration/workflow-script-store.js";
@@ -179,7 +184,7 @@ export { MemoryRosterStore, FileRosterStore, type RosterStore, type RosterEntry,
179
184
  export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, type ConfigKnob, type ConfigOverrideDeclaration, type ConfigProvenance, type EffectiveConfigField, } from "./config/catalog.js";
180
185
  export { normalizeAgentName } from "./core/task-registry.js";
181
186
  export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM, TEAMMATE_TASK_LIST_ADDENDUM } from "./prompts/coordinator.js";
182
- export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, FORK_DEFAULT_MAX_TURNS, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
187
+ export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
183
188
  export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
184
189
  export { createSendMessageTool, SEND_MESSAGE_TOOL_NAME, type SendMessageToolOptions } from "./agents/send-message-tool.js";
185
190
  export { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME, type AgentTranscriptToolOptions, } from "./agents/agent-transcript-tool.js";
@@ -190,6 +195,7 @@ export { createTaskServer, type TaskServerOptions, type TaskRequestBody, } from
190
195
  export { clearStaleToolResults, COMPACTABLE_TOOLS, editBudget, type ContextEditOptions, } from "./core/context-edit.js";
191
196
  export { createOpenAIBrain, type OpenAIBrainConfig } from "./brain/openai.js";
192
197
  export { createAnthropicBrain, type AnthropicBrainConfig } from "./brain/anthropic.js";
198
+ export { createOpenResponsesBrain, type OpenResponsesBrainConfig } from "./brain/open-responses.js";
193
199
  export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
194
200
  export { createFailoverBrain } from "./brain/failover.js";
195
201
  export { createRoutingBrain, type RoutingBrainOptions } from "./brain/routing.js";
@@ -200,7 +206,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
200
206
  export { type BrainTimeoutConfig } from "./brain/timeout.js";
201
207
  export { createAssistantMessageEventStream } from "./internal/llm.js";
202
208
  export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
203
- export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
209
+ export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
204
210
  export { Type } from "typebox";
205
211
  export type { TSchema, Static } from "typebox";
206
212
  export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { Runner, runTask, DEFAULT_MAX_TURNS } from "./core/runner/runtask.js";
1
+ export { Runner, runTask } from "./core/runner/runtask.js";
2
+ export { resolveTaskLimits } from "./core/runner/prepare-task.js";
2
3
  export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
3
4
  export { defineTool } from "./core/tools.js";
4
5
  export { SKILL_TOOL_NAME } from "./core/runner/synthetic-tools.js";
@@ -64,7 +65,10 @@ export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW,
64
65
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
65
66
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
66
67
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, } from "./core/tool-result-store.js";
67
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingWalltimeMs, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
68
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
69
+ export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, } from "./core/usage-window-store.js";
70
+ export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
71
+ export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
68
72
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
69
73
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
70
74
  export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, } from "./stores/file/index.js";
@@ -74,7 +78,7 @@ export { brainToRuntime } from "./core/runtime.js";
74
78
  export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
75
79
  export { createFsWriteGatePolicy } from "./core/fs-write-gate-policy.js";
76
80
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
77
- export { DEFAULT_SUBAGENT_TOOL_NAME, SESSION_BG_DEFAULT_TIMEOUT_SEC } from "./agents/subagent.js";
81
+ export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
78
82
  export { renderTaskNotificationXml, taskNotificationDedupKey, SystemInjectionQueue, } from "./core/task-notification.js";
79
83
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
80
84
  export { InMemoryMailboxStore } from "./core/mailbox-store.js";
@@ -131,7 +135,7 @@ export { runSpec } from "./orchestration/run-spec.js";
131
135
  export { isSelfOrchestrationActive, workflowsCapability, selfOrchestrationFailClosedReason, } from "./orchestration/workflow-script-runner.js";
132
136
  export { devWorkflowScriptRunner } from "./orchestration/dev-vm-script-runner.js";
133
137
  export { parseWorkflowMeta, splitWorkflowMeta, WorkflowScriptError, workflowScriptReadsClockOrRandom } from "./orchestration/workflow-meta.js";
134
- export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring } from "./orchestration/workflow-sandbox-conformance.js";
138
+ export { assertWorkflowSandboxConformance, assertWorkflowPrimitivesWiring, assertWorkflowDeterminism } from "./orchestration/workflow-sandbox-conformance.js";
135
139
  export { WorkflowModelNotAllowedError } from "./orchestration/workflow-governance.js";
136
140
  export { WorkflowMaxAgentsError, WorkflowResultTooLargeError } from "./orchestration/workflow.js";
137
141
  export { createFileWorkflowScriptStore, mergeWorkflowArgs, } from "./orchestration/workflow-script-store.js";
@@ -162,7 +166,7 @@ export { MemoryRosterStore, FileRosterStore } from "./agents/roster-store.js";
162
166
  export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, } from "./config/catalog.js";
163
167
  export { normalizeAgentName } from "./core/task-registry.js";
164
168
  export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM, TEAMMATE_TASK_LIST_ADDENDUM } from "./prompts/coordinator.js";
165
- export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, FORK_DEFAULT_MAX_TURNS, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, } from "./agents/subagent.js";
169
+ export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, } from "./agents/subagent.js";
166
170
  export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
167
171
  export { createSendMessageTool, SEND_MESSAGE_TOOL_NAME } from "./agents/send-message-tool.js";
168
172
  export { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME, } from "./agents/agent-transcript-tool.js";
@@ -173,6 +177,7 @@ export { createTaskServer, } from "./server/http.js";
173
177
  export { clearStaleToolResults, COMPACTABLE_TOOLS, editBudget, } from "./core/context-edit.js";
174
178
  export { createOpenAIBrain } from "./brain/openai.js";
175
179
  export { createAnthropicBrain } from "./brain/anthropic.js";
180
+ export { createOpenResponsesBrain } from "./brain/open-responses.js";
176
181
  export { FABLE_5_COMPAT, fable5Model } from "./brain/model-presets.js";
177
182
  export { createFailoverBrain } from "./brain/failover.js";
178
183
  export { createRoutingBrain } from "./brain/routing.js";
@@ -1,2 +1,2 @@
1
1
  export { createAssistantMessageEventStream, stripEngineMetadata } from "../engine/llm/index.js";
2
- export type { AnthropicMessagesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ResilienceOptions, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, Usage, UserMessage, } from "../engine/llm/index.js";
2
+ export type { AnthropicMessagesCompat, OpenAICompletionsCompat, OpenAIResponsesCompat, AssistantMessage, AssistantMessageDiagnostic, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, Model, ResilienceOptions, SimpleStreamOptions, StallTimeouts, StopReason, StreamFn, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, Usage, UserMessage, } from "../engine/llm/index.js";
@@ -148,16 +148,12 @@ export async function runGoal(runner, spec) {
148
148
  if (result.status === "blocked")
149
149
  return mk("blocked", iteration, { result });
150
150
  if (result.status === "failed") {
151
- if (result.errorCode === "limit.max_turns") {
151
+ if (result.errorCode !== undefined && result.errorCode.startsWith("limits.max_")) {
152
152
  lastFeedback = TIMEOUT_FEEDBACK;
153
153
  continue;
154
154
  }
155
155
  return mk("failed", iteration, { result, errorCode: result.errorCode });
156
156
  }
157
- if (result.status === "timeout") {
158
- lastFeedback = TIMEOUT_FEEDBACK;
159
- continue;
160
- }
161
157
  const gate1 = hasOutputSchema ? result.structuredOutput !== undefined : doneRef.declared === true;
162
158
  if (!gate1) {
163
159
  lastFeedback = NOT_DECLARED_FEEDBACK;
@@ -38,7 +38,7 @@ export interface WorkflowLimits {
38
38
  maxScriptChars?: number;
39
39
  maxAgents?: number;
40
40
  totalTimeoutMs?: number;
41
- perAgentTimeoutSec?: number;
41
+ perAgentMaxWalltimeMs?: number;
42
42
  childMaxCostUsd?: number;
43
43
  childMaxTokens?: number;
44
44
  childMaxTurns?: number;
@@ -17,7 +17,6 @@ const DEFAULTS = {
17
17
  maxScriptChars: 100_000,
18
18
  maxAgents: 50,
19
19
  totalTimeoutMs: 600_000,
20
- perAgentTimeoutSec: 300,
21
20
  maxResultChars: 100_000,
22
21
  maxLogChars: 10_000,
23
22
  };
@@ -141,7 +140,7 @@ export async function createRunWorkflowTool(d) {
141
140
  const lim = d.limits ?? {};
142
141
  const maxScriptChars = lim.maxScriptChars ?? DEFAULTS.maxScriptChars;
143
142
  const childCaps = {
144
- perAgentTimeoutSec: lim.perAgentTimeoutSec ?? DEFAULTS.perAgentTimeoutSec,
143
+ perAgentMaxWalltimeMs: lim.perAgentMaxWalltimeMs,
145
144
  childMaxCostUsd: lim.childMaxCostUsd,
146
145
  childMaxTokens: lim.childMaxTokens,
147
146
  childMaxTurns: lim.childMaxTurns,
@@ -13,20 +13,20 @@ export interface WorkflowAgentSpec {
13
13
  images?: ImageInput[];
14
14
  limits?: {
15
15
  maxTurns?: number;
16
- timeoutSec?: number;
16
+ maxWalltimeMs?: number;
17
+ maxTokens?: number;
18
+ maxCostUsd?: number;
17
19
  };
18
- maxCostUsd?: number;
19
- maxTokens?: number;
20
20
  }
21
- export declare const WHITELIST_KEYS: readonly ["objective", "modelName", "thinking", "systemPrompt", "images", "limits", "maxCostUsd", "maxTokens"];
21
+ export declare const WHITELIST_KEYS: readonly ["objective", "modelName", "thinking", "systemPrompt", "images", "limits"];
22
22
  export interface WorkflowChildCaps {
23
- perAgentTimeoutSec?: number;
23
+ perAgentMaxWalltimeMs?: number;
24
24
  childMaxCostUsd?: number;
25
25
  childMaxTokens?: number;
26
26
  childMaxTurns?: number;
27
27
  }
28
28
  export interface ResourceClampNote {
29
- field: "maxCostUsd" | "maxTokens" | "timeoutSec" | "maxTurns";
29
+ field: "maxCostUsd" | "maxTokens" | "maxWalltimeMs" | "maxTurns";
30
30
  requested: number | undefined;
31
31
  applied: number;
32
32
  }
@@ -17,8 +17,6 @@ export const WHITELIST_KEYS = [
17
17
  "systemPrompt",
18
18
  "images",
19
19
  "limits",
20
- "maxCostUsd",
21
- "maxTokens",
22
20
  ];
23
21
  const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
24
22
  export function resolveModelName(name, allowlist, models) {
@@ -91,36 +89,26 @@ function pickWhitelist(scriptSpec) {
91
89
  }
92
90
  if (s.limits !== undefined) {
93
91
  if (typeof s.limits !== "object" || s.limits === null || Array.isArray(s.limits)) {
94
- throw new WorkflowScriptError("agent(spec): `limits` must be an object { maxTurns?, timeoutSec? }");
92
+ throw new WorkflowScriptError("agent(spec): `limits` must be an object { maxTurns?, maxWalltimeMs?, maxTokens?, maxCostUsd? }");
95
93
  }
96
94
  const l = s.limits;
97
95
  const limits = {};
98
- if (l.maxTurns !== undefined) {
99
- if (typeof l.maxTurns !== "number" || !Number.isFinite(l.maxTurns))
100
- throw new WorkflowScriptError("agent(spec): `limits.maxTurns` must be a number");
101
- if (l.maxTurns <= 0)
102
- throw new WorkflowScriptError(NON_POSITIVE_LIMIT_MSG("maxTurns", "turn cap"));
103
- limits.maxTurns = l.maxTurns;
104
- }
105
- if (l.timeoutSec !== undefined) {
106
- if (typeof l.timeoutSec !== "number" || !Number.isFinite(l.timeoutSec))
107
- throw new WorkflowScriptError("agent(spec): `limits.timeoutSec` must be a number");
108
- if (l.timeoutSec <= 0)
109
- throw new WorkflowScriptError(NON_POSITIVE_LIMIT_MSG("timeoutSec", "wall-clock window"));
110
- limits.timeoutSec = l.timeoutSec;
111
- }
96
+ const readAxis = (field, what) => {
97
+ const raw = l[field];
98
+ if (raw === undefined)
99
+ return;
100
+ if (typeof raw !== "number" || !Number.isFinite(raw))
101
+ throw new WorkflowScriptError(`agent(spec): \`limits.${field}\` must be a number`);
102
+ if (raw <= 0)
103
+ throw new WorkflowScriptError(NON_POSITIVE_LIMIT_MSG(field, what));
104
+ limits[field] = raw;
105
+ };
106
+ readAxis("maxTurns", "turn cap");
107
+ readAxis("maxWalltimeMs", "wall-clock window");
108
+ readAxis("maxTokens", "token budget");
109
+ readAxis("maxCostUsd", "spend ceiling");
112
110
  safe.limits = limits;
113
111
  }
114
- if (s.maxCostUsd !== undefined) {
115
- if (typeof s.maxCostUsd !== "number" || !Number.isFinite(s.maxCostUsd))
116
- throw new WorkflowScriptError("agent(spec): `maxCostUsd` must be a number");
117
- safe.maxCostUsd = s.maxCostUsd;
118
- }
119
- if (s.maxTokens !== undefined) {
120
- if (typeof s.maxTokens !== "number" || !Number.isFinite(s.maxTokens))
121
- throw new WorkflowScriptError("agent(spec): `maxTokens` must be a number");
122
- safe.maxTokens = s.maxTokens;
123
- }
124
112
  let modelName;
125
113
  if (s.modelName !== undefined) {
126
114
  if (typeof s.modelName !== "string")
@@ -131,37 +119,35 @@ function pickWhitelist(scriptSpec) {
131
119
  }
132
120
  function clampResourceLimits(safe, base, caps) {
133
121
  const notes = [];
134
- const requestedCost = safe.maxCostUsd;
135
- const cost = minDefined(safe.maxCostUsd, base.maxCostUsd, caps?.childMaxCostUsd);
136
- if (cost !== undefined) {
137
- if (cost !== requestedCost)
138
- notes.push({ field: "maxCostUsd", requested: requestedCost, applied: cost });
139
- safe.maxCostUsd = cost;
140
- }
141
- const requestedTokens = safe.maxTokens;
142
- const tokens = minDefined(safe.maxTokens, base.maxTokens, caps?.childMaxTokens);
143
- if (tokens !== undefined) {
144
- if (tokens !== requestedTokens)
145
- notes.push({ field: "maxTokens", requested: requestedTokens, applied: tokens });
146
- safe.maxTokens = tokens;
147
- }
148
- const requestedTimeoutSec = safe.limits?.timeoutSec;
122
+ const requestedCost = safe.limits?.maxCostUsd;
123
+ const requestedTokens = safe.limits?.maxTokens;
124
+ const requestedWalltimeMs = safe.limits?.maxWalltimeMs;
149
125
  const requestedMaxTurns = safe.limits?.maxTurns;
150
- const timeoutSec = minPositiveDefined(safe.limits?.timeoutSec, base.limits?.timeoutSec, caps?.perAgentTimeoutSec);
126
+ const cost = minDefined(safe.limits?.maxCostUsd, base.limits?.maxCostUsd, caps?.childMaxCostUsd);
127
+ const tokens = minDefined(safe.limits?.maxTokens, base.limits?.maxTokens, caps?.childMaxTokens);
128
+ const maxWalltimeMs = minPositiveDefined(safe.limits?.maxWalltimeMs, base.limits?.maxWalltimeMs, caps?.perAgentMaxWalltimeMs);
151
129
  const maxTurns = minPositiveDefined(safe.limits?.maxTurns, base.limits?.maxTurns, caps?.childMaxTurns);
152
- if (timeoutSec !== undefined && timeoutSec !== requestedTimeoutSec) {
153
- notes.push({ field: "timeoutSec", requested: requestedTimeoutSec, applied: timeoutSec });
130
+ if (cost !== undefined && cost !== requestedCost)
131
+ notes.push({ field: "maxCostUsd", requested: requestedCost, applied: cost });
132
+ if (tokens !== undefined && tokens !== requestedTokens)
133
+ notes.push({ field: "maxTokens", requested: requestedTokens, applied: tokens });
134
+ if (maxWalltimeMs !== undefined && maxWalltimeMs !== requestedWalltimeMs) {
135
+ notes.push({ field: "maxWalltimeMs", requested: requestedWalltimeMs, applied: maxWalltimeMs });
154
136
  }
155
137
  if (maxTurns !== undefined && maxTurns !== requestedMaxTurns) {
156
138
  notes.push({ field: "maxTurns", requested: requestedMaxTurns, applied: maxTurns });
157
139
  }
158
140
  const baseOtherLimits = { ...base.limits };
159
141
  delete baseOtherLimits.maxTurns;
160
- delete baseOtherLimits.timeoutSec;
142
+ delete baseOtherLimits.maxWalltimeMs;
143
+ delete baseOtherLimits.maxTokens;
144
+ delete baseOtherLimits.maxCostUsd;
161
145
  const rebuilt = {
162
146
  ...baseOtherLimits,
163
147
  ...(maxTurns !== undefined ? { maxTurns } : {}),
164
- ...(timeoutSec !== undefined ? { timeoutSec } : {}),
148
+ ...(maxWalltimeMs !== undefined ? { maxWalltimeMs } : {}),
149
+ ...(tokens !== undefined ? { maxTokens: tokens } : {}),
150
+ ...(cost !== undefined ? { maxCostUsd: cost } : {}),
165
151
  };
166
152
  if (base.limits !== undefined || Object.keys(rebuilt).length > 0)
167
153
  safe.limits = rebuilt;
@@ -222,6 +222,14 @@ function normalizeWorkflowHardCap(name, v) {
222
222
  }
223
223
  return v;
224
224
  }
225
+ function normalizeWorkflowStallMs(v) {
226
+ if (v === undefined)
227
+ return WORKFLOW_AGENT_STALL_MS;
228
+ if (!Number.isFinite(v)) {
229
+ throw new Error(`runWorkflow: stallMs must be a finite number of milliseconds (got ${v}); 0 or a negative value is the documented explicit "off", not NaN/Infinity`);
230
+ }
231
+ return v;
232
+ }
225
233
  function createSemaphore(max) {
226
234
  let active = 0;
227
235
  const waiters = [];
@@ -307,12 +315,13 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
307
315
  const maxAgents = normalizeWorkflowHardCap("maxAgents", opts.maxAgents);
308
316
  const maxLogChars = normalizeWorkflowHardCap("maxLogChars", opts.maxLogChars);
309
317
  const maxResultChars = normalizeWorkflowHardCap("maxResultChars", opts.maxResultChars);
310
- const stallMs = opts.stallMs ?? WORKFLOW_AGENT_STALL_MS;
311
- const agentMaxRetries = opts.agentMaxRetries ?? WORKFLOW_AGENT_MAX_RETRIES;
312
- const throttleBackoffMs = opts.throttleBackoffMs ?? WORKFLOW_AGENT_THROTTLE_BACKOFF_MS;
318
+ const totalTimeoutMs = normalizeWorkflowHardCap("totalTimeoutMs", opts.totalTimeoutMs);
319
+ const stallMs = normalizeWorkflowStallMs(opts.stallMs);
320
+ const agentMaxRetries = normalizeWorkflowHardCap("agentMaxRetries", opts.agentMaxRetries) ?? WORKFLOW_AGENT_MAX_RETRIES;
321
+ const throttleBackoffMs = normalizeWorkflowHardCap("throttleBackoffMs", opts.throttleBackoffMs) ?? WORKFLOW_AGENT_THROTTLE_BACKOFF_MS;
313
322
  const timers = opts.timers ?? REAL_WORKFLOW_TIMERS;
314
323
  const cancelController = new AbortController();
315
- const timeoutController = opts.totalTimeoutMs !== undefined ? new AbortController() : undefined;
324
+ const timeoutController = totalTimeoutMs !== undefined ? new AbortController() : undefined;
316
325
  const signalSources = [cancelController.signal];
317
326
  if (opts.signal)
318
327
  signalSources.push(opts.signal);
@@ -375,7 +384,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
375
384
  };
376
385
  markWorkflowActive(runId, scope);
377
386
  if (timeoutController) {
378
- timeoutTimer = setTimeout(() => timeoutController.abort(new Error("workflow total timeout")), opts.totalTimeoutMs);
387
+ timeoutTimer = setTimeout(() => timeoutController.abort(new Error("workflow total timeout")), totalTimeoutMs);
379
388
  timeoutTimer.unref?.();
380
389
  }
381
390
  emit({ type: "run_start", runId, scope, ts: t0 });
@@ -13,9 +13,8 @@ export const EVENT_PROMPT_REGISTRY = new Map([
13
13
  { kind: "skills_listing", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderSkillsListingDelta" },
14
14
  { kind: "mcp_instructions", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderMcpInstructionsDelta" },
15
15
  { kind: "mcp_dropped_tools", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderMcpDroppedTools" },
16
- { kind: "deadline_converge", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#nudgeSchedule" },
17
- { kind: "deadline_deliver_now", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#nudgeSchedule" },
18
- { kind: "deadline_finalize", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#buildFinalizeText" },
16
+ { kind: "limit_approach_converge", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#limitApproachFrames" },
17
+ { kind: "limit_approach_deliver", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#limitApproachFrames" },
19
18
  { kind: "final_verification", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#final-verification" },
20
19
  ].map((e) => [e.kind, e]));
21
20
  export function eventDefaultOn(kind) {
@@ -20,6 +20,9 @@ export async function acquireCcLock(target, opts) {
20
20
  }
21
21
  };
22
22
  for (let attempt = 0;; attempt++) {
23
+ if (attempt >= RETRIES) {
24
+ throw new Error(`cc lockfile: could not acquire ${lockPath} after ${RETRIES} retries`);
25
+ }
23
26
  try {
24
27
  mkdirSync(lockPath);
25
28
  writeFileSync(ownerPath, nonce);
@@ -60,21 +63,16 @@ export async function acquireCcLock(target, opts) {
60
63
  const st = statSync(lockPath);
61
64
  if (Date.now() - st.mtimeMs > staleMs) {
62
65
  const st2 = statSync(lockPath);
63
- if (st2.mtimeMs !== st.mtimeMs)
64
- continue;
65
- try {
66
- rmSync(lockPath, { recursive: true, force: true });
67
- }
68
- catch {
66
+ if (st2.mtimeMs === st.mtimeMs) {
67
+ try {
68
+ rmSync(lockPath, { recursive: true, force: true });
69
+ }
70
+ catch {
71
+ }
69
72
  }
70
- continue;
71
73
  }
72
74
  }
73
75
  catch {
74
- continue;
75
- }
76
- if (attempt >= RETRIES) {
77
- throw new Error(`cc lockfile: could not acquire ${lockPath} after ${RETRIES} retries (held and fresh)`);
78
76
  }
79
77
  const backoff = Math.min(MAX_TIMEOUT_MS, MIN_TIMEOUT_MS * 2 ** attempt);
80
78
  await sleep(backoff / 2 + Math.random() * (backoff / 2));
@@ -3,6 +3,7 @@ import { join, resolve } from "node:path";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { atomicWriteFile, canonicalStoreKey } from "../file/fs-atomic.js";
5
5
  import { withCcLock } from "./lockfile.js";
6
+ const INBOX_FILE_EXT = ".json";
6
7
  export function sanitizeCcAgentName(name) {
7
8
  return name.replace(/[^a-zA-Z0-9]/g, "-").toLowerCase();
8
9
  }
@@ -23,10 +24,8 @@ export function createCcFileMailboxStore(opts) {
23
24
  throw new Error(`CcFileMailboxStore: CC inbox files carry no tenant axis — scope:"default" only (D-1); got ${JSON.stringify(scope)}`);
24
25
  }
25
26
  };
26
- const inboxPath = (handle) => {
27
- const name = opts.agentNameOf?.(handle) ?? handle;
28
- return join(inboxDir, `${sanitizeCcAgentName(name)}.json`);
29
- };
27
+ const leaseKey = (handle) => sanitizeCcAgentName(opts.agentNameOf?.(handle) ?? handle);
28
+ const inboxPath = (handle) => join(inboxDir, `${leaseKey(handle)}${INBOX_FILE_EXT}`);
30
29
  const discloseCorrupt = (path, reason) => {
31
30
  try {
32
31
  opts.onCorruptRead?.({ path, reason });
@@ -98,6 +97,42 @@ export function createCcFileMailboxStore(opts) {
98
97
  const saveBox = (path, box) => {
99
98
  atomicWriteFile(inboxDir, path, JSON.stringify(box, null, 2));
100
99
  };
100
+ const isColderThan = (box, now, maxAgeMs) => {
101
+ if (box.length === 0)
102
+ return false;
103
+ const newest = box.reduce((acc, e) => {
104
+ const t = typeof e.timestamp === "string" ? Date.parse(e.timestamp) : Number.NaN;
105
+ return Number.isFinite(t) ? Math.max(acc, t) : Number.POSITIVE_INFINITY;
106
+ }, 0);
107
+ return newest !== Number.POSITIVE_INFINITY && now - newest > maxAgeMs;
108
+ };
109
+ const sweepColdBoxes = async (now, maxAgeMs) => {
110
+ let dropped = 0;
111
+ for (const f of readdirSync(inboxDir)) {
112
+ if (!f.endsWith(INBOX_FILE_EXT))
113
+ continue;
114
+ const path = join(inboxDir, f);
115
+ const boxKey = f.slice(0, -INBOX_FILE_EXT.length);
116
+ const preNotes = deferredNotes();
117
+ if (!isColderThan(loadBox(path, preNotes.note), now, maxAgeMs)) {
118
+ preNotes.flush();
119
+ continue;
120
+ }
121
+ const notes = deferredNotes();
122
+ const swept = await withCcLock(path, () => {
123
+ if (!isColderThan(loadBox(path, notes.note), now, maxAgeMs))
124
+ return false;
125
+ leases.delete(boxKey);
126
+ rmSync(path, { force: true });
127
+ return true;
128
+ }).finally(() => {
129
+ notes.flush();
130
+ });
131
+ if (swept)
132
+ dropped += 1;
133
+ }
134
+ return dropped;
135
+ };
101
136
  return {
102
137
  append: (scope, handle, msg) => {
103
138
  requireDefaultScope(scope);
@@ -124,11 +159,12 @@ export function createCcFileMailboxStore(opts) {
124
159
  claimLease: (scope, handle, owner, ttlMs, now) => {
125
160
  requireDefaultScope(scope);
126
161
  const t = now ?? opts.now?.() ?? Date.now();
127
- const key = inboxPath(handle);
162
+ const key = leaseKey(handle);
163
+ const path = inboxPath(handle);
128
164
  const held = leases.get(key);
129
165
  if (held !== undefined && held.expiresAt > t && held.owner !== owner)
130
166
  return Promise.resolve(null);
131
- const box = loadBox(key, discloseCorrupt);
167
+ const box = loadBox(path, discloseCorrupt);
132
168
  const maxSeq = box.length;
133
169
  const pending = box
134
170
  .map((e, i) => ({ e, seq: i + 1 }))
@@ -147,7 +183,7 @@ export function createCcFileMailboxStore(opts) {
147
183
  ack: (scope, handle, owner, upToSeq) => {
148
184
  requireDefaultScope(scope);
149
185
  const path = inboxPath(handle);
150
- const held = leases.get(path);
186
+ const held = leases.get(leaseKey(handle));
151
187
  if (held === undefined || held.owner !== owner)
152
188
  return Promise.resolve();
153
189
  if (!existsSync(path))
@@ -165,14 +201,14 @@ export function createCcFileMailboxStore(opts) {
165
201
  if (changed)
166
202
  saveBox(path, box);
167
203
  if (held.maxSeq <= upToSeq)
168
- leases.delete(path);
204
+ leases.delete(leaseKey(handle));
169
205
  }).finally(() => {
170
206
  notes.flush();
171
207
  });
172
208
  },
173
209
  releaseLease: (scope, handle, owner) => {
174
210
  requireDefaultScope(scope);
175
- const key = inboxPath(handle);
211
+ const key = leaseKey(handle);
176
212
  const held = leases.get(key);
177
213
  if (held !== undefined && held.owner === owner)
178
214
  leases.delete(key);
@@ -185,42 +221,17 @@ export function createCcFileMailboxStore(opts) {
185
221
  drop: (scope, handle) => {
186
222
  requireDefaultScope(scope);
187
223
  const path = inboxPath(handle);
188
- leases.delete(path);
189
- try {
224
+ leases.delete(leaseKey(handle));
225
+ return withCcLock(path, () => {
190
226
  rmSync(path, { force: true });
191
- rmSync(`${path}.lock`, { recursive: true, force: true });
192
- }
193
- catch {
194
- }
195
- return Promise.resolve();
227
+ });
196
228
  },
197
229
  reap: (scope, now, reapOpts) => {
198
230
  requireDefaultScope(scope);
199
231
  const maxAgeMs = reapOpts?.maxAgeMs;
200
232
  if (maxAgeMs === undefined || !existsSync(inboxDir))
201
233
  return Promise.resolve(0);
202
- let dropped = 0;
203
- for (const f of readdirSync(inboxDir)) {
204
- if (!f.endsWith(".json"))
205
- continue;
206
- const path = join(inboxDir, f);
207
- const box = loadBox(path, discloseCorrupt);
208
- const newest = box.reduce((acc, e) => {
209
- const t = typeof e.timestamp === "string" ? Date.parse(e.timestamp) : Number.NaN;
210
- return Number.isFinite(t) ? Math.max(acc, t) : Number.POSITIVE_INFINITY;
211
- }, 0);
212
- if (box.length > 0 && newest !== Number.POSITIVE_INFINITY && now - newest > maxAgeMs) {
213
- leases.delete(path);
214
- try {
215
- rmSync(path, { force: true });
216
- rmSync(`${path}.lock`, { recursive: true, force: true });
217
- dropped += 1;
218
- }
219
- catch {
220
- }
221
- }
222
- }
223
- return Promise.resolve(dropped);
234
+ return sweepColdBoxes(now, maxAgeMs);
224
235
  },
225
236
  };
226
237
  }
@@ -7,6 +7,7 @@ import { type FileCheckpointStoreOptions } from "./checkpoint-store.js";
7
7
  import type { SessionPolicyStore } from "../../core/session-policy-store.js";
8
8
  import type { FileSnapshotStore } from "../../core/file-snapshot-store.js";
9
9
  import type { WorkflowJournalStore } from "../../core/workflow-journal-store.js";
10
+ import type { UsageWindowStore } from "../../core/usage-window-store.js";
10
11
  export { FileCheckpointStore, type FileCheckpointStoreOptions } from "./checkpoint-store.js";
11
12
  export { FileMemoryStore } from "./memory-store.js";
12
13
  export { FileSessionRepo, type FileSessionRepoOptions } from "./session-store.js";
@@ -14,6 +15,7 @@ export { FileToolResultStore } from "./tool-result-store.js";
14
15
  export { FileSessionPolicyStore, type FileSessionPolicyStoreOptions, type SessionPolicyCorruptReadInfo } from "./session-policy-store.js";
15
16
  export { FileFileSnapshotStore, type FileFileSnapshotStoreOptions } from "./file-snapshot-store.js";
16
17
  export { FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult } from "./workflow-journal-store.js";
18
+ export { FileUsageWindowStore } from "./usage-window-store.js";
17
19
  export { resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock } from "./fs-atomic.js";
18
20
  export { atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog } from "./fs-atomic.js";
19
21
  export interface FileStorageBackendOptions {
@@ -40,6 +42,7 @@ export declare class FileStorageBackend {
40
42
  readonly sessionPolicyStore: SessionPolicyStore;
41
43
  readonly fileSnapshotStore: FileSnapshotStore;
42
44
  readonly workflowJournalStore: WorkflowJournalStore;
45
+ readonly usageWindowStore: UsageWindowStore;
43
46
  readonly consolidationLock: (scope: string) => (() => void) | undefined;
44
47
  private readonly lock;
45
48
  private readonly fileCheckpoints;