@cuylabs/agent-core 0.9.0 → 0.10.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 (116) hide show
  1. package/README.md +33 -17
  2. package/dist/chunk-2O4MCSQS.js +780 -0
  3. package/dist/chunk-2TTOLHBT.js +198 -0
  4. package/dist/chunk-5FMSGQVX.js +281 -0
  5. package/dist/chunk-5NVVNXPQ.js +288 -0
  6. package/dist/{chunk-EKR6PKXU.js → chunk-6HZBHFOL.js} +3 -3
  7. package/dist/chunk-CJI7PVS2.js +58 -0
  8. package/dist/{chunk-WKHDSSXG.js → chunk-CMYN2RCB.js} +146 -46
  9. package/dist/chunk-FII65CN7.js +117 -0
  10. package/dist/{chunk-UHCJEM2E.js → chunk-ICZ66572.js} +13 -6
  11. package/dist/chunk-KYLPMBHD.js +316 -0
  12. package/dist/chunk-MXAP4UG6.js +2956 -0
  13. package/dist/{chunk-4QFNWPIF.js → chunk-N3VX7FEE.js} +35 -2
  14. package/dist/{chunk-MAZ5DY5B.js → chunk-NDZWXCBZ.js} +213 -78
  15. package/dist/{chunk-MHKK374K.js → chunk-Q742PSH3.js} +11 -27
  16. package/dist/{chunk-WGZAPU6N.js → chunk-QAL3OMI3.js} +15 -1
  17. package/dist/{chunk-UDCZ673N.js → chunk-RN6WZEUF.js} +27 -23
  18. package/dist/{chunk-ZXAKHMWH.js → chunk-ROTGCYDW.js} +22 -84
  19. package/dist/chunk-SPBFQXOT.js +0 -0
  20. package/dist/chunk-SSFBF3US.js +602 -0
  21. package/dist/chunk-SZ2XBPTW.js +8 -0
  22. package/dist/chunk-T4UIX5D7.js +115 -0
  23. package/dist/{chunk-IYWQOJMQ.js → chunk-TIHPYVAJ.js} +34 -34
  24. package/dist/{chunk-RKEW5WXI.js → chunk-TOTDGK3P.js} +1 -1
  25. package/dist/chunk-V4RFNEET.js +563 -0
  26. package/dist/chunk-VOUEJSW6.js +0 -0
  27. package/dist/{chunk-J4QDGZIA.js → chunk-WBPOZ7CL.js} +659 -275
  28. package/dist/chunk-X4VN4GIJ.js +185 -0
  29. package/dist/dispatch/index.d.ts +93 -0
  30. package/dist/dispatch/index.js +37 -0
  31. package/dist/events/index.d.ts +93 -0
  32. package/dist/events/index.js +6 -0
  33. package/dist/{runtime → execution}/index.d.ts +120 -35
  34. package/dist/{runtime → execution}/index.js +17 -11
  35. package/dist/index.d.ts +489 -115
  36. package/dist/index.js +1665 -462
  37. package/dist/inference/errors/index.js +1 -1
  38. package/dist/inference/index.d.ts +13 -21
  39. package/dist/inference/index.js +15 -12
  40. package/dist/instance-BqV2D5pc.d.ts +5723 -0
  41. package/dist/logger/index.d.ts +50 -0
  42. package/dist/logger/index.js +11 -0
  43. package/dist/mcp/index.d.ts +5 -9
  44. package/dist/mcp/index.js +2 -3
  45. package/dist/middleware/index.d.ts +10 -150
  46. package/dist/middleware/index.js +10 -2
  47. package/dist/model-messages-B4nK9D1-.d.ts +13 -0
  48. package/dist/models/index.d.ts +5 -2
  49. package/dist/models/index.js +2 -1
  50. package/dist/models/reasoning/index.js +2 -1
  51. package/dist/plugin/index.d.ts +55 -11
  52. package/dist/plugin/index.js +1 -1
  53. package/dist/profiles/index.d.ts +55 -0
  54. package/dist/{presets → profiles}/index.js +10 -10
  55. package/dist/prompt/index.d.ts +8 -13
  56. package/dist/safety/index.d.ts +109 -14
  57. package/dist/safety/index.js +59 -3
  58. package/dist/sandbox/index.d.ts +81 -0
  59. package/dist/sandbox/index.js +1 -0
  60. package/dist/skill/index.d.ts +10 -8
  61. package/dist/skill/index.js +2 -2
  62. package/dist/storage/index.d.ts +12 -4
  63. package/dist/storage/index.js +1 -1
  64. package/dist/subagents/index.d.ts +177 -0
  65. package/dist/subagents/index.js +78 -0
  66. package/dist/team/index.d.ts +544 -0
  67. package/dist/team/index.js +41 -0
  68. package/dist/tool/host/index.d.ts +41 -0
  69. package/dist/tool/host/index.js +10 -0
  70. package/dist/tool/index.d.ts +111 -21
  71. package/dist/tool/index.js +20 -13
  72. package/dist/{types-VQgymC1N.d.ts → types-Bj_J8u_W.d.ts} +44 -64
  73. package/dist/{types-CHiPh8U2.d.ts → types-C_LCeYNg.d.ts} +7 -7
  74. package/dist/types-RSCv7nQ4.d.ts +59 -0
  75. package/package.json +46 -47
  76. package/dist/builder-BgZ_j4Vs.d.ts +0 -35
  77. package/dist/chunk-5ARZJWD2.js +0 -259
  78. package/dist/chunk-DXFBQMXP.js +0 -53
  79. package/dist/chunk-H3FUYU52.js +0 -81
  80. package/dist/chunk-JLXG2SH7.js +0 -905
  81. package/dist/chunk-N7P4PN3O.js +0 -84
  82. package/dist/chunk-OFDKHNCX.js +0 -727
  83. package/dist/chunk-SDSBEQXG.js +0 -157
  84. package/dist/chunk-VEKUXUVF.js +0 -41
  85. package/dist/chunk-VNQBHPCT.js +0 -398
  86. package/dist/chunk-WWYYNWEW.js +0 -259
  87. package/dist/context/index.d.ts +0 -259
  88. package/dist/context/index.js +0 -26
  89. package/dist/events-CE72w8W4.d.ts +0 -149
  90. package/dist/host/index.d.ts +0 -45
  91. package/dist/host/index.js +0 -8
  92. package/dist/index-DQuTZ8xL.d.ts +0 -1335
  93. package/dist/messages-BYWGn8TY.d.ts +0 -110
  94. package/dist/presets/index.d.ts +0 -53
  95. package/dist/registry-DwYqsQkX.d.ts +0 -164
  96. package/dist/runner-CI-XeR16.d.ts +0 -91
  97. package/dist/scope/index.d.ts +0 -10
  98. package/dist/scope/index.js +0 -14
  99. package/dist/session-manager-KbYt2WUh.d.ts +0 -282
  100. package/dist/signal/index.d.ts +0 -28
  101. package/dist/signal/index.js +0 -6
  102. package/dist/sub-agent/index.d.ts +0 -24
  103. package/dist/sub-agent/index.js +0 -32
  104. package/dist/tool-CZWN3KbO.d.ts +0 -141
  105. package/dist/tool-DkhSCV2Y.d.ts +0 -145
  106. package/dist/tracker-DClqYqTj.d.ts +0 -96
  107. package/dist/tracking/index.d.ts +0 -111
  108. package/dist/tracking/index.js +0 -20
  109. package/dist/types-BfNpU8NS.d.ts +0 -270
  110. package/dist/types-BlOKk-Bb.d.ts +0 -330
  111. package/dist/types-BlZwmnuW.d.ts +0 -50
  112. package/dist/types-CQL-SvTn.d.ts +0 -29
  113. package/dist/types-CWm-7rvB.d.ts +0 -55
  114. package/dist/types-DTSkxakL.d.ts +0 -651
  115. package/dist/types-DmDwi2zI.d.ts +0 -339
  116. package/dist/types-YuWV4ag7.d.ts +0 -72
