fourmis-agents-sdk 0.3.1 → 0.4.1

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 (84) hide show
  1. package/README.md +126 -198
  2. package/dist/agent-loop.d.ts +21 -3
  3. package/dist/agent-loop.d.ts.map +1 -1
  4. package/dist/agent-loop.js +279 -90
  5. package/dist/agents/index.js +1079 -124
  6. package/dist/agents/tools.d.ts.map +1 -1
  7. package/dist/agents/tools.js +1079 -124
  8. package/dist/agents/types.d.ts +4 -0
  9. package/dist/agents/types.d.ts.map +1 -1
  10. package/dist/api.d.ts +8 -5
  11. package/dist/api.d.ts.map +1 -1
  12. package/dist/api.js +1663 -430
  13. package/dist/hooks.d.ts +19 -1
  14. package/dist/hooks.d.ts.map +1 -1
  15. package/dist/hooks.js +27 -2
  16. package/dist/index.d.ts +8 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1671 -431
  19. package/dist/mcp/client.d.ts +8 -1
  20. package/dist/mcp/client.d.ts.map +1 -1
  21. package/dist/mcp/client.js +134 -13
  22. package/dist/mcp/index.js +134 -13
  23. package/dist/mcp/types.d.ts +21 -1
  24. package/dist/mcp/types.d.ts.map +1 -1
  25. package/dist/permissions.d.ts.map +1 -1
  26. package/dist/permissions.js +7 -3
  27. package/dist/providers/anthropic.d.ts.map +1 -1
  28. package/dist/providers/anthropic.js +41 -2
  29. package/dist/providers/openai.d.ts +6 -0
  30. package/dist/providers/openai.d.ts.map +1 -1
  31. package/dist/providers/openai.js +36 -6
  32. package/dist/providers/registry.js +76 -8
  33. package/dist/providers/types.d.ts +4 -1
  34. package/dist/providers/types.d.ts.map +1 -1
  35. package/dist/query.d.ts +21 -2
  36. package/dist/query.d.ts.map +1 -1
  37. package/dist/query.js +69 -1
  38. package/dist/skills/index.js +23 -1
  39. package/dist/skills/skills.d.ts +16 -0
  40. package/dist/skills/skills.d.ts.map +1 -1
  41. package/dist/skills/skills.js +23 -1
  42. package/dist/tools/ask-user-question.d.ts +7 -0
  43. package/dist/tools/ask-user-question.d.ts.map +1 -0
  44. package/dist/tools/ask-user-question.js +48 -0
  45. package/dist/tools/bash.d.ts.map +1 -1
  46. package/dist/tools/bash.js +47 -2
  47. package/dist/tools/config.d.ts +7 -0
  48. package/dist/tools/config.d.ts.map +1 -0
  49. package/dist/tools/config.js +114 -0
  50. package/dist/tools/exit-plan-mode.d.ts +7 -0
  51. package/dist/tools/exit-plan-mode.d.ts.map +1 -0
  52. package/dist/tools/exit-plan-mode.js +34 -0
  53. package/dist/tools/index.d.ts +7 -0
  54. package/dist/tools/index.d.ts.map +1 -1
  55. package/dist/tools/index.js +506 -9
  56. package/dist/tools/notebook-edit.d.ts +7 -0
  57. package/dist/tools/notebook-edit.d.ts.map +1 -0
  58. package/dist/tools/notebook-edit.js +83 -0
  59. package/dist/tools/presets.d.ts +2 -1
  60. package/dist/tools/presets.d.ts.map +1 -1
  61. package/dist/tools/presets.js +22 -4
  62. package/dist/tools/read.d.ts.map +1 -1
  63. package/dist/tools/read.js +12 -1
  64. package/dist/tools/registry.d.ts +2 -0
  65. package/dist/tools/registry.d.ts.map +1 -1
  66. package/dist/tools/registry.js +10 -0
  67. package/dist/tools/todo-write.d.ts +7 -0
  68. package/dist/tools/todo-write.d.ts.map +1 -0
  69. package/dist/tools/todo-write.js +69 -0
  70. package/dist/tools/web-fetch.d.ts +6 -0
  71. package/dist/tools/web-fetch.d.ts.map +1 -0
  72. package/dist/tools/web-fetch.js +85 -0
  73. package/dist/tools/web-search.d.ts +7 -0
  74. package/dist/tools/web-search.d.ts.map +1 -0
  75. package/dist/tools/web-search.js +78 -0
  76. package/dist/types.d.ts +344 -42
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/utils/session-store.d.ts +1 -1
  79. package/dist/utils/session-store.d.ts.map +1 -1
  80. package/dist/utils/session-store.js +49 -2
  81. package/dist/utils/system-prompt.d.ts +2 -0
  82. package/dist/utils/system-prompt.d.ts.map +1 -1
  83. package/dist/utils/system-prompt.js +33 -4
  84. package/package.json +3 -2
