@cuylabs/agent-core 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/{builder-BRvqCcIk.d.ts → builder-BgZ_j4Vs.d.ts} +3 -2
  2. package/dist/chunk-4QFNWPIF.js +202 -0
  3. package/dist/chunk-5ARZJWD2.js +259 -0
  4. package/dist/chunk-DXFBQMXP.js +53 -0
  5. package/dist/chunk-EKR6PKXU.js +180 -0
  6. package/dist/{chunk-IVUJDISU.js → chunk-GFTW23FV.js} +5 -14
  7. package/dist/{chunk-IEFIQENH.js → chunk-H3FUYU52.js} +15 -7
  8. package/dist/chunk-I6PKJ7XQ.js +292 -0
  9. package/dist/chunk-IYWQOJMQ.js +102 -0
  10. package/dist/{chunk-3HNO5SVI.js → chunk-J4QDGZIA.js} +20 -4
  11. package/dist/{chunk-7MUFEN4K.js → chunk-JLXG2SH7.js} +349 -3
  12. package/dist/{chunk-CDTV2UYU.js → chunk-MAZ5DY5B.js} +64 -276
  13. package/dist/{chunk-P6YF7USR.js → chunk-MHKK374K.js} +12 -11
  14. package/dist/{chunk-VBWWUHWI.js → chunk-OFDKHNCX.js} +4 -1
  15. package/dist/{chunk-YUUJK53A.js → chunk-RKEW5WXI.js} +1 -1
  16. package/dist/{chunk-LRHOS4ZN.js → chunk-SPILYYDF.js} +3 -2
  17. package/dist/{chunk-QGOGIP7T.js → chunk-UDCZ673N.js} +385 -233
  18. package/dist/{chunk-BDBZ3SLK.js → chunk-UHCJEM2E.js} +39 -2
  19. package/dist/chunk-WGZAPU6N.js +929 -0
  20. package/dist/{chunk-5K7AQVOU.js → chunk-WKHDSSXG.js} +130 -209
  21. package/dist/{chunk-BNSHUWCV.js → chunk-WWYYNWEW.js} +1 -1
  22. package/dist/context/index.js +1 -1
  23. package/dist/events-CE72w8W4.d.ts +149 -0
  24. package/dist/index-BCqEGzBj.d.ts +251 -0
  25. package/dist/{index-C33hlD6H.d.ts → index-DQuTZ8xL.d.ts} +319 -56
  26. package/dist/index.d.ts +42 -121
  27. package/dist/index.js +951 -848
  28. package/dist/inference/errors/index.d.ts +11 -0
  29. package/dist/inference/errors/index.js +16 -0
  30. package/dist/inference/index.d.ts +12 -8
  31. package/dist/inference/index.js +35 -7
  32. package/dist/llm-error-D93FNNLY.d.ts +32 -0
  33. package/dist/middleware/index.d.ts +246 -7
  34. package/dist/middleware/index.js +3 -1
  35. package/dist/models/index.d.ts +132 -9
  36. package/dist/models/index.js +48 -8
  37. package/dist/models/reasoning/index.d.ts +4 -0
  38. package/dist/{reasoning → models/reasoning}/index.js +2 -7
  39. package/dist/plugin/index.d.ts +414 -0
  40. package/dist/plugin/index.js +32 -0
  41. package/dist/presets/index.d.ts +53 -0
  42. package/dist/presets/index.js +30 -0
  43. package/dist/prompt/index.d.ts +11 -8
  44. package/dist/prompt/index.js +3 -2
  45. package/dist/{registry-BDLIHOQB.d.ts → registry-DwYqsQkX.d.ts} +1 -1
  46. package/dist/runner-CI-XeR16.d.ts +91 -0
  47. package/dist/runtime/index.d.ts +12 -8
  48. package/dist/runtime/index.js +8 -7
  49. package/dist/safety/index.d.ts +38 -0
  50. package/dist/safety/index.js +12 -0
  51. package/dist/scope/index.d.ts +2 -2
  52. package/dist/{session-manager-B_CWGTsl.d.ts → session-manager-KbYt2WUh.d.ts} +8 -0
  53. package/dist/signal/index.d.ts +28 -0
  54. package/dist/signal/index.js +6 -0
  55. package/dist/skill/index.d.ts +7 -6
  56. package/dist/skill/index.js +3 -3
  57. package/dist/storage/index.d.ts +2 -2
  58. package/dist/storage/index.js +1 -1
  59. package/dist/sub-agent/index.d.ts +16 -10
  60. package/dist/sub-agent/index.js +21 -4
  61. package/dist/tool/index.d.ts +22 -6
  62. package/dist/tool/index.js +3 -3
  63. package/dist/tool-CZWN3KbO.d.ts +141 -0
  64. package/dist/{tool-HUtkiVBx.d.ts → tool-DkhSCV2Y.d.ts} +2 -2
  65. package/dist/tracking/index.d.ts +2 -2
  66. package/dist/tracking/index.js +1 -1
  67. package/dist/{tool-Db1Ue-1U.d.ts → types-BfNpU8NS.d.ts} +1 -150
  68. package/dist/{types-FRpzzg_9.d.ts → types-BlOKk-Bb.d.ts} +10 -35
  69. package/dist/types-BlZwmnuW.d.ts +50 -0
  70. package/dist/{types-9jGQUjqW.d.ts → types-CQL-SvTn.d.ts} +1 -1
  71. package/dist/types-CWm-7rvB.d.ts +55 -0
  72. package/dist/{runner-DSKaEz3z.d.ts → types-DTSkxakL.d.ts} +7 -235
  73. package/dist/{types-CqDZTh4d.d.ts → types-DmDwi2zI.d.ts} +8 -4
  74. package/dist/types-YuWV4ag7.d.ts +72 -0
  75. package/package.json +67 -6
  76. package/dist/capability-resolver-CgRGsWVX.d.ts +0 -254
  77. package/dist/chunk-ZPMACVZK.js +0 -305
  78. package/dist/index-CfBGYrpd.d.ts +0 -317
  79. package/dist/reasoning/index.d.ts +0 -117
