@radaros/core 0.3.4 → 0.3.6
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/index.d.ts +1407 -0
- package/dist/index.js +5269 -0
- package/package.json +6 -2
- package/src/a2a/a2a-remote-agent.ts +0 -270
- package/src/a2a/types.ts +0 -142
- package/src/agent/agent.ts +0 -417
- package/src/agent/llm-loop.ts +0 -290
- package/src/agent/run-context.ts +0 -35
- package/src/agent/types.ts +0 -89
- package/src/events/event-bus.ts +0 -45
- package/src/events/types.ts +0 -16
- package/src/guardrails/types.ts +0 -5
- package/src/hooks/types.ts +0 -6
- package/src/index.ts +0 -157
- package/src/knowledge/knowledge-base.ts +0 -146
- package/src/logger/logger.ts +0 -249
- package/src/mcp/mcp-client.ts +0 -264
- package/src/memory/memory.ts +0 -87
- package/src/memory/types.ts +0 -13
- package/src/memory/user-memory.ts +0 -211
- package/src/models/provider.ts +0 -22
- package/src/models/providers/anthropic.ts +0 -360
- package/src/models/providers/google.ts +0 -386
- package/src/models/providers/ollama.ts +0 -211
- package/src/models/providers/openai.ts +0 -345
- package/src/models/providers/vertex.ts +0 -427
- package/src/models/registry.ts +0 -107
- package/src/models/types.ts +0 -124
- package/src/session/session-manager.ts +0 -75
- package/src/session/types.ts +0 -10
- package/src/storage/driver.ts +0 -10
- package/src/storage/in-memory.ts +0 -44
- package/src/storage/mongodb.ts +0 -70
- package/src/storage/postgres.ts +0 -81
- package/src/storage/sqlite.ts +0 -81
- package/src/team/modes.ts +0 -1
- package/src/team/team.ts +0 -323
- package/src/team/types.ts +0 -26
- package/src/toolkits/base.ts +0 -15
- package/src/toolkits/duckduckgo.ts +0 -256
- package/src/toolkits/gmail.ts +0 -226
- package/src/toolkits/hackernews.ts +0 -121
- package/src/toolkits/websearch.ts +0 -158
- package/src/toolkits/whatsapp.ts +0 -209
- package/src/tools/define-tool.ts +0 -22
- package/src/tools/tool-executor.ts +0 -221
- package/src/tools/types.ts +0 -36
- package/src/utils/retry.ts +0 -56
- package/src/vector/base.ts +0 -44
- package/src/vector/embeddings/google.ts +0 -64
- package/src/vector/embeddings/openai.ts +0 -66
- package/src/vector/in-memory.ts +0 -115
- package/src/vector/mongodb.ts +0 -241
- package/src/vector/pgvector.ts +0 -169
- package/src/vector/qdrant.ts +0 -203
- package/src/vector/types.ts +0 -55
- package/src/workflow/step-runner.ts +0 -303
- package/src/workflow/types.ts +0 -55
- package/src/workflow/workflow.ts +0 -68
- package/tsconfig.json +0 -8
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { ToolDef } from "../tools/types.js";
|
|
3
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
4
|
-
import { Toolkit } from "./base.js";
|
|
5
|
-
|
|
6
|
-
export interface WebSearchConfig {
|
|
7
|
-
/** Search provider: "tavily" or "serpapi". */
|
|
8
|
-
provider: "tavily" | "serpapi";
|
|
9
|
-
/** API key for the search provider. Falls back to TAVILY_API_KEY or SERPAPI_API_KEY env vars. */
|
|
10
|
-
apiKey?: string;
|
|
11
|
-
/** Max results to return per search (default 5). */
|
|
12
|
-
maxResults?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Web Search Toolkit — search the web from your agent.
|
|
17
|
-
*
|
|
18
|
-
* Supports Tavily and SerpAPI backends.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* const search = new WebSearchToolkit({ provider: "tavily" });
|
|
23
|
-
* const agent = new Agent({ tools: [...search.getTools()] });
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export class WebSearchToolkit extends Toolkit {
|
|
27
|
-
readonly name = "websearch";
|
|
28
|
-
private config: WebSearchConfig;
|
|
29
|
-
|
|
30
|
-
constructor(config: WebSearchConfig) {
|
|
31
|
-
super();
|
|
32
|
-
this.config = config;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
private getApiKey(): string {
|
|
36
|
-
if (this.config.apiKey) return this.config.apiKey;
|
|
37
|
-
|
|
38
|
-
const envKey =
|
|
39
|
-
this.config.provider === "tavily"
|
|
40
|
-
? process.env.TAVILY_API_KEY
|
|
41
|
-
: process.env.SERPAPI_API_KEY;
|
|
42
|
-
|
|
43
|
-
if (!envKey) {
|
|
44
|
-
const envName =
|
|
45
|
-
this.config.provider === "tavily"
|
|
46
|
-
? "TAVILY_API_KEY"
|
|
47
|
-
: "SERPAPI_API_KEY";
|
|
48
|
-
throw new Error(
|
|
49
|
-
`WebSearchToolkit: No API key provided. Set ${envName} env var or pass apiKey in config.`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
return envKey;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getTools(): ToolDef[] {
|
|
56
|
-
const self = this;
|
|
57
|
-
|
|
58
|
-
return [
|
|
59
|
-
{
|
|
60
|
-
name: "web_search",
|
|
61
|
-
description:
|
|
62
|
-
"Search the web for current information. Returns titles, URLs, and snippets from search results.",
|
|
63
|
-
parameters: z.object({
|
|
64
|
-
query: z.string().describe("The search query"),
|
|
65
|
-
maxResults: z
|
|
66
|
-
.number()
|
|
67
|
-
.optional()
|
|
68
|
-
.describe("Maximum number of results (default 5)"),
|
|
69
|
-
}),
|
|
70
|
-
execute: async (
|
|
71
|
-
args: Record<string, unknown>,
|
|
72
|
-
_ctx: RunContext
|
|
73
|
-
): Promise<string> => {
|
|
74
|
-
const query = args.query as string;
|
|
75
|
-
const max =
|
|
76
|
-
(args.maxResults as number) ?? self.config.maxResults ?? 5;
|
|
77
|
-
|
|
78
|
-
if (self.config.provider === "tavily") {
|
|
79
|
-
return self.searchTavily(query, max);
|
|
80
|
-
}
|
|
81
|
-
return self.searchSerpApi(query, max);
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
private async searchTavily(
|
|
88
|
-
query: string,
|
|
89
|
-
maxResults: number
|
|
90
|
-
): Promise<string> {
|
|
91
|
-
const apiKey = this.getApiKey();
|
|
92
|
-
const res = await fetch("https://api.tavily.com/search", {
|
|
93
|
-
method: "POST",
|
|
94
|
-
headers: { "Content-Type": "application/json" },
|
|
95
|
-
body: JSON.stringify({
|
|
96
|
-
api_key: apiKey,
|
|
97
|
-
query,
|
|
98
|
-
max_results: maxResults,
|
|
99
|
-
include_answer: true,
|
|
100
|
-
}),
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (!res.ok) {
|
|
104
|
-
throw new Error(`Tavily search failed: ${res.status} ${res.statusText}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const data = (await res.json()) as any;
|
|
108
|
-
const results: string[] = [];
|
|
109
|
-
|
|
110
|
-
if (data.answer) {
|
|
111
|
-
results.push(`Answer: ${data.answer}\n`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
for (const r of data.results ?? []) {
|
|
115
|
-
results.push(`Title: ${r.title}\nURL: ${r.url}\nSnippet: ${r.content}\n`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return results.join("\n---\n") || "No results found.";
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private async searchSerpApi(
|
|
122
|
-
query: string,
|
|
123
|
-
maxResults: number
|
|
124
|
-
): Promise<string> {
|
|
125
|
-
const apiKey = this.getApiKey();
|
|
126
|
-
const params = new URLSearchParams({
|
|
127
|
-
q: query,
|
|
128
|
-
api_key: apiKey,
|
|
129
|
-
engine: "google",
|
|
130
|
-
num: String(maxResults),
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const res = await fetch(
|
|
134
|
-
`https://serpapi.com/search.json?${params.toString()}`
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
if (!res.ok) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
`SerpAPI search failed: ${res.status} ${res.statusText}`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const data = (await res.json()) as any;
|
|
144
|
-
const results: string[] = [];
|
|
145
|
-
|
|
146
|
-
if (data.answer_box?.answer) {
|
|
147
|
-
results.push(`Answer: ${data.answer_box.answer}\n`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
for (const r of (data.organic_results ?? []).slice(0, maxResults)) {
|
|
151
|
-
results.push(
|
|
152
|
-
`Title: ${r.title}\nURL: ${r.link}\nSnippet: ${r.snippet ?? ""}\n`
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return results.join("\n---\n") || "No results found.";
|
|
157
|
-
}
|
|
158
|
-
}
|
package/src/toolkits/whatsapp.ts
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { ToolDef } from "../tools/types.js";
|
|
3
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
4
|
-
import { Toolkit } from "./base.js";
|
|
5
|
-
|
|
6
|
-
export interface WhatsAppConfig {
|
|
7
|
-
/** WhatsApp Business API access token. Falls back to WHATSAPP_ACCESS_TOKEN env var. */
|
|
8
|
-
accessToken?: string;
|
|
9
|
-
/** WhatsApp Business phone number ID. Falls back to WHATSAPP_PHONE_NUMBER_ID env var. */
|
|
10
|
-
phoneNumberId?: string;
|
|
11
|
-
/** API version (default "v22.0"). Falls back to WHATSAPP_VERSION env var. */
|
|
12
|
-
version?: string;
|
|
13
|
-
/** Default recipient WhatsApp ID. Falls back to WHATSAPP_RECIPIENT_WAID env var. */
|
|
14
|
-
recipientWaid?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* WhatsApp Toolkit — send messages via WhatsApp Business Cloud API (Meta).
|
|
19
|
-
*
|
|
20
|
-
* Uses the WhatsApp Cloud API directly (no Twilio).
|
|
21
|
-
* Setup: https://developers.facebook.com/docs/whatsapp/cloud-api/get-started
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* const whatsapp = new WhatsAppToolkit({
|
|
26
|
-
* accessToken: "...",
|
|
27
|
-
* phoneNumberId: "...",
|
|
28
|
-
* });
|
|
29
|
-
* const agent = new Agent({ tools: [...whatsapp.getTools()] });
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export class WhatsAppToolkit extends Toolkit {
|
|
33
|
-
readonly name = "whatsapp";
|
|
34
|
-
private accessToken: string;
|
|
35
|
-
private phoneNumberId: string;
|
|
36
|
-
private version: string;
|
|
37
|
-
private recipientWaid: string | undefined;
|
|
38
|
-
|
|
39
|
-
constructor(config: WhatsAppConfig = {}) {
|
|
40
|
-
super();
|
|
41
|
-
this.accessToken =
|
|
42
|
-
config.accessToken ?? process.env.WHATSAPP_ACCESS_TOKEN ?? "";
|
|
43
|
-
this.phoneNumberId =
|
|
44
|
-
config.phoneNumberId ?? process.env.WHATSAPP_PHONE_NUMBER_ID ?? "";
|
|
45
|
-
this.version =
|
|
46
|
-
config.version ?? process.env.WHATSAPP_VERSION ?? "v22.0";
|
|
47
|
-
this.recipientWaid =
|
|
48
|
-
config.recipientWaid ?? process.env.WHATSAPP_RECIPIENT_WAID;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private getBaseUrl(): string {
|
|
52
|
-
return `https://graph.facebook.com/${this.version}/${this.phoneNumberId}/messages`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private validate(): void {
|
|
56
|
-
if (!this.accessToken) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
"WhatsAppToolkit: accessToken is required. Set WHATSAPP_ACCESS_TOKEN env var or pass in config."
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
if (!this.phoneNumberId) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
"WhatsAppToolkit: phoneNumberId is required. Set WHATSAPP_PHONE_NUMBER_ID env var or pass in config."
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private resolveRecipient(recipient?: string): string {
|
|
69
|
-
const r = recipient ?? this.recipientWaid;
|
|
70
|
-
if (!r) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
"WhatsAppToolkit: recipient is required. Provide it in the tool call or set WHATSAPP_RECIPIENT_WAID env var."
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return r.replace(/[^0-9]/g, "");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
getTools(): ToolDef[] {
|
|
79
|
-
const self = this;
|
|
80
|
-
|
|
81
|
-
return [
|
|
82
|
-
{
|
|
83
|
-
name: "whatsapp_send_text",
|
|
84
|
-
description:
|
|
85
|
-
"Send a text message to a WhatsApp user via WhatsApp Business Cloud API.",
|
|
86
|
-
parameters: z.object({
|
|
87
|
-
text: z.string().describe("The text message to send"),
|
|
88
|
-
recipient: z
|
|
89
|
-
.string()
|
|
90
|
-
.optional()
|
|
91
|
-
.describe(
|
|
92
|
-
"Recipient WhatsApp number with country code (e.g. 919876543210). Uses default if omitted."
|
|
93
|
-
),
|
|
94
|
-
previewUrl: z
|
|
95
|
-
.boolean()
|
|
96
|
-
.optional()
|
|
97
|
-
.describe("Enable URL previews in the message (default false)"),
|
|
98
|
-
}),
|
|
99
|
-
execute: async (
|
|
100
|
-
args: Record<string, unknown>,
|
|
101
|
-
_ctx: RunContext
|
|
102
|
-
): Promise<string> => {
|
|
103
|
-
self.validate();
|
|
104
|
-
const recipient = self.resolveRecipient(args.recipient as string);
|
|
105
|
-
|
|
106
|
-
const res = await fetch(self.getBaseUrl(), {
|
|
107
|
-
method: "POST",
|
|
108
|
-
headers: {
|
|
109
|
-
Authorization: `Bearer ${self.accessToken}`,
|
|
110
|
-
"Content-Type": "application/json",
|
|
111
|
-
},
|
|
112
|
-
body: JSON.stringify({
|
|
113
|
-
messaging_product: "whatsapp",
|
|
114
|
-
recipient_type: "individual",
|
|
115
|
-
to: recipient,
|
|
116
|
-
type: "text",
|
|
117
|
-
text: {
|
|
118
|
-
preview_url: (args.previewUrl as boolean) ?? false,
|
|
119
|
-
body: args.text as string,
|
|
120
|
-
},
|
|
121
|
-
}),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!res.ok) {
|
|
125
|
-
const err = await res.text();
|
|
126
|
-
throw new Error(
|
|
127
|
-
`WhatsApp send failed: ${res.status} ${err}`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const data = (await res.json()) as any;
|
|
132
|
-
const msgId = data.messages?.[0]?.id ?? "unknown";
|
|
133
|
-
return `Message sent successfully to ${recipient}. Message ID: ${msgId}`;
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: "whatsapp_send_template",
|
|
138
|
-
description:
|
|
139
|
-
"Send a template message to a WhatsApp user. Required for first-time outreach (24-hour messaging window).",
|
|
140
|
-
parameters: z.object({
|
|
141
|
-
templateName: z
|
|
142
|
-
.string()
|
|
143
|
-
.describe(
|
|
144
|
-
'The pre-approved template name (e.g. "hello_world")'
|
|
145
|
-
),
|
|
146
|
-
recipient: z
|
|
147
|
-
.string()
|
|
148
|
-
.optional()
|
|
149
|
-
.describe(
|
|
150
|
-
"Recipient WhatsApp number with country code. Uses default if omitted."
|
|
151
|
-
),
|
|
152
|
-
languageCode: z
|
|
153
|
-
.string()
|
|
154
|
-
.optional()
|
|
155
|
-
.describe('Template language code (default "en_US")'),
|
|
156
|
-
components: z
|
|
157
|
-
.array(z.record(z.any()))
|
|
158
|
-
.optional()
|
|
159
|
-
.describe(
|
|
160
|
-
"Template components for dynamic content (header, body, button parameters)"
|
|
161
|
-
),
|
|
162
|
-
}),
|
|
163
|
-
execute: async (
|
|
164
|
-
args: Record<string, unknown>,
|
|
165
|
-
_ctx: RunContext
|
|
166
|
-
): Promise<string> => {
|
|
167
|
-
self.validate();
|
|
168
|
-
const recipient = self.resolveRecipient(args.recipient as string);
|
|
169
|
-
const langCode = (args.languageCode as string) ?? "en_US";
|
|
170
|
-
|
|
171
|
-
const template: Record<string, unknown> = {
|
|
172
|
-
name: args.templateName as string,
|
|
173
|
-
language: { code: langCode },
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
if (args.components) {
|
|
177
|
-
template.components = args.components;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const res = await fetch(self.getBaseUrl(), {
|
|
181
|
-
method: "POST",
|
|
182
|
-
headers: {
|
|
183
|
-
Authorization: `Bearer ${self.accessToken}`,
|
|
184
|
-
"Content-Type": "application/json",
|
|
185
|
-
},
|
|
186
|
-
body: JSON.stringify({
|
|
187
|
-
messaging_product: "whatsapp",
|
|
188
|
-
recipient_type: "individual",
|
|
189
|
-
to: recipient,
|
|
190
|
-
type: "template",
|
|
191
|
-
template,
|
|
192
|
-
}),
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
if (!res.ok) {
|
|
196
|
-
const err = await res.text();
|
|
197
|
-
throw new Error(
|
|
198
|
-
`WhatsApp template send failed: ${res.status} ${err}`
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const data = (await res.json()) as any;
|
|
203
|
-
const msgId = data.messages?.[0]?.id ?? "unknown";
|
|
204
|
-
return `Template message "${args.templateName}" sent to ${recipient}. Message ID: ${msgId}`;
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
];
|
|
208
|
-
}
|
|
209
|
-
}
|
package/src/tools/define-tool.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { z } from "zod";
|
|
2
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
3
|
-
import type { ToolDef, ToolResult, ToolCacheConfig } from "./types.js";
|
|
4
|
-
|
|
5
|
-
export function defineTool<T extends z.ZodObject<any>>(config: {
|
|
6
|
-
name: string;
|
|
7
|
-
description: string;
|
|
8
|
-
parameters: T;
|
|
9
|
-
execute: (
|
|
10
|
-
args: z.infer<T>,
|
|
11
|
-
ctx: RunContext
|
|
12
|
-
) => Promise<string | ToolResult>;
|
|
13
|
-
cache?: ToolCacheConfig;
|
|
14
|
-
}): ToolDef {
|
|
15
|
-
return {
|
|
16
|
-
name: config.name,
|
|
17
|
-
description: config.description,
|
|
18
|
-
parameters: config.parameters,
|
|
19
|
-
execute: config.execute as ToolDef["execute"],
|
|
20
|
-
cache: config.cache,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import type { ToolCall } from "../models/types.js";
|
|
3
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
4
|
-
import type { ToolDef, ToolCallResult, ToolResult } from "./types.js";
|
|
5
|
-
|
|
6
|
-
const _require = createRequire(import.meta.url);
|
|
7
|
-
|
|
8
|
-
interface CacheEntry {
|
|
9
|
-
result: string | ToolResult;
|
|
10
|
-
expiresAt: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class ToolExecutor {
|
|
14
|
-
private tools: Map<string, ToolDef>;
|
|
15
|
-
private concurrency: number;
|
|
16
|
-
private cache = new Map<string, CacheEntry>();
|
|
17
|
-
private cachedDefs: Array<{
|
|
18
|
-
name: string;
|
|
19
|
-
description: string;
|
|
20
|
-
parameters: Record<string, unknown>;
|
|
21
|
-
}> | null = null;
|
|
22
|
-
|
|
23
|
-
constructor(tools: ToolDef[], concurrency: number = 5) {
|
|
24
|
-
this.tools = new Map(tools.map((t) => [t.name, t]));
|
|
25
|
-
this.concurrency = concurrency;
|
|
26
|
-
this.cachedDefs = this.buildToolDefinitions();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
clearCache(): void {
|
|
30
|
-
this.cache.clear();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private getCacheKey(toolName: string, args: Record<string, unknown>): string {
|
|
34
|
-
const sortedArgs = JSON.stringify(args, Object.keys(args).sort());
|
|
35
|
-
return `${toolName}:${sortedArgs}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
private getCached(toolName: string, args: Record<string, unknown>): (string | ToolResult) | undefined {
|
|
39
|
-
const tool = this.tools.get(toolName);
|
|
40
|
-
if (!tool?.cache) return undefined;
|
|
41
|
-
|
|
42
|
-
const key = this.getCacheKey(toolName, args);
|
|
43
|
-
const entry = this.cache.get(key);
|
|
44
|
-
if (!entry) return undefined;
|
|
45
|
-
|
|
46
|
-
if (Date.now() > entry.expiresAt) {
|
|
47
|
-
this.cache.delete(key);
|
|
48
|
-
return undefined;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return entry.result;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private setCache(toolName: string, args: Record<string, unknown>, result: string | ToolResult): void {
|
|
55
|
-
const tool = this.tools.get(toolName);
|
|
56
|
-
if (!tool?.cache) return;
|
|
57
|
-
|
|
58
|
-
const key = this.getCacheKey(toolName, args);
|
|
59
|
-
this.cache.set(key, {
|
|
60
|
-
result,
|
|
61
|
-
expiresAt: Date.now() + tool.cache.ttl,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async executeAll(
|
|
66
|
-
toolCalls: ToolCall[],
|
|
67
|
-
ctx: RunContext
|
|
68
|
-
): Promise<ToolCallResult[]> {
|
|
69
|
-
const results: ToolCallResult[] = [];
|
|
70
|
-
|
|
71
|
-
for (let i = 0; i < toolCalls.length; i += this.concurrency) {
|
|
72
|
-
const batch = toolCalls.slice(i, i + this.concurrency);
|
|
73
|
-
const batchResults = await Promise.allSettled(
|
|
74
|
-
batch.map((tc) => this.executeSingle(tc, ctx))
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
for (let j = 0; j < batchResults.length; j++) {
|
|
78
|
-
const settled = batchResults[j];
|
|
79
|
-
const tc = batch[j];
|
|
80
|
-
|
|
81
|
-
if (settled.status === "fulfilled") {
|
|
82
|
-
results.push(settled.value);
|
|
83
|
-
} else {
|
|
84
|
-
results.push({
|
|
85
|
-
toolCallId: tc.id,
|
|
86
|
-
toolName: tc.name,
|
|
87
|
-
result: `Error: ${settled.reason?.message ?? "Unknown error"}`,
|
|
88
|
-
error: settled.reason?.message ?? "Unknown error",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return results;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private async executeSingle(
|
|
98
|
-
toolCall: ToolCall,
|
|
99
|
-
ctx: RunContext
|
|
100
|
-
): Promise<ToolCallResult> {
|
|
101
|
-
const tool = this.tools.get(toolCall.name);
|
|
102
|
-
if (!tool) {
|
|
103
|
-
return {
|
|
104
|
-
toolCallId: toolCall.id,
|
|
105
|
-
toolName: toolCall.name,
|
|
106
|
-
result: `Error: Tool "${toolCall.name}" not found`,
|
|
107
|
-
error: `Tool "${toolCall.name}" not found`,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
ctx.eventBus.emit("tool.call", {
|
|
112
|
-
runId: ctx.runId,
|
|
113
|
-
toolName: toolCall.name,
|
|
114
|
-
args: toolCall.arguments,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const cachedResult = this.getCached(toolCall.name, toolCall.arguments);
|
|
118
|
-
if (cachedResult !== undefined) {
|
|
119
|
-
const resultContent =
|
|
120
|
-
typeof cachedResult === "string" ? cachedResult : cachedResult.content;
|
|
121
|
-
|
|
122
|
-
ctx.eventBus.emit("tool.result", {
|
|
123
|
-
runId: ctx.runId,
|
|
124
|
-
toolName: toolCall.name,
|
|
125
|
-
result: `[cached] ${resultContent}`,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
toolCallId: toolCall.id,
|
|
130
|
-
toolName: toolCall.name,
|
|
131
|
-
result: cachedResult,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const parsed = tool.parameters.safeParse(toolCall.arguments);
|
|
136
|
-
if (!parsed.success) {
|
|
137
|
-
const errMsg = `Invalid arguments: ${parsed.error.message}`;
|
|
138
|
-
const result: ToolCallResult = {
|
|
139
|
-
toolCallId: toolCall.id,
|
|
140
|
-
toolName: toolCall.name,
|
|
141
|
-
result: errMsg,
|
|
142
|
-
error: errMsg,
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
ctx.eventBus.emit("tool.result", {
|
|
146
|
-
runId: ctx.runId,
|
|
147
|
-
toolName: toolCall.name,
|
|
148
|
-
result: errMsg,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const rawResult = await tool.execute(parsed.data, ctx);
|
|
155
|
-
const resultContent =
|
|
156
|
-
typeof rawResult === "string" ? rawResult : rawResult.content;
|
|
157
|
-
|
|
158
|
-
this.setCache(toolCall.name, toolCall.arguments, rawResult);
|
|
159
|
-
|
|
160
|
-
ctx.eventBus.emit("tool.result", {
|
|
161
|
-
runId: ctx.runId,
|
|
162
|
-
toolName: toolCall.name,
|
|
163
|
-
result: resultContent,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
toolCallId: toolCall.id,
|
|
168
|
-
toolName: toolCall.name,
|
|
169
|
-
result: rawResult,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
getToolDefinitions(): Array<{
|
|
174
|
-
name: string;
|
|
175
|
-
description: string;
|
|
176
|
-
parameters: Record<string, unknown>;
|
|
177
|
-
}> {
|
|
178
|
-
if (this.cachedDefs) return this.cachedDefs;
|
|
179
|
-
this.cachedDefs = this.buildToolDefinitions();
|
|
180
|
-
return this.cachedDefs;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
private buildToolDefinitions(): Array<{
|
|
184
|
-
name: string;
|
|
185
|
-
description: string;
|
|
186
|
-
parameters: Record<string, unknown>;
|
|
187
|
-
}> {
|
|
188
|
-
const { zodToJsonSchema } = _require("zod-to-json-schema");
|
|
189
|
-
const defs: Array<{
|
|
190
|
-
name: string;
|
|
191
|
-
description: string;
|
|
192
|
-
parameters: Record<string, unknown>;
|
|
193
|
-
}> = [];
|
|
194
|
-
|
|
195
|
-
for (const tool of this.tools.values()) {
|
|
196
|
-
if (tool.rawJsonSchema) {
|
|
197
|
-
defs.push({
|
|
198
|
-
name: tool.name,
|
|
199
|
-
description: tool.description,
|
|
200
|
-
parameters: tool.rawJsonSchema,
|
|
201
|
-
});
|
|
202
|
-
} else {
|
|
203
|
-
const jsonSchema = zodToJsonSchema(tool.parameters, {
|
|
204
|
-
target: "jsonSchema7",
|
|
205
|
-
$refStrategy: "none",
|
|
206
|
-
}) as Record<string, unknown>;
|
|
207
|
-
|
|
208
|
-
delete jsonSchema["$schema"];
|
|
209
|
-
delete jsonSchema["additionalProperties"];
|
|
210
|
-
|
|
211
|
-
defs.push({
|
|
212
|
-
name: tool.name,
|
|
213
|
-
description: tool.description,
|
|
214
|
-
parameters: jsonSchema,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return defs;
|
|
220
|
-
}
|
|
221
|
-
}
|
package/src/tools/types.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { z } from "zod";
|
|
2
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
3
|
-
|
|
4
|
-
export interface Artifact {
|
|
5
|
-
type: string;
|
|
6
|
-
data: unknown;
|
|
7
|
-
mimeType?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface ToolResult {
|
|
11
|
-
content: string;
|
|
12
|
-
artifacts?: Artifact[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ToolCacheConfig {
|
|
16
|
-
/** Time-to-live in milliseconds. Cached results expire after this duration. */
|
|
17
|
-
ttl: number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ToolDef {
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
parameters: z.ZodObject<any>;
|
|
24
|
-
execute: (args: Record<string, unknown>, ctx: RunContext) => Promise<string | ToolResult>;
|
|
25
|
-
/** Raw JSON Schema to send to the LLM, bypassing Zod-to-JSON conversion (used by MCP tools). */
|
|
26
|
-
rawJsonSchema?: Record<string, unknown>;
|
|
27
|
-
/** Enable result caching for this tool. */
|
|
28
|
-
cache?: ToolCacheConfig;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ToolCallResult {
|
|
32
|
-
toolCallId: string;
|
|
33
|
-
toolName: string;
|
|
34
|
-
result: string | ToolResult;
|
|
35
|
-
error?: string;
|
|
36
|
-
}
|
package/src/utils/retry.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export interface RetryConfig {
|
|
2
|
-
maxRetries: number;
|
|
3
|
-
initialDelayMs: number;
|
|
4
|
-
maxDelayMs: number;
|
|
5
|
-
retryableErrors?: (error: unknown) => boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const DEFAULT_CONFIG: RetryConfig = {
|
|
9
|
-
maxRetries: 3,
|
|
10
|
-
initialDelayMs: 500,
|
|
11
|
-
maxDelayMs: 10_000,
|
|
12
|
-
retryableErrors: isRetryableError,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function isRetryableError(error: unknown): boolean {
|
|
16
|
-
if (error && typeof error === "object") {
|
|
17
|
-
const status = (error as any).status ?? (error as any).statusCode;
|
|
18
|
-
if (status === 429 || (status >= 500 && status < 600)) return true;
|
|
19
|
-
|
|
20
|
-
const code = (error as any).code;
|
|
21
|
-
if (code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ENOTFOUND") return true;
|
|
22
|
-
|
|
23
|
-
const msg = (error as any).message;
|
|
24
|
-
if (typeof msg === "string" && /rate.limit|too.many.requests|overloaded/i.test(msg)) return true;
|
|
25
|
-
}
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function sleep(ms: number): Promise<void> {
|
|
30
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function withRetry<T>(
|
|
34
|
-
fn: () => Promise<T>,
|
|
35
|
-
config?: Partial<RetryConfig>
|
|
36
|
-
): Promise<T> {
|
|
37
|
-
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
38
|
-
let lastError: unknown;
|
|
39
|
-
|
|
40
|
-
for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {
|
|
41
|
-
try {
|
|
42
|
-
return await fn();
|
|
43
|
-
} catch (error) {
|
|
44
|
-
lastError = error;
|
|
45
|
-
if (attempt >= cfg.maxRetries || !cfg.retryableErrors!(error)) throw error;
|
|
46
|
-
|
|
47
|
-
const delay = Math.min(
|
|
48
|
-
cfg.initialDelayMs * Math.pow(2, attempt) + Math.random() * 200,
|
|
49
|
-
cfg.maxDelayMs
|
|
50
|
-
);
|
|
51
|
-
await sleep(delay);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
throw lastError;
|
|
56
|
-
}
|