@agentionai/agents 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/AgentConfig.d.ts +19 -0
- package/dist/agents/BaseAgent.d.ts +39 -0
- package/dist/agents/BaseAgent.js +100 -1
- package/dist/agents/anthropic/ClaudeAgent.d.ts +0 -2
- package/dist/agents/anthropic/ClaudeAgent.js +8 -4
- package/dist/agents/google/GeminiAgent.d.ts +0 -2
- package/dist/agents/google/GeminiAgent.js +4 -4
- package/dist/agents/mistral/MistralAgent.d.ts +0 -2
- package/dist/agents/mistral/MistralAgent.js +4 -4
- package/dist/agents/openai/OpenAiAgent.d.ts +0 -2
- package/dist/agents/openai/OpenAiAgent.js +4 -4
- package/dist/embeddings/VoyageAIEmbeddings.js +1 -0
- package/dist/graph/planning/PlanExecutor.d.ts +12 -0
- package/dist/graph/planning/PlanExecutor.js +74 -19
- package/dist/graph/planning/PlanStore.js +6 -2
- package/dist/history/History.js +3 -0
- package/package.json +1 -1
|
@@ -6,24 +6,43 @@ export type AgentVendor = "openai" | "anthropic" | "mistral" | "gemini";
|
|
|
6
6
|
* Common configuration shared by all agents
|
|
7
7
|
*/
|
|
8
8
|
export interface CommonAgentConfig {
|
|
9
|
+
/** Unique identifier for the agent instance */
|
|
9
10
|
id: string;
|
|
11
|
+
/** Human-readable name for the agent */
|
|
10
12
|
name: string;
|
|
13
|
+
/** Description of the agent's purpose and capabilities */
|
|
11
14
|
description: string;
|
|
15
|
+
/** API key for authenticating with the LLM provider */
|
|
12
16
|
apiKey: string;
|
|
17
|
+
/** Enable debug logging for troubleshooting (default: false) */
|
|
13
18
|
debug?: boolean;
|
|
19
|
+
/** Maximum number of messages to retain in conversation history */
|
|
14
20
|
maxHistoryLength?: number;
|
|
21
|
+
/** Model identifier (e.g., "claude-3-5-sonnet-20241022", "gpt-4") */
|
|
15
22
|
model?: string;
|
|
23
|
+
/** Array of tools the agent can use during execution */
|
|
16
24
|
tools?: Tool<unknown>[];
|
|
25
|
+
/** Array of sub-agents this agent can delegate tasks to */
|
|
17
26
|
agents?: BaseAgent[];
|
|
27
|
+
/** Maximum number of tokens to generate in the response */
|
|
18
28
|
maxTokens?: number;
|
|
29
|
+
/** Sampling temperature (0.0-1.0). Higher values increase randomness */
|
|
19
30
|
temperature?: number;
|
|
31
|
+
/** Nucleus sampling threshold (0.0-1.0). Considers tokens with top cumulative probability */
|
|
20
32
|
topP?: number;
|
|
33
|
+
/** Top-K sampling. Only considers the K most likely tokens (Anthropic, Gemini) */
|
|
21
34
|
topK?: number;
|
|
35
|
+
/** Sequences that will stop generation when encountered */
|
|
22
36
|
stopSequences?: string[];
|
|
37
|
+
/** Request timeout in milliseconds */
|
|
23
38
|
timeout?: number;
|
|
39
|
+
/** Maximum number of retry attempts on API failures */
|
|
24
40
|
maxRetries?: number;
|
|
41
|
+
/** Random seed for deterministic outputs (when supported by vendor) */
|
|
25
42
|
seed?: number;
|
|
43
|
+
/** Penalty for using tokens that already appear in the text (-2.0 to 2.0) */
|
|
26
44
|
presencePenalty?: number;
|
|
45
|
+
/** Penalty based on token frequency in the text (-2.0 to 2.0) */
|
|
27
46
|
frequencyPenalty?: number;
|
|
28
47
|
}
|
|
29
48
|
/**
|
|
@@ -4,6 +4,11 @@ import { History, HistoryEntry, MessageRole, MessageContent } from "../history/H
|
|
|
4
4
|
import { AgentVendor, CommonAgentConfig, VendorSpecificConfig } from "./AgentConfig";
|
|
5
5
|
export type { HistoryEntry, MessageRole, MessageContent };
|
|
6
6
|
export type { AgentVendor };
|
|
7
|
+
/**
|
|
8
|
+
* Parses a `retry-after` header value (seconds as string) into milliseconds.
|
|
9
|
+
*/
|
|
10
|
+
declare function parseRetryAfterHeader(header: string | undefined): number | undefined;
|
|
11
|
+
export { parseRetryAfterHeader };
|
|
7
12
|
/**
|
|
8
13
|
* Agent config as used across all agents
|
|
9
14
|
* @deprecated Use CommonAgentConfig with vendorConfig instead
|
|
@@ -33,6 +38,16 @@ export declare abstract class BaseAgent<TInput = unknown, TOutput = unknown> ext
|
|
|
33
38
|
protected vendor: AgentVendor;
|
|
34
39
|
/** The model identifier for this agent */
|
|
35
40
|
protected model: string;
|
|
41
|
+
/** Token usage from the last execution (for metrics tracking) */
|
|
42
|
+
lastTokenUsage?: TokenUsage;
|
|
43
|
+
/** Maximum number of retry attempts (0 = disabled) */
|
|
44
|
+
protected maxRetries: number;
|
|
45
|
+
/** Initial backoff delay in ms */
|
|
46
|
+
private retryDelayMs;
|
|
47
|
+
/** Multiplier applied to delay after each attempt */
|
|
48
|
+
private retryBackoffFactor;
|
|
49
|
+
/** Maximum backoff delay cap in ms */
|
|
50
|
+
private retryMaxDelayMs;
|
|
36
51
|
/**
|
|
37
52
|
* An Agent is the primary LLM entity.
|
|
38
53
|
*
|
|
@@ -68,6 +83,30 @@ export declare abstract class BaseAgent<TInput = unknown, TOutput = unknown> ext
|
|
|
68
83
|
* Add a message with content blocks to history
|
|
69
84
|
*/
|
|
70
85
|
protected addMessageToHistory(role: MessageRole, content: MessageContent[]): void;
|
|
86
|
+
/**
|
|
87
|
+
* Enable retry with exponential backoff for this agent.
|
|
88
|
+
* @param options.maxRetries - Number of retry attempts (default: 3)
|
|
89
|
+
* @param options.initialDelay - Initial backoff delay in ms (default: 1000)
|
|
90
|
+
* @param options.backoffFactor - Multiplier per attempt (default: 2)
|
|
91
|
+
* @param options.maxDelay - Maximum delay cap in ms (default: 30000)
|
|
92
|
+
*/
|
|
93
|
+
withRetry(options?: {
|
|
94
|
+
maxRetries?: number;
|
|
95
|
+
initialDelay?: number;
|
|
96
|
+
backoffFactor?: number;
|
|
97
|
+
maxDelay?: number;
|
|
98
|
+
}): this;
|
|
99
|
+
/**
|
|
100
|
+
* Executes a function with retry and exponential backoff.
|
|
101
|
+
*
|
|
102
|
+
* Retries on 429 (rate limit) and 5xx (server error) responses.
|
|
103
|
+
* Never retries on MaxTokensExceededError or 4xx client errors.
|
|
104
|
+
* Throws MaxRetriesExceededError when all attempts are exhausted.
|
|
105
|
+
*
|
|
106
|
+
* @param fn - The async function to execute
|
|
107
|
+
* @param getRetryAfterMs - Optional extractor for retry-after header (returns ms to wait)
|
|
108
|
+
*/
|
|
109
|
+
protected executeWithRetry<T>(fn: () => Promise<T>, getRetryAfterMs?: (error: unknown) => number | undefined): Promise<T>;
|
|
71
110
|
addTools(tools: Tool<unknown>[]): void;
|
|
72
111
|
getId(): string;
|
|
73
112
|
getName(): string;
|
package/dist/agents/BaseAgent.js
CHANGED
|
@@ -4,9 +4,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.BaseAgent = void 0;
|
|
7
|
+
exports.parseRetryAfterHeader = parseRetryAfterHeader;
|
|
7
8
|
const events_1 = __importDefault(require("events"));
|
|
8
9
|
const Tool_1 = require("../tools/Tool");
|
|
9
10
|
const History_1 = require("../history/History");
|
|
11
|
+
const AgentEvent_1 = require("./AgentEvent");
|
|
12
|
+
const AgentError_1 = require("./errors/AgentError");
|
|
13
|
+
/**
|
|
14
|
+
* Extracts an HTTP status code from a raw SDK error of any vendor shape.
|
|
15
|
+
*/
|
|
16
|
+
function extractStatusCode(error) {
|
|
17
|
+
if (error instanceof AgentError_1.ApiError)
|
|
18
|
+
return error.statusCode;
|
|
19
|
+
const e = error;
|
|
20
|
+
return typeof e.status === "number" ? e.status : undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parses a `retry-after` header value (seconds as string) into milliseconds.
|
|
24
|
+
*/
|
|
25
|
+
function parseRetryAfterHeader(header) {
|
|
26
|
+
if (!header)
|
|
27
|
+
return undefined;
|
|
28
|
+
const seconds = parseFloat(header);
|
|
29
|
+
return isNaN(seconds) ? undefined : Math.ceil(seconds * 1000);
|
|
30
|
+
}
|
|
10
31
|
/**
|
|
11
32
|
* The base agent is what the other agents are inheriting from
|
|
12
33
|
* Handles the BaseConfig
|
|
@@ -24,7 +45,15 @@ class BaseAgent extends events_1.default {
|
|
|
24
45
|
constructor(config, history = new History_1.History([], { transient: true })) {
|
|
25
46
|
super();
|
|
26
47
|
this.history = history;
|
|
27
|
-
this.debug =
|
|
48
|
+
this.debug = false;
|
|
49
|
+
/** Maximum number of retry attempts (0 = disabled) */
|
|
50
|
+
this.maxRetries = 0;
|
|
51
|
+
/** Initial backoff delay in ms */
|
|
52
|
+
this.retryDelayMs = 1000;
|
|
53
|
+
/** Multiplier applied to delay after each attempt */
|
|
54
|
+
this.retryBackoffFactor = 2;
|
|
55
|
+
/** Maximum backoff delay cap in ms */
|
|
56
|
+
this.retryMaxDelayMs = 30000;
|
|
28
57
|
this.id = config.id;
|
|
29
58
|
this.debug = config.debug || false;
|
|
30
59
|
this.name = config.name;
|
|
@@ -41,6 +70,7 @@ class BaseAgent extends events_1.default {
|
|
|
41
70
|
}
|
|
42
71
|
this.tools = new Map((config.tools || []).map((tool) => [tool.name, tool]));
|
|
43
72
|
this.maxHistoryLength = config.maxHistoryLength || 100;
|
|
73
|
+
this.maxRetries = config.maxRetries ?? 0;
|
|
44
74
|
}
|
|
45
75
|
getToolDefinitions() {
|
|
46
76
|
return Array.from(this.tools.values()).map((tool) => tool.getPrompt());
|
|
@@ -81,6 +111,75 @@ class BaseAgent extends events_1.default {
|
|
|
81
111
|
addMessageToHistory(role, content) {
|
|
82
112
|
this.history.addMessage(role, content);
|
|
83
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Enable retry with exponential backoff for this agent.
|
|
116
|
+
* @param options.maxRetries - Number of retry attempts (default: 3)
|
|
117
|
+
* @param options.initialDelay - Initial backoff delay in ms (default: 1000)
|
|
118
|
+
* @param options.backoffFactor - Multiplier per attempt (default: 2)
|
|
119
|
+
* @param options.maxDelay - Maximum delay cap in ms (default: 30000)
|
|
120
|
+
*/
|
|
121
|
+
withRetry(options) {
|
|
122
|
+
this.maxRetries = options?.maxRetries ?? 3;
|
|
123
|
+
if (options?.initialDelay !== undefined)
|
|
124
|
+
this.retryDelayMs = options.initialDelay;
|
|
125
|
+
if (options?.backoffFactor !== undefined)
|
|
126
|
+
this.retryBackoffFactor = options.backoffFactor;
|
|
127
|
+
if (options?.maxDelay !== undefined)
|
|
128
|
+
this.retryMaxDelayMs = options.maxDelay;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Executes a function with retry and exponential backoff.
|
|
133
|
+
*
|
|
134
|
+
* Retries on 429 (rate limit) and 5xx (server error) responses.
|
|
135
|
+
* Never retries on MaxTokensExceededError or 4xx client errors.
|
|
136
|
+
* Throws MaxRetriesExceededError when all attempts are exhausted.
|
|
137
|
+
*
|
|
138
|
+
* @param fn - The async function to execute
|
|
139
|
+
* @param getRetryAfterMs - Optional extractor for retry-after header (returns ms to wait)
|
|
140
|
+
*/
|
|
141
|
+
async executeWithRetry(fn, getRetryAfterMs) {
|
|
142
|
+
let attempt = 0;
|
|
143
|
+
let delayMs = this.retryDelayMs;
|
|
144
|
+
while (true) {
|
|
145
|
+
try {
|
|
146
|
+
return await fn();
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
// MaxTokensExceededError is never retryable
|
|
150
|
+
if (error instanceof AgentError_1.MaxTokensExceededError)
|
|
151
|
+
throw error;
|
|
152
|
+
const statusCode = extractStatusCode(error);
|
|
153
|
+
const isRetryable = statusCode === 429 ||
|
|
154
|
+
(statusCode !== undefined && statusCode >= 500);
|
|
155
|
+
if (!isRetryable || attempt >= this.maxRetries) {
|
|
156
|
+
if (attempt > 0) {
|
|
157
|
+
this.emit(AgentEvent_1.AgentEvent.MAX_RETRIES_EXCEEDED, {
|
|
158
|
+
maxRetries: this.maxRetries,
|
|
159
|
+
error,
|
|
160
|
+
});
|
|
161
|
+
throw new AgentError_1.MaxRetriesExceededError(`Max retries (${this.maxRetries}) exceeded`, this.maxRetries);
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
attempt++;
|
|
166
|
+
// Respect retry-after header if the SDK provides it
|
|
167
|
+
const retryAfter = getRetryAfterMs?.(error);
|
|
168
|
+
// Add ±10% jitter to avoid thundering herd
|
|
169
|
+
const jitter = delayMs * 0.1 * (Math.random() * 2 - 1);
|
|
170
|
+
const waitMs = Math.min(retryAfter ?? delayMs + jitter, this.retryMaxDelayMs);
|
|
171
|
+
this.emit(AgentEvent_1.AgentEvent.RETRY, {
|
|
172
|
+
attempt,
|
|
173
|
+
maxRetries: this.maxRetries,
|
|
174
|
+
delayMs: waitMs,
|
|
175
|
+
statusCode,
|
|
176
|
+
error,
|
|
177
|
+
});
|
|
178
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
179
|
+
delayMs = Math.min(delayMs * this.retryBackoffFactor, this.retryMaxDelayMs);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
84
183
|
addTools(tools) {
|
|
85
184
|
tools.forEach((tool) => {
|
|
86
185
|
if (!this.tools.has(tool.name)) {
|
|
@@ -28,8 +28,6 @@ type AgentConfig = BaseAgentConfig & {
|
|
|
28
28
|
export declare class ClaudeAgent extends BaseAgent {
|
|
29
29
|
private client;
|
|
30
30
|
protected config: Partial<AgentConfig>;
|
|
31
|
-
/** Token usage from the last execution (for metrics tracking) */
|
|
32
|
-
lastTokenUsage?: TokenUsage;
|
|
33
31
|
/** Current visualization event ID for tracking */
|
|
34
32
|
private vizEventId?;
|
|
35
33
|
/** Count of tool calls in current execution */
|
|
@@ -77,7 +77,7 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
77
77
|
try {
|
|
78
78
|
const messages = transformers_1.anthropicTransformer.toProvider(this.history.entries);
|
|
79
79
|
const systemMessage = this.history.getSystemMessage();
|
|
80
|
-
const response = await this.client.messages.create({
|
|
80
|
+
const response = await this.executeWithRetry(() => this.client.messages.create({
|
|
81
81
|
model: this.config.model,
|
|
82
82
|
system: systemMessage,
|
|
83
83
|
max_tokens: this.config.maxTokens,
|
|
@@ -88,7 +88,9 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
88
88
|
top_k: this.config.topK,
|
|
89
89
|
stop_sequences: this.config.stopSequences,
|
|
90
90
|
metadata: this.config.metadata,
|
|
91
|
-
})
|
|
91
|
+
}), (err) => err instanceof sdk_1.APIError
|
|
92
|
+
? (0, BaseAgent_1.parseRetryAfterHeader)(err.headers?.["retry-after"])
|
|
93
|
+
: undefined);
|
|
92
94
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
93
95
|
return await this.handleResponse(response);
|
|
94
96
|
}
|
|
@@ -178,7 +180,7 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
178
180
|
// Continue conversation with tool results
|
|
179
181
|
try {
|
|
180
182
|
const messages = transformers_1.anthropicTransformer.toProvider(this.history.entries);
|
|
181
|
-
const newResponse = await this.client.messages.create({
|
|
183
|
+
const newResponse = await this.executeWithRetry(() => this.client.messages.create({
|
|
182
184
|
model: this.config.model,
|
|
183
185
|
max_tokens: this.config.maxTokens,
|
|
184
186
|
messages,
|
|
@@ -188,7 +190,9 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
188
190
|
top_k: this.config.topK,
|
|
189
191
|
stop_sequences: this.config.stopSequences,
|
|
190
192
|
metadata: this.config.metadata,
|
|
191
|
-
})
|
|
193
|
+
}), (err) => err instanceof sdk_1.APIError
|
|
194
|
+
? (0, BaseAgent_1.parseRetryAfterHeader)(err.headers?.["retry-after"])
|
|
195
|
+
: undefined);
|
|
192
196
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
193
197
|
return this.handleResponse(newResponse);
|
|
194
198
|
}
|
|
@@ -29,8 +29,6 @@ export declare class GeminiAgent extends BaseAgent {
|
|
|
29
29
|
private client;
|
|
30
30
|
private generativeModel;
|
|
31
31
|
protected config: Partial<AgentConfig>;
|
|
32
|
-
/** Token usage from the last execution (for metrics tracking) */
|
|
33
|
-
lastTokenUsage?: TokenUsage;
|
|
34
32
|
/** Current visualization event ID for tracking */
|
|
35
33
|
private vizEventId?;
|
|
36
34
|
/** Count of tool calls in current execution */
|
|
@@ -179,7 +179,7 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
179
179
|
const contents = transformers_1.geminiTransformer.toProvider(this.history.entries);
|
|
180
180
|
const systemMessage = this.history.getSystemMessage();
|
|
181
181
|
const tools = this.getToolDefinitionsForGemini();
|
|
182
|
-
const response = await this.generativeModel.generateContent({
|
|
182
|
+
const response = await this.executeWithRetry(() => this.generativeModel.generateContent({
|
|
183
183
|
contents,
|
|
184
184
|
systemInstruction: systemMessage,
|
|
185
185
|
tools: tools ? [tools] : undefined,
|
|
@@ -193,7 +193,7 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
193
193
|
responseMimeType: this.config.responseMimeType,
|
|
194
194
|
responseSchema: this.config.responseSchema,
|
|
195
195
|
},
|
|
196
|
-
});
|
|
196
|
+
}));
|
|
197
197
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
198
198
|
return await this.handleResponse(response);
|
|
199
199
|
}
|
|
@@ -293,7 +293,7 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
293
293
|
const newContents = transformers_1.geminiTransformer.toProvider(this.history.entries);
|
|
294
294
|
const systemMessage = this.history.getSystemMessage();
|
|
295
295
|
const tools = this.getToolDefinitionsForGemini();
|
|
296
|
-
const newResponse = await this.generativeModel.generateContent({
|
|
296
|
+
const newResponse = await this.executeWithRetry(() => this.generativeModel.generateContent({
|
|
297
297
|
contents: newContents,
|
|
298
298
|
systemInstruction: systemMessage,
|
|
299
299
|
tools: tools ? [tools] : undefined,
|
|
@@ -307,7 +307,7 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
307
307
|
responseMimeType: this.config.responseMimeType,
|
|
308
308
|
responseSchema: this.config.responseSchema,
|
|
309
309
|
},
|
|
310
|
-
});
|
|
310
|
+
}));
|
|
311
311
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
312
312
|
return this.handleResponse(newResponse);
|
|
313
313
|
}
|
|
@@ -29,8 +29,6 @@ type AgentConfig = BaseAgentConfig & {
|
|
|
29
29
|
export declare class MistralAgent extends BaseAgent {
|
|
30
30
|
private client;
|
|
31
31
|
protected config: Partial<AgentConfig>;
|
|
32
|
-
/** Token usage from the last execution (for metrics tracking) */
|
|
33
|
-
lastTokenUsage?: TokenUsage;
|
|
34
32
|
/** Current visualization event ID for tracking */
|
|
35
33
|
private vizEventId?;
|
|
36
34
|
/** Count of tool calls in current execution */
|
|
@@ -87,7 +87,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
87
87
|
this.addTextToHistory("user", input);
|
|
88
88
|
try {
|
|
89
89
|
const messages = transformers_1.mistralTransformer.toProvider(this.history.entries);
|
|
90
|
-
const response = await this.client.chat.complete({
|
|
90
|
+
const response = await this.executeWithRetry(() => this.client.chat.complete({
|
|
91
91
|
model: this.config.model,
|
|
92
92
|
messages: messages,
|
|
93
93
|
tools: this.getToolDefinitions(),
|
|
@@ -97,7 +97,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
97
97
|
randomSeed: this.config.randomSeed,
|
|
98
98
|
safePrompt: this.config.safePrompt,
|
|
99
99
|
stop: this.config.stopSequences,
|
|
100
|
-
});
|
|
100
|
+
}));
|
|
101
101
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
102
102
|
return await this.handleResponse(response);
|
|
103
103
|
}
|
|
@@ -203,7 +203,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
203
203
|
// Continue conversation
|
|
204
204
|
try {
|
|
205
205
|
const messages = transformers_1.mistralTransformer.toProvider(this.history.entries);
|
|
206
|
-
const newResponse = await this.client.chat.complete({
|
|
206
|
+
const newResponse = await this.executeWithRetry(() => this.client.chat.complete({
|
|
207
207
|
model: this.config.model,
|
|
208
208
|
messages: messages,
|
|
209
209
|
tools: this.getToolDefinitions(),
|
|
@@ -213,7 +213,7 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
213
213
|
randomSeed: this.config.randomSeed,
|
|
214
214
|
safePrompt: this.config.safePrompt,
|
|
215
215
|
stop: this.config.stopSequences,
|
|
216
|
-
});
|
|
216
|
+
}));
|
|
217
217
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
218
218
|
return this.handleResponse(newResponse);
|
|
219
219
|
}
|
|
@@ -30,8 +30,6 @@ type AgentConfig = BaseAgentConfig & {
|
|
|
30
30
|
export declare class OpenAiAgent extends BaseAgent {
|
|
31
31
|
private client;
|
|
32
32
|
protected config: Partial<AgentConfig>;
|
|
33
|
-
/** Token usage from the last execution (for metrics tracking) */
|
|
34
|
-
lastTokenUsage?: TokenUsage;
|
|
35
33
|
/** Current visualization event ID for tracking */
|
|
36
34
|
private vizEventId?;
|
|
37
35
|
/** Count of tool calls in current execution */
|
|
@@ -98,7 +98,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
98
98
|
this.addTextToHistory("user", input);
|
|
99
99
|
try {
|
|
100
100
|
const inputMessages = transformers_1.openAiTransformer.toProvider(this.history.entries);
|
|
101
|
-
const response = await this.client.responses.create({
|
|
101
|
+
const response = await this.executeWithRetry(() => this.client.responses.create({
|
|
102
102
|
model: this.config.model,
|
|
103
103
|
max_output_tokens: this.config.maxTokens,
|
|
104
104
|
input: inputMessages,
|
|
@@ -110,7 +110,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
110
110
|
user: this.config.user,
|
|
111
111
|
...(this.config.disableReasoning && { reasoning: { effort: null } }),
|
|
112
112
|
reasoning: { effort: this.config.reasoningEffort },
|
|
113
|
-
});
|
|
113
|
+
}));
|
|
114
114
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
115
115
|
return await this.handleResponse(response);
|
|
116
116
|
}
|
|
@@ -217,7 +217,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
217
217
|
// Continue conversation
|
|
218
218
|
try {
|
|
219
219
|
const inputMessages = transformers_1.openAiTransformer.toProvider(this.history.entries);
|
|
220
|
-
const newResponse = await this.client.responses.create({
|
|
220
|
+
const newResponse = await this.executeWithRetry(() => this.client.responses.create({
|
|
221
221
|
model: this.config.model,
|
|
222
222
|
max_output_tokens: this.config.maxTokens,
|
|
223
223
|
input: inputMessages,
|
|
@@ -234,7 +234,7 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
234
234
|
!this.config.disableReasoning && {
|
|
235
235
|
reasoning: { effort: this.config.reasoningEffort },
|
|
236
236
|
}),
|
|
237
|
-
});
|
|
237
|
+
}));
|
|
238
238
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
239
239
|
return this.handleResponse(newResponse);
|
|
240
240
|
}
|
|
@@ -103,6 +103,7 @@ class VoyageAIEmbeddings extends Embeddings_1.Embeddings {
|
|
|
103
103
|
return [];
|
|
104
104
|
}
|
|
105
105
|
// Dynamic import to keep voyageai optional at module load time
|
|
106
|
+
// @ts-ignore - voyageai is an optional peer dependency
|
|
106
107
|
const { VoyageAIClient } = await Promise.resolve().then(() => __importStar(require("voyageai")));
|
|
107
108
|
const client = new VoyageAIClient({
|
|
108
109
|
apiKey: this.apiKey,
|
|
@@ -23,6 +23,14 @@ export interface PlanExecutorOptions {
|
|
|
23
23
|
* @default true
|
|
24
24
|
*/
|
|
25
25
|
stopOnFailure?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Maximum number of previous step results to include in worker context.
|
|
28
|
+
* This prevents context overflow by limiting how much history is passed to each step.
|
|
29
|
+
* Set to 0 to include no previous steps (workers should use context_get to retrieve data).
|
|
30
|
+
* Set to a small number (1-3) to include only recent context.
|
|
31
|
+
* @default 0 (workers request context explicitly)
|
|
32
|
+
*/
|
|
33
|
+
maxContextSteps?: number;
|
|
26
34
|
/**
|
|
27
35
|
* Callback invoked when planning phase completes.
|
|
28
36
|
*/
|
|
@@ -145,6 +153,10 @@ export declare class PlanExecutor extends BaseExecutor<string, string> {
|
|
|
145
153
|
private createPlanningPrompt;
|
|
146
154
|
/**
|
|
147
155
|
* Create input for a step execution.
|
|
156
|
+
*
|
|
157
|
+
* By default, only includes the current step information.
|
|
158
|
+
* Workers should use context_get to retrieve data from previous steps.
|
|
159
|
+
* This prevents token overflow from accumulating context.
|
|
148
160
|
*/
|
|
149
161
|
private createStepInput;
|
|
150
162
|
/**
|
|
@@ -57,6 +57,7 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
57
57
|
maxSteps: options.maxSteps ?? 50,
|
|
58
58
|
concurrency: options.concurrency ?? 1,
|
|
59
59
|
stopOnFailure: options.stopOnFailure ?? true,
|
|
60
|
+
maxContextSteps: options.maxContextSteps ?? 0, // Default: no auto context
|
|
60
61
|
onPlanCreated: options.onPlanCreated,
|
|
61
62
|
onStepStart: options.onStepStart,
|
|
62
63
|
onStepComplete: options.onStepComplete,
|
|
@@ -150,11 +151,16 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
150
151
|
const results = [];
|
|
151
152
|
let stepNumber = 0;
|
|
152
153
|
const activePromises = new Map();
|
|
154
|
+
let stopError;
|
|
153
155
|
while (stepNumber < this.options.maxSteps) {
|
|
154
156
|
// Wait if we've reached concurrency limit
|
|
155
157
|
if (activePromises.size >= this.options.concurrency) {
|
|
156
158
|
await Promise.race(activePromises.values());
|
|
157
159
|
}
|
|
160
|
+
// If a step failed and stopOnFailure is set, drain remaining promises then throw
|
|
161
|
+
if (stopError) {
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
158
164
|
const nextStep = this.planStore.getNextStep();
|
|
159
165
|
if (!nextStep) {
|
|
160
166
|
// No more pending steps
|
|
@@ -202,9 +208,9 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
202
208
|
});
|
|
203
209
|
// Notify step failure
|
|
204
210
|
this.options.onStepFailed?.(nextStep, error instanceof Error ? error : new Error(errorMessage), stepNumber);
|
|
205
|
-
//
|
|
211
|
+
// Record error to stop after in-flight steps complete
|
|
206
212
|
if (this.options.stopOnFailure) {
|
|
207
|
-
|
|
213
|
+
stopError = new Error(`Step ${stepNumber} failed: ${errorMessage}`);
|
|
208
214
|
}
|
|
209
215
|
}
|
|
210
216
|
finally {
|
|
@@ -220,9 +226,12 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
220
226
|
await promise;
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
|
-
//
|
|
229
|
+
// Always wait for all in-flight promises to finish before returning/throwing
|
|
224
230
|
if (activePromises.size > 0) {
|
|
225
|
-
await Promise.
|
|
231
|
+
await Promise.allSettled(activePromises.values());
|
|
232
|
+
}
|
|
233
|
+
if (stopError) {
|
|
234
|
+
throw stopError;
|
|
226
235
|
}
|
|
227
236
|
if (stepNumber >= this.options.maxSteps) {
|
|
228
237
|
const plan = this.planStore.getActivePlan();
|
|
@@ -241,34 +250,81 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
241
250
|
|
|
242
251
|
Task: ${task}
|
|
243
252
|
|
|
244
|
-
|
|
253
|
+
CRITICAL: You can create a maximum of ${this.options.maxSteps} steps. Plan accordingly and prioritize the most important subtasks.
|
|
254
|
+
|
|
255
|
+
CONTEXT LIMIT WARNING: Each step will be executed independently with limited context. To avoid rate limits and context overflow:
|
|
256
|
+
- Break work into VERY SMALL, ATOMIC steps
|
|
257
|
+
- Each step should process only 1-3 items at a time
|
|
258
|
+
- Never create steps that say "analyze all", "process everything", "read all files", etc.
|
|
259
|
+
- Instead, break into multiple steps: "Read file1", "Read file2", "Read file3"
|
|
260
|
+
|
|
261
|
+
Use the create_plan tool to create a plan with clear, actionable steps. Each step MUST be:
|
|
262
|
+
|
|
263
|
+
1. MICRO-SIZED - Can be completed in under 10 seconds with minimal tokens
|
|
264
|
+
2. SINGLE ACTION - Exactly ONE thing to do (read ONE file, list ONE directory, etc.)
|
|
265
|
+
3. SPECIFIC - Mention exact file names, directories, or items (not "all files")
|
|
266
|
+
4. NO BATCH OPERATIONS - Process items one-by-one, not in bulk
|
|
267
|
+
5. SEQUENTIAL - Let each step's output inform the next step
|
|
268
|
+
|
|
269
|
+
GOOD EXAMPLES (SMALL STEPS):
|
|
270
|
+
✓ "List files in the lib/graph directory"
|
|
271
|
+
✓ "Read the first 50 lines of PlanExecutor.ts"
|
|
272
|
+
✓ "Search for the definition of 'createPlan' function"
|
|
273
|
+
✓ "Summarize the purpose of SequentialExecutor class in 2 sentences"
|
|
274
|
+
|
|
275
|
+
BAD EXAMPLES (TOO LARGE):
|
|
276
|
+
✗ "Read and analyze all files in lib/graph" (reads too much, use multiple steps)
|
|
277
|
+
✗ "Analyze the entire codebase architecture" (too broad, break into 5+ steps)
|
|
278
|
+
✗ "Review all test files and identify issues" (batch operation, do one at a time)
|
|
279
|
+
✗ "Research best practices and implement them" (vague, multi-step)
|
|
245
280
|
|
|
246
|
-
|
|
247
|
-
-
|
|
248
|
-
-
|
|
249
|
-
-
|
|
281
|
+
STRATEGY FOR AVOIDING RATE LIMITS:
|
|
282
|
+
- If analyzing multiple files: Create one step per file
|
|
283
|
+
- If processing a list: Create one step per item
|
|
284
|
+
- If researching: Create steps for: 1) identify what to research, 2) research item 1, 3) research item 2, etc.
|
|
285
|
+
- If the task seems large: Create 2x as many steps as you initially think
|
|
286
|
+
|
|
287
|
+
Break down complex tasks into the SMALLEST possible steps. Having ${this.options.maxSteps} small steps is much better than having ${Math.floor(this.options.maxSteps / 2)} larger ones.
|
|
250
288
|
|
|
251
289
|
After creating the plan, respond with a brief confirmation.`;
|
|
252
290
|
}
|
|
253
291
|
/**
|
|
254
292
|
* Create input for a step execution.
|
|
293
|
+
*
|
|
294
|
+
* By default, only includes the current step information.
|
|
295
|
+
* Workers should use context_get to retrieve data from previous steps.
|
|
296
|
+
* This prevents token overflow from accumulating context.
|
|
255
297
|
*/
|
|
256
298
|
createStepInput(step, stepNumber) {
|
|
257
299
|
const plan = this.planStore.getActivePlan();
|
|
258
300
|
const completedSteps = plan?.steps.filter((s) => s.status === "completed") || [];
|
|
259
|
-
|
|
301
|
+
// Limit context to prevent token overflow
|
|
302
|
+
// Only include the most recent N steps based on maxContextSteps option
|
|
303
|
+
const recentSteps = this.options.maxContextSteps > 0
|
|
304
|
+
? completedSteps.slice(-this.options.maxContextSteps)
|
|
305
|
+
: [];
|
|
306
|
+
const input = {
|
|
260
307
|
stepNumber,
|
|
261
308
|
totalSteps: plan?.steps.length,
|
|
262
309
|
currentStep: {
|
|
263
310
|
id: step.id,
|
|
264
311
|
description: step.description,
|
|
265
312
|
},
|
|
266
|
-
|
|
313
|
+
planGoal: plan?.goal,
|
|
314
|
+
};
|
|
315
|
+
// Only add previous steps if maxContextSteps > 0
|
|
316
|
+
if (this.options.maxContextSteps > 0 && recentSteps.length > 0) {
|
|
317
|
+
input.previousSteps = recentSteps.map((s) => ({
|
|
267
318
|
description: s.description,
|
|
268
319
|
output: s.output,
|
|
269
|
-
}))
|
|
270
|
-
|
|
271
|
-
}
|
|
320
|
+
}));
|
|
321
|
+
input.contextNote = `Showing last ${recentSteps.length} of ${completedSteps.length} completed steps`;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
input.contextNote =
|
|
325
|
+
"Use context_get tool to retrieve data from previous steps if needed";
|
|
326
|
+
}
|
|
327
|
+
return JSON.stringify(input, null, 2);
|
|
272
328
|
}
|
|
273
329
|
/**
|
|
274
330
|
* Compile the final result from step results.
|
|
@@ -321,13 +377,12 @@ After creating the plan, respond with a brief confirmation.`;
|
|
|
321
377
|
* Extract token usage from an agent if available.
|
|
322
378
|
*/
|
|
323
379
|
extractTokenUsage(agent) {
|
|
324
|
-
|
|
325
|
-
if (!agentWithUsage.lastTokenUsage)
|
|
380
|
+
if (!agent.lastTokenUsage)
|
|
326
381
|
return undefined;
|
|
327
382
|
return {
|
|
328
|
-
inputTokens:
|
|
329
|
-
outputTokens:
|
|
330
|
-
totalTokens:
|
|
383
|
+
inputTokens: agent.lastTokenUsage.input_tokens,
|
|
384
|
+
outputTokens: agent.lastTokenUsage.output_tokens,
|
|
385
|
+
totalTokens: agent.lastTokenUsage.total_tokens,
|
|
331
386
|
};
|
|
332
387
|
}
|
|
333
388
|
/**
|
|
@@ -119,8 +119,12 @@ class PlanStore {
|
|
|
119
119
|
const plan = this.getActivePlan();
|
|
120
120
|
if (!plan)
|
|
121
121
|
return undefined;
|
|
122
|
+
const maxIndex = plan.steps.reduce((max, s) => {
|
|
123
|
+
const match = s.id.match(/^step_(\d+)$/);
|
|
124
|
+
return match ? Math.max(max, parseInt(match[1], 10)) : max;
|
|
125
|
+
}, 0);
|
|
122
126
|
const newStep = {
|
|
123
|
-
id: `step_${
|
|
127
|
+
id: `step_${maxIndex + 1}`,
|
|
124
128
|
description,
|
|
125
129
|
status: "pending",
|
|
126
130
|
};
|
|
@@ -169,7 +173,7 @@ class PlanStore {
|
|
|
169
173
|
* Update the overall plan status based on step statuses.
|
|
170
174
|
*/
|
|
171
175
|
updatePlanStatus(plan) {
|
|
172
|
-
const allCompleted = plan.steps.every((s) => s.status === "completed");
|
|
176
|
+
const allCompleted = plan.steps.every((s) => s.status === "completed" || s.status === "skipped");
|
|
173
177
|
const anyFailed = plan.steps.some((s) => s.status === "failed");
|
|
174
178
|
const anyInProgress = plan.steps.some((s) => s.status === "in_progress");
|
|
175
179
|
let newStatus;
|
package/dist/history/History.js
CHANGED
|
@@ -62,6 +62,9 @@ class History extends events_1.default {
|
|
|
62
62
|
...entry,
|
|
63
63
|
__metadata,
|
|
64
64
|
});
|
|
65
|
+
if (this.options.maxLength && this._entries.length > this.options.maxLength) {
|
|
66
|
+
this._entries = this._entries.slice(this._entries.length - this.options.maxLength);
|
|
67
|
+
}
|
|
65
68
|
this.emit("entry", entry);
|
|
66
69
|
}
|
|
67
70
|
/**
|