agent-accelerator 0.1.0 → 0.3.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/README.md +174 -123
- package/{SYSTEM_PROMPT_AGENT.md → examples/prompts/SYSTEM_PROMPT_AGENT.md} +1 -1
- package/package.json +14 -9
- package/src/agent/agent.ts +385 -73
- package/src/agent/context.ts +1 -0
- package/src/agent/delegation.ts +443 -30
- package/src/agent/loop.ts +183 -53
- package/src/data/README.md +6 -6
- package/src/index.ts +163 -46
- package/src/models/catalog-cache.ts +60 -9
- package/src/models/catalog.ts +55 -8
- package/src/providers/google.ts +926 -0
- package/src/providers/openai-compat.ts +1147 -0
- package/src/providers/openai.ts +959 -0
- package/src/providers/openrouter-responses.ts +949 -0
- package/src/providers/openrouter.ts +1037 -0
- package/src/{ai-sdk → providers}/registry.ts +43 -55
- package/src/providers.ts +492 -0
- package/src/session/store.ts +806 -0
- package/src/streaming/sse-parser.ts +6 -4
- package/src/tools/executor.ts +23 -7
- package/src/tools/schema.ts +21 -11
- package/src/types/agent.ts +33 -2
- package/src/types/core.ts +3 -2
- package/src/types/message.ts +5 -0
- package/src/types/model.ts +3 -7
- package/src/types/provider-payloads.ts +2 -84
- package/src/types/response.ts +24 -0
- package/src/types/tool.ts +8 -0
- package/src/update-models.ts +56 -0
- package/src/utils/cache.ts +1 -1
- package/src/utils/documents.ts +517 -0
- package/src/utils/env.ts +0 -7
- package/src/{ai-sdk → utils}/errors.ts +61 -2
- package/src/utils/headers.ts +10 -20
- package/src/utils/media.ts +5 -2
- package/src/utils/retry.ts +89 -0
- package/src/utils/serialization.ts +15 -0
- package/src/utils/session.ts +36 -0
- package/src/ai-sdk/converters.ts +0 -342
- package/src/ai-sdk/executor.ts +0 -454
- package/src/ai-sdk/index.ts +0 -55
- package/src/ai-sdk/model-provider.ts +0 -303
- package/src/ai-sdk/options.ts +0 -306
- package/src/ai-sdk/provider.ts +0 -415
- package/src/tokens/counter.ts +0 -136
- /package/{SYSTEM_PROMPT.md → examples/prompts/SYSTEM_PROMPT.md} +0 -0
- /package/{SYSTEM_PROMPT_TOOLS.md → examples/prompts/SYSTEM_PROMPT_TOOLS.md} +0 -0
package/src/index.ts
CHANGED
|
@@ -9,21 +9,49 @@ export type { CreateToolOptions } from "./tools/tool.ts";
|
|
|
9
9
|
export { zodToJsonSchema, cleanJsonSchema } from "./tools/schema.ts";
|
|
10
10
|
export { executeToolCalls } from "./tools/executor.ts";
|
|
11
11
|
|
|
12
|
+
// Client-side document conversion (optional anydoc peer — see utils/documents.ts)
|
|
13
|
+
export {
|
|
14
|
+
convertDocumentToMarkdown,
|
|
15
|
+
convertDocumentInput,
|
|
16
|
+
convert_document_to_markdown,
|
|
17
|
+
isAnydocAvailable,
|
|
18
|
+
resolveDocumentFormat,
|
|
19
|
+
truncateMarkdown,
|
|
20
|
+
buildDocumentXml,
|
|
21
|
+
modelSupportsFileInput,
|
|
22
|
+
preprocessFilePartsForBypass,
|
|
23
|
+
DocumentConversionError,
|
|
24
|
+
DEFAULT_DOCUMENT_MAX_CHARS,
|
|
25
|
+
MAX_DOCUMENT_FETCH_BYTES,
|
|
26
|
+
} from "./utils/documents.ts";
|
|
27
|
+
export type { ConvertDocumentOptions, ConvertedDocument } from "./utils/documents.ts";
|
|
28
|
+
|
|
12
29
|
// Multi-Agent Delegation & Tools
|
|
13
30
|
export {
|
|
14
31
|
buildAgentTools,
|
|
32
|
+
agentToTool,
|
|
15
33
|
createSubagentSpawnTool,
|
|
34
|
+
createChildSessionId,
|
|
35
|
+
createFixedChildSessionId,
|
|
36
|
+
isSessionDescendant,
|
|
37
|
+
getSubAgentTrace,
|
|
38
|
+
listSubAgentTraceIds,
|
|
39
|
+
subscribeToSubAgent,
|
|
16
40
|
} from "./agent/delegation.ts";
|
|
17
|
-
export type { DynamicSubagentTask } from "./agent/delegation.ts";
|
|
41
|
+
export type { DynamicSubagentTask, AgentAsToolTarget, SubAgentTrace } from "./agent/delegation.ts";
|
|
18
42
|
|
|
19
|
-
// Providers & Registry — unified multi-provider layer
|
|
43
|
+
// Providers & Registry — unified multi-provider layer, all native REST
|
|
20
44
|
export {
|
|
21
45
|
getProvider,
|
|
22
46
|
resolveModel,
|
|
23
47
|
ModelProvider,
|
|
24
48
|
ensureCustomProvider,
|
|
25
49
|
normalizeProviderPrefix,
|
|
26
|
-
} from "./
|
|
50
|
+
} from "./providers/registry.ts";
|
|
51
|
+
export type {
|
|
52
|
+
ModelProviderInstance,
|
|
53
|
+
ModelProviderConfig,
|
|
54
|
+
} from "./providers/registry.ts";
|
|
27
55
|
export {
|
|
28
56
|
getModelFromCatalog,
|
|
29
57
|
getModelThinkingInfo,
|
|
@@ -37,48 +65,78 @@ export {
|
|
|
37
65
|
getCatalogTTL,
|
|
38
66
|
getCacheDir,
|
|
39
67
|
getCacheFilePath,
|
|
68
|
+
isValidCatalogPayload,
|
|
69
|
+
createGenericModelSpec,
|
|
40
70
|
DEFAULT_CATALOG_TTL_MS,
|
|
41
71
|
type CatalogStatus,
|
|
42
72
|
type RefreshCatalogOptions,
|
|
43
73
|
} from "./models/catalog.ts";
|
|
44
|
-
export {
|
|
74
|
+
export { resolveEffectiveThinking } from "./agent/agent.ts";
|
|
75
|
+
export { withRetries, isTransientError } from "./utils/retry.ts";
|
|
76
|
+
export { toConciseProviderError, assertModalitiesSupported, assertNoVideoPartsOnResponses } from "./utils/errors.ts";
|
|
77
|
+
// Native provider implementations. `openrouter-responses.ts` (discontinued
|
|
78
|
+
// beta-Responses transport) stays importable directly but is wired nowhere.
|
|
45
79
|
export {
|
|
46
|
-
|
|
47
|
-
|
|
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,
|
|
80
|
+
OpenAICompatibleChatProvider,
|
|
81
|
+
OpenAICompatibleChatProvider as OpenAICompatibleProvider,
|
|
71
82
|
createOpenAICompatibleProvider,
|
|
72
83
|
createCustomProvider,
|
|
73
84
|
CustomProvider,
|
|
74
|
-
|
|
75
|
-
} from "./
|
|
76
|
-
|
|
85
|
+
} from "./providers/openai-compat.ts";
|
|
86
|
+
export type { CustomProviderOptions } from "./providers/openai-compat.ts";
|
|
87
|
+
|
|
88
|
+
// Canonical provider contract (provider-agnostic) + native adapters.
|
|
89
|
+
export {
|
|
90
|
+
GoogleInteractionsProvider,
|
|
91
|
+
GoogleInteractionsProvider as GoogleAIStudioProvider,
|
|
92
|
+
clearInteractionChains,
|
|
93
|
+
} from "./providers/google.ts";
|
|
94
|
+
export {
|
|
95
|
+
OpenRouterChatCompletionsProvider,
|
|
96
|
+
OpenRouterChatCompletionsProvider as OpenRouterProvider,
|
|
97
|
+
} from "./providers/openrouter.ts";
|
|
98
|
+
// Discontinued beta-Responses transport, retained frozen as migration
|
|
99
|
+
// evidence (importable via `./providers/openrouter-responses.ts`, not wired
|
|
100
|
+
// anywhere): OpenRouterResponsesProvider.
|
|
101
|
+
export {
|
|
102
|
+
OpenAIResponsesProvider,
|
|
103
|
+
OpenAIResponsesProvider as OpenAIProvider,
|
|
104
|
+
} from "./providers/openai.ts";
|
|
105
|
+
export {
|
|
106
|
+
emitProviderWarning,
|
|
107
|
+
clearEmittedWarnings,
|
|
108
|
+
noteProviderTurn,
|
|
109
|
+
lastProviderFor,
|
|
110
|
+
isMixedProviderSession,
|
|
111
|
+
clearSessionRouting,
|
|
112
|
+
mapThinkingLevelToGoogle,
|
|
113
|
+
mapServiceTierToGoogle,
|
|
114
|
+
applyCacheForGoogle,
|
|
115
|
+
mapThinkingLevelToOpenRouter,
|
|
116
|
+
mapServiceTierToOpenRouter,
|
|
117
|
+
applyCacheForOpenRouter,
|
|
118
|
+
mapToolChoiceToOpenRouter,
|
|
119
|
+
mapThinkingLevelToOpenRouterChat,
|
|
120
|
+
mapToolChoiceToOpenRouterChat,
|
|
121
|
+
mapThinkingLevelToOpenAI,
|
|
122
|
+
mapServiceTierToOpenAI,
|
|
123
|
+
applyCacheForOpenAI,
|
|
124
|
+
applyCacheForCustom,
|
|
125
|
+
mapToolChoiceToOpenAI,
|
|
126
|
+
normalizeToolChoice,
|
|
127
|
+
parseStreamedToolArguments,
|
|
128
|
+
} from "./providers.ts";
|
|
129
|
+
export type {
|
|
130
|
+
ProviderCapabilityStatus,
|
|
131
|
+
CanonicalToolChoiceMode,
|
|
132
|
+
OpenRouterToolChoice,
|
|
133
|
+
OpenRouterChatToolChoice,
|
|
134
|
+
OpenAIToolChoice,
|
|
135
|
+
} from "./providers.ts";
|
|
77
136
|
|
|
78
137
|
export {
|
|
79
138
|
GOOGLE_MODELS,
|
|
80
139
|
OPENAI_MODELS,
|
|
81
|
-
OPENCODE_MODELS,
|
|
82
140
|
OPENROUTER_MODELS,
|
|
83
141
|
} from "./models/catalog.ts";
|
|
84
142
|
|
|
@@ -101,14 +159,6 @@ export type {
|
|
|
101
159
|
CachedContentMetadata,
|
|
102
160
|
} from "./utils/cache.ts";
|
|
103
161
|
|
|
104
|
-
|
|
105
|
-
export {
|
|
106
|
-
countTokens,
|
|
107
|
-
estimateTokensFromText,
|
|
108
|
-
estimateTokensFromMessage,
|
|
109
|
-
estimateTokensFromPart,
|
|
110
|
-
} from "./tokens/counter.ts";
|
|
111
|
-
|
|
112
162
|
// Streaming & Events
|
|
113
163
|
export { AssistantMessageEventStream } from "./streaming/event-stream.ts";
|
|
114
164
|
export { SSEParser } from "./streaming/sse-parser.ts";
|
|
@@ -116,13 +166,37 @@ export { SSEParser } from "./streaming/sse-parser.ts";
|
|
|
116
166
|
// Responses
|
|
117
167
|
export { AgentResponse } from "./types/response.ts";
|
|
118
168
|
|
|
169
|
+
// Session persistence & telemetry (conversation history + cost rollup)
|
|
170
|
+
export {
|
|
171
|
+
SessionTelemetry,
|
|
172
|
+
loadSessionFile,
|
|
173
|
+
saveSessionFile,
|
|
174
|
+
loadSessionDir,
|
|
175
|
+
saveSessionDir,
|
|
176
|
+
writeFileAtomic,
|
|
177
|
+
findLatestSessionDir,
|
|
178
|
+
sessionDirFor,
|
|
179
|
+
extractMediaToDir,
|
|
180
|
+
resolveMediaPaths,
|
|
181
|
+
buildSessionData,
|
|
182
|
+
serializeSession,
|
|
183
|
+
deserializeSession,
|
|
184
|
+
getSessionContextWindow,
|
|
185
|
+
computeSessionTurnCost,
|
|
186
|
+
formatSessionTokens,
|
|
187
|
+
formatSessionCost,
|
|
188
|
+
formatSessionBanner,
|
|
189
|
+
emptyTotals,
|
|
190
|
+
} from "./session/store.ts";
|
|
191
|
+
export type { PersistedAgentSession, SessionTotals, SessionAgentLike, LoadedSessionDir, PersistedSubAgentTrace } from "./session/store.ts";
|
|
192
|
+
|
|
119
193
|
// Utilities
|
|
120
|
-
export { createSessionId } from "./utils/session.ts";
|
|
194
|
+
export { createSessionId, hashSessionPart, createTrackingId } from "./utils/session.ts";
|
|
121
195
|
export { getApiKey, getEnv } from "./utils/env.ts";
|
|
122
196
|
export { buildSessionHeaders } from "./utils/headers.ts";
|
|
123
197
|
export { normalizeMediaInput, inferMimeType } from "./utils/media.ts";
|
|
124
198
|
export { base64ToBytes, bytesToBase64 } from "./utils/base64.ts";
|
|
125
|
-
export { toJsonSafe, safeStringify } from "./utils/serialization.ts";
|
|
199
|
+
export { toJsonSafe, safeStringify, escapeXml } from "./utils/serialization.ts";
|
|
126
200
|
|
|
127
201
|
// Re-export Zod
|
|
128
202
|
export { z };
|
|
@@ -174,6 +248,7 @@ export type {
|
|
|
174
248
|
export type {
|
|
175
249
|
AgentResponseJSON,
|
|
176
250
|
SubAgentExecutionMetadata,
|
|
251
|
+
SubAgentStep,
|
|
177
252
|
StreamEvent,
|
|
178
253
|
StreamEventType,
|
|
179
254
|
} from "./types/response.ts";
|
|
@@ -181,10 +256,52 @@ export type {
|
|
|
181
256
|
export type {
|
|
182
257
|
AgentConfig,
|
|
183
258
|
AgentRunOptions,
|
|
259
|
+
AgentTurnEvent,
|
|
184
260
|
DynamicSubagentsConfig,
|
|
185
261
|
} from "./types/agent.ts";
|
|
186
262
|
|
|
263
|
+
// Provider wire payload types (back-compat inspection of raw requests/responses,
|
|
264
|
+
// e.g. `res.raw.request.body as OpenAIChatCompletionRequest`).
|
|
265
|
+
// NOTE: wire `OpenAIToolChoice` intentionally omitted — it duplicates the
|
|
266
|
+
// canonical `OpenAIToolChoice` exported above (same shape); use that one.
|
|
187
267
|
export type {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
268
|
+
GoogleThinkingLevel,
|
|
269
|
+
GoogleThinkingConfig,
|
|
270
|
+
GoogleFunctionCallingMode,
|
|
271
|
+
GoogleFunctionCallingConfig,
|
|
272
|
+
GoogleToolConfig,
|
|
273
|
+
GoogleFunctionDeclaration,
|
|
274
|
+
GoogleTool,
|
|
275
|
+
GoogleBlob,
|
|
276
|
+
GooglePart,
|
|
277
|
+
GoogleContent,
|
|
278
|
+
GoogleGenerationConfig,
|
|
279
|
+
GoogleCandidate,
|
|
280
|
+
GoogleUsageMetadata,
|
|
281
|
+
GoogleGenerateContentRequest,
|
|
282
|
+
GoogleGenerateContentResponse,
|
|
283
|
+
OpenRouterProviderRouting,
|
|
284
|
+
OpenRouterReasoning,
|
|
285
|
+
OpenRouterParameters,
|
|
286
|
+
OpenRouterUsage,
|
|
287
|
+
OpenRouterChatRequest,
|
|
288
|
+
OpenRouterResponse,
|
|
289
|
+
OpenAIMessageRole,
|
|
290
|
+
OpenAIReasoningEffort,
|
|
291
|
+
OpenAIServiceTier,
|
|
292
|
+
OpenAITextPart,
|
|
293
|
+
OpenAIImageUrlPart,
|
|
294
|
+
OpenAIInputAudioPart,
|
|
295
|
+
OpenAIVideoUrlPart,
|
|
296
|
+
OpenAIContentPart,
|
|
297
|
+
OpenAIToolCall,
|
|
298
|
+
OpenAIMessage,
|
|
299
|
+
OpenAITool,
|
|
300
|
+
OpenAIUsage,
|
|
301
|
+
OpenAIChoice,
|
|
302
|
+
OpenAIDelta,
|
|
303
|
+
OpenAIChunkChoice,
|
|
304
|
+
OpenAIChatCompletionRequest,
|
|
305
|
+
OpenAIChatCompletionResponse,
|
|
306
|
+
OpenAIChatCompletionChunk,
|
|
307
|
+
} from "./types/provider-payloads.ts";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
|
+
import { getEnv } from "../utils/env.ts";
|
|
3
4
|
|
|
4
5
|
/** Default TTL: 12 Hours (in milliseconds). */
|
|
5
6
|
export const DEFAULT_CATALOG_TTL_MS = 12 * 60 * 60 * 1000;
|
|
@@ -65,14 +66,20 @@ function notifyUpdateListeners(): void {
|
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Catalog cache directory. Defaults to `src/data` (repo convention); override
|
|
71
|
+
* with `AGENT_CACHE_DIR` when embedding as a package or running on a
|
|
72
|
+
* read-only filesystem (serverless/containers).
|
|
73
|
+
*/
|
|
69
74
|
export function getCacheDir(): string {
|
|
75
|
+
const override = getEnv("AGENT_CACHE_DIR");
|
|
76
|
+
if (override && override.trim()) return path.resolve(override.trim());
|
|
70
77
|
return path.resolve(process.cwd(), "src/data");
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
/** Non-configurable cache file path: src/data/models
|
|
80
|
+
/** Non-configurable cache file path: src/data/models.dev.json */
|
|
74
81
|
export function getCacheFilePath(): string {
|
|
75
|
-
return path.resolve(process.cwd(), "src/data/models
|
|
82
|
+
return path.resolve(process.cwd(), "src/data/models.dev.json");
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
function readJsonFileSync(filePath: string): any {
|
|
@@ -99,7 +106,7 @@ let activeFetchedAt: number | undefined = undefined;
|
|
|
99
106
|
let activeTtlMs: number = globalCatalogTtlMs;
|
|
100
107
|
let activeFromCache = false;
|
|
101
108
|
|
|
102
|
-
// Synchronous bootstrap: load from src/data/models
|
|
109
|
+
// Synchronous bootstrap: load from src/data/models.dev.json if present
|
|
103
110
|
function initializeCatalogSync(): void {
|
|
104
111
|
const cachePath = getCacheFilePath();
|
|
105
112
|
const cached = readJsonFileSync(cachePath);
|
|
@@ -165,9 +172,30 @@ export function getCatalogStatus(): CatalogStatus {
|
|
|
165
172
|
};
|
|
166
173
|
}
|
|
167
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Structural check for a models.dev catalog payload: a map of provider ids
|
|
177
|
+
* to entries that each carry a `models` map. Rejects chat-completion
|
|
178
|
+
* payloads, error envelopes, and other non-catalog JSON (e.g. from mocked
|
|
179
|
+
* `fetch` in tests) BEFORE they can overwrite the good on-disk cache.
|
|
180
|
+
*/
|
|
181
|
+
export function isValidCatalogPayload(data: unknown): data is Record<string, any> {
|
|
182
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return false;
|
|
183
|
+
const entries = Object.entries(data as Record<string, unknown>);
|
|
184
|
+
if (entries.length < 3) return false;
|
|
185
|
+
let providersWithModels = 0;
|
|
186
|
+
for (const [, value] of entries) {
|
|
187
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
188
|
+
const models = (value as Record<string, unknown>).models;
|
|
189
|
+
if (!models || typeof models !== "object" || Array.isArray(models)) return false;
|
|
190
|
+
if (Object.keys(models).length > 0) providersWithModels++;
|
|
191
|
+
}
|
|
192
|
+
// Guard against degenerate-but-shaped payloads (e.g. `{a:{models:{}}}`).
|
|
193
|
+
return providersWithModels >= 3;
|
|
194
|
+
}
|
|
195
|
+
|
|
168
196
|
/**
|
|
169
197
|
* Refreshes the model catalog by downloading from models.dev
|
|
170
|
-
* directly into src/data/models
|
|
198
|
+
* directly into src/data/models.dev.json with a 12-hour TTL.
|
|
171
199
|
*/
|
|
172
200
|
export async function refreshModelCatalog(options: RefreshCatalogOptions = {}): Promise<CatalogStatus> {
|
|
173
201
|
const effectiveTtl = options.ttlMs ?? globalCatalogTtlMs;
|
|
@@ -211,6 +239,21 @@ export async function refreshModelCatalog(options: RefreshCatalogOptions = {}):
|
|
|
211
239
|
}
|
|
212
240
|
|
|
213
241
|
freshData = (await res.json()) as Record<string, any>;
|
|
242
|
+
|
|
243
|
+
// Never let a non-catalog payload (mocked fetch, proxy error page,
|
|
244
|
+
// chat-completion stub) overwrite the good on-disk cache.
|
|
245
|
+
if (!isValidCatalogPayload(freshData)) {
|
|
246
|
+
clearTimeout(timer);
|
|
247
|
+
const existing = readJsonFileSync(cachePath);
|
|
248
|
+
if (existing && existing.data) {
|
|
249
|
+
activeCatalog = existing.data;
|
|
250
|
+
activeFetchedAt = existing.fetchedAt;
|
|
251
|
+
activeTtlMs = existing.ttlMs || effectiveTtl;
|
|
252
|
+
activeFromCache = true;
|
|
253
|
+
notifyUpdateListeners();
|
|
254
|
+
}
|
|
255
|
+
return getCatalogStatus();
|
|
256
|
+
}
|
|
214
257
|
} catch (err: any) {
|
|
215
258
|
clearTimeout(timer);
|
|
216
259
|
// If download fails, retain disk cache if available
|
|
@@ -236,15 +279,23 @@ export async function refreshModelCatalog(options: RefreshCatalogOptions = {}):
|
|
|
236
279
|
data: freshData,
|
|
237
280
|
};
|
|
238
281
|
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// Update in-memory state
|
|
282
|
+
// Update in-memory state FIRST so a read-only filesystem still serves the
|
|
283
|
+
// fresh catalog for this process; disk persistence below is best-effort.
|
|
243
284
|
activeCatalog = freshData;
|
|
244
285
|
activeFetchedAt = fetchedAt;
|
|
245
286
|
activeTtlMs = effectiveTtl;
|
|
246
287
|
activeFromCache = true;
|
|
247
288
|
|
|
289
|
+
// Save to src/data/models.dev.json (or the AGENT_CACHE_DIR override)
|
|
290
|
+
try {
|
|
291
|
+
writeJsonFileSync(cachePath, cachePayload);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
activeFromCache = false;
|
|
294
|
+
console.warn(
|
|
295
|
+
`[Agent Accelerator] Could not write model catalog cache to ${cachePath} (${err instanceof Error ? err.message : String(err)}). Continuing with the in-memory catalog.`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
248
299
|
notifyUpdateListeners();
|
|
249
300
|
return getCatalogStatus();
|
|
250
301
|
}
|
package/src/models/catalog.ts
CHANGED
|
@@ -22,12 +22,10 @@ import type { ThinkingLevel } from "../types/core.ts";
|
|
|
22
22
|
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
// Provider aliases — maps our internal ids to models.dev keys
|
|
25
|
-
// battle-tested:
|
|
25
|
+
// battle-tested: google covers vertex variants
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
27
|
const PROVIDER_ALIASES: Record<string, string[]> = {
|
|
28
28
|
google: ["google", "google-vertex", "google-vertex-anthropic"],
|
|
29
|
-
opencode: ["opencode", "opencode-go"],
|
|
30
|
-
"opencode-go": ["opencode-go", "opencode"],
|
|
31
29
|
openrouter: ["openrouter"],
|
|
32
30
|
openai: ["openai"],
|
|
33
31
|
};
|
|
@@ -42,6 +40,11 @@ const MODALITY_OVERRIDES: Record<string, { input?: string[]; output?: string[] }
|
|
|
42
40
|
// verified end-to-end via examples/08. If routing changes, the runtime
|
|
43
41
|
// 404 still surfaces as a one-line error.
|
|
44
42
|
"openrouter/nvidia/nemotron-3.5-lightning:free": { input: ["text", "pdf"] },
|
|
43
|
+
// Live-verified 2026-09-24: `stealth/space-bunny-alpha` accepts PDF
|
|
44
|
+
// `input_file` over Responses and PDFs via the file-parser plugin over Chat
|
|
45
|
+
// Completions (Berkshire letter + sample-files PDF both completed), though
|
|
46
|
+
// models.dev lists text/image/video only.
|
|
47
|
+
"openrouter/stealth/space-bunny-alpha": { input: ["text", "image", "video", "pdf"] },
|
|
45
48
|
};
|
|
46
49
|
|
|
47
50
|
function applyModalityOverrides(provider: string, modelId: string, base: ModelModalities): ModelModalities {
|
|
@@ -241,7 +244,7 @@ export function getModelThinkingInfo(provider: string, modelId: string): ModelTh
|
|
|
241
244
|
if (!spec) {
|
|
242
245
|
return {
|
|
243
246
|
supportsThinking: true,
|
|
244
|
-
allowedLevels: ["none", "minimal", "low", "medium", "high", "xhigh", "dynamic"],
|
|
247
|
+
allowedLevels: ["none", "minimal", "low", "medium", "high", "xhigh", "max", "dynamic"],
|
|
245
248
|
supportsDisable: true,
|
|
246
249
|
description: "Model not found in catalog; generic thinking levels allowed.",
|
|
247
250
|
};
|
|
@@ -292,6 +295,7 @@ export function getModelThinkingInfo(provider: string, modelId: string): ModelTh
|
|
|
292
295
|
allowed.add("medium");
|
|
293
296
|
allowed.add("high");
|
|
294
297
|
allowed.add("xhigh");
|
|
298
|
+
allowed.add("max");
|
|
295
299
|
}
|
|
296
300
|
|
|
297
301
|
// Fixed reasoning model (no reasoning_options) e.g. DeepSeek-R1, QwQ-32B
|
|
@@ -305,6 +309,11 @@ export function getModelThinkingInfo(provider: string, modelId: string): ModelTh
|
|
|
305
309
|
};
|
|
306
310
|
}
|
|
307
311
|
|
|
312
|
+
// "dynamic" means server default (the level is omitted from the request),
|
|
313
|
+
// so it is expressible on every configurable thinking model regardless of
|
|
314
|
+
// which concrete effort/toggle/budget options the catalog lists.
|
|
315
|
+
allowed.add("dynamic");
|
|
316
|
+
|
|
308
317
|
const allowedLevels = Array.from(allowed);
|
|
309
318
|
const supportsDisable = allowed.has("none") || !!toggleOpt || Boolean(budgetOpt && (budgetOpt.min === undefined || budgetOpt.min <= 0));
|
|
310
319
|
|
|
@@ -437,7 +446,7 @@ export function validateModelThinking(provider: string, modelId: string, request
|
|
|
437
446
|
|
|
438
447
|
// ---------------------------------------------------------------------------
|
|
439
448
|
// getModelsForProvider — battle-tested view for BaseProvider.models
|
|
440
|
-
//
|
|
449
|
+
// Total context length now comes from catalog, not stale hardcoded file.
|
|
441
450
|
// ---------------------------------------------------------------------------
|
|
442
451
|
/**
|
|
443
452
|
* Returns normalized catalog specs for a provider and its configured aliases.
|
|
@@ -466,7 +475,6 @@ export function getModelsForProvider(provider: string): ModelSpec[] {
|
|
|
466
475
|
|
|
467
476
|
export const GOOGLE_MODELS: ModelSpec[] = [...getModelsForProvider("google")];
|
|
468
477
|
export const OPENAI_MODELS: ModelSpec[] = [...getModelsForProvider("openai")];
|
|
469
|
-
export const OPENCODE_MODELS: ModelSpec[] = [...getModelsForProvider("opencode")];
|
|
470
478
|
export const OPENROUTER_MODELS: ModelSpec[] = [...getModelsForProvider("openrouter")];
|
|
471
479
|
|
|
472
480
|
function refreshExportedModels(): void {
|
|
@@ -474,8 +482,6 @@ function refreshExportedModels(): void {
|
|
|
474
482
|
GOOGLE_MODELS.push(...getModelsForProvider("google"));
|
|
475
483
|
OPENAI_MODELS.length = 0;
|
|
476
484
|
OPENAI_MODELS.push(...getModelsForProvider("openai"));
|
|
477
|
-
OPENCODE_MODELS.length = 0;
|
|
478
|
-
OPENCODE_MODELS.push(...getModelsForProvider("opencode"));
|
|
479
485
|
OPENROUTER_MODELS.length = 0;
|
|
480
486
|
OPENROUTER_MODELS.push(...getModelsForProvider("openrouter"));
|
|
481
487
|
}
|
|
@@ -497,7 +503,48 @@ export {
|
|
|
497
503
|
getCatalogTTL,
|
|
498
504
|
getCacheDir,
|
|
499
505
|
getCacheFilePath,
|
|
506
|
+
isValidCatalogPayload,
|
|
500
507
|
DEFAULT_CATALOG_TTL_MS,
|
|
501
508
|
type CatalogStatus,
|
|
502
509
|
type RefreshCatalogOptions,
|
|
503
510
|
} from "./catalog-cache.ts";
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Permissive placeholder so custom endpoints never fail preflight:
|
|
514
|
+
* allows every ThinkingLevel (none -> max + dynamic).
|
|
515
|
+
* @example `const spec = createGenericModelSpec("groq", "llama-3.3-70b-versatile");`
|
|
516
|
+
*/
|
|
517
|
+
export function createGenericModelSpec(provider: string, modelId: string): ModelSpec {
|
|
518
|
+
const clean = modelId.includes("/") ? modelId.split("/").slice(1).join("/") : modelId;
|
|
519
|
+
return {
|
|
520
|
+
id: clean,
|
|
521
|
+
provider: provider as ProviderId,
|
|
522
|
+
name: clean,
|
|
523
|
+
contextWindow: 128000,
|
|
524
|
+
maxOutputTokens: 8192,
|
|
525
|
+
limit: { context: 128000, output: 8192 },
|
|
526
|
+
cost: {},
|
|
527
|
+
modalities: { input: ["text"], output: ["text"] },
|
|
528
|
+
reasoning: true,
|
|
529
|
+
reasoning_options: [
|
|
530
|
+
{ type: "toggle" },
|
|
531
|
+
{ type: "effort", values: ["minimal", "low", "medium", "high", "xhigh", "max"] },
|
|
532
|
+
{ type: "budget_tokens", min: 0, max: 128000 },
|
|
533
|
+
],
|
|
534
|
+
tool_call: true,
|
|
535
|
+
capabilities: {
|
|
536
|
+
supportsThinking: true,
|
|
537
|
+
supportsThinkingLevel: true,
|
|
538
|
+
supportsThinkingBudget: true,
|
|
539
|
+
supportsReasoningToggle: true,
|
|
540
|
+
supportsReasoningEffort: true,
|
|
541
|
+
supportsImplicitCaching: true,
|
|
542
|
+
supportsExplicitCaching: false,
|
|
543
|
+
supportsLongCacheRetention: false,
|
|
544
|
+
supportsParallelToolCalls: true,
|
|
545
|
+
supportsStreaming: true,
|
|
546
|
+
modalities: ["text"],
|
|
547
|
+
},
|
|
548
|
+
pricing: {},
|
|
549
|
+
};
|
|
550
|
+
}
|