@agentionai/agents 1.6.0 → 1.7.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/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 +45 -15
- package/dist/agents/cancellation.d.ts +55 -0
- package/dist/agents/cancellation.js +72 -0
- package/dist/agents/errors/AgentError.d.ts +16 -0
- package/dist/agents/errors/AgentError.js +21 -1
- package/dist/agents/google/GeminiAgent.d.ts +3 -2
- package/dist/agents/google/GeminiAgent.js +27 -9
- package/dist/agents/mistral/MistralAgent.d.ts +3 -2
- package/dist/agents/mistral/MistralAgent.js +28 -11
- 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 +44 -15
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.d.ts +4 -3
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.js +46 -17
- package/dist/core.d.ts +1 -0
- package/dist/core.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/MCPClient.js +4 -2
- package/dist/tools/Tool.d.ts +13 -3
- package/dist/tools/Tool.js +18 -4
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ const mistralai_1 = require("@mistralai/mistralai");
|
|
|
6
6
|
const http_1 = require("@mistralai/mistralai/lib/http");
|
|
7
7
|
const BaseAgent_1 = require("../BaseAgent");
|
|
8
8
|
const AgentEvent_1 = require("../AgentEvent");
|
|
9
|
+
const cancellation_1 = require("../cancellation");
|
|
9
10
|
const AgentError_1 = require("../errors/AgentError");
|
|
10
11
|
const transformers_1 = require("../../history/transformers");
|
|
11
12
|
const components_1 = require("@mistralai/mistralai/models/components");
|
|
@@ -129,7 +130,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
129
130
|
async process(_input) {
|
|
130
131
|
return "";
|
|
131
132
|
}
|
|
132
|
-
async execute(input) {
|
|
133
|
+
async execute(input, options) {
|
|
133
134
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
134
135
|
// Reset token usage for this execution
|
|
135
136
|
this.resetTokenUsage();
|
|
@@ -169,11 +170,19 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
169
170
|
randomSeed: this.config.randomSeed,
|
|
170
171
|
safePrompt: this.config.safePrompt,
|
|
171
172
|
stop: this.config.stopSequences,
|
|
172
|
-
});
|
|
173
|
+
}, { signal: options?.signal });
|
|
173
174
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
174
|
-
return await this.handleResponse(response);
|
|
175
|
+
return await this.handleResponse(response, options);
|
|
175
176
|
}
|
|
176
177
|
catch (error) {
|
|
178
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
179
|
+
const abortError = this.abortError(error, options?.signal);
|
|
180
|
+
if (this.vizEventId) {
|
|
181
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
182
|
+
this.vizEventId = undefined;
|
|
183
|
+
}
|
|
184
|
+
throw abortError;
|
|
185
|
+
}
|
|
177
186
|
const err = error;
|
|
178
187
|
if (err.status) {
|
|
179
188
|
const apiError = new AgentError_1.ApiError(`Mistral API error: ${err.message || "Unknown error"}`, err.status, error);
|
|
@@ -200,7 +209,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
200
209
|
this.history.endExecution();
|
|
201
210
|
}
|
|
202
211
|
}
|
|
203
|
-
async handleResponse(response) {
|
|
212
|
+
async handleResponse(response, options) {
|
|
204
213
|
if (!response.choices || response.choices.length === 0) {
|
|
205
214
|
const error = new AgentError_1.ExecutionError("Empty response from Mistral API");
|
|
206
215
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
@@ -255,18 +264,26 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
255
264
|
}
|
|
256
265
|
else if (choice.finishReason === "tool_calls" || message.toolCalls) {
|
|
257
266
|
try {
|
|
267
|
+
// Stop before the assistant turn is written: nothing else would notice
|
|
268
|
+
// a cancellation until the next provider call, and bailing out here
|
|
269
|
+
// avoids both running the tools' side effects and leaving a tool call
|
|
270
|
+
// in history with no tool message to answer it.
|
|
271
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
258
272
|
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, message.toolCalls);
|
|
259
273
|
// Add assistant message with tool calls to history (normalized)
|
|
260
274
|
const assistantEntry = transformers_1.mistralTransformer.fromProviderMessage(message);
|
|
261
275
|
this.addToHistory(assistantEntry);
|
|
262
|
-
const toolResults = await this.handleToolCalls(message.toolCalls || []);
|
|
276
|
+
const toolResults = await this.handleToolCalls(message.toolCalls || [], options);
|
|
263
277
|
// Add tool results to history (normalized)
|
|
264
278
|
for (const result of toolResults) {
|
|
265
279
|
const resultEntry = transformers_1.mistralTransformer.toolResultEntry(result.toolCallId, result.name, result.content);
|
|
266
280
|
this.addToHistory(resultEntry);
|
|
267
281
|
}
|
|
268
|
-
// Rate limiting delay for Mistral
|
|
269
|
-
|
|
282
|
+
// Rate limiting delay for Mistral. Aborting during the wait rejects
|
|
283
|
+
// immediately rather than sitting out the full delay first.
|
|
284
|
+
await (0, promises_1.setTimeout)(this.config.rateLimitDelay || 1500, undefined, {
|
|
285
|
+
signal: options?.signal,
|
|
286
|
+
});
|
|
270
287
|
// Continue conversation
|
|
271
288
|
try {
|
|
272
289
|
const messages = transformers_1.mistralTransformer.toProvider(this.history.getEntries());
|
|
@@ -281,9 +298,9 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
281
298
|
randomSeed: this.config.randomSeed,
|
|
282
299
|
safePrompt: this.config.safePrompt,
|
|
283
300
|
stop: this.config.stopSequences,
|
|
284
|
-
});
|
|
301
|
+
}, { signal: options?.signal });
|
|
285
302
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
286
|
-
return this.handleResponse(newResponse);
|
|
303
|
+
return this.handleResponse(newResponse, options);
|
|
287
304
|
}
|
|
288
305
|
catch (error) {
|
|
289
306
|
const err = error;
|
|
@@ -316,7 +333,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
316
333
|
}
|
|
317
334
|
throw error;
|
|
318
335
|
}
|
|
319
|
-
async handleToolCalls(toolCalls) {
|
|
336
|
+
async handleToolCalls(toolCalls, options) {
|
|
320
337
|
if (!toolCalls.length) {
|
|
321
338
|
throw new AgentError_1.ExecutionError("No tool calls found in response");
|
|
322
339
|
}
|
|
@@ -346,7 +363,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
346
363
|
else {
|
|
347
364
|
args = toolCall.function.arguments;
|
|
348
365
|
}
|
|
349
|
-
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, "mistral");
|
|
366
|
+
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, "mistral", { signal: options?.signal });
|
|
350
367
|
return {
|
|
351
368
|
name: toolName,
|
|
352
369
|
toolCallId,
|
|
@@ -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 { OllamaModel } from "../model-types";
|
|
4
5
|
type AgentConfig = BaseAgentConfig & {
|
|
@@ -50,9 +51,22 @@ export declare class OllamaAgent extends BaseAgent {
|
|
|
50
51
|
private vizEventId?;
|
|
51
52
|
/** Count of tool calls in current execution */
|
|
52
53
|
private currentToolCallCount;
|
|
53
|
-
/** Cached Ollama client instance */
|
|
54
|
+
/** Cached signal-less Ollama client instance */
|
|
54
55
|
private _client;
|
|
56
|
+
/** Cached constructor from the optional `ollama` peer dependency */
|
|
57
|
+
private _clientClass;
|
|
55
58
|
constructor(config: Omit<AgentConfig, "vendor">, history?: History);
|
|
59
|
+
private loadClientClass;
|
|
60
|
+
/**
|
|
61
|
+
* Get an Ollama client.
|
|
62
|
+
*
|
|
63
|
+
* The `ollama` package takes no per-request options — its own `abort()`
|
|
64
|
+
* cancels every streamed request on the client at once, which is too blunt
|
|
65
|
+
* for a per-run signal. A client does accept a `fetch` implementation
|
|
66
|
+
* though, so a run with a signal gets its own client whose `fetch` attaches
|
|
67
|
+
* that signal to each request. Clients are cheap (they open no connection),
|
|
68
|
+
* and the signal-less one is still cached and shared.
|
|
69
|
+
*/
|
|
56
70
|
private getClient;
|
|
57
71
|
/**
|
|
58
72
|
* List the models currently available on the Ollama server.
|
|
@@ -64,10 +78,10 @@ export declare class OllamaAgent extends BaseAgent {
|
|
|
64
78
|
listModels(): Promise<ModelInfo<OllamaModelInfo>[]>;
|
|
65
79
|
protected getToolDefinitions(): OllamaToolDefinition[];
|
|
66
80
|
protected process(_input: string): Promise<string>;
|
|
67
|
-
execute(input: string | MessageContent[]): Promise<string>;
|
|
81
|
+
execute(input: string | MessageContent[], options?: ExecuteOptions): Promise<string>;
|
|
68
82
|
private buildOptions;
|
|
69
83
|
private callOllama;
|
|
70
|
-
protected handleResponse(response: unknown): Promise<string>;
|
|
84
|
+
protected handleResponse(response: unknown, options?: ExecuteOptions): Promise<string>;
|
|
71
85
|
private handleToolCalls;
|
|
72
86
|
protected parseUsage(input: unknown): TokenUsage;
|
|
73
87
|
}
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.OllamaAgent = void 0;
|
|
37
37
|
const BaseAgent_1 = require("../BaseAgent");
|
|
38
38
|
const AgentEvent_1 = require("../AgentEvent");
|
|
39
|
+
const cancellation_1 = require("../cancellation");
|
|
39
40
|
const AgentError_1 = require("../errors/AgentError");
|
|
40
41
|
const transformers_1 = require("../../history/transformers");
|
|
41
42
|
const VizReporter_1 = require("../../viz/VizReporter");
|
|
@@ -73,8 +74,10 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
73
74
|
super({ ...config, vendor: "ollama" }, history);
|
|
74
75
|
/** Count of tool calls in current execution */
|
|
75
76
|
this.currentToolCallCount = 0;
|
|
76
|
-
/** Cached Ollama client instance */
|
|
77
|
+
/** Cached signal-less Ollama client instance */
|
|
77
78
|
this._client = null;
|
|
79
|
+
/** Cached constructor from the optional `ollama` peer dependency */
|
|
80
|
+
this._clientClass = null;
|
|
78
81
|
const vendorConfig = config.vendorConfig?.ollama || {};
|
|
79
82
|
const host = config.host ?? vendorConfig.host;
|
|
80
83
|
this.config = {
|
|
@@ -91,8 +94,8 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
91
94
|
};
|
|
92
95
|
this.addSystemMessage(this.getSystemMessage());
|
|
93
96
|
}
|
|
94
|
-
async
|
|
95
|
-
if (!this.
|
|
97
|
+
async loadClientClass() {
|
|
98
|
+
if (!this._clientClass) {
|
|
96
99
|
const pkg = "ollama";
|
|
97
100
|
try {
|
|
98
101
|
const mod = (await Promise.resolve(`${pkg}`).then(s => __importStar(require(s))));
|
|
@@ -100,15 +103,39 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
100
103
|
if (!OllamaClass) {
|
|
101
104
|
throw new Error("Could not find Ollama class in ollama package");
|
|
102
105
|
}
|
|
103
|
-
this.
|
|
104
|
-
host: this.config.host,
|
|
105
|
-
headers: this.config.defaultHeaders,
|
|
106
|
-
});
|
|
106
|
+
this._clientClass = OllamaClass;
|
|
107
107
|
}
|
|
108
108
|
catch (err) {
|
|
109
109
|
throw new AgentError_1.ExecutionError(`Failed to load 'ollama' package. Install it with: npm install ollama\n${err instanceof Error ? err.message : String(err)}`);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
return this._clientClass;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get an Ollama client.
|
|
116
|
+
*
|
|
117
|
+
* The `ollama` package takes no per-request options — its own `abort()`
|
|
118
|
+
* cancels every streamed request on the client at once, which is too blunt
|
|
119
|
+
* for a per-run signal. A client does accept a `fetch` implementation
|
|
120
|
+
* though, so a run with a signal gets its own client whose `fetch` attaches
|
|
121
|
+
* that signal to each request. Clients are cheap (they open no connection),
|
|
122
|
+
* and the signal-less one is still cached and shared.
|
|
123
|
+
*/
|
|
124
|
+
async getClient(signal) {
|
|
125
|
+
if (!signal && this._client)
|
|
126
|
+
return this._client;
|
|
127
|
+
const OllamaClass = await this.loadClientClass();
|
|
128
|
+
if (signal) {
|
|
129
|
+
return new OllamaClass({
|
|
130
|
+
host: this.config.host,
|
|
131
|
+
headers: this.config.defaultHeaders,
|
|
132
|
+
fetch: fetchWithSignal(signal),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
this._client ?? (this._client = new OllamaClass({
|
|
136
|
+
host: this.config.host,
|
|
137
|
+
headers: this.config.defaultHeaders,
|
|
138
|
+
}));
|
|
112
139
|
return this._client;
|
|
113
140
|
}
|
|
114
141
|
/**
|
|
@@ -146,7 +173,7 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
146
173
|
async process(_input) {
|
|
147
174
|
return "";
|
|
148
175
|
}
|
|
149
|
-
async execute(input) {
|
|
176
|
+
async execute(input, options) {
|
|
150
177
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
151
178
|
this.resetTokenUsage();
|
|
152
179
|
this.currentToolCallCount = 0;
|
|
@@ -167,12 +194,19 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
167
194
|
this.history.setSessionAnchor();
|
|
168
195
|
this.history.beginExecution();
|
|
169
196
|
try {
|
|
170
|
-
await this.
|
|
171
|
-
const response = await this.callOllama();
|
|
197
|
+
const response = await this.callOllama(options);
|
|
172
198
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
173
|
-
return await this.handleResponse(response);
|
|
199
|
+
return await this.handleResponse(response, options);
|
|
174
200
|
}
|
|
175
201
|
catch (error) {
|
|
202
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
203
|
+
const abortError = this.abortError(error, options?.signal);
|
|
204
|
+
if (this.vizEventId) {
|
|
205
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
206
|
+
this.vizEventId = undefined;
|
|
207
|
+
}
|
|
208
|
+
throw abortError;
|
|
209
|
+
}
|
|
176
210
|
if (error instanceof AgentError_1.ExecutionError || error instanceof AgentError_1.ApiError) {
|
|
177
211
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
178
212
|
if (this.vizEventId) {
|
|
@@ -211,8 +245,8 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
211
245
|
opts.think = this.config.think;
|
|
212
246
|
return opts;
|
|
213
247
|
}
|
|
214
|
-
async callOllama() {
|
|
215
|
-
const client = await this.getClient();
|
|
248
|
+
async callOllama(executeOptions) {
|
|
249
|
+
const client = await this.getClient(executeOptions?.signal);
|
|
216
250
|
const messages = transformers_1.ollamaTransformer.toProvider(this.history.getEntries());
|
|
217
251
|
const tools = this.tools.size > 0 ? this.getToolDefinitions() : undefined;
|
|
218
252
|
const options = this.buildOptions();
|
|
@@ -226,7 +260,7 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
226
260
|
options: Object.keys(options).length > 0 ? options : undefined,
|
|
227
261
|
});
|
|
228
262
|
}
|
|
229
|
-
async handleResponse(response) {
|
|
263
|
+
async handleResponse(response, options) {
|
|
230
264
|
const ollamaResponse = response;
|
|
231
265
|
const usage = this.accumulateUsage(this.parseUsage(ollamaResponse));
|
|
232
266
|
if (ollamaResponse.done_reason === "length") {
|
|
@@ -258,22 +292,27 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
258
292
|
}
|
|
259
293
|
// Tool calls detected
|
|
260
294
|
const toolCalls = message.tool_calls;
|
|
295
|
+
// Stop before the assistant turn is written: nothing else would notice a
|
|
296
|
+
// cancellation until the next provider call, and bailing out here avoids
|
|
297
|
+
// both running the tools' side effects and leaving a tool call in history
|
|
298
|
+
// with no tool message to answer it.
|
|
299
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
261
300
|
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
262
301
|
this.currentToolCallCount += toolCalls.length;
|
|
263
302
|
// Generate IDs — Ollama doesn't provide tool call IDs
|
|
264
303
|
const generatedIds = toolCalls.map((_, i) => `ollama_${Date.now()}_${i}`);
|
|
265
304
|
const assistantEntry = transformers_1.ollamaTransformer.fromProviderMessage(message, generatedIds);
|
|
266
305
|
this.addToHistory(assistantEntry);
|
|
267
|
-
const toolResults = await this.handleToolCalls(toolCalls, generatedIds);
|
|
306
|
+
const toolResults = await this.handleToolCalls(toolCalls, generatedIds, options);
|
|
268
307
|
for (const result of toolResults) {
|
|
269
308
|
const resultEntry = transformers_1.ollamaTransformer.toolResultEntry(result.toolCallId, result.content);
|
|
270
309
|
this.addToHistory(resultEntry);
|
|
271
310
|
}
|
|
272
311
|
// Continue conversation with tool results
|
|
273
312
|
try {
|
|
274
|
-
const newResponse = await this.callOllama();
|
|
313
|
+
const newResponse = await this.callOllama(options);
|
|
275
314
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
276
|
-
return this.handleResponse(newResponse);
|
|
315
|
+
return this.handleResponse(newResponse, options);
|
|
277
316
|
}
|
|
278
317
|
catch (error) {
|
|
279
318
|
const executionError = new AgentError_1.ExecutionError(`Ollama error during tool response: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -281,7 +320,7 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
281
320
|
throw executionError;
|
|
282
321
|
}
|
|
283
322
|
}
|
|
284
|
-
async handleToolCalls(toolCalls, generatedIds) {
|
|
323
|
+
async handleToolCalls(toolCalls, generatedIds, options) {
|
|
285
324
|
return Promise.all(toolCalls.map(async (toolCall, idx) => {
|
|
286
325
|
const toolName = toolCall.function.name;
|
|
287
326
|
const tool = this.tools.get(toolName);
|
|
@@ -296,7 +335,7 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
296
335
|
const args = typeof toolCall.function.arguments === "string"
|
|
297
336
|
? JSON.parse(toolCall.function.arguments)
|
|
298
337
|
: toolCall.function.arguments;
|
|
299
|
-
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, "ollama");
|
|
338
|
+
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, "ollama", { signal: options?.signal });
|
|
300
339
|
return { toolCallId, content: JSON.stringify(result) };
|
|
301
340
|
}
|
|
302
341
|
catch (error) {
|
|
@@ -329,4 +368,15 @@ class OllamaAgent extends BaseAgent_1.BaseAgent {
|
|
|
329
368
|
}
|
|
330
369
|
}
|
|
331
370
|
exports.OllamaAgent = OllamaAgent;
|
|
371
|
+
/**
|
|
372
|
+
* Wrap the global `fetch` so every request carries `signal`, keeping any
|
|
373
|
+
* signal the caller already set — the `ollama` package attaches its own to
|
|
374
|
+
* streamed requests so that its `abort()` keeps working.
|
|
375
|
+
*/
|
|
376
|
+
function fetchWithSignal(signal) {
|
|
377
|
+
return (input, init) => fetch(input, {
|
|
378
|
+
...init,
|
|
379
|
+
signal: (0, cancellation_1.combineSignals)(init?.signal ?? undefined, signal),
|
|
380
|
+
});
|
|
381
|
+
}
|
|
332
382
|
//# sourceMappingURL=OllamaAgent.js.map
|
|
@@ -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");
|
|
@@ -163,7 +164,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
163
164
|
async process(_input) {
|
|
164
165
|
return "";
|
|
165
166
|
}
|
|
166
|
-
async execute(input) {
|
|
167
|
+
async execute(input, options) {
|
|
167
168
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
168
169
|
// Reset token usage for this execution
|
|
169
170
|
this.resetTokenUsage();
|
|
@@ -204,11 +205,19 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
204
205
|
// Note: Responses API doesn't support seed, presence_penalty, frequency_penalty, stop
|
|
205
206
|
user: this.config.user,
|
|
206
207
|
...this.buildReasoningParams(),
|
|
207
|
-
});
|
|
208
|
+
}, { signal: options?.signal });
|
|
208
209
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
209
|
-
return await this.handleResponse(response);
|
|
210
|
+
return await this.handleResponse(response, options);
|
|
210
211
|
}
|
|
211
212
|
catch (error) {
|
|
213
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
214
|
+
const abortError = this.abortError(error, options?.signal);
|
|
215
|
+
if (this.vizEventId) {
|
|
216
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
217
|
+
this.vizEventId = undefined;
|
|
218
|
+
}
|
|
219
|
+
throw abortError;
|
|
220
|
+
}
|
|
212
221
|
if (error && typeof error === "object" && "error" in error) {
|
|
213
222
|
const openAIError = error;
|
|
214
223
|
const apiError = new AgentError_1.ApiError(`OpenAI API error: ${openAIError.error.message || "Unknown error"}`, openAIError.status, openAIError.error);
|
|
@@ -239,7 +248,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
239
248
|
this.history.endExecution();
|
|
240
249
|
}
|
|
241
250
|
}
|
|
242
|
-
async handleResponse(response) {
|
|
251
|
+
async handleResponse(response, options) {
|
|
243
252
|
if (!response.output || !response.output.length) {
|
|
244
253
|
const error = new AgentError_1.ExecutionError("Invalid response format: missing output");
|
|
245
254
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
@@ -288,6 +297,11 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
288
297
|
}
|
|
289
298
|
else if (toolCalls.length) {
|
|
290
299
|
try {
|
|
300
|
+
// Stop before the assistant turn is written: nothing else would notice
|
|
301
|
+
// a cancellation until the next provider call, and bailing out here
|
|
302
|
+
// avoids both running the tools' side effects and leaving a function
|
|
303
|
+
// call in history with no output to answer it.
|
|
304
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
291
305
|
// Add assistant message with tool calls to history (normalized)
|
|
292
306
|
const functionCalls = toolCalls.map((tc) => ({
|
|
293
307
|
id: tc.id || tc.call_id,
|
|
@@ -297,7 +311,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
297
311
|
}));
|
|
298
312
|
const assistantEntry = transformers_1.openAiTransformer.fromProviderMessage("assistant", response.output_text || "", functionCalls);
|
|
299
313
|
this.addToHistory(assistantEntry);
|
|
300
|
-
const toolResponses = await this.handleToolUse(toolCalls);
|
|
314
|
+
const toolResponses = await this.handleToolUse(toolCalls, options);
|
|
301
315
|
// Add tool results to history (normalized)
|
|
302
316
|
for (const result of toolResponses) {
|
|
303
317
|
const resultEntry = transformers_1.openAiTransformer.toolResultEntry(result.call_id, result.output, false);
|
|
@@ -318,9 +332,9 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
318
332
|
// Note: Responses API doesn't support seed, presence_penalty, frequency_penalty, stop
|
|
319
333
|
user: this.config.user,
|
|
320
334
|
...this.buildReasoningParams(),
|
|
321
|
-
});
|
|
335
|
+
}, { signal: options?.signal });
|
|
322
336
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
323
|
-
return this.handleResponse(newResponse);
|
|
337
|
+
return this.handleResponse(newResponse, options);
|
|
324
338
|
}
|
|
325
339
|
catch (error) {
|
|
326
340
|
if (error && typeof error === "object" && "error" in error) {
|
|
@@ -358,7 +372,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
358
372
|
throw error;
|
|
359
373
|
}
|
|
360
374
|
}
|
|
361
|
-
async handleToolUse(content) {
|
|
375
|
+
async handleToolUse(content, options) {
|
|
362
376
|
if (!content || !content.length) {
|
|
363
377
|
throw new AgentError_1.ExecutionError("Invalid tool calls content");
|
|
364
378
|
}
|
|
@@ -389,7 +403,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
389
403
|
catch (parseError) {
|
|
390
404
|
throw new AgentError_1.ToolExecutionError(`Invalid tool arguments: ${parseError instanceof Error ? parseError.message : "Parse error"}`, toolName, toolCall.arguments);
|
|
391
405
|
}
|
|
392
|
-
const result = await tool.execute(this.getId(), this.getName(), toolArgs, toolCall.id || "", this.config.model, "openai");
|
|
406
|
+
const result = await tool.execute(this.getId(), this.getName(), toolArgs, toolCall.id || "", this.config.model, "openai", { signal: options?.signal });
|
|
393
407
|
return {
|
|
394
408
|
call_id: toolCall.call_id,
|
|
395
409
|
output: JSON.stringify(result),
|
|
@@ -422,7 +436,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
422
436
|
* }
|
|
423
437
|
* ```
|
|
424
438
|
*/
|
|
425
|
-
async *executeStream(input) {
|
|
439
|
+
async *executeStream(input, options) {
|
|
426
440
|
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
427
441
|
this.resetTokenUsage();
|
|
428
442
|
this.currentToolCallCount = 0;
|
|
@@ -443,9 +457,17 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
443
457
|
this.history.setSessionAnchor();
|
|
444
458
|
this.history.beginExecution();
|
|
445
459
|
try {
|
|
446
|
-
yield* this.streamTurn();
|
|
460
|
+
yield* this.streamTurn(options);
|
|
447
461
|
}
|
|
448
462
|
catch (error) {
|
|
463
|
+
if ((0, cancellation_1.isAbortError)(error, options?.signal)) {
|
|
464
|
+
const abortError = this.abortError(error, options?.signal);
|
|
465
|
+
if (this.vizEventId) {
|
|
466
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "AbortError", abortError.message, false);
|
|
467
|
+
this.vizEventId = undefined;
|
|
468
|
+
}
|
|
469
|
+
throw abortError;
|
|
470
|
+
}
|
|
449
471
|
if (error instanceof AgentError_1.AgentError) {
|
|
450
472
|
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
451
473
|
if (this.vizEventId) {
|
|
@@ -476,7 +498,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
476
498
|
this.history.endExecution();
|
|
477
499
|
}
|
|
478
500
|
}
|
|
479
|
-
async *streamTurn() {
|
|
501
|
+
async *streamTurn(options) {
|
|
480
502
|
const inputMessages = transformers_1.openAiTransformer.toProvider(this.history.getEntries());
|
|
481
503
|
this.startTurnTimer();
|
|
482
504
|
const stream = await this.client.responses.create({
|
|
@@ -490,7 +512,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
490
512
|
top_p: this.config.topP,
|
|
491
513
|
user: this.config.user,
|
|
492
514
|
...this.buildReasoningParams("auto"),
|
|
493
|
-
});
|
|
515
|
+
}, { signal: options?.signal });
|
|
494
516
|
let completedEvent = null;
|
|
495
517
|
for await (const event of stream) {
|
|
496
518
|
if (event.type === "response.output_text.delta") {
|
|
@@ -513,12 +535,19 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
513
535
|
throw new AgentError_1.MaxTokensExceededError("Response incomplete: max tokens reached", this.config.maxTokens || 1024);
|
|
514
536
|
}
|
|
515
537
|
}
|
|
538
|
+
// The SDK's stream iterator swallows the abort and simply stops yielding.
|
|
539
|
+
// Without this the turn would fail as a malformed stream instead of a
|
|
540
|
+
// cancellation — checked here so the tokens already spent are reported.
|
|
541
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
516
542
|
if (!completedEvent) {
|
|
517
543
|
throw new AgentError_1.ExecutionError("OpenAI stream ended without a completed event");
|
|
518
544
|
}
|
|
519
545
|
const response = completedEvent.response;
|
|
520
546
|
const toolCalls = response.output.filter((o) => o.type === "function_call");
|
|
521
547
|
if (toolCalls.length > 0) {
|
|
548
|
+
// As in handleResponse(): bail out before the assistant turn is written,
|
|
549
|
+
// so a cancelled run leaves no unanswered function call in history.
|
|
550
|
+
(0, cancellation_1.throwIfAborted)(options?.signal, `Execution of agent ${this.getName()}`);
|
|
522
551
|
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
523
552
|
this.currentToolCallCount += toolCalls.length;
|
|
524
553
|
const functionCalls = toolCalls.map((tc) => ({
|
|
@@ -529,11 +558,11 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
529
558
|
}));
|
|
530
559
|
const assistantEntry = transformers_1.openAiTransformer.fromProviderMessage("assistant", response.output_text || "", functionCalls);
|
|
531
560
|
this.addToHistory(assistantEntry);
|
|
532
|
-
const toolResults = await this.handleToolUse(toolCalls);
|
|
561
|
+
const toolResults = await this.handleToolUse(toolCalls, options);
|
|
533
562
|
for (const result of toolResults) {
|
|
534
563
|
this.addToHistory(transformers_1.openAiTransformer.toolResultEntry(result.call_id, result.output, false));
|
|
535
564
|
}
|
|
536
|
-
yield* this.streamTurn();
|
|
565
|
+
yield* this.streamTurn(options);
|
|
537
566
|
}
|
|
538
567
|
else {
|
|
539
568
|
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;
|