@agentionai/agents 1.6.0 → 1.8.0-beta-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/README.md +4 -2
- package/dist/agents/Agent.d.ts +9 -2
- package/dist/agents/Agent.js +4 -0
- package/dist/agents/AgentConfig.d.ts +76 -2
- package/dist/agents/BaseAgent.d.ts +24 -2
- package/dist/agents/BaseAgent.js +17 -0
- package/dist/agents/anthropic/ClaudeAgent.d.ts +4 -3
- package/dist/agents/anthropic/ClaudeAgent.js +47 -17
- package/dist/agents/cancellation.d.ts +55 -0
- package/dist/agents/cancellation.js +72 -0
- package/dist/agents/errors/AgentError.d.ts +50 -2
- package/dist/agents/errors/AgentError.js +57 -1
- package/dist/agents/google/GeminiAgent.d.ts +3 -2
- package/dist/agents/google/GeminiAgent.js +34 -11
- package/dist/agents/mistral/MistralAgent.d.ts +3 -2
- package/dist/agents/mistral/MistralAgent.js +33 -13
- package/dist/agents/ollama/OllamaAgent.d.ts +17 -3
- package/dist/agents/ollama/OllamaAgent.js +69 -19
- package/dist/agents/openai/OpenAiAgent.d.ts +4 -3
- package/dist/agents/openai/OpenAiAgent.js +52 -17
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.d.ts +4 -3
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.js +48 -19
- package/dist/agents/openrouter/OpenRouterAgent.d.ts +234 -0
- package/dist/agents/openrouter/OpenRouterAgent.js +711 -0
- package/dist/agents/openrouter/types.d.ts +164 -0
- package/dist/agents/openrouter/types.js +15 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +1 -0
- package/dist/history/transformers.d.ts +80 -0
- package/dist/history/transformers.js +156 -1
- package/dist/history/types.d.ts +22 -2
- package/dist/history/types.js +13 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/mcp/MCPClient.js +4 -2
- package/dist/openrouter.d.ts +6 -0
- package/dist/openrouter.js +24 -0
- package/dist/tools/Tool.d.ts +13 -3
- package/dist/tools/Tool.js +18 -4
- package/dist/viz/types.d.ts +1 -1
- package/package.json +10 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseAgent, BaseAgentConfig, ModelInfo, TokenUsage } from "../BaseAgent";
|
|
2
|
+
import { ExecuteOptions } from "../cancellation";
|
|
2
3
|
import { History, MessageContent } from "../../history/History";
|
|
3
4
|
import { Tool, Response, ResponseUsage } from "openai/resources/responses/responses";
|
|
4
5
|
import type { Model as OpenAIModelCard } from "openai/resources/models";
|
|
@@ -95,8 +96,8 @@ export declare class OpenAiAgent<M extends OpenAIModel = OpenAIModel> extends Ba
|
|
|
95
96
|
*/
|
|
96
97
|
private buildReasoningParams;
|
|
97
98
|
protected process(_input: string): Promise<string>;
|
|
98
|
-
execute(input: string | MessageContent[]): Promise<string>;
|
|
99
|
-
protected handleResponse(response: Response): Promise<string>;
|
|
99
|
+
execute(input: string | MessageContent[], options?: ExecuteOptions): Promise<string>;
|
|
100
|
+
protected handleResponse(response: Response, options?: ExecuteOptions): Promise<string>;
|
|
100
101
|
private handleToolUse;
|
|
101
102
|
/**
|
|
102
103
|
* Stream a response as an async generator of `StreamChunk` objects.
|
|
@@ -110,7 +111,7 @@ export declare class OpenAiAgent<M extends OpenAIModel = OpenAIModel> extends Ba
|
|
|
110
111
|
* }
|
|
111
112
|
* ```
|
|
112
113
|
*/
|
|
113
|
-
executeStream(input: string | MessageContent[]): AsyncGenerator<StreamChunk>;
|
|
114
|
+
executeStream(input: string | MessageContent[], options?: ExecuteOptions): AsyncGenerator<StreamChunk>;
|
|
114
115
|
private streamTurn;
|
|
115
116
|
protected parseUsage(input: ResponseUsage): TokenUsage;
|
|
116
117
|
}
|
|
@@ -8,6 +8,7 @@ exports.lowestReasoningEffort = lowestReasoningEffort;
|
|
|
8
8
|
const openai_1 = __importDefault(require("openai"));
|
|
9
9
|
const BaseAgent_1 = require("../BaseAgent");
|
|
10
10
|
const AgentEvent_1 = require("../AgentEvent");
|
|
11
|
+
const cancellation_1 = require("../cancellation");
|
|
11
12
|
const AgentError_1 = require("../errors/AgentError");
|
|
12
13
|
const transformers_1 = require("../../history/transformers");
|
|
13
14
|
const VizReporter_1 = require("../../viz/VizReporter");
|
|
@@ -72,7 +73,13 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
72
73
|
const user = config.user ?? vendorConfig.user;
|
|
73
74
|
this.config = {
|
|
74
75
|
model: config.model || "gpt-4.1-mini",
|
|
75
|
-
|
|
76
|
+
// No default. `max_output_tokens` is optional on the Responses API, and
|
|
77
|
+
// omitting it lets the model use its full output budget. A default here
|
|
78
|
+
// silently truncated every response — and on reasoning models it was
|
|
79
|
+
// worse than a truncation, since reasoning tokens count against the same
|
|
80
|
+
// budget: a small cap could be spent entirely on thinking, returning
|
|
81
|
+
// `status: "incomplete"` with no text at all.
|
|
82
|
+
maxTokens: config.maxTokens,
|
|
76
83
|
disableParallelToolUse,
|
|
77
84
|
disableReasoning,
|
|
78
85
|
reasoningEffort,
|
|
@@ -163,7 +170,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
163
170
|
async process(_input) {
|
|
164
171
|
return "";
|
|
165
172
|
}
|
|
166
|
-
async execute(input) {
|
|
173
|
+
async execute(input, options) {
|
|
167
174
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
168
175
|
// Reset token usage for this execution
|
|
169
176
|
this.resetTokenUsage();
|
|
@@ -204,11 +211,19 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
204
211
|
// Note: Responses API doesn't support seed, presence_penalty, frequency_penalty, stop
|
|
205
212
|
user: this.config.user,
|
|
206
213
|
...this.buildReasoningParams(),
|
|
207
|
-
});
|
|
214
|
+
}, { signal: options?.signal });
|
|
208
215
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
209
|
-
return await this.handleResponse(response);
|
|
216
|
+
return await this.handleResponse(response, options);
|
|
210
217
|
}
|
|
211
218
|
catch (error) {
|
|
219
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
220
|
+
const abortError = this.abortError(error, options?.signal);
|
|
221
|
+
if (this.vizEventId) {
|
|
222
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
223
|
+
this.vizEventId = undefined;
|
|
224
|
+
}
|
|
225
|
+
throw abortError;
|
|
226
|
+
}
|
|
212
227
|
if (error && typeof error === "object" && "error" in error) {
|
|
213
228
|
const openAIError = error;
|
|
214
229
|
const apiError = new AgentError_1.ApiError(`OpenAI API error: ${openAIError.error.message || "Unknown error"}`, openAIError.status, openAIError.error);
|
|
@@ -239,7 +254,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
239
254
|
this.history.endExecution();
|
|
240
255
|
}
|
|
241
256
|
}
|
|
242
|
-
async handleResponse(response) {
|
|
257
|
+
async handleResponse(response, options) {
|
|
243
258
|
if (!response.output || !response.output.length) {
|
|
244
259
|
const error = new AgentError_1.ExecutionError("Invalid response format: missing output");
|
|
245
260
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
@@ -288,6 +303,11 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
288
303
|
}
|
|
289
304
|
else if (toolCalls.length) {
|
|
290
305
|
try {
|
|
306
|
+
// Stop before the assistant turn is written: nothing else would notice
|
|
307
|
+
// a cancellation until the next provider call, and bailing out here
|
|
308
|
+
// avoids both running the tools' side effects and leaving a function
|
|
309
|
+
// call in history with no output to answer it.
|
|
310
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
291
311
|
// Add assistant message with tool calls to history (normalized)
|
|
292
312
|
const functionCalls = toolCalls.map((tc) => ({
|
|
293
313
|
id: tc.id || tc.call_id,
|
|
@@ -297,7 +317,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
297
317
|
}));
|
|
298
318
|
const assistantEntry = transformers_1.openAiTransformer.fromProviderMessage("assistant", response.output_text || "", functionCalls);
|
|
299
319
|
this.addToHistory(assistantEntry);
|
|
300
|
-
const toolResponses = await this.handleToolUse(toolCalls);
|
|
320
|
+
const toolResponses = await this.handleToolUse(toolCalls, options);
|
|
301
321
|
// Add tool results to history (normalized)
|
|
302
322
|
for (const result of toolResponses) {
|
|
303
323
|
const resultEntry = transformers_1.openAiTransformer.toolResultEntry(result.call_id, result.output, false);
|
|
@@ -318,9 +338,9 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
318
338
|
// Note: Responses API doesn't support seed, presence_penalty, frequency_penalty, stop
|
|
319
339
|
user: this.config.user,
|
|
320
340
|
...this.buildReasoningParams(),
|
|
321
|
-
});
|
|
341
|
+
}, { signal: options?.signal });
|
|
322
342
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
323
|
-
return this.handleResponse(newResponse);
|
|
343
|
+
return this.handleResponse(newResponse, options);
|
|
324
344
|
}
|
|
325
345
|
catch (error) {
|
|
326
346
|
if (error && typeof error === "object" && "error" in error) {
|
|
@@ -358,7 +378,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
358
378
|
throw error;
|
|
359
379
|
}
|
|
360
380
|
}
|
|
361
|
-
async handleToolUse(content) {
|
|
381
|
+
async handleToolUse(content, options) {
|
|
362
382
|
if (!content || !content.length) {
|
|
363
383
|
throw new AgentError_1.ExecutionError("Invalid tool calls content");
|
|
364
384
|
}
|
|
@@ -389,7 +409,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
389
409
|
catch (parseError) {
|
|
390
410
|
throw new AgentError_1.ToolExecutionError(`Invalid tool arguments: ${parseError instanceof Error ? parseError.message : "Parse error"}`, toolName, toolCall.arguments);
|
|
391
411
|
}
|
|
392
|
-
const result = await tool.execute(this.getId(), this.getName(), toolArgs, toolCall.id || "", this.config.model, "openai");
|
|
412
|
+
const result = await tool.execute(this.getId(), this.getName(), toolArgs, toolCall.id || "", this.config.model, "openai", { signal: options?.signal });
|
|
393
413
|
return {
|
|
394
414
|
call_id: toolCall.call_id,
|
|
395
415
|
output: JSON.stringify(result),
|
|
@@ -422,7 +442,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
422
442
|
* }
|
|
423
443
|
* ```
|
|
424
444
|
*/
|
|
425
|
-
async *executeStream(input) {
|
|
445
|
+
async *executeStream(input, options) {
|
|
426
446
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
427
447
|
this.resetTokenUsage();
|
|
428
448
|
this.currentToolCallCount = 0;
|
|
@@ -443,9 +463,17 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
443
463
|
this.history.setSessionAnchor();
|
|
444
464
|
this.history.beginExecution();
|
|
445
465
|
try {
|
|
446
|
-
yield* this.streamTurn();
|
|
466
|
+
yield* this.streamTurn(options);
|
|
447
467
|
}
|
|
448
468
|
catch (error) {
|
|
469
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
470
|
+
const abortError = this.abortError(error, options?.signal);
|
|
471
|
+
if (this.vizEventId) {
|
|
472
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
473
|
+
this.vizEventId = undefined;
|
|
474
|
+
}
|
|
475
|
+
throw abortError;
|
|
476
|
+
}
|
|
449
477
|
if (error instanceof AgentError_1.AgentError) {
|
|
450
478
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
451
479
|
if (this.vizEventId) {
|
|
@@ -476,7 +504,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
476
504
|
this.history.endExecution();
|
|
477
505
|
}
|
|
478
506
|
}
|
|
479
|
-
async *streamTurn() {
|
|
507
|
+
async *streamTurn(options) {
|
|
480
508
|
const inputMessages = transformers_1.openAiTransformer.toProvider(this.history.getEntries());
|
|
481
509
|
this.startTurnTimer();
|
|
482
510
|
const stream = await this.client.responses.create({
|
|
@@ -490,7 +518,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
490
518
|
top_p: this.config.topP,
|
|
491
519
|
user: this.config.user,
|
|
492
520
|
...this.buildReasoningParams("auto"),
|
|
493
|
-
});
|
|
521
|
+
}, { signal: options?.signal });
|
|
494
522
|
let completedEvent = null;
|
|
495
523
|
for await (const event of stream) {
|
|
496
524
|
if (event.type === "response.output_text.delta") {
|
|
@@ -510,15 +538,22 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
510
538
|
}
|
|
511
539
|
}
|
|
512
540
|
if (event.type === "response.incomplete") {
|
|
513
|
-
throw new AgentError_1.MaxTokensExceededError("Response incomplete: max tokens reached", this.config.maxTokens
|
|
541
|
+
throw new AgentError_1.MaxTokensExceededError("Response incomplete: max tokens reached", this.config.maxTokens);
|
|
514
542
|
}
|
|
515
543
|
}
|
|
544
|
+
// The SDK's stream iterator swallows the abort and simply stops yielding.
|
|
545
|
+
// Without this the turn would fail as a malformed stream instead of a
|
|
546
|
+
// cancellation — checked here so the tokens already spent are reported.
|
|
547
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
516
548
|
if (!completedEvent) {
|
|
517
549
|
throw new AgentError_1.ExecutionError("OpenAI stream ended without a completed event");
|
|
518
550
|
}
|
|
519
551
|
const response = completedEvent.response;
|
|
520
552
|
const toolCalls = response.output.filter((o) => o.type === "function_call");
|
|
521
553
|
if (toolCalls.length > 0) {
|
|
554
|
+
// As in handleResponse(): bail out before the assistant turn is written,
|
|
555
|
+
// so a cancelled run leaves no unanswered function call in history.
|
|
556
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
522
557
|
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
523
558
|
this.currentToolCallCount += toolCalls.length;
|
|
524
559
|
const functionCalls = toolCalls.map((tc) => ({
|
|
@@ -529,11 +564,11 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
529
564
|
}));
|
|
530
565
|
const assistantEntry = transformers_1.openAiTransformer.fromProviderMessage("assistant", response.output_text || "", functionCalls);
|
|
531
566
|
this.addToHistory(assistantEntry);
|
|
532
|
-
const toolResults = await this.handleToolUse(toolCalls);
|
|
567
|
+
const toolResults = await this.handleToolUse(toolCalls, options);
|
|
533
568
|
for (const result of toolResults) {
|
|
534
569
|
this.addToHistory(transformers_1.openAiTransformer.toolResultEntry(result.call_id, result.output, false));
|
|
535
570
|
}
|
|
536
|
-
yield* this.streamTurn();
|
|
571
|
+
yield* this.streamTurn(options);
|
|
537
572
|
}
|
|
538
573
|
else {
|
|
539
574
|
const textContent = response.output_text || "";
|
|
@@ -3,6 +3,7 @@ import { ChatCompletion, ChatCompletionTool } from "openai/resources/chat/comple
|
|
|
3
3
|
import { Model } from "openai/resources/models";
|
|
4
4
|
import { BaseAgent, BaseAgentConfig, ModelInfo, TokenUsage } from "../BaseAgent";
|
|
5
5
|
import { AgentVendor } from "../AgentConfig";
|
|
6
|
+
import { ExecuteOptions } from "../cancellation";
|
|
6
7
|
import { History, MessageContent } from "../../history/History";
|
|
7
8
|
/**
|
|
8
9
|
* A single chunk yielded by `executeStream()`.
|
|
@@ -50,9 +51,9 @@ export declare abstract class OpenAICompatibleAgent extends BaseAgent {
|
|
|
50
51
|
listModels(): Promise<ModelInfo<Model>[]>;
|
|
51
52
|
protected getToolDefinitions(): ChatCompletionTool[];
|
|
52
53
|
protected process(_input: string): Promise<string>;
|
|
53
|
-
execute(input: string | MessageContent[]): Promise<string>;
|
|
54
|
+
execute(input: string | MessageContent[], options?: ExecuteOptions): Promise<string>;
|
|
54
55
|
private callProvider;
|
|
55
|
-
protected handleResponse(response: ChatCompletion): Promise<string>;
|
|
56
|
+
protected handleResponse(response: ChatCompletion, options?: ExecuteOptions): Promise<string>;
|
|
56
57
|
private handleToolCalls;
|
|
57
58
|
/**
|
|
58
59
|
* Stream a response as an async generator of `StreamChunk` objects.
|
|
@@ -69,7 +70,7 @@ export declare abstract class OpenAICompatibleAgent extends BaseAgent {
|
|
|
69
70
|
* }
|
|
70
71
|
* ```
|
|
71
72
|
*/
|
|
72
|
-
executeStream(input: string | MessageContent[]): AsyncGenerator<StreamChunk>;
|
|
73
|
+
executeStream(input: string | MessageContent[], options?: ExecuteOptions): AsyncGenerator<StreamChunk>;
|
|
73
74
|
private streamTurn;
|
|
74
75
|
private accumulateStreamUsage;
|
|
75
76
|
protected parseUsage(response: ChatCompletion): TokenUsage;
|
|
@@ -7,6 +7,7 @@ exports.OpenAICompatibleAgent = void 0;
|
|
|
7
7
|
const openai_1 = __importDefault(require("openai"));
|
|
8
8
|
const BaseAgent_1 = require("../BaseAgent");
|
|
9
9
|
const AgentEvent_1 = require("../AgentEvent");
|
|
10
|
+
const cancellation_1 = require("../cancellation");
|
|
10
11
|
const AgentError_1 = require("../errors/AgentError");
|
|
11
12
|
const transformers_1 = require("../../history/transformers");
|
|
12
13
|
const VizReporter_1 = require("../../viz/VizReporter");
|
|
@@ -84,7 +85,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
84
85
|
async process(_input) {
|
|
85
86
|
return "";
|
|
86
87
|
}
|
|
87
|
-
async execute(input) {
|
|
88
|
+
async execute(input, options) {
|
|
88
89
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
89
90
|
this.resetTokenUsage();
|
|
90
91
|
this.currentToolCallCount = 0;
|
|
@@ -105,11 +106,19 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
105
106
|
this.history.setSessionAnchor();
|
|
106
107
|
this.history.beginExecution();
|
|
107
108
|
try {
|
|
108
|
-
const response = await this.callProvider();
|
|
109
|
+
const response = await this.callProvider(options);
|
|
109
110
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
110
|
-
return await this.handleResponse(response);
|
|
111
|
+
return await this.handleResponse(response, options);
|
|
111
112
|
}
|
|
112
113
|
catch (error) {
|
|
114
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
115
|
+
const abortError = this.abortError(error, options?.signal);
|
|
116
|
+
if (this.vizEventId) {
|
|
117
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
118
|
+
this.vizEventId = undefined;
|
|
119
|
+
}
|
|
120
|
+
throw abortError;
|
|
121
|
+
}
|
|
113
122
|
if (error instanceof openai_1.default.APIError) {
|
|
114
123
|
const apiError = new AgentError_1.ApiError(`${this.getVendorName()} API error: ${error.message}`, error.status, error);
|
|
115
124
|
this.emit(AgentEvent_1.AgentEvent.ERROR, apiError);
|
|
@@ -139,7 +148,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
139
148
|
this.history.endExecution();
|
|
140
149
|
}
|
|
141
150
|
}
|
|
142
|
-
async callProvider() {
|
|
151
|
+
async callProvider(options) {
|
|
143
152
|
const messages = transformers_1.chatCompletionsTransformer.toProvider(this.history.getEntries());
|
|
144
153
|
const tools = this.tools.size > 0 ? this.getToolDefinitions() : undefined;
|
|
145
154
|
this.startTurnTimer();
|
|
@@ -156,14 +165,14 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
156
165
|
presence_penalty: this.config.presencePenalty,
|
|
157
166
|
frequency_penalty: this.config.frequencyPenalty,
|
|
158
167
|
...this.buildExtraRequestParams(),
|
|
159
|
-
});
|
|
168
|
+
}, { signal: options?.signal });
|
|
160
169
|
}
|
|
161
|
-
async handleResponse(response) {
|
|
170
|
+
async handleResponse(response, options) {
|
|
162
171
|
const usage = this.accumulateUsage(this.parseUsage(response));
|
|
163
172
|
const choice = response.choices[0];
|
|
164
173
|
const message = choice.message;
|
|
165
174
|
if (choice.finish_reason === "length") {
|
|
166
|
-
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens
|
|
175
|
+
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens);
|
|
167
176
|
this.emit(AgentEvent_1.AgentEvent.MAX_TOKENS_EXCEEDED, error);
|
|
168
177
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
169
178
|
if (this.vizEventId) {
|
|
@@ -189,19 +198,24 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
189
198
|
return textContent;
|
|
190
199
|
}
|
|
191
200
|
const toolCalls = message.tool_calls;
|
|
201
|
+
// Stop before the assistant turn is written: nothing else would notice a
|
|
202
|
+
// cancellation until the next provider call, and bailing out here avoids
|
|
203
|
+
// both running the tools' side effects and leaving a tool call in history
|
|
204
|
+
// with no tool message to answer it.
|
|
205
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
192
206
|
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
193
207
|
this.currentToolCallCount += toolCalls.length;
|
|
194
208
|
const assistantEntry = transformers_1.chatCompletionsTransformer.fromProviderMessage(message);
|
|
195
209
|
this.addToHistory(assistantEntry);
|
|
196
|
-
const toolResults = await this.handleToolCalls(toolCalls);
|
|
210
|
+
const toolResults = await this.handleToolCalls(toolCalls, options);
|
|
197
211
|
for (const result of toolResults) {
|
|
198
212
|
const resultEntry = transformers_1.chatCompletionsTransformer.toolResultEntry(result.toolCallId, result.content);
|
|
199
213
|
this.addToHistory(resultEntry);
|
|
200
214
|
}
|
|
201
215
|
try {
|
|
202
|
-
const newResponse = await this.callProvider();
|
|
216
|
+
const newResponse = await this.callProvider(options);
|
|
203
217
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
204
|
-
return this.handleResponse(newResponse);
|
|
218
|
+
return this.handleResponse(newResponse, options);
|
|
205
219
|
}
|
|
206
220
|
catch (error) {
|
|
207
221
|
const executionError = new AgentError_1.ExecutionError(`${this.getVendorName()} error during tool response: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -209,7 +223,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
209
223
|
throw executionError;
|
|
210
224
|
}
|
|
211
225
|
}
|
|
212
|
-
async handleToolCalls(toolCalls) {
|
|
226
|
+
async handleToolCalls(toolCalls, options) {
|
|
213
227
|
return Promise.all(toolCalls.map(async (toolCall) => {
|
|
214
228
|
const toolName = toolCall.type === "function" ? toolCall.function.name : "";
|
|
215
229
|
const tool = this.tools.get(toolName);
|
|
@@ -224,7 +238,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
224
238
|
}
|
|
225
239
|
try {
|
|
226
240
|
const args = JSON.parse(toolCall.function.arguments || "{}");
|
|
227
|
-
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, this.vendor);
|
|
241
|
+
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, this.vendor, { signal: options?.signal });
|
|
228
242
|
return { toolCallId, content: JSON.stringify(result) };
|
|
229
243
|
}
|
|
230
244
|
catch (error) {
|
|
@@ -253,7 +267,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
253
267
|
* }
|
|
254
268
|
* ```
|
|
255
269
|
*/
|
|
256
|
-
async *executeStream(input) {
|
|
270
|
+
async *executeStream(input, options) {
|
|
257
271
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
258
272
|
this.resetTokenUsage();
|
|
259
273
|
this.currentToolCallCount = 0;
|
|
@@ -274,9 +288,17 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
274
288
|
this.history.setSessionAnchor();
|
|
275
289
|
this.history.beginExecution();
|
|
276
290
|
try {
|
|
277
|
-
yield* this.streamTurn();
|
|
291
|
+
yield* this.streamTurn(options);
|
|
278
292
|
}
|
|
279
293
|
catch (error) {
|
|
294
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
295
|
+
const abortError = this.abortError(error, options?.signal);
|
|
296
|
+
if (this.vizEventId) {
|
|
297
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
298
|
+
this.vizEventId = undefined;
|
|
299
|
+
}
|
|
300
|
+
throw abortError;
|
|
301
|
+
}
|
|
280
302
|
if (error instanceof openai_1.default.APIError) {
|
|
281
303
|
const apiError = new AgentError_1.ApiError(`${this.getVendorName()} API error: ${error.message}`, error.status, error);
|
|
282
304
|
this.emit(AgentEvent_1.AgentEvent.ERROR, apiError);
|
|
@@ -306,7 +328,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
306
328
|
this.history.endExecution();
|
|
307
329
|
}
|
|
308
330
|
}
|
|
309
|
-
async *streamTurn() {
|
|
331
|
+
async *streamTurn(options) {
|
|
310
332
|
const messages = transformers_1.chatCompletionsTransformer.toProvider(this.history.getEntries());
|
|
311
333
|
const tools = this.tools.size > 0 ? this.getToolDefinitions() : undefined;
|
|
312
334
|
this.startTurnTimer();
|
|
@@ -324,7 +346,7 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
324
346
|
presence_penalty: this.config.presencePenalty,
|
|
325
347
|
frequency_penalty: this.config.frequencyPenalty,
|
|
326
348
|
...this.buildExtraRequestParams(),
|
|
327
|
-
});
|
|
349
|
+
}, { signal: options?.signal });
|
|
328
350
|
let textContent = "";
|
|
329
351
|
let reasoningContent = "";
|
|
330
352
|
const toolCallAcc = new Map();
|
|
@@ -383,8 +405,12 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
383
405
|
// continues into a tool call still reports what it spent.
|
|
384
406
|
if (streamUsage)
|
|
385
407
|
this.accumulateStreamUsage(streamUsage);
|
|
408
|
+
// The SDK's stream iterator swallows the abort and simply stops yielding,
|
|
409
|
+
// so without this an interrupted stream would look like a short but
|
|
410
|
+
// complete turn — writing partial text to history and emitting DONE.
|
|
411
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
386
412
|
if (finishReason === "length") {
|
|
387
|
-
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens
|
|
413
|
+
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens);
|
|
388
414
|
this.emit(AgentEvent_1.AgentEvent.MAX_TOKENS_EXCEEDED, error);
|
|
389
415
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
390
416
|
if (this.vizEventId) {
|
|
@@ -394,6 +420,9 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
394
420
|
throw error;
|
|
395
421
|
}
|
|
396
422
|
if (finishReason === "tool_calls" && toolCallAcc.size > 0) {
|
|
423
|
+
// As in handleResponse(): bail out before the assistant turn is written,
|
|
424
|
+
// so a cancelled run leaves no unanswered tool call in history.
|
|
425
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
397
426
|
const toolCalls = Array.from(toolCallAcc.entries())
|
|
398
427
|
.sort(([a], [b]) => a - b)
|
|
399
428
|
.map(([, tc]) => ({
|
|
@@ -410,11 +439,11 @@ class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
|
410
439
|
reasoning_content: reasoningContent || null,
|
|
411
440
|
});
|
|
412
441
|
this.addToHistory(assistantEntry);
|
|
413
|
-
const toolResults = await this.handleToolCalls(toolCalls);
|
|
442
|
+
const toolResults = await this.handleToolCalls(toolCalls, options);
|
|
414
443
|
for (const result of toolResults) {
|
|
415
444
|
this.addToHistory(transformers_1.chatCompletionsTransformer.toolResultEntry(result.toolCallId, result.content));
|
|
416
445
|
}
|
|
417
|
-
yield* this.streamTurn();
|
|
446
|
+
yield* this.streamTurn(options);
|
|
418
447
|
}
|
|
419
448
|
else {
|
|
420
449
|
const assistantEntry = transformers_1.chatCompletionsTransformer.fromProviderMessage({
|