package/dist/index.js CHANGED
@@ -1,36 +1,93 @@
1
1
  import {
2
- DEFAULT_MAX_CONCURRENT,
3
- DEFAULT_MAX_SPAWN_DEPTH,
4
- DEFAULT_SESSION_TITLE_PREFIX,
5
- SubAgentTracker,
2
+ DEFAULT_SUBAGENT_CONCURRENCY,
3
+ DEFAULT_SUBAGENT_DEPTH,
4
+ DEFAULT_SUBAGENT_SESSION_PREFIX,
5
+ LOCAL_SUBAGENT_BACKEND,
6
+ SUBAGENT_TOOL_IDS,
7
+ clearInstalledSubAgents,
8
+ configureSubAgents,
9
+ createCloseAgentTool,
10
+ createInvokeAgentTool,
6
11
  createSubAgentTools,
7
- discoverAgentProfiles,
8
- getProjectAgentsDir,
9
- getUserAgentsDir,
10
- isMarkdownProfile,
11
- parseAgentFrontmatter,
12
- parseMarkdownAgent,
13
- parseToolSpec,
14
- toAgentProfile
15
- } from "./chunk-JLXG2SH7.js";
12
+ createWaitAgentTool,
13
+ discoverSubAgentRoles,
14
+ formatAsyncSpawnedResult,
15
+ formatCancelledAgentResult,
16
+ formatCloseAlreadyResolvedResult,
17
+ formatCloseMissingAgentResult,
18
+ formatInvalidAgentTypeResult,
19
+ formatMissingAgentsResult,
20
+ formatSpawnBlockedResult,
21
+ formatSyncSubAgentErrorResult,
22
+ formatSyncSubAgentResult,
23
+ formatWaitErrorResult,
24
+ formatWaitResult,
25
+ formatWaitTimeoutResult,
26
+ getConfiguredSubAgents,
27
+ getInstalledSubAgentBackend,
28
+ getProjectSubAgentRolesDir,
29
+ getUserSubAgentRolesDir,
30
+ installLocalSubAgents,
31
+ installSubAgentTools,
32
+ isMarkdownSubAgentRole,
33
+ parseMarkdownSubAgentRole,
34
+ parseSubAgentRoleFrontmatter,
35
+ parseSubAgentToolSpec,
36
+ toSubAgentRole
37
+ } from "./chunk-2O4MCSQS.js";
38
+ import {
39
+ InMemoryMailboxStore,
40
+ InMemoryTaskBoardStore,
41
+ Mailbox,
42
+ TERMINAL_STATUSES,
43
+ TaskBoard,
44
+ TaskConflictError,
45
+ TeamCoordinator,
46
+ addTokenUsage,
47
+ buildCoordinatorNotificationEvent,
48
+ buildCoordinatorSystemPrompt,
49
+ coordinatorToolDescriptions,
50
+ createTeamCoordinator,
51
+ evaluateCoordinatorRoundTransition,
52
+ formatCoordinatorRoundMessage,
53
+ formatCoordinatorTaskNotifications,
54
+ formatCoordinatorWorkerReports,
55
+ teamPermissionPolicy
56
+ } from "./chunk-MXAP4UG6.js";
16
57
  import {
17
58
  ToolRegistry,
59
+ createToolSearchTool,
18
60
  defaultRegistry
19
- } from "./chunk-SDSBEQXG.js";
61
+ } from "./chunk-KYLPMBHD.js";
20
62
  import {
21
- TurnChangeTracker,
22
- clearCheckpoints,
23
- createCheckpointManager,
24
- createTurnTracker
25
- } from "./chunk-OFDKHNCX.js";
63
+ ToolHostRegistry,
64
+ defaultToolHostRegistry,
65
+ localHost
66
+ } from "./chunk-X4VN4GIJ.js";
26
67
  import {
27
- applyPreset,
28
- createPreset,
68
+ LayeredSettings,
69
+ NullSettings,
70
+ PluginEventBus,
71
+ PluginRegistry,
72
+ StaticSettings,
73
+ ValidatedSettings,
74
+ definePlugin,
75
+ discoverPlugins,
76
+ getPluginLoader,
77
+ isDefinedPlugin,
78
+ loadPluginModule,
79
+ resetFrameworkAliases,
80
+ resetPluginLoader,
81
+ resolveFrameworkAliases
82
+ } from "./chunk-QAL3OMI3.js";
83
+ import {
84
+ applyProfile,
85
+ createProfile,
29
86
  filterTools,
30
- mergePresets
31
- } from "./chunk-IYWQOJMQ.js";
87
+ mergeProfiles
88
+ } from "./chunk-TIHPYVAJ.js";
32
89
  import {
33
- Presets,
90
+ Profiles,
34
91
  careful,
35
92
  code,
36
93
  explore,
@@ -38,7 +95,7 @@ import {
38
95
  quick,
39
96
  review,
40
97
  watch
41
- } from "./chunk-EKR6PKXU.js";
98
+ } from "./chunk-6HZBHFOL.js";
42
99
  import {
43
100
  DEFAULT_INSTRUCTION_PATTERNS,
44
101
  DEFAULT_MAX_DEPTH,
@@ -61,58 +118,12 @@ import {
61
118
  loadGlobalInstructions,
62
119
  summarizeEnvironment
63
120
  } from "./chunk-GFTW23FV.js";
64
- import {
65
- AgentTurnEngine,
66
- ContextOverflowError,
67
- DoomLoopError,
68
- advanceAgentTurnState,
69
- applyAgentWorkflowCommitResult,
70
- applyAgentWorkflowModelStepResult,
71
- applyAgentWorkflowToolBatchResult,
72
- applyAgentWorkflowToolCallResult,
73
- cloneAgentWorkflowTurnState,
74
- commitOutput,
75
- commitStep,
76
- convertAgentMessagesToModelMessages,
77
- createAgentTaskRunner,
78
- createAgentTurnEngine,
79
- createAgentTurnState,
80
- createAgentTurnStepCommitBatch,
81
- createAgentWorkflowTurnState,
82
- defaultAgentTaskCheckpointStrategy,
83
- failAgentTurnState,
84
- failAgentWorkflowTurnState,
85
- planNextAgentWorkflowOperation,
86
- prepareModelStep,
87
- processStepStream,
88
- processStream,
89
- recordAgentWorkflowReplayDecision,
90
- restoreAgentWorkflowMessage,
91
- restoreAgentWorkflowMessages,
92
- runModelStep,
93
- runToolBatch,
94
- snapshotAgentWorkflowMessage,
95
- snapshotAgentWorkflowMessages
96
- } from "./chunk-J4QDGZIA.js";
97
- import {
98
- LocalSignal
99
- } from "./chunk-DXFBQMXP.js";
121
+ import "./chunk-VOUEJSW6.js";
100
122
  import {
101
123
  createSkillResourceTool,
102
124
  createSkillTool,
103
125
  createSkillTools
104
- } from "./chunk-RKEW5WXI.js";
105
- import {
106
- MAX_BYTES,
107
- MAX_LINES,
108
- TRUNCATE_DIR,
109
- TRUNCATE_GLOB,
110
- Tool,
111
- defineTool,
112
- formatSize,
113
- normalizeToolReplayPolicy,
114
- truncateOutput
115
- } from "./chunk-MHKK374K.js";
126
+ } from "./chunk-TOTDGK3P.js";
116
127
  import {
117
128
  DEFAULT_EXTERNAL_DIRS,
118
129
  DEFAULT_MAX_SCAN_DEPTH,
@@ -128,6 +139,38 @@ import {
128
139
  loadSkillMetadata,
129
140
  parseFrontmatter
130
141
  } from "./chunk-SPILYYDF.js";
142
+ import {
143
+ createCompositeDispatchTaskExecutor,
144
+ createDispatchExternalTaskControl,
145
+ createDispatchTaskExecutor,
146
+ createRuntimeDispatchExecutor,
147
+ createRuntimeDispatchTargets,
148
+ ensureNonEmpty,
149
+ mergeInspection
150
+ } from "./chunk-5FMSGQVX.js";
151
+ import {
152
+ DEFAULT_DISPATCH_TOOL_IDS,
153
+ DEFAULT_LOCAL_DISPATCH_CONCURRENCY,
154
+ DEFAULT_LOCAL_DISPATCH_DEPTH,
155
+ DEFAULT_LOCAL_DISPATCH_TITLE_PREFIX,
156
+ DISPATCH_STATES,
157
+ createDispatchTools,
158
+ createLocalDispatchRuntime,
159
+ createSubAgentRunSession,
160
+ ensureSessionLoaded,
161
+ getVisibleSessionMessages,
162
+ repairOrphanedToolCalls
163
+ } from "./chunk-SSFBF3US.js";
164
+ import {
165
+ sleep
166
+ } from "./chunk-SZ2XBPTW.js";
167
+ import {
168
+ MAX_BYTES,
169
+ MAX_LINES,
170
+ Tool,
171
+ normalizeToolReplayPolicy,
172
+ truncateOutput
173
+ } from "./chunk-Q742PSH3.js";
131
174
  import {
132
175
  FileStorage,
133
176
  MemoryStorage,
@@ -152,50 +195,78 @@ import {
152
195
  serializeMessage,
153
196
  toJSONL,
154
197
  toJSONLBatch
155
- } from "./chunk-UHCJEM2E.js";
198
+ } from "./chunk-ICZ66572.js";
199
+ import {
200
+ createEventBus
201
+ } from "./chunk-2TTOLHBT.js";
156
202
  import {
203
+ AgentTurnEngine,
157
204
  ContextManager,
205
+ ContextOverflowError,
158
206
  DEFAULT_CONTEXT_LIMITS,
159
- PRUNE_PROTECTED_TOOLS,
207
+ DoomLoopError,
208
+ advanceAgentTurnState,
209
+ applyAgentWorkflowCommitResult,
210
+ applyAgentWorkflowModelStepResult,
211
+ applyAgentWorkflowToolBatchResult,
212
+ applyAgentWorkflowToolCallResult,
213
+ applyWorkflowInterventions,
214
+ cloneAgentWorkflowTurnState,
215
+ commitOutput,
216
+ commitStep,
217
+ createAgentTaskRunner,
218
+ createAgentTurnEngine,
219
+ createAgentTurnState,
220
+ createAgentTurnStepCommitBatch,
221
+ createAgentWorkflowTurnState,
222
+ defaultAgentTaskCheckpointStrategy,
223
+ drainWorkflowInterventions,
160
224
  estimateConversationTokens,
161
225
  estimateMessageTokens,
162
226
  estimateTokens,
227
+ failAgentTurnState,
228
+ failAgentWorkflowTurnState,
163
229
  findCutPoint,
164
- generateSummary,
165
- isContextOverflowing,
166
- pruneContext,
167
- pruneToolResults,
168
- shouldPruneContext
169
- } from "./chunk-WWYYNWEW.js";
170
- import {
171
- dockerHost,
172
- localHost
173
- } from "./chunk-VNQBHPCT.js";
230
+ getUsableTokenLimit,
231
+ planNextAgentWorkflowOperation,
232
+ prepareModelStep,
233
+ processStepStream,
234
+ queueWorkflowFollowUps,
235
+ recordAgentWorkflowReplayDecision,
236
+ restoreAgentWorkflowMessage,
237
+ restoreAgentWorkflowMessages,
238
+ runModelStep,
239
+ runToolBatch,
240
+ snapshotAgentWorkflowMessage,
241
+ snapshotAgentWorkflowMessages
242
+ } from "./chunk-WBPOZ7CL.js";
174
243
  import {
175
- DEFAULT_MAX_OUTPUT_TOKENS,
176
244
  DEFAULT_RETRY_CONFIG,
177
245
  Inference,
178
- LLM,
179
- OUTPUT_TOKEN_MAX,
246
+ buildModelCallContext,
180
247
  buildToolSet,
181
248
  calculateDelay,
249
+ convertAgentMessagesToModelMessages,
182
250
  createRetryHandler,
183
251
  createRetryState,
184
252
  shouldRetry,
185
- sleep,
186
253
  stream,
187
254
  streamOnce,
188
255
  streamStep,
189
256
  withRetry
190
- } from "./chunk-WKHDSSXG.js";
191
- import {
192
- executeAgentToolCall
193
- } from "./chunk-H3FUYU52.js";
257
+ } from "./chunk-CMYN2RCB.js";
194
258
  import {
259
+ PRUNE_PROTECTED_TOOLS,
260
+ accumulateUsage,
261
+ currentScope,
262
+ executeAgentToolCall,
195
263
  extractFilePathsFromArgs,
264
+ restoreScope,
196
265
  shouldCaptureBaseline,
197
- withFileTracking
198
- } from "./chunk-VEKUXUVF.js";
266
+ snapshotScope,
267
+ streamWithinScope,
268
+ withinScope
269
+ } from "./chunk-5NVVNXPQ.js";
199
270
  import {
200
271
  LLMError,
201
272
  getErrorCategory,
@@ -203,35 +274,7 @@ import {
203
274
  isRetryable,
204
275
  isRetryableCategory,
205
276
  parseRetryDelay
206
- } from "./chunk-4QFNWPIF.js";
207
- import {
208
- createScope,
209
- currentScope,
210
- restoreScope,
211
- snapshotScope,
212
- streamWithinScope,
213
- withinScope
214
- } from "./chunk-N7P4PN3O.js";
215
- import {
216
- createMCPManager,
217
- defineServer,
218
- httpServer,
219
- sseServer,
220
- stdioServer
221
- } from "./chunk-ZXAKHMWH.js";
222
- import {
223
- MiddlewareRunner,
224
- approvalMiddleware,
225
- createTelemetryConfig,
226
- otelMiddleware,
227
- promptCacheMiddleware
228
- } from "./chunk-MAZ5DY5B.js";
229
- import {
230
- ApprovalDeniedError,
231
- ApprovalTimeoutError,
232
- createApprovalHandler,
233
- getToolRisk
234
- } from "./chunk-5ARZJWD2.js";
277
+ } from "./chunk-N3VX7FEE.js";
235
278
  import {
236
279
  CacheCapabilitySource,
237
280
  CapabilityCache,
@@ -262,7 +305,31 @@ import {
262
305
  shouldIncludeReasoningSummary,
263
306
  supportsReasoning,
264
307
  supportsReasoningSync
265
- } from "./chunk-UDCZ673N.js";
308
+ } from "./chunk-RN6WZEUF.js";
309
+ import "./chunk-SPBFQXOT.js";
310
+ import {
311
+ createMCPManager,
312
+ httpServer,
313
+ sseServer,
314
+ stdioServer
315
+ } from "./chunk-ROTGCYDW.js";
316
+ import {
317
+ MiddlewareRunner,
318
+ approvalMiddleware,
319
+ createTelemetryConfig,
320
+ isApprovalMiddleware,
321
+ otelMiddleware,
322
+ promptCacheMiddleware
323
+ } from "./chunk-NDZWXCBZ.js";
324
+ import {
325
+ DEFAULT_AGENT_NAME,
326
+ DEFAULT_MAX_STEPS,
327
+ DEFAULT_MAX_TOKENS,
328
+ DEFAULT_SYSTEM_PROMPT,
329
+ isBlockedModelCall,
330
+ resolveAgentDefaults,
331
+ sandboxDefaultsProvider
332
+ } from "./chunk-CJI7PVS2.js";
266
333
  import {
267
334
  DEFAULT_RESOLVER_OPTIONS,
268
335
  PatternCapabilitySource,
@@ -277,23 +344,419 @@ import {
277
344
  likelySupportsReasoning
278
345
  } from "./chunk-I6PKJ7XQ.js";
279
346
  import {
280
- LayeredSettings,
281
- NullSettings,
282
- PluginEventBus,
283
- PluginRegistry,
284
- StaticSettings,
285
- ValidatedSettings,
286
- definePlugin,
287
- discoverPlugins,
288
- getPluginLoader,
289
- isDefinedPlugin,
290
- loadPluginModule,
291
- resetFrameworkAliases,
292
- resetPluginLoader,
293
- resolveFrameworkAliases
294
- } from "./chunk-WGZAPU6N.js";
347
+ ApprovalDeniedError,
348
+ ApprovalTimeoutError,
349
+ allApprovalConditions,
350
+ anyApprovalConditions,
351
+ approvalRequestsOverlap,
352
+ buildApprovalRuleContext,
353
+ createApprovalCorrection,
354
+ createApprovalHandler,
355
+ createApprovalPolicyPreset,
356
+ createConditionalApprovalRule,
357
+ createDangerouslyAllowAllApprovalPolicy,
358
+ createHeadlessDenyApprovalPolicy,
359
+ createInteractiveApprovalPolicy,
360
+ createRememberedApprovalRules,
361
+ createRiskTierApprovalPolicy,
362
+ createThresholdApprovalRule,
363
+ createTrustedSessionApprovalPolicy,
364
+ formatApprovalDeniedReason,
365
+ getToolRisk,
366
+ matchApprovalArgValue,
367
+ matchApprovalNumericArg,
368
+ matchApprovalRisks,
369
+ matchApprovalSessions,
370
+ matchApprovalStringPrefixes,
371
+ normalizeApprovalCascadePolicy,
372
+ normalizeRememberScopes,
373
+ selectRememberScope,
374
+ shouldCascadeApprovalDecision
375
+ } from "./chunk-V4RFNEET.js";
376
+ import {
377
+ describeApprovalOperation,
378
+ extractApprovalPatterns,
379
+ getRequiredToolHost,
380
+ matchApprovalPattern,
381
+ requiresToolHost,
382
+ resolveCapability
383
+ } from "./chunk-FII65CN7.js";
384
+ import {
385
+ createConsoleLogger,
386
+ createFileLogger,
387
+ silentLogger
388
+ } from "./chunk-T4UIX5D7.js";
389
+
390
+ // src/tracking/turn-tracker/tracker.ts
391
+ import { spawn } from "child_process";
392
+ import { normalize, relative as relative2, resolve } from "path";
393
+
394
+ // src/tracking/turn-tracker/diff.ts
395
+ import { createHash } from "crypto";
396
+ import { mkdir, readFile, stat, unlink, writeFile } from "fs/promises";
397
+ import { dirname, relative } from "path";
398
+ async function captureTurnFileBaseline(absPath) {
399
+ try {
400
+ const content = await readFile(absPath, "utf-8");
401
+ const stats = await stat(absPath);
402
+ return {
403
+ path: absPath,
404
+ content,
405
+ mode: stats.mode,
406
+ hash: hashTurnTrackerContent(content),
407
+ capturedAt: /* @__PURE__ */ new Date()
408
+ };
409
+ } catch (error) {
410
+ if (error.code === "ENOENT") {
411
+ return {
412
+ path: absPath,
413
+ content: null,
414
+ mode: null,
415
+ hash: null,
416
+ capturedAt: /* @__PURE__ */ new Date()
417
+ };
418
+ }
419
+ throw error;
420
+ }
421
+ }
422
+ async function restoreTurnTrackedFile(absPath, baseline) {
423
+ if (baseline.content === null) {
424
+ try {
425
+ await unlink(absPath);
426
+ } catch (error) {
427
+ if (error.code !== "ENOENT") {
428
+ throw error;
429
+ }
430
+ }
431
+ return;
432
+ }
433
+ await mkdir(dirname(absPath), { recursive: true });
434
+ await writeFile(absPath, baseline.content, {
435
+ mode: baseline.mode ?? void 0
436
+ });
437
+ }
438
+ async function computeTurnTrackerFileChange(options) {
439
+ const { cwd, absPath, baseline, preferGitDiff, canUseGitDiff } = options;
440
+ const relPath = relative(cwd, absPath);
441
+ const currentContent = await readTrackedFileContent(absPath);
442
+ let type;
443
+ if (baseline.content === null && currentContent === null) {
444
+ type = "unchanged";
445
+ } else if (baseline.content === null && currentContent !== null) {
446
+ type = "created";
447
+ } else if (baseline.content !== null && currentContent === null) {
448
+ type = "deleted";
449
+ } else if (baseline.content === currentContent) {
450
+ type = "unchanged";
451
+ } else {
452
+ type = "modified";
453
+ }
454
+ if (type === "unchanged") {
455
+ return { path: relPath, type, additions: 0, deletions: 0 };
456
+ }
457
+ const diff = await generateTurnTrackerDiff({
458
+ relPath,
459
+ oldContent: baseline.content,
460
+ newContent: currentContent,
461
+ preferGitDiff,
462
+ canUseGitDiff
463
+ });
464
+ const { additions, deletions } = countUnifiedDiffStats(diff);
465
+ return {
466
+ path: relPath,
467
+ type,
468
+ additions,
469
+ deletions,
470
+ diff
471
+ };
472
+ }
473
+ async function readTrackedFileContent(absPath) {
474
+ try {
475
+ return await readFile(absPath, "utf-8");
476
+ } catch (error) {
477
+ if (error.code === "ENOENT") {
478
+ return null;
479
+ }
480
+ throw error;
481
+ }
482
+ }
483
+ async function generateTurnTrackerDiff(options) {
484
+ const { relPath, oldContent, newContent, preferGitDiff, canUseGitDiff } = options;
485
+ const oldLines = (oldContent ?? "").split("\n");
486
+ const newLines = (newContent ?? "").split("\n");
487
+ if (preferGitDiff && canUseGitDiff) {
488
+ const gitDiff = await createGitStyleDiffPlaceholder();
489
+ if (gitDiff) {
490
+ return gitDiff;
491
+ }
492
+ }
493
+ return buildSimpleUnifiedDiff({
494
+ path: relPath,
495
+ oldLines,
496
+ newLines,
497
+ wasCreated: oldContent === null,
498
+ wasDeleted: newContent === null
499
+ });
500
+ }
501
+ function buildSimpleUnifiedDiff(options) {
502
+ const { path, oldLines, newLines, wasCreated, wasDeleted } = options;
503
+ const header = [
504
+ `--- a/${path}${wasCreated ? " (new file)" : ""}`,
505
+ `+++ b/${path}${wasDeleted ? " (deleted)" : ""}`
506
+ ];
507
+ const hunks = [];
508
+ if (wasCreated) {
509
+ hunks.push(`@@ -0,0 +1,${newLines.length} @@`);
510
+ for (const line of newLines) {
511
+ hunks.push(`+${line}`);
512
+ }
513
+ } else if (wasDeleted) {
514
+ hunks.push(`@@ -1,${oldLines.length} +0,0 @@`);
515
+ for (const line of oldLines) {
516
+ hunks.push(`-${line}`);
517
+ }
518
+ } else {
519
+ hunks.push(`@@ -1,${oldLines.length} +1,${newLines.length} @@`);
520
+ for (const line of oldLines) {
521
+ hunks.push(`-${line}`);
522
+ }
523
+ for (const line of newLines) {
524
+ hunks.push(`+${line}`);
525
+ }
526
+ }
527
+ return [...header, ...hunks].join("\n");
528
+ }
529
+ function countUnifiedDiffStats(diff) {
530
+ let additions = 0;
531
+ let deletions = 0;
532
+ for (const line of diff.split("\n")) {
533
+ if (line.startsWith("+") && !line.startsWith("+++")) {
534
+ additions++;
535
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
536
+ deletions++;
537
+ }
538
+ }
539
+ return { additions, deletions };
540
+ }
541
+ function hashTurnTrackerContent(content) {
542
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
543
+ }
544
+ async function createGitStyleDiffPlaceholder() {
545
+ return null;
546
+ }
547
+
548
+ // src/tracking/turn-tracker/tracker.ts
549
+ var TurnChangeTracker = class {
550
+ config;
551
+ currentTurn = null;
552
+ gitDetected = null;
553
+ log;
554
+ constructor(config, logger) {
555
+ this.config = {
556
+ cwd: resolve(config.cwd),
557
+ useGit: config.useGit ?? true,
558
+ maxTrackedFiles: config.maxTrackedFiles ?? 100
559
+ };
560
+ this.log = logger?.child("turn-tracker") ?? silentLogger;
561
+ }
562
+ startTurn(turnId) {
563
+ if (this.currentTurn && !this.currentTurn.completed) {
564
+ this.currentTurn.completed = true;
565
+ }
566
+ this.currentTurn = {
567
+ id: turnId,
568
+ startedAt: /* @__PURE__ */ new Date(),
569
+ baselines: /* @__PURE__ */ new Map(),
570
+ completed: false
571
+ };
572
+ }
573
+ async endTurn() {
574
+ if (!this.currentTurn) {
575
+ return {
576
+ turnId: "",
577
+ files: [],
578
+ totalTracked: 0,
579
+ additions: 0,
580
+ deletions: 0,
581
+ diff: null,
582
+ duration: 0
583
+ };
584
+ }
585
+ const turn = this.currentTurn;
586
+ turn.completed = true;
587
+ const files = [];
588
+ let additions = 0;
589
+ let deletions = 0;
590
+ const diffs = [];
591
+ for (const [absPath, baseline] of turn.baselines) {
592
+ const change = await this.computeFileChange(absPath, baseline);
593
+ files.push(change);
594
+ additions += change.additions;
595
+ deletions += change.deletions;
596
+ if (change.diff) {
597
+ diffs.push(change.diff);
598
+ }
599
+ }
600
+ files.sort((left, right) => left.path.localeCompare(right.path));
601
+ return {
602
+ turnId: turn.id,
603
+ files,
604
+ totalTracked: turn.baselines.size,
605
+ additions,
606
+ deletions,
607
+ diff: diffs.length > 0 ? diffs.join("\n") : null,
608
+ duration: Date.now() - turn.startedAt.getTime()
609
+ };
610
+ }
611
+ isInTurn() {
612
+ return this.currentTurn !== null && !this.currentTurn.completed;
613
+ }
614
+ getCurrentTurnId() {
615
+ return this.currentTurn?.id ?? null;
616
+ }
617
+ async beforeWrite(filePath) {
618
+ if (!this.currentTurn || this.currentTurn.completed) {
619
+ return false;
620
+ }
621
+ const absPath = resolve(this.config.cwd, filePath);
622
+ const normalizedPath = normalize(absPath);
623
+ if (this.currentTurn.baselines.has(normalizedPath)) {
624
+ return false;
625
+ }
626
+ if (this.currentTurn.baselines.size >= this.config.maxTrackedFiles) {
627
+ this.log.warn(
628
+ `Max tracked files (${this.config.maxTrackedFiles}) reached, skipping: ${filePath}`
629
+ );
630
+ return false;
631
+ }
632
+ const baseline = await captureTurnFileBaseline(normalizedPath);
633
+ this.currentTurn.baselines.set(normalizedPath, baseline);
634
+ return true;
635
+ }
636
+ getTrackedFiles() {
637
+ if (!this.currentTurn) {
638
+ return [];
639
+ }
640
+ return Array.from(this.currentTurn.baselines.keys()).map(
641
+ (path) => relative2(this.config.cwd, path)
642
+ );
643
+ }
644
+ isTracking(filePath) {
645
+ if (!this.currentTurn) {
646
+ return false;
647
+ }
648
+ const absPath = resolve(this.config.cwd, filePath);
649
+ return this.currentTurn.baselines.has(normalize(absPath));
650
+ }
651
+ async getDiff() {
652
+ if (!this.currentTurn || this.currentTurn.baselines.size === 0) {
653
+ return null;
654
+ }
655
+ const diffs = [];
656
+ for (const [absPath, baseline] of this.currentTurn.baselines) {
657
+ const change = await this.computeFileChange(absPath, baseline);
658
+ if (change.diff) {
659
+ diffs.push(change.diff);
660
+ }
661
+ }
662
+ return diffs.length > 0 ? diffs.join("\n") : null;
663
+ }
664
+ async getFileDiff(filePath) {
665
+ if (!this.currentTurn) {
666
+ return null;
667
+ }
668
+ const absPath = resolve(this.config.cwd, filePath);
669
+ const baseline = this.currentTurn.baselines.get(normalize(absPath));
670
+ if (!baseline) {
671
+ return null;
672
+ }
673
+ const change = await this.computeFileChange(absPath, baseline);
674
+ return change.diff ?? null;
675
+ }
676
+ async undoTurn() {
677
+ if (!this.currentTurn) {
678
+ return { restored: [], failed: [] };
679
+ }
680
+ const result = { restored: [], failed: [] };
681
+ for (const [absPath, baseline] of this.currentTurn.baselines) {
682
+ const relPath = relative2(this.config.cwd, absPath);
683
+ try {
684
+ await restoreTurnTrackedFile(absPath, baseline);
685
+ result.restored.push(relPath);
686
+ } catch (error) {
687
+ result.failed.push({
688
+ path: relPath,
689
+ reason: error instanceof Error ? error.message : String(error)
690
+ });
691
+ }
692
+ }
693
+ return result;
694
+ }
695
+ async undoFiles(filePaths) {
696
+ if (!this.currentTurn) {
697
+ return { restored: [], failed: [] };
698
+ }
699
+ const result = { restored: [], failed: [] };
700
+ for (const filePath of filePaths) {
701
+ const absPath = resolve(this.config.cwd, filePath);
702
+ const normalizedPath = normalize(absPath);
703
+ const baseline = this.currentTurn.baselines.get(normalizedPath);
704
+ if (!baseline) {
705
+ result.failed.push({
706
+ path: filePath,
707
+ reason: "File not tracked in current turn"
708
+ });
709
+ continue;
710
+ }
711
+ try {
712
+ await restoreTurnTrackedFile(absPath, baseline);
713
+ result.restored.push(filePath);
714
+ } catch (error) {
715
+ result.failed.push({
716
+ path: filePath,
717
+ reason: error instanceof Error ? error.message : String(error)
718
+ });
719
+ }
720
+ }
721
+ return result;
722
+ }
723
+ async computeFileChange(absPath, baseline) {
724
+ return await computeTurnTrackerFileChange({
725
+ cwd: this.config.cwd,
726
+ absPath,
727
+ baseline,
728
+ preferGitDiff: this.config.useGit,
729
+ canUseGitDiff: await this.isInGitRepo()
730
+ });
731
+ }
732
+ async isInGitRepo() {
733
+ if (!this.config.useGit) {
734
+ return false;
735
+ }
736
+ if (this.gitDetected !== null) {
737
+ return this.gitDetected;
738
+ }
739
+ return await new Promise((resolvePromise) => {
740
+ const proc = spawn("git", ["rev-parse", "--git-dir"], {
741
+ cwd: this.config.cwd,
742
+ stdio: ["ignore", "pipe", "pipe"]
743
+ });
744
+ proc.on("close", (code2) => {
745
+ this.gitDetected = code2 === 0;
746
+ resolvePromise(this.gitDetected);
747
+ });
748
+ proc.on("error", () => {
749
+ this.gitDetected = false;
750
+ resolvePromise(false);
751
+ });
752
+ });
753
+ }
754
+ };
755
+ function createTurnTracker(config, logger) {
756
+ return new TurnChangeTracker(config, logger);
757
+ }
295
758
 
