@radaros/core 0.2.0 → 0.3.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/index.d.ts +174 -1
- package/dist/index.js +822 -37
- package/package.json +6 -2
- package/src/index.ts +14 -1
- package/src/models/providers/vertex.ts +400 -0
- package/src/models/registry.ts +17 -0
- package/src/toolkits/base.ts +15 -0
- package/src/toolkits/gmail.ts +226 -0
- package/src/toolkits/hackernews.ts +121 -0
- package/src/toolkits/websearch.ts +158 -0
- package/src/toolkits/whatsapp.ts +209 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radaros/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"ollama": "^0.5.0",
|
|
35
35
|
"openai": "^4.0.0 || ^5.0.0 || ^6.0.0",
|
|
36
36
|
"pg": "^8.0.0",
|
|
37
|
-
"@modelcontextprotocol/sdk": ">=1.0.0"
|
|
37
|
+
"@modelcontextprotocol/sdk": ">=1.0.0",
|
|
38
|
+
"googleapis": ">=100.0.0"
|
|
38
39
|
},
|
|
39
40
|
"peerDependenciesMeta": {
|
|
40
41
|
"openai": {
|
|
@@ -63,6 +64,9 @@
|
|
|
63
64
|
},
|
|
64
65
|
"@modelcontextprotocol/sdk": {
|
|
65
66
|
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"googleapis": {
|
|
69
|
+
"optional": true
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
}
|
package/src/index.ts
CHANGED
|
@@ -49,11 +49,13 @@ export type {
|
|
|
49
49
|
ModelConfig,
|
|
50
50
|
} from "./models/types.js";
|
|
51
51
|
export { getTextContent, isMultiModal } from "./models/types.js";
|
|
52
|
-
export { ModelRegistry, registry, openai, anthropic, google, ollama } from "./models/registry.js";
|
|
52
|
+
export { ModelRegistry, registry, openai, anthropic, google, ollama, vertex } from "./models/registry.js";
|
|
53
53
|
export { OpenAIProvider } from "./models/providers/openai.js";
|
|
54
54
|
export { AnthropicProvider } from "./models/providers/anthropic.js";
|
|
55
55
|
export { GoogleProvider } from "./models/providers/google.js";
|
|
56
56
|
export { OllamaProvider } from "./models/providers/ollama.js";
|
|
57
|
+
export { VertexAIProvider } from "./models/providers/vertex.js";
|
|
58
|
+
export type { VertexAIConfig } from "./models/providers/vertex.js";
|
|
57
59
|
|
|
58
60
|
// Tools
|
|
59
61
|
export { defineTool } from "./tools/define-tool.js";
|
|
@@ -133,3 +135,14 @@ export type {
|
|
|
133
135
|
A2ASendParams,
|
|
134
136
|
A2ATaskQueryParams,
|
|
135
137
|
} from "./a2a/types.js";
|
|
138
|
+
|
|
139
|
+
// Toolkits
|
|
140
|
+
export { Toolkit } from "./toolkits/base.js";
|
|
141
|
+
export { WebSearchToolkit } from "./toolkits/websearch.js";
|
|
142
|
+
export type { WebSearchConfig } from "./toolkits/websearch.js";
|
|
143
|
+
export { GmailToolkit } from "./toolkits/gmail.js";
|
|
144
|
+
export type { GmailConfig } from "./toolkits/gmail.js";
|
|
145
|
+
export { WhatsAppToolkit } from "./toolkits/whatsapp.js";
|
|
146
|
+
export type { WhatsAppConfig } from "./toolkits/whatsapp.js";
|
|
147
|
+
export { HackerNewsToolkit } from "./toolkits/hackernews.js";
|
|
148
|
+
export type { HackerNewsConfig } from "./toolkits/hackernews.js";
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import type { ModelProvider } from "../provider.js";
|
|
3
|
+
import {
|
|
4
|
+
getTextContent,
|
|
5
|
+
isMultiModal,
|
|
6
|
+
type ChatMessage,
|
|
7
|
+
type ContentPart,
|
|
8
|
+
type ModelConfig,
|
|
9
|
+
type ModelResponse,
|
|
10
|
+
type StreamChunk,
|
|
11
|
+
type ToolDefinition,
|
|
12
|
+
type TokenUsage,
|
|
13
|
+
type ToolCall,
|
|
14
|
+
} from "../types.js";
|
|
15
|
+
|
|
16
|
+
const _require = createRequire(import.meta.url);
|
|
17
|
+
|
|
18
|
+
export interface VertexAIConfig {
|
|
19
|
+
project?: string;
|
|
20
|
+
location?: string;
|
|
21
|
+
/** Service account key JSON string or path (optional — uses ADC by default). */
|
|
22
|
+
credentials?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Vertex AI provider using Google's @google/genai SDK in Vertex mode.
|
|
27
|
+
*
|
|
28
|
+
* Authentication (in order of precedence):
|
|
29
|
+
* 1. Explicit `project` + `location` in config
|
|
30
|
+
* 2. GOOGLE_CLOUD_PROJECT / GOOGLE_CLOUD_LOCATION env vars
|
|
31
|
+
* 3. Application Default Credentials (gcloud auth)
|
|
32
|
+
*/
|
|
33
|
+
export class VertexAIProvider implements ModelProvider {
|
|
34
|
+
readonly providerId = "vertex";
|
|
35
|
+
readonly modelId: string;
|
|
36
|
+
private ai: any = null;
|
|
37
|
+
private GoogleGenAICtor: any;
|
|
38
|
+
private project: string;
|
|
39
|
+
private location: string;
|
|
40
|
+
|
|
41
|
+
constructor(modelId: string, config?: VertexAIConfig) {
|
|
42
|
+
this.modelId = modelId;
|
|
43
|
+
this.project =
|
|
44
|
+
config?.project ??
|
|
45
|
+
process.env.GOOGLE_CLOUD_PROJECT ??
|
|
46
|
+
process.env.GCLOUD_PROJECT ??
|
|
47
|
+
"";
|
|
48
|
+
this.location =
|
|
49
|
+
config?.location ??
|
|
50
|
+
process.env.GOOGLE_CLOUD_LOCATION ??
|
|
51
|
+
process.env.GOOGLE_CLOUD_REGION ??
|
|
52
|
+
"us-central1";
|
|
53
|
+
|
|
54
|
+
if (!this.project) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"VertexAIProvider: 'project' is required. Pass it in config or set GOOGLE_CLOUD_PROJECT env var."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const { GoogleGenAI } = _require("@google/genai");
|
|
62
|
+
this.GoogleGenAICtor = GoogleGenAI;
|
|
63
|
+
} catch {
|
|
64
|
+
throw new Error(
|
|
65
|
+
"@google/genai is required for VertexAIProvider. Install it: npm install @google/genai"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private getClient(): any {
|
|
71
|
+
if (this.ai) return this.ai;
|
|
72
|
+
this.ai = new this.GoogleGenAICtor({
|
|
73
|
+
vertexai: true,
|
|
74
|
+
project: this.project,
|
|
75
|
+
location: this.location,
|
|
76
|
+
});
|
|
77
|
+
return this.ai;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async generate(
|
|
81
|
+
messages: ChatMessage[],
|
|
82
|
+
options?: ModelConfig & { tools?: ToolDefinition[] }
|
|
83
|
+
): Promise<ModelResponse> {
|
|
84
|
+
const { systemInstruction, contents } = this.toGoogleMessages(messages);
|
|
85
|
+
|
|
86
|
+
const config: Record<string, unknown> = {};
|
|
87
|
+
if (options?.temperature !== undefined)
|
|
88
|
+
config.temperature = options.temperature;
|
|
89
|
+
if (options?.maxTokens !== undefined)
|
|
90
|
+
config.maxOutputTokens = options.maxTokens;
|
|
91
|
+
if (options?.topP !== undefined) config.topP = options.topP;
|
|
92
|
+
if (options?.stop) config.stopSequences = options.stop;
|
|
93
|
+
|
|
94
|
+
if (options?.responseFormat) {
|
|
95
|
+
config.responseMimeType = "application/json";
|
|
96
|
+
const rf = options.responseFormat;
|
|
97
|
+
if (
|
|
98
|
+
typeof rf === "object" &&
|
|
99
|
+
rf !== null &&
|
|
100
|
+
"type" in rf &&
|
|
101
|
+
rf.type === "json_schema" &&
|
|
102
|
+
"schema" in rf &&
|
|
103
|
+
rf.schema
|
|
104
|
+
) {
|
|
105
|
+
config.responseSchema = this.cleanJsonSchema(
|
|
106
|
+
rf.schema as Record<string, unknown>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const params: Record<string, unknown> = {
|
|
112
|
+
model: this.modelId,
|
|
113
|
+
contents,
|
|
114
|
+
config,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
if (systemInstruction) params.systemInstruction = systemInstruction;
|
|
118
|
+
if (options?.tools?.length) {
|
|
119
|
+
params.tools = [
|
|
120
|
+
{ functionDeclarations: this.toGoogleTools(options.tools) },
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const client = this.getClient();
|
|
125
|
+
const response = await client.models.generateContent(params);
|
|
126
|
+
return this.normalizeResponse(response);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async *stream(
|
|
130
|
+
messages: ChatMessage[],
|
|
131
|
+
options?: ModelConfig & { tools?: ToolDefinition[] }
|
|
132
|
+
): AsyncGenerator<StreamChunk> {
|
|
133
|
+
const { systemInstruction, contents } = this.toGoogleMessages(messages);
|
|
134
|
+
|
|
135
|
+
const config: Record<string, unknown> = {};
|
|
136
|
+
if (options?.temperature !== undefined)
|
|
137
|
+
config.temperature = options.temperature;
|
|
138
|
+
if (options?.maxTokens !== undefined)
|
|
139
|
+
config.maxOutputTokens = options.maxTokens;
|
|
140
|
+
if (options?.topP !== undefined) config.topP = options.topP;
|
|
141
|
+
if (options?.stop) config.stopSequences = options.stop;
|
|
142
|
+
|
|
143
|
+
const params: Record<string, unknown> = {
|
|
144
|
+
model: this.modelId,
|
|
145
|
+
contents,
|
|
146
|
+
config,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (systemInstruction) params.systemInstruction = systemInstruction;
|
|
150
|
+
if (options?.tools?.length) {
|
|
151
|
+
params.tools = [
|
|
152
|
+
{ functionDeclarations: this.toGoogleTools(options.tools) },
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const client = this.getClient();
|
|
157
|
+
const streamResult = await client.models.generateContentStream(params);
|
|
158
|
+
|
|
159
|
+
let toolCallCounter = 0;
|
|
160
|
+
|
|
161
|
+
for await (const chunk of streamResult) {
|
|
162
|
+
const candidate = chunk.candidates?.[0];
|
|
163
|
+
if (!candidate?.content?.parts) continue;
|
|
164
|
+
|
|
165
|
+
for (const part of candidate.content.parts) {
|
|
166
|
+
if (part.text) {
|
|
167
|
+
yield { type: "text", text: part.text };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (part.functionCall) {
|
|
171
|
+
const id = `vertex_tc_${toolCallCounter++}`;
|
|
172
|
+
yield {
|
|
173
|
+
type: "tool_call_start",
|
|
174
|
+
toolCall: { id, name: part.functionCall.name },
|
|
175
|
+
};
|
|
176
|
+
yield {
|
|
177
|
+
type: "tool_call_delta",
|
|
178
|
+
toolCallId: id,
|
|
179
|
+
argumentsDelta: JSON.stringify(part.functionCall.args ?? {}),
|
|
180
|
+
};
|
|
181
|
+
yield { type: "tool_call_end", toolCallId: id };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (candidate.finishReason) {
|
|
186
|
+
let finishReason = "stop";
|
|
187
|
+
if (
|
|
188
|
+
candidate.finishReason === "STOP" ||
|
|
189
|
+
candidate.finishReason === "END_TURN"
|
|
190
|
+
)
|
|
191
|
+
finishReason = "stop";
|
|
192
|
+
else if (candidate.finishReason === "MAX_TOKENS")
|
|
193
|
+
finishReason = "length";
|
|
194
|
+
else if (candidate.finishReason === "SAFETY")
|
|
195
|
+
finishReason = "content_filter";
|
|
196
|
+
|
|
197
|
+
const hasToolCalls = candidate.content?.parts?.some(
|
|
198
|
+
(p: any) => p.functionCall
|
|
199
|
+
);
|
|
200
|
+
if (hasToolCalls) finishReason = "tool_calls";
|
|
201
|
+
|
|
202
|
+
yield {
|
|
203
|
+
type: "finish",
|
|
204
|
+
finishReason,
|
|
205
|
+
usage: chunk.usageMetadata
|
|
206
|
+
? {
|
|
207
|
+
promptTokens: chunk.usageMetadata.promptTokenCount ?? 0,
|
|
208
|
+
completionTokens:
|
|
209
|
+
chunk.usageMetadata.candidatesTokenCount ?? 0,
|
|
210
|
+
totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,
|
|
211
|
+
}
|
|
212
|
+
: undefined,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── Message conversion (identical to GoogleProvider) ─────────────────────
|
|
219
|
+
|
|
220
|
+
private toGoogleMessages(messages: ChatMessage[]): {
|
|
221
|
+
systemInstruction: string | undefined;
|
|
222
|
+
contents: unknown[];
|
|
223
|
+
} {
|
|
224
|
+
let systemInstruction: string | undefined;
|
|
225
|
+
const contents: unknown[] = [];
|
|
226
|
+
|
|
227
|
+
for (const msg of messages) {
|
|
228
|
+
if (msg.role === "system") {
|
|
229
|
+
systemInstruction = getTextContent(msg.content) || undefined;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (msg.role === "user") {
|
|
234
|
+
if (isMultiModal(msg.content)) {
|
|
235
|
+
contents.push({
|
|
236
|
+
role: "user",
|
|
237
|
+
parts: msg.content.map((p) => this.partToGoogle(p)),
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
contents.push({
|
|
241
|
+
role: "user",
|
|
242
|
+
parts: [{ text: msg.content ?? "" }],
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (msg.role === "assistant") {
|
|
249
|
+
const parts: unknown[] = [];
|
|
250
|
+
if (msg.content) parts.push({ text: msg.content });
|
|
251
|
+
if (msg.toolCalls) {
|
|
252
|
+
for (const tc of msg.toolCalls) {
|
|
253
|
+
parts.push({
|
|
254
|
+
functionCall: { name: tc.name, args: tc.arguments },
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (parts.length === 0) parts.push({ text: "" });
|
|
259
|
+
contents.push({ role: "model", parts });
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (msg.role === "tool") {
|
|
264
|
+
contents.push({
|
|
265
|
+
role: "function",
|
|
266
|
+
parts: [
|
|
267
|
+
{
|
|
268
|
+
functionResponse: {
|
|
269
|
+
name: msg.name ?? "unknown",
|
|
270
|
+
response: { result: msg.content ?? "" },
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
});
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return { systemInstruction, contents };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private partToGoogle(part: ContentPart): unknown {
|
|
283
|
+
switch (part.type) {
|
|
284
|
+
case "text":
|
|
285
|
+
return { text: part.text };
|
|
286
|
+
case "image":
|
|
287
|
+
case "audio":
|
|
288
|
+
case "file": {
|
|
289
|
+
const isUrl =
|
|
290
|
+
part.data.startsWith("http://") || part.data.startsWith("https://");
|
|
291
|
+
if (isUrl) {
|
|
292
|
+
return {
|
|
293
|
+
fileData: {
|
|
294
|
+
fileUri: part.data,
|
|
295
|
+
mimeType:
|
|
296
|
+
part.mimeType ??
|
|
297
|
+
(part.type === "image"
|
|
298
|
+
? "image/png"
|
|
299
|
+
: "application/octet-stream"),
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
inlineData: {
|
|
305
|
+
data: part.data,
|
|
306
|
+
mimeType:
|
|
307
|
+
part.mimeType ??
|
|
308
|
+
(part.type === "image"
|
|
309
|
+
? "image/png"
|
|
310
|
+
: part.type === "audio"
|
|
311
|
+
? "audio/mp3"
|
|
312
|
+
: "application/octet-stream"),
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private toGoogleTools(tools: ToolDefinition[]): unknown[] {
|
|
320
|
+
return tools.map((t) => ({
|
|
321
|
+
name: t.name,
|
|
322
|
+
description: t.description,
|
|
323
|
+
parameters: t.parameters,
|
|
324
|
+
}));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private cleanJsonSchema(
|
|
328
|
+
schema: Record<string, unknown>
|
|
329
|
+
): Record<string, unknown> {
|
|
330
|
+
const cleaned = { ...schema };
|
|
331
|
+
delete cleaned["$schema"];
|
|
332
|
+
delete cleaned["$ref"];
|
|
333
|
+
delete cleaned["additionalProperties"];
|
|
334
|
+
|
|
335
|
+
if (cleaned.properties && typeof cleaned.properties === "object") {
|
|
336
|
+
const props: Record<string, unknown> = {};
|
|
337
|
+
for (const [key, val] of Object.entries(
|
|
338
|
+
cleaned.properties as Record<string, unknown>
|
|
339
|
+
)) {
|
|
340
|
+
props[key] =
|
|
341
|
+
typeof val === "object" && val
|
|
342
|
+
? this.cleanJsonSchema(val as Record<string, unknown>)
|
|
343
|
+
: val;
|
|
344
|
+
}
|
|
345
|
+
cleaned.properties = props;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (cleaned.items && typeof cleaned.items === "object") {
|
|
349
|
+
cleaned.items = this.cleanJsonSchema(
|
|
350
|
+
cleaned.items as Record<string, unknown>
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return cleaned;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private normalizeResponse(response: any): ModelResponse {
|
|
358
|
+
const candidate = response.candidates?.[0];
|
|
359
|
+
const parts = candidate?.content?.parts ?? [];
|
|
360
|
+
|
|
361
|
+
let textContent = "";
|
|
362
|
+
const toolCalls: ToolCall[] = [];
|
|
363
|
+
let toolCallCounter = 0;
|
|
364
|
+
|
|
365
|
+
for (const part of parts) {
|
|
366
|
+
if (part.text) textContent += part.text;
|
|
367
|
+
if (part.functionCall) {
|
|
368
|
+
toolCalls.push({
|
|
369
|
+
id: `vertex_tc_${toolCallCounter++}`,
|
|
370
|
+
name: part.functionCall.name,
|
|
371
|
+
arguments: part.functionCall.args ?? {},
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const usage: TokenUsage = {
|
|
377
|
+
promptTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
378
|
+
completionTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
|
|
379
|
+
totalTokens: response.usageMetadata?.totalTokenCount ?? 0,
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
let finishReason: ModelResponse["finishReason"] = "stop";
|
|
383
|
+
if (toolCalls.length > 0) finishReason = "tool_calls";
|
|
384
|
+
else if (candidate?.finishReason === "MAX_TOKENS")
|
|
385
|
+
finishReason = "length";
|
|
386
|
+
else if (candidate?.finishReason === "SAFETY")
|
|
387
|
+
finishReason = "content_filter";
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
message: {
|
|
391
|
+
role: "assistant",
|
|
392
|
+
content: textContent || null,
|
|
393
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
394
|
+
},
|
|
395
|
+
usage,
|
|
396
|
+
finishReason,
|
|
397
|
+
raw: response,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
package/src/models/registry.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { OpenAIProvider } from "./providers/openai.js";
|
|
|
3
3
|
import { AnthropicProvider } from "./providers/anthropic.js";
|
|
4
4
|
import { GoogleProvider } from "./providers/google.js";
|
|
5
5
|
import { OllamaProvider } from "./providers/ollama.js";
|
|
6
|
+
import { VertexAIProvider } from "./providers/vertex.js";
|
|
6
7
|
|
|
7
8
|
type ProviderFactory = (
|
|
8
9
|
modelId: string,
|
|
@@ -88,3 +89,19 @@ export function ollama(
|
|
|
88
89
|
): ModelProvider {
|
|
89
90
|
return registry.resolve("ollama", modelId, config);
|
|
90
91
|
}
|
|
92
|
+
|
|
93
|
+
registry.register(
|
|
94
|
+
"vertex",
|
|
95
|
+
(modelId, config) =>
|
|
96
|
+
new VertexAIProvider(
|
|
97
|
+
modelId,
|
|
98
|
+
config as { project?: string; location?: string; credentials?: string }
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
export function vertex(
|
|
103
|
+
modelId: string,
|
|
104
|
+
config?: { project?: string; location?: string; credentials?: string }
|
|
105
|
+
): ModelProvider {
|
|
106
|
+
return registry.resolve("vertex", modelId, config);
|
|
107
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ToolDef } from "../tools/types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base class for all RadarOS Toolkits.
|
|
5
|
+
* A Toolkit is a collection of related tools that share configuration.
|
|
6
|
+
*/
|
|
7
|
+
export abstract class Toolkit {
|
|
8
|
+
abstract readonly name: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns all tools provided by this toolkit as ToolDef[].
|
|
12
|
+
* Spread them into an Agent's `tools` array.
|
|
13
|
+
*/
|
|
14
|
+
abstract getTools(): ToolDef[];
|
|
15
|
+
}
|