@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.
- package/dist/build.tsbuildinfo +1 -1
- package/dist/runtime/agent-runtime.d.ts +7 -0
- package/dist/runtime/agent-runtime.js +135 -110
- package/dist/runtime/agent-runtime.js.map +1 -1
- package/dist/runtime/event-bus.d.ts +1 -0
- package/dist/runtime/event-bus.js +4 -0
- package/dist/runtime/event-bus.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/sdk/agent.d.ts +9 -6
- package/dist/sdk/agent.js +124 -29
- package/dist/sdk/agent.js.map +1 -1
- package/dist/types/runtime/event.d.ts +7 -1
- package/dist/types/runtime/event.js.map +1 -1
- package/dist/types/sdk/agent.d.ts +2 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
|
89
|
-
const rawResult = await this.runGenerateLoop(list
|
|
90
|
-
return this.finalizeGenerate(rawResult, list
|
|
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(
|
|
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.
|
|
101
|
+
this.emitEvent({ type: "error", message: String(error), error });
|
|
98
102
|
}
|
|
99
|
-
return {
|
|
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
|
-
|
|
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
|
|
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.
|
|
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 {
|
|
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
|
-
|
|
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: ${
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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,
|
|
173
|
+
const rawResult = await this.runGenerateLoop(list, pendingResume);
|
|
159
174
|
if (!rawResult.pendingSuspend) {
|
|
160
|
-
await this.cleanupRun(
|
|
175
|
+
await this.cleanupRun();
|
|
161
176
|
}
|
|
162
|
-
return this.finalizeGenerate(rawResult, list
|
|
177
|
+
return this.finalizeGenerate(rawResult, list);
|
|
163
178
|
}
|
|
164
179
|
return {
|
|
165
|
-
runId:
|
|
166
|
-
stream: this.startStreamLoop(list,
|
|
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.
|
|
189
|
+
this.emitEvent({ type: "error", message: String(error), error });
|
|
174
190
|
}
|
|
175
191
|
if (method === 'generate') {
|
|
176
192
|
return {
|
|
177
|
-
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:
|
|
200
|
+
return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
|
|
184
201
|
}
|
|
185
202
|
}
|
|
186
|
-
async buildMessageList(input
|
|
203
|
+
async buildMessageList(input) {
|
|
187
204
|
const list = new message_list_1.AgentMessageList();
|
|
188
|
-
|
|
189
|
-
|
|
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 &&
|
|
197
|
-
await this.performSemanticRecall(list, input,
|
|
214
|
+
if (this.config.semanticRecall && persistence?.threadId) {
|
|
215
|
+
await this.performSemanticRecall(list, input, persistence.threadId, persistence.resourceId);
|
|
198
216
|
}
|
|
199
|
-
await this.setListWorkingMemoryConfig(list,
|
|
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
|
|
282
|
-
this.eventBus.resetAbort(
|
|
283
|
-
this.updateState({
|
|
284
|
-
|
|
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
|
|
305
|
+
return await this.buildMessageList(normalizedInput);
|
|
291
306
|
}
|
|
292
|
-
finalizeGenerate(result, list
|
|
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.
|
|
299
|
-
return finalized;
|
|
313
|
+
this.emitEvent({ type: "agent_end", messages: finalized.messages });
|
|
314
|
+
return { ...finalized, getState: () => this.getState() };
|
|
300
315
|
}
|
|
301
|
-
resolveTelemetry(
|
|
316
|
+
resolveTelemetry() {
|
|
302
317
|
if (this.config.telemetry)
|
|
303
318
|
return this.config.telemetry;
|
|
304
|
-
const inherited =
|
|
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(
|
|
324
|
+
async flushTelemetry() {
|
|
310
325
|
try {
|
|
311
|
-
const resolved = this.resolveTelemetry(
|
|
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(
|
|
320
|
-
const t = this.resolveTelemetry(
|
|
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,
|
|
336
|
-
const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext(
|
|
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(
|
|
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,
|
|
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 =
|
|
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.
|
|
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(
|
|
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,
|
|
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
|
|
428
|
-
await this.flushTelemetry(
|
|
429
|
-
|
|
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:
|
|
433
|
-
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,
|
|
468
|
+
startStreamLoop(list, pendingResume) {
|
|
450
469
|
const { readable, writable } = new TransformStream();
|
|
451
470
|
const writer = writable.getWriter();
|
|
452
|
-
this.runStreamLoop(list,
|
|
453
|
-
await this.flushTelemetry(
|
|
454
|
-
await this.cleanupRun(
|
|
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,
|
|
467
|
-
const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext(
|
|
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 =
|
|
494
|
+
const maxIterations = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
|
|
476
495
|
const closeStreamWithError = async (error, status) => {
|
|
477
|
-
await this.cleanupRun(
|
|
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(
|
|
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,
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
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,
|
|
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.
|
|
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
|
|
649
|
-
|
|
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:
|
|
653
|
-
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(
|
|
660
|
-
await this.flushTelemetry(
|
|
679
|
+
await this.cleanupRun();
|
|
680
|
+
await this.flushTelemetry();
|
|
661
681
|
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
662
|
-
this.
|
|
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
|
|
669
|
-
|
|
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,
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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(
|
|
1057
|
-
const wmTool = this.buildWorkingMemoryToolForRun(
|
|
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(
|
|
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,
|
|
1086
|
-
const
|
|
1087
|
-
|
|
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:
|
|
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(
|
|
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.
|
|
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;
|