296
- // src/agent/intervention.ts
759
+ // src/intervention/intervention.ts
297
760
  var InterventionController = class {
298
761
  /** Immediate interventions — applied at the next step boundary */
299
762
  immediate = [];
@@ -304,6 +767,8 @@ var InterventionController = class {
304
767
  * Set by the Agent before starting a chat turn, cleared after.
305
768
  */
306
769
  onApplied;
770
+ /** Callback fired when a deferred follow-up is queued. */
771
+ onDeferredQueued;
307
772
  // ---------------------------------------------------------------------------
308
773
  // Immediate interventions (mid-turn redirect)
309
774
  // ---------------------------------------------------------------------------
@@ -367,9 +832,9 @@ var InterventionController = class {
367
832
  */
368
833
  queueNext(message) {
369
834
  const id = crypto.randomUUID();
370
- this.deferred.push(
371
- Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() })
372
- );
835
+ const queued = Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() });
836
+ this.deferred.push(queued);
837
+ this.onDeferredQueued?.(queued);
373
838
  return id;
374
839
  }
375
840
  /**
@@ -389,132 +854,24 @@ var InterventionController = class {
389
854
  get hasDeferred() {
390
855
  return this.deferred.length > 0;
391
856
  }
392
- /** Number of deferred messages */
393
- get deferredCount() {
394
- return this.deferred.length;
395
- }
396
- // ---------------------------------------------------------------------------
397
- // Housekeeping
398
- // ---------------------------------------------------------------------------
399
- /** Clear all queues (immediate + deferred) */
400
- clear() {
401
- this.immediate.length = 0;
402
- this.deferred.length = 0;
403
- }
404
- /** Reset the controller for a new turn (clears onApplied, keeps queues) */
405
- resetCallbacks() {
406
- this.onApplied = void 0;
407
- }
408
- };
409
-
410
- // src/agent/chat-loop/commit.ts
411
- function createChatLoopCommitBatchApplier(params) {
412
- const { turnEngine, sessions, middlewareRunner } = params;
413
- return async function* applyCommitBatch(batch, options = {}) {
414
- turnEngine.recordEvent(batch.startBoundary, (/* @__PURE__ */ new Date()).toISOString());
415
- middlewareRunner.emitEvent(batch.startBoundary);
416
- yield batch.startBoundary;
417
- await sessions.addMessages(batch.messages);
418
- turnEngine.recordEvent(batch.finishBoundary, (/* @__PURE__ */ new Date()).toISOString());
419
- middlewareRunner.emitEvent(batch.finishBoundary);
420
- yield batch.finishBoundary;
421
- if (options.emitMessages) {
422
- for (const committedMessage of batch.messages) {
423
- yield { type: "message", message: committedMessage };
424
- }
425
- }
426
- };
427
- }
428
-
429
- // src/agent/session.ts
430
- async function ensureSessionLoaded(options) {
431
- const { sessionId, sessions, cwd } = options;
432
- if (sessions.getSessionId() === sessionId) {
433
- return;
434
- }
435
- const exists = await sessions.sessionExists(sessionId);
436
- if (exists) {
437
- await sessions.load(sessionId);
438
- } else {
439
- await sessions.create({ id: sessionId, cwd });
440
- }
441
- }
442
- async function repairOrphanedToolCalls(sessions) {
443
- const messages = sessions.getMessages();
444
- const pendingCallIds = /* @__PURE__ */ new Map();
445
- for (const message of messages) {
446
- if (message.role === "assistant" && message.toolCalls) {
447
- for (const toolCall of message.toolCalls) {
448
- pendingCallIds.set(toolCall.toolCallId, { toolName: toolCall.toolName });
449
- }
450
- }
451
- if (message.role === "tool" && message.toolCallId) {
452
- pendingCallIds.delete(message.toolCallId);
453
- }
454
- }
455
- for (const [toolCallId, { toolName }] of pendingCallIds) {
456
- const toolMessage = {
457
- id: crypto.randomUUID(),
458
- role: "tool",
459
- content: "Error: tool execution failed (result was not recorded)",
460
- toolCallId,
461
- toolName,
462
- result: "Error: tool execution failed (result was not recorded)",
463
- createdAt: /* @__PURE__ */ new Date()
464
- };
465
- await sessions.addMessage(toolMessage);
466
- }
467
- }
468
- async function createSubAgentRunSession(options) {
469
- const sessionId = options.parentSessionId ? `${options.parentSessionId}:sub:${crypto.randomUUID().slice(0, 8)}` : `sub:${crypto.randomUUID().slice(0, 8)}`;
470
- await options.sessions.create({
471
- id: sessionId,
472
- cwd: options.cwd,
473
- title: options.title ?? "Sub-agent task",
474
- parentSessionId: options.parentSessionId
475
- });
476
- return sessionId;
477
- }
478
- function getVisibleSessionMessages(sessions) {
479
- const leafId = sessions.getLeafId();
480
- if (!leafId) {
481
- return [];
857
+ /** Number of deferred messages */
858
+ get deferredCount() {
859
+ return this.deferred.length;
482
860
  }
483
- const path = buildEntryPath(
484
- sessions.getEntries(),
485
- leafId
486
- );
487
- const visible = [];
488
- let skipUntilId;
489
- for (const entry of path) {
490
- if (entry.type === "compaction") {
491
- visible.push({
492
- message: {
493
- id: entry.id,
494
- role: "system",
495
- content: `## Previous Conversation Summary
496
-
497
- ${entry.summary}`,
498
- createdAt: new Date(entry.timestamp)
499
- }
500
- });
501
- skipUntilId = entry.firstKeptEntryId;
502
- continue;
503
- }
504
- if (skipUntilId && entry.id !== skipUntilId) {
505
- continue;
506
- }
507
- if (entry.id === skipUntilId) {
508
- skipUntilId = void 0;
509
- }
510
- if (entry.type === "message") {
511
- visible.push({
512
- message: deserializeMessage(entry.message)
513
- });
514
- }
861
+ // ---------------------------------------------------------------------------
862
+ // Housekeeping
863
+ // ---------------------------------------------------------------------------
864
+ /** Clear all queues (immediate + deferred) */
865
+ clear() {
866
+ this.immediate.length = 0;
867
+ this.deferred.length = 0;
515
868
  }
516
- return visible;
517
- }
869
+ /** Reset the controller for a new turn (clears onApplied, keeps queues) */
870
+ resetCallbacks() {
871
+ this.onApplied = void 0;
872
+ this.onDeferredQueued = void 0;
873
+ }
874
+ };
518
875
 
519
876
  // src/agent/runtime-config.ts
520
877
  function createAgentToolRecord(tools) {
@@ -524,9 +881,6 @@ function createAgentToolRecord(tools) {
524
881
  }
525
882
  return toolRecord;
526
883
  }
527
- function getAgentContextStats(contextManager, messages) {
528
- return contextManager.getStats(messages);
529
- }
530
884
  function buildFallbackCompactionSummary(messages) {
531
885
  const excerpt = messages.map((message) => {
532
886
  const role = message.role.toUpperCase();
@@ -539,9 +893,9 @@ function buildFallbackCompactionSummary(messages) {
539
893
  return trimmed.length > 0 ? trimmed : "Earlier conversation context was compacted.";
540
894
  }
541
895
  async function compactAgentContext(options) {
542
- const { contextManager, sessions } = options;
543
- const visibleMessages = getVisibleSessionMessages(sessions);
544
- const messages = visibleMessages.map((item) => item.message);
896
+ const { contextManager, sessions, logger } = options;
897
+ const log = logger ?? silentLogger;
898
+ const messages = getVisibleSessionMessages(sessions);
545
899
  if (!contextManager.shouldPrune(messages)) {
546
900
  return {
547
901
  removedCount: 0,
@@ -559,7 +913,10 @@ async function compactAgentContext(options) {
559
913
  removedCount = result.removedCount;
560
914
  summarized = result.summarized;
561
915
  summary = result.summary;
562
- } catch {
916
+ } catch (pruneError) {
917
+ log.warn("Context compaction LLM summarisation failed, using fallback", {
918
+ error: pruneError instanceof Error ? pruneError.message : String(pruneError)
919
+ });
563
920
  }
564
921
  if (removedCount === 0) {
565
922
  removedCount = findCutPoint(
@@ -643,29 +1000,56 @@ function createAgentTurnRuntimeConfig(options) {
643
1000
  ...config.enforceDoomLoop !== void 0 ? { enforceDoomLoop: config.enforceDoomLoop } : {},
644
1001
  ...config.onDoomLoop ? { onDoomLoop: config.onDoomLoop } : {},
645
1002
  ...config.contextWindow !== void 0 ? { contextWindow: config.contextWindow } : {},
1003
+ ...options.reserveTokens !== void 0 ? { reserveTokens: options.reserveTokens } : {},
646
1004
  ...config.streamProvider ? { streamProvider: config.streamProvider } : {},
647
1005
  ...telemetrySettings ? { telemetry: telemetrySettings } : {}
648
1006
  };
649
1007
  }
650
1008
 
1009
+ // src/agent/chat-loop/commit.ts
1010
+ function createChatLoopCommitBatchApplier(params) {
1011
+ const { turnEngine, sessions, middlewareRunner } = params;
1012
+ return async function* applyCommitBatch(batch, options = {}) {
1013
+ turnEngine.recordEvent(batch.startBoundary, (/* @__PURE__ */ new Date()).toISOString());
1014
+ middlewareRunner.emitEvent(batch.startBoundary);
1015
+ yield batch.startBoundary;
1016
+ await sessions.addMessages(batch.messages);
1017
+ turnEngine.recordEvent(batch.finishBoundary, (/* @__PURE__ */ new Date()).toISOString());
1018
+ middlewareRunner.emitEvent(batch.finishBoundary);
1019
+ yield batch.finishBoundary;
1020
+ if (options.emitMessages) {
1021
+ for (const committedMessage of batch.messages) {
1022
+ yield { type: "message", message: committedMessage };
1023
+ }
1024
+ }
1025
+ };
1026
+ }
1027
+
651
1028
  // src/agent/chat-loop/compaction.ts
652
1029
  async function runAutoCompaction(params) {
653
- const { contextManager, sessions } = params;
1030
+ const { contextManager, sessions, logger } = params;
654
1031
  const messages = sessions.getMessages();
655
1032
  if (!contextManager.shouldPrune(messages)) {
656
1033
  return [];
657
1034
  }
658
1035
  const events = [{ type: "status", status: "processing" }];
659
- const pruneResult = await compactAgentContext({
660
- contextManager,
661
- sessions
662
- });
663
- if (pruneResult.removedCount > 0 || pruneResult.summarized) {
664
- const limits = contextManager.getLimits();
665
- events.push({
666
- type: "context-overflow",
667
- inputTokens: estimateConversationTokens(messages),
668
- limit: limits.contextWindow - limits.reserveTokens
1036
+ try {
1037
+ const pruneResult = await compactAgentContext({
1038
+ contextManager,
1039
+ sessions,
1040
+ logger
1041
+ });
1042
+ if (pruneResult.removedCount > 0 || pruneResult.summarized) {
1043
+ const limits = contextManager.getLimits();
1044
+ events.push({
1045
+ type: "context-overflow",
1046
+ inputTokens: estimateConversationTokens(messages),
1047
+ limit: getUsableTokenLimit(limits)
1048
+ });
1049
+ }
1050
+ } catch (error) {
1051
+ logger?.warn("Auto-compaction failed, continuing without compaction", {
1052
+ error: error instanceof Error ? error.message : String(error)
669
1053
  });
670
1054
  }
671
1055
  return events;
@@ -683,23 +1067,6 @@ async function buildChatSystemPrompts(params) {
683
1067
  });
684
1068
  }
685
1069
 
686
- // src/agent/chat-loop/usage.ts
687
- function accumulateUsage(current, next) {
688
- if (!next) return current;
689
- if (!current) {
690
- return {
691
- inputTokens: next.inputTokens ?? 0,
692
- outputTokens: next.outputTokens ?? 0,
693
- totalTokens: next.totalTokens ?? 0
694
- };
695
- }
696
- return {
697
- inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
698
- outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
699
- totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0)
700
- };
701
- }
702
-
703
1070
  // src/agent/chat-loop/loop.ts
704
1071
  async function* runChatLoop(deps) {
705
1072
  yield* streamWithinScope(
@@ -711,11 +1078,12 @@ async function* runChatLoop(deps) {
711
1078
  (async function* () {
712
1079
  const {
713
1080
  sessionId,
1081
+ turnId,
714
1082
  message,
715
1083
  abort,
716
1084
  systemOverride,
717
1085
  sessions,
718
- tools: toolRecord,
1086
+ tools: liveTools,
719
1087
  config,
720
1088
  turnTracker,
721
1089
  interventionCtrl,
@@ -725,10 +1093,13 @@ async function* runChatLoop(deps) {
725
1093
  reasoningLevel,
726
1094
  promptBuilder,
727
1095
  host,
1096
+ humanInputController,
728
1097
  mcpTools,
729
1098
  toModelMessages,
730
1099
  setIsStreaming
731
1100
  } = deps;
1101
+ let toolRecord = createAgentToolRecord(liveTools);
1102
+ const isPlanMode = deps.toolExecutionMode === "plan";
732
1103
  const turnEngine = createAgentTurnEngine({
733
1104
  sessionId,
734
1105
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -753,20 +1124,24 @@ async function* runChatLoop(deps) {
753
1124
  let chatOutput;
754
1125
  try {
755
1126
  if (middlewareRunner.hasMiddleware) {
756
- await middlewareRunner.runChatStart(sessionId, message);
1127
+ await middlewareRunner.runChatStart(sessionId, message, {
1128
+ sessionId,
1129
+ turnId
1130
+ });
757
1131
  }
758
- const systemPrompts = await buildChatSystemPrompts({
759
- promptBuilder,
760
- middlewareRunner,
761
- systemOverride,
762
- sessionId,
763
- config,
764
- tools: toolRecord
765
- });
766
1132
  let step = 1;
767
1133
  let finalStepText = "";
768
1134
  let accumulatedUsage;
769
1135
  while (step <= config.maxSteps) {
1136
+ toolRecord = createAgentToolRecord(liveTools);
1137
+ const systemPrompts = await buildChatSystemPrompts({
1138
+ promptBuilder,
1139
+ middlewareRunner,
1140
+ systemOverride,
1141
+ sessionId,
1142
+ config,
1143
+ tools: toolRecord
1144
+ });
770
1145
  const preparedStep = prepareModelStep({
771
1146
  sessionId,
772
1147
  step,
@@ -778,10 +1153,12 @@ async function* runChatLoop(deps) {
778
1153
  mcpTools,
779
1154
  config,
780
1155
  host,
1156
+ humanInputController,
781
1157
  turnTracker,
782
1158
  intervention: interventionCtrl,
783
1159
  middleware: middlewareRunner,
784
- reasoningLevel
1160
+ reasoningLevel,
1161
+ toolExecutionMode: deps.toolExecutionMode
785
1162
  });
786
1163
  const stepResult = yield* runModelStep({
787
1164
  preparedStep,
@@ -794,6 +1171,7 @@ async function* runChatLoop(deps) {
794
1171
  chatError = stepResult.error;
795
1172
  return;
796
1173
  }
1174
+ const planSnapshot = isPlanMode && stepResult.finishReason === "tool-calls" ? turnEngine.createStepCommitSnapshot() : void 0;
797
1175
  yield* commitStep({
798
1176
  step,
799
1177
  finishReason: stepResult.finishReason,
@@ -814,6 +1192,31 @@ async function* runChatLoop(deps) {
814
1192
  yield errorEvent;
815
1193
  return;
816
1194
  }
1195
+ if (isPlanMode && planSnapshot && planSnapshot.toolCalls.length > 0) {
1196
+ const batchResult = await runToolBatch({
1197
+ sessionId,
1198
+ snapshot: planSnapshot,
1199
+ tools: toolRecord,
1200
+ cwd: config.cwd,
1201
+ abort,
1202
+ host,
1203
+ humanInputController,
1204
+ turnTracker,
1205
+ middleware: middlewareRunner,
1206
+ intervention: interventionCtrl
1207
+ });
1208
+ for (const event of batchResult.events) {
1209
+ turnEngine.recordEvent(event, (/* @__PURE__ */ new Date()).toISOString());
1210
+ middlewareRunner.emitEvent(event);
1211
+ yield event;
1212
+ }
1213
+ yield* commitStep({
1214
+ step,
1215
+ finishReason: "tool-calls",
1216
+ turnEngine,
1217
+ applyCommitBatch
1218
+ });
1219
+ }
817
1220
  step += 1;
818
1221
  continue;
819
1222
  }
@@ -829,7 +1232,8 @@ async function* runChatLoop(deps) {
829
1232
  if (config.compaction?.auto !== false) {
830
1233
  const compactionEvents = await runAutoCompaction({
831
1234
  contextManager,
832
- sessions
1235
+ sessions,
1236
+ logger: deps.logger
833
1237
  });
834
1238
  for (const event of compactionEvents) {
835
1239
  yield event;
@@ -874,6 +1278,9 @@ async function* runChatLoop(deps) {
874
1278
  usage: chatUsage,
875
1279
  error: chatError,
876
1280
  output: chatOutput
1281
+ }, {
1282
+ sessionId,
1283
+ turnId
877
1284
  });
878
1285
  }
879
1286
  }
@@ -883,10 +1290,10 @@ async function* runChatLoop(deps) {
883
1290
 
884
1291
  // src/agent/fork.ts
885
1292
  function resolveForkOptions(options, parentTools, systemPrompt) {
886
- if (!options.preset) {
1293
+ if (!options.profile) {
887
1294
  return options;
888
1295
  }
889
- const applied = applyPreset(options.preset, parentTools, systemPrompt);
1296
+ const applied = applyProfile(options.profile, parentTools, systemPrompt);
890
1297
  return {
891
1298
  ...applied,
892
1299
  ...options,
@@ -925,6 +1332,8 @@ function createForkedAgentConfig(options) {
925
1332
  parentTools,
926
1333
  reasoningLevel,
927
1334
  host,
1335
+ sandbox,
1336
+ humanInputController,
928
1337
  ownsHost,
929
1338
  sessions,
930
1339
  mcpManager,
@@ -941,7 +1350,8 @@ function createForkedAgentConfig(options) {
941
1350
  return {
942
1351
  model: forkOptions.model ?? parentConfig.model,
943
1352
  cwd: parentConfig.cwd,
944
- ...ownsHost ? {} : { host },
1353
+ ...ownsHost ? {} : sandbox !== void 0 ? { sandbox } : { host },
1354
+ ...humanInputController ? { humanInput: humanInputController } : {},
945
1355
  maxOutputTokens: parentConfig.maxOutputTokens,
946
1356
  maxSteps: forkOptions.maxSteps ?? parentConfig.maxSteps,
947
1357
  temperature: forkOptions.temperature ?? parentConfig.temperature,
@@ -961,7 +1371,7 @@ function createForkedAgentConfig(options) {
961
1371
  }
962
1372
 
963
1373
  // src/agent/mcp-bridge.ts
964
- async function ensureMcpTools(state) {
1374
+ async function ensureMcpTools(state, logger) {
965
1375
  if (!state.manager) {
966
1376
  return { connected: false, cachedTools: void 0 };
967
1377
  }
@@ -971,17 +1381,18 @@ async function ensureMcpTools(state) {
971
1381
  cachedTools: state.cachedTools
972
1382
  };
973
1383
  }
1384
+ const log = logger.child("mcp");
974
1385
  const statuses = await state.manager.connect();
975
1386
  let connectedCount = 0;
976
1387
  for (const [name, status] of statuses) {
977
1388
  if (status.status === "connected") {
978
1389
  connectedCount++;
979
1390
  } else if (status.status === "error") {
980
- console.warn(`[mcp] Failed to connect to ${name}: ${status.error}`);
1391
+ log.warn(`Failed to connect to ${name}: ${status.error}`);
981
1392
  }
982
1393
  }
983
1394
  if (connectedCount === 0 && statuses.size > 0) {
984
- console.warn("[mcp] No MCP servers connected successfully");
1395
+ log.warn("No MCP servers connected successfully");
985
1396
  }
986
1397
  const cachedTools = await state.manager.getTools();
987
1398
  return {
@@ -999,6 +1410,393 @@ async function closeMcpManager(manager) {
999
1410
  };
1000
1411
  }
1001
1412
 
1413
+ // src/signal/local.ts
1414
+ var LocalSignal = class {
1415
+ /** type → Set<handler> for typed subscriptions */
1416
+ typed = /* @__PURE__ */ new Map();
1417
+ /** handlers that receive every event */
1418
+ wildcard = /* @__PURE__ */ new Set();
1419
+ on(type, handler) {
1420
+ let set = this.typed.get(type);
1421
+ if (!set) {
1422
+ set = /* @__PURE__ */ new Set();
1423
+ this.typed.set(type, set);
1424
+ }
1425
+ const wrapped = (event) => {
1426
+ handler(event);
1427
+ };
1428
+ set.add(wrapped);
1429
+ return () => {
1430
+ set.delete(wrapped);
1431
+ if (set.size === 0) this.typed.delete(type);
1432
+ };
1433
+ }
1434
+ onAny(handler) {
1435
+ this.wildcard.add(handler);
1436
+ return () => {
1437
+ this.wildcard.delete(handler);
1438
+ };
1439
+ }
1440
+ emit(event) {
1441
+ const set = this.typed.get(event.type);
1442
+ if (set) {
1443
+ for (const fn of set) {
1444
+ try {
1445
+ fn(event);
1446
+ } catch {
1447
+ }
1448
+ }
1449
+ }
1450
+ for (const fn of this.wildcard) {
1451
+ try {
1452
+ fn(event);
1453
+ } catch {
1454
+ }
1455
+ }
1456
+ }
1457
+ clear() {
1458
+ this.typed.clear();
1459
+ this.wildcard.clear();
1460
+ }
1461
+ };
1462
+
1463
+ // src/human/controller.ts
1464
+ var HumanInputTimeoutError = class extends Error {
1465
+ constructor(timeoutMs) {
1466
+ super(`Human input request timed out after ${timeoutMs}ms`);
1467
+ this.name = "HumanInputTimeoutError";
1468
+ }
1469
+ };
1470
+ var HumanInputUnavailableError = class extends Error {
1471
+ constructor() {
1472
+ super("No human input controller configured");
1473
+ this.name = "HumanInputUnavailableError";
1474
+ }
1475
+ };
1476
+ function cloneRecord(record) {
1477
+ return structuredClone(record);
1478
+ }
1479
+ function normalizeStatuses(status) {
1480
+ if (!status) {
1481
+ return void 0;
1482
+ }
1483
+ return new Set(Array.isArray(status) ? status : [status]);
1484
+ }
1485
+ function inferKind(input) {
1486
+ if (input.kind) {
1487
+ return input.kind;
1488
+ }
1489
+ if (input.options && input.options.length > 0) {
1490
+ return "choice";
1491
+ }
1492
+ return "text";
1493
+ }
1494
+ function isHumanInputController(value) {
1495
+ if (!value || typeof value !== "object") {
1496
+ return false;
1497
+ }
1498
+ const candidate = value;
1499
+ return typeof candidate.request === "function" && typeof candidate.respondToRequest === "function" && typeof candidate.getRequest === "function" && typeof candidate.listRequests === "function" && typeof candidate.cancelAll === "function";
1500
+ }
1501
+ async function emitHumanInputEvent(context, event) {
1502
+ await context?.emitEvent?.(event);
1503
+ }
1504
+ function createHumanInputController(config = {}) {
1505
+ const timeout = config.timeout ?? 5 * 60 * 1e3;
1506
+ let requestCounter = 0;
1507
+ const pending = /* @__PURE__ */ new Map();
1508
+ async function request(sessionId, input, context = {}) {
1509
+ const requestPayload = {
1510
+ id: `human-input-${++requestCounter}-${Date.now()}`,
1511
+ sessionId,
1512
+ kind: inferKind(input),
1513
+ title: input.title,
1514
+ question: input.question,
1515
+ ...input.options ? { options: input.options.map((option) => ({ ...option })) } : {},
1516
+ ...input.allowMultiple !== void 0 ? { allowMultiple: input.allowMultiple } : {},
1517
+ ...input.placeholder ? { placeholder: input.placeholder } : {},
1518
+ ...input.confirmLabel ? { confirmLabel: input.confirmLabel } : {},
1519
+ ...input.denyLabel ? { denyLabel: input.denyLabel } : {},
1520
+ ...input.toolCallId ? { toolCallId: input.toolCallId } : {},
1521
+ timestamp: Date.now()
1522
+ };
1523
+ const record = {
1524
+ id: requestPayload.id,
1525
+ sessionId,
1526
+ request: structuredClone(requestPayload),
1527
+ status: "pending",
1528
+ createdAt: requestPayload.timestamp,
1529
+ updatedAt: requestPayload.timestamp
1530
+ };
1531
+ const responsePromise = new Promise((resolve2, reject) => {
1532
+ const timeoutId = setTimeout(() => {
1533
+ const current2 = pending.get(record.id);
1534
+ if (!current2) {
1535
+ return;
1536
+ }
1537
+ pending.delete(record.id);
1538
+ current2.record = {
1539
+ ...current2.record,
1540
+ status: "timed-out",
1541
+ updatedAt: Date.now()
1542
+ };
1543
+ void emitHumanInputEvent(
1544
+ { emitEvent: current2.emitEvent },
1545
+ { type: "status", status: "processing" }
1546
+ );
1547
+ reject(new HumanInputTimeoutError(timeout));
1548
+ }, timeout);
1549
+ pending.set(record.id, {
1550
+ record,
1551
+ resolve: resolve2,
1552
+ reject,
1553
+ ready: Promise.resolve(),
1554
+ timeoutId,
1555
+ emitEvent: context.emitEvent
1556
+ });
1557
+ });
1558
+ const current = pending.get(record.id);
1559
+ if (current) {
1560
+ current.ready = (async () => {
1561
+ await emitHumanInputEvent(context, {
1562
+ type: "status",
1563
+ status: "waiting-input"
1564
+ });
1565
+ await emitHumanInputEvent(context, {
1566
+ type: "human-input-request",
1567
+ request: {
1568
+ id: requestPayload.id,
1569
+ kind: requestPayload.kind,
1570
+ title: requestPayload.title,
1571
+ question: requestPayload.question,
1572
+ ...requestPayload.options ? { options: requestPayload.options } : {},
1573
+ ...requestPayload.allowMultiple !== void 0 ? { allowMultiple: requestPayload.allowMultiple } : {},
1574
+ ...requestPayload.placeholder ? { placeholder: requestPayload.placeholder } : {},
1575
+ ...requestPayload.confirmLabel ? { confirmLabel: requestPayload.confirmLabel } : {},
1576
+ ...requestPayload.denyLabel ? { denyLabel: requestPayload.denyLabel } : {}
1577
+ }
1578
+ });
1579
+ })();
1580
+ }
1581
+ if (config.onRequest) {
1582
+ void (async () => {
1583
+ try {
1584
+ await pending.get(record.id)?.ready;
1585
+ const response = await config.onRequest(requestPayload);
1586
+ await respondToRequest(record.id, response, context);
1587
+ } catch (error) {
1588
+ if (error instanceof HumanInputTimeoutError) {
1589
+ return;
1590
+ }
1591
+ const current2 = pending.get(record.id);
1592
+ if (!current2) {
1593
+ return;
1594
+ }
1595
+ pending.delete(record.id);
1596
+ clearTimeout(current2.timeoutId);
1597
+ current2.record = {
1598
+ ...current2.record,
1599
+ status: "cancelled",
1600
+ updatedAt: Date.now()
1601
+ };
1602
+ current2.reject(
1603
+ error instanceof Error ? error : new Error(String(error))
1604
+ );
1605
+ await emitHumanInputEvent(
1606
+ { emitEvent: current2.emitEvent },
1607
+ { type: "status", status: "processing" }
1608
+ );
1609
+ }
1610
+ })();
1611
+ }
1612
+ return await responsePromise;
1613
+ }
1614
+ async function respondToRequest(requestId, response, context = {}) {
1615
+ const current = pending.get(requestId);
1616
+ if (!current) {
1617
+ throw new Error(`Human input request not found: ${requestId}`);
1618
+ }
1619
+ await current.ready;
1620
+ pending.delete(requestId);
1621
+ clearTimeout(current.timeoutId);
1622
+ const respondedAt = Date.now();
1623
+ const next = {
1624
+ ...current.record,
1625
+ status: "answered",
1626
+ updatedAt: respondedAt,
1627
+ respondedAt,
1628
+ response: structuredClone(response)
1629
+ };
1630
+ current.resolve(response);
1631
+ const emitEvent = context.emitEvent ?? current.emitEvent;
1632
+ await emitHumanInputEvent(
1633
+ { emitEvent },
1634
+ {
1635
+ type: "human-input-resolved",
1636
+ id: requestId,
1637
+ response
1638
+ }
1639
+ );
1640
+ await emitHumanInputEvent(
1641
+ { emitEvent },
1642
+ { type: "status", status: "processing" }
1643
+ );
1644
+ return cloneRecord(next);
1645
+ }
1646
+ function getRequest(requestId) {
1647
+ const current = pending.get(requestId);
1648
+ return current ? cloneRecord(current.record) : void 0;
1649
+ }
1650
+ function listRequests(options = {}) {
1651
+ const statuses = normalizeStatuses(options.status);
1652
+ return [...pending.values()].map((entry) => cloneRecord(entry.record)).filter((record) => {
1653
+ if (options.sessionId && record.sessionId !== options.sessionId) {
1654
+ return false;
1655
+ }
1656
+ if (statuses && !statuses.has(record.status)) {
1657
+ return false;
1658
+ }
1659
+ return true;
1660
+ }).sort((left, right) => left.createdAt - right.createdAt);
1661
+ }
1662
+ function cancelAll(reason = "Cancelled") {
1663
+ for (const [requestId, current] of pending) {
1664
+ pending.delete(requestId);
1665
+ clearTimeout(current.timeoutId);
1666
+ current.record = {
1667
+ ...current.record,
1668
+ status: "cancelled",
1669
+ updatedAt: Date.now()
1670
+ };
1671
+ current.reject(new Error(reason));
1672
+ void emitHumanInputEvent(
1673
+ { emitEvent: current.emitEvent },
1674
+ { type: "status", status: "processing" }
1675
+ );
1676
+ }
1677
+ }
1678
+ return {
1679
+ get hasPendingRequests() {
1680
+ return pending.size > 0;
1681
+ },
1682
+ request,
1683
+ respondToRequest,
1684
+ getRequest,
1685
+ listRequests,
1686
+ cancelAll
1687
+ };
1688
+ }
1689
+
1690
+ // src/human/handler.ts
1691
+ function createHumanInputHandler(config = {}) {
1692
+ return createHumanInputController(config);
1693
+ }
1694
+
1695
+ // src/human/tool.ts
1696
+ import { z } from "zod";
1697
+ function createHumanInputTool(options = {}) {
1698
+ if (options.controller) {
1699
+ return createHumanInputToolWithController(options.controller, options);
1700
+ }
1701
+ if (options.onRequest || options.timeout !== void 0) {
1702
+ return createHumanInputToolWithController(
1703
+ createHumanInputController(options),
1704
+ options
1705
+ );
1706
+ }
1707
+ return createHumanInputToolWithController(void 0, options);
1708
+ }
1709
+ function createHumanInputToolWithController(controller, options = {}) {
1710
+ return Tool.define(
1711
+ options.name ?? "question",
1712
+ {
1713
+ description: options.description ?? "Ask a human for missing input, a decision, a confirmation, or a choice.",
1714
+ parameters: z.object({
1715
+ title: z.string().min(1).describe("Short heading for the request"),
1716
+ question: z.string().min(1).describe("What to ask the human"),
1717
+ kind: z.enum(["text", "confirm", "choice"]).optional(),
1718
+ options: z.array(
1719
+ z.object({
1720
+ label: z.string().min(1),
1721
+ value: z.string().optional(),
1722
+ description: z.string().optional()
1723
+ })
1724
+ ).optional(),
1725
+ allowMultiple: z.boolean().optional(),
1726
+ placeholder: z.string().optional(),
1727
+ confirmLabel: z.string().optional(),
1728
+ denyLabel: z.string().optional()
1729
+ }),
1730
+ validate: (params) => {
1731
+ const kind = params.kind ?? (params.options?.length ? "choice" : "text");
1732
+ if (kind === "choice" && (!params.options || params.options.length === 0)) {
1733
+ return {
1734
+ ok: false,
1735
+ reason: "Choice requests must include at least one option."
1736
+ };
1737
+ }
1738
+ if (kind !== "choice" && params.allowMultiple) {
1739
+ return {
1740
+ ok: false,
1741
+ reason: "allowMultiple is only valid for choice requests."
1742
+ };
1743
+ }
1744
+ return { ok: true };
1745
+ },
1746
+ capabilities: {
1747
+ readOnly: true,
1748
+ riskLevel: "safe",
1749
+ parallelSafe: false,
1750
+ humanInput: true
1751
+ },
1752
+ replayPolicy: {
1753
+ mode: "manual",
1754
+ sideEffectLevel: "external",
1755
+ reason: "Depends on a human response before execution can continue."
1756
+ },
1757
+ execute: async (params, ctx) => {
1758
+ let response;
1759
+ try {
1760
+ const activeController = controller ?? ctx.humanInputController;
1761
+ if (!activeController) {
1762
+ throw new HumanInputUnavailableError();
1763
+ }
1764
+ response = await activeController.request(ctx.sessionID, {
1765
+ ...params,
1766
+ toolCallId: typeof ctx.extra?.toolCallId === "string" ? ctx.extra.toolCallId : ctx.messageID
1767
+ }, {
1768
+ emitEvent: ctx.emitEvent
1769
+ });
1770
+ } catch (error) {
1771
+ if (error instanceof HumanInputUnavailableError) {
1772
+ throw error;
1773
+ }
1774
+ throw error;
1775
+ }
1776
+ return {
1777
+ title: params.title,
1778
+ output: response.text,
1779
+ metadata: { response }
1780
+ };
1781
+ }
1782
+ },
1783
+ {
1784
+ replayPolicy: {
1785
+ mode: "manual",
1786
+ sideEffectLevel: "external",
1787
+ reason: "Depends on a human response before execution can continue."
1788
+ },
1789
+ capabilitiesHint: {
1790
+ readOnly: true,
1791
+ riskLevel: "safe",
1792
+ parallelSafe: false,
1793
+ humanInput: true
1794
+ }
1795
+ }
1796
+ );
1797
+ }
1798
+ var createHumanInputToolWithHandler = createHumanInputToolWithController;
1799
+
1002
1800
  // src/agent/stream-provider.ts
1003
1801
  var DEFAULT_CUSTOM_STREAM_MODELS = [
1004
1802
  "computer-use-preview",
@@ -1035,18 +1833,6 @@ function autoDetectStreamProvider(model, tools, explicitProvider) {
1035
1833
  return void 0;
1036
1834
  }
1037
1835
 
1038
- // src/agent/defaults.ts
1039
- var DEFAULT_SYSTEM_PROMPT = `You are a capable AI assistant with access to tools.
1040
-
1041
- Think step by step about what you need to do.
1042
- Use the available tools to accomplish tasks.
1043
- Verify your results after each action.
1044
-
1045
- If a tool fails, try an alternative approach \u2014 do not give up after a single error.
1046
- Keep working until the task is fully resolved or you have exhausted all options.`;
1047
- var DEFAULT_MAX_STEPS = 50;
1048
- var DEFAULT_MAX_TOKENS = 32e3;
1049
-
1050
1836
  // src/agent/setup.ts
1051
1837
  function createAgentPromptBuilder(config) {
1052
1838
  if (config.prompt !== void 0) {
@@ -1063,14 +1849,24 @@ function createEffectiveAgentConfig(config) {
1063
1849
  config.tools,
1064
1850
  config.streamProvider
1065
1851
  );
1852
+ const resolvedCwd = config.cwd ?? config.sandbox?.metadata?.workingDirectory ?? process.cwd();
1853
+ const defaultsContext = {
1854
+ sandbox: config.sandbox,
1855
+ cwd: resolvedCwd,
1856
+ modelId: extractModelId(config.model)
1857
+ };
1858
+ const providers = [
1859
+ sandboxDefaultsProvider,
1860
+ ...config.defaultsProviders ?? []
1861
+ ];
1862
+ const defaults = resolveAgentDefaults(defaultsContext, providers);
1066
1863
  return {
1067
- systemPrompt: DEFAULT_SYSTEM_PROMPT,
1068
- cwd: process.cwd(),
1069
- reasoningLevel: "off",
1070
1864
  ...config,
1071
- // Re-apply defaults after spread so explicit `undefined` from callers doesn't win.
1072
- maxSteps: config.maxSteps ?? DEFAULT_MAX_STEPS,
1073
- maxOutputTokens: config.maxOutputTokens ?? DEFAULT_MAX_TOKENS,
1865
+ systemPrompt: config.systemPrompt ?? defaults.systemPrompt,
1866
+ cwd: resolvedCwd,
1867
+ reasoningLevel: config.reasoningLevel ?? "off",
1868
+ maxSteps: config.maxSteps ?? defaults.maxSteps,
1869
+ maxOutputTokens: config.maxOutputTokens ?? defaults.maxOutputTokens,
1074
1870
  streamProvider: effectiveStreamProvider
1075
1871
  };
1076
1872
  }
@@ -1089,9 +1885,6 @@ function resolveInitialReasoningLevel(config) {
1089
1885
  function createAgentState(config) {
1090
1886
  return {
1091
1887
  model: config.model,
1092
- systemPrompt: config.systemPrompt,
1093
- cwd: config.cwd,
1094
- isStreaming: false,
1095
1888
  reasoningLevel: resolveInitialReasoningLevel(config)
1096
1889
  };
1097
1890
  }
@@ -1115,7 +1908,7 @@ function resolveAgentContextLimits(contextWindow, compactionConfig = {}) {
1115
1908
  Math.max(1024, Math.round(contextWindow * 0.25)),
1116
1909
  Math.max(512, proportionalReserve)
1117
1910
  );
1118
- const usableWindow = Math.max(512, contextWindow - reserveTokens);
1911
+ const usableWindow = Math.max(512, getUsableTokenLimit({ contextWindow, reserveTokens }));
1119
1912
  const requestedProtected = compactionConfig.protectedTokens ?? DEFAULT_CONTEXT_LIMITS.protectedTokens;
1120
1913
  const requestedPruneMinimum = compactionConfig.pruneMinimum ?? DEFAULT_CONTEXT_LIMITS.pruneMinimum;
1121
1914
  return {
@@ -1131,51 +1924,95 @@ function resolveAgentContextLimits(contextWindow, compactionConfig = {}) {
1131
1924
  };
1132
1925
  }
1133
1926
  function createMiddlewareSetup(input, config) {
1134
- let effectiveMiddleware = input.middleware;
1927
+ const inputMiddleware = [...input.middleware ?? []];
1928
+ const hasManualApprovalMiddleware = inputMiddleware.some(
1929
+ (mw) => isApprovalMiddleware(mw)
1930
+ );
1931
+ if (input.approval && hasManualApprovalMiddleware) {
1932
+ throw new Error(
1933
+ "createAgent() received both `approval` config and an explicit approval middleware. Use `approval` for the built-in sugar, or install `approvalMiddleware(...)` manually, but not both."
1934
+ );
1935
+ }
1936
+ let effectiveMiddleware = inputMiddleware;
1135
1937
  let telemetrySettings;
1136
1938
  let tracingShutdown;
1939
+ if (input.approval) {
1940
+ effectiveMiddleware.push(approvalMiddleware(input.approval));
1941
+ }
1137
1942
  if (input.tracing) {
1138
- const agentName = config.name ?? "agent";
1943
+ const agentName = config.name ?? DEFAULT_AGENT_NAME;
1139
1944
  const telemetryResult = createTelemetryConfig({
1945
+ ...input.tracing,
1140
1946
  agentName,
1141
- agentDescription: input.tracing.agentDescription,
1142
- recordInputs: input.tracing.recordInputs,
1143
- recordOutputs: input.tracing.recordOutputs,
1144
- emitToolSpans: input.tracing.emitToolSpans,
1145
- spanTimeoutMs: input.tracing.spanTimeoutMs,
1146
- spanProcessor: input.tracing.spanProcessor,
1147
1947
  serviceName: input.tracing.serviceName ?? agentName
1148
1948
  });
1149
1949
  effectiveMiddleware = [
1150
1950
  telemetryResult.middleware,
1151
- ...input.middleware ?? []
1951
+ ...effectiveMiddleware
1152
1952
  ];
1153
1953
  telemetrySettings = telemetryResult.telemetry;
1154
1954
  tracingShutdown = telemetryResult.shutdown;
1155
1955
  }
1156
1956
  return {
1157
- middlewareRunner: new MiddlewareRunner(effectiveMiddleware),
1957
+ middlewareRunner: new MiddlewareRunner(effectiveMiddleware, input.logger),
1158
1958
  ...telemetrySettings ? { telemetrySettings } : {},
1159
1959
  ...tracingShutdown ? { tracingShutdown } : {}
1160
1960
  };
1161
1961
  }
1962
+ function resolveHumanInputController(input) {
1963
+ if (!input.humanInput) {
1964
+ return {};
1965
+ }
1966
+ return {
1967
+ humanInputController: isHumanInputController(input.humanInput) ? input.humanInput : createHumanInputController(input.humanInput)
1968
+ };
1969
+ }
1970
+ function resolveExecutionEnvironment(input, config) {
1971
+ if (input.host !== void 0 && input.sandbox !== void 0 && input.host !== input.sandbox.host) {
1972
+ throw new Error(
1973
+ "createAgent() received both `host` and `sandbox`, but `sandbox.host` does not match the provided host. Pass only one execution input, or reuse the same host instance for both."
1974
+ );
1975
+ }
1976
+ if (input.host !== void 0) {
1977
+ return {
1978
+ host: input.host,
1979
+ ...input.sandbox ? { sandbox: input.sandbox } : {},
1980
+ ownsHost: false
1981
+ };
1982
+ }
1983
+ if (input.sandbox !== void 0) {
1984
+ return {
1985
+ host: input.sandbox.host,
1986
+ sandbox: input.sandbox,
1987
+ ownsHost: false
1988
+ };
1989
+ }
1990
+ return {
1991
+ host: localHost(config.cwd),
1992
+ ownsHost: true
1993
+ };
1994
+ }
1162
1995
  function createAgentSetup(input) {
1163
1996
  const promptBuilder = createAgentPromptBuilder(input);
1164
1997
  const config = createEffectiveAgentConfig(input);
1165
1998
  const middlewareSetup = createMiddlewareSetup(input, config);
1999
+ const humanInputSetup = resolveHumanInputController(input);
2000
+ const executionEnvironment = resolveExecutionEnvironment(input, config);
2001
+ const logger = input.logger ?? silentLogger;
1166
2002
  return {
1167
2003
  config,
1168
2004
  tools: createToolMap(input.tools),
1169
2005
  sessions: input.sessionManager ?? getDefaultSessionManager(),
1170
2006
  state: createAgentState(config),
1171
2007
  contextManager: createAgentContextManager(config),
1172
- turnTracker: createTurnTracker({ cwd: config.cwd }),
2008
+ turnTracker: createTurnTracker({ cwd: config.cwd }, logger),
1173
2009
  ...input.mcp ? { mcpManager: input.mcp } : {},
1174
2010
  ...promptBuilder ? { promptBuilder } : {},
1175
2011
  interventionCtrl: new InterventionController(),
1176
- host: input.host ?? localHost(config.cwd),
1177
- ownsHost: input.host === void 0,
2012
+ ...humanInputSetup,
2013
+ ...executionEnvironment,
1178
2014
  middlewareRunner: middlewareSetup.middlewareRunner,
2015
+ logger,
1179
2016
  ...middlewareSetup.telemetrySettings ? { telemetrySettings: middlewareSetup.telemetrySettings } : {},
1180
2017
  ...middlewareSetup.tracingShutdown ? { tracingShutdown: middlewareSetup.tracingShutdown } : {}
1181
2018
  };
@@ -1212,6 +2049,10 @@ var Agent = class _Agent {
1212
2049
  interventionCtrl;
1213
2050
  /** Execution environment for tool operations */
1214
2051
  host;
2052
+ /** Managed sandbox session, when the agent was created from one */
2053
+ sandbox;
2054
+ /** Managed human-input controller for question-style tools */
2055
+ humanInputController;
1215
2056
  /** Whether the agent owns the host and can safely recreate it on cwd changes */
1216
2057
  ownsHost;
1217
2058
  /** Middleware runner for lifecycle hooks */
@@ -1228,6 +2069,8 @@ var Agent = class _Agent {
1228
2069
  activeTurns = /* @__PURE__ */ new Map();
1229
2070
  /** Per-session turn queue to prevent concurrent writes to the same history */
1230
2071
  sessionLocks = /* @__PURE__ */ new Map();
2072
+ /** Structured logger for diagnostic output */
2073
+ _logger;
1231
2074
  constructor(config) {
1232
2075
  const setup = createAgentSetup(config);
1233
2076
  this.config = setup.config;
@@ -1240,8 +2083,11 @@ var Agent = class _Agent {
1240
2083
  this.promptBuilder = setup.promptBuilder;
1241
2084
  this.interventionCtrl = setup.interventionCtrl;
1242
2085
  this.host = setup.host;
2086
+ this.sandbox = setup.sandbox;
2087
+ this.humanInputController = setup.humanInputController;
1243
2088
  this.ownsHost = setup.ownsHost;
1244
2089
  this.middlewareRunner = setup.middlewareRunner;
2090
+ this._logger = setup.logger;
1245
2091
  this.telemetrySettings = setup.telemetrySettings;
1246
2092
  this.tracingShutdown = setup.tracingShutdown;
1247
2093
  this._signal = config.signal ?? new LocalSignal();
@@ -1256,9 +2102,13 @@ var Agent = class _Agent {
1256
2102
  get signal() {
1257
2103
  return this._signal;
1258
2104
  }
2105
+ /** Structured logger — silent by default, configurable via `createAgent({ logger })`. */
2106
+ get logger() {
2107
+ return this._logger;
2108
+ }
1259
2109
  /** Agent name (identity for spans, Dapr workflows, etc.) */
1260
2110
  get name() {
1261
- return this.config.name ?? "agent";
2111
+ return this.config.name ?? DEFAULT_AGENT_NAME;
1262
2112
  }
1263
2113
  /** Working directory for file operations */
1264
2114
  get cwd() {
@@ -1328,8 +2178,8 @@ var Agent = class _Agent {
1328
2178
  async acquireSessionLock(sessionId) {
1329
2179
  const previous = this.sessionLocks.get(sessionId) ?? Promise.resolve();
1330
2180
  let releaseLock;
1331
- const current = new Promise((resolve) => {
1332
- releaseLock = resolve;
2181
+ const current = new Promise((resolve2) => {
2182
+ releaseLock = resolve2;
1333
2183
  });
1334
2184
  const chain = previous.catch(() => void 0).then(() => current);
1335
2185
  this.sessionLocks.set(sessionId, chain);
@@ -1344,6 +2194,29 @@ var Agent = class _Agent {
1344
2194
  }
1345
2195
  };
1346
2196
  }
2197
+ /**
2198
+ * Force-clear all pending session locks for a given session.
2199
+ *
2200
+ * This is an escape hatch for callers that manage sequencing
2201
+ * externally (e.g. the coordinator loop) and need to guarantee a
2202
+ * prior `chat()` generator's lock won't block the next call — even
2203
+ * if the generator's cleanup is stuck on a network read.
2204
+ *
2205
+ * **Only use when you are certain no concurrent `chat()` calls are
2206
+ * active on this session.**
2207
+ */
2208
+ clearSessionLock(sessionId) {
2209
+ this.sessionLocks.delete(sessionId);
2210
+ }
2211
+ /**
2212
+ * Acquire the same per-session turn lock used by `chat()`.
2213
+ *
2214
+ * External durable runtimes can hold this lock across a workflow-backed
2215
+ * turn so direct `chat()` calls cannot interleave with the same session.
2216
+ */
2217
+ async acquireSessionTurnLock(sessionId) {
2218
+ return await this.acquireSessionLock(sessionId);
2219
+ }
1347
2220
  getActiveInterventionController() {
1348
2221
  const active = Array.from(this.activeTurns.values());
1349
2222
  if (active.length === 0) {
@@ -1377,7 +2250,6 @@ var Agent = class _Agent {
1377
2250
  0,
1378
2251
  this.activeTurnCount + (active ? 1 : -1)
1379
2252
  );
1380
- this.state.isStreaming = this.activeTurnCount > 0;
1381
2253
  }
1382
2254
  async syncSessionView(sessionId) {
1383
2255
  if (!await this.sessions.sessionExists(sessionId)) {
@@ -1394,34 +2266,11 @@ var Agent = class _Agent {
1394
2266
  manager: this.mcpManager,
1395
2267
  connected: this.mcpConnected,
1396
2268
  cachedTools: this.mcpToolsCache
1397
- });
2269
+ }, this._logger);
1398
2270
  this.mcpConnected = nextState.connected;
1399
2271
  this.mcpToolsCache = nextState.cachedTools;
1400
2272
  return nextState.cachedTools ?? {};
1401
2273
  }
1402
- /**
1403
- * Repair session history by synthesising missing tool-result messages.
1404
- *
1405
- * When a tool `execute()` throws, the AI SDK emits `tool-error` instead
1406
- * of `tool-result`. If the error event wasn't persisted (e.g. because
1407
- * the fix above wasn't in place), subsequent turns will fail with
1408
- * `MissingToolResultsError`. This method detects orphaned tool-call IDs
1409
- * and adds placeholder `tool` messages so the history is valid again.
1410
- */
1411
- async repairOrphanedToolCalls(sessions) {
1412
- await repairOrphanedToolCalls(sessions);
1413
- }
1414
- /**
1415
- * Convert internal {@link Message} array to Vercel AI SDK {@link ModelMessage} format.
1416
- *
1417
- * Handles the role-specific mappings:
1418
- * - `user` / `system` → pass-through
1419
- * - `assistant` with tool calls → `ToolCallPart[]` content
1420
- * - `tool` → `tool-result` content part
1421
- */
1422
- toModelMessages(messages) {
1423
- return convertAgentMessagesToModelMessages(messages);
1424
- }
1425
2274
  /**
1426
2275
  * Stream a chat response.
1427
2276
  *
@@ -1455,15 +2304,16 @@ var Agent = class _Agent {
1455
2304
  cwd: this.config.cwd
1456
2305
  });
1457
2306
  turnTracker.startTurn(turnId);
1458
- await this.repairOrphanedToolCalls(sessions);
2307
+ await repairOrphanedToolCalls(sessions);
1459
2308
  const mcpTools = await this.ensureMCPConnected();
1460
2309
  const loop = runChatLoop({
1461
2310
  sessionId,
2311
+ turnId,
1462
2312
  message,
1463
2313
  abort,
1464
2314
  systemOverride: options?.system,
1465
2315
  sessions,
1466
- tools: createAgentToolRecord(this.tools),
2316
+ tools: this.tools,
1467
2317
  config: this.config,
1468
2318
  turnTracker,
1469
2319
  interventionCtrl,
@@ -1473,14 +2323,17 @@ var Agent = class _Agent {
1473
2323
  reasoningLevel: this.state.reasoningLevel,
1474
2324
  promptBuilder: this.promptBuilder,
1475
2325
  host: this.host,
2326
+ humanInputController: this.humanInputController,
1476
2327
  mcpTools,
1477
2328
  telemetrySettings: this.telemetrySettings,
1478
- toModelMessages: this.toModelMessages.bind(this),
2329
+ toModelMessages: convertAgentMessagesToModelMessages,
1479
2330
  setIsStreaming: (value) => {
1480
2331
  if (value === streamingStateActive) return;
1481
2332
  streamingStateActive = value;
1482
2333
  this.syncStreamingState(value);
1483
- }
2334
+ },
2335
+ toolExecutionMode: this.config.toolExecutionMode,
2336
+ logger: this._logger
1484
2337
  });
1485
2338
  for await (const event of loop) {
1486
2339
  this._signal.emit(event);
@@ -1572,7 +2425,15 @@ var Agent = class _Agent {
1572
2425
  getSessionContext() {
1573
2426
  return this.sessions.getContext();
1574
2427
  }
1575
- /** Get messages from current session */
2428
+ /**
2429
+ * Get messages from current session.
2430
+ *
2431
+ * NOTE: during an active `chat()` turn, messages are accumulated in a
2432
+ * per-turn SessionManager and synced back after the turn completes.
2433
+ * Calling this mid-turn returns the shared view, which may lag behind
2434
+ * the in-progress turn. Use `send()` or consume the `chat()` generator
2435
+ * for real-time access to turn messages.
2436
+ */
1576
2437
  getMessages() {
1577
2438
  return this.sessions.getMessages();
1578
2439
  }
@@ -1613,8 +2474,7 @@ var Agent = class _Agent {
1613
2474
  * ```
1614
2475
  */
1615
2476
  getContextStats() {
1616
- return getAgentContextStats(
1617
- this.contextManager,
2477
+ return this.contextManager.getStats(
1618
2478
  this.sessions.getMessages()
1619
2479
  );
1620
2480
  }
@@ -1629,7 +2489,8 @@ var Agent = class _Agent {
1629
2489
  async compactContext() {
1630
2490
  return await compactAgentContext({
1631
2491
  contextManager: this.contextManager,
1632
- sessions: this.sessions
2492
+ sessions: this.sessions,
2493
+ logger: this._logger
1633
2494
  });
1634
2495
  }
1635
2496
  /**
@@ -1813,14 +2674,12 @@ var Agent = class _Agent {
1813
2674
  */
1814
2675
  setSystemPrompt(prompt) {
1815
2676
  this.config.systemPrompt = prompt;
1816
- this.state.systemPrompt = prompt;
1817
2677
  this.promptBuilder = void 0;
1818
2678
  this.resetPromptScopedTools();
1819
2679
  }
1820
2680
  /** Update working directory */
1821
2681
  setCwd(cwd) {
1822
2682
  this.config.cwd = cwd;
1823
- this.state.cwd = cwd;
1824
2683
  this.turnTracker = createTurnTracker({ cwd });
1825
2684
  if (this.ownsHost) {
1826
2685
  this.host = localHost(cwd);
@@ -1902,7 +2761,8 @@ var Agent = class _Agent {
1902
2761
  getTurnRuntimeConfig() {
1903
2762
  return createAgentTurnRuntimeConfig({
1904
2763
  config: this.config,
1905
- telemetrySettings: this.telemetrySettings
2764
+ telemetrySettings: this.telemetrySettings,
2765
+ reserveTokens: this.contextManager.getLimits().reserveTokens
1906
2766
  });
1907
2767
  }
1908
2768
  /**
@@ -1911,6 +2771,26 @@ var Agent = class _Agent {
1911
2771
  getHost() {
1912
2772
  return this.host;
1913
2773
  }
2774
+ /**
2775
+ * Get the configured sandbox session, if one was provided.
2776
+ */
2777
+ getSandbox() {
2778
+ return this.sandbox;
2779
+ }
2780
+ /**
2781
+ * Get the configured human-input controller, if one was provided.
2782
+ */
2783
+ getHumanInputController() {
2784
+ return this.humanInputController;
2785
+ }
2786
+ /**
2787
+ * Whether any registered tool advertises human-input semantics.
2788
+ */
2789
+ hasHumanInputTools() {
2790
+ return [...this.tools.values()].some(
2791
+ (tool) => tool.capabilitiesHint?.humanInput === true
2792
+ );
2793
+ }
1914
2794
  /**
1915
2795
  * Get the configured middleware runner.
1916
2796
  *
@@ -1920,6 +2800,18 @@ var Agent = class _Agent {
1920
2800
  getMiddlewareRunner() {
1921
2801
  return this.middlewareRunner;
1922
2802
  }
2803
+ /**
2804
+ * Get the configured middleware stack.
2805
+ */
2806
+ getMiddleware() {
2807
+ return this.middlewareRunner.getMiddleware();
2808
+ }
2809
+ /**
2810
+ * Ensure MCP is connected and return the current MCP tool set.
2811
+ */
2812
+ async getMcpTools() {
2813
+ return await this.ensureMCPConnected();
2814
+ }
1923
2815
  // ============================================================================
1924
2816
  // Sub-Agents (Forking)
1925
2817
  // ============================================================================
@@ -1961,6 +2853,8 @@ var Agent = class _Agent {
1961
2853
  parentTools: Array.from(this.tools.values()),
1962
2854
  reasoningLevel: this.state.reasoningLevel,
1963
2855
  host: this.host,
2856
+ sandbox: this.sandbox,
2857
+ humanInputController: this.humanInputController,
1964
2858
  ownsHost: this.ownsHost,
1965
2859
  sessions: this.sessions,
1966
2860
  mcpManager: this.mcpManager,
@@ -1970,29 +2864,29 @@ var Agent = class _Agent {
1970
2864
  );
1971
2865
  }
1972
2866
  /**
1973
- * Create a sub-agent with a preset configuration.
2867
+ * Create a sub-agent with a profile.
1974
2868
  *
1975
- * Convenience method that applies a preset and returns a forked agent.
2869
+ * Convenience method that applies a profile and returns a forked agent.
1976
2870
  *
1977
2871
  * @example
1978
2872
  * ```typescript
1979
- * import { Presets } from "@cuylabs/agent-core";
2873
+ * import { Profiles } from "@cuylabs/agent-core";
1980
2874
  *
1981
2875
  * // Create an exploration sub-agent
1982
- * const explorer = agent.withPreset(Presets.explore);
2876
+ * const explorer = agent.withProfile(Profiles.explore);
1983
2877
  * const result = await explorer.run({
1984
2878
  * message: "Find all API routes in this project",
1985
2879
  * });
1986
2880
  *
1987
2881
  * // Create a careful review sub-agent
1988
- * const reviewer = agent.withPreset(Presets.review);
2882
+ * const reviewer = agent.withProfile(Profiles.review);
1989
2883
  * const review = await reviewer.run({
1990
2884
  * message: "Review src/auth.ts for security issues",
1991
2885
  * });
1992
2886
  * ```
1993
2887
  */
1994
- withPreset(preset) {
1995
- return this.fork({ preset });
2888
+ withProfile(profile) {
2889
+ return this.fork({ profile });
1996
2890
  }
1997
2891
  /**
1998
2892
  * Run a task in an isolated sub-agent session.
@@ -2068,6 +2962,7 @@ var Agent = class _Agent {
2068
2962
  */
2069
2963
  async close() {
2070
2964
  this._signal.clear();
2965
+ this.humanInputController?.cancelAll("Agent closed");
2071
2966
  if (this.tracingShutdown) {
2072
2967
  await this.tracingShutdown();
2073
2968
  }
@@ -2077,30 +2972,243 @@ var Agent = class _Agent {
2077
2972
  }
2078
2973
  };
2079
2974
 
2080
- // src/agent/concurrent.ts
2081
- async function runConcurrent(tasks, options) {
2082
- const maxConcurrency = options?.maxConcurrency ?? 5;
2083
- const results = new Array(tasks.length);
2084
- let currentIndex = 0;
2085
- async function runNext() {
2086
- while (currentIndex < tasks.length) {
2087
- if (options?.abort?.aborted) break;
2088
- const index = currentIndex++;
2089
- const task = tasks[index];
2090
- results[index] = await task.agent.run({
2091
- parentSessionId: task.parentSessionId,
2092
- message: task.message,
2093
- title: task.title,
2094
- abort: options?.abort
2095
- });
2975
+ // src/agent/event-printer.ts
2976
+ function createEventPrinter(options = {}) {
2977
+ const {
2978
+ tools = true,
2979
+ reasoning = true,
2980
+ steps = false,
2981
+ safety = true,
2982
+ completion = true,
2983
+ team = false,
2984
+ stdout = process.stdout,
2985
+ stderr = process.stderr
2986
+ } = options;
2987
+ return (event) => {
2988
+ switch (event.type) {
2989
+ // ── Lifecycle ─────────────────────────────────────────────────
2990
+ case "status":
2991
+ if (steps) stderr.write(`\u23F3 Status \u2192 ${event.status}
2992
+ `);
2993
+ break;
2994
+ case "step-start":
2995
+ if (steps) stderr.write(`\u{1F4CD} Step ${event.step}/${event.maxSteps}
2996
+ `);
2997
+ break;
2998
+ case "step-finish":
2999
+ break;
3000
+ // silent by default
3001
+ case "turn-boundary":
3002
+ if (steps) stderr.write(`\u{1F9F1} Boundary \u2192 ${event.boundary}
3003
+ `);
3004
+ break;
3005
+ // ── Text streaming ────────────────────────────────────────────
3006
+ case "text-start":
3007
+ break;
3008
+ // cursor is already in place
3009
+ case "text-delta":
3010
+ stdout.write(event.text);
3011
+ break;
3012
+ case "text-end":
3013
+ stdout.write("\n");
3014
+ break;
3015
+ // ── Messages ──────────────────────────────────────────────────
3016
+ case "message":
3017
+ break;
3018
+ // too noisy for CLI output
3019
+ // ── Reasoning ─────────────────────────────────────────────────
3020
+ case "reasoning-start":
3021
+ if (reasoning) stderr.write("\u{1F4AD} ");
3022
+ break;
3023
+ case "reasoning-delta":
3024
+ if (reasoning) stderr.write(event.text);
3025
+ break;
3026
+ case "reasoning-end":
3027
+ if (reasoning) stderr.write("\n");
3028
+ break;
3029
+ // ── Tool execution ────────────────────────────────────────────
3030
+ case "tool-start":
3031
+ if (tools)
3032
+ stderr.write(
3033
+ `\u{1F527} ${event.toolName}(${JSON.stringify(event.input)})
3034
+ `
3035
+ );
3036
+ break;
3037
+ case "tool-result":
3038
+ if (tools)
3039
+ stderr.write(` \u2713 ${String(event.result).slice(0, 200)}
3040
+ `);
3041
+ break;
3042
+ case "tool-error":
3043
+ if (tools) stderr.write(` \u2717 ${event.error}
3044
+ `);
3045
+ break;
3046
+ // ── Approval / intervention ───────────────────────────────────
3047
+ case "approval-request":
3048
+ if (safety)
3049
+ stderr.write(
3050
+ `\u{1F6C2} Approval needed \u2192 ${event.request.tool} [${event.request.risk}]
3051
+ `
3052
+ );
3053
+ break;
3054
+ case "approval-resolved":
3055
+ if (safety)
3056
+ stderr.write(`\u{1F6C2} Approval ${event.id} \u2192 ${event.action}
3057
+ `);
3058
+ break;
3059
+ case "intervention-applied":
3060
+ if (safety)
3061
+ stderr.write(`\u270B Intervention \u2192 ${event.message}
3062
+ `);
3063
+ break;
3064
+ case "follow-up-queued":
3065
+ if (safety)
3066
+ stderr.write(`\u{1F4CC} Follow-up queued \u2192 ${event.message}
3067
+ `);
3068
+ break;
3069
+ // ── Safety ────────────────────────────────────────────────────
3070
+ case "doom-loop":
3071
+ if (safety)
3072
+ stderr.write(
3073
+ `\u26A0\uFE0F Doom loop: ${event.toolName} repeated ${event.repeatCount}x
3074
+ `
3075
+ );
3076
+ break;
3077
+ case "context-overflow":
3078
+ if (safety)
3079
+ stderr.write(
3080
+ `\u26A0\uFE0F Context overflow: ${event.inputTokens}/${event.limit} tokens
3081
+ `
3082
+ );
3083
+ break;
3084
+ case "turn-summary":
3085
+ if (safety)
3086
+ stderr.write(
3087
+ `\u{1F5C2}\uFE0F Turn summary \u2192 ${event.files.length} file(s), +${event.additions}/-${event.deletions}
3088
+ `
3089
+ );
3090
+ break;
3091
+ // ── Computer use ──────────────────────────────────────────────
3092
+ case "computer-call":
3093
+ if (tools)
3094
+ stderr.write(`\u{1F5A5}\uFE0F Computer action \u2192 ${event.callId}
3095
+ `);
3096
+ break;
3097
+ case "computer-result":
3098
+ if (tools)
3099
+ stderr.write(`\u{1F5A5}\uFE0F Computer result \u2192 ${event.callId}
3100
+ `);
3101
+ break;
3102
+ // ── Human input ───────────────────────────────────────────────
3103
+ case "human-input-request":
3104
+ if (safety)
3105
+ stderr.write(
3106
+ `\u2753 ${event.request.title}: ${event.request.question}
3107
+ `
3108
+ );
3109
+ break;
3110
+ case "human-input-resolved":
3111
+ break;
3112
+ // host handles display
3113
+ // ── Error & retry ─────────────────────────────────────────────
3114
+ case "retry":
3115
+ stderr.write(
3116
+ `\u{1F501} Retry ${event.attempt} in ${event.delayMs}ms
3117
+ `
3118
+ );
3119
+ break;
3120
+ case "error":
3121
+ stderr.write(`\u274C ${event.error.message}
3122
+ `);
3123
+ break;
3124
+ // ── Completion ────────────────────────────────────────────────
3125
+ case "complete":
3126
+ if (completion)
3127
+ stderr.write(
3128
+ `\u2705 Done \u2014 ${event.usage?.totalTokens ?? "?"} tokens
3129
+ `
3130
+ );
3131
+ break;
3132
+ // ── Team events ───────────────────────────────────────────────
3133
+ default:
3134
+ if (team && "type" in event && event.type.startsWith("team-")) {
3135
+ printTeamEvent(stderr, event);
3136
+ }
3137
+ break;
2096
3138
  }
3139
+ };
3140
+ }
3141
+ function printTeamEvent(out, event) {
3142
+ switch (event.type) {
3143
+ case "team-started":
3144
+ out.write(`\u{1F3C1} Team started
3145
+ `);
3146
+ break;
3147
+ case "team-member-registered":
3148
+ out.write(
3149
+ ` \u{1F464} ${event.member.id} (${event.member.role})
3150
+ `
3151
+ );
3152
+ break;
3153
+ case "team-task-completed":
3154
+ out.write(
3155
+ ` \u2705 Task ${event.taskId} completed
3156
+ `
3157
+ );
3158
+ break;
3159
+ case "team-task-failed":
3160
+ out.write(
3161
+ ` \u274C Task ${event.taskId} failed
3162
+ `
3163
+ );
3164
+ break;
3165
+ case "team-stopped":
3166
+ out.write(`\u{1F3C1} Team stopped
3167
+ `);
3168
+ break;
2097
3169
  }
2098
- const workers = Array.from(
2099
- { length: Math.min(maxConcurrency, tasks.length) },
2100
- () => runNext()
2101
- );
2102
- await Promise.all(workers);
2103
- return results;
3170
+ }
3171
+
3172
+ // src/intervention/follow-up-policy.ts
3173
+ function normalizeFollowUpMode(mode) {
3174
+ return mode ?? "suggest";
3175
+ }
3176
+ function createQueuedFollowUpRecord(request, options = {}) {
3177
+ const createdAt = options.createdAt ?? new Date(request.timestamp).toISOString();
3178
+ return {
3179
+ id: request.id,
3180
+ sessionId: request.sessionId,
3181
+ message: request.message,
3182
+ createdAt,
3183
+ updatedAt: options.updatedAt ?? createdAt,
3184
+ mode: normalizeFollowUpMode(options.mode),
3185
+ status: "queued",
3186
+ ...options.sourceTurnId ? { sourceTurnId: options.sourceTurnId } : {},
3187
+ ...options.workflowInstanceId ? { workflowInstanceId: options.workflowInstanceId } : {}
3188
+ };
3189
+ }
3190
+ function resolveQueuedFollowUp(record, action, updatedAt) {
3191
+ return {
3192
+ ...record,
3193
+ status: action === "accept" ? "accepted" : "discarded",
3194
+ updatedAt,
3195
+ decidedAt: updatedAt
3196
+ };
3197
+ }
3198
+ function markQueuedFollowUpApplied(record, updatedAt, seededTurnId) {
3199
+ return {
3200
+ ...record,
3201
+ status: "applied",
3202
+ updatedAt,
3203
+ appliedAt: updatedAt,
3204
+ ...seededTurnId ? { seededTurnId } : {}
3205
+ };
3206
+ }
3207
+ function canSeedQueuedFollowUp(record) {
3208
+ if (record.status === "accepted") {
3209
+ return true;
3210
+ }
3211
+ return record.status === "queued" && record.mode === "auto-run";
2104
3212
  }
2105
3213
  export {
2106
3214
  Agent,
@@ -2111,39 +3219,49 @@ export {
2111
3219
  CapabilityCache,
2112
3220
  ContextManager,
2113
3221
  ContextOverflowError,
3222
+ DEFAULT_AGENT_NAME,
2114
3223
  DEFAULT_CONTEXT_LIMITS,
3224
+ DEFAULT_DISPATCH_TOOL_IDS,
2115
3225
  DEFAULT_EXTERNAL_DIRS,
2116
3226
  DEFAULT_INSTRUCTION_PATTERNS,
2117
- DEFAULT_MAX_CONCURRENT,
3227
+ DEFAULT_LOCAL_DISPATCH_CONCURRENCY,
3228
+ DEFAULT_LOCAL_DISPATCH_DEPTH,
3229
+ DEFAULT_LOCAL_DISPATCH_TITLE_PREFIX,
2118
3230
  DEFAULT_MAX_DEPTH,
2119
3231
  DEFAULT_MAX_FILE_SIZE,
2120
- DEFAULT_MAX_OUTPUT_TOKENS,
3232
+ DEFAULT_MAX_TOKENS as DEFAULT_MAX_OUTPUT_TOKENS,
2121
3233
  DEFAULT_MAX_SCAN_DEPTH,
2122
- DEFAULT_MAX_SPAWN_DEPTH,
2123
3234
  DEFAULT_MAX_STEPS,
2124
3235
  DEFAULT_MAX_TOKENS,
2125
3236
  DEFAULT_RESOLVER_OPTIONS,
2126
3237
  DEFAULT_RETRY_CONFIG,
2127
- DEFAULT_SESSION_TITLE_PREFIX,
2128
3238
  DEFAULT_SKILL_MAX_SIZE,
3239
+ DEFAULT_SUBAGENT_CONCURRENCY,
3240
+ DEFAULT_SUBAGENT_DEPTH,
3241
+ DEFAULT_SUBAGENT_SESSION_PREFIX,
2129
3242
  DEFAULT_SYSTEM_PROMPT,
3243
+ DISPATCH_STATES,
2130
3244
  DoomLoopError,
2131
3245
  EXTENDED_LEVELS,
2132
3246
  FIXED_LEVELS,
2133
3247
  FileStorage,
3248
+ HumanInputTimeoutError,
3249
+ HumanInputUnavailableError,
3250
+ InMemoryMailboxStore,
3251
+ InMemoryTaskBoardStore,
2134
3252
  Inference,
2135
3253
  InterventionController,
2136
- LLM,
2137
3254
  LLMError,
3255
+ LOCAL_SUBAGENT_BACKEND,
2138
3256
  LayeredSettings,
2139
3257
  LocalSignal,
2140
3258
  MAX_BYTES,
2141
3259
  MAX_LINES,
3260
+ Mailbox,
2142
3261
  MemoryStorage,
2143
3262
  MiddlewareRunner,
2144
3263
  ModelCapabilityResolver,
2145
3264
  NullSettings,
2146
- OUTPUT_TOKEN_MAX,
2147
3265
  PRIORITY_BASE,
2148
3266
  PRIORITY_CUSTOM,
2149
3267
  PRIORITY_ENVIRONMENT,
@@ -2154,39 +3272,52 @@ export {
2154
3272
  PatternCapabilitySource,
2155
3273
  PluginEventBus,
2156
3274
  PluginRegistry,
2157
- Presets,
3275
+ Profiles,
2158
3276
  PromptBuilder,
2159
3277
  RemoteCapabilityFetcher,
2160
3278
  RemoteCapabilitySource,
2161
3279
  SKILL_FILENAME,
2162
3280
  STANDARD_LEVELS,
2163
3281
  STORAGE_VERSION,
3282
+ SUBAGENT_TOOL_IDS,
2164
3283
  SessionManager,
2165
3284
  SkillRegistry,
2166
3285
  SourcePriority,
2167
3286
  StaticSettings,
2168
- SubAgentTracker,
2169
- TRUNCATE_DIR,
2170
- TRUNCATE_GLOB,
3287
+ TERMINAL_STATUSES,
3288
+ TaskBoard,
3289
+ TaskConflictError,
3290
+ TeamCoordinator,
2171
3291
  Tool,
3292
+ ToolHostRegistry,
2172
3293
  ToolRegistry,
2173
3294
  TurnChangeTracker,
2174
3295
  ValidatedSettings,
3296
+ accumulateUsage,
3297
+ addTokenUsage,
2175
3298
  advanceAgentTurnState,
3299
+ allApprovalConditions,
3300
+ anyApprovalConditions,
2176
3301
  applyAgentWorkflowCommitResult,
2177
3302
  applyAgentWorkflowModelStepResult,
2178
3303
  applyAgentWorkflowToolBatchResult,
2179
3304
  applyAgentWorkflowToolCallResult,
2180
3305
  applyCapabilityOverride,
2181
- applyPreset,
3306
+ applyProfile,
3307
+ applyWorkflowInterventions,
2182
3308
  approvalMiddleware,
3309
+ approvalRequestsOverlap,
2183
3310
  autoDetectStreamProvider,
2184
3311
  buildAnthropicOptions,
3312
+ buildApprovalRuleContext,
2185
3313
  buildBedrockOptions,
3314
+ buildCoordinatorNotificationEvent,
3315
+ buildCoordinatorSystemPrompt,
2186
3316
  buildEntryPath,
2187
3317
  buildGoogleOptions,
2188
3318
  buildGroqOptions,
2189
3319
  buildMessagesFromEntries,
3320
+ buildModelCallContext,
2190
3321
  buildOpenAIOptions,
2191
3322
  buildOpenRouterOptions,
2192
3323
  buildReasoningOptions,
@@ -2194,58 +3325,95 @@ export {
2194
3325
  buildToolSet,
2195
3326
  buildXAIOptions,
2196
3327
  calculateDelay,
3328
+ canSeedQueuedFollowUp,
2197
3329
  careful,
2198
- clearCheckpoints,
3330
+ clearInstalledSubAgents,
2199
3331
  cloneAgentWorkflowTurnState,
2200
3332
  code,
2201
3333
  commitOutput,
2202
3334
  commitStep,
2203
3335
  configureDefaultSessionManager,
2204
3336
  configureResolver,
3337
+ configureSubAgents,
2205
3338
  convertAgentMessagesToModelMessages,
3339
+ coordinatorToolDescriptions,
2206
3340
  createAgent,
2207
3341
  createAgentTaskRunner,
2208
3342
  createAgentTurnEngine,
2209
3343
  createAgentTurnState,
2210
3344
  createAgentTurnStepCommitBatch,
2211
3345
  createAgentWorkflowTurnState,
3346
+ createApprovalCorrection,
2212
3347
  createApprovalHandler,
2213
- createCheckpointManager,
3348
+ createApprovalPolicyPreset,
3349
+ createCloseAgentTool,
3350
+ createCompositeDispatchTaskExecutor,
3351
+ createConditionalApprovalRule,
3352
+ createConsoleLogger,
3353
+ createDangerouslyAllowAllApprovalPolicy,
3354
+ createDispatchExternalTaskControl,
3355
+ createDispatchTaskExecutor,
3356
+ createDispatchTools,
3357
+ createEventBus,
3358
+ createEventPrinter,
3359
+ createFileLogger,
3360
+ createHeadlessDenyApprovalPolicy,
3361
+ createHumanInputController,
3362
+ createHumanInputHandler,
3363
+ createHumanInputTool,
3364
+ createHumanInputToolWithController,
3365
+ createHumanInputToolWithHandler,
3366
+ createInteractiveApprovalPolicy,
3367
+ createInvokeAgentTool,
3368
+ createLocalDispatchRuntime,
2214
3369
  createMCPManager,
2215
3370
  createMessageEntry,
2216
3371
  createMetadataEntry,
2217
- createPreset,
3372
+ createProfile,
2218
3373
  createPromptBuilder,
3374
+ createQueuedFollowUpRecord,
3375
+ createRememberedApprovalRules,
2219
3376
  createResolver,
2220
3377
  createRetryHandler,
2221
3378
  createRetryState,
2222
- createScope,
3379
+ createRiskTierApprovalPolicy,
3380
+ createRuntimeDispatchExecutor,
3381
+ createRuntimeDispatchTargets,
2223
3382
  createSkillRegistry,
2224
3383
  createSkillResourceTool,
2225
3384
  createSkillTool,
2226
3385
  createSkillTools,
2227
3386
  createSubAgentTools,
3387
+ createTeamCoordinator,
2228
3388
  createTelemetryConfig,
3389
+ createThresholdApprovalRule,
3390
+ createToolSearchTool,
3391
+ createTrustedSessionApprovalPolicy,
2229
3392
  createTurnTracker,
3393
+ createWaitAgentTool,
2230
3394
  currentScope,
2231
3395
  defaultAgentTaskCheckpointStrategy,
2232
3396
  defaultRegistry,
3397
+ defaultToolHostRegistry,
2233
3398
  definePlugin,
2234
- defineServer,
2235
- defineTool,
3399
+ describeApprovalOperation,
2236
3400
  deserializeMessage,
2237
3401
  detectModelFamily,
2238
- discoverAgentProfiles,
2239
3402
  discoverInstructions,
2240
3403
  discoverPlugins,
2241
3404
  discoverSkills,
2242
- dockerHost,
3405
+ discoverSubAgentRoles,
3406
+ drainWorkflowInterventions,
2243
3407
  emptySkillRegistry,
3408
+ ensureNonEmpty,
3409
+ ensureSessionLoaded,
2244
3410
  estimateConversationTokens,
2245
3411
  estimateMessageTokens,
2246
3412
  estimateTokens,
3413
+ evaluateCoordinatorRoundTransition,
2247
3414
  executeAgentToolCall,
2248
3415
  explore,
3416
+ extractApprovalPatterns,
2249
3417
  extractFilePathsFromArgs,
2250
3418
  extractModelId,
2251
3419
  extractProvider,
@@ -2255,43 +3423,64 @@ export {
2255
3423
  filterTools,
2256
3424
  findCapabilityOverride,
2257
3425
  findCutPoint,
3426
+ formatApprovalDeniedReason,
3427
+ formatAsyncSpawnedResult,
3428
+ formatCancelledAgentResult,
3429
+ formatCloseAlreadyResolvedResult,
3430
+ formatCloseMissingAgentResult,
3431
+ formatCoordinatorRoundMessage,
3432
+ formatCoordinatorTaskNotifications,
3433
+ formatCoordinatorWorkerReports,
2258
3434
  formatEnvironment,
2259
3435
  formatInstructions,
2260
- formatSize,
3436
+ formatInvalidAgentTypeResult,
3437
+ formatMissingAgentsResult,
3438
+ formatSpawnBlockedResult,
3439
+ formatSyncSubAgentErrorResult,
3440
+ formatSyncSubAgentResult,
3441
+ formatWaitErrorResult,
3442
+ formatWaitResult,
3443
+ formatWaitTimeoutResult,
2261
3444
  gatherEnvironment,
2262
3445
  generateEntryId,
2263
- generateSummary,
2264
3446
  getAvailableFamilies,
3447
+ getConfiguredSubAgents,
2265
3448
  getDataDir,
2266
3449
  getDefaultResolver,
2267
3450
  getDefaultSessionManager,
2268
3451
  getErrorCategory,
2269
3452
  getGitRootHash,
3453
+ getInstalledSubAgentBackend,
2270
3454
  getLeafId,
2271
3455
  getModelId,
2272
3456
  getNetworkStatus,
2273
3457
  getPluginLoader,
2274
- getProjectAgentsDir,
2275
3458
  getProjectId,
2276
3459
  getProjectSessionsDir,
3460
+ getProjectSubAgentRolesDir,
2277
3461
  getProviderCompatibility,
2278
3462
  getProviderId,
2279
3463
  getProviderOptionsKey,
2280
3464
  getReasoningConfig,
2281
3465
  getReasoningConfigSync,
3466
+ getRequiredToolHost,
2282
3467
  getRetryDelay,
2283
3468
  getSessionsDir,
2284
3469
  getTemplate,
2285
3470
  getToolRisk,
2286
- getUserAgentsDir,
2287
- hasStreamProviderFactory,
3471
+ getUsableTokenLimit,
3472
+ getUserSubAgentRolesDir,
2288
3473
  httpServer,
2289
3474
  inferContextWindow,
2290
3475
  inferProvider,
2291
3476
  inferResourceType,
2292
- isContextOverflowing,
3477
+ installLocalSubAgents,
3478
+ installSubAgentTools,
3479
+ isApprovalMiddleware,
3480
+ isBlockedModelCall,
2293
3481
  isDefinedPlugin,
2294
- isMarkdownProfile,
3482
+ isHumanInputController,
3483
+ isMarkdownSubAgentRole,
2295
3484
  isRetryable,
2296
3485
  isRetryableCategory,
2297
3486
  likelySupportsReasoning,
@@ -2301,42 +3490,56 @@ export {
2301
3490
  loadSkillContent,
2302
3491
  loadSkillMetadata,
2303
3492
  localHost,
2304
- mergePresets,
2305
- needsCustomStreamProvider,
3493
+ markQueuedFollowUpApplied,
3494
+ matchApprovalArgValue,
3495
+ matchApprovalNumericArg,
3496
+ matchApprovalPattern,
3497
+ matchApprovalRisks,
3498
+ matchApprovalSessions,
3499
+ matchApprovalStringPrefixes,
3500
+ mergeInspection,
3501
+ mergeProfiles,
3502
+ normalizeApprovalCascadePolicy,
3503
+ normalizeFollowUpMode,
3504
+ normalizeRememberScopes,
2306
3505
  normalizeToolReplayPolicy,
2307
3506
  otelMiddleware,
2308
- parseAgentFrontmatter,
2309
3507
  parseFrontmatter,
2310
3508
  parseJSONL,
2311
- parseMarkdownAgent,
3509
+ parseMarkdownSubAgentRole,
2312
3510
  parseRetryDelay,
2313
- parseToolSpec,
3511
+ parseSubAgentRoleFrontmatter,
3512
+ parseSubAgentToolSpec,
2314
3513
  plan,
2315
3514
  planNextAgentWorkflowOperation,
2316
3515
  prepareModelStep,
2317
3516
  processStepStream,
2318
- processStream,
2319
3517
  promptCacheMiddleware,
2320
- pruneContext,
2321
- pruneToolResults,
3518
+ queueWorkflowFollowUps,
2322
3519
  quick,
2323
3520
  recordAgentWorkflowReplayDecision,
3521
+ requiresToolHost,
2324
3522
  resetFrameworkAliases,
2325
3523
  resetPluginLoader,
3524
+ resolveAgentDefaults,
3525
+ resolveCapability,
2326
3526
  resolveFrameworkAliases,
3527
+ resolveQueuedFollowUp,
2327
3528
  restoreAgentWorkflowMessage,
2328
3529
  restoreAgentWorkflowMessages,
2329
3530
  restoreScope,
2330
3531
  review,
2331
3532
  runChatLoop,
2332
- runConcurrent,
2333
3533
  runModelStep,
2334
3534
  runToolBatch,
3535
+ sandboxDefaultsProvider,
3536
+ selectRememberScope,
2335
3537
  serializeMessage,
2336
3538
  shouldCaptureBaseline,
3539
+ shouldCascadeApprovalDecision,
2337
3540
  shouldIncludeReasoningSummary,
2338
- shouldPruneContext,
2339
3541
  shouldRetry,
3542
+ silentLogger,
2340
3543
  sleep,
2341
3544
  snapshotAgentWorkflowMessage,
2342
3545
  snapshotAgentWorkflowMessages,
@@ -2349,12 +3552,12 @@ export {
2349
3552
  summarizeEnvironment,
2350
3553
  supportsReasoning,
2351
3554
  supportsReasoningSync,
2352
- toAgentProfile,
3555
+ teamPermissionPolicy,
2353
3556
  toJSONL,
2354
3557
  toJSONLBatch,
3558
+ toSubAgentRole,
2355
3559
  truncateOutput,
2356
3560
  watch,
2357
- withFileTracking,
2358
3561
  withRetry,
2359
3562
  withinScope
2360
3563
  };