agent-accelerator 0.1.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/LICENSE +21 -0
- package/README.md +1220 -0
- package/SYSTEM_PROMPT.md +14 -0
- package/SYSTEM_PROMPT_AGENT.md +34 -0
- package/SYSTEM_PROMPT_TOOLS.md +9 -0
- package/bunfig.toml +2 -0
- package/package.json +59 -0
- package/src/agent/agent.ts +615 -0
- package/src/agent/context.ts +161 -0
- package/src/agent/delegation.ts +481 -0
- package/src/agent/loop.ts +569 -0
- package/src/agent/subagent.ts +83 -0
- package/src/ai-sdk/converters.ts +342 -0
- package/src/ai-sdk/errors.ts +122 -0
- package/src/ai-sdk/executor.ts +454 -0
- package/src/ai-sdk/index.ts +55 -0
- package/src/ai-sdk/model-provider.ts +303 -0
- package/src/ai-sdk/options.ts +306 -0
- package/src/ai-sdk/provider.ts +415 -0
- package/src/ai-sdk/registry.ts +416 -0
- package/src/data/README.md +84 -0
- package/src/index.ts +190 -0
- package/src/models/catalog-cache.ts +273 -0
- package/src/models/catalog.ts +503 -0
- package/src/streaming/event-stream.ts +211 -0
- package/src/streaming/sse-parser.ts +97 -0
- package/src/tokens/counter.ts +136 -0
- package/src/tools/executor.ts +365 -0
- package/src/tools/schema.ts +221 -0
- package/src/tools/tool.ts +101 -0
- package/src/types/agent.ts +87 -0
- package/src/types/core.ts +86 -0
- package/src/types/message.ts +115 -0
- package/src/types/model.ts +212 -0
- package/src/types/provider-payloads.ts +434 -0
- package/src/types/response.ts +158 -0
- package/src/types/tool.ts +61 -0
- package/src/utils/base64.ts +27 -0
- package/src/utils/cache.ts +146 -0
- package/src/utils/env.ts +78 -0
- package/src/utils/headers.ts +110 -0
- package/src/utils/media.ts +137 -0
- package/src/utils/serialization.ts +91 -0
- package/src/utils/session.ts +26 -0
- package/src/utils/thought-signature.ts +27 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import type { Provider, ProviderId, ModelSpec } from "../types/model.ts";
|
|
2
|
+
import type { ThinkingLevel } from "../types/core.ts";
|
|
3
|
+
import {
|
|
4
|
+
GoogleAiSdkProvider,
|
|
5
|
+
OpenCodeAiSdkProvider,
|
|
6
|
+
OpenRouterAiSdkProvider,
|
|
7
|
+
OpenAiAiSdkProvider,
|
|
8
|
+
CustomAiSdkProvider,
|
|
9
|
+
} from "./model-provider.ts";
|
|
10
|
+
import { getModelFromCatalog } from "../models/catalog.ts";
|
|
11
|
+
import { getEnv } from "../utils/env.ts";
|
|
12
|
+
|
|
13
|
+
const providerRegistry = new Map<ProviderId, Provider>();
|
|
14
|
+
|
|
15
|
+
// Initialize default supported providers powered purely by Vercel AI SDK
|
|
16
|
+
const googleProvider = new GoogleAiSdkProvider();
|
|
17
|
+
const opencodeProvider = new OpenCodeAiSdkProvider();
|
|
18
|
+
const openrouterProvider = new OpenRouterAiSdkProvider();
|
|
19
|
+
const openaiProvider = new OpenAiAiSdkProvider();
|
|
20
|
+
|
|
21
|
+
providerRegistry.set("google", googleProvider);
|
|
22
|
+
providerRegistry.set("gemini", googleProvider);
|
|
23
|
+
providerRegistry.set("opencode", opencodeProvider);
|
|
24
|
+
providerRegistry.set("opencode-go", opencodeProvider);
|
|
25
|
+
providerRegistry.set("openrouter", openrouterProvider);
|
|
26
|
+
providerRegistry.set("openai", openaiProvider);
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Unified multi-provider layer powered purely by Vercel AI SDK
|
|
30
|
+
// Any `MODEL="<prefix>/<model-id>"` works without SDK changes as long as
|
|
31
|
+
// `{PREFIX}_API_KEY` (+ optional `{PREFIX}_BASE_URL`) is set. Examples:
|
|
32
|
+
// MODEL="groq/llama-3.3-70b-versatile" + GROQ_API_KEY + GROQ_BASE_URL
|
|
33
|
+
// MODEL="cerebras/gpt-oss-120b" + CEREBRAS_API_KEY + CEREBRAS_BASE_URL
|
|
34
|
+
// MODEL="ollama/qwen2.5-coder" + OLLAMA_BASE_URL (key optional for local)
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const FIRST_CLASS = new Set([
|
|
37
|
+
"google",
|
|
38
|
+
"gemini",
|
|
39
|
+
"opencode",
|
|
40
|
+
"opencode-go",
|
|
41
|
+
"openrouter",
|
|
42
|
+
"openai",
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes a provider prefix for registry lookup and environment resolution.
|
|
47
|
+
* @example `const prefix = normalizeProviderPrefix(" Groq/llama ");`
|
|
48
|
+
*/
|
|
49
|
+
export function normalizeProviderPrefix(prefix: string): string {
|
|
50
|
+
return prefix.trim().toLowerCase();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get-or-create an OpenAI-compatible provider for any prefix backed by Vercel AI SDK.
|
|
55
|
+
* Cached, so repeated `resolveModel("groq/...")` calls reuse one instance.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Registers or retrieves an OpenAI-compatible provider for any custom prefix.
|
|
59
|
+
*
|
|
60
|
+
* @example `const groq = ensureCustomProvider("groq", { baseUrl: "https://api.groq.com/openai/v1" });`
|
|
61
|
+
*/
|
|
62
|
+
export function ensureCustomProvider(
|
|
63
|
+
prefix: string,
|
|
64
|
+
opts?: { baseUrl?: string; apiKey?: string; name?: string }
|
|
65
|
+
): Provider {
|
|
66
|
+
const id = normalizeProviderPrefix(prefix) as ProviderId;
|
|
67
|
+
const existing = providerRegistry.get(id);
|
|
68
|
+
if (existing && !FIRST_CLASS.has(id.toLowerCase())) return existing;
|
|
69
|
+
if (existing && opts?.baseUrl === undefined && opts?.apiKey === undefined) {
|
|
70
|
+
return existing;
|
|
71
|
+
}
|
|
72
|
+
const created = new CustomAiSdkProvider(id, opts);
|
|
73
|
+
providerRegistry.set(id, created);
|
|
74
|
+
return created;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Retrieves a provider by ID.
|
|
79
|
+
* Unknown ids auto-create an OpenAI-compatible provider (unified layer),
|
|
80
|
+
* so `getProvider("groq")` works after setting `GROQ_API_KEY`/`GROQ_BASE_URL`.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* Retrieves a first-class provider or lazily creates a custom compatible provider.
|
|
84
|
+
*
|
|
85
|
+
* @example `const provider = getProvider("google");`
|
|
86
|
+
*/
|
|
87
|
+
export function getProvider(id: ProviderId | string): Provider {
|
|
88
|
+
const key = String(id).trim() as ProviderId;
|
|
89
|
+
const provider = providerRegistry.get(key);
|
|
90
|
+
if (provider) return provider;
|
|
91
|
+
if (!key) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Provider '' is not supported or not registered. Available first-support providers: google, opencode, openrouter, openai — or any custom prefix via {PREFIX}_API_KEY + {PREFIX}_BASE_URL.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
// Unified layer: lazily create OpenAI-compatible provider for any custom prefix.
|
|
97
|
+
return ensureCustomProvider(key);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Provider/model pair returned by resolveModel. */
|
|
101
|
+
export interface ResolvedModel {
|
|
102
|
+
provider: Provider;
|
|
103
|
+
modelId: string;
|
|
104
|
+
modelSpec?: ModelSpec;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolves a model string (e.g. "google/model-id", "opencode/model-id", "openrouter/scope/model:variant")
|
|
109
|
+
* or ModelSpec into provider instance and model ID using Vercel AI SDK provider layer.
|
|
110
|
+
*/
|
|
111
|
+
/**
|
|
112
|
+
* Resolves `provider/model`, catalog specs, scoped OpenRouter IDs, and custom prefixes.
|
|
113
|
+
*
|
|
114
|
+
* @example `const { provider, modelId } = resolveModel("openai/gpt-4o");`
|
|
115
|
+
*/
|
|
116
|
+
export function resolveModel(model: string | ModelSpec): ResolvedModel {
|
|
117
|
+
if (!model || (typeof model === "string" && !model.trim())) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
"[Agent Accelerator] No model specified. Please specify 'model' in Agent configuration or set the MODEL environment variable."
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof model === "object" && model !== null && "provider" in model) {
|
|
124
|
+
const provider = getProvider(model.provider);
|
|
125
|
+
// Enrich with catalog if available
|
|
126
|
+
const catalogSpec = getModelFromCatalog(model.provider, model.id);
|
|
127
|
+
return {
|
|
128
|
+
provider,
|
|
129
|
+
modelId: model.id,
|
|
130
|
+
modelSpec: catalogSpec || model,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const modelStr = String(model).trim();
|
|
135
|
+
|
|
136
|
+
// Try catalog first for any provider/model
|
|
137
|
+
const tryCatalogLookup = (prov: string, mid: string): ModelSpec | undefined => {
|
|
138
|
+
return (
|
|
139
|
+
getModelFromCatalog(prov, mid) ||
|
|
140
|
+
getModelFromCatalog(prov.toLowerCase(), mid) ||
|
|
141
|
+
getModelFromCatalog(mid, mid)
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const hasCustomOpenAIBase = !!(getEnv("OPENAI_BASE_URL") || getEnv("OPENAI_API_BASE"));
|
|
146
|
+
|
|
147
|
+
// Explicit prefix with slash — deterministic
|
|
148
|
+
if (modelStr.includes("/")) {
|
|
149
|
+
const parts = modelStr.split("/");
|
|
150
|
+
const providerPrefix = parts[0]!.toLowerCase();
|
|
151
|
+
const remainingModel = parts.slice(1).join("/");
|
|
152
|
+
|
|
153
|
+
// 1. Explicit openai/ prefix ALWAYS routes to OpenAI provider
|
|
154
|
+
if (providerPrefix === "openai") {
|
|
155
|
+
const p = getProvider("openai");
|
|
156
|
+
const spec =
|
|
157
|
+
p.getModel(remainingModel) ||
|
|
158
|
+
getModelFromCatalog("openai", remainingModel) ||
|
|
159
|
+
getModelFromCatalog(remainingModel, remainingModel);
|
|
160
|
+
return { provider: p, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 2. Unified layer: any non-first-class prefix routes to auto-created custom provider
|
|
164
|
+
const isExplicitOther = [
|
|
165
|
+
"google",
|
|
166
|
+
"gemini",
|
|
167
|
+
"opencode",
|
|
168
|
+
"opencode-go",
|
|
169
|
+
"openrouter",
|
|
170
|
+
].includes(providerPrefix);
|
|
171
|
+
|
|
172
|
+
if (!isExplicitOther && providerPrefix !== "openai") {
|
|
173
|
+
const envName = providerPrefix.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
174
|
+
const hasDedicatedEnv = !!(
|
|
175
|
+
getEnv(`${envName}_BASE_URL`) ||
|
|
176
|
+
getEnv(`${envName}_BASEURL`) ||
|
|
177
|
+
getEnv(`${envName}_API_BASE`) ||
|
|
178
|
+
getEnv(`${envName}_API_KEY`) ||
|
|
179
|
+
getEnv(`${envName}_BASE_API_KEY`)
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const looksLikeOpenRouterScope =
|
|
183
|
+
parts.length === 2 && modelStr.includes(":") && !hasDedicatedEnv;
|
|
184
|
+
|
|
185
|
+
if (!looksLikeOpenRouterScope) {
|
|
186
|
+
if (hasCustomOpenAIBase && !hasDedicatedEnv) {
|
|
187
|
+
const p = getProvider("openai");
|
|
188
|
+
const spec = p.getModel(remainingModel) || getModelFromCatalog(remainingModel, remainingModel);
|
|
189
|
+
return { provider: p, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
190
|
+
}
|
|
191
|
+
const custom = ensureCustomProvider(providerPrefix);
|
|
192
|
+
const spec =
|
|
193
|
+
custom.getModel(remainingModel) ||
|
|
194
|
+
custom.getModel(modelStr) ||
|
|
195
|
+
tryCatalogLookup(providerPrefix, remainingModel) ||
|
|
196
|
+
tryCatalogLookup(providerPrefix, modelStr) ||
|
|
197
|
+
getModelFromCatalog(remainingModel, remainingModel);
|
|
198
|
+
return { provider: custom, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (providerPrefix === "google" || providerPrefix === "gemini") {
|
|
203
|
+
const p = getProvider("google");
|
|
204
|
+
const spec =
|
|
205
|
+
p.getModel(remainingModel) ||
|
|
206
|
+
getModelFromCatalog("google", remainingModel) ||
|
|
207
|
+
getModelFromCatalog(remainingModel, remainingModel);
|
|
208
|
+
return { provider: p, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (
|
|
212
|
+
providerPrefix === "opencode" ||
|
|
213
|
+
providerPrefix === "opencode-go"
|
|
214
|
+
) {
|
|
215
|
+
const p = getProvider("opencode");
|
|
216
|
+
const spec =
|
|
217
|
+
p.getModel(remainingModel) ||
|
|
218
|
+
getModelFromCatalog("opencode", remainingModel) ||
|
|
219
|
+
getModelFromCatalog(remainingModel, remainingModel);
|
|
220
|
+
return { provider: p, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (providerPrefix === "openrouter") {
|
|
224
|
+
const p = getProvider("openrouter");
|
|
225
|
+
const spec =
|
|
226
|
+
p.getModel(remainingModel) ||
|
|
227
|
+
getModelFromCatalog("openrouter", remainingModel) ||
|
|
228
|
+
getModelFromCatalog(remainingModel, remainingModel);
|
|
229
|
+
return { provider: p, modelId: remainingModel, modelSpec: spec as ModelSpec };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Scoped OpenRouter models like "scope/model:variant" without openrouter prefix
|
|
233
|
+
if (parts.length === 2 && modelStr.includes(":")) {
|
|
234
|
+
const p = getProvider("openrouter");
|
|
235
|
+
const spec = p.getModel(modelStr) || tryCatalogLookup("openrouter", modelStr);
|
|
236
|
+
return { provider: p, modelId: modelStr, modelSpec: spec as ModelSpec };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check catalog for this exact provider/model
|
|
240
|
+
const catalogSpec =
|
|
241
|
+
tryCatalogLookup(providerPrefix, remainingModel) ||
|
|
242
|
+
tryCatalogLookup(providerPrefix, modelStr);
|
|
243
|
+
if (catalogSpec) {
|
|
244
|
+
const internalProvider = getProvider(catalogSpec.provider);
|
|
245
|
+
return { provider: internalProvider, modelId: catalogSpec.id, modelSpec: catalogSpec };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Unknown provider prefix — try catalog with priority
|
|
249
|
+
const prioritizedUnknown =
|
|
250
|
+
tryCatalogLookup(providerPrefix, remainingModel) ||
|
|
251
|
+
tryCatalogLookup("google", remainingModel) ||
|
|
252
|
+
tryCatalogLookup("opencode", remainingModel) ||
|
|
253
|
+
tryCatalogLookup("openai", remainingModel) ||
|
|
254
|
+
tryCatalogLookup("openrouter", remainingModel) ||
|
|
255
|
+
getModelFromCatalog(modelStr, modelStr);
|
|
256
|
+
if (prioritizedUnknown) {
|
|
257
|
+
const internalProvider = getProvider(prioritizedUnknown.provider);
|
|
258
|
+
return {
|
|
259
|
+
provider: internalProvider,
|
|
260
|
+
modelId: prioritizedUnknown.id,
|
|
261
|
+
modelSpec: prioritizedUnknown,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Fallback custom provider
|
|
266
|
+
const fallbackCustom = ensureCustomProvider(providerPrefix);
|
|
267
|
+
const fallbackSpec =
|
|
268
|
+
fallbackCustom.getModel(remainingModel) || fallbackCustom.getModel(modelStr);
|
|
269
|
+
return {
|
|
270
|
+
provider: fallbackCustom,
|
|
271
|
+
modelId: remainingModel,
|
|
272
|
+
modelSpec: fallbackSpec as ModelSpec,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// When OPENAI_BASE_URL is set: trust user completely
|
|
277
|
+
if (hasCustomOpenAIBase) {
|
|
278
|
+
const p = getProvider("openai");
|
|
279
|
+
const spec = p.getModel(modelStr) || getModelFromCatalog(modelStr, modelStr);
|
|
280
|
+
return { provider: p, modelId: modelStr, modelSpec: spec as ModelSpec };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// No slash — try catalog with internal provider priority
|
|
284
|
+
const prioritized =
|
|
285
|
+
tryCatalogLookup("google", modelStr) ||
|
|
286
|
+
tryCatalogLookup("opencode", modelStr) ||
|
|
287
|
+
tryCatalogLookup("openai", modelStr) ||
|
|
288
|
+
tryCatalogLookup("openrouter", modelStr) ||
|
|
289
|
+
getModelFromCatalog(modelStr, modelStr);
|
|
290
|
+
if (prioritized) {
|
|
291
|
+
const internalProvider = getProvider(prioritized.provider);
|
|
292
|
+
return { provider: internalProvider, modelId: prioritized.id, modelSpec: prioritized };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Fallback to openrouter
|
|
296
|
+
const p = getProvider("openrouter");
|
|
297
|
+
return { provider: p, modelId: modelStr, modelSpec: p.getModel(modelStr) };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Configuration accepted by the ModelProvider helper family. */
|
|
301
|
+
export interface ModelProviderConfig {
|
|
302
|
+
apiKey?: string;
|
|
303
|
+
thinkingLevel?: ThinkingLevel;
|
|
304
|
+
baseUrl?: string;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Serializable model/provider selection returned by ModelProvider helpers. */
|
|
308
|
+
export interface ModelProviderInstance {
|
|
309
|
+
model: string;
|
|
310
|
+
apiKey?: string;
|
|
311
|
+
baseUrl?: string;
|
|
312
|
+
thinkingLevel?: ThinkingLevel;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* ModelProvider builder helper for python-like and expressive syntax
|
|
317
|
+
*/
|
|
318
|
+
/**
|
|
319
|
+
* Provider/model builder helpers for expressive configuration.
|
|
320
|
+
*
|
|
321
|
+
* @example `new Agent({ model: ModelProvider.GoogleGenAI("gemini-3.5-flash-lite") })`
|
|
322
|
+
*/
|
|
323
|
+
export const ModelProvider = {
|
|
324
|
+
/** Builds a Google AI Studio model selection. @example `ModelProvider.GoogleGenAI("gemini-3.5-flash-lite")` */
|
|
325
|
+
GoogleGenAI(
|
|
326
|
+
model: string,
|
|
327
|
+
apiKey?: string,
|
|
328
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
329
|
+
): ModelProviderInstance {
|
|
330
|
+
return {
|
|
331
|
+
model: model.startsWith("google/") ? model : `google/${model}`,
|
|
332
|
+
apiKey,
|
|
333
|
+
baseUrl: options?.baseUrl,
|
|
334
|
+
thinkingLevel: options?.thinkingLevel,
|
|
335
|
+
};
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
/** Builds an OpenCode model selection. @example `ModelProvider.OpenCode("kimi-k2.5")` */
|
|
339
|
+
OpenCode(
|
|
340
|
+
model: string,
|
|
341
|
+
apiKey?: string,
|
|
342
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
343
|
+
): ModelProviderInstance {
|
|
344
|
+
return {
|
|
345
|
+
model: model.startsWith("opencode") ? model : `opencode/${model}`,
|
|
346
|
+
apiKey,
|
|
347
|
+
baseUrl: options?.baseUrl,
|
|
348
|
+
thinkingLevel: options?.thinkingLevel,
|
|
349
|
+
};
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
/** Builds an OpenRouter model selection. @example `ModelProvider.OpenRouter("openai/gpt-4o")` */
|
|
353
|
+
OpenRouter(
|
|
354
|
+
model: string,
|
|
355
|
+
apiKey?: string,
|
|
356
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
357
|
+
): ModelProviderInstance {
|
|
358
|
+
return {
|
|
359
|
+
model: model.startsWith("openrouter/") ? model : `openrouter/${model}`,
|
|
360
|
+
apiKey,
|
|
361
|
+
baseUrl: options?.baseUrl,
|
|
362
|
+
thinkingLevel: options?.thinkingLevel,
|
|
363
|
+
};
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
/** Builds an OpenAI model selection. @example `ModelProvider.OpenAI("gpt-4o")` */
|
|
367
|
+
OpenAI(
|
|
368
|
+
model: string,
|
|
369
|
+
apiKey?: string,
|
|
370
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
371
|
+
): ModelProviderInstance {
|
|
372
|
+
return {
|
|
373
|
+
model: model.startsWith("openai/") ? model : `openai/${model}`,
|
|
374
|
+
apiKey,
|
|
375
|
+
baseUrl: options?.baseUrl,
|
|
376
|
+
thinkingLevel: options?.thinkingLevel,
|
|
377
|
+
};
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
/** Builds an arbitrary OpenAI-compatible model selection. @example `ModelProvider.Custom("groq/llama-3.3-70b-versatile")` */
|
|
381
|
+
Custom(
|
|
382
|
+
model: string,
|
|
383
|
+
apiKey?: string,
|
|
384
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
385
|
+
): ModelProviderInstance {
|
|
386
|
+
const normalized = model.includes("/") ? model : `custom/${model}`;
|
|
387
|
+
const prefix = normalized.split("/")[0]!;
|
|
388
|
+
try {
|
|
389
|
+
ensureCustomProvider(prefix, { baseUrl: options?.baseUrl, apiKey });
|
|
390
|
+
} catch {}
|
|
391
|
+
return {
|
|
392
|
+
model: normalized,
|
|
393
|
+
apiKey,
|
|
394
|
+
baseUrl: options?.baseUrl,
|
|
395
|
+
thinkingLevel: options?.thinkingLevel,
|
|
396
|
+
};
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
/** Alias for Custom for explicit OpenAI-compatible endpoints. @example `ModelProvider.OpenAICompatible("ollama/qwen2.5-coder")` */
|
|
400
|
+
OpenAICompatible(
|
|
401
|
+
model: string,
|
|
402
|
+
apiKey?: string,
|
|
403
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
404
|
+
): ModelProviderInstance {
|
|
405
|
+
return ModelProvider.Custom(model, apiKey, options);
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
/** Alias for Custom for generic local/hosted endpoints. @example `ModelProvider.Generic("my-provider/model-id")` */
|
|
409
|
+
Generic(
|
|
410
|
+
model: string,
|
|
411
|
+
apiKey?: string,
|
|
412
|
+
options?: { thinkingLevel?: ThinkingLevel; baseUrl?: string }
|
|
413
|
+
): ModelProviderInstance {
|
|
414
|
+
return ModelProvider.Custom(model, apiKey, options);
|
|
415
|
+
},
|
|
416
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Model Catalog Cache (`src/data/`)
|
|
2
|
+
|
|
3
|
+
This directory is the local destination for the dynamic model catalog cache used by **Agent Accelerator**.
|
|
4
|
+
|
|
5
|
+
Agent Accelerator references a catalog of **7,500+ models across 200+ providers** for token limits, context windows, modality support, reasoning configurations, and per-token pricing (input, output, cache-read, cache-write).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Zero-Bloat Distribution Architecture
|
|
10
|
+
|
|
11
|
+
To keep the repository and published npm/Bun package lightweight and blazing fast:
|
|
12
|
+
|
|
13
|
+
1. **Excluded from Production Package & Git**:
|
|
14
|
+
* The ~4.5 MB full catalog snapshot (`models-cache.json` / `models.dev.json`) is **never** committed to git and is **excluded** from the npm/Bun distribution bundle.
|
|
15
|
+
* Both files are tracked in `.gitignore` and `.npmignore`.
|
|
16
|
+
|
|
17
|
+
2. **Dynamic 12-Hour Automated TTL Cache**:
|
|
18
|
+
* On agent execution (`runAgentLoop` / `streamAgentLoop`), Agent Accelerator checks the status of `src/data/models-cache.json`.
|
|
19
|
+
* **Cache Hit (< 12h)**: Instant memory/disk load with zero network overhead.
|
|
20
|
+
* **Cache Miss / Expired (≥ 12h)**: Automatically downloads the latest catalog directly from `https://models.dev/api.json`, caches it to `src/data/models-cache.json`, and loads the catalog into memory.
|
|
21
|
+
* **Resilience**: If an existing cache exists on disk, temporary upstream network issues will safely continue using the local cached copy.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Developer Controls & Management
|
|
26
|
+
|
|
27
|
+
### 1. CLI Script
|
|
28
|
+
|
|
29
|
+
You can manually inspect or refresh the model catalog anytime via the developer CLI script:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Refresh catalog if expired (or download if missing)
|
|
33
|
+
bun run update-models
|
|
34
|
+
|
|
35
|
+
# Force download regardless of age
|
|
36
|
+
bun run update-models --force
|
|
37
|
+
|
|
38
|
+
# Custom TTL (e.g., 24 hours)
|
|
39
|
+
bun scripts/update-models.ts --ttl=24h
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### 2. Programmatic API
|
|
45
|
+
|
|
46
|
+
All catalog cache lifecycle controls are exported from the root package:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import {
|
|
50
|
+
refreshModelCatalog,
|
|
51
|
+
ensureModelCatalogFresh,
|
|
52
|
+
getCatalogStatus,
|
|
53
|
+
setCatalogTTL,
|
|
54
|
+
getModelFromCatalog,
|
|
55
|
+
} from "agent-accelerator";
|
|
56
|
+
|
|
57
|
+
// 1. Check current cache status
|
|
58
|
+
const status = getCatalogStatus();
|
|
59
|
+
console.log(status);
|
|
60
|
+
// {
|
|
61
|
+
// isExpired: false,
|
|
62
|
+
// cachedAt: 1773400000000,
|
|
63
|
+
// ttlMs: 43200000,
|
|
64
|
+
// modelCount: 7696,
|
|
65
|
+
// providerCount: 213,
|
|
66
|
+
// source: "cache"
|
|
67
|
+
// }
|
|
68
|
+
|
|
69
|
+
// 2. Refresh on-demand (e.g. in a cron job or startup hook)
|
|
70
|
+
await refreshModelCatalog({ force: true });
|
|
71
|
+
|
|
72
|
+
// 3. Customize runtime TTL (e.g., 6 hours)
|
|
73
|
+
setCatalogTTL(6 * 60 * 60 * 1000);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Structure
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
src/data/
|
|
82
|
+
├── README.md # This documentation
|
|
83
|
+
└── models-cache.json # Auto-generated on first run (gitignored, excluded from bundle)
|
|
84
|
+
```
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// Core Agent & Tool Classes
|
|
4
|
+
export { Agent, SubAgentModelError } from "./agent/agent.ts";
|
|
5
|
+
export { SubAgent } from "./agent/subagent.ts";
|
|
6
|
+
export type { SubAgentConfig } from "./agent/subagent.ts";
|
|
7
|
+
export { tool, toStandardToolDeclarations } from "./tools/tool.ts";
|
|
8
|
+
export type { CreateToolOptions } from "./tools/tool.ts";
|
|
9
|
+
export { zodToJsonSchema, cleanJsonSchema } from "./tools/schema.ts";
|
|
10
|
+
export { executeToolCalls } from "./tools/executor.ts";
|
|
11
|
+
|
|
12
|
+
// Multi-Agent Delegation & Tools
|
|
13
|
+
export {
|
|
14
|
+
buildAgentTools,
|
|
15
|
+
createSubagentSpawnTool,
|
|
16
|
+
} from "./agent/delegation.ts";
|
|
17
|
+
export type { DynamicSubagentTask } from "./agent/delegation.ts";
|
|
18
|
+
|
|
19
|
+
// Providers & Registry — unified multi-provider layer powered by Vercel AI SDK
|
|
20
|
+
export {
|
|
21
|
+
getProvider,
|
|
22
|
+
resolveModel,
|
|
23
|
+
ModelProvider,
|
|
24
|
+
ensureCustomProvider,
|
|
25
|
+
normalizeProviderPrefix,
|
|
26
|
+
} from "./ai-sdk/registry.ts";
|
|
27
|
+
export {
|
|
28
|
+
getModelFromCatalog,
|
|
29
|
+
getModelThinkingInfo,
|
|
30
|
+
validateModelThinking,
|
|
31
|
+
getModelsForProvider,
|
|
32
|
+
ThinkingLevelError,
|
|
33
|
+
refreshModelCatalog,
|
|
34
|
+
ensureModelCatalogFresh,
|
|
35
|
+
getCatalogStatus,
|
|
36
|
+
setCatalogTTL,
|
|
37
|
+
getCatalogTTL,
|
|
38
|
+
getCacheDir,
|
|
39
|
+
getCacheFilePath,
|
|
40
|
+
DEFAULT_CATALOG_TTL_MS,
|
|
41
|
+
type CatalogStatus,
|
|
42
|
+
type RefreshCatalogOptions,
|
|
43
|
+
} from "./models/catalog.ts";
|
|
44
|
+
export { AiSdkBaseProvider as BaseProvider } from "./ai-sdk/model-provider.ts";
|
|
45
|
+
export {
|
|
46
|
+
mapThinkingToReasoning,
|
|
47
|
+
resolveEffectiveThinking,
|
|
48
|
+
mapToolChoice,
|
|
49
|
+
mapThinkingToProviderOptions,
|
|
50
|
+
mapServiceTierToProviderOptions,
|
|
51
|
+
mapCacheToProviderOptions,
|
|
52
|
+
buildAiSdkCallOptions,
|
|
53
|
+
withAiSdkRetries,
|
|
54
|
+
isTransientAiSdkError,
|
|
55
|
+
} from "./ai-sdk/options.ts";
|
|
56
|
+
export { toConciseProviderError, assertModalitiesSupported } from "./ai-sdk/errors.ts";
|
|
57
|
+
|
|
58
|
+
// Provider Implementations powered by Vercel AI SDK
|
|
59
|
+
export {
|
|
60
|
+
GoogleAIStudioProvider,
|
|
61
|
+
GoogleAiSdkProvider,
|
|
62
|
+
OpenCodeProvider,
|
|
63
|
+
OpenCodeAiSdkProvider,
|
|
64
|
+
OpenRouterProvider,
|
|
65
|
+
OpenRouterAiSdkProvider,
|
|
66
|
+
OpenAIProvider,
|
|
67
|
+
OpenAiAiSdkProvider,
|
|
68
|
+
OpenAICompatibleProvider,
|
|
69
|
+
CustomAiSdkProvider,
|
|
70
|
+
AiSdkBaseProvider,
|
|
71
|
+
createOpenAICompatibleProvider,
|
|
72
|
+
createCustomProvider,
|
|
73
|
+
CustomProvider,
|
|
74
|
+
createGenericModelSpec,
|
|
75
|
+
} from "./ai-sdk/model-provider.ts";
|
|
76
|
+
export type { CustomProviderOptions } from "./ai-sdk/model-provider.ts";
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
GOOGLE_MODELS,
|
|
80
|
+
OPENAI_MODELS,
|
|
81
|
+
OPENCODE_MODELS,
|
|
82
|
+
OPENROUTER_MODELS,
|
|
83
|
+
} from "./models/catalog.ts";
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
isValidThoughtSignature,
|
|
87
|
+
retainThoughtSignature,
|
|
88
|
+
extractGoogleThoughtSignature,
|
|
89
|
+
} from "./utils/thought-signature.ts";
|
|
90
|
+
|
|
91
|
+
export { stripSchemaForGoogle } from "./tools/schema.ts";
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
createExplicitCache,
|
|
95
|
+
retentionToTtlSeconds,
|
|
96
|
+
getPromptCacheRetention,
|
|
97
|
+
clampCacheKey,
|
|
98
|
+
} from "./utils/cache.ts";
|
|
99
|
+
export type {
|
|
100
|
+
CreateExplicitCacheOptions,
|
|
101
|
+
CachedContentMetadata,
|
|
102
|
+
} from "./utils/cache.ts";
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
countTokens,
|
|
107
|
+
estimateTokensFromText,
|
|
108
|
+
estimateTokensFromMessage,
|
|
109
|
+
estimateTokensFromPart,
|
|
110
|
+
} from "./tokens/counter.ts";
|
|
111
|
+
|
|
112
|
+
// Streaming & Events
|
|
113
|
+
export { AssistantMessageEventStream } from "./streaming/event-stream.ts";
|
|
114
|
+
export { SSEParser } from "./streaming/sse-parser.ts";
|
|
115
|
+
|
|
116
|
+
// Responses
|
|
117
|
+
export { AgentResponse } from "./types/response.ts";
|
|
118
|
+
|
|
119
|
+
// Utilities
|
|
120
|
+
export { createSessionId } from "./utils/session.ts";
|
|
121
|
+
export { getApiKey, getEnv } from "./utils/env.ts";
|
|
122
|
+
export { buildSessionHeaders } from "./utils/headers.ts";
|
|
123
|
+
export { normalizeMediaInput, inferMimeType } from "./utils/media.ts";
|
|
124
|
+
export { base64ToBytes, bytesToBase64 } from "./utils/base64.ts";
|
|
125
|
+
export { toJsonSafe, safeStringify } from "./utils/serialization.ts";
|
|
126
|
+
|
|
127
|
+
// Re-export Zod
|
|
128
|
+
export { z };
|
|
129
|
+
|
|
130
|
+
// TypeScript Type Exports
|
|
131
|
+
export type {
|
|
132
|
+
ThinkingLevel,
|
|
133
|
+
ThinkingConfig,
|
|
134
|
+
CacheRetention,
|
|
135
|
+
CacheConfig,
|
|
136
|
+
ServiceTier,
|
|
137
|
+
TokenUsage,
|
|
138
|
+
} from "./types/core.ts";
|
|
139
|
+
|
|
140
|
+
export type {
|
|
141
|
+
Message,
|
|
142
|
+
MessageRole,
|
|
143
|
+
ContentPart,
|
|
144
|
+
TextPart,
|
|
145
|
+
ImagePart,
|
|
146
|
+
AudioPart,
|
|
147
|
+
VideoPart,
|
|
148
|
+
FilePart,
|
|
149
|
+
ToolCallPart,
|
|
150
|
+
ToolResultPart,
|
|
151
|
+
ThinkingPart,
|
|
152
|
+
ProviderContext,
|
|
153
|
+
} from "./types/message.ts";
|
|
154
|
+
|
|
155
|
+
export type {
|
|
156
|
+
ToolDefinition,
|
|
157
|
+
ToolExecuteFn,
|
|
158
|
+
ToolExecutionContext,
|
|
159
|
+
ToolCallRecord,
|
|
160
|
+
ToolResultRecord,
|
|
161
|
+
StandardToolDeclaration,
|
|
162
|
+
} from "./types/tool.ts";
|
|
163
|
+
|
|
164
|
+
export type {
|
|
165
|
+
ModelSpec,
|
|
166
|
+
ModelCapabilities,
|
|
167
|
+
Provider,
|
|
168
|
+
ProviderId,
|
|
169
|
+
ProviderRequestOptions,
|
|
170
|
+
ProviderGenerateResult,
|
|
171
|
+
ProviderRawData,
|
|
172
|
+
} from "./types/model.ts";
|
|
173
|
+
|
|
174
|
+
export type {
|
|
175
|
+
AgentResponseJSON,
|
|
176
|
+
SubAgentExecutionMetadata,
|
|
177
|
+
StreamEvent,
|
|
178
|
+
StreamEventType,
|
|
179
|
+
} from "./types/response.ts";
|
|
180
|
+
|
|
181
|
+
export type {
|
|
182
|
+
AgentConfig,
|
|
183
|
+
AgentRunOptions,
|
|
184
|
+
DynamicSubagentsConfig,
|
|
185
|
+
} from "./types/agent.ts";
|
|
186
|
+
|
|
187
|
+
export type {
|
|
188
|
+
ModelProviderInstance,
|
|
189
|
+
ModelProviderConfig,
|
|
190
|
+
} from "./ai-sdk/registry.ts";
|