@agentionai/agents 0.6.1 → 0.7.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 +0 -39
- package/dist/agents/BaseAgent.js +1 -100
- package/dist/agents/anthropic/ClaudeAgent.d.ts +2 -0
- package/dist/agents/anthropic/ClaudeAgent.js +4 -8
- package/dist/agents/google/GeminiAgent.d.ts +2 -0
- package/dist/agents/google/GeminiAgent.js +4 -4
- package/dist/agents/mistral/MistralAgent.d.ts +2 -0
- package/dist/agents/mistral/MistralAgent.js +4 -4
- package/dist/agents/openai/OpenAiAgent.d.ts +2 -0
- package/dist/agents/openai/OpenAiAgent.js +4 -4
- package/dist/core.d.ts +1 -0
- package/dist/core.js +2 -0
- package/dist/graph/planning/PlanExecutor.d.ts +0 -12
- package/dist/graph/planning/PlanExecutor.js +19 -74
- package/dist/graph/planning/PlanStore.js +2 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/mcp/MCPClient.d.ts +106 -0
- package/dist/mcp/MCPClient.js +264 -0
- package/dist/mcp/index.d.ts +64 -0
- package/dist/mcp/index.js +67 -0
- package/dist/mcp/types.d.ts +51 -0
- package/dist/mcp/types.js +3 -0
- package/package.json +5 -1
|
@@ -4,11 +4,6 @@ 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 };
|
|
12
7
|
/**
|
|
13
8
|
* Agent config as used across all agents
|
|
14
9
|
* @deprecated Use CommonAgentConfig with vendorConfig instead
|
|
@@ -38,16 +33,6 @@ export declare abstract class BaseAgent<TInput = unknown, TOutput = unknown> ext
|
|
|
38
33
|
protected vendor: AgentVendor;
|
|
39
34
|
/** The model identifier for this agent */
|
|
40
35
|
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;
|
|
51
36
|
/**
|
|
52
37
|
* An Agent is the primary LLM entity.
|
|
53
38
|
*
|
|
@@ -83,30 +68,6 @@ export declare abstract class BaseAgent<TInput = unknown, TOutput = unknown> ext
|
|
|
83
68
|
* Add a message with content blocks to history
|
|
84
69
|
*/
|
|
85
70
|
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>;
|
|
110
71
|
addTools(tools: Tool<unknown>[]): void;
|
|
111
72
|
getId(): string;
|
|
112
73
|
getName(): string;
|
package/dist/agents/BaseAgent.js
CHANGED
|
@@ -4,30 +4,9 @@ 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;
|
|
8
7
|
const events_1 = __importDefault(require("events"));
|
|
9
8
|
const Tool_1 = require("../tools/Tool");
|
|
10
9
|
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
|
-
}
|
|
31
10
|
/**
|
|
32
11
|
* The base agent is what the other agents are inheriting from
|
|
33
12
|
* Handles the BaseConfig
|
|
@@ -45,15 +24,7 @@ class BaseAgent extends events_1.default {
|
|
|
45
24
|
constructor(config, history = new History_1.History([], { transient: true })) {
|
|
46
25
|
super();
|
|
47
26
|
this.history = history;
|
|
48
|
-
this.debug =
|
|
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;
|
|
27
|
+
this.debug = true;
|
|
57
28
|
this.id = config.id;
|
|
58
29
|
this.debug = config.debug || false;
|
|
59
30
|
this.name = config.name;
|
|
@@ -70,7 +41,6 @@ class BaseAgent extends events_1.default {
|
|
|
70
41
|
}
|
|
71
42
|
this.tools = new Map((config.tools || []).map((tool) => [tool.name, tool]));
|
|
72
43
|
this.maxHistoryLength = config.maxHistoryLength || 100;
|
|
73
|
-
this.maxRetries = config.maxRetries ?? 0;
|
|
74
44
|
}
|
|
75
45
|
getToolDefinitions() {
|
|
76
46
|
return Array.from(this.tools.values()).map((tool) => tool.getPrompt());
|
|
@@ -111,75 +81,6 @@ class BaseAgent extends events_1.default {
|
|
|
111
81
|
addMessageToHistory(role, content) {
|
|
112
82
|
this.history.addMessage(role, content);
|
|
113
83
|
}
|
|
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
|
-
}
|
|
183
84
|
addTools(tools) {
|
|
184
85
|
tools.forEach((tool) => {
|
|
185
86
|
if (!this.tools.has(tool.name)) {
|
|
@@ -28,6 +28,8 @@ 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;
|
|
31
33
|
/** Current visualization event ID for tracking */
|
|
32
34
|
private vizEventId?;
|
|
33
35
|
/** 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.
|
|
80
|
+
const response = await this.client.messages.create({
|
|
81
81
|
model: this.config.model,
|
|
82
82
|
system: systemMessage,
|
|
83
83
|
max_tokens: this.config.maxTokens,
|
|
@@ -88,9 +88,7 @@ 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
|
-
})
|
|
92
|
-
? (0, BaseAgent_1.parseRetryAfterHeader)(err.headers?.["retry-after"])
|
|
93
|
-
: undefined);
|
|
91
|
+
});
|
|
94
92
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
95
93
|
return await this.handleResponse(response);
|
|
96
94
|
}
|
|
@@ -180,7 +178,7 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
180
178
|
// Continue conversation with tool results
|
|
181
179
|
try {
|
|
182
180
|
const messages = transformers_1.anthropicTransformer.toProvider(this.history.entries);
|
|
183
|
-
const newResponse = await this.
|
|
181
|
+
const newResponse = await this.client.messages.create({
|
|
184
182
|
model: this.config.model,
|
|
185
183
|
max_tokens: this.config.maxTokens,
|
|
186
184
|
messages,
|
|
@@ -190,9 +188,7 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
190
188
|
top_k: this.config.topK,
|
|
191
189
|
stop_sequences: this.config.stopSequences,
|
|
192
190
|
metadata: this.config.metadata,
|
|
193
|
-
})
|
|
194
|
-
? (0, BaseAgent_1.parseRetryAfterHeader)(err.headers?.["retry-after"])
|
|
195
|
-
: undefined);
|
|
191
|
+
});
|
|
196
192
|
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
197
193
|
return this.handleResponse(newResponse);
|
|
198
194
|
}
|
|
@@ -29,6 +29,8 @@ 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;
|
|
32
34
|
/** Current visualization event ID for tracking */
|
|
33
35
|
private vizEventId?;
|
|
34
36
|
/** 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.
|
|
182
|
+
const response = await 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.
|
|
296
|
+
const newResponse = await 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,6 +29,8 @@ 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;
|
|
32
34
|
/** Current visualization event ID for tracking */
|
|
33
35
|
private vizEventId?;
|
|
34
36
|
/** 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.
|
|
90
|
+
const response = await 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.
|
|
206
|
+
const newResponse = await 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,6 +30,8 @@ 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;
|
|
33
35
|
/** Current visualization event ID for tracking */
|
|
34
36
|
private vizEventId?;
|
|
35
37
|
/** 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.
|
|
101
|
+
const response = await 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.
|
|
220
|
+
const newResponse = await 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
|
}
|
package/dist/core.d.ts
CHANGED
package/dist/core.js
CHANGED
|
@@ -29,6 +29,8 @@ __exportStar(require("./history/types"), exports);
|
|
|
29
29
|
__exportStar(require("./graph/AgentGraph"), exports);
|
|
30
30
|
// Tools
|
|
31
31
|
__exportStar(require("./tools/Tool"), exports);
|
|
32
|
+
// MCP (Model Context Protocol)
|
|
33
|
+
__exportStar(require("./mcp"), exports);
|
|
32
34
|
// Visualization
|
|
33
35
|
__exportStar(require("./viz"), exports);
|
|
34
36
|
// Vector Store
|
|
@@ -23,14 +23,6 @@ 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;
|
|
34
26
|
/**
|
|
35
27
|
* Callback invoked when planning phase completes.
|
|
36
28
|
*/
|
|
@@ -153,10 +145,6 @@ export declare class PlanExecutor extends BaseExecutor<string, string> {
|
|
|
153
145
|
private createPlanningPrompt;
|
|
154
146
|
/**
|
|
155
147
|
* 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.
|
|
160
148
|
*/
|
|
161
149
|
private createStepInput;
|
|
162
150
|
/**
|
|
@@ -57,7 +57,6 @@ 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
|
|
61
60
|
onPlanCreated: options.onPlanCreated,
|
|
62
61
|
onStepStart: options.onStepStart,
|
|
63
62
|
onStepComplete: options.onStepComplete,
|
|
@@ -151,16 +150,11 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
151
150
|
const results = [];
|
|
152
151
|
let stepNumber = 0;
|
|
153
152
|
const activePromises = new Map();
|
|
154
|
-
let stopError;
|
|
155
153
|
while (stepNumber < this.options.maxSteps) {
|
|
156
154
|
// Wait if we've reached concurrency limit
|
|
157
155
|
if (activePromises.size >= this.options.concurrency) {
|
|
158
156
|
await Promise.race(activePromises.values());
|
|
159
157
|
}
|
|
160
|
-
// If a step failed and stopOnFailure is set, drain remaining promises then throw
|
|
161
|
-
if (stopError) {
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
158
|
const nextStep = this.planStore.getNextStep();
|
|
165
159
|
if (!nextStep) {
|
|
166
160
|
// No more pending steps
|
|
@@ -208,9 +202,9 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
208
202
|
});
|
|
209
203
|
// Notify step failure
|
|
210
204
|
this.options.onStepFailed?.(nextStep, error instanceof Error ? error : new Error(errorMessage), stepNumber);
|
|
211
|
-
//
|
|
205
|
+
// Stop if configured to do so
|
|
212
206
|
if (this.options.stopOnFailure) {
|
|
213
|
-
|
|
207
|
+
throw new Error(`Step ${stepNumber} failed: ${errorMessage}`);
|
|
214
208
|
}
|
|
215
209
|
}
|
|
216
210
|
finally {
|
|
@@ -226,12 +220,9 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
226
220
|
await promise;
|
|
227
221
|
}
|
|
228
222
|
}
|
|
229
|
-
//
|
|
223
|
+
// Wait for all remaining promises to complete
|
|
230
224
|
if (activePromises.size > 0) {
|
|
231
|
-
await Promise.
|
|
232
|
-
}
|
|
233
|
-
if (stopError) {
|
|
234
|
-
throw stopError;
|
|
225
|
+
await Promise.all(activePromises.values());
|
|
235
226
|
}
|
|
236
227
|
if (stepNumber >= this.options.maxSteps) {
|
|
237
228
|
const plan = this.planStore.getActivePlan();
|
|
@@ -250,81 +241,34 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
250
241
|
|
|
251
242
|
Task: ${task}
|
|
252
243
|
|
|
253
|
-
|
|
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)
|
|
244
|
+
IMPORTANT: You can create a maximum of ${this.options.maxSteps} steps. Plan accordingly and prioritize the most important subtasks.
|
|
280
245
|
|
|
281
|
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
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.
|
|
246
|
+
Use the create_plan tool to create a plan with clear, actionable steps. Each step should be:
|
|
247
|
+
- Specific and focused on a single subtask
|
|
248
|
+
- Ordered logically (dependencies should be addressed)
|
|
249
|
+
- Achievable by a worker agent
|
|
288
250
|
|
|
289
251
|
After creating the plan, respond with a brief confirmation.`;
|
|
290
252
|
}
|
|
291
253
|
/**
|
|
292
254
|
* 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.
|
|
297
255
|
*/
|
|
298
256
|
createStepInput(step, stepNumber) {
|
|
299
257
|
const plan = this.planStore.getActivePlan();
|
|
300
258
|
const completedSteps = plan?.steps.filter((s) => s.status === "completed") || [];
|
|
301
|
-
|
|
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 = {
|
|
259
|
+
return JSON.stringify({
|
|
307
260
|
stepNumber,
|
|
308
261
|
totalSteps: plan?.steps.length,
|
|
309
262
|
currentStep: {
|
|
310
263
|
id: step.id,
|
|
311
264
|
description: step.description,
|
|
312
265
|
},
|
|
313
|
-
|
|
314
|
-
};
|
|
315
|
-
// Only add previous steps if maxContextSteps > 0
|
|
316
|
-
if (this.options.maxContextSteps > 0 && recentSteps.length > 0) {
|
|
317
|
-
input.previousSteps = recentSteps.map((s) => ({
|
|
266
|
+
previousSteps: completedSteps.map((s) => ({
|
|
318
267
|
description: s.description,
|
|
319
268
|
output: s.output,
|
|
320
|
-
}))
|
|
321
|
-
|
|
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);
|
|
269
|
+
})),
|
|
270
|
+
planGoal: plan?.goal,
|
|
271
|
+
});
|
|
328
272
|
}
|
|
329
273
|
/**
|
|
330
274
|
* Compile the final result from step results.
|
|
@@ -377,12 +321,13 @@ After creating the plan, respond with a brief confirmation.`;
|
|
|
377
321
|
* Extract token usage from an agent if available.
|
|
378
322
|
*/
|
|
379
323
|
extractTokenUsage(agent) {
|
|
380
|
-
|
|
324
|
+
const agentWithUsage = agent;
|
|
325
|
+
if (!agentWithUsage.lastTokenUsage)
|
|
381
326
|
return undefined;
|
|
382
327
|
return {
|
|
383
|
-
inputTokens:
|
|
384
|
-
outputTokens:
|
|
385
|
-
totalTokens:
|
|
328
|
+
inputTokens: agentWithUsage.lastTokenUsage.input_tokens,
|
|
329
|
+
outputTokens: agentWithUsage.lastTokenUsage.output_tokens,
|
|
330
|
+
totalTokens: agentWithUsage.lastTokenUsage.total_tokens,
|
|
386
331
|
};
|
|
387
332
|
}
|
|
388
333
|
/**
|
|
@@ -119,12 +119,8 @@ 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);
|
|
126
122
|
const newStep = {
|
|
127
|
-
id: `step_${
|
|
123
|
+
id: `step_${plan.steps.length + 1}`,
|
|
128
124
|
description,
|
|
129
125
|
status: "pending",
|
|
130
126
|
};
|
|
@@ -173,7 +169,7 @@ class PlanStore {
|
|
|
173
169
|
* Update the overall plan status based on step statuses.
|
|
174
170
|
*/
|
|
175
171
|
updatePlanStatus(plan) {
|
|
176
|
-
const allCompleted = plan.steps.every((s) => s.status === "completed"
|
|
172
|
+
const allCompleted = plan.steps.every((s) => s.status === "completed");
|
|
177
173
|
const anyFailed = plan.steps.some((s) => s.status === "failed");
|
|
178
174
|
const anyInProgress = plan.steps.some((s) => s.status === "in_progress");
|
|
179
175
|
let newStatus;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./history/types";
|
|
|
9
9
|
export { anthropicTransformer, openAiTransformer, mistralTransformer, geminiTransformer, } from "./history/transformers";
|
|
10
10
|
export * from "./graph/AgentGraph";
|
|
11
11
|
export * from "./tools/Tool";
|
|
12
|
+
export * from "./mcp";
|
|
12
13
|
export * from "./viz";
|
|
13
14
|
export * from "./vectorstore";
|
|
14
15
|
export * from "./embeddings";
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,8 @@ Object.defineProperty(exports, "geminiTransformer", { enumerable: true, get: fun
|
|
|
45
45
|
__exportStar(require("./graph/AgentGraph"), exports);
|
|
46
46
|
// Tools
|
|
47
47
|
__exportStar(require("./tools/Tool"), exports);
|
|
48
|
+
// MCP (Model Context Protocol)
|
|
49
|
+
__exportStar(require("./mcp"), exports);
|
|
48
50
|
// Visualization
|
|
49
51
|
__exportStar(require("./viz"), exports);
|
|
50
52
|
// Vector Store
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Tool } from "../tools/Tool";
|
|
2
|
+
import { MCPStdioConfig, MCPHttpConfig, MCPClientOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* MCPClient connects to an MCP (Model Context Protocol) server and converts its
|
|
5
|
+
* tools into agention-lib {@link Tool} instances that can be passed to any agent.
|
|
6
|
+
*
|
|
7
|
+
* Supports two transport types:
|
|
8
|
+
* - **stdio** — spawns a local process and communicates over stdin/stdout
|
|
9
|
+
* - **http** — connects to a remote MCP server over Streamable HTTP
|
|
10
|
+
*
|
|
11
|
+
* @requires @modelcontextprotocol/sdk - Install as a peer dependency:
|
|
12
|
+
* ```
|
|
13
|
+
* npm install @modelcontextprotocol/sdk
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Stdio (local process)
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
19
|
+
* import { ClaudeAgent } from "@agentionai/agents/claude";
|
|
20
|
+
*
|
|
21
|
+
* const mcp = MCPClient.fromStdio({
|
|
22
|
+
* command: "npx",
|
|
23
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* await mcp.connect();
|
|
27
|
+
* const agent = new ClaudeAgent({
|
|
28
|
+
* id: "file-agent",
|
|
29
|
+
* name: "File Agent",
|
|
30
|
+
* description: "An agent that can work with files",
|
|
31
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
32
|
+
* tools: mcp.getTools(),
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
36
|
+
* await mcp.disconnect();
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example HTTP with static API key
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
42
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* await mcp.connect();
|
|
46
|
+
* agent.addTools(mcp.getTools());
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example HTTP with OAuth
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
52
|
+
*
|
|
53
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
54
|
+
* authProvider: myOAuthProvider, // implements OAuthClientProvider
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare class MCPClient {
|
|
59
|
+
private readonly transportConfig;
|
|
60
|
+
private readonly options;
|
|
61
|
+
private sdkClient;
|
|
62
|
+
private sdkTransport;
|
|
63
|
+
private _tools;
|
|
64
|
+
private connected;
|
|
65
|
+
private constructor();
|
|
66
|
+
/**
|
|
67
|
+
* Create an MCPClient that connects to a local MCP server process via stdio.
|
|
68
|
+
*
|
|
69
|
+
* @param config - Command and arguments to spawn the MCP server process
|
|
70
|
+
* @param options - Optional client identification options
|
|
71
|
+
*/
|
|
72
|
+
static fromStdio(config: MCPStdioConfig, options?: MCPClientOptions): MCPClient;
|
|
73
|
+
/**
|
|
74
|
+
* Create an MCPClient that connects to a remote MCP server via HTTP.
|
|
75
|
+
*
|
|
76
|
+
* @param url - Full URL to the MCP endpoint
|
|
77
|
+
* @param options - Optional client options including auth headers or OAuth provider
|
|
78
|
+
*/
|
|
79
|
+
static fromUrl(url: string, options?: MCPClientOptions & Pick<MCPHttpConfig, "headers" | "authProvider">): MCPClient;
|
|
80
|
+
/**
|
|
81
|
+
* Connect to the MCP server and discover all available tools.
|
|
82
|
+
*
|
|
83
|
+
* This method is idempotent — calling it when already connected is a no-op.
|
|
84
|
+
* Must be called before {@link getTools}.
|
|
85
|
+
*
|
|
86
|
+
* @throws If the MCP server cannot be reached or the SDK is not installed
|
|
87
|
+
*/
|
|
88
|
+
connect(): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Return all tools discovered from the MCP server as agention-lib Tool instances.
|
|
91
|
+
*
|
|
92
|
+
* Returns an empty array if {@link connect} has not been called yet.
|
|
93
|
+
* The returned tools can be passed directly to any agent via the `tools` config
|
|
94
|
+
* option or {@link BaseAgent.addTools}.
|
|
95
|
+
*/
|
|
96
|
+
getTools(): Tool<unknown>[];
|
|
97
|
+
/**
|
|
98
|
+
* Disconnect from the MCP server and release all resources.
|
|
99
|
+
*
|
|
100
|
+
* This method is idempotent — calling it when not connected is a no-op.
|
|
101
|
+
* After disconnecting, {@link getTools} returns an empty array.
|
|
102
|
+
*/
|
|
103
|
+
disconnect(): Promise<void>;
|
|
104
|
+
private wrapMcpTool;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=MCPClient.d.ts.map
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MCPClient = void 0;
|
|
37
|
+
const Tool_1 = require("../tools/Tool");
|
|
38
|
+
/**
|
|
39
|
+
* MCPClient connects to an MCP (Model Context Protocol) server and converts its
|
|
40
|
+
* tools into agention-lib {@link Tool} instances that can be passed to any agent.
|
|
41
|
+
*
|
|
42
|
+
* Supports two transport types:
|
|
43
|
+
* - **stdio** — spawns a local process and communicates over stdin/stdout
|
|
44
|
+
* - **http** — connects to a remote MCP server over Streamable HTTP
|
|
45
|
+
*
|
|
46
|
+
* @requires @modelcontextprotocol/sdk - Install as a peer dependency:
|
|
47
|
+
* ```
|
|
48
|
+
* npm install @modelcontextprotocol/sdk
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Stdio (local process)
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
54
|
+
* import { ClaudeAgent } from "@agentionai/agents/claude";
|
|
55
|
+
*
|
|
56
|
+
* const mcp = MCPClient.fromStdio({
|
|
57
|
+
* command: "npx",
|
|
58
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* await mcp.connect();
|
|
62
|
+
* const agent = new ClaudeAgent({
|
|
63
|
+
* id: "file-agent",
|
|
64
|
+
* name: "File Agent",
|
|
65
|
+
* description: "An agent that can work with files",
|
|
66
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
67
|
+
* tools: mcp.getTools(),
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
71
|
+
* await mcp.disconnect();
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example HTTP with static API key
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
77
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* await mcp.connect();
|
|
81
|
+
* agent.addTools(mcp.getTools());
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example HTTP with OAuth
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
87
|
+
*
|
|
88
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
89
|
+
* authProvider: myOAuthProvider, // implements OAuthClientProvider
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
class MCPClient {
|
|
94
|
+
constructor(transportConfig, options = {}) {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
|
+
this.sdkClient = null;
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
+
this.sdkTransport = null;
|
|
99
|
+
this._tools = [];
|
|
100
|
+
this.connected = false;
|
|
101
|
+
this.transportConfig = transportConfig;
|
|
102
|
+
this.options = {
|
|
103
|
+
clientName: options.clientName ?? "agention-mcp-client",
|
|
104
|
+
clientVersion: options.clientVersion ?? "1.0.0",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create an MCPClient that connects to a local MCP server process via stdio.
|
|
109
|
+
*
|
|
110
|
+
* @param config - Command and arguments to spawn the MCP server process
|
|
111
|
+
* @param options - Optional client identification options
|
|
112
|
+
*/
|
|
113
|
+
static fromStdio(config, options) {
|
|
114
|
+
return new MCPClient({ type: "stdio", config }, options);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create an MCPClient that connects to a remote MCP server via HTTP.
|
|
118
|
+
*
|
|
119
|
+
* @param url - Full URL to the MCP endpoint
|
|
120
|
+
* @param options - Optional client options including auth headers or OAuth provider
|
|
121
|
+
*/
|
|
122
|
+
static fromUrl(url, options) {
|
|
123
|
+
const config = {
|
|
124
|
+
url,
|
|
125
|
+
headers: options?.headers,
|
|
126
|
+
authProvider: options?.authProvider,
|
|
127
|
+
};
|
|
128
|
+
return new MCPClient({ type: "http", config }, options);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Connect to the MCP server and discover all available tools.
|
|
132
|
+
*
|
|
133
|
+
* This method is idempotent — calling it when already connected is a no-op.
|
|
134
|
+
* Must be called before {@link getTools}.
|
|
135
|
+
*
|
|
136
|
+
* @throws If the MCP server cannot be reached or the SDK is not installed
|
|
137
|
+
*/
|
|
138
|
+
async connect() {
|
|
139
|
+
if (this.connected)
|
|
140
|
+
return;
|
|
141
|
+
// Build module paths at runtime so tsc does not attempt to resolve them at
|
|
142
|
+
// compile time. @modelcontextprotocol/sdk is an optional peer dependency and
|
|
143
|
+
// may not be installed on the build host.
|
|
144
|
+
const pkg = "@modelcontextprotocol/sdk";
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
const { Client } = await Promise.resolve(`${`${pkg}/client/index.js`}`).then(s => __importStar(require(s)));
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
|
+
const sdkClient = new Client({ name: this.options.clientName, version: this.options.clientVersion }, { capabilities: {} });
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
let transport;
|
|
151
|
+
if (this.transportConfig.type === "stdio") {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
const { StdioClientTransport } = await Promise.resolve(`${`${pkg}/client/stdio.js`}`).then(s => __importStar(require(s)));
|
|
154
|
+
transport = new StdioClientTransport({
|
|
155
|
+
command: this.transportConfig.config.command,
|
|
156
|
+
args: this.transportConfig.config.args ?? [],
|
|
157
|
+
env: this.transportConfig.config.env,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
|
+
const { StreamableHTTPClientTransport } = await Promise.resolve(`${`${pkg}/client/streamableHttp.js`}`).then(s => __importStar(require(s)));
|
|
163
|
+
const { url, headers, authProvider } = this.transportConfig.config;
|
|
164
|
+
transport = new StreamableHTTPClientTransport(new URL(url), {
|
|
165
|
+
...(headers ? { requestInit: { headers } } : {}),
|
|
166
|
+
...(authProvider ? { authProvider } : {}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await sdkClient.connect(transport);
|
|
170
|
+
this.sdkClient = sdkClient;
|
|
171
|
+
this.sdkTransport = transport;
|
|
172
|
+
this.connected = true;
|
|
173
|
+
// Paginate through all tools
|
|
174
|
+
const allMcpTools = [];
|
|
175
|
+
let cursor;
|
|
176
|
+
do {
|
|
177
|
+
const response = await sdkClient.listTools(cursor ? { cursor } : {});
|
|
178
|
+
allMcpTools.push(...response.tools);
|
|
179
|
+
cursor = response.nextCursor;
|
|
180
|
+
} while (cursor);
|
|
181
|
+
this._tools = allMcpTools.map((mcpTool) => this.wrapMcpTool(mcpTool));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Return all tools discovered from the MCP server as agention-lib Tool instances.
|
|
185
|
+
*
|
|
186
|
+
* Returns an empty array if {@link connect} has not been called yet.
|
|
187
|
+
* The returned tools can be passed directly to any agent via the `tools` config
|
|
188
|
+
* option or {@link BaseAgent.addTools}.
|
|
189
|
+
*/
|
|
190
|
+
getTools() {
|
|
191
|
+
return this._tools;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Disconnect from the MCP server and release all resources.
|
|
195
|
+
*
|
|
196
|
+
* This method is idempotent — calling it when not connected is a no-op.
|
|
197
|
+
* After disconnecting, {@link getTools} returns an empty array.
|
|
198
|
+
*/
|
|
199
|
+
async disconnect() {
|
|
200
|
+
if (!this.connected)
|
|
201
|
+
return;
|
|
202
|
+
try {
|
|
203
|
+
if (this.transportConfig.type === "http" && this.sdkTransport) {
|
|
204
|
+
await this.sdkTransport.terminateSession?.();
|
|
205
|
+
}
|
|
206
|
+
if (this.sdkClient) {
|
|
207
|
+
await this.sdkClient.close();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
this.sdkClient = null;
|
|
212
|
+
this.sdkTransport = null;
|
|
213
|
+
this._tools = [];
|
|
214
|
+
this.connected = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
wrapMcpTool(mcpTool) {
|
|
218
|
+
const inputSchema = {
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: mcpTool.inputSchema?.properties ?? {},
|
|
221
|
+
required: mcpTool.inputSchema?.required,
|
|
222
|
+
};
|
|
223
|
+
return new Tool_1.Tool({
|
|
224
|
+
name: mcpTool.name,
|
|
225
|
+
description: mcpTool.description ?? mcpTool.name,
|
|
226
|
+
inputSchema,
|
|
227
|
+
execute: async (input) => {
|
|
228
|
+
if (!this.connected || !this.sdkClient) {
|
|
229
|
+
throw new Error(`MCPClient: Cannot execute tool "${mcpTool.name}" — client is not connected`);
|
|
230
|
+
}
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
|
+
let result;
|
|
233
|
+
try {
|
|
234
|
+
result = await this.sdkClient.callTool({
|
|
235
|
+
name: mcpTool.name,
|
|
236
|
+
arguments: input,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
241
|
+
throw new Error(`MCPClient: Tool "${mcpTool.name}" execution failed: ${message}`);
|
|
242
|
+
}
|
|
243
|
+
// Extract text content items from MCP result
|
|
244
|
+
if (result?.content && Array.isArray(result.content)) {
|
|
245
|
+
const textItems = result.content
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
247
|
+
.filter((item) => item.type === "text")
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
249
|
+
.map((item) => item.text);
|
|
250
|
+
if (textItems.length > 0) {
|
|
251
|
+
return textItems.length === 1 ? textItems[0] : textItems.join("\n");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Fall back to structured content or full JSON serialization
|
|
255
|
+
if (result?.structuredContent !== undefined) {
|
|
256
|
+
return result.structuredContent;
|
|
257
|
+
}
|
|
258
|
+
return JSON.stringify(result ?? null);
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.MCPClient = MCPClient;
|
|
264
|
+
//# sourceMappingURL=MCPClient.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) support for agention-lib.
|
|
3
|
+
*
|
|
4
|
+
* Connects to any MCP server — local stdio processes or remote HTTP endpoints —
|
|
5
|
+
* and exposes their tools as agention-lib {@link Tool} instances compatible with
|
|
6
|
+
* all agent types (ClaudeAgent, OpenAiAgent, MistralAgent, GeminiAgent).
|
|
7
|
+
*
|
|
8
|
+
* @requires @modelcontextprotocol/sdk - Optional peer dependency, install when needed:
|
|
9
|
+
* ```
|
|
10
|
+
* npm install @modelcontextprotocol/sdk
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @example Stdio (local process)
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { MCPClient, ClaudeAgent } from "@agentionai/agents";
|
|
16
|
+
*
|
|
17
|
+
* const mcp = MCPClient.fromStdio({
|
|
18
|
+
* command: "npx",
|
|
19
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* await mcp.connect();
|
|
23
|
+
*
|
|
24
|
+
* const agent = new ClaudeAgent({
|
|
25
|
+
* id: "file-agent",
|
|
26
|
+
* name: "File Agent",
|
|
27
|
+
* description: "An agent that can work with files",
|
|
28
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
29
|
+
* tools: mcp.getTools(),
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
33
|
+
* await mcp.disconnect();
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example HTTP with static API key
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
39
|
+
*
|
|
40
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
41
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* await mcp.connect();
|
|
45
|
+
* agent.addTools(mcp.getTools());
|
|
46
|
+
* await mcp.disconnect();
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example HTTP with OAuth
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
52
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
53
|
+
*
|
|
54
|
+
* // Implement OAuthClientProvider from the MCP SDK
|
|
55
|
+
* const myOAuthProvider: OAuthClientProvider = { ... };
|
|
56
|
+
*
|
|
57
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
58
|
+
* authProvider: myOAuthProvider,
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export { MCPClient } from "./MCPClient";
|
|
63
|
+
export type { MCPStdioConfig, MCPHttpConfig, MCPClientOptions } from "./types";
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP (Model Context Protocol) support for agention-lib.
|
|
4
|
+
*
|
|
5
|
+
* Connects to any MCP server — local stdio processes or remote HTTP endpoints —
|
|
6
|
+
* and exposes their tools as agention-lib {@link Tool} instances compatible with
|
|
7
|
+
* all agent types (ClaudeAgent, OpenAiAgent, MistralAgent, GeminiAgent).
|
|
8
|
+
*
|
|
9
|
+
* @requires @modelcontextprotocol/sdk - Optional peer dependency, install when needed:
|
|
10
|
+
* ```
|
|
11
|
+
* npm install @modelcontextprotocol/sdk
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example Stdio (local process)
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { MCPClient, ClaudeAgent } from "@agentionai/agents";
|
|
17
|
+
*
|
|
18
|
+
* const mcp = MCPClient.fromStdio({
|
|
19
|
+
* command: "npx",
|
|
20
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* await mcp.connect();
|
|
24
|
+
*
|
|
25
|
+
* const agent = new ClaudeAgent({
|
|
26
|
+
* id: "file-agent",
|
|
27
|
+
* name: "File Agent",
|
|
28
|
+
* description: "An agent that can work with files",
|
|
29
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
30
|
+
* tools: mcp.getTools(),
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
34
|
+
* await mcp.disconnect();
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example HTTP with static API key
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
40
|
+
*
|
|
41
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
42
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* await mcp.connect();
|
|
46
|
+
* agent.addTools(mcp.getTools());
|
|
47
|
+
* await mcp.disconnect();
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example HTTP with OAuth
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
53
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
54
|
+
*
|
|
55
|
+
* // Implement OAuthClientProvider from the MCP SDK
|
|
56
|
+
* const myOAuthProvider: OAuthClientProvider = { ... };
|
|
57
|
+
*
|
|
58
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
59
|
+
* authProvider: myOAuthProvider,
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
64
|
+
exports.MCPClient = void 0;
|
|
65
|
+
var MCPClient_1 = require("./MCPClient");
|
|
66
|
+
Object.defineProperty(exports, "MCPClient", { enumerable: true, get: function () { return MCPClient_1.MCPClient; } });
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for connecting to an MCP server via stdio (local process).
|
|
3
|
+
*/
|
|
4
|
+
export interface MCPStdioConfig {
|
|
5
|
+
/** The command to spawn (e.g. "node", "python", "npx") */
|
|
6
|
+
command: string;
|
|
7
|
+
/** Arguments to pass to the command */
|
|
8
|
+
args?: string[];
|
|
9
|
+
/** Environment variables for the spawned process */
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for connecting to an MCP server via HTTP (remote URL).
|
|
14
|
+
*/
|
|
15
|
+
export interface MCPHttpConfig {
|
|
16
|
+
/** Full URL to the MCP endpoint */
|
|
17
|
+
url: string;
|
|
18
|
+
/** Optional HTTP headers for static auth tokens or API keys */
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Optional OAuth provider for dynamic authorization.
|
|
22
|
+
* Implement the `OAuthClientProvider` interface from `@modelcontextprotocol/sdk`
|
|
23
|
+
* and pass it here for OAuth 2.0 + PKCE flows.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
28
|
+
*
|
|
29
|
+
* const mcp = MCPClient.fromUrl("https://my-server.com/mcp", {
|
|
30
|
+
* authProvider: myOAuthProvider,
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
authProvider?: unknown;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Options shared by all MCPClient connection types.
|
|
38
|
+
*/
|
|
39
|
+
export interface MCPClientOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Name to identify this MCP client (sent during SDK handshake).
|
|
42
|
+
* @default "agention-mcp-client"
|
|
43
|
+
*/
|
|
44
|
+
clientName?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Version string for the MCP client.
|
|
47
|
+
* @default "1.0.0"
|
|
48
|
+
*/
|
|
49
|
+
clientVersion?: string;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentionai/agents",
|
|
3
3
|
"author": "Laurent Zuijdwijk",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "Agent Library",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
"@google/generative-ai": "^0.24.1",
|
|
111
111
|
"@lancedb/lancedb": "^0.23.0",
|
|
112
112
|
"@mistralai/mistralai": "^1.13.0",
|
|
113
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
113
114
|
"apache-arrow": "^18.0.0",
|
|
114
115
|
"openai": "^6.16.0",
|
|
115
116
|
"voyageai": "^0.0.3"
|
|
@@ -130,6 +131,9 @@
|
|
|
130
131
|
"@anthropic-ai/sdk": {
|
|
131
132
|
"optional": true
|
|
132
133
|
},
|
|
134
|
+
"@modelcontextprotocol/sdk": {
|
|
135
|
+
"optional": true
|
|
136
|
+
},
|
|
133
137
|
"openai": {
|
|
134
138
|
"optional": true
|
|
135
139
|
},
|