@cuylabs/agent-core 0.4.0 → 0.5.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 +57 -8
- package/dist/builder-RcTZuYnO.d.ts +34 -0
- package/dist/capabilities/index.d.ts +97 -0
- package/dist/capabilities/index.js +46 -0
- package/dist/chunk-6TDTQJ4P.js +116 -0
- package/dist/chunk-7MUFEN4K.js +559 -0
- package/dist/chunk-BDBZ3SLK.js +745 -0
- package/dist/chunk-DWYX7ASF.js +26 -0
- package/dist/chunk-FG4MD5MU.js +54 -0
- package/dist/chunk-IMGQOTU2.js +2019 -0
- package/dist/chunk-IVUJDISU.js +556 -0
- package/dist/chunk-LRHOS4ZN.js +584 -0
- package/dist/chunk-OTUGSCED.js +691 -0
- package/dist/chunk-P6YF7USR.js +182 -0
- package/dist/chunk-QAQADS4X.js +258 -0
- package/dist/chunk-QWFMX226.js +879 -0
- package/dist/{chunk-6VKLWNRE.js → chunk-SDSBEQXG.js} +1 -132
- package/dist/chunk-VBWWUHWI.js +724 -0
- package/dist/chunk-VEKUXUVF.js +41 -0
- package/dist/chunk-X635CM2F.js +305 -0
- package/dist/chunk-YUUJK53A.js +91 -0
- package/dist/chunk-ZXAKHMWH.js +283 -0
- package/dist/config-D2xeGEHK.d.ts +52 -0
- package/dist/context/index.d.ts +259 -0
- package/dist/context/index.js +26 -0
- package/dist/identifiers-BLUxFqV_.d.ts +12 -0
- package/dist/index-p0kOsVsE.d.ts +1067 -0
- package/dist/index-tmhaADz5.d.ts +198 -0
- package/dist/index.d.ts +210 -5736
- package/dist/index.js +2126 -7766
- package/dist/mcp/index.d.ts +26 -0
- package/dist/mcp/index.js +14 -0
- package/dist/messages-BYWGn8TY.d.ts +110 -0
- package/dist/middleware/index.d.ts +7 -0
- package/dist/middleware/index.js +12 -0
- package/dist/models/index.d.ts +33 -0
- package/dist/models/index.js +12 -0
- package/dist/network-D76DS5ot.d.ts +5 -0
- package/dist/prompt/index.d.ts +224 -0
- package/dist/prompt/index.js +45 -0
- package/dist/reasoning/index.d.ts +71 -0
- package/dist/reasoning/index.js +47 -0
- package/dist/registry-CuRWWtcT.d.ts +164 -0
- package/dist/resolver-DOfZ-xuk.d.ts +254 -0
- package/dist/runner-C7aMP_x3.d.ts +596 -0
- package/dist/runtime/index.d.ts +357 -0
- package/dist/runtime/index.js +64 -0
- package/dist/session-manager-Uawm2Le7.d.ts +274 -0
- package/dist/skill/index.d.ts +103 -0
- package/dist/skill/index.js +39 -0
- package/dist/storage/index.d.ts +167 -0
- package/dist/storage/index.js +50 -0
- package/dist/sub-agent/index.d.ts +14 -0
- package/dist/sub-agent/index.js +15 -0
- package/dist/tool/index.d.ts +173 -1
- package/dist/tool/index.js +12 -3
- package/dist/tool-DYp6-cC3.d.ts +239 -0
- package/dist/tool-pFAnJc5Y.d.ts +419 -0
- package/dist/tracker-DClqYqTj.d.ts +96 -0
- package/dist/tracking/index.d.ts +109 -0
- package/dist/tracking/index.js +20 -0
- package/dist/types-CQaXbRsS.d.ts +47 -0
- package/dist/types-MM1JoX5T.d.ts +810 -0
- package/dist/types-VQgymC1N.d.ts +156 -0
- package/package.json +89 -5
- package/dist/index-BlSTfS-W.d.ts +0 -470
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getModelId,
|
|
3
|
+
getProviderId
|
|
4
|
+
} from "./chunk-DWYX7ASF.js";
|
|
5
|
+
|
|
6
|
+
// src/capabilities/types.ts
|
|
7
|
+
var SourcePriority = /* @__PURE__ */ ((SourcePriority3) => {
|
|
8
|
+
SourcePriority3[SourcePriority3["UserConfig"] = 0] = "UserConfig";
|
|
9
|
+
SourcePriority3[SourcePriority3["LocalCache"] = 1] = "LocalCache";
|
|
10
|
+
SourcePriority3[SourcePriority3["BundledData"] = 2] = "BundledData";
|
|
11
|
+
SourcePriority3[SourcePriority3["PatternMatch"] = 3] = "PatternMatch";
|
|
12
|
+
SourcePriority3[SourcePriority3["RemoteAPI"] = 4] = "RemoteAPI";
|
|
13
|
+
return SourcePriority3;
|
|
14
|
+
})(SourcePriority || {});
|
|
15
|
+
var DEFAULT_RESOLVER_OPTIONS = {
|
|
16
|
+
enableRemoteFetch: false,
|
|
17
|
+
remoteApiUrl: "https://models.dev",
|
|
18
|
+
cachePath: ".agent-core/cache",
|
|
19
|
+
cacheTtlMs: 60 * 60 * 1e3,
|
|
20
|
+
// 1 hour
|
|
21
|
+
networkTimeoutMs: 10 * 1e3,
|
|
22
|
+
// 10 seconds
|
|
23
|
+
modelOverrides: {}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/capabilities/patterns.ts
|
|
27
|
+
var REASONING_PATTERNS = [
|
|
28
|
+
// OpenAI o-series
|
|
29
|
+
{
|
|
30
|
+
pattern: /^o[134]-?(mini|pro|preview)?$/i,
|
|
31
|
+
provider: "openai",
|
|
32
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
33
|
+
compatibility: { supportsReasoningEffort: true, thinkingFormat: "openai" },
|
|
34
|
+
confidence: 0.95
|
|
35
|
+
},
|
|
36
|
+
// OpenAI GPT-5.x
|
|
37
|
+
{
|
|
38
|
+
pattern: /gpt-?5(\.\d)?/i,
|
|
39
|
+
provider: "openai",
|
|
40
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
41
|
+
compatibility: { supportsReasoningEffort: true, thinkingFormat: "openai" },
|
|
42
|
+
confidence: 0.9
|
|
43
|
+
},
|
|
44
|
+
// DeepSeek R1 variants
|
|
45
|
+
{
|
|
46
|
+
pattern: /deepseek[_-]?r1|r1[_-]distill/i,
|
|
47
|
+
capabilities: { reasoning: true, toolCalling: false },
|
|
48
|
+
confidence: 0.95
|
|
49
|
+
},
|
|
50
|
+
// Anthropic Claude with thinking
|
|
51
|
+
{
|
|
52
|
+
pattern: /claude.*thinking|thinking.*claude/i,
|
|
53
|
+
provider: "anthropic",
|
|
54
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
55
|
+
compatibility: { thinkingFormat: "anthropic" },
|
|
56
|
+
confidence: 0.9
|
|
57
|
+
},
|
|
58
|
+
// Claude 4.x series (reasoning capable)
|
|
59
|
+
{
|
|
60
|
+
pattern: /claude[_-]?(opus|sonnet)[_-]?4/i,
|
|
61
|
+
provider: "anthropic",
|
|
62
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
63
|
+
compatibility: { thinkingFormat: "anthropic" },
|
|
64
|
+
confidence: 0.85
|
|
65
|
+
},
|
|
66
|
+
// Gemini thinking models
|
|
67
|
+
{
|
|
68
|
+
pattern: /gemini.*thinking|gemini[_-]?2\.5[_-]?pro/i,
|
|
69
|
+
provider: "google",
|
|
70
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
71
|
+
compatibility: { thinkingFormat: "google" },
|
|
72
|
+
confidence: 0.85
|
|
73
|
+
},
|
|
74
|
+
// Gemini 3.x (future-proofing)
|
|
75
|
+
{
|
|
76
|
+
pattern: /gemini[_-]?3/i,
|
|
77
|
+
provider: "google",
|
|
78
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
79
|
+
compatibility: { thinkingFormat: "google" },
|
|
80
|
+
confidence: 0.8
|
|
81
|
+
},
|
|
82
|
+
// Grok reasoning models
|
|
83
|
+
{
|
|
84
|
+
pattern: /grok[_-]?\d[_-]?(mini|reasoning)/i,
|
|
85
|
+
provider: "xai",
|
|
86
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
87
|
+
confidence: 0.85
|
|
88
|
+
},
|
|
89
|
+
// Qwen thinking models
|
|
90
|
+
{
|
|
91
|
+
pattern: /qwen.*thinking|qwen3/i,
|
|
92
|
+
capabilities: { reasoning: true, toolCalling: true },
|
|
93
|
+
confidence: 0.8
|
|
94
|
+
},
|
|
95
|
+
// Generic reasoning/thinking in name
|
|
96
|
+
{
|
|
97
|
+
pattern: /reasoning|thinking/i,
|
|
98
|
+
capabilities: { reasoning: true },
|
|
99
|
+
confidence: 0.7
|
|
100
|
+
}
|
|
101
|
+
];
|
|
102
|
+
var PROVIDER_PATTERNS = [
|
|
103
|
+
{ pattern: /^(gpt|o[134]|chatgpt|davinci)/i, provider: "openai" },
|
|
104
|
+
{ pattern: /^claude/i, provider: "anthropic" },
|
|
105
|
+
{ pattern: /^gemini|^palm/i, provider: "google" },
|
|
106
|
+
{ pattern: /^grok/i, provider: "xai" },
|
|
107
|
+
{ pattern: /^deepseek/i, provider: "deepseek" },
|
|
108
|
+
{ pattern: /^mistral|^mixtral|codestral/i, provider: "mistral" },
|
|
109
|
+
{ pattern: /^llama/i, provider: "meta" },
|
|
110
|
+
{ pattern: /^qwen/i, provider: "alibaba" },
|
|
111
|
+
{ pattern: /^command/i, provider: "cohere" }
|
|
112
|
+
];
|
|
113
|
+
function inferProvider(modelId) {
|
|
114
|
+
const normalized = modelId.toLowerCase();
|
|
115
|
+
for (const { pattern, provider } of PROVIDER_PATTERNS) {
|
|
116
|
+
if (pattern.test(normalized)) {
|
|
117
|
+
return provider;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (modelId.includes("/")) {
|
|
121
|
+
return modelId.split("/")[0];
|
|
122
|
+
}
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
function matchPatterns(modelId, providerHint) {
|
|
126
|
+
const normalized = modelId.toLowerCase();
|
|
127
|
+
for (const rule of REASONING_PATTERNS) {
|
|
128
|
+
if (rule.provider && providerHint && rule.provider !== providerHint) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const matches = typeof rule.pattern === "string" ? normalized.includes(rule.pattern.toLowerCase()) : rule.pattern.test(normalized);
|
|
132
|
+
if (matches) {
|
|
133
|
+
return { rule, confidence: rule.confidence };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
function createDefaultCapabilities() {
|
|
139
|
+
return {
|
|
140
|
+
reasoning: false,
|
|
141
|
+
toolCalling: true,
|
|
142
|
+
temperature: true,
|
|
143
|
+
attachments: false,
|
|
144
|
+
streaming: true,
|
|
145
|
+
inputModalities: ["text"],
|
|
146
|
+
outputModalities: ["text"]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
var PatternCapabilitySource = class {
|
|
150
|
+
priority = 3 /* PatternMatch */;
|
|
151
|
+
name = "Pattern Matching";
|
|
152
|
+
async lookup(modelId, providerHint) {
|
|
153
|
+
const provider = providerHint || inferProvider(modelId);
|
|
154
|
+
const match = matchPatterns(modelId, provider);
|
|
155
|
+
const baseCapabilities = createDefaultCapabilities();
|
|
156
|
+
if (match) {
|
|
157
|
+
const entry = {
|
|
158
|
+
id: modelId,
|
|
159
|
+
name: modelId,
|
|
160
|
+
provider: match.rule.provider || provider || "unknown",
|
|
161
|
+
capabilities: {
|
|
162
|
+
...baseCapabilities,
|
|
163
|
+
...match.rule.capabilities
|
|
164
|
+
},
|
|
165
|
+
compatibility: match.rule.compatibility
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
entry,
|
|
169
|
+
source: this.priority,
|
|
170
|
+
confident: match.confidence > 0.8
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
entry: {
|
|
175
|
+
id: modelId,
|
|
176
|
+
name: modelId,
|
|
177
|
+
provider: provider || "unknown",
|
|
178
|
+
capabilities: baseCapabilities
|
|
179
|
+
},
|
|
180
|
+
source: this.priority,
|
|
181
|
+
confident: false
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
async isAvailable() {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
function likelySupportsReasoning(modelId) {
|
|
189
|
+
const match = matchPatterns(modelId);
|
|
190
|
+
return match !== void 0 && match.rule.capabilities.reasoning === true;
|
|
191
|
+
}
|
|
192
|
+
function getProviderCompatibility(modelId, provider) {
|
|
193
|
+
const match = matchPatterns(modelId, provider);
|
|
194
|
+
return match?.rule.compatibility;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/capabilities/overrides.ts
|
|
198
|
+
function normalizeKey(value) {
|
|
199
|
+
const trimmed = value?.trim();
|
|
200
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
201
|
+
}
|
|
202
|
+
function findCapabilityOverride(overrides, modelId, provider) {
|
|
203
|
+
if (!overrides) return {};
|
|
204
|
+
const normalizedModel = normalizeKey(modelId);
|
|
205
|
+
const normalizedProvider = normalizeKey(provider);
|
|
206
|
+
if (!normalizedModel) return {};
|
|
207
|
+
if (normalizedProvider) {
|
|
208
|
+
const scopedKey = `${normalizedProvider}/${normalizedModel}`;
|
|
209
|
+
const scopedOverride = overrides[scopedKey];
|
|
210
|
+
if (scopedOverride) {
|
|
211
|
+
return { override: scopedOverride, matchedKey: scopedKey };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const modelOverride = overrides[normalizedModel];
|
|
215
|
+
if (modelOverride) {
|
|
216
|
+
return { override: modelOverride, matchedKey: normalizedModel };
|
|
217
|
+
}
|
|
218
|
+
return {};
|
|
219
|
+
}
|
|
220
|
+
function applyCapabilityOverride(entry, override) {
|
|
221
|
+
if (!override) return entry;
|
|
222
|
+
return {
|
|
223
|
+
...entry,
|
|
224
|
+
capabilities: {
|
|
225
|
+
...entry.capabilities,
|
|
226
|
+
...override
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/capabilities/cache/adapters.ts
|
|
232
|
+
function isNodeEnvironment() {
|
|
233
|
+
return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
234
|
+
}
|
|
235
|
+
function hasLocalStorage() {
|
|
236
|
+
try {
|
|
237
|
+
return typeof localStorage !== "undefined" && localStorage !== null;
|
|
238
|
+
} catch {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
var FileSystemAdapter = class {
|
|
243
|
+
cachePath;
|
|
244
|
+
fs;
|
|
245
|
+
path;
|
|
246
|
+
constructor(cachePath) {
|
|
247
|
+
this.cachePath = cachePath;
|
|
248
|
+
}
|
|
249
|
+
async ensureModules() {
|
|
250
|
+
if (!this.fs) {
|
|
251
|
+
this.fs = await import("fs/promises");
|
|
252
|
+
this.path = await import("path");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
getFilePath() {
|
|
256
|
+
return this.path.join(this.cachePath, "model-capabilities.json");
|
|
257
|
+
}
|
|
258
|
+
async read() {
|
|
259
|
+
await this.ensureModules();
|
|
260
|
+
try {
|
|
261
|
+
const content = await this.fs.readFile(this.getFilePath(), "utf-8");
|
|
262
|
+
return JSON.parse(content);
|
|
263
|
+
} catch {
|
|
264
|
+
return void 0;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async write(data) {
|
|
268
|
+
await this.ensureModules();
|
|
269
|
+
const filePath = this.getFilePath();
|
|
270
|
+
await this.fs.mkdir(this.path.dirname(filePath), { recursive: true });
|
|
271
|
+
await this.fs.writeFile(filePath, JSON.stringify(data, null, 2));
|
|
272
|
+
}
|
|
273
|
+
async clear() {
|
|
274
|
+
await this.ensureModules();
|
|
275
|
+
try {
|
|
276
|
+
await this.fs.unlink(this.getFilePath());
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var LocalStorageAdapter = class {
|
|
282
|
+
key = "agent-core:model-capabilities";
|
|
283
|
+
async read() {
|
|
284
|
+
try {
|
|
285
|
+
const content = localStorage.getItem(this.key);
|
|
286
|
+
if (!content) return void 0;
|
|
287
|
+
return JSON.parse(content);
|
|
288
|
+
} catch {
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async write(data) {
|
|
293
|
+
try {
|
|
294
|
+
localStorage.setItem(this.key, JSON.stringify(data));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.warn("[agent-core] Failed to write to localStorage:", error);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
async clear() {
|
|
300
|
+
try {
|
|
301
|
+
localStorage.removeItem(this.key);
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
var MemoryAdapter = class {
|
|
307
|
+
data;
|
|
308
|
+
async read() {
|
|
309
|
+
return this.data;
|
|
310
|
+
}
|
|
311
|
+
async write(data) {
|
|
312
|
+
this.data = data;
|
|
313
|
+
}
|
|
314
|
+
async clear() {
|
|
315
|
+
this.data = void 0;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
function createCapabilityCacheAdapter(cachePath) {
|
|
319
|
+
if (isNodeEnvironment()) {
|
|
320
|
+
return new FileSystemAdapter(cachePath);
|
|
321
|
+
}
|
|
322
|
+
if (hasLocalStorage()) {
|
|
323
|
+
return new LocalStorageAdapter();
|
|
324
|
+
}
|
|
325
|
+
return new MemoryAdapter();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// src/capabilities/cache/types.ts
|
|
329
|
+
var CACHE_VERSION = 1;
|
|
330
|
+
function cacheKey(modelId, provider) {
|
|
331
|
+
return provider ? `${provider}:${modelId}` : modelId;
|
|
332
|
+
}
|
|
333
|
+
function isExpired(data) {
|
|
334
|
+
return Date.now() > new Date(data.expiresAt).getTime();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/capabilities/cache/manager.ts
|
|
338
|
+
var CapabilityCache = class {
|
|
339
|
+
adapter;
|
|
340
|
+
memoryCache = /* @__PURE__ */ new Map();
|
|
341
|
+
ttlMs;
|
|
342
|
+
loaded = false;
|
|
343
|
+
constructor(options = {}) {
|
|
344
|
+
const opts = { ...DEFAULT_RESOLVER_OPTIONS, ...options };
|
|
345
|
+
this.ttlMs = opts.cacheTtlMs;
|
|
346
|
+
this.adapter = createCapabilityCacheAdapter(opts.cachePath);
|
|
347
|
+
}
|
|
348
|
+
async load() {
|
|
349
|
+
if (this.loaded) return;
|
|
350
|
+
try {
|
|
351
|
+
const data = await this.adapter.read();
|
|
352
|
+
if (data && data.version === CACHE_VERSION && !isExpired(data)) {
|
|
353
|
+
for (const [key, entry] of Object.entries(data.models)) {
|
|
354
|
+
this.memoryCache.set(key, entry);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.warn("[agent-core] Failed to load capability cache:", error);
|
|
359
|
+
}
|
|
360
|
+
this.loaded = true;
|
|
361
|
+
}
|
|
362
|
+
async get(modelId, provider) {
|
|
363
|
+
await this.load();
|
|
364
|
+
return this.memoryCache.get(cacheKey(modelId, provider));
|
|
365
|
+
}
|
|
366
|
+
async set(entry) {
|
|
367
|
+
await this.load();
|
|
368
|
+
this.memoryCache.set(cacheKey(entry.id, entry.provider), entry);
|
|
369
|
+
}
|
|
370
|
+
async setMany(entries) {
|
|
371
|
+
await this.load();
|
|
372
|
+
for (const entry of entries) {
|
|
373
|
+
this.memoryCache.set(cacheKey(entry.id, entry.provider), entry);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async persist() {
|
|
377
|
+
const models = {};
|
|
378
|
+
for (const [key, entry] of this.memoryCache.entries()) {
|
|
379
|
+
models[key] = entry;
|
|
380
|
+
}
|
|
381
|
+
await this.adapter.write({
|
|
382
|
+
version: CACHE_VERSION,
|
|
383
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
384
|
+
expiresAt: new Date(Date.now() + this.ttlMs).toISOString(),
|
|
385
|
+
models
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
async clear() {
|
|
389
|
+
this.memoryCache.clear();
|
|
390
|
+
await this.adapter.clear();
|
|
391
|
+
this.loaded = false;
|
|
392
|
+
}
|
|
393
|
+
stats() {
|
|
394
|
+
return {
|
|
395
|
+
size: this.memoryCache.size,
|
|
396
|
+
loaded: this.loaded
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
async getAll() {
|
|
400
|
+
await this.load();
|
|
401
|
+
return Array.from(this.memoryCache.values());
|
|
402
|
+
}
|
|
403
|
+
async getAllByProvider() {
|
|
404
|
+
await this.load();
|
|
405
|
+
const byProvider = {};
|
|
406
|
+
for (const entry of this.memoryCache.values()) {
|
|
407
|
+
const provider = entry.provider ?? "unknown";
|
|
408
|
+
byProvider[provider] ??= [];
|
|
409
|
+
byProvider[provider].push(entry);
|
|
410
|
+
}
|
|
411
|
+
return byProvider;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var CacheCapabilitySource = class {
|
|
415
|
+
constructor(cache) {
|
|
416
|
+
this.cache = cache;
|
|
417
|
+
}
|
|
418
|
+
priority = 1 /* LocalCache */;
|
|
419
|
+
name = "Local Cache";
|
|
420
|
+
async lookup(modelId, provider) {
|
|
421
|
+
const entry = await this.cache.get(modelId, provider);
|
|
422
|
+
if (entry) {
|
|
423
|
+
return {
|
|
424
|
+
entry,
|
|
425
|
+
source: this.priority,
|
|
426
|
+
confident: true
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
source: this.priority,
|
|
431
|
+
confident: false
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async isAvailable() {
|
|
435
|
+
return this.cache.stats().size > 0;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/capabilities/remote/network.ts
|
|
440
|
+
function hasBrowserNetworkAPI() {
|
|
441
|
+
return typeof globalThis.navigator !== "undefined" && "onLine" in globalThis.navigator;
|
|
442
|
+
}
|
|
443
|
+
function isBrowserOnline() {
|
|
444
|
+
if (typeof globalThis.navigator !== "undefined" && "onLine" in globalThis.navigator) {
|
|
445
|
+
return globalThis.navigator.onLine;
|
|
446
|
+
}
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
var NetworkTracker = class {
|
|
450
|
+
status = {
|
|
451
|
+
online: true,
|
|
452
|
+
failureCount: 0
|
|
453
|
+
};
|
|
454
|
+
getStatus() {
|
|
455
|
+
if (hasBrowserNetworkAPI()) {
|
|
456
|
+
return {
|
|
457
|
+
...this.status,
|
|
458
|
+
online: isBrowserOnline() && this.status.failureCount < 3
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
...this.status,
|
|
463
|
+
online: this.status.failureCount < 3
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
recordSuccess() {
|
|
467
|
+
this.status = {
|
|
468
|
+
online: true,
|
|
469
|
+
lastSuccess: Date.now(),
|
|
470
|
+
failureCount: 0
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
recordFailure(error) {
|
|
474
|
+
this.status = {
|
|
475
|
+
...this.status,
|
|
476
|
+
online: this.status.failureCount < 2,
|
|
477
|
+
lastError: error,
|
|
478
|
+
failureCount: this.status.failureCount + 1
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
var networkTracker = new NetworkTracker();
|
|
483
|
+
function getNetworkStatus() {
|
|
484
|
+
return networkTracker.getStatus();
|
|
485
|
+
}
|
|
486
|
+
function recordNetworkSuccess() {
|
|
487
|
+
networkTracker.recordSuccess();
|
|
488
|
+
}
|
|
489
|
+
function recordNetworkFailure(error) {
|
|
490
|
+
networkTracker.recordFailure(error);
|
|
491
|
+
}
|
|
492
|
+
async function fetchWithTimeout(url, timeoutMs) {
|
|
493
|
+
const controller = new AbortController();
|
|
494
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
495
|
+
try {
|
|
496
|
+
const response = await fetch(url, {
|
|
497
|
+
signal: controller.signal,
|
|
498
|
+
headers: {
|
|
499
|
+
Accept: "application/json",
|
|
500
|
+
"User-Agent": "cuylabs-agent-core/1.0"
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
if (!response.ok) {
|
|
504
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
505
|
+
}
|
|
506
|
+
return response;
|
|
507
|
+
} finally {
|
|
508
|
+
clearTimeout(timeout);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/capabilities/remote/transform.ts
|
|
513
|
+
function transformModelsDevEntry(raw) {
|
|
514
|
+
const capabilities = {
|
|
515
|
+
reasoning: raw.reasoning ?? false,
|
|
516
|
+
toolCalling: raw.tool_call ?? false,
|
|
517
|
+
temperature: raw.temperature ?? true,
|
|
518
|
+
attachments: raw.attachment ?? false,
|
|
519
|
+
streaming: true,
|
|
520
|
+
inputModalities: raw.modalities?.input ?? ["text"],
|
|
521
|
+
outputModalities: raw.modalities?.output ?? ["text"],
|
|
522
|
+
contextWindow: raw.limit?.context,
|
|
523
|
+
maxOutput: raw.limit?.output
|
|
524
|
+
};
|
|
525
|
+
return {
|
|
526
|
+
id: raw.id,
|
|
527
|
+
name: raw.name,
|
|
528
|
+
provider: raw.provider ?? "unknown",
|
|
529
|
+
capabilities,
|
|
530
|
+
costInput: raw.cost?.input,
|
|
531
|
+
costOutput: raw.cost?.output,
|
|
532
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/capabilities/remote/fetcher.ts
|
|
537
|
+
var RemoteCapabilityFetcher = class {
|
|
538
|
+
apiUrl;
|
|
539
|
+
timeoutMs;
|
|
540
|
+
cache;
|
|
541
|
+
lastFetchTime = 0;
|
|
542
|
+
minFetchInterval = 60 * 1e3;
|
|
543
|
+
constructor(cache, options = {}) {
|
|
544
|
+
const opts = { ...DEFAULT_RESOLVER_OPTIONS, ...options };
|
|
545
|
+
this.apiUrl = opts.remoteApiUrl;
|
|
546
|
+
this.timeoutMs = opts.networkTimeoutMs;
|
|
547
|
+
this.cache = cache;
|
|
548
|
+
}
|
|
549
|
+
async fetchAll() {
|
|
550
|
+
const now = Date.now();
|
|
551
|
+
if (now - this.lastFetchTime < this.minFetchInterval) {
|
|
552
|
+
throw new Error("Fetch rate limited - try again later");
|
|
553
|
+
}
|
|
554
|
+
if (!getNetworkStatus().online) {
|
|
555
|
+
throw new Error("Network appears offline");
|
|
556
|
+
}
|
|
557
|
+
try {
|
|
558
|
+
const response = await fetchWithTimeout(`${this.apiUrl}/api.json`, this.timeoutMs);
|
|
559
|
+
const data = await response.json();
|
|
560
|
+
const entries = [];
|
|
561
|
+
if (data && typeof data === "object") {
|
|
562
|
+
for (const [providerId, providerData] of Object.entries(data)) {
|
|
563
|
+
if (typeof providerData !== "object" || providerData === null) continue;
|
|
564
|
+
const models = providerData.models;
|
|
565
|
+
if (!Array.isArray(models)) continue;
|
|
566
|
+
for (const model of models) {
|
|
567
|
+
entries.push(transformModelsDevEntry({
|
|
568
|
+
...model,
|
|
569
|
+
provider: providerId
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
await this.cache.setMany(entries);
|
|
575
|
+
await this.cache.persist();
|
|
576
|
+
this.lastFetchTime = now;
|
|
577
|
+
recordNetworkSuccess();
|
|
578
|
+
return entries;
|
|
579
|
+
} catch (error) {
|
|
580
|
+
recordNetworkFailure(error instanceof Error ? error.message : String(error));
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
async ping() {
|
|
585
|
+
try {
|
|
586
|
+
const response = await fetchWithTimeout(this.apiUrl, 5e3);
|
|
587
|
+
recordNetworkSuccess();
|
|
588
|
+
return response.ok;
|
|
589
|
+
} catch {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// src/capabilities/remote/source.ts
|
|
596
|
+
var RemoteCapabilitySource = class {
|
|
597
|
+
priority = 4 /* RemoteAPI */;
|
|
598
|
+
name = "Remote API (models.dev)";
|
|
599
|
+
fetcher;
|
|
600
|
+
cache;
|
|
601
|
+
fetchPromise;
|
|
602
|
+
enabled;
|
|
603
|
+
constructor(cache, options = {}) {
|
|
604
|
+
const opts = { ...DEFAULT_RESOLVER_OPTIONS, ...options };
|
|
605
|
+
this.cache = cache;
|
|
606
|
+
this.fetcher = new RemoteCapabilityFetcher(cache, opts);
|
|
607
|
+
this.enabled = opts.enableRemoteFetch;
|
|
608
|
+
}
|
|
609
|
+
async lookup(modelId, provider) {
|
|
610
|
+
if (!this.enabled) {
|
|
611
|
+
return {
|
|
612
|
+
source: this.priority,
|
|
613
|
+
confident: false,
|
|
614
|
+
error: "Remote fetch disabled"
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const cached = await this.cache.get(modelId, provider);
|
|
618
|
+
if (cached) {
|
|
619
|
+
return {
|
|
620
|
+
entry: cached,
|
|
621
|
+
source: 1 /* LocalCache */,
|
|
622
|
+
confident: true
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
if (!this.fetchPromise) {
|
|
626
|
+
this.fetchPromise = this.fetcher.fetchAll().finally(() => {
|
|
627
|
+
this.fetchPromise = void 0;
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
try {
|
|
631
|
+
await this.fetchPromise;
|
|
632
|
+
const entry = await this.cache.get(modelId, provider);
|
|
633
|
+
if (entry) {
|
|
634
|
+
return {
|
|
635
|
+
entry,
|
|
636
|
+
source: this.priority,
|
|
637
|
+
confident: true
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
} catch (error) {
|
|
641
|
+
return {
|
|
642
|
+
source: this.priority,
|
|
643
|
+
confident: false,
|
|
644
|
+
error: error instanceof Error ? error.message : String(error)
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
source: this.priority,
|
|
649
|
+
confident: false,
|
|
650
|
+
error: "Model not found in remote database"
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
async isAvailable() {
|
|
654
|
+
return this.enabled && getNetworkStatus().online;
|
|
655
|
+
}
|
|
656
|
+
async refresh() {
|
|
657
|
+
if (!this.enabled) return;
|
|
658
|
+
await this.fetcher.fetchAll();
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/capabilities/resolver.ts
|
|
663
|
+
function extractModelId(model) {
|
|
664
|
+
return getModelId(model);
|
|
665
|
+
}
|
|
666
|
+
function extractProvider(model) {
|
|
667
|
+
const provider = getProviderId(model);
|
|
668
|
+
return provider ?? inferProvider(extractModelId(model));
|
|
669
|
+
}
|
|
670
|
+
var ModelCapabilityResolver = class {
|
|
671
|
+
options;
|
|
672
|
+
cache;
|
|
673
|
+
sources;
|
|
674
|
+
initialized = false;
|
|
675
|
+
initPromise;
|
|
676
|
+
constructor(options = {}) {
|
|
677
|
+
this.options = { ...DEFAULT_RESOLVER_OPTIONS, ...options };
|
|
678
|
+
this.cache = new CapabilityCache(this.options);
|
|
679
|
+
this.sources = [
|
|
680
|
+
new CacheCapabilitySource(this.cache),
|
|
681
|
+
new PatternCapabilitySource()
|
|
682
|
+
];
|
|
683
|
+
if (this.options.enableRemoteFetch) {
|
|
684
|
+
this.sources.push(new RemoteCapabilitySource(this.cache, this.options));
|
|
685
|
+
}
|
|
686
|
+
this.sources.sort((a, b) => a.priority - b.priority);
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Initialize the resolver (load cache, optionally fetch remote)
|
|
690
|
+
*/
|
|
691
|
+
async initialize() {
|
|
692
|
+
if (this.initialized) return;
|
|
693
|
+
if (this.initPromise) return this.initPromise;
|
|
694
|
+
this.initPromise = (async () => {
|
|
695
|
+
if (this.options.enableRemoteFetch) {
|
|
696
|
+
const remoteSource = this.sources.find(
|
|
697
|
+
(s) => s instanceof RemoteCapabilitySource
|
|
698
|
+
);
|
|
699
|
+
if (remoteSource) {
|
|
700
|
+
remoteSource.refresh().catch((err) => {
|
|
701
|
+
console.warn("[agent-core] Background refresh failed:", err);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
this.initialized = true;
|
|
706
|
+
})();
|
|
707
|
+
return this.initPromise;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Resolve capabilities for a model
|
|
711
|
+
*/
|
|
712
|
+
async resolve(model) {
|
|
713
|
+
const start = Date.now();
|
|
714
|
+
await this.initialize();
|
|
715
|
+
const modelId = extractModelId(model);
|
|
716
|
+
const provider = extractProvider(model);
|
|
717
|
+
const overrideLookup = findCapabilityOverride(this.options.modelOverrides, modelId, provider);
|
|
718
|
+
let bestResult;
|
|
719
|
+
for (const source of this.sources) {
|
|
720
|
+
try {
|
|
721
|
+
const result = await source.lookup(modelId, provider);
|
|
722
|
+
if (result.entry) {
|
|
723
|
+
if (result.confident) {
|
|
724
|
+
bestResult = result;
|
|
725
|
+
break;
|
|
726
|
+
}
|
|
727
|
+
if (!bestResult) {
|
|
728
|
+
bestResult = result;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
} catch (error) {
|
|
732
|
+
console.warn(`[agent-core] Source ${source.name} failed:`, error);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (!bestResult?.entry) {
|
|
736
|
+
throw new Error(`Failed to resolve capabilities for model: ${modelId}`);
|
|
737
|
+
}
|
|
738
|
+
const entry = applyCapabilityOverride(bestResult.entry, overrideLookup.override);
|
|
739
|
+
return {
|
|
740
|
+
entry,
|
|
741
|
+
source: bestResult.source,
|
|
742
|
+
confident: bestResult.confident,
|
|
743
|
+
resolveTimeMs: Date.now() - start
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Quick check if a model supports reasoning
|
|
748
|
+
* Uses cache/patterns only for speed
|
|
749
|
+
*/
|
|
750
|
+
async supportsReasoning(model) {
|
|
751
|
+
const modelId = extractModelId(model);
|
|
752
|
+
const provider = extractProvider(model);
|
|
753
|
+
const cached = await this.cache.get(modelId, provider);
|
|
754
|
+
if (cached) {
|
|
755
|
+
return cached.capabilities.reasoning;
|
|
756
|
+
}
|
|
757
|
+
return likelySupportsReasoning(modelId);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Get capabilities for a model
|
|
761
|
+
*/
|
|
762
|
+
async getCapabilities(model) {
|
|
763
|
+
const result = await this.resolve(model);
|
|
764
|
+
return result.entry.capabilities;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Get provider compatibility settings
|
|
768
|
+
*/
|
|
769
|
+
async getCompatibility(model) {
|
|
770
|
+
const result = await this.resolve(model);
|
|
771
|
+
return result.entry.compatibility;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Force refresh from remote API
|
|
775
|
+
*/
|
|
776
|
+
async refreshRemote() {
|
|
777
|
+
if (!this.options.enableRemoteFetch) {
|
|
778
|
+
throw new Error("Remote fetch is not enabled");
|
|
779
|
+
}
|
|
780
|
+
const remoteSource = this.sources.find(
|
|
781
|
+
(s) => s instanceof RemoteCapabilitySource
|
|
782
|
+
);
|
|
783
|
+
if (remoteSource) {
|
|
784
|
+
await remoteSource.refresh();
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Get current network status
|
|
789
|
+
*/
|
|
790
|
+
getNetworkStatus() {
|
|
791
|
+
return getNetworkStatus();
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Get resolver statistics
|
|
795
|
+
*/
|
|
796
|
+
getStats() {
|
|
797
|
+
const cacheStats = this.cache.stats();
|
|
798
|
+
const networkStatus = getNetworkStatus();
|
|
799
|
+
return {
|
|
800
|
+
cacheSize: cacheStats.size,
|
|
801
|
+
cacheLoaded: cacheStats.loaded,
|
|
802
|
+
remoteFetchEnabled: this.options.enableRemoteFetch,
|
|
803
|
+
networkOnline: networkStatus.online
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Clear all cached data
|
|
808
|
+
*/
|
|
809
|
+
async clearCache() {
|
|
810
|
+
await this.cache.clear();
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* List all available models
|
|
814
|
+
* Fetches from remote if cache is empty and remote is enabled
|
|
815
|
+
*/
|
|
816
|
+
async listModels() {
|
|
817
|
+
await this.initialize();
|
|
818
|
+
const stats = this.cache.stats();
|
|
819
|
+
if (stats.size === 0 && this.options.enableRemoteFetch) {
|
|
820
|
+
const remoteSource = this.sources.find(
|
|
821
|
+
(s) => s instanceof RemoteCapabilitySource
|
|
822
|
+
);
|
|
823
|
+
if (remoteSource) {
|
|
824
|
+
await remoteSource.refresh();
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
return this.cache.getAll();
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* List all available models grouped by provider
|
|
831
|
+
*/
|
|
832
|
+
async listModelsByProvider() {
|
|
833
|
+
await this.initialize();
|
|
834
|
+
const stats = this.cache.stats();
|
|
835
|
+
if (stats.size === 0 && this.options.enableRemoteFetch) {
|
|
836
|
+
const remoteSource = this.sources.find(
|
|
837
|
+
(s) => s instanceof RemoteCapabilitySource
|
|
838
|
+
);
|
|
839
|
+
if (remoteSource) {
|
|
840
|
+
await remoteSource.refresh();
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return this.cache.getAllByProvider();
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
var defaultResolver;
|
|
847
|
+
function getDefaultResolver() {
|
|
848
|
+
if (!defaultResolver) {
|
|
849
|
+
defaultResolver = new ModelCapabilityResolver({
|
|
850
|
+
enableRemoteFetch: process.env.CODE_AGENT_ENABLE_REMOTE_FETCH === "true",
|
|
851
|
+
remoteApiUrl: process.env.CODE_AGENT_MODELS_API || "https://models.dev"
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
return defaultResolver;
|
|
855
|
+
}
|
|
856
|
+
function configureResolver(options) {
|
|
857
|
+
defaultResolver = new ModelCapabilityResolver(options);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export {
|
|
861
|
+
SourcePriority,
|
|
862
|
+
DEFAULT_RESOLVER_OPTIONS,
|
|
863
|
+
inferProvider,
|
|
864
|
+
PatternCapabilitySource,
|
|
865
|
+
likelySupportsReasoning,
|
|
866
|
+
getProviderCompatibility,
|
|
867
|
+
findCapabilityOverride,
|
|
868
|
+
applyCapabilityOverride,
|
|
869
|
+
CapabilityCache,
|
|
870
|
+
CacheCapabilitySource,
|
|
871
|
+
getNetworkStatus,
|
|
872
|
+
RemoteCapabilityFetcher,
|
|
873
|
+
RemoteCapabilitySource,
|
|
874
|
+
extractModelId,
|
|
875
|
+
extractProvider,
|
|
876
|
+
ModelCapabilityResolver,
|
|
877
|
+
getDefaultResolver,
|
|
878
|
+
configureResolver
|
|
879
|
+
};
|