@n8n/agents 0.5.2 → 0.6.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.
@@ -1,7 +1,9 @@
1
1
  import type { ProviderOptions } from '@ai-sdk/provider-utils';
2
2
  import type { z } from 'zod';
3
+ import { type ModelCost } from '../sdk/catalog';
3
4
  import type { BuiltMemory, BuiltProviderTool, BuiltTelemetry, BuiltTool, CheckpointStore, GenerateResult, RunOptions, SemanticRecallConfig, SerializableAgentState, StreamResult, ThinkingConfig, TitleGenerationConfig } from '../types';
4
5
  import { AgentEventBus } from './event-bus';
6
+ import { RunStateManager } from './run-state';
5
7
  import type { ExecutionOptions, ModelConfig } from '../types/sdk/agent';
6
8
  import type { AgentMessage } from '../types/sdk/message';
7
9
  export interface AgentRuntimeConfig {
@@ -28,6 +30,8 @@ export interface AgentRuntimeConfig {
28
30
  toolCallConcurrency?: number;
29
31
  titleGeneration?: TitleGenerationConfig;
30
32
  telemetry?: BuiltTelemetry;
33
+ modelCost?: ModelCost;
34
+ runState?: RunStateManager;
31
35
  }
32
36
  export declare class AgentRuntime {
33
37
  private config;
@@ -35,6 +39,8 @@ export declare class AgentRuntime {
35
39
  private eventBus;
36
40
  private currentState;
37
41
  private modelCost;
42
+ private runId;
43
+ private executionOptions;
38
44
  constructor(config: AgentRuntimeConfig);
39
45
  getState(): SerializableAgentState;
40
46
  abort(): void;
@@ -77,5 +83,6 @@ export declare class AgentRuntime {
77
83
  private ensureModelCost;
78
84
  private applyCost;
79
85
  private setListWorkingMemoryConfig;
86
+ private emitEvent;
80
87
  private resolveWorkingMemoryParams;
81
88
  }
@@ -65,9 +65,11 @@ const EMPTY_MESSAGE_LIST = {
65
65
  };
66
66
  class AgentRuntime {
67
67
  constructor(config) {
68
+ this.runId = '';
68
69
  this.config = config;
69
- this.runState = new run_state_1.RunStateManager(config.checkpointStorage);
70
+ this.runState = config.runState ?? new run_state_1.RunStateManager(config.checkpointStorage);
70
71
  this.eventBus = config.eventBus ?? new event_bus_1.AgentEventBus();
72
+ this.modelCost = config.modelCost;
71
73
  this.currentState = {
72
74
  persistence: undefined,
73
75
  status: 'idle',
@@ -82,43 +84,58 @@ class AgentRuntime {
82
84
  this.eventBus.abort();
83
85
  }
84
86
  async generate(input, options) {
85
- const runId = (0, run_state_1.generateRunId)();
87
+ this.runId = (0, run_state_1.generateRunId)();
88
+ this.executionOptions = options;
89
+ this.updateState({ persistence: options?.persistence });
86
90
  let list = undefined;
87
91
  try {
88
- list = await this.initRun(input, options);
89
- const rawResult = await this.runGenerateLoop(list, options, undefined, runId);
90
- return this.finalizeGenerate(rawResult, list, runId);
92
+ list = await this.initRun(input);
93
+ const rawResult = await this.runGenerateLoop(list);
94
+ return this.finalizeGenerate(rawResult, list);
91
95
  }
92
96
  catch (error) {
93
- await this.flushTelemetry(options);
97
+ await this.flushTelemetry();
94
98
  const isAbort = this.eventBus.isAborted;
95
99
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
96
100
  if (!isAbort) {
97
- this.eventBus.emit({ type: "error", message: String(error), error });
101
+ this.emitEvent({ type: "error", message: String(error), error });
98
102
  }
99
- return { runId, messages: list?.responseDelta() ?? [], finishReason: 'error', error };
103
+ return {
104
+ runId: this.runId,
105
+ messages: list?.responseDelta() ?? [],
106
+ finishReason: 'error',
107
+ error,
108
+ getState: () => this.getState(),
109
+ };
100
110
  }
101
111
  }
102
112
  async stream(input, options) {
103
- const runId = (0, run_state_1.generateRunId)();
113
+ this.runId = (0, run_state_1.generateRunId)();
114
+ this.executionOptions = options;
115
+ this.updateState({ persistence: options?.persistence });
104
116
  let list;
105
117
  try {
106
- list = await this.initRun(input, options);
118
+ list = await this.initRun(input);
107
119
  }
108
120
  catch (error) {
109
121
  const isAbort = this.eventBus.isAborted;
110
122
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
111
123
  if (!isAbort) {
112
- this.eventBus.emit({ type: "error", message: String(error), error });
124
+ this.emitEvent({ type: "error", message: String(error), error });
113
125
  }
114
- return { runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
126
+ return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
115
127
  }
116
- return { runId, stream: this.startStreamLoop(list, options, undefined, runId) };
128
+ return {
129
+ runId: this.runId,
130
+ stream: this.startStreamLoop(list),
131
+ getState: () => this.getState(),
132
+ };
117
133
  }
118
134
  async resume(method, data, options) {
119
- const state = await this.runState.resume(options.runId);
135
+ this.runId = options.runId;
136
+ const state = await this.runState.resume(this.runId);
120
137
  if (!state)
121
- throw new Error(`No suspended run found for runId: ${options.runId}`);
138
+ throw new Error(`No suspended run found for runId: ${this.runId}`);
122
139
  const toolCall = state.pendingToolCalls[options.toolCallId];
123
140
  if (!toolCall)
124
141
  throw new Error(`No tool call found for toolCallId: ${options.toolCallId}`);
@@ -141,11 +158,9 @@ class AgentRuntime {
141
158
  ...persisted,
142
159
  ...callerExecOptions,
143
160
  };
144
- const resumeOptions = {
145
- persistence: state.persistence,
146
- ...mergedExecOptions,
147
- };
148
- this.eventBus.resetAbort(resumeOptions.abortSignal);
161
+ this.executionOptions = mergedExecOptions;
162
+ this.updateState({ persistence: state.persistence });
163
+ this.eventBus.resetAbort(this.executionOptions?.abortSignal);
149
164
  const pendingResume = {
150
165
  pendingToolCalls: state.pendingToolCalls,
151
166
  resumeToolCallId: options.toolCallId,
@@ -155,48 +170,51 @@ class AgentRuntime {
155
170
  await this.ensureModelCost();
156
171
  await this.setListWorkingMemoryConfig(list, state.persistence);
157
172
  if (method === 'generate') {
158
- const rawResult = await this.runGenerateLoop(list, resumeOptions, pendingResume, options.runId);
173
+ const rawResult = await this.runGenerateLoop(list, pendingResume);
159
174
  if (!rawResult.pendingSuspend) {
160
- await this.cleanupRun(options.runId);
175
+ await this.cleanupRun();
161
176
  }
162
- return this.finalizeGenerate(rawResult, list, options.runId);
177
+ return this.finalizeGenerate(rawResult, list);
163
178
  }
164
179
  return {
165
- runId: options.runId,
166
- stream: this.startStreamLoop(list, resumeOptions, pendingResume, options.runId),
180
+ runId: this.runId,
181
+ stream: this.startStreamLoop(list, pendingResume),
182
+ getState: () => this.getState(),
167
183
  };
168
184
  }
169
185
  catch (error) {
170
186
  const isAbort = this.eventBus.isAborted;
171
187
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
172
188
  if (!isAbort) {
173
- this.eventBus.emit({ type: "error", message: String(error), error });
189
+ this.emitEvent({ type: "error", message: String(error), error });
174
190
  }
175
191
  if (method === 'generate') {
176
192
  return {
177
- runId: options.runId,
193
+ runId: this.runId,
178
194
  messages: [],
179
195
  finishReason: 'error',
180
196
  error,
197
+ getState: () => this.getState(),
181
198
  };
182
199
  }
183
- return { runId: options.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
200
+ return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
184
201
  }
185
202
  }
186
- async buildMessageList(input, options) {
203
+ async buildMessageList(input) {
187
204
  const list = new message_list_1.AgentMessageList();
188
- if (this.config.memory && options?.persistence?.threadId) {
189
- const memMessages = await this.config.memory.getMessages(options.persistence.threadId, {
205
+ const persistence = this.currentState.persistence;
206
+ if (this.config.memory && persistence?.threadId) {
207
+ const memMessages = await this.config.memory.getMessages(persistence.threadId, {
190
208
  limit: this.config.lastMessages ?? 10,
191
209
  });
192
210
  if (memMessages.length > 0) {
193
211
  list.addHistory((0, strip_orphaned_tool_messages_1.stripOrphanedToolMessages)(memMessages));
194
212
  }
195
213
  }
196
- if (this.config.semanticRecall && options?.persistence?.threadId) {
197
- await this.performSemanticRecall(list, input, options.persistence.threadId, options.persistence.resourceId);
214
+ if (this.config.semanticRecall && persistence?.threadId) {
215
+ await this.performSemanticRecall(list, input, persistence.threadId, persistence.resourceId);
198
216
  }
199
- await this.setListWorkingMemoryConfig(list, options?.persistence);
217
+ await this.setListWorkingMemoryConfig(list, persistence);
200
218
  list.addInput(input);
201
219
  return list;
202
220
  }
@@ -278,37 +296,34 @@ class AgentRuntime {
278
296
  return mid && expandedIds.has(mid);
279
297
  });
280
298
  }
281
- async initRun(input, options) {
282
- this.eventBus.resetAbort(options?.abortSignal);
283
- this.updateState({
284
- status: 'running',
285
- persistence: options?.persistence,
286
- });
287
- this.eventBus.emit({ type: "agent_start" });
299
+ async initRun(input) {
300
+ this.eventBus.resetAbort(this.executionOptions?.abortSignal);
301
+ this.updateState({ status: 'running' });
302
+ this.emitEvent({ type: "agent_start" });
288
303
  await this.ensureModelCost();
289
304
  const normalizedInput = (0, runtime_helpers_1.normalizeInput)(input);
290
- return await this.buildMessageList(normalizedInput, options);
305
+ return await this.buildMessageList(normalizedInput);
291
306
  }
292
- finalizeGenerate(result, list, runId) {
293
- result.runId = runId;
307
+ finalizeGenerate(result, list) {
308
+ result.runId = this.runId;
294
309
  result.usage = this.applyCost(result.usage);
295
310
  result.model = this.modelIdString;
296
311
  const finalized = (0, runtime_helpers_1.applySubAgentUsage)(result);
297
312
  this.updateState({ status: 'success', messageList: list.serialize() });
298
- this.eventBus.emit({ type: "agent_end", messages: finalized.messages });
299
- return finalized;
313
+ this.emitEvent({ type: "agent_end", messages: finalized.messages });
314
+ return { ...finalized, getState: () => this.getState() };
300
315
  }
301
- resolveTelemetry(options) {
316
+ resolveTelemetry() {
302
317
  if (this.config.telemetry)
303
318
  return this.config.telemetry;
304
- const inherited = options?.telemetry;
319
+ const inherited = this.executionOptions?.telemetry;
305
320
  if (!inherited)
306
321
  return undefined;
307
322
  return { ...inherited, functionId: this.config.name };
308
323
  }
309
- async flushTelemetry(options) {
324
+ async flushTelemetry() {
310
325
  try {
311
- const resolved = this.resolveTelemetry(options);
326
+ const resolved = this.resolveTelemetry();
312
327
  if (resolved?.provider) {
313
328
  await resolved.provider.forceFlush();
314
329
  }
@@ -316,8 +331,8 @@ class AgentRuntime {
316
331
  catch {
317
332
  }
318
333
  }
319
- buildTelemetryOptions(options) {
320
- const t = this.resolveTelemetry(options);
334
+ buildTelemetryOptions() {
335
+ const t = this.resolveTelemetry();
321
336
  if (!t?.enabled)
322
337
  return {};
323
338
  return {
@@ -332,14 +347,14 @@ class AgentRuntime {
332
347
  },
333
348
  };
334
349
  }
335
- async runGenerateLoop(list, options, pendingResume, runId) {
336
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext({ ...options, persistence: options?.persistence });
350
+ async runGenerateLoop(list, pendingResume) {
351
+ const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
337
352
  let totalUsage;
338
353
  let lastFinishReason = 'stop';
339
354
  let structuredOutput;
340
355
  const toolCallSummary = [];
341
356
  const collectedSubAgentUsage = [];
342
- const runTelemetry = this.resolveTelemetry(options);
357
+ const runTelemetry = this.resolveTelemetry();
343
358
  if (pendingResume) {
344
359
  const batch = await this.iteratePendingToolCallsConcurrent(pendingResume, toolMap, list, runTelemetry);
345
360
  for (const r of batch.results) {
@@ -348,7 +363,7 @@ class AgentRuntime {
348
363
  collectedSubAgentUsage.push(...r.subAgentUsage);
349
364
  }
350
365
  if (Object.keys(batch.pending).length > 0) {
351
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
366
+ const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
352
367
  return {
353
368
  runId: suspendRunId,
354
369
  messages: list.responseDelta(),
@@ -362,16 +377,17 @@ class AgentRuntime {
362
377
  suspendPayload: s.payload,
363
378
  resumeSchema: s.resumeSchema,
364
379
  })),
380
+ getState: () => this.getState(),
365
381
  };
366
382
  }
367
383
  }
368
- const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
384
+ const maxIterations = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
369
385
  for (let i = 0; i < maxIterations; i++) {
370
386
  if (this.eventBus.isAborted) {
371
387
  this.updateState({ status: 'cancelled' });
372
388
  throw new Error('Agent run was aborted');
373
389
  }
374
- this.eventBus.emit({ type: "turn_start" });
390
+ this.emitEvent({ type: "turn_start" });
375
391
  const result = await (0, ai_1.generateText)({
376
392
  model,
377
393
  messages: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
@@ -381,7 +397,7 @@ class AgentRuntime {
381
397
  ? { providerOptions: providerOptions }
382
398
  : {}),
383
399
  ...(outputSpec ? { output: outputSpec } : {}),
384
- ...this.buildTelemetryOptions(options),
400
+ ...this.buildTelemetryOptions(),
385
401
  });
386
402
  const aiFinishReason = result.finishReason;
387
403
  lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
@@ -403,7 +419,7 @@ class AgentRuntime {
403
419
  collectedSubAgentUsage.push(...r.subAgentUsage);
404
420
  }
405
421
  if (Object.keys(batch.pending).length > 0) {
406
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
422
+ const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
407
423
  return {
408
424
  runId: suspendRunId,
409
425
  messages: list.responseDelta(),
@@ -417,6 +433,7 @@ class AgentRuntime {
417
433
  suspendPayload: s.payload,
418
434
  resumeSchema: s.resumeSchema,
419
435
  })),
436
+ getState: () => this.getState(),
420
437
  };
421
438
  }
422
439
  this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractToolResults)(list.responseDelta()));
@@ -424,34 +441,36 @@ class AgentRuntime {
424
441
  if (lastFinishReason === 'tool-calls') {
425
442
  throw new Error(`Agent loop exceeded ${maxIterations} iterations without reaching a stop condition`);
426
443
  }
427
- await this.saveToMemory(list, options);
428
- await this.flushTelemetry(options);
429
- if (this.config.titleGeneration && options?.persistence?.threadId && this.config.memory) {
444
+ await this.saveToMemory(list);
445
+ await this.flushTelemetry();
446
+ const persistence = this.currentState.persistence;
447
+ if (this.config.titleGeneration && persistence?.threadId && this.config.memory) {
430
448
  void (0, title_generation_1.generateThreadTitle)({
431
449
  memory: this.config.memory,
432
- threadId: options.persistence.threadId,
433
- resourceId: options.persistence.resourceId,
450
+ threadId: persistence.threadId,
451
+ resourceId: persistence.resourceId,
434
452
  titleConfig: this.config.titleGeneration,
435
453
  agentModel: this.config.model,
436
454
  turnDelta: list.turnDelta(),
437
455
  });
438
456
  }
439
457
  return {
440
- runId: runId ?? '',
458
+ runId: this.runId,
441
459
  messages: list.responseDelta(),
442
460
  finishReason: lastFinishReason,
443
461
  usage: totalUsage,
444
462
  ...(structuredOutput !== undefined && { structuredOutput }),
445
463
  ...(toolCallSummary.length > 0 && { toolCalls: toolCallSummary }),
446
464
  ...(collectedSubAgentUsage.length > 0 && { subAgentUsage: collectedSubAgentUsage }),
465
+ getState: () => this.getState(),
447
466
  };
448
467
  }
449
- startStreamLoop(list, options, pendingResume, runId) {
468
+ startStreamLoop(list, pendingResume) {
450
469
  const { readable, writable } = new TransformStream();
451
470
  const writer = writable.getWriter();
452
- this.runStreamLoop(list, options, writer, pendingResume, runId).catch(async (error) => {
453
- await this.flushTelemetry(options);
454
- await this.cleanupRun(runId);
471
+ this.runStreamLoop(list, writer, pendingResume).catch(async (error) => {
472
+ await this.flushTelemetry();
473
+ await this.cleanupRun();
455
474
  try {
456
475
  await writer.write({ type: 'error', error });
457
476
  await writer.write({ type: 'finish', finishReason: 'error' });
@@ -463,8 +482,8 @@ class AgentRuntime {
463
482
  });
464
483
  return readable;
465
484
  }
466
- async runStreamLoop(list, options, writer, pendingResume, runId) {
467
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext({ ...options, persistence: options?.persistence });
485
+ async runStreamLoop(list, writer, pendingResume) {
486
+ const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
468
487
  const writeChunk = async (chunk) => {
469
488
  await writer.write(chunk);
470
489
  };
@@ -472,9 +491,9 @@ class AgentRuntime {
472
491
  let lastFinishReason = 'stop';
473
492
  let structuredOutput;
474
493
  const collectedSubAgentUsage = [];
475
- const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
494
+ const maxIterations = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
476
495
  const closeStreamWithError = async (error, status) => {
477
- await this.cleanupRun(runId);
496
+ await this.cleanupRun();
478
497
  this.updateState({ status });
479
498
  await writer.write({ type: 'error', error });
480
499
  await writer.write({ type: 'finish', finishReason: 'error' });
@@ -486,7 +505,7 @@ class AgentRuntime {
486
505
  await closeStreamWithError(new Error('Agent run was aborted'), 'cancelled');
487
506
  return true;
488
507
  };
489
- const runTelemetry = this.resolveTelemetry(options);
508
+ const runTelemetry = this.resolveTelemetry();
490
509
  if (pendingResume) {
491
510
  try {
492
511
  const batch = await this.iteratePendingToolCallsConcurrent(pendingResume, toolMap, list, runTelemetry);
@@ -508,7 +527,7 @@ class AgentRuntime {
508
527
  });
509
528
  }
510
529
  if (Object.keys(batch.pending).length > 0) {
511
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
530
+ const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
512
531
  for (const s of batch.suspensions) {
513
532
  await writer.write({
514
533
  type: 'tool-call-suspended',
@@ -526,7 +545,7 @@ class AgentRuntime {
526
545
  }
527
546
  }
528
547
  catch (error) {
529
- this.eventBus.emit({ type: "error", message: String(error), error });
548
+ this.emitEvent({ type: "error", message: String(error), error });
530
549
  await closeStreamWithError(error, 'failed');
531
550
  return;
532
551
  }
@@ -534,7 +553,7 @@ class AgentRuntime {
534
553
  for (let i = 0; i < maxIterations; i++) {
535
554
  if (await handleAbort())
536
555
  return;
537
- this.eventBus.emit({ type: "turn_start" });
556
+ this.emitEvent({ type: "turn_start" });
538
557
  const result = (0, ai_1.streamText)({
539
558
  model,
540
559
  messages: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
@@ -544,7 +563,7 @@ class AgentRuntime {
544
563
  ? { providerOptions: providerOptions }
545
564
  : {}),
546
565
  ...(outputSpec ? { output: outputSpec } : {}),
547
- ...this.buildTelemetryOptions(options),
566
+ ...this.buildTelemetryOptions(),
548
567
  });
549
568
  try {
550
569
  for await (const chunk of result.fullStream) {
@@ -558,7 +577,7 @@ class AgentRuntime {
558
577
  catch (streamError) {
559
578
  if (await handleAbort())
560
579
  return;
561
- this.eventBus.emit({
580
+ this.emitEvent({
562
581
  type: "error",
563
582
  message: String(streamError),
564
583
  error: streamError,
@@ -606,7 +625,7 @@ class AgentRuntime {
606
625
  });
607
626
  }
608
627
  if (Object.keys(batch.pending).length > 0) {
609
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
628
+ const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
610
629
  for (const s of batch.suspensions) {
611
630
  await writer.write({
612
631
  type: 'tool-call-suspended',
@@ -624,7 +643,7 @@ class AgentRuntime {
624
643
  }
625
644
  }
626
645
  catch (error) {
627
- this.eventBus.emit({ type: "error", message: String(error), error });
646
+ this.emitEvent({ type: "error", message: String(error), error });
628
647
  await closeStreamWithError(error, 'failed');
629
648
  return;
630
649
  }
@@ -645,35 +664,37 @@ class AgentRuntime {
645
664
  }),
646
665
  });
647
666
  try {
648
- await this.saveToMemory(list, options);
649
- if (this.config.titleGeneration && options?.persistence && this.config.memory) {
667
+ await this.saveToMemory(list);
668
+ const persistence = this.currentState.persistence;
669
+ if (this.config.titleGeneration && persistence && this.config.memory) {
650
670
  void (0, title_generation_1.generateThreadTitle)({
651
671
  memory: this.config.memory,
652
- threadId: options.persistence.threadId,
653
- resourceId: options.persistence.resourceId,
672
+ threadId: persistence.threadId,
673
+ resourceId: persistence.resourceId,
654
674
  titleConfig: this.config.titleGeneration,
655
675
  agentModel: this.config.model,
656
676
  turnDelta: list.turnDelta(),
657
677
  });
658
678
  }
659
- await this.cleanupRun(runId);
660
- await this.flushTelemetry(options);
679
+ await this.cleanupRun();
680
+ await this.flushTelemetry();
661
681
  this.updateState({ status: 'success', messageList: list.serialize() });
662
- this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
682
+ this.emitEvent({ type: "agent_end", messages: list.responseDelta() });
663
683
  }
664
684
  finally {
665
685
  await writer.close();
666
686
  }
667
687
  }
668
- async saveToMemory(list, options) {
669
- if (!this.config.memory || !options?.persistence)
688
+ async saveToMemory(list) {
689
+ const persistence = this.currentState.persistence;
690
+ if (!this.config.memory || !persistence)
670
691
  return;
671
692
  const delta = list.turnDelta();
672
693
  if (delta.length === 0)
673
694
  return;
674
- await (0, memory_store_1.saveMessagesToThread)(this.config.memory, options.persistence.threadId, options.persistence.resourceId, delta);
695
+ await (0, memory_store_1.saveMessagesToThread)(this.config.memory, persistence.threadId, persistence.resourceId, delta);
675
696
  if (this.config.semanticRecall?.embedder && this.config.memory.saveEmbeddings) {
676
- await this.saveEmbeddingsForMessages(options.persistence.threadId, options.persistence.resourceId, delta);
697
+ await this.saveEmbeddingsForMessages(persistence.threadId, persistence.resourceId, delta);
677
698
  }
678
699
  }
679
700
  async saveEmbeddingsForMessages(threadId, resourceId, messages) {
@@ -943,14 +964,14 @@ class AgentRuntime {
943
964
  }
944
965
  async processToolCall(toolCallId, toolName, toolInput, toolMap, list, resumeData, resolvedTelemetry) {
945
966
  const builtTool = toolMap.get(toolName);
946
- this.eventBus.emit({
967
+ this.emitEvent({
947
968
  type: "tool_execution_start",
948
969
  toolCallId,
949
970
  toolName,
950
971
  args: toolInput,
951
972
  });
952
973
  const makeToolError = (error) => {
953
- this.eventBus.emit({
974
+ this.emitEvent({
954
975
  type: "tool_execution_end",
955
976
  toolCallId,
956
977
  toolName,
@@ -970,7 +991,7 @@ class AgentRuntime {
970
991
  .flatMap((m) => m.content.filter((content) => content.type === 'tool-result'));
971
992
  const existingToolResult = existingToolResults.find((r) => r.toolCallId === toolCallId);
972
993
  if (existingToolResult) {
973
- this.eventBus.emit({
994
+ this.emitEvent({
974
995
  type: "tool_execution_end",
975
996
  toolCallId,
976
997
  toolName,
@@ -1024,7 +1045,7 @@ class AgentRuntime {
1024
1045
  actualResult = toolResult.output;
1025
1046
  extractedSubAgentUsage = toolResult.subAgentUsage;
1026
1047
  }
1027
- this.eventBus.emit({
1048
+ this.emitEvent({
1028
1049
  type: "tool_execution_end",
1029
1050
  toolCallId,
1030
1051
  toolName,
@@ -1053,8 +1074,8 @@ class AgentRuntime {
1053
1074
  message: toolResultMsg,
1054
1075
  };
1055
1076
  }
1056
- buildLoopContext(execOptions) {
1057
- const wmTool = this.buildWorkingMemoryToolForRun(execOptions?.persistence);
1077
+ buildLoopContext() {
1078
+ const wmTool = this.buildWorkingMemoryToolForRun(this.currentState.persistence);
1058
1079
  const allUserTools = wmTool
1059
1080
  ? [...(this.config.tools ?? []), wmTool]
1060
1081
  : (this.config.tools ?? []);
@@ -1065,7 +1086,7 @@ class AgentRuntime {
1065
1086
  model: (0, model_factory_1.createModel)(this.config.model),
1066
1087
  toolMap: (0, tool_adapter_1.buildToolMap)(allUserTools),
1067
1088
  aiTools: allTools,
1068
- providerOptions: this.buildCallProviderOptions(execOptions?.providerOptions),
1089
+ providerOptions: this.buildCallProviderOptions(this.executionOptions?.providerOptions),
1069
1090
  hasTools: Object.keys(allTools).length > 0,
1070
1091
  outputSpec: this.config.structuredOutput
1071
1092
  ? ai_1.Output.object({ schema: this.config.structuredOutput })
@@ -1082,30 +1103,31 @@ class AgentRuntime {
1082
1103
  persist: wmParams.persistFn,
1083
1104
  });
1084
1105
  }
1085
- async persistSuspension(pendingToolCalls, options, list, totalUsage, existingRunId) {
1086
- const runId = existingRunId ?? (0, run_state_1.generateRunId)();
1087
- const executionOptions = options?.maxIterations !== undefined ? { maxIterations: options.maxIterations } : undefined;
1106
+ async persistSuspension(pendingToolCalls, list, totalUsage) {
1107
+ const executionOptions = this.executionOptions?.maxIterations !== undefined
1108
+ ? { maxIterations: this.executionOptions.maxIterations }
1109
+ : undefined;
1088
1110
  const state = {
1089
- persistence: options?.persistence,
1111
+ persistence: this.currentState.persistence,
1090
1112
  status: 'suspended',
1091
1113
  messageList: list.serialize(),
1092
1114
  pendingToolCalls,
1093
1115
  usage: totalUsage,
1094
1116
  executionOptions,
1095
1117
  };
1096
- await this.runState.suspend(runId, state);
1118
+ await this.runState.suspend(this.runId, state);
1097
1119
  this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
1098
- return runId;
1120
+ return this.runId;
1099
1121
  }
1100
- async cleanupRun(runId) {
1101
- if (runId) {
1102
- await this.runState.complete(runId);
1122
+ async cleanupRun() {
1123
+ if (this.runId) {
1124
+ await this.runState.complete(this.runId);
1103
1125
  }
1104
1126
  }
1105
1127
  emitTurnEnd(newMessages, toolResults) {
1106
1128
  const assistantMsg = newMessages.find((m) => 'role' in m && m.role === 'assistant');
1107
1129
  if (assistantMsg) {
1108
- this.eventBus.emit({ type: "turn_end", message: assistantMsg, toolResults });
1130
+ this.emitEvent({ type: "turn_end", message: assistantMsg, toolResults });
1109
1131
  }
1110
1132
  }
1111
1133
  updateState(patch) {
@@ -1153,6 +1175,9 @@ class AgentRuntime {
1153
1175
  ...(wmParams.instruction !== undefined && { instruction: wmParams.instruction }),
1154
1176
  };
1155
1177
  }
1178
+ emitEvent(data) {
1179
+ this.eventBus.emit({ ...data, runId: this.runId });
1180
+ }
1156
1181
  resolveWorkingMemoryParams(options) {
1157
1182
  if (!options)
1158
1183
  return null;