@swifty.js/swifty 0.0.26 → 0.0.28
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 +14 -6
- package/dist/agent-3NON2EXE.js +4 -0
- package/dist/anthropic-BJ5GN2VT.js +4 -0
- package/dist/checker-N5TIJEN5.js +4 -0
- package/dist/{chunk-H7VXSMJR.js → chunk-C3WGLVVZ.js} +10 -10
- package/dist/chunk-D34FUVGU.js +4 -0
- package/dist/chunk-FPQ2LBL4.js +10 -0
- package/dist/chunk-JGSIQXEN.js +4 -0
- package/dist/{chunk-5KXBVL2A.js → chunk-K5ZK27BX.js} +1 -1
- package/dist/chunk-LZBOXJX2.js +301 -0
- package/dist/chunk-OTVZGPHD.js +121 -0
- package/dist/chunk-QCKJLO6X.js +4 -0
- package/dist/chunk-R63ASIIW.js +407 -0
- package/dist/chunk-WX3B64R4.js +4 -0
- package/dist/chunk-Y6SQB5FG.js +4 -0
- package/dist/{devtools-3OAJUZGE.js → devtools-OJ75EP3T.js} +1 -1
- package/dist/glob.wasm +0 -0
- package/dist/lib/agent-XYO2MXXK.js +11 -0
- package/dist/lib/{anthropic-RYPJDHQM.js → anthropic-TGJGAP5R.js} +4 -5
- package/dist/lib/{checker-6BW4222R.js → checker-AXHPKVBY.js} +2 -2
- package/dist/lib/{chunk-HK2Z6WP4.js → chunk-2IVEVG5N.js} +5 -1
- package/dist/lib/{chunk-2AUSNVIB.js → chunk-ALJAVRRX.js} +28 -34
- package/dist/lib/{chunk-GNI7YX6F.js → chunk-DJ6AILPN.js} +70 -24
- package/dist/lib/chunk-DV6RV5WU.js +2345 -0
- package/dist/lib/{chunk-3LU4APFB.js → chunk-FBSPZQGC.js} +126 -73
- package/dist/lib/chunk-IB5IQK2S.js +136 -0
- package/dist/lib/{chunk-PZ42NAFA.js → chunk-KG4MJGKQ.js} +19 -21
- package/dist/lib/{chunk-XFSN4LMA.js → chunk-P4F46PEF.js} +43 -14
- package/dist/lib/glob.wasm +0 -0
- package/dist/lib/index.d.ts +145 -123
- package/dist/lib/index.js +2186 -1726
- package/dist/lib/{openai-VX5VBXZ4.js → openai-5UCIIDPO.js} +2 -3
- package/dist/lib/{tool-filter-VF7TZRE5.js → tool-filter-R6HDDJHE.js} +1 -1
- package/dist/main.js +226 -196
- package/dist/{node-OES65R33.js → node-4LTSRXL2.js} +1 -1
- package/dist/{openai-6MXNADYN.js → openai-YLS2LUAI.js} +14 -14
- package/dist/server-GX72MJQF.js +244 -0
- package/dist/{tool-filter-NO7I3HFD.js → tool-filter-VBP6WOGO.js} +1 -1
- package/package.json +36 -32
- package/dist/agent-GAABBZRW.js +0 -4
- package/dist/anthropic-7QRAPLOY.js +0 -4
- package/dist/checker-3RWAYF2U.js +0 -4
- package/dist/chunk-7MHXMDYC.js +0 -35
- package/dist/chunk-A2VR3BC4.js +0 -4
- package/dist/chunk-FZPTNGTU.js +0 -4
- package/dist/chunk-MWZIARZE.js +0 -130
- package/dist/chunk-NR62AA5K.js +0 -4
- package/dist/chunk-QN27QEFS.js +0 -4
- package/dist/chunk-RMMK4PO5.js +0 -389
- package/dist/chunk-SIWLMWHH.js +0 -93
- package/dist/chunk-VC6OXOMP.js +0 -238
- package/dist/chunk-W37Y53LX.js +0 -4
- package/dist/chunk-XBHVVB5A.js +0 -10
- package/dist/lib/agent-U7MIUCKT.js +0 -9
- package/dist/lib/chunk-2QILP24G.js +0 -1120
- package/dist/lib/chunk-OO2CLOEE.js +0 -88
- package/dist/lib/chunk-RKJYTYQM.js +0 -1285
- package/dist/server-P2VE5HLJ.js +0 -244
|
@@ -2,6 +2,40 @@ import {
|
|
|
2
2
|
createChildLogger
|
|
3
3
|
} from "./chunk-EY7HE52Q.js";
|
|
4
4
|
|
|
5
|
+
// src/llm/errors.ts
|
|
6
|
+
var LLMError = class extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "LLMError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var AuthenticationError = class extends LLMError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "AuthenticationError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var RateLimitError = class extends LLMError {
|
|
19
|
+
retryAfter;
|
|
20
|
+
constructor(message, retryAfter) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "RateLimitError";
|
|
23
|
+
this.retryAfter = retryAfter;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var NetworkError = class extends LLMError {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "NetworkError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var ContextTooLongError = class extends LLMError {
|
|
33
|
+
constructor(message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "ContextTooLongError";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
5
39
|
// src/config/config.ts
|
|
6
40
|
import { existsSync, readFileSync } from "fs";
|
|
7
41
|
import { homedir } from "os";
|
|
@@ -38,68 +72,22 @@ var ProviderConfigSchema = z.object({
|
|
|
38
72
|
context_window: z.coerce.number().optional(),
|
|
39
73
|
max_output_tokens: z.coerce.number().optional()
|
|
40
74
|
});
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
["claude", 2e5]
|
|
52
|
-
];
|
|
53
|
-
function lookupModelContextWindow(model) {
|
|
54
|
-
const model_ = model.toLowerCase();
|
|
55
|
-
for (const [m, window] of MODEL_CONTEXT_WINDOWS) {
|
|
56
|
-
if (model_.includes(m)) {
|
|
57
|
-
return window;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return model_.includes("claude") ? 2e5 : 128e3;
|
|
61
|
-
}
|
|
62
|
-
function getContextWindow(p) {
|
|
63
|
-
if (p.context_window && p.context_window > 0) {
|
|
64
|
-
return p.context_window;
|
|
65
|
-
}
|
|
66
|
-
return lookupModelContextWindow(p.model);
|
|
67
|
-
}
|
|
68
|
-
var fetchedWindowCache = /* @__PURE__ */ new Map();
|
|
69
|
-
async function getContextWindowAsync(p, fetcher) {
|
|
70
|
-
if (p.context_window && p.context_window > 0) {
|
|
71
|
-
return p.context_window;
|
|
72
|
-
}
|
|
73
|
-
if (p.protocol === "anthropic") {
|
|
74
|
-
const key = `${p.name}-${p.model}`;
|
|
75
|
-
let fetched = fetchedWindowCache.get(key);
|
|
76
|
-
if (fetched === void 0) {
|
|
77
|
-
try {
|
|
78
|
-
const fn = fetcher ?? (await import("./anthropic-RYPJDHQM.js")).fetchModelContextWindow;
|
|
79
|
-
fetched = await fn(p);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
log.error({ err }, "config operation failed");
|
|
82
|
-
fetched = 0;
|
|
83
|
-
}
|
|
84
|
-
fetchedWindowCache.set(key, fetched);
|
|
85
|
-
}
|
|
86
|
-
if (fetched && fetched > 0) {
|
|
87
|
-
return fetched;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return lookupModelContextWindow(p.model);
|
|
75
|
+
var DEFAULT_PROVIDER_THINKING = true;
|
|
76
|
+
var DEFAULT_CONTEXT_WINDOW = 1e6;
|
|
77
|
+
var DEFAULT_MAX_OUTPUT_TOKENS = 128e3;
|
|
78
|
+
function withProviderDefaults(provider) {
|
|
79
|
+
return {
|
|
80
|
+
...provider,
|
|
81
|
+
thinking: provider.thinking ?? DEFAULT_PROVIDER_THINKING,
|
|
82
|
+
context_window: getContextWindow(provider),
|
|
83
|
+
max_output_tokens: getMaxOutputTokens(provider)
|
|
84
|
+
};
|
|
91
85
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
86
|
+
function getContextWindow(provider) {
|
|
87
|
+
return Number.isSafeInteger(provider.context_window) && (provider.context_window ?? 0) > 0 ? provider.context_window ?? DEFAULT_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
|
|
94
88
|
}
|
|
95
|
-
function getMaxOutputTokens(
|
|
96
|
-
|
|
97
|
-
return p.max_output_tokens;
|
|
98
|
-
}
|
|
99
|
-
if (p.thinking) {
|
|
100
|
-
return 64e3;
|
|
101
|
-
}
|
|
102
|
-
return 8192;
|
|
89
|
+
function getMaxOutputTokens(provider) {
|
|
90
|
+
return Number.isSafeInteger(provider.max_output_tokens) && (provider.max_output_tokens ?? 0) > 0 ? provider.max_output_tokens ?? DEFAULT_MAX_OUTPUT_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS;
|
|
103
91
|
}
|
|
104
92
|
function resolveAPIKey(p) {
|
|
105
93
|
if (p.api_key) {
|
|
@@ -173,10 +161,8 @@ function loadSingleFile(path) {
|
|
|
173
161
|
if (parsed.success) {
|
|
174
162
|
const data2 = parsed.data;
|
|
175
163
|
return {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
mcp_servers: data2.mcp_servers,
|
|
179
|
-
hooks: data2.hooks
|
|
164
|
+
...data2,
|
|
165
|
+
providers: data2.providers.map(withProviderDefaults)
|
|
180
166
|
};
|
|
181
167
|
}
|
|
182
168
|
log.error({ error: parsed.error }, "config error");
|
|
@@ -190,7 +176,7 @@ function loadSingleFile(path) {
|
|
|
190
176
|
if ("providers" in raw) {
|
|
191
177
|
const parsed2 = safeParse(z.array(ProviderConfigSchema), raw.providers);
|
|
192
178
|
if (parsed2.success) {
|
|
193
|
-
providers = parsed2.data;
|
|
179
|
+
providers = parsed2.data.map(withProviderDefaults);
|
|
194
180
|
}
|
|
195
181
|
}
|
|
196
182
|
if ("permission_mode" in raw && typeof raw.permission_mode === "string") {
|
|
@@ -278,7 +264,7 @@ function validateProviders(config) {
|
|
|
278
264
|
base_url: p.base_url,
|
|
279
265
|
model: p.model
|
|
280
266
|
};
|
|
281
|
-
const missing = requiredFields.filter((field) => !(
|
|
267
|
+
const missing = requiredFields.filter((field) => !values[field].trim());
|
|
282
268
|
if (missing.length > 0) {
|
|
283
269
|
throw new ConfigError(`Provider #${String(i + 1)}: missing fields: ${missing.join(", ")}`);
|
|
284
270
|
}
|
|
@@ -289,10 +275,12 @@ function validateProviders(config) {
|
|
|
289
275
|
}
|
|
290
276
|
}
|
|
291
277
|
}
|
|
292
|
-
function loadConfig(path) {
|
|
278
|
+
function loadConfig(path, options = {}) {
|
|
293
279
|
if (path) {
|
|
294
280
|
const config = loadSingleFile(path);
|
|
295
|
-
|
|
281
|
+
if (!options.allowEmptyProviders || config.providers.length > 0) {
|
|
282
|
+
validateProviders(config);
|
|
283
|
+
}
|
|
296
284
|
return config;
|
|
297
285
|
}
|
|
298
286
|
const wd = process.cwd();
|
|
@@ -315,25 +303,90 @@ function loadConfig(path) {
|
|
|
315
303
|
}
|
|
316
304
|
}
|
|
317
305
|
if (!merged) {
|
|
306
|
+
if (options.allowEmptyProviders) {
|
|
307
|
+
return { providers: [], mcp_servers: [], hooks: [] };
|
|
308
|
+
}
|
|
318
309
|
throw new ConfigError(
|
|
319
310
|
"No config file found, expected .swifty/config.y(a)ml under project or $HOME/.swifty/config.y(a)ml."
|
|
320
311
|
);
|
|
321
312
|
}
|
|
322
|
-
|
|
313
|
+
if (!options.allowEmptyProviders || merged.providers.length > 0) {
|
|
314
|
+
validateProviders(merged);
|
|
315
|
+
}
|
|
323
316
|
return merged;
|
|
324
317
|
}
|
|
325
318
|
|
|
319
|
+
// src/conversation/pairing.ts
|
|
320
|
+
var INTERRUPTED_TOOL_RESULT = "Tool execution was interrupted. The tool may or may not have completed; verify before relying on its effects.";
|
|
321
|
+
var REJECTED_TOOL_RESULT = "The user rejected this tool use. Nothing was changed (for file edits, the new content was NOT written).";
|
|
322
|
+
function ensureToolPairing(messages) {
|
|
323
|
+
const out = [];
|
|
324
|
+
for (let i = 0; i < messages.length; i++) {
|
|
325
|
+
const m = messages[i];
|
|
326
|
+
if (m.role === "assistant" && m.toolUses?.length) {
|
|
327
|
+
out.push(m);
|
|
328
|
+
const pending = new Set(m.toolUses.map((tu) => tu.toolUseId));
|
|
329
|
+
const results = [];
|
|
330
|
+
const resultMessages = [];
|
|
331
|
+
while (i + 1 < messages.length) {
|
|
332
|
+
const next = messages[i + 1];
|
|
333
|
+
if (next.role !== "user" || !next.toolResults?.length || next.toolUses?.length) {
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
i++;
|
|
337
|
+
resultMessages.push(next);
|
|
338
|
+
for (const tr of next.toolResults) {
|
|
339
|
+
if (pending.delete(tr.toolUseId)) {
|
|
340
|
+
results.push(tr);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
for (const toolUseId of pending) {
|
|
345
|
+
results.push({ toolUseId, content: INTERRUPTED_TOOL_RESULT, isError: true });
|
|
346
|
+
}
|
|
347
|
+
out.push({
|
|
348
|
+
...resultMessages[0] ?? { role: "user", content: "" },
|
|
349
|
+
toolResults: results
|
|
350
|
+
});
|
|
351
|
+
for (const remaining of resultMessages.slice(1)) {
|
|
352
|
+
if (remaining.content.length > 0 || remaining.thinkingBlocks?.length) {
|
|
353
|
+
out.push({ ...remaining, toolResults: [] });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if ((m.toolResults?.length ?? 0) > 0) {
|
|
359
|
+
if (m.content.length === 0 && !m.toolUses?.length && !m.thinkingBlocks?.length) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
out.push({ ...m, toolResults: [] });
|
|
363
|
+
} else {
|
|
364
|
+
out.push(m);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return out;
|
|
368
|
+
}
|
|
369
|
+
|
|
326
370
|
export {
|
|
371
|
+
LLMError,
|
|
372
|
+
AuthenticationError,
|
|
373
|
+
RateLimitError,
|
|
374
|
+
NetworkError,
|
|
375
|
+
ContextTooLongError,
|
|
327
376
|
ConfigError,
|
|
328
377
|
ProviderConfigSchema,
|
|
329
|
-
|
|
378
|
+
DEFAULT_PROVIDER_THINKING,
|
|
379
|
+
DEFAULT_CONTEXT_WINDOW,
|
|
380
|
+
DEFAULT_MAX_OUTPUT_TOKENS,
|
|
381
|
+
withProviderDefaults,
|
|
330
382
|
getContextWindow,
|
|
331
|
-
getContextWindowAsync,
|
|
332
|
-
_resetContextWindowCache,
|
|
333
383
|
getMaxOutputTokens,
|
|
334
384
|
resolveAPIKey,
|
|
335
385
|
HookConfigSchema,
|
|
336
386
|
forkEnabled,
|
|
337
387
|
mergeConfig,
|
|
338
|
-
loadConfig
|
|
388
|
+
loadConfig,
|
|
389
|
+
INTERRUPTED_TOOL_RESULT,
|
|
390
|
+
REJECTED_TOOL_RESULT,
|
|
391
|
+
ensureToolPairing
|
|
339
392
|
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// src/tools/types.ts
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
var IMAGE_MEDIA_TYPES = /* @__PURE__ */ new Set([
|
|
6
|
+
"image/jpeg",
|
|
7
|
+
"image/png",
|
|
8
|
+
"image/gif",
|
|
9
|
+
"image/webp"
|
|
10
|
+
]);
|
|
11
|
+
function isImageMediaType(value) {
|
|
12
|
+
return IMAGE_MEDIA_TYPES.has(value);
|
|
13
|
+
}
|
|
14
|
+
function normalizeTextBlock(value) {
|
|
15
|
+
return isRecord(value) && value.type === "text" && typeof value.text === "string" ? { type: "text", text: value.text } : null;
|
|
16
|
+
}
|
|
17
|
+
function normalizeImageBlock(value) {
|
|
18
|
+
if (!isRecord(value) || value.type !== "image" || !isRecord(value.source)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
if (value.source.type === "url" && typeof value.source.url === "string") {
|
|
22
|
+
return { type: "image", source: { type: "url", url: value.source.url } };
|
|
23
|
+
}
|
|
24
|
+
if (value.source.type === "base64" && typeof value.source.media_type === "string" && isImageMediaType(value.source.media_type) && typeof value.source.data === "string") {
|
|
25
|
+
return {
|
|
26
|
+
type: "image",
|
|
27
|
+
source: {
|
|
28
|
+
type: "base64",
|
|
29
|
+
media_type: value.source.media_type,
|
|
30
|
+
data: value.source.data
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
function normalizeDocumentBlock(value) {
|
|
37
|
+
if (value.type !== "document" || !isRecord(value.source)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
let source = null;
|
|
41
|
+
if (value.source.type === "url" && typeof value.source.url === "string") {
|
|
42
|
+
source = { type: "url", url: value.source.url };
|
|
43
|
+
} else if (value.source.type === "base64" && value.source.media_type === "application/pdf" && typeof value.source.data === "string") {
|
|
44
|
+
source = { type: "base64", media_type: "application/pdf", data: value.source.data };
|
|
45
|
+
} else if (value.source.type === "text" && value.source.media_type === "text/plain" && typeof value.source.data === "string") {
|
|
46
|
+
source = { type: "text", media_type: "text/plain", data: value.source.data };
|
|
47
|
+
} else if (value.source.type === "content") {
|
|
48
|
+
if (typeof value.source.content === "string") {
|
|
49
|
+
source = { type: "content", content: value.source.content };
|
|
50
|
+
} else if (Array.isArray(value.source.content)) {
|
|
51
|
+
const content = [];
|
|
52
|
+
for (const raw of value.source.content) {
|
|
53
|
+
const block = normalizeTextBlock(raw) ?? normalizeImageBlock(raw);
|
|
54
|
+
if (!block) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
content.push(block);
|
|
58
|
+
}
|
|
59
|
+
source = { type: "content", content };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!source) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
type: "document",
|
|
67
|
+
source,
|
|
68
|
+
...typeof value.title === "string" || value.title === null ? { title: value.title } : {},
|
|
69
|
+
...typeof value.context === "string" || value.context === null ? { context: value.context } : {}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function normalizeToolResultContentBlock(value) {
|
|
73
|
+
const text = normalizeTextBlock(value);
|
|
74
|
+
if (text) {
|
|
75
|
+
return text;
|
|
76
|
+
}
|
|
77
|
+
const image = normalizeImageBlock(value);
|
|
78
|
+
if (image) {
|
|
79
|
+
return image;
|
|
80
|
+
}
|
|
81
|
+
if (!isRecord(value)) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (value.type === "tool_reference" && typeof value.tool_name === "string") {
|
|
85
|
+
return { type: "tool_reference", tool_name: value.tool_name };
|
|
86
|
+
}
|
|
87
|
+
if (value.type === "search_result" && typeof value.source === "string" && typeof value.title === "string" && Array.isArray(value.content)) {
|
|
88
|
+
const content = [];
|
|
89
|
+
for (const raw of value.content) {
|
|
90
|
+
const block = normalizeTextBlock(raw);
|
|
91
|
+
if (!block) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
content.push(block);
|
|
95
|
+
}
|
|
96
|
+
return { type: "search_result", source: value.source, title: value.title, content };
|
|
97
|
+
}
|
|
98
|
+
return normalizeDocumentBlock(value);
|
|
99
|
+
}
|
|
100
|
+
function isToolResultContentBlock(value) {
|
|
101
|
+
return normalizeToolResultContentBlock(value) !== null;
|
|
102
|
+
}
|
|
103
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
104
|
+
".claude",
|
|
105
|
+
// Claude Code
|
|
106
|
+
".git",
|
|
107
|
+
// Git
|
|
108
|
+
".swifty",
|
|
109
|
+
// Swifty
|
|
110
|
+
".next",
|
|
111
|
+
// Next.js
|
|
112
|
+
".venv",
|
|
113
|
+
// Python venv
|
|
114
|
+
".mypy_cache",
|
|
115
|
+
// Python mypy
|
|
116
|
+
".tox",
|
|
117
|
+
// Python tox
|
|
118
|
+
"__pycache__",
|
|
119
|
+
// Python
|
|
120
|
+
"build",
|
|
121
|
+
// C++
|
|
122
|
+
"dist",
|
|
123
|
+
// Webpack, Vite
|
|
124
|
+
"node_modules",
|
|
125
|
+
// Node.js
|
|
126
|
+
"vendor",
|
|
127
|
+
// Go
|
|
128
|
+
"venv"
|
|
129
|
+
// Python venv
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
normalizeToolResultContentBlock,
|
|
134
|
+
isToolResultContentBlock,
|
|
135
|
+
SKIP_DIRS
|
|
136
|
+
};
|
|
@@ -54,9 +54,9 @@ var MCPToolWrapper = class {
|
|
|
54
54
|
input_schema: this.inputSchema
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
async execute(
|
|
57
|
+
async execute(ctx, args) {
|
|
58
58
|
try {
|
|
59
|
-
return await this.client.callTool(this.originalName, args);
|
|
59
|
+
return await this.client.callTool(this.originalName, args, ctx.abortSignal);
|
|
60
60
|
} catch (err) {
|
|
61
61
|
log.error({ err }, "mcp operation failed");
|
|
62
62
|
return {
|
|
@@ -82,7 +82,7 @@ function coerceScalar(value, want) {
|
|
|
82
82
|
return value;
|
|
83
83
|
}
|
|
84
84
|
const parsed = want === "integer" ? Number.parseInt(text, 10) : Number.parseFloat(text);
|
|
85
|
-
return Number.
|
|
85
|
+
return Number.isFinite(parsed) ? parsed : value;
|
|
86
86
|
}
|
|
87
87
|
if (want === "boolean" && typeof value === "string") {
|
|
88
88
|
const low = value.trim().toLowerCase();
|
|
@@ -177,21 +177,15 @@ var McpCallTool = class {
|
|
|
177
177
|
}
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
* round.
|
|
186
|
-
*/
|
|
187
|
-
resolve(server, tool) {
|
|
188
|
-
const direct = this.registry.get(tool) ?? this.registry.get(buildMcpToolName(server, tool));
|
|
189
|
-
if (direct) {
|
|
190
|
-
return direct;
|
|
180
|
+
resolveTarget(args) {
|
|
181
|
+
const server = strArg(args, "server");
|
|
182
|
+
const name = strArg(args, "tool");
|
|
183
|
+
if (!server || !name) {
|
|
184
|
+
return void 0;
|
|
191
185
|
}
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
return
|
|
186
|
+
const fullName = name.startsWith(MCP_TOOL_PREFIX) ? name : buildMcpToolName(server, name);
|
|
187
|
+
const target = this.registry.get(fullName);
|
|
188
|
+
return target && isMcpToolLike(target) && sanitizeSegment(target.mcpServerName) === sanitizeSegment(server) ? target : void 0;
|
|
195
189
|
}
|
|
196
190
|
availableNames() {
|
|
197
191
|
return this.registry.listTools().filter((t) => t.name.startsWith(MCP_TOOL_PREFIX)).map((t) => t.name).sort();
|
|
@@ -202,7 +196,7 @@ var McpCallTool = class {
|
|
|
202
196
|
if (tool === "") {
|
|
203
197
|
return { output: "McpCall requires a 'tool' name", isError: true };
|
|
204
198
|
}
|
|
205
|
-
const target = this.
|
|
199
|
+
const target = this.resolveTarget(args);
|
|
206
200
|
if (!target) {
|
|
207
201
|
const names = this.availableNames();
|
|
208
202
|
const hint = names.length > 0 ? names.join(", ") : "(none connected)";
|
|
@@ -211,10 +205,13 @@ var McpCallTool = class {
|
|
|
211
205
|
isError: true
|
|
212
206
|
};
|
|
213
207
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
208
|
+
if (typeof args.arguments !== "object" || args.arguments === null || Array.isArray(args.arguments)) {
|
|
209
|
+
return {
|
|
210
|
+
output: "McpCall requires an 'arguments' object matching the target schema",
|
|
211
|
+
isError: true
|
|
212
|
+
};
|
|
217
213
|
}
|
|
214
|
+
let inner = asRecord(args.arguments);
|
|
218
215
|
if (isMcpToolLike(target)) {
|
|
219
216
|
const schema = target.mcpInputSchema();
|
|
220
217
|
if (Object.keys(schema).length > 0) {
|
|
@@ -224,6 +221,7 @@ var McpCallTool = class {
|
|
|
224
221
|
}
|
|
225
222
|
}
|
|
226
223
|
}
|
|
224
|
+
ctx.abortSignal?.throwIfAborted();
|
|
227
225
|
return target.execute(ctx, inner);
|
|
228
226
|
}
|
|
229
227
|
};
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getMaxOutputTokens,
|
|
3
|
-
resolveAPIKey
|
|
4
|
-
} from "./chunk-3LU4APFB.js";
|
|
5
1
|
import {
|
|
6
2
|
AuthenticationError,
|
|
7
3
|
ContextTooLongError,
|
|
8
4
|
LLMError,
|
|
9
5
|
NetworkError,
|
|
10
6
|
RateLimitError,
|
|
11
|
-
ensureToolPairing
|
|
12
|
-
|
|
7
|
+
ensureToolPairing,
|
|
8
|
+
getMaxOutputTokens,
|
|
9
|
+
resolveAPIKey
|
|
10
|
+
} from "./chunk-FBSPZQGC.js";
|
|
13
11
|
import {
|
|
14
12
|
asRecord,
|
|
15
13
|
asString,
|
|
@@ -82,6 +80,7 @@ var OpenAIClient = class {
|
|
|
82
80
|
let jsonAccumulate = "";
|
|
83
81
|
let reasoningId = "";
|
|
84
82
|
let reasoningText = "";
|
|
83
|
+
let sawTerminalResponse = false;
|
|
85
84
|
for await (const event of stream) {
|
|
86
85
|
if (event.type === "response.output_text.delta") {
|
|
87
86
|
yield {
|
|
@@ -139,19 +138,22 @@ var OpenAIClient = class {
|
|
|
139
138
|
currentToolId = "";
|
|
140
139
|
jsonAccumulate = "";
|
|
141
140
|
}
|
|
142
|
-
} else if (event.type === "response.completed") {
|
|
141
|
+
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
142
|
+
sawTerminalResponse = true;
|
|
143
143
|
const usage = event.response.usage;
|
|
144
144
|
if (usage) {
|
|
145
145
|
outputTokens = usage.output_tokens;
|
|
146
|
-
cacheReadInputTokens = usage.input_tokens_details
|
|
146
|
+
cacheReadInputTokens = usage.input_tokens_details?.cached_tokens ?? 0;
|
|
147
147
|
inputTokens = Math.max(0, usage.input_tokens - cacheReadInputTokens);
|
|
148
148
|
}
|
|
149
149
|
let stopReason = "end_turn";
|
|
150
150
|
const resp = event.response;
|
|
151
|
-
if (resp.status === "incomplete") {
|
|
151
|
+
if (event.type === "response.incomplete" || resp.status === "incomplete") {
|
|
152
152
|
const details = resp.incomplete_details;
|
|
153
153
|
if (details?.reason === "max_output_tokens") {
|
|
154
154
|
stopReason = "max_tokens";
|
|
155
|
+
} else {
|
|
156
|
+
throw new LLMError(`Response incomplete: ${details?.reason ?? "unknown reason"}`);
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
yield {
|
|
@@ -165,8 +167,18 @@ var OpenAIClient = class {
|
|
|
165
167
|
// 0
|
|
166
168
|
}
|
|
167
169
|
};
|
|
170
|
+
} else if (event.type === "response.failed") {
|
|
171
|
+
const error = event.response.error;
|
|
172
|
+
const message = `${error?.code ?? "unknown"}: ${error?.message ?? "Response failed"}`;
|
|
173
|
+
throw containsContextLengthError(message) ? new ContextTooLongError(message) : new LLMError(message);
|
|
174
|
+
} else if (event.type === "error") {
|
|
175
|
+
const message = `${event.code ?? "unknown"}: ${event.message}`;
|
|
176
|
+
throw containsContextLengthError(message) ? new ContextTooLongError(message) : new LLMError(message);
|
|
168
177
|
}
|
|
169
178
|
}
|
|
179
|
+
if (!sawTerminalResponse) {
|
|
180
|
+
throw new NetworkError("OpenAI Responses stream ended before a terminal response event");
|
|
181
|
+
}
|
|
170
182
|
} catch (err) {
|
|
171
183
|
log.error({ err }, "llm operation failed");
|
|
172
184
|
throw classifyOpenAIError(err);
|
|
@@ -349,6 +361,9 @@ function buildOpenAIInput(messages) {
|
|
|
349
361
|
output: toolOutputForResponses(tr)
|
|
350
362
|
});
|
|
351
363
|
}
|
|
364
|
+
if (m.content.length > 0) {
|
|
365
|
+
result.push({ role: "user", content: userContentsFor(m.content) });
|
|
366
|
+
}
|
|
352
367
|
} else if (m.role === "assistant") {
|
|
353
368
|
result.push({
|
|
354
369
|
role: "assistant",
|
|
@@ -510,6 +525,9 @@ var OpenAICompatClient = class {
|
|
|
510
525
|
}
|
|
511
526
|
}
|
|
512
527
|
}
|
|
528
|
+
if (finishReason === null) {
|
|
529
|
+
throw new NetworkError("Chat Completions stream ended before a finish reason");
|
|
530
|
+
}
|
|
513
531
|
let stopReason;
|
|
514
532
|
if (finishReason === "length") {
|
|
515
533
|
stopReason = "max_tokens";
|
|
@@ -535,6 +553,9 @@ var OpenAICompatClient = class {
|
|
|
535
553
|
}
|
|
536
554
|
};
|
|
537
555
|
function classifyOpenAIError(err) {
|
|
556
|
+
if (err instanceof LLMError) {
|
|
557
|
+
return err;
|
|
558
|
+
}
|
|
538
559
|
if (err instanceof OpenAI.APIError) {
|
|
539
560
|
if (err.status === 413 /* PromptTooLong */ || err.status === 400 /* BadRequest */ && containsContextLengthError(err.message)) {
|
|
540
561
|
return new ContextTooLongError(`Context Too Long: ${err.message}`);
|
|
@@ -543,7 +564,11 @@ function classifyOpenAIError(err) {
|
|
|
543
564
|
return new AuthenticationError(`Invalid API key: ${err.message}`);
|
|
544
565
|
}
|
|
545
566
|
if (err.status === 429 /* RateLimitError */) {
|
|
546
|
-
|
|
567
|
+
const headers = err.headers;
|
|
568
|
+
return new RateLimitError(
|
|
569
|
+
"Rate limit error, please wait.",
|
|
570
|
+
headers instanceof Headers ? headers.get("retry-after") ?? void 0 : void 0
|
|
571
|
+
);
|
|
547
572
|
}
|
|
548
573
|
return new LLMError(`OpenAI API error (${asString(err.status)}): ${err.message}`);
|
|
549
574
|
}
|
|
@@ -558,16 +583,14 @@ function buildChatCompletionMessages(messages) {
|
|
|
558
583
|
params.push({
|
|
559
584
|
role: "assistant",
|
|
560
585
|
content: assistantText || null,
|
|
586
|
+
...reasoning ? { reasoning_content: reasoning } : {},
|
|
561
587
|
tool_calls: m.toolUses.map((tu) => ({
|
|
562
588
|
id: tu.toolUseId,
|
|
563
589
|
type: "function",
|
|
564
590
|
function: {
|
|
565
591
|
name: tu.toolName,
|
|
566
592
|
arguments: JSON.stringify(tu.arguments)
|
|
567
|
-
}
|
|
568
|
-
...reasoning ? {
|
|
569
|
-
reasoning_content: reasoning
|
|
570
|
-
} : {}
|
|
593
|
+
}
|
|
571
594
|
}))
|
|
572
595
|
});
|
|
573
596
|
} else if (m.toolResults && m.toolResults.length > 0) {
|
|
@@ -580,6 +603,12 @@ function buildChatCompletionMessages(messages) {
|
|
|
580
603
|
});
|
|
581
604
|
pendingRichParts.push(...collectRichParts(tr));
|
|
582
605
|
}
|
|
606
|
+
if (m.content.length > 0) {
|
|
607
|
+
const content = userPartsFor(m.content);
|
|
608
|
+
pendingRichParts.push(
|
|
609
|
+
...typeof content === "string" ? [{ type: "text", text: content }] : content
|
|
610
|
+
);
|
|
611
|
+
}
|
|
583
612
|
if (pendingRichParts.length > 0) {
|
|
584
613
|
params.push({
|
|
585
614
|
role: "user",
|
package/dist/lib/glob.wasm
CHANGED
|
Binary file
|