@@ -104,10 +104,57 @@ function mergeUsage(a, b) {
104
104
  }
105
105
 
106
106
  // src/agent-loop.ts
107
+ function makeModelUsageEntry() {
108
+ return {
109
+ inputTokens: 0,
110
+ outputTokens: 0,
111
+ cacheReadInputTokens: 0,
112
+ cacheCreationInputTokens: 0,
113
+ totalCostUsd: 0
114
+ };
115
+ }
116
+ function makeErrorResult(params) {
117
+ return {
118
+ type: "result",
119
+ subtype: params.subtype,
120
+ duration_ms: Date.now() - params.startTime,
121
+ duration_api_ms: params.apiTimeMs,
122
+ is_error: true,
123
+ num_turns: params.turns,
124
+ stop_reason: null,
125
+ total_cost_usd: params.costUsd,
126
+ usage: params.usage,
127
+ modelUsage: params.modelUsage,
128
+ permission_denials: params.permissionDenials,
129
+ errors: params.errors,
130
+ uuid: uuid(),
131
+ session_id: params.sessionId
132
+ };
133
+ }
134
+ function extractStructuredJson(text) {
135
+ const trimmed = text.trim();
136
+ if (!trimmed) {
137
+ return { ok: false, error: "Empty result text; expected JSON output." };
138
+ }
139
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
140
+ const candidate = fenced ? fenced[1].trim() : trimmed;
141
+ try {
142
+ return { ok: true, value: JSON.parse(candidate) };
143
+ } catch (err) {
144
+ const message = err instanceof Error ? err.message : String(err);
145
+ return { ok: false, error: `Invalid JSON output: ${message}` };
146
+ }
147
+ }
107
148
  async function* agentLoop(prompt, options) {
108
149
  const {
109
150
  provider,
110
151
  model,
152
+ fallbackModel,
153
+ modelState,
154
+ maxThinkingTokensState,
155
+ thinking,
156
+ effort,
157
+ outputFormat,
111
158
  systemPrompt,
112
159
  tools,
113
160
  permissions,
@@ -115,7 +162,7 @@ async function* agentLoop(prompt, options) {
115
162
  sessionId,
116
163
  maxTurns,
117
164
  maxBudgetUsd,
118
- includeStreamEvents,
165
+ includePartialMessages,
119
166
  signal,
120
167
  env,
121
168
  debug,
@@ -123,14 +170,17 @@ async function* agentLoop(prompt, options) {
123
170
  mcpClient,
124
171
  previousMessages,
125
172
  sessionLogger,
126
- nativeMemoryTool
173
+ nativeMemoryTool,
174
+ initMeta
127
175
  } = options;
176
+ const effectiveModelState = modelState ?? { current: model };
128
177
  const startTime = Date.now();
129
178
  let apiTimeMs = 0;
130
179
  let turns = 0;
131
180
  let totalUsage = emptyTokenUsage();
132
181
  let costUsd = 0;
133
182
  const modelUsage = {};
183
+ const permissionDenials = [];
134
184
  if (mcpClient) {
135
185
  await mcpClient.connectAll();
136
186
  for (const tool of mcpClient.getTools()) {
@@ -148,56 +198,135 @@ async function* agentLoop(prompt, options) {
148
198
  sessionLogger("user", prompt, null);
149
199
  }
150
200
  yield {
151
- type: "init",
152
- sessionId,
153
- model,
154
- provider: provider.name,
201
+ type: "system",
202
+ subtype: "init",
203
+ apiKeySource: "user",
204
+ claude_code_version: "fourmis-agent-sdk",
205
+ session_id: sessionId,
206
+ model: effectiveModelState.current,
155
207
  tools: tools.list(),
156
208
  cwd,
209
+ mcp_servers: (mcpClient?.status() ?? []).map((s) => ({ name: s.name, status: s.status })),
210
+ permissionMode: permissions.getMode(),
211
+ agents: initMeta?.agents,
212
+ betas: initMeta?.betas,
213
+ slash_commands: initMeta?.slashCommands ?? [],
214
+ output_style: initMeta?.outputStyle ?? "default",
215
+ skills: initMeta?.skills ?? [],
216
+ plugins: (initMeta?.plugins ?? []).map((p) => ({ name: p.path.split("/").pop() ?? p.path, path: p.path })),
157
217
  uuid: uuid()
158
218
  };
159
219
  if (hooks) {
160
- await hooks.fire("SessionStart", { event: "SessionStart", session_id: sessionId }, undefined, { signal });
220
+ await hooks.fire("Setup", {
221
+ event: "Setup",
222
+ hook_event_name: "Setup",
223
+ trigger: "init",
224
+ session_id: sessionId,
225
+ cwd,
226
+ permission_mode: permissions.getMode()
227
+ }, undefined, { signal });
228
+ }
229
+ if (hooks) {
230
+ await hooks.fire("SessionStart", {
231
+ event: "SessionStart",
232
+ hook_event_name: "SessionStart",
233
+ session_id: sessionId,
234
+ source: "startup",
235
+ model: effectiveModelState.current,
236
+ cwd,
237
+ permission_mode: permissions.getMode()
238
+ }, undefined, { signal });
161
239
  }
162
240
  while (true) {
163
241
  if (signal.aborted) {
164
- yield makeError("error_execution", ["Aborted"], turns, costUsd, sessionId, startTime);
242
+ yield makeErrorResult({
243
+ subtype: "error_during_execution",
244
+ errors: ["Aborted"],
245
+ turns,
246
+ costUsd,
247
+ sessionId,
248
+ startTime,
249
+ apiTimeMs,
250
+ usage: totalUsage,
251
+ modelUsage,
252
+ permissionDenials
253
+ });
165
254
  return;
166
255
  }
167
256
  if (turns >= maxTurns) {
168
- yield makeError("error_max_turns", [`Reached maximum turns (${maxTurns})`], turns, costUsd, sessionId, startTime);
257
+ yield makeErrorResult({
258
+ subtype: "error_max_turns",
259
+ errors: [`Reached maximum turns (${maxTurns})`],
260
+ turns,
261
+ costUsd,
262
+ sessionId,
263
+ startTime,
264
+ apiTimeMs,
265
+ usage: totalUsage,
266
+ modelUsage,
267
+ permissionDenials
268
+ });
169
269
  return;
170
270
  }
171
271
  if (maxBudgetUsd > 0 && costUsd >= maxBudgetUsd) {
172
- yield makeError("error_max_budget", [`Reached budget limit ($${maxBudgetUsd})`], turns, costUsd, sessionId, startTime);
272
+ yield makeErrorResult({
273
+ subtype: "error_max_budget_usd",
274
+ errors: [],
275
+ turns,
276
+ costUsd,
277
+ sessionId,
278
+ startTime,
279
+ apiTimeMs,
280
+ usage: totalUsage,
281
+ modelUsage,
282
+ permissionDenials
283
+ });
173
284
  return;
174
285
  }
286
+ const activeModel = effectiveModelState.current;
175
287
  const toolDefs = tools.getDefinitions();
176
288
  const apiStart = Date.now();
177
289
  let assistantTextParts = [];
178
- let toolCalls = [];
290
+ const toolCalls = [];
179
291
  let turnUsage = emptyTokenUsage();
292
+ let turnStopReason = null;
180
293
  const nativeTools = nativeMemoryTool ? [nativeMemoryTool.definition] : undefined;
181
294
  try {
182
295
  const chunks = provider.chat({
183
- model,
296
+ model: activeModel,
184
297
  messages,
185
298
  tools: toolDefs.length > 0 ? toolDefs : undefined,
186
299
  systemPrompt,
187
300
  signal,
188
- nativeTools
301
+ nativeTools,
302
+ thinkingBudget: maxThinkingTokensState?.current,
303
+ thinking,
304
+ effort,
305
+ outputFormat
189
306
  });
190
307
  for await (const chunk of chunks) {
191
308
  switch (chunk.type) {
192
309
  case "text_delta":
193
310
  assistantTextParts.push(chunk.text);
194
- if (includeStreamEvents) {
195
- yield { type: "stream", subtype: "text_delta", text: chunk.text, uuid: uuid() };
311
+ if (includePartialMessages) {
312
+ yield {
313
+ type: "stream_event",
314
+ event: { type: "text_delta", text: chunk.text },
315
+ parent_tool_use_id: null,
316
+ uuid: uuid(),
317
+ session_id: sessionId
318
+ };
196
319
  }
197
320
  break;
198
321
  case "thinking_delta":
199
- if (includeStreamEvents) {
200
- yield { type: "stream", subtype: "thinking_delta", text: chunk.text, uuid: uuid() };
322
+ if (includePartialMessages) {
323
+ yield {
324
+ type: "stream_event",
325
+ event: { type: "thinking_delta", thinking: chunk.text },
326
+ parent_tool_use_id: null,
327
+ uuid: uuid(),
328
+ session_id: sessionId
329
+ };
201
330
  }
202
331
  break;
203
332
  case "tool_call":
@@ -207,33 +336,54 @@ async function* agentLoop(prompt, options) {
207
336
  turnUsage = mergeUsage(turnUsage, chunk.usage);
208
337
  break;
209
338
  case "done":
339
+ turnStopReason = chunk.stopReason ?? null;
210
340
  break;
211
341
  }
212
342
  }
213
343
  } catch (err) {
214
344
  const message = err instanceof Error ? err.message : String(err);
215
- yield makeError("error_execution", [`API error: ${message}`], turns, costUsd, sessionId, startTime);
345
+ if (fallbackModel && activeModel !== fallbackModel) {
346
+ effectiveModelState.current = fallbackModel;
347
+ yield {
348
+ type: "system",
349
+ subtype: "status",
350
+ status: null,
351
+ permissionMode: permissions.getMode(),
352
+ uuid: uuid(),
353
+ session_id: sessionId
354
+ };
355
+ continue;
356
+ }
357
+ yield makeErrorResult({
358
+ subtype: "error_during_execution",
359
+ errors: [`API error: ${message}`],
360
+ turns,
361
+ costUsd,
362
+ sessionId,
363
+ startTime,
364
+ apiTimeMs,
365
+ usage: totalUsage,
366
+ modelUsage,
367
+ permissionDenials
368
+ });
216
369
  return;
217
370
  }
218
371
  apiTimeMs += Date.now() - apiStart;
219
372
  turns++;
220
373
  totalUsage = mergeUsage(totalUsage, turnUsage);
221
- const turnCost = provider.calculateCost(model, turnUsage);
374
+ const turnCost = provider.calculateCost(activeModel, turnUsage);
222
375
  costUsd += turnCost;
223
- if (!modelUsage[model]) {
224
- modelUsage[model] = {
225
- inputTokens: 0,
226
- outputTokens: 0,
227
- cacheReadInputTokens: 0,
228
- cacheCreationInputTokens: 0,
229
- totalCostUsd: 0
230
- };
376
+ if (!modelUsage[activeModel]) {
377
+ modelUsage[activeModel] = makeModelUsageEntry();
231
378
  }
232
- modelUsage[model].inputTokens += turnUsage.inputTokens;
233
- modelUsage[model].outputTokens += turnUsage.outputTokens;
234
- modelUsage[model].cacheReadInputTokens += turnUsage.cacheReadInputTokens;
235
- modelUsage[model].cacheCreationInputTokens += turnUsage.cacheCreationInputTokens;
236
- modelUsage[model].totalCostUsd += turnCost;
379
+ modelUsage[activeModel].inputTokens += turnUsage.inputTokens;
380
+ modelUsage[activeModel].outputTokens += turnUsage.outputTokens;
381
+ modelUsage[activeModel].cacheReadInputTokens += turnUsage.cacheReadInputTokens;
382
+ modelUsage[activeModel].cacheCreationInputTokens += turnUsage.cacheCreationInputTokens;
383
+ modelUsage[activeModel].totalCostUsd += turnCost;
384
+ modelUsage[activeModel].webSearchRequests = (modelUsage[activeModel].webSearchRequests ?? 0) + (turnUsage.webSearchRequests ?? 0);
385
+ modelUsage[activeModel].costUSD = modelUsage[activeModel].totalCostUsd;
386
+ modelUsage[activeModel].contextWindow = provider.getContextWindow(activeModel);
237
387
  const assistantText = assistantTextParts.join("");
238
388
  const assistantContent = [];
239
389
  if (assistantText) {
@@ -251,28 +401,72 @@ async function* agentLoop(prompt, options) {
251
401
  if (sessionLogger) {
252
402
  sessionLogger("assistant", assistantContent, null);
253
403
  }
254
- if (assistantText) {
255
- yield { type: "text", text: assistantText, uuid: uuid() };
256
- }
404
+ yield {
405
+ type: "assistant",
406
+ message: {
407
+ role: "assistant",
408
+ content: assistantContent
409
+ },
410
+ parent_tool_use_id: null,
411
+ uuid: uuid(),
412
+ session_id: sessionId
413
+ };
257
414
  if (toolCalls.length === 0) {
415
+ let structuredOutput;
416
+ if (outputFormat?.type === "json_schema") {
417
+ const parsed = extractStructuredJson(assistantText);
418
+ if (!parsed.ok) {
419
+ yield makeErrorResult({
420
+ subtype: "error_max_structured_output_retries",
421
+ errors: [parsed.error],
422
+ turns,
423
+ costUsd,
424
+ sessionId,
425
+ startTime,
426
+ apiTimeMs,
427
+ usage: totalUsage,
428
+ modelUsage,
429
+ permissionDenials
430
+ });
431
+ return;
432
+ }
433
+ structuredOutput = parsed.value;
434
+ }
258
435
  if (hooks) {
259
- await hooks.fire("Stop", { event: "Stop", session_id: sessionId, text: assistantText || undefined }, undefined, { signal });
436
+ await hooks.fire("Stop", {
437
+ event: "Stop",
438
+ hook_event_name: "Stop",
439
+ session_id: sessionId,
440
+ text: assistantText || undefined,
441
+ stop_reason: turnStopReason ?? undefined
442
+ }, undefined, {
443
+ signal
444
+ });
260
445
  }
261
446
  if (hooks) {
262
- await hooks.fire("SessionEnd", { event: "SessionEnd", session_id: sessionId }, undefined, { signal });
447
+ await hooks.fire("SessionEnd", {
448
+ event: "SessionEnd",
449
+ hook_event_name: "SessionEnd",
450
+ session_id: sessionId,
451
+ reason: "other"
452
+ }, undefined, { signal });
263
453
  }
264
454
  yield {
265
455
  type: "result",
266
456
  subtype: "success",
267
- text: assistantText || null,
268
- turns,
269
- costUsd,
270
- durationMs: Date.now() - startTime,
271
- durationApiMs: apiTimeMs,
272
- sessionId,
457
+ duration_ms: Date.now() - startTime,
458
+ duration_api_ms: apiTimeMs,
459
+ is_error: false,
460
+ num_turns: turns,
461
+ result: assistantText,
462
+ stop_reason: turnStopReason,
463
+ total_cost_usd: costUsd,
273
464
  usage: totalUsage,
274
465
  modelUsage,
275
- uuid: uuid()
466
+ permission_denials: permissionDenials,
467
+ structured_output: structuredOutput,
468
+ uuid: uuid(),
469
+ session_id: sessionId
276
470
  };
277
471
  return;
278
472
  }
@@ -281,7 +475,13 @@ async function* agentLoop(prompt, options) {
281
475
  let hookDenied = false;
282
476
  let hookUpdatedInput;
283
477
  if (hooks) {
284
- const hookResult = await hooks.fire("PreToolUse", { event: "PreToolUse", tool_name: call.name, tool_input: call.input, session_id: sessionId }, call.id, { signal });
478
+ const hookResult = await hooks.fire("PreToolUse", {
479
+ event: "PreToolUse",
480
+ hook_event_name: "PreToolUse",
481
+ tool_name: call.name,
482
+ tool_input: call.input,
483
+ session_id: sessionId
484
+ }, call.id, { signal });
285
485
  if (hookResult) {
286
486
  if (hookResult.permissionDecision === "deny") {
287
487
  hookDenied = true;
@@ -293,14 +493,6 @@ async function* agentLoop(prompt, options) {
293
493
  }
294
494
  if (hookDenied) {
295
495
  const denyContent = "Denied by hook";
296
- yield {
297
- type: "tool_result",
298
- id: call.id,
299
- name: call.name,
300
- content: denyContent,
301
- isError: true,
302
- uuid: uuid()
303
- };
304
496
  toolResults.push({
305
497
  type: "tool_result",
306
498
  tool_use_id: call.id,
@@ -316,14 +508,11 @@ async function* agentLoop(prompt, options) {
316
508
  const permResult = await permissions.check(call.name, inputAfterHook ?? {}, { signal, toolUseId: call.id });
317
509
  if (permResult.behavior === "deny") {
318
510
  const denyContent = `Permission denied: ${permResult.message}`;
319
- yield {
320
- type: "tool_result",
321
- id: call.id,
322
- name: call.name,
323
- content: denyContent,
324
- isError: true,
325
- uuid: uuid()
326
- };
511
+ permissionDenials.push({
512
+ tool_name: call.name,
513
+ tool_use_id: call.id,
514
+ tool_input: inputAfterHook ?? {}
515
+ });
327
516
  toolResults.push({
328
517
  type: "tool_result",
329
518
  tool_use_id: call.id,
@@ -336,13 +525,6 @@ async function* agentLoop(prompt, options) {
336
525
  continue;
337
526
  }
338
527
  const toolInput = permResult.behavior === "allow" && permResult.updatedInput ? permResult.updatedInput : inputAfterHook;
339
- yield {
340
- type: "tool_use",
341
- id: call.id,
342
- name: call.name,
343
- input: toolInput,
344
- uuid: uuid()
345
- };
346
528
  let result;
347
529
  if (call.name === "memory" && nativeMemoryTool) {
348
530
  try {
@@ -361,28 +543,36 @@ async function* agentLoop(prompt, options) {
361
543
  };
362
544
  result = await tools.execute(call.name, toolInput, toolCtx);
363
545
  }
546
+ if (call.name === "ExitPlanMode") {
547
+ permissions.setMode("default");
548
+ }
364
549
  if (debug) {
365
550
  console.error(`[debug] Tool ${call.name}: ${result.isError ? "ERROR" : "OK"} (${result.content.length} chars)`);
366
551
  }
367
552
  if (hooks) {
368
553
  if (result.isError) {
369
- await hooks.fire("PostToolUseFailure", { event: "PostToolUseFailure", tool_name: call.name, tool_result: result.content, tool_error: true, session_id: sessionId }, call.id, { signal });
554
+ await hooks.fire("PostToolUseFailure", {
555
+ event: "PostToolUseFailure",
556
+ hook_event_name: "PostToolUseFailure",
557
+ tool_name: call.name,
558
+ tool_result: result.content,
559
+ tool_error: true,
560
+ session_id: sessionId
561
+ }, call.id, { signal });
370
562
  } else {
371
- const postResult = await hooks.fire("PostToolUse", { event: "PostToolUse", tool_name: call.name, tool_result: result.content, session_id: sessionId }, call.id, { signal });
563
+ const postResult = await hooks.fire("PostToolUse", {
564
+ event: "PostToolUse",
565
+ hook_event_name: "PostToolUse",
566
+ tool_name: call.name,
567
+ tool_result: result.content,
568
+ session_id: sessionId
569
+ }, call.id, { signal });
372
570
  if (postResult?.additionalContext) {
373
571
  result.content += `
374
572
  ${postResult.additionalContext}`;
375
573
  }
376
574
  }
377
575
  }
378
- yield {
379
- type: "tool_result",
380
- id: call.id,
381
- name: call.name,
382
- content: result.content,
383
- isError: result.isError,
384
- uuid: uuid()
385
- };
386
576
  toolResults.push({
387
577
  type: "tool_result",
388
578
  tool_use_id: call.id,
@@ -394,20 +584,19 @@ ${postResult.additionalContext}`;
394
584
  if (sessionLogger) {
395
585
  sessionLogger("user", toolResults, null);
396
586
  }
587
+ yield {
588
+ type: "user",
589
+ message: {
590
+ role: "user",
591
+ content: toolResults
592
+ },
593
+ parent_tool_use_id: null,
594
+ isSynthetic: true,
595
+ uuid: uuid(),
596
+ session_id: sessionId
597
+ };
397
598
  }
398
599
  }
399
- function makeError(subtype, errors, turns, costUsd, sessionId, startTime) {
400
- return {
401
- type: "result",
402
- subtype,
403
- errors,
404
- turns,
405
- costUsd,
406
- durationMs: Date.now() - startTime,
407
- sessionId,
408
- uuid: uuid()
409
- };
410
- }
411
600
  export {
412
601
  agentLoop
413
602
  };