package/dist/index.js CHANGED
@@ -1,3 +1,66 @@
1
+ import {
2
+ DEFAULT_MAX_CONCURRENT,
3
+ DEFAULT_MAX_SPAWN_DEPTH,
4
+ DEFAULT_SESSION_TITLE_PREFIX,
5
+ SubAgentTracker,
6
+ createSubAgentTools,
7
+ discoverAgentProfiles,
8
+ getProjectAgentsDir,
9
+ getUserAgentsDir,
10
+ isMarkdownProfile,
11
+ parseAgentFrontmatter,
12
+ parseMarkdownAgent,
13
+ parseToolSpec,
14
+ toAgentProfile
15
+ } from "./chunk-JLXG2SH7.js";
16
+ import {
17
+ ToolRegistry,
18
+ defaultRegistry
19
+ } from "./chunk-SDSBEQXG.js";
20
+ import {
21
+ TurnChangeTracker,
22
+ clearCheckpoints,
23
+ createCheckpointManager,
24
+ createTurnTracker
25
+ } from "./chunk-OFDKHNCX.js";
26
+ import {
27
+ applyPreset,
28
+ createPreset,
29
+ filterTools,
30
+ mergePresets
31
+ } from "./chunk-IYWQOJMQ.js";
32
+ import {
33
+ Presets,
34
+ careful,
35
+ code,
36
+ explore,
37
+ plan,
38
+ quick,
39
+ review,
40
+ watch
41
+ } from "./chunk-EKR6PKXU.js";
42
+ import {
43
+ DEFAULT_INSTRUCTION_PATTERNS,
44
+ DEFAULT_MAX_DEPTH,
45
+ DEFAULT_MAX_FILE_SIZE,
46
+ PRIORITY_BASE,
47
+ PRIORITY_CUSTOM,
48
+ PRIORITY_ENVIRONMENT,
49
+ PRIORITY_INSTRUCTIONS,
50
+ PRIORITY_OVERRIDE,
51
+ PRIORITY_SKILLS,
52
+ PromptBuilder,
53
+ createPromptBuilder,
54
+ detectModelFamily,
55
+ discoverInstructions,
56
+ formatEnvironment,
57
+ formatInstructions,
58
+ gatherEnvironment,
59
+ getAvailableFamilies,
60
+ getTemplate,
61
+ loadGlobalInstructions,
62
+ summarizeEnvironment
63
+ } from "./chunk-GFTW23FV.js";
1
64
  import {
2
65
  AgentTurnEngine,
3
66
  ContextOverflowError,
@@ -30,12 +93,41 @@ import {
30
93
  runToolBatch,
31
94
  snapshotAgentWorkflowMessage,
32
95
  snapshotAgentWorkflowMessages
33
- } from "./chunk-3HNO5SVI.js";
96
+ } from "./chunk-J4QDGZIA.js";
97
+ import {
98
+ LocalSignal
99
+ } from "./chunk-DXFBQMXP.js";
34
100
  import {
35
101
  createSkillResourceTool,
36
102
  createSkillTool,
37
103
  createSkillTools
38
- } from "./chunk-YUUJK53A.js";
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";
116
+ import {
117
+ DEFAULT_EXTERNAL_DIRS,
118
+ DEFAULT_MAX_SCAN_DEPTH,
119
+ DEFAULT_SKILL_MAX_SIZE,
120
+ SKILL_FILENAME,
121
+ SkillRegistry,
122
+ createSkillRegistry,
123
+ discoverSkills,
124
+ emptySkillRegistry,
125
+ inferResourceType,
126
+ loadResourceContent,
127
+ loadSkillContent,
128
+ loadSkillMetadata,
129
+ parseFrontmatter
130
+ } from "./chunk-SPILYYDF.js";
39
131
  import {
40
132
  FileStorage,
41
133
  MemoryStorage,
@@ -60,35 +152,7 @@ import {
60
152
  serializeMessage,
61
153
  toJSONL,
62
154
  toJSONLBatch
63
- } from "./chunk-BDBZ3SLK.js";
64
- import {
65
- DEFAULT_MAX_CONCURRENT,
66
- DEFAULT_MAX_SPAWN_DEPTH,
67
- DEFAULT_SESSION_TITLE_PREFIX,
68
- SubAgentTracker,
69
- createSubAgentTools
70
- } from "./chunk-7MUFEN4K.js";
71
- import {
72
- ToolRegistry,
73
- defaultRegistry
74
- } from "./chunk-SDSBEQXG.js";
75
- import {
76
- MAX_BYTES,
77
- MAX_LINES,
78
- TRUNCATE_DIR,
79
- TRUNCATE_GLOB,
80
- Tool,
81
- defineTool,
82
- formatSize,
83
- normalizeToolReplayPolicy,
84
- truncateOutput
85
- } from "./chunk-P6YF7USR.js";
86
- import {
87
- TurnChangeTracker,
88
- clearCheckpoints,
89
- createCheckpointManager,
90
- createTurnTracker
91
- } from "./chunk-VBWWUHWI.js";
155
+ } from "./chunk-UHCJEM2E.js";
92
156
  import {
93
157
  ContextManager,
94
158
  DEFAULT_CONTEXT_LIMITS,
@@ -102,7 +166,7 @@ import {
102
166
  pruneContext,
103
167
  pruneToolResults,
104
168
  shouldPruneContext
105
- } from "./chunk-BNSHUWCV.js";
169
+ } from "./chunk-WWYYNWEW.js";
106
170
  import {
107
171
  dockerHost,
108
172
  localHost
@@ -112,28 +176,72 @@ import {
112
176
  DEFAULT_RETRY_CONFIG,
113
177
  Inference,
114
178
  LLM,
115
- LLMError,
116
179
  OUTPUT_TOKEN_MAX,
117
180
  buildToolSet,
118
181
  calculateDelay,
119
182
  createRetryHandler,
120
183
  createRetryState,
121
- getErrorCategory,
122
- getRetryDelay,
123
- isRetryable,
124
- isRetryableCategory,
125
- parseRetryDelay,
126
184
  shouldRetry,
127
185
  sleep,
128
186
  stream,
129
187
  streamOnce,
130
188
  streamStep,
131
189
  withRetry
132
- } from "./chunk-5K7AQVOU.js";
190
+ } from "./chunk-WKHDSSXG.js";
191
+ import {
192
+ executeAgentToolCall
193
+ } from "./chunk-H3FUYU52.js";
194
+ import {
195
+ extractFilePathsFromArgs,
196
+ shouldCaptureBaseline,
197
+ withFileTracking
198
+ } from "./chunk-VEKUXUVF.js";
199
+ import {
200
+ LLMError,
201
+ getErrorCategory,
202
+ getRetryDelay,
203
+ isRetryable,
204
+ isRetryableCategory,
205
+ 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";
133
235
  import {
236
+ CacheCapabilitySource,
237
+ CapabilityCache,
134
238
  EXTENDED_LEVELS,
135
239
  FIXED_LEVELS,
240
+ ModelCapabilityResolver,
241
+ RemoteCapabilityFetcher,
242
+ RemoteCapabilitySource,
136
243
  STANDARD_LEVELS,
244
+ applyCapabilityOverride,
137
245
  buildAnthropicOptions,
138
246
  buildBedrockOptions,
139
247
  buildGoogleOptions,
@@ -143,158 +251,373 @@ import {
143
251
  buildReasoningOptions,
144
252
  buildReasoningOptionsSync,
145
253
  buildXAIOptions,
254
+ configureResolver,
255
+ createResolver,
256
+ findCapabilityOverride,
257
+ getDefaultResolver,
258
+ getNetworkStatus,
146
259
  getProviderOptionsKey,
147
260
  getReasoningConfig,
148
261
  getReasoningConfigSync,
149
262
  shouldIncludeReasoningSummary,
150
263
  supportsReasoning,
151
264
  supportsReasoningSync
152
- } from "./chunk-ZPMACVZK.js";
153
- import {
154
- executeAgentToolCall
155
- } from "./chunk-IEFIQENH.js";
156
- import {
157
- streamWithinScope
158
- } from "./chunk-N7P4PN3O.js";
159
- import {
160
- extractFilePathsFromArgs,
161
- shouldCaptureBaseline,
162
- withFileTracking
163
- } from "./chunk-VEKUXUVF.js";
164
- import {
165
- ApprovalDeniedError,
166
- ApprovalTimeoutError,
167
- MiddlewareRunner,
168
- approvalMiddleware,
169
- createApprovalHandler,
170
- createTelemetryConfig,
171
- getToolRisk,
172
- otelMiddleware,
173
- promptCacheMiddleware
174
- } from "./chunk-CDTV2UYU.js";
265
+ } from "./chunk-UDCZ673N.js";
175
266
  import {
176
- CacheCapabilitySource,
177
- CapabilityCache,
178
267
  DEFAULT_RESOLVER_OPTIONS,
179
- ModelCapabilityResolver,
180
268
  PatternCapabilitySource,
181
- RemoteCapabilityFetcher,
182
- RemoteCapabilitySource,
183
269
  SourcePriority,
184
- applyCapabilityOverride,
185
- configureResolver,
186
- createResolver,
187
270
  extractModelId,
188
271
  extractProvider,
189
- findCapabilityOverride,
190
- getDefaultResolver,
191
272
  getModelId,
192
- getNetworkStatus,
193
273
  getProviderCompatibility,
194
274
  getProviderId,
275
+ inferContextWindow,
195
276
  inferProvider,
196
277
  likelySupportsReasoning
197
- } from "./chunk-QGOGIP7T.js";
198
- import {
199
- createMCPManager,
200
- defineServer,
201
- httpServer,
202
- sseServer,
203
- stdioServer
204
- } from "./chunk-ZXAKHMWH.js";
205
- import {
206
- DEFAULT_INSTRUCTION_PATTERNS,
207
- DEFAULT_MAX_DEPTH,
208
- DEFAULT_MAX_FILE_SIZE,
209
- PRIORITY_BASE,
210
- PRIORITY_CUSTOM,
211
- PRIORITY_ENVIRONMENT,
212
- PRIORITY_INSTRUCTIONS,
213
- PRIORITY_OVERRIDE,
214
- PRIORITY_SKILLS,
215
- PromptBuilder,
216
- createPromptBuilder,
217
- detectModelFamily,
218
- discoverInstructions,
219
- formatEnvironment,
220
- formatInstructions,
221
- gatherEnvironment,
222
- getAvailableFamilies,
223
- getTemplate,
224
- loadGlobalInstructions,
225
- summarizeEnvironment
226
- } from "./chunk-IVUJDISU.js";
278
+ } from "./chunk-I6PKJ7XQ.js";
227
279
  import {
228
- DEFAULT_EXTERNAL_DIRS,
229
- DEFAULT_MAX_SCAN_DEPTH,
230
- DEFAULT_SKILL_MAX_SIZE,
231
- SKILL_FILENAME,
232
- SkillRegistry,
233
- createSkillRegistry,
234
- discoverSkills,
235
- emptySkillRegistry,
236
- inferResourceType,
237
- loadResourceContent,
238
- loadSkillContent,
239
- loadSkillMetadata,
240
- parseFrontmatter
241
- } from "./chunk-LRHOS4ZN.js";
242
-
243
- // src/agent/chat-loop/commit.ts
244
- function createChatLoopCommitBatchApplier(params) {
245
- const { turnEngine, sessions, middlewareRunner } = params;
246
- return async function* applyCommitBatch(batch, options = {}) {
247
- turnEngine.recordEvent(batch.startBoundary, (/* @__PURE__ */ new Date()).toISOString());
248
- middlewareRunner.emitEvent(batch.startBoundary);
249
- yield batch.startBoundary;
250
- await sessions.addMessages(batch.messages);
251
- turnEngine.recordEvent(batch.finishBoundary, (/* @__PURE__ */ new Date()).toISOString());
252
- middlewareRunner.emitEvent(batch.finishBoundary);
253
- yield batch.finishBoundary;
254
- if (options.emitMessages) {
255
- for (const committedMessage of batch.messages) {
256
- yield { type: "message", message: committedMessage };
257
- }
258
- }
259
- };
260
- }
261
-
262
- // src/agent/chat-loop/compaction.ts
263
- async function runAutoCompaction(params) {
264
- const { contextManager, messages } = params;
265
- if (!contextManager.shouldPrune(messages)) {
266
- return [];
267
- }
268
- const events = [{ type: "status", status: "processing" }];
269
- const pruneResult = await contextManager.prune(messages);
270
- if (pruneResult.removedCount > 0 || pruneResult.summarized) {
271
- const limits = contextManager.getLimits();
272
- events.push({
273
- type: "context-overflow",
274
- inputTokens: estimateConversationTokens(messages),
275
- limit: limits.contextWindow - limits.reserveTokens
276
- });
277
- }
278
- return events;
279
- }
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";
280
295
 
281
- // src/agent/chat-loop/prompts.ts
282
- async function buildChatSystemPrompts(params) {
296
+ // src/agent/intervention.ts
297
+ var InterventionController = class {
298
+ /** Immediate interventions — applied at the next step boundary */
299
+ immediate = [];
300
+ /** Deferred messages — held until the turn completes */
301
+ deferred = [];
302
+ /**
303
+ * Callback fired when an intervention is wired into a step.
304
+ * Set by the Agent before starting a chat turn, cleared after.
305
+ */
306
+ onApplied;
307
+ // ---------------------------------------------------------------------------
308
+ // Immediate interventions (mid-turn redirect)
309
+ // ---------------------------------------------------------------------------
310
+ /**
311
+ * Inject a message at the next LLM step boundary.
312
+ *
313
+ * The message is appended as a user message to the conversation
314
+ * before the next LLM call in the current multi-step turn. The
315
+ * LLM will see it and can adjust its behavior accordingly.
316
+ *
317
+ * Safe to call from any async context while `chat()` is running.
318
+ * If called when no turn is active, the message will be picked up
319
+ * by the first step of the next `chat()` call.
320
+ *
321
+ * @param message - The user message to inject
322
+ * @returns Intervention ID for tracking
323
+ */
324
+ intervene(message) {
325
+ const id = crypto.randomUUID();
326
+ this.immediate.push(
327
+ Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() })
328
+ );
329
+ return id;
330
+ }
331
+ /**
332
+ * Drain and return all pending immediate interventions.
333
+ * The internal queue is cleared atomically.
334
+ *
335
+ * @internal Called by the LLM stream's `prepareStep` hook
336
+ */
337
+ drainImmediate() {
338
+ if (this.immediate.length === 0) return [];
339
+ return this.immediate.splice(0);
340
+ }
341
+ /** Adopt existing immediate interventions without changing their IDs. */
342
+ adoptImmediate(items) {
343
+ if (items.length === 0) return;
344
+ this.immediate.push(...items);
345
+ }
346
+ /** Whether there are pending immediate interventions */
347
+ get hasPending() {
348
+ return this.immediate.length > 0;
349
+ }
350
+ /** Number of pending immediate interventions */
351
+ get pendingCount() {
352
+ return this.immediate.length;
353
+ }
354
+ // ---------------------------------------------------------------------------
355
+ // Deferred messages (after-turn follow-ups)
356
+ // ---------------------------------------------------------------------------
357
+ /**
358
+ * Queue a message for after the current turn completes.
359
+ *
360
+ * Unlike `intervene()`, this does **not** inject mid-turn. The
361
+ * message is held and available via `drainDeferred()` after
362
+ * `chat()` finishes. The consumer decides whether to send it
363
+ * as a new turn.
364
+ *
365
+ * @param message - The message to queue
366
+ * @returns Intervention ID for tracking
367
+ */
368
+ queueNext(message) {
369
+ const id = crypto.randomUUID();
370
+ this.deferred.push(
371
+ Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() })
372
+ );
373
+ return id;
374
+ }
375
+ /**
376
+ * Drain and return all deferred messages.
377
+ * The internal queue is cleared atomically.
378
+ */
379
+ drainDeferred() {
380
+ if (this.deferred.length === 0) return [];
381
+ return this.deferred.splice(0);
382
+ }
383
+ /** Adopt existing deferred interventions without changing their IDs. */
384
+ adoptDeferred(items) {
385
+ if (items.length === 0) return;
386
+ this.deferred.push(...items);
387
+ }
388
+ /** Whether there are deferred messages */
389
+ get hasDeferred() {
390
+ return this.deferred.length > 0;
391
+ }
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 [];
482
+ }
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
+ }
515
+ }
516
+ return visible;
517
+ }
518
+
519
+ // src/agent/runtime-config.ts
520
+ function createAgentToolRecord(tools) {
521
+ const toolRecord = {};
522
+ for (const [id, tool] of tools) {
523
+ toolRecord[id] = tool;
524
+ }
525
+ return toolRecord;
526
+ }
527
+ function getAgentContextStats(contextManager, messages) {
528
+ return contextManager.getStats(messages);
529
+ }
530
+ function buildFallbackCompactionSummary(messages) {
531
+ const excerpt = messages.map((message) => {
532
+ const role = message.role.toUpperCase();
533
+ const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
534
+ return `[${role}] ${content}`;
535
+ }).join("\n\n");
536
+ const trimmed = excerpt.length > 8e3 ? `${excerpt.slice(0, 8e3)}
537
+
538
+ ...[truncated during compaction]` : excerpt;
539
+ return trimmed.length > 0 ? trimmed : "Earlier conversation context was compacted.";
540
+ }
541
+ async function compactAgentContext(options) {
542
+ const { contextManager, sessions } = options;
543
+ const visibleMessages = getVisibleSessionMessages(sessions);
544
+ const messages = visibleMessages.map((item) => item.message);
545
+ if (!contextManager.shouldPrune(messages)) {
546
+ return {
547
+ removedCount: 0,
548
+ tokensRemoved: 0,
549
+ summarized: false,
550
+ summary: void 0
551
+ };
552
+ }
553
+ const tokensBefore = estimateConversationTokens(messages);
554
+ let removedCount = 0;
555
+ let summarized = false;
556
+ let summary;
557
+ try {
558
+ const result = await contextManager.prune(messages);
559
+ removedCount = result.removedCount;
560
+ summarized = result.summarized;
561
+ summary = result.summary;
562
+ } catch {
563
+ }
564
+ if (removedCount === 0) {
565
+ removedCount = findCutPoint(
566
+ messages,
567
+ contextManager.getLimits().protectedTokens
568
+ );
569
+ }
570
+ if (removedCount === 0) {
571
+ return {
572
+ removedCount: 0,
573
+ tokensRemoved: 0,
574
+ summarized: false,
575
+ summary: void 0
576
+ };
577
+ }
578
+ const summaryText = summary ?? buildFallbackCompactionSummary(messages.slice(0, removedCount));
579
+ const keptMessages = messages.slice(removedCount);
580
+ const persistedMessages = [
581
+ {
582
+ id: "compaction-preview",
583
+ role: "system",
584
+ content: `## Previous Conversation Summary
585
+
586
+ ${summaryText}`,
587
+ createdAt: /* @__PURE__ */ new Date()
588
+ },
589
+ ...keptMessages
590
+ ];
591
+ const tokensAfter = estimateConversationTokens(persistedMessages);
592
+ await sessions.replaceWithCompaction({
593
+ summary: summaryText,
594
+ messages: keptMessages,
595
+ tokensBefore,
596
+ tokensAfter
597
+ });
598
+ return {
599
+ removedCount,
600
+ tokensRemoved: Math.max(0, tokensBefore - tokensAfter),
601
+ summarized,
602
+ summary: summaryText
603
+ };
604
+ }
605
+ async function buildAgentSystemPrompts(options) {
283
606
  const {
284
- promptBuilder,
285
- middlewareRunner,
286
- systemOverride,
287
- sessionId,
288
607
  config,
289
- tools
290
- } = params;
608
+ toolIds,
609
+ sessionId,
610
+ override,
611
+ promptBuilder,
612
+ middlewareRunner
613
+ } = options;
291
614
  if (promptBuilder) {
292
615
  const composedPrompt = await promptBuilder.build(
293
616
  {
294
617
  cwd: config.cwd,
295
618
  model: config.model,
296
- toolNames: Object.keys(tools),
297
- override: systemOverride,
619
+ toolNames: toolIds,
620
+ ...override ? { override } : {},
298
621
  sessionId
299
622
  },
300
623
  middlewareRunner
@@ -302,36 +625,88 @@ async function buildChatSystemPrompts(params) {
302
625
  return [composedPrompt];
303
626
  }
304
627
  const prompts = [config.systemPrompt];
305
- if (systemOverride) {
306
- prompts.push(systemOverride);
628
+ if (override) {
629
+ prompts.push(override);
307
630
  }
308
631
  return prompts;
309
632
  }
310
-
311
- // src/agent/chat-loop/usage.ts
312
- function accumulateUsage(current, next) {
313
- if (!next) return current;
314
- if (!current) {
315
- return {
316
- inputTokens: next.inputTokens ?? 0,
317
- outputTokens: next.outputTokens ?? 0,
318
- totalTokens: next.totalTokens ?? 0
319
- };
320
- }
633
+ function createAgentTurnRuntimeConfig(options) {
634
+ const { config, telemetrySettings } = options;
321
635
  return {
322
- inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
323
- outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
324
- totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0)
325
- };
326
- }
327
-
328
- // src/agent/chat-loop/loop.ts
329
- async function* runChatLoop(deps) {
330
- yield* streamWithinScope(
331
- {
332
- kind: "turn",
333
- name: "agent-turn",
334
- sessionId: deps.sessionId
636
+ model: config.model,
637
+ cwd: config.cwd,
638
+ ...config.temperature !== void 0 ? { temperature: config.temperature } : {},
639
+ ...config.topP !== void 0 ? { topP: config.topP } : {},
640
+ ...config.maxOutputTokens !== void 0 ? { maxOutputTokens: config.maxOutputTokens } : {},
641
+ maxSteps: config.maxSteps,
642
+ ...config.doomLoopThreshold !== void 0 ? { doomLoopThreshold: config.doomLoopThreshold } : {},
643
+ ...config.enforceDoomLoop !== void 0 ? { enforceDoomLoop: config.enforceDoomLoop } : {},
644
+ ...config.onDoomLoop ? { onDoomLoop: config.onDoomLoop } : {},
645
+ ...config.contextWindow !== void 0 ? { contextWindow: config.contextWindow } : {},
646
+ ...config.streamProvider ? { streamProvider: config.streamProvider } : {},
647
+ ...telemetrySettings ? { telemetry: telemetrySettings } : {}
648
+ };
649
+ }
650
+
651
+ // src/agent/chat-loop/compaction.ts
652
+ async function runAutoCompaction(params) {
653
+ const { contextManager, sessions } = params;
654
+ const messages = sessions.getMessages();
655
+ if (!contextManager.shouldPrune(messages)) {
656
+ return [];
657
+ }
658
+ 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
669
+ });
670
+ }
671
+ return events;
672
+ }
673
+
674
+ // src/agent/chat-loop/prompts.ts
675
+ async function buildChatSystemPrompts(params) {
676
+ return buildAgentSystemPrompts({
677
+ config: params.config,
678
+ toolIds: Object.keys(params.tools),
679
+ sessionId: params.sessionId,
680
+ override: params.systemOverride,
681
+ promptBuilder: params.promptBuilder,
682
+ middlewareRunner: params.middlewareRunner
683
+ });
684
+ }
685
+
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
+ // src/agent/chat-loop/loop.ts
704
+ async function* runChatLoop(deps) {
705
+ yield* streamWithinScope(
706
+ {
707
+ kind: "turn",
708
+ name: "agent-turn",
709
+ sessionId: deps.sessionId
335
710
  },
336
711
  (async function* () {
337
712
  const {
@@ -454,7 +829,7 @@ async function* runChatLoop(deps) {
454
829
  if (config.compaction?.auto !== false) {
455
830
  const compactionEvents = await runAutoCompaction({
456
831
  contextManager,
457
- messages: sessions.getMessages()
832
+ sessions
458
833
  });
459
834
  for (const event of compactionEvents) {
460
835
  yield event;
@@ -484,6 +859,12 @@ async function* runChatLoop(deps) {
484
859
  };
485
860
  } catch (error) {
486
861
  chatError = error instanceof Error ? error : new Error(String(error));
862
+ const statusEvent = { type: "status", status: "error" };
863
+ middlewareRunner.emitEvent(statusEvent);
864
+ yield statusEvent;
865
+ const errorEvent = { type: "error", error: chatError };
866
+ middlewareRunner.emitEvent(errorEvent);
867
+ yield errorEvent;
487
868
  throw error;
488
869
  } finally {
489
870
  setIsStreaming(false);
@@ -500,272 +881,6 @@ async function* runChatLoop(deps) {
500
881
  );
501
882
  }
502
883
 
503
- // src/presets/patterns.ts
504
- function globToRegex(pattern) {
505
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
506
- return new RegExp(`^${escaped}$`, "i");
507
- }
508
- function matchesPatterns(id, patterns) {
509
- return patterns.some((pattern) => globToRegex(pattern).test(id));
510
- }
511
- function filterTools(tools, options) {
512
- const allowPatterns = options.allow ?? [];
513
- const denyPatterns = options.deny ?? [];
514
- return tools.filter((tool) => {
515
- const matchesAllow = allowPatterns.length === 0 || matchesPatterns(tool.id, allowPatterns);
516
- if (!matchesAllow) {
517
- return false;
518
- }
519
- const matchesDeny = denyPatterns.length > 0 && matchesPatterns(tool.id, denyPatterns);
520
- if (matchesDeny && allowPatterns.length === 0) {
521
- return false;
522
- }
523
- return true;
524
- });
525
- }
526
-
527
- // src/presets/apply.ts
528
- function applyPreset(preset, availableTools, baseSystemPrompt) {
529
- const tools = filterTools(availableTools, {
530
- allow: preset.allowTools,
531
- deny: preset.denyTools
532
- });
533
- let systemPrompt = preset.systemPrompt;
534
- if (systemPrompt && baseSystemPrompt) {
535
- systemPrompt = systemPrompt.replace("{basePrompt}", baseSystemPrompt);
536
- }
537
- return {
538
- name: preset.name,
539
- systemPrompt,
540
- tools: tools.length > 0 ? tools : void 0,
541
- temperature: preset.temperature,
542
- maxSteps: preset.maxSteps,
543
- reasoningLevel: preset.reasoningLevel,
544
- model: preset.model
545
- };
546
- }
547
- function mergePresets(...presets) {
548
- if (presets.length === 0) {
549
- throw new Error("mergePresets requires at least one preset");
550
- }
551
- if (presets.length === 1) {
552
- return presets[0];
553
- }
554
- const [first, ...rest] = presets;
555
- const allAllow = [];
556
- const allDeny = [];
557
- for (const preset of presets) {
558
- if (preset.allowTools?.length) {
559
- allAllow.push(preset.allowTools);
560
- }
561
- if (preset.denyTools?.length) {
562
- allDeny.push(...preset.denyTools);
563
- }
564
- }
565
- const combinedAllow = allAllow.length > 0 ? allAllow.reduce(
566
- (left, right) => left.length <= right.length ? left : right
567
- ) : void 0;
568
- return {
569
- name: presets.map((preset) => preset.name).join("+"),
570
- description: presets.map((preset) => preset.description).join(" | "),
571
- allowTools: combinedAllow,
572
- denyTools: allDeny.length > 0 ? [...new Set(allDeny)] : void 0,
573
- systemPrompt: rest.reduce(
574
- (value, preset) => preset.systemPrompt ?? value,
575
- first.systemPrompt
576
- ),
577
- temperature: rest.reduce(
578
- (value, preset) => preset.temperature ?? value,
579
- first.temperature
580
- ),
581
- maxSteps: rest.reduce(
582
- (value, preset) => preset.maxSteps ?? value,
583
- first.maxSteps
584
- ),
585
- reasoningLevel: rest.reduce(
586
- (value, preset) => preset.reasoningLevel ?? value,
587
- first.reasoningLevel
588
- ),
589
- model: rest.reduce((value, preset) => preset.model ?? value, first.model)
590
- };
591
- }
592
- function createPreset(options) {
593
- return {
594
- description: options.description ?? `Custom preset: ${options.name}`,
595
- ...options
596
- };
597
- }
598
-
599
- // src/presets/builtins.ts
600
- var explore = {
601
- name: "explore",
602
- description: "Read-only exploration mode for understanding content",
603
- allowTools: ["read*", "search*", "glob*", "grep*", "list*", "find*"],
604
- denyTools: ["write*", "edit*", "delete*", "bash*", "exec*", "run*"],
605
- systemPrompt: `{basePrompt}
606
-
607
- ## EXPLORATION MODE
608
-
609
- You are in **exploration mode**. Your goal is to thoroughly understand the content.
610
-
611
- Guidelines:
612
- - **Always start with glob or grep to discover correct paths** \u2014 never assume directory structure
613
- - Use search and read tools extensively to build understanding
614
- - Map out structures, dependencies, and patterns
615
- - Look for conventions, common patterns, and documentation
616
- - DO NOT modify anything \u2014 only read and analyse
617
- - Summarise findings clearly with references to specific locations
618
-
619
- Error recovery:
620
- - If a tool returns an error (ENOENT, not found, etc.), try a different path or approach
621
- - Use glob with broader patterns to discover the correct location
622
- - Keep going until you have a thorough answer \u2014 do not give up after one failure
623
- - You have multiple steps available \u2014 use them all if needed`,
624
- temperature: 0.3,
625
- maxSteps: 30
626
- };
627
- var plan = {
628
- name: "plan",
629
- description: "Planning mode for analyzing tasks and creating detailed plans",
630
- allowTools: ["read*", "search*", "glob*", "grep*", "list*", "find*"],
631
- denyTools: ["write*", "edit*", "delete*", "bash*", "exec*", "run*"],
632
- systemPrompt: `{basePrompt}
633
-
634
- ## PLANNING MODE
635
-
636
- You are in **planning mode**. Your goal is to analyze and plan before implementation.
637
-
638
- Guidelines:
639
- - Analyse the task requirements thoroughly
640
- - Research existing patterns and conventions
641
- - Identify potential impacts and dependencies
642
- - Create a clear, step-by-step implementation plan
643
- - DO NOT implement anything \u2014 only plan and document
644
- - Output a numbered list of specific, actionable steps`,
645
- temperature: 0.2,
646
- maxSteps: 20
647
- };
648
- var review = {
649
- name: "review",
650
- description: "Thorough review and analysis mode",
651
- allowTools: ["read*", "grep*", "search*", "glob*", "list*"],
652
- denyTools: ["*"],
653
- systemPrompt: `{basePrompt}
654
-
655
- ## REVIEW MODE
656
-
657
- You are in **review mode**. Your goal is to perform a thorough analysis.
658
-
659
- Review checklist:
660
- - [ ] Logic errors and edge cases
661
- - [ ] Security vulnerabilities
662
- - [ ] Performance issues
663
- - [ ] Error handling and recovery
664
- - [ ] Clarity and maintainability
665
- - [ ] Coverage gaps
666
-
667
- Guidelines:
668
- - Be thorough and systematic
669
- - Cite specific locations and details
670
- - Explain WHY something is an issue
671
- - Suggest concrete fixes
672
- - Rate severity: Critical / High / Medium / Low`,
673
- temperature: 0.1,
674
- maxSteps: 25
675
- };
676
- var quick = {
677
- name: "quick",
678
- description: "Fast mode for simple questions and quick operations",
679
- systemPrompt: `{basePrompt}
680
-
681
- ## QUICK MODE
682
-
683
- You are in **quick mode**. Be fast and focused.
684
-
685
- Guidelines:
686
- - Answer directly without lengthy explanations
687
- - Use minimal tool calls (1-3 max)
688
- - If you can't answer quickly, say so
689
- - Prioritize speed over thoroughness`,
690
- temperature: 0,
691
- maxSteps: 5
692
- };
693
- var careful = {
694
- name: "careful",
695
- description: "Extra cautious mode for sensitive operations",
696
- denyTools: ["bash*", "exec*", "run*", "delete*", "remove*"],
697
- systemPrompt: `{basePrompt}
698
-
699
- ## CAREFUL MODE
700
-
701
- You are in **careful mode**. Every action must be verified.
702
-
703
- Guidelines:
704
- - Double-check before any file modifications
705
- - Explain what you're about to do BEFORE doing it
706
- - Prefer smaller, incremental changes
707
- - Always verify changes after making them
708
- - If uncertain, ask for clarification rather than guessing`,
709
- temperature: 0,
710
- maxSteps: 50
711
- };
712
- var code = {
713
- name: "code",
714
- description: "Full-power implementation mode for writing and modifying code",
715
- systemPrompt: `{basePrompt}
716
-
717
- ## IMPLEMENTATION MODE
718
-
719
- You are a focused **implementation agent**. Your goal is to complete the assigned task fully and correctly.
720
-
721
- Guidelines:
722
- - Read existing code first to understand context and conventions before making changes
723
- - Follow the project's existing patterns, naming conventions, and style
724
- - Make minimal, targeted changes \u2014 do not refactor unrelated code
725
- - Verify your work: re-read modified files, run tests or lint if available
726
- - If the task requires multiple files, handle them systematically one at a time
727
-
728
- Error recovery:
729
- - If a command fails, read the error output carefully and fix the root cause
730
- - If a test fails, read the failure details and iterate until it passes
731
- - If you cannot find a file, use glob or grep to discover the correct path
732
- - Keep iterating until the task is DONE \u2014 do not stop at a partial solution
733
- - You have many steps available \u2014 use them all if needed`,
734
- temperature: 0,
735
- maxSteps: 50
736
- };
737
- var watch = {
738
- name: "watch",
739
- description: "Process monitoring mode for running and watching long commands",
740
- allowTools: ["bash*", "exec*", "run*", "read*", "grep*", "glob*", "list*", "find*"],
741
- denyTools: ["write*", "edit*", "delete*", "remove*"],
742
- systemPrompt: `{basePrompt}
743
-
744
- ## WATCH MODE
745
-
746
- You are a **process monitor**. Your goal is to execute a command, observe its output, and report the result.
747
-
748
- Guidelines:
749
- - Run the command as given \u2014 do not modify or "improve" it
750
- - Wait for completion and capture the full output
751
- - Parse the output for success/failure status, error counts, warnings
752
- - Report a clear summary: what ran, whether it passed, key details
753
- - If the process fails, include the relevant error output verbatim
754
- - Do NOT attempt to fix issues \u2014 only observe and report`,
755
- temperature: 0,
756
- maxSteps: 10,
757
- reasoningLevel: "low"
758
- };
759
- var Presets = {
760
- explore,
761
- plan,
762
- review,
763
- quick,
764
- careful,
765
- code,
766
- watch
767
- };
768
-
769
884
  // src/agent/fork.ts
770
885
  function resolveForkOptions(options, parentTools, systemPrompt) {
771
886
  if (!options.preset) {
@@ -783,279 +898,115 @@ function resolveChildPromptConfig(options) {
783
898
  if (forkOptions.systemPrompt) {
784
899
  return { systemPrompt: forkOptions.systemPrompt };
785
900
  }
786
- if (forkOptions.prompt) {
787
- return { prompt: forkOptions.prompt };
788
- }
789
- if (promptBuilder) {
790
- return { prompt: parentPromptConfig ?? {} };
791
- }
792
- return { systemPrompt: parentSystemPrompt };
793
- }
794
- function resolveForkMiddleware(options, middlewareRunner) {
795
- if (options.middleware) {
796
- return options.middleware;
797
- }
798
- if (options.additionalMiddleware) {
799
- return [
800
- ...middlewareRunner.getMiddleware(),
801
- ...options.additionalMiddleware
802
- ];
803
- }
804
- return [...middlewareRunner.getMiddleware()];
805
- }
806
- function createForkedAgentConfig(options) {
807
- const {
808
- forkOptions,
809
- parentConfig,
810
- parentTools,
811
- reasoningLevel,
812
- host,
813
- sessions,
814
- mcpManager,
815
- middlewareRunner,
816
- promptBuilder
817
- } = options;
818
- const tools = forkOptions.tools ?? parentTools;
819
- const childPrompt = resolveChildPromptConfig({
820
- forkOptions,
821
- promptBuilder,
822
- parentPromptConfig: parentConfig.prompt,
823
- parentSystemPrompt: parentConfig.systemPrompt
824
- });
825
- return {
826
- model: forkOptions.model ?? parentConfig.model,
827
- cwd: parentConfig.cwd,
828
- host,
829
- maxOutputTokens: parentConfig.maxOutputTokens,
830
- maxSteps: forkOptions.maxSteps ?? parentConfig.maxSteps,
831
- temperature: forkOptions.temperature ?? parentConfig.temperature,
832
- topP: parentConfig.topP,
833
- reasoningLevel: forkOptions.reasoningLevel ?? reasoningLevel,
834
- ...childPrompt,
835
- sessionManager: new SessionManager(sessions.getStorage()),
836
- tools,
837
- onDoomLoop: parentConfig.onDoomLoop,
838
- enforceDoomLoop: parentConfig.enforceDoomLoop,
839
- doomLoopThreshold: parentConfig.doomLoopThreshold,
840
- compaction: parentConfig.compaction,
841
- contextWindow: parentConfig.contextWindow,
842
- mcp: mcpManager,
843
- middleware: resolveForkMiddleware(forkOptions, middlewareRunner)
844
- };
845
- }
846
-
847
- // src/agent/mcp.ts
848
- async function ensureMcpTools(state) {
849
- if (!state.manager) {
850
- return { connected: false, cachedTools: void 0 };
851
- }
852
- if (state.connected && state.cachedTools) {
853
- return {
854
- connected: state.connected,
855
- cachedTools: state.cachedTools
856
- };
857
- }
858
- const statuses = await state.manager.connect();
859
- let connectedCount = 0;
860
- for (const [name, status] of statuses) {
861
- if (status.status === "connected") {
862
- connectedCount++;
863
- } else if (status.status === "error") {
864
- console.warn(`[mcp] Failed to connect to ${name}: ${status.error}`);
865
- }
866
- }
867
- if (connectedCount === 0 && statuses.size > 0) {
868
- console.warn("[mcp] No MCP servers connected successfully");
869
- }
870
- const cachedTools = await state.manager.getTools();
871
- return {
872
- connected: true,
873
- cachedTools
874
- };
875
- }
876
- async function closeMcpManager(manager) {
877
- if (manager) {
878
- await manager.close();
879
- }
880
- return {
881
- connected: false,
882
- cachedTools: void 0
883
- };
884
- }
885
-
886
- // src/agent/session.ts
887
- async function ensureSessionLoaded(options) {
888
- const { sessionId, sessions, loadedSessions, cwd } = options;
889
- if (loadedSessions.has(sessionId) && sessions.getSessionId() === sessionId) {
890
- return;
891
- }
892
- const exists = await sessions.sessionExists(sessionId);
893
- if (exists) {
894
- await sessions.load(sessionId);
895
- } else {
896
- await sessions.create({ id: sessionId, cwd });
897
- }
898
- loadedSessions.add(sessionId);
899
- }
900
- async function repairOrphanedToolCalls(sessions) {
901
- const messages = sessions.getMessages();
902
- const pendingCallIds = /* @__PURE__ */ new Map();
903
- for (const message of messages) {
904
- if (message.role === "assistant" && message.toolCalls) {
905
- for (const toolCall of message.toolCalls) {
906
- pendingCallIds.set(toolCall.toolCallId, { toolName: toolCall.toolName });
907
- }
908
- }
909
- if (message.role === "tool" && message.toolCallId) {
910
- pendingCallIds.delete(message.toolCallId);
911
- }
912
- }
913
- for (const [toolCallId, { toolName }] of pendingCallIds) {
914
- const toolMessage = {
915
- id: crypto.randomUUID(),
916
- role: "tool",
917
- content: "Error: tool execution failed (result was not recorded)",
918
- toolCallId,
919
- toolName,
920
- result: "Error: tool execution failed (result was not recorded)",
921
- createdAt: /* @__PURE__ */ new Date()
922
- };
923
- await sessions.addMessage(toolMessage);
924
- }
925
- }
926
- async function createSubAgentRunSession(options) {
927
- const sessionId = options.parentSessionId ? `${options.parentSessionId}:sub:${crypto.randomUUID().slice(0, 8)}` : `sub:${crypto.randomUUID().slice(0, 8)}`;
928
- await options.sessions.create({
929
- id: sessionId,
930
- cwd: options.cwd,
931
- title: options.title ?? "Sub-agent task",
932
- parentSessionId: options.parentSessionId
933
- });
934
- options.loadedSessions.add(sessionId);
935
- return sessionId;
936
- }
937
-
938
- // src/agent/intervention.ts
939
- var InterventionController = class {
940
- /** Immediate interventions — applied at the next step boundary */
941
- immediate = [];
942
- /** Deferred messages — held until the turn completes */
943
- deferred = [];
944
- /**
945
- * Callback fired when an intervention is wired into a step.
946
- * Set by the Agent before starting a chat turn, cleared after.
947
- */
948
- onApplied;
949
- // ---------------------------------------------------------------------------
950
- // Immediate interventions (mid-turn redirect)
951
- // ---------------------------------------------------------------------------
952
- /**
953
- * Inject a message at the next LLM step boundary.
954
- *
955
- * The message is appended as a user message to the conversation
956
- * before the next LLM call in the current multi-step turn. The
957
- * LLM will see it and can adjust its behavior accordingly.
958
- *
959
- * Safe to call from any async context while `chat()` is running.
960
- * If called when no turn is active, the message will be picked up
961
- * by the first step of the next `chat()` call.
962
- *
963
- * @param message - The user message to inject
964
- * @returns Intervention ID for tracking
965
- */
966
- intervene(message) {
967
- const id = crypto.randomUUID();
968
- this.immediate.push(
969
- Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() })
970
- );
971
- return id;
972
- }
973
- /**
974
- * Drain and return all pending immediate interventions.
975
- * The internal queue is cleared atomically.
976
- *
977
- * @internal Called by the LLM stream's `prepareStep` hook
978
- */
979
- drainImmediate() {
980
- if (this.immediate.length === 0) return [];
981
- return this.immediate.splice(0);
982
- }
983
- /** Whether there are pending immediate interventions */
984
- get hasPending() {
985
- return this.immediate.length > 0;
986
- }
987
- /** Number of pending immediate interventions */
988
- get pendingCount() {
989
- return this.immediate.length;
990
- }
991
- // ---------------------------------------------------------------------------
992
- // Deferred messages (after-turn follow-ups)
993
- // ---------------------------------------------------------------------------
994
- /**
995
- * Queue a message for after the current turn completes.
996
- *
997
- * Unlike `intervene()`, this does **not** inject mid-turn. The
998
- * message is held and available via `drainDeferred()` after
999
- * `chat()` finishes. The consumer decides whether to send it
1000
- * as a new turn.
1001
- *
1002
- * @param message - The message to queue
1003
- * @returns Intervention ID for tracking
1004
- */
1005
- queueNext(message) {
1006
- const id = crypto.randomUUID();
1007
- this.deferred.push(
1008
- Object.freeze({ id, message, createdAt: /* @__PURE__ */ new Date() })
1009
- );
1010
- return id;
1011
- }
1012
- /**
1013
- * Drain and return all deferred messages.
1014
- * The internal queue is cleared atomically.
1015
- */
1016
- drainDeferred() {
1017
- if (this.deferred.length === 0) return [];
1018
- return this.deferred.splice(0);
901
+ if (forkOptions.prompt) {
902
+ return { prompt: forkOptions.prompt };
1019
903
  }
1020
- /** Whether there are deferred messages */
1021
- get hasDeferred() {
1022
- return this.deferred.length > 0;
904
+ if (promptBuilder) {
905
+ return { prompt: parentPromptConfig ?? {} };
1023
906
  }
1024
- /** Number of deferred messages */
1025
- get deferredCount() {
1026
- return this.deferred.length;
907
+ return { systemPrompt: parentSystemPrompt };
908
+ }
909
+ function resolveForkMiddleware(options, middlewareRunner) {
910
+ if (options.middleware) {
911
+ return options.middleware;
1027
912
  }
1028
- // ---------------------------------------------------------------------------
1029
- // Housekeeping
1030
- // ---------------------------------------------------------------------------
1031
- /** Clear all queues (immediate + deferred) */
1032
- clear() {
1033
- this.immediate.length = 0;
1034
- this.deferred.length = 0;
913
+ if (options.additionalMiddleware) {
914
+ return [
915
+ ...middlewareRunner.getMiddleware(),
916
+ ...options.additionalMiddleware
917
+ ];
1035
918
  }
1036
- /** Reset the controller for a new turn (clears onApplied, keeps queues) */
1037
- resetCallbacks() {
1038
- this.onApplied = void 0;
919
+ return [...middlewareRunner.getMiddleware()];
920
+ }
921
+ function createForkedAgentConfig(options) {
922
+ const {
923
+ forkOptions,
924
+ parentConfig,
925
+ parentTools,
926
+ reasoningLevel,
927
+ host,
928
+ ownsHost,
929
+ sessions,
930
+ mcpManager,
931
+ middlewareRunner,
932
+ promptBuilder
933
+ } = options;
934
+ const tools = forkOptions.tools ?? parentTools;
935
+ const childPrompt = resolveChildPromptConfig({
936
+ forkOptions,
937
+ promptBuilder,
938
+ parentPromptConfig: parentConfig.prompt,
939
+ parentSystemPrompt: parentConfig.systemPrompt
940
+ });
941
+ return {
942
+ model: forkOptions.model ?? parentConfig.model,
943
+ cwd: parentConfig.cwd,
944
+ ...ownsHost ? {} : { host },
945
+ maxOutputTokens: parentConfig.maxOutputTokens,
946
+ maxSteps: forkOptions.maxSteps ?? parentConfig.maxSteps,
947
+ temperature: forkOptions.temperature ?? parentConfig.temperature,
948
+ topP: parentConfig.topP,
949
+ reasoningLevel: forkOptions.reasoningLevel ?? reasoningLevel,
950
+ ...childPrompt,
951
+ sessionManager: new SessionManager(sessions.getStorage()),
952
+ tools,
953
+ onDoomLoop: parentConfig.onDoomLoop,
954
+ enforceDoomLoop: parentConfig.enforceDoomLoop,
955
+ doomLoopThreshold: parentConfig.doomLoopThreshold,
956
+ compaction: parentConfig.compaction,
957
+ contextWindow: parentConfig.contextWindow,
958
+ mcp: mcpManager,
959
+ middleware: resolveForkMiddleware(forkOptions, middlewareRunner)
960
+ };
961
+ }
962
+
963
+ // src/agent/mcp-bridge.ts
964
+ async function ensureMcpTools(state) {
965
+ if (!state.manager) {
966
+ return { connected: false, cachedTools: void 0 };
1039
967
  }
1040
- };
968
+ if (state.connected && state.cachedTools) {
969
+ return {
970
+ connected: state.connected,
971
+ cachedTools: state.cachedTools
972
+ };
973
+ }
974
+ const statuses = await state.manager.connect();
975
+ let connectedCount = 0;
976
+ for (const [name, status] of statuses) {
977
+ if (status.status === "connected") {
978
+ connectedCount++;
979
+ } else if (status.status === "error") {
980
+ console.warn(`[mcp] Failed to connect to ${name}: ${status.error}`);
981
+ }
982
+ }
983
+ if (connectedCount === 0 && statuses.size > 0) {
984
+ console.warn("[mcp] No MCP servers connected successfully");
985
+ }
986
+ const cachedTools = await state.manager.getTools();
987
+ return {
988
+ connected: true,
989
+ cachedTools
990
+ };
991
+ }
992
+ async function closeMcpManager(manager) {
993
+ if (manager) {
994
+ await manager.close();
995
+ }
996
+ return {
997
+ connected: false,
998
+ cachedTools: void 0
999
+ };
1000
+ }
1041
1001
 
1042
- // src/agent/model-detection.ts
1002
+ // src/agent/stream-provider.ts
1043
1003
  var DEFAULT_CUSTOM_STREAM_MODELS = [
1044
1004
  "computer-use-preview",
1045
1005
  "computer-use-preview-2025-03-11"
1046
1006
  ];
1047
- function getModelId2(model) {
1048
- if (typeof model === "string") {
1049
- return model;
1050
- }
1051
- if (typeof model === "object" && model !== null && "modelId" in model) {
1052
- return String(model.modelId);
1053
- }
1054
- return void 0;
1055
- }
1056
1007
  function needsCustomStreamProvider(model, customPatterns) {
1057
- const modelId = getModelId2(model);
1058
- if (!modelId) return false;
1008
+ const modelId = extractModelId(model);
1009
+ if (!modelId || modelId === "[object Object]") return false;
1059
1010
  const patterns = customPatterns ?? DEFAULT_CUSTOM_STREAM_MODELS;
1060
1011
  return patterns.some((pattern) => modelId.includes(pattern));
1061
1012
  }
@@ -1070,7 +1021,7 @@ function autoDetectStreamProvider(model, tools, explicitProvider) {
1070
1021
  const enhancedTools = tools;
1071
1022
  const customPatterns = enhancedTools.__customStreamModels;
1072
1023
  if (needsCustomStreamProvider(model, customPatterns) && hasStreamProviderFactory(enhancedTools)) {
1073
- const modelId = getModelId2(model);
1024
+ const modelId = extractModelId(model);
1074
1025
  if (modelId) {
1075
1026
  const streamConfig = {
1076
1027
  apiKey: process.env.OPENAI_API_KEY,
@@ -1115,10 +1066,11 @@ function createEffectiveAgentConfig(config) {
1115
1066
  return {
1116
1067
  systemPrompt: DEFAULT_SYSTEM_PROMPT,
1117
1068
  cwd: process.cwd(),
1118
- maxOutputTokens: DEFAULT_MAX_TOKENS,
1119
- maxSteps: DEFAULT_MAX_STEPS,
1120
1069
  reasoningLevel: "off",
1121
1070
  ...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,
1122
1074
  streamProvider: effectiveStreamProvider
1123
1075
  };
1124
1076
  }
@@ -1145,17 +1097,39 @@ function createAgentState(config) {
1145
1097
  }
1146
1098
  function createAgentContextManager(config) {
1147
1099
  const compactionConfig = config.compaction ?? {};
1100
+ const modelId = extractModelId(config.model);
1101
+ const inferredWindow = inferContextWindow(modelId);
1102
+ const contextWindow = config.contextWindow ?? inferredWindow ?? DEFAULT_CONTEXT_LIMITS.contextWindow;
1148
1103
  return new ContextManager({
1149
1104
  limits: {
1150
- contextWindow: config.contextWindow ?? DEFAULT_CONTEXT_LIMITS.contextWindow,
1151
- reserveTokens: DEFAULT_CONTEXT_LIMITS.reserveTokens,
1152
- protectedTokens: compactionConfig.protectedTokens ?? DEFAULT_CONTEXT_LIMITS.protectedTokens,
1153
- pruneMinimum: compactionConfig.pruneMinimum ?? DEFAULT_CONTEXT_LIMITS.pruneMinimum
1105
+ contextWindow,
1106
+ ...resolveAgentContextLimits(contextWindow, compactionConfig)
1154
1107
  },
1155
1108
  model: compactionConfig.summaryModel ?? config.model,
1156
1109
  summaryPrompt: compactionConfig.summaryPrompt
1157
1110
  });
1158
1111
  }
1112
+ function resolveAgentContextLimits(contextWindow, compactionConfig = {}) {
1113
+ const proportionalReserve = Math.round(contextWindow * 0.12);
1114
+ const reserveTokens = contextWindow >= 64e3 ? Math.min(32e3, Math.max(8e3, proportionalReserve)) : Math.min(
1115
+ Math.max(1024, Math.round(contextWindow * 0.25)),
1116
+ Math.max(512, proportionalReserve)
1117
+ );
1118
+ const usableWindow = Math.max(512, contextWindow - reserveTokens);
1119
+ const requestedProtected = compactionConfig.protectedTokens ?? DEFAULT_CONTEXT_LIMITS.protectedTokens;
1120
+ const requestedPruneMinimum = compactionConfig.pruneMinimum ?? DEFAULT_CONTEXT_LIMITS.pruneMinimum;
1121
+ return {
1122
+ reserveTokens,
1123
+ protectedTokens: Math.min(
1124
+ requestedProtected,
1125
+ Math.max(512, Math.round(usableWindow * 0.6))
1126
+ ),
1127
+ pruneMinimum: Math.min(
1128
+ requestedPruneMinimum,
1129
+ Math.max(256, Math.round(usableWindow * 0.5))
1130
+ )
1131
+ };
1132
+ }
1159
1133
  function createMiddlewareSetup(input, config) {
1160
1134
  let effectiveMiddleware = input.middleware;
1161
1135
  let telemetrySettings;
@@ -1200,78 +1174,13 @@ function createAgentSetup(input) {
1200
1174
  ...promptBuilder ? { promptBuilder } : {},
1201
1175
  interventionCtrl: new InterventionController(),
1202
1176
  host: input.host ?? localHost(config.cwd),
1177
+ ownsHost: input.host === void 0,
1203
1178
  middlewareRunner: middlewareSetup.middlewareRunner,
1204
1179
  ...middlewareSetup.telemetrySettings ? { telemetrySettings: middlewareSetup.telemetrySettings } : {},
1205
1180
  ...middlewareSetup.tracingShutdown ? { tracingShutdown: middlewareSetup.tracingShutdown } : {}
1206
1181
  };
1207
1182
  }
1208
1183
 
1209
- // src/agent/runtime-config.ts
1210
- function createAgentToolRecord(tools) {
1211
- const toolRecord = {};
1212
- for (const [id, tool] of tools) {
1213
- toolRecord[id] = tool;
1214
- }
1215
- return toolRecord;
1216
- }
1217
- function getAgentContextStats(contextManager, messages) {
1218
- return contextManager.getStats(messages);
1219
- }
1220
- async function compactAgentContext(contextManager, messages) {
1221
- const result = await contextManager.prune(messages);
1222
- return {
1223
- removedCount: result.removedCount,
1224
- tokensRemoved: result.tokensRemoved,
1225
- summarized: result.summarized,
1226
- summary: result.summary
1227
- };
1228
- }
1229
- async function buildAgentSystemPrompts(options) {
1230
- const {
1231
- config,
1232
- toolIds,
1233
- sessionId,
1234
- override,
1235
- promptBuilder,
1236
- middlewareRunner
1237
- } = options;
1238
- if (promptBuilder) {
1239
- const composedPrompt = await promptBuilder.build(
1240
- {
1241
- cwd: config.cwd,
1242
- model: config.model,
1243
- toolNames: toolIds,
1244
- ...override ? { override } : {},
1245
- sessionId
1246
- },
1247
- middlewareRunner
1248
- );
1249
- return [composedPrompt];
1250
- }
1251
- const prompts = [config.systemPrompt];
1252
- if (override) {
1253
- prompts.push(override);
1254
- }
1255
- return prompts;
1256
- }
1257
- function createAgentTurnRuntimeConfig(options) {
1258
- const { config, telemetrySettings } = options;
1259
- return {
1260
- model: config.model,
1261
- cwd: config.cwd,
1262
- ...config.temperature !== void 0 ? { temperature: config.temperature } : {},
1263
- ...config.topP !== void 0 ? { topP: config.topP } : {},
1264
- ...config.maxOutputTokens !== void 0 ? { maxOutputTokens: config.maxOutputTokens } : {},
1265
- maxSteps: config.maxSteps,
1266
- ...config.doomLoopThreshold !== void 0 ? { doomLoopThreshold: config.doomLoopThreshold } : {},
1267
- ...config.enforceDoomLoop !== void 0 ? { enforceDoomLoop: config.enforceDoomLoop } : {},
1268
- ...config.onDoomLoop ? { onDoomLoop: config.onDoomLoop } : {},
1269
- ...config.contextWindow !== void 0 ? { contextWindow: config.contextWindow } : {},
1270
- ...config.streamProvider ? { streamProvider: config.streamProvider } : {},
1271
- ...telemetrySettings ? { telemetry: telemetrySettings } : {}
1272
- };
1273
- }
1274
-
1275
1184
  // src/agent/instance.ts
1276
1185
  function createAgent(config) {
1277
1186
  return new Agent(config);
@@ -1280,7 +1189,6 @@ var Agent = class _Agent {
1280
1189
  config;
1281
1190
  tools;
1282
1191
  sessions;
1283
- loadedSessions = /* @__PURE__ */ new Set();
1284
1192
  state;
1285
1193
  /** Context manager for overflow detection and compaction */
1286
1194
  contextManager;
@@ -1294,6 +1202,8 @@ var Agent = class _Agent {
1294
1202
  mcpManager;
1295
1203
  /** Whether MCP has been connected (lazy init) */
1296
1204
  mcpConnected = false;
1205
+ /** Whether skill tools have been resolved (lazy init) */
1206
+ skillToolsResolved = false;
1297
1207
  /** Cached MCP tools (refreshed on connect) */
1298
1208
  mcpToolsCache;
1299
1209
  /** Prompt pipeline builder (when using layered prompt mode) */
@@ -1302,12 +1212,22 @@ var Agent = class _Agent {
1302
1212
  interventionCtrl;
1303
1213
  /** Execution environment for tool operations */
1304
1214
  host;
1215
+ /** Whether the agent owns the host and can safely recreate it on cwd changes */
1216
+ ownsHost;
1305
1217
  /** Middleware runner for lifecycle hooks */
1306
1218
  middlewareRunner;
1307
1219
  /** AI SDK telemetry settings (auto-created from `tracing` config) */
1308
1220
  telemetrySettings;
1309
1221
  /** Tracing shutdown function (from `tracing` config auto-setup) */
1310
1222
  tracingShutdown;
1223
+ /** Multi-consumer event dispatch */
1224
+ _signal;
1225
+ /** Number of active turns across all sessions */
1226
+ activeTurnCount = 0;
1227
+ /** Active turn intervention controllers, keyed by turn id */
1228
+ activeTurns = /* @__PURE__ */ new Map();
1229
+ /** Per-session turn queue to prevent concurrent writes to the same history */
1230
+ sessionLocks = /* @__PURE__ */ new Map();
1311
1231
  constructor(config) {
1312
1232
  const setup = createAgentSetup(config);
1313
1233
  this.config = setup.config;
@@ -1320,9 +1240,21 @@ var Agent = class _Agent {
1320
1240
  this.promptBuilder = setup.promptBuilder;
1321
1241
  this.interventionCtrl = setup.interventionCtrl;
1322
1242
  this.host = setup.host;
1243
+ this.ownsHost = setup.ownsHost;
1323
1244
  this.middlewareRunner = setup.middlewareRunner;
1324
1245
  this.telemetrySettings = setup.telemetrySettings;
1325
1246
  this.tracingShutdown = setup.tracingShutdown;
1247
+ this._signal = config.signal ?? new LocalSignal();
1248
+ }
1249
+ /**
1250
+ * Event signal — subscribe to events without consuming the generator.
1251
+ *
1252
+ * Every event yielded by `chat()` is also dispatched here, allowing
1253
+ * multiple passive observers (SSE routes, TUI, plugins) to listen
1254
+ * concurrently.
1255
+ */
1256
+ get signal() {
1257
+ return this._signal;
1326
1258
  }
1327
1259
  /** Agent name (identity for spans, Dapr workflows, etc.) */
1328
1260
  get name() {
@@ -1342,7 +1274,7 @@ var Agent = class _Agent {
1342
1274
  }
1343
1275
  /** Is currently streaming */
1344
1276
  get isStreaming() {
1345
- return this.state.isStreaming;
1277
+ return this.activeTurnCount > 0;
1346
1278
  }
1347
1279
  /** Current reasoning level */
1348
1280
  get reasoningLevel() {
@@ -1369,6 +1301,90 @@ var Agent = class _Agent {
1369
1301
  supportsReasoning() {
1370
1302
  return supportsReasoningSync(this.state.model);
1371
1303
  }
1304
+ /**
1305
+ * Ensure skill tools are registered when `prompt.skills` is configured.
1306
+ * Lazy initialization — resolves the registry and adds tools on first use.
1307
+ */
1308
+ async ensureSkillTools() {
1309
+ if (this.skillToolsResolved || !this.promptBuilder) return;
1310
+ this.skillToolsResolved = true;
1311
+ const registry = await this.promptBuilder.getSkillRegistry(this.config.cwd);
1312
+ if (registry.size > 0) {
1313
+ for (const tool of createSkillTools(registry)) {
1314
+ if (!this.tools.has(tool.id)) {
1315
+ this.tools.set(tool.id, tool);
1316
+ }
1317
+ }
1318
+ }
1319
+ }
1320
+ resetPromptScopedTools() {
1321
+ this.tools.delete("skill");
1322
+ this.tools.delete("skill_resource");
1323
+ this.skillToolsResolved = false;
1324
+ }
1325
+ createSessionManager() {
1326
+ return new SessionManager(this.sessions.getStorage());
1327
+ }
1328
+ async acquireSessionLock(sessionId) {
1329
+ const previous = this.sessionLocks.get(sessionId) ?? Promise.resolve();
1330
+ let releaseLock;
1331
+ const current = new Promise((resolve) => {
1332
+ releaseLock = resolve;
1333
+ });
1334
+ const chain = previous.catch(() => void 0).then(() => current);
1335
+ this.sessionLocks.set(sessionId, chain);
1336
+ await previous.catch(() => void 0);
1337
+ let released = false;
1338
+ return () => {
1339
+ if (released) return;
1340
+ released = true;
1341
+ releaseLock();
1342
+ if (this.sessionLocks.get(sessionId) === chain) {
1343
+ this.sessionLocks.delete(sessionId);
1344
+ }
1345
+ };
1346
+ }
1347
+ getActiveInterventionController() {
1348
+ const active = Array.from(this.activeTurns.values());
1349
+ if (active.length === 0) {
1350
+ return void 0;
1351
+ }
1352
+ if (active.length > 1) {
1353
+ throw new Error(
1354
+ "Interventions are ambiguous while multiple agent turns are active. Use separate Agent instances or wait for one turn to finish."
1355
+ );
1356
+ }
1357
+ return active[0].interventionCtrl;
1358
+ }
1359
+ getInterventionControllerForTurn() {
1360
+ const activeController = this.getActiveInterventionController();
1361
+ return activeController ?? this.interventionCtrl;
1362
+ }
1363
+ createTurnInterventionController() {
1364
+ return this.activeTurns.size === 0 ? this.interventionCtrl : new InterventionController();
1365
+ }
1366
+ releaseTurnInterventions(controller) {
1367
+ if (controller === this.interventionCtrl) {
1368
+ controller.resetCallbacks();
1369
+ return;
1370
+ }
1371
+ this.interventionCtrl.adoptImmediate(controller.drainImmediate());
1372
+ this.interventionCtrl.adoptDeferred(controller.drainDeferred());
1373
+ controller.resetCallbacks();
1374
+ }
1375
+ syncStreamingState(active) {
1376
+ this.activeTurnCount = Math.max(
1377
+ 0,
1378
+ this.activeTurnCount + (active ? 1 : -1)
1379
+ );
1380
+ this.state.isStreaming = this.activeTurnCount > 0;
1381
+ }
1382
+ async syncSessionView(sessionId) {
1383
+ if (!await this.sessions.sessionExists(sessionId)) {
1384
+ return;
1385
+ }
1386
+ await this.sessions.load(sessionId);
1387
+ }
1372
1388
  /**
1373
1389
  * Ensure MCP is connected and return tools
1374
1390
  * Lazy initialization - only connects on first use
@@ -1392,8 +1408,8 @@ var Agent = class _Agent {
1392
1408
  * `MissingToolResultsError`. This method detects orphaned tool-call IDs
1393
1409
  * and adds placeholder `tool` messages so the history is valid again.
1394
1410
  */
1395
- async repairOrphanedToolCalls() {
1396
- await repairOrphanedToolCalls(this.sessions);
1411
+ async repairOrphanedToolCalls(sessions) {
1412
+ await repairOrphanedToolCalls(sessions);
1397
1413
  }
1398
1414
  /**
1399
1415
  * Convert internal {@link Message} array to Vercel AI SDK {@link ModelMessage} format.
@@ -1419,46 +1435,74 @@ var Agent = class _Agent {
1419
1435
  * @yields {AgentEvent} Events as they occur during processing
1420
1436
  */
1421
1437
  async *chat(sessionId, message, options) {
1422
- await this.ensureSession(sessionId);
1423
- const abort = options?.abort ?? new AbortController().signal;
1438
+ const releaseSessionLock = await this.acquireSessionLock(sessionId);
1439
+ const sessions = this.createSessionManager();
1424
1440
  const turnId = `${sessionId}-turn-${++this.turnCounter}`;
1425
- this.turnTracker.startTurn(turnId);
1426
- await this.repairOrphanedToolCalls();
1427
- const mcpTools = await this.ensureMCPConnected();
1428
- yield* runChatLoop({
1429
- sessionId,
1430
- message,
1431
- abort,
1432
- systemOverride: options?.system,
1433
- sessions: this.sessions,
1434
- tools: createAgentToolRecord(this.tools),
1435
- config: this.config,
1436
- turnTracker: this.turnTracker,
1437
- interventionCtrl: this.interventionCtrl,
1438
- middlewareRunner: this.middlewareRunner,
1439
- contextManager: this.contextManager,
1440
- rememberedDoomLoopTools: this.rememberedDoomLoopTools,
1441
- reasoningLevel: this.state.reasoningLevel,
1442
- promptBuilder: this.promptBuilder,
1443
- host: this.host,
1444
- mcpTools,
1445
- telemetrySettings: this.telemetrySettings,
1446
- toModelMessages: this.toModelMessages.bind(this),
1447
- setIsStreaming: (v) => {
1448
- this.state.isStreaming = v;
1441
+ let turnTracker;
1442
+ let interventionCtrl = this.interventionCtrl;
1443
+ let streamingStateActive = false;
1444
+ let turnRegistered = false;
1445
+ try {
1446
+ await this.ensureSkillTools();
1447
+ const abort = options?.abort ?? new AbortController().signal;
1448
+ turnTracker = createTurnTracker({ cwd: this.config.cwd });
1449
+ interventionCtrl = this.createTurnInterventionController();
1450
+ this.activeTurns.set(turnId, { sessionId, interventionCtrl });
1451
+ turnRegistered = true;
1452
+ await ensureSessionLoaded({
1453
+ sessionId,
1454
+ sessions,
1455
+ cwd: this.config.cwd
1456
+ });
1457
+ turnTracker.startTurn(turnId);
1458
+ await this.repairOrphanedToolCalls(sessions);
1459
+ const mcpTools = await this.ensureMCPConnected();
1460
+ const loop = runChatLoop({
1461
+ sessionId,
1462
+ message,
1463
+ abort,
1464
+ systemOverride: options?.system,
1465
+ sessions,
1466
+ tools: createAgentToolRecord(this.tools),
1467
+ config: this.config,
1468
+ turnTracker,
1469
+ interventionCtrl,
1470
+ middlewareRunner: this.middlewareRunner,
1471
+ contextManager: this.contextManager,
1472
+ rememberedDoomLoopTools: this.rememberedDoomLoopTools,
1473
+ reasoningLevel: this.state.reasoningLevel,
1474
+ promptBuilder: this.promptBuilder,
1475
+ host: this.host,
1476
+ mcpTools,
1477
+ telemetrySettings: this.telemetrySettings,
1478
+ toModelMessages: this.toModelMessages.bind(this),
1479
+ setIsStreaming: (value) => {
1480
+ if (value === streamingStateActive) return;
1481
+ streamingStateActive = value;
1482
+ this.syncStreamingState(value);
1483
+ }
1484
+ });
1485
+ for await (const event of loop) {
1486
+ this._signal.emit(event);
1487
+ yield event;
1449
1488
  }
1450
- });
1451
- }
1452
- /**
1453
- * Ensure a session is loaded or created
1454
- */
1455
- async ensureSession(sessionId) {
1456
- await ensureSessionLoaded({
1457
- sessionId,
1458
- sessions: this.sessions,
1459
- loadedSessions: this.loadedSessions,
1460
- cwd: this.config.cwd
1461
- });
1489
+ } finally {
1490
+ try {
1491
+ if (streamingStateActive) {
1492
+ this.syncStreamingState(false);
1493
+ }
1494
+ if (turnRegistered) {
1495
+ this.activeTurns.delete(turnId);
1496
+ }
1497
+ this.releaseTurnInterventions(interventionCtrl);
1498
+ if (turnRegistered && turnTracker) {
1499
+ this.turnTracker = turnTracker;
1500
+ }
1501
+ await this.syncSessionView(sessionId);
1502
+ } finally {
1503
+ releaseSessionLock();
1504
+ }
1505
+ }
1462
1506
  }
1463
1507
  /**
1464
1508
  * Send a message and wait for the complete response (non-streaming).
@@ -1534,7 +1578,6 @@ var Agent = class _Agent {
1534
1578
  }
1535
1579
  /** Delete a session */
1536
1580
  async deleteSession(sessionId) {
1537
- this.loadedSessions.delete(sessionId);
1538
1581
  return this.sessions.deleteSession(sessionId);
1539
1582
  }
1540
1583
  /** List all sessions */
@@ -1584,10 +1627,10 @@ var Agent = class _Agent {
1584
1627
  * @returns Pruning result with details about what was removed/summarized
1585
1628
  */
1586
1629
  async compactContext() {
1587
- return await compactAgentContext(
1588
- this.contextManager,
1589
- this.sessions.getMessages()
1590
- );
1630
+ return await compactAgentContext({
1631
+ contextManager: this.contextManager,
1632
+ sessions: this.sessions
1633
+ });
1591
1634
  }
1592
1635
  /**
1593
1636
  * Clear remembered doom loop tools.
@@ -1617,6 +1660,8 @@ var Agent = class _Agent {
1617
1660
  *
1618
1661
  * If called when no turn is active, the message will be picked up
1619
1662
  * by the first step of the next `chat()` call.
1663
+ * If multiple turns are active concurrently, this throws because the
1664
+ * target turn would be ambiguous.
1620
1665
  *
1621
1666
  * @param message - The user message to inject mid-turn
1622
1667
  * @returns Intervention ID for tracking
@@ -1638,7 +1683,7 @@ var Agent = class _Agent {
1638
1683
  * ```
1639
1684
  */
1640
1685
  intervene(message) {
1641
- return this.interventionCtrl.intervene(message);
1686
+ return this.getInterventionControllerForTurn().intervene(message);
1642
1687
  }
1643
1688
  /**
1644
1689
  * Queue a message for after the current turn completes.
@@ -1648,6 +1693,9 @@ var Agent = class _Agent {
1648
1693
  * `chat()` finishes. The consumer decides whether to send it as a
1649
1694
  * new turn.
1650
1695
  *
1696
+ * If multiple turns are active concurrently, this throws because the
1697
+ * target turn would be ambiguous.
1698
+ *
1651
1699
  * @param message - The message to queue
1652
1700
  * @returns Intervention ID for tracking
1653
1701
  *
@@ -1670,15 +1718,15 @@ var Agent = class _Agent {
1670
1718
  * ```
1671
1719
  */
1672
1720
  queueNext(message) {
1673
- return this.interventionCtrl.queueNext(message);
1721
+ return this.getInterventionControllerForTurn().queueNext(message);
1674
1722
  }
1675
1723
  /** Whether there are deferred messages queued for after the turn */
1676
1724
  hasQueuedNext() {
1677
- return this.interventionCtrl.hasDeferred;
1725
+ return this.getInterventionControllerForTurn().hasDeferred;
1678
1726
  }
1679
1727
  /** Drain and return all deferred messages (clears the queue) */
1680
1728
  drainQueuedNext() {
1681
- return this.interventionCtrl.drainDeferred();
1729
+ return this.getInterventionControllerForTurn().drainDeferred();
1682
1730
  }
1683
1731
  /**
1684
1732
  * Get the raw intervention controller for advanced use cases.
@@ -1690,7 +1738,7 @@ var Agent = class _Agent {
1690
1738
  * @internal
1691
1739
  */
1692
1740
  getInterventionController() {
1693
- return this.interventionCtrl;
1741
+ return this.getInterventionControllerForTurn();
1694
1742
  }
1695
1743
  // ============================================================================
1696
1744
  // Turn Tracking
@@ -1767,17 +1815,39 @@ var Agent = class _Agent {
1767
1815
  this.config.systemPrompt = prompt;
1768
1816
  this.state.systemPrompt = prompt;
1769
1817
  this.promptBuilder = void 0;
1818
+ this.resetPromptScopedTools();
1770
1819
  }
1771
1820
  /** Update working directory */
1772
1821
  setCwd(cwd) {
1773
1822
  this.config.cwd = cwd;
1774
1823
  this.state.cwd = cwd;
1824
+ this.turnTracker = createTurnTracker({ cwd });
1825
+ if (this.ownsHost) {
1826
+ this.host = localHost(cwd);
1827
+ }
1828
+ this.resetPromptScopedTools();
1775
1829
  this.promptBuilder?.clearCache();
1776
1830
  }
1777
1831
  /** Update model */
1778
1832
  setModel(model) {
1779
1833
  this.config.model = model;
1780
1834
  this.state.model = model;
1835
+ if (this.config.compaction?.summaryModel === void 0) {
1836
+ this.contextManager.setModel(model);
1837
+ }
1838
+ if (this.config.contextWindow === void 0) {
1839
+ const modelId = extractModelId(model);
1840
+ const inferred = inferContextWindow(modelId);
1841
+ if (inferred) {
1842
+ this.contextManager.setLimits({
1843
+ contextWindow: inferred,
1844
+ ...resolveAgentContextLimits(
1845
+ inferred,
1846
+ this.config.compaction
1847
+ )
1848
+ });
1849
+ }
1850
+ }
1781
1851
  }
1782
1852
  /**
1783
1853
  * Get the prompt builder (when using pipeline mode).
@@ -1815,6 +1885,7 @@ var Agent = class _Agent {
1815
1885
  * runtimes can start durable turns without duplicating prompt assembly.
1816
1886
  */
1817
1887
  async buildSystemPrompts(sessionId, override) {
1888
+ await this.ensureSkillTools();
1818
1889
  return await buildAgentSystemPrompts({
1819
1890
  config: this.config,
1820
1891
  toolIds: Array.from(this.tools.keys()),
@@ -1890,6 +1961,7 @@ var Agent = class _Agent {
1890
1961
  parentTools: Array.from(this.tools.values()),
1891
1962
  reasoningLevel: this.state.reasoningLevel,
1892
1963
  host: this.host,
1964
+ ownsHost: this.ownsHost,
1893
1965
  sessions: this.sessions,
1894
1966
  mcpManager: this.mcpManager,
1895
1967
  middlewareRunner: this.middlewareRunner,
@@ -1941,9 +2013,9 @@ var Agent = class _Agent {
1941
2013
  * ```
1942
2014
  */
1943
2015
  async run(options) {
2016
+ const sessions = this.createSessionManager();
1944
2017
  const sessionId = await createSubAgentRunSession({
1945
- sessions: this.sessions,
1946
- loadedSessions: this.loadedSessions,
2018
+ sessions,
1947
2019
  cwd: this.config.cwd,
1948
2020
  parentSessionId: options.parentSessionId,
1949
2021
  title: options.title
@@ -1995,6 +2067,7 @@ var Agent = class _Agent {
1995
2067
  * After calling close(), the agent should not be used.
1996
2068
  */
1997
2069
  async close() {
2070
+ this._signal.clear();
1998
2071
  if (this.tracingShutdown) {
1999
2072
  await this.tracingShutdown();
2000
2073
  }
@@ -2011,6 +2084,7 @@ async function runConcurrent(tasks, options) {
2011
2084
  let currentIndex = 0;
2012
2085
  async function runNext() {
2013
2086
  while (currentIndex < tasks.length) {
2087
+ if (options?.abort?.aborted) break;
2014
2088
  const index = currentIndex++;
2015
2089
  const task = tasks[index];
2016
2090
  results[index] = await task.agent.run({
@@ -2061,11 +2135,14 @@ export {
2061
2135
  InterventionController,
2062
2136
  LLM,
2063
2137
  LLMError,
2138
+ LayeredSettings,
2139
+ LocalSignal,
2064
2140
  MAX_BYTES,
2065
2141
  MAX_LINES,
2066
2142
  MemoryStorage,
2067
2143
  MiddlewareRunner,
2068
2144
  ModelCapabilityResolver,
2145
+ NullSettings,
2069
2146
  OUTPUT_TOKEN_MAX,
2070
2147
  PRIORITY_BASE,
2071
2148
  PRIORITY_CUSTOM,
@@ -2075,6 +2152,8 @@ export {
2075
2152
  PRIORITY_SKILLS,
2076
2153
  PRUNE_PROTECTED_TOOLS,
2077
2154
  PatternCapabilitySource,
2155
+ PluginEventBus,
2156
+ PluginRegistry,
2078
2157
  Presets,
2079
2158
  PromptBuilder,
2080
2159
  RemoteCapabilityFetcher,
@@ -2085,12 +2164,14 @@ export {
2085
2164
  SessionManager,
2086
2165
  SkillRegistry,
2087
2166
  SourcePriority,
2167
+ StaticSettings,
2088
2168
  SubAgentTracker,
2089
2169
  TRUNCATE_DIR,
2090
2170
  TRUNCATE_GLOB,
2091
2171
  Tool,
2092
2172
  ToolRegistry,
2093
2173
  TurnChangeTracker,
2174
+ ValidatedSettings,
2094
2175
  advanceAgentTurnState,
2095
2176
  applyAgentWorkflowCommitResult,
2096
2177
  applyAgentWorkflowModelStepResult,
@@ -2138,6 +2219,7 @@ export {
2138
2219
  createResolver,
2139
2220
  createRetryHandler,
2140
2221
  createRetryState,
2222
+ createScope,
2141
2223
  createSkillRegistry,
2142
2224
  createSkillResourceTool,
2143
2225
  createSkillTool,
@@ -2145,13 +2227,17 @@ export {
2145
2227
  createSubAgentTools,
2146
2228
  createTelemetryConfig,
2147
2229
  createTurnTracker,
2230
+ currentScope,
2148
2231
  defaultAgentTaskCheckpointStrategy,
2149
2232
  defaultRegistry,
2233
+ definePlugin,
2150
2234
  defineServer,
2151
2235
  defineTool,
2152
2236
  deserializeMessage,
2153
2237
  detectModelFamily,
2238
+ discoverAgentProfiles,
2154
2239
  discoverInstructions,
2240
+ discoverPlugins,
2155
2241
  discoverSkills,
2156
2242
  dockerHost,
2157
2243
  emptySkillRegistry,
@@ -2184,6 +2270,8 @@ export {
2184
2270
  getLeafId,
2185
2271
  getModelId,
2186
2272
  getNetworkStatus,
2273
+ getPluginLoader,
2274
+ getProjectAgentsDir,
2187
2275
  getProjectId,
2188
2276
  getProjectSessionsDir,
2189
2277
  getProviderCompatibility,
@@ -2195,15 +2283,20 @@ export {
2195
2283
  getSessionsDir,
2196
2284
  getTemplate,
2197
2285
  getToolRisk,
2286
+ getUserAgentsDir,
2198
2287
  hasStreamProviderFactory,
2199
2288
  httpServer,
2289
+ inferContextWindow,
2200
2290
  inferProvider,
2201
2291
  inferResourceType,
2202
2292
  isContextOverflowing,
2293
+ isDefinedPlugin,
2294
+ isMarkdownProfile,
2203
2295
  isRetryable,
2204
2296
  isRetryableCategory,
2205
2297
  likelySupportsReasoning,
2206
2298
  loadGlobalInstructions,
2299
+ loadPluginModule,
2207
2300
  loadResourceContent,
2208
2301
  loadSkillContent,
2209
2302
  loadSkillMetadata,
@@ -2212,9 +2305,12 @@ export {
2212
2305
  needsCustomStreamProvider,
2213
2306
  normalizeToolReplayPolicy,
2214
2307
  otelMiddleware,
2308
+ parseAgentFrontmatter,
2215
2309
  parseFrontmatter,
2216
2310
  parseJSONL,
2311
+ parseMarkdownAgent,
2217
2312
  parseRetryDelay,
2313
+ parseToolSpec,
2218
2314
  plan,
2219
2315
  planNextAgentWorkflowOperation,
2220
2316
  prepareModelStep,
@@ -2225,8 +2321,12 @@ export {
2225
2321
  pruneToolResults,
2226
2322
  quick,
2227
2323
  recordAgentWorkflowReplayDecision,
2324
+ resetFrameworkAliases,
2325
+ resetPluginLoader,
2326
+ resolveFrameworkAliases,
2228
2327
  restoreAgentWorkflowMessage,
2229
2328
  restoreAgentWorkflowMessages,
2329
+ restoreScope,
2230
2330
  review,
2231
2331
  runChatLoop,
2232
2332
  runConcurrent,
@@ -2240,6 +2340,7 @@ export {
2240
2340
  sleep,
2241
2341
  snapshotAgentWorkflowMessage,
2242
2342
  snapshotAgentWorkflowMessages,
2343
+ snapshotScope,
2243
2344
  sseServer,
2244
2345
  stdioServer,
2245
2346
  stream,
@@ -2248,10 +2349,12 @@ export {
2248
2349
  summarizeEnvironment,
2249
2350
  supportsReasoning,
2250
2351
  supportsReasoningSync,
2352
+ toAgentProfile,
2251
2353
  toJSONL,
2252
2354
  toJSONLBatch,
2253
2355
  truncateOutput,
2254
2356
  watch,
2255
2357
  withFileTracking,
2256
- withRetry
2358
+ withRetry,
2359
+ withinScope
2257
2360
  };