@swifty.js/swifty 0.0.29 → 0.0.31
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 +25 -11
- package/dist/agent-O6C4FCQY.js +4 -0
- package/dist/anthropic-CFM2DXMB.js +4 -0
- package/dist/checker-A6PGACKZ.js +4 -0
- package/dist/chunk-4ABFUBO4.js +601 -0
- package/dist/{chunk-K5ZK27BX.js → chunk-AGJYBJ5M.js} +1 -1
- package/dist/chunk-AQ3A5CF4.js +5 -0
- package/dist/chunk-MVVSONAE.js +4 -0
- package/dist/chunk-OQCEP2F5.js +4 -0
- package/dist/{chunk-QFSCPD63.js → chunk-TCQ4EB4G.js} +1 -1
- package/dist/chunk-Y2UUXOQA.js +4 -0
- package/dist/chunk-YAXZ2OUD.js +150 -0
- package/dist/lib/agent-YRTROHXU.js +10 -0
- package/dist/lib/{anthropic-KWO3KLNV.js → anthropic-R6DMXE7U.js} +4 -5
- package/dist/lib/{checker-AXHPKVBY.js → checker-M7RKMKJQ.js} +2 -3
- package/dist/lib/{chunk-KZSBR4FO.js → chunk-4MDCRPVV.js} +76 -40
- package/dist/lib/{chunk-DJ6AILPN.js → chunk-A4MXZA5Q.js} +209 -51
- package/dist/lib/{chunk-2IVEVG5N.js → chunk-EWE5IWZE.js} +28 -25
- package/dist/lib/{chunk-KG4MJGKQ.js → chunk-FZ4Y6MBN.js} +1 -4
- package/dist/lib/{chunk-GCY44T7S.js → chunk-J6AV7SIF.js} +221 -351
- package/dist/lib/{chunk-3FBS5NB7.js → chunk-OEPCNATU.js} +217 -41
- package/dist/lib/{chunk-Z4CYHTII.js → chunk-OQIQOU5S.js} +85 -26
- package/dist/lib/{chunk-PIL7M52F.js → chunk-XT67KGWE.js} +16 -3
- package/dist/lib/index.d.ts +1212 -932
- package/dist/lib/index.js +2836 -1611
- package/dist/lib/{openai-PBF7EWNJ.js → openai-5N42ZYIJ.js} +2 -2
- package/dist/lib/{tool-filter-R6HDDJHE.js → tool-filter-XG2GXFVN.js} +3 -2
- package/dist/main.js +197 -189
- package/dist/openai-NQYARTT6.js +34 -0
- package/dist/{server-G23HCFLI.js → server-BNT2IIKB.js} +18 -18
- package/dist/tool-filter-5NDJMSTD.js +4 -0
- package/package.json +4 -3
- package/dist/agent-YR6YK26C.js +0 -4
- package/dist/anthropic-5GRR5JCT.js +0 -4
- package/dist/checker-N5TIJEN5.js +0 -4
- package/dist/chunk-D34FUVGU.js +0 -4
- package/dist/chunk-E55KH72M.js +0 -4
- package/dist/chunk-LIMEBKCY.js +0 -408
- package/dist/chunk-POHIQUFP.js +0 -301
- package/dist/chunk-QCKJLO6X.js +0 -4
- package/dist/chunk-TMEX7RFA.js +0 -4
- package/dist/chunk-Y6SQB5FG.js +0 -4
- package/dist/glob.wasm +0 -0
- package/dist/lib/agent-5WEKVRTD.js +0 -11
- package/dist/lib/chunk-GHF2PSEW.js +0 -8
- package/dist/lib/glob.wasm +0 -0
- package/dist/openai-QQ2K7GPF.js +0 -34
- package/dist/tool-filter-VBP6WOGO.js +0 -4
|
@@ -4,12 +4,14 @@ import {
|
|
|
4
4
|
LLMError,
|
|
5
5
|
NetworkError,
|
|
6
6
|
RateLimitError,
|
|
7
|
+
clampThinkingLevel,
|
|
7
8
|
ensureToolPairing,
|
|
8
9
|
getMaxOutputTokens,
|
|
10
|
+
getSupportedThinkingLevels,
|
|
9
11
|
getThinkingLevel,
|
|
10
12
|
resolveAPIKey,
|
|
11
13
|
toReasoningEffort
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-OQIQOU5S.js";
|
|
13
15
|
import {
|
|
14
16
|
asRecord,
|
|
15
17
|
asString,
|
|
@@ -22,12 +24,90 @@ import {
|
|
|
22
24
|
// src/llm/openai.ts
|
|
23
25
|
import OpenAI from "openai";
|
|
24
26
|
var log = createChildLogger({ module: "llm" });
|
|
27
|
+
function computerActionArguments(action) {
|
|
28
|
+
switch (action.type) {
|
|
29
|
+
case "scroll":
|
|
30
|
+
return {
|
|
31
|
+
type: "scroll",
|
|
32
|
+
x: action.x,
|
|
33
|
+
y: action.y,
|
|
34
|
+
scrollX: action.scroll_x,
|
|
35
|
+
scrollY: action.scroll_y,
|
|
36
|
+
...action.keys?.length ? { keys: action.keys } : {}
|
|
37
|
+
};
|
|
38
|
+
case "click":
|
|
39
|
+
case "double_click":
|
|
40
|
+
case "drag":
|
|
41
|
+
case "move": {
|
|
42
|
+
const { keys, ...rest } = action;
|
|
43
|
+
return {
|
|
44
|
+
...rest,
|
|
45
|
+
...keys?.length ? { keys } : {}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
return { ...action };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function computerCallArguments(item) {
|
|
53
|
+
const actions = item.actions ?? (item.action ? [item.action] : []);
|
|
54
|
+
return {
|
|
55
|
+
actions: actions.map(computerActionArguments),
|
|
56
|
+
pendingSafetyChecks: item.pending_safety_checks.map((check) => ({
|
|
57
|
+
id: check.id,
|
|
58
|
+
...check.code ? { code: check.code } : {},
|
|
59
|
+
...check.message ? { message: check.message } : {}
|
|
60
|
+
})),
|
|
61
|
+
status: item.status
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function toOpenAIResponsesTool(schema) {
|
|
65
|
+
if ("type" in schema && schema.type === "computer") {
|
|
66
|
+
return { ...schema };
|
|
67
|
+
}
|
|
68
|
+
if ("input_schema" in schema) {
|
|
69
|
+
const tool = schema;
|
|
70
|
+
return {
|
|
71
|
+
type: "function",
|
|
72
|
+
name: tool.name,
|
|
73
|
+
description: tool.description,
|
|
74
|
+
parameters: tool.input_schema,
|
|
75
|
+
strict: tool.strict ?? false
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if ("type" in schema && schema.type === "function" && "parameters" in schema) {
|
|
79
|
+
return { ...schema };
|
|
80
|
+
}
|
|
81
|
+
throw new Error("OpenAI Responses received a tool schema serialized for another protocol.");
|
|
82
|
+
}
|
|
83
|
+
function toOpenAICompatTool(schema) {
|
|
84
|
+
if ("input_schema" in schema) {
|
|
85
|
+
const tool = schema;
|
|
86
|
+
return {
|
|
87
|
+
type: "function",
|
|
88
|
+
function: {
|
|
89
|
+
name: tool.name,
|
|
90
|
+
description: tool.description,
|
|
91
|
+
parameters: tool.input_schema,
|
|
92
|
+
strict: tool.strict ?? false
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if ("function" in schema) {
|
|
97
|
+
return { ...schema };
|
|
98
|
+
}
|
|
99
|
+
throw new Error(
|
|
100
|
+
"OpenAI Chat Completions received a tool schema serialized for another protocol."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
25
103
|
var OpenAIClient = class {
|
|
104
|
+
protocol = "openai";
|
|
26
105
|
client;
|
|
27
106
|
model;
|
|
28
107
|
systemPrompt;
|
|
29
108
|
maxOutputTokens;
|
|
30
109
|
thinkingLevel;
|
|
110
|
+
config;
|
|
31
111
|
constructor(config, systemPrompt) {
|
|
32
112
|
const apiKey = resolveAPIKey(config);
|
|
33
113
|
if (!apiKey) {
|
|
@@ -42,6 +122,7 @@ var OpenAIClient = class {
|
|
|
42
122
|
this.model = config.model;
|
|
43
123
|
this.systemPrompt = systemPrompt;
|
|
44
124
|
this.maxOutputTokens = getMaxOutputTokens(config);
|
|
125
|
+
this.config = { ...config };
|
|
45
126
|
this.thinkingLevel = getThinkingLevel(config);
|
|
46
127
|
}
|
|
47
128
|
async *stream(conversation, toolSchemas, abortSignal) {
|
|
@@ -54,25 +135,17 @@ var OpenAIClient = class {
|
|
|
54
135
|
for (const message of messages) {
|
|
55
136
|
input.push(message);
|
|
56
137
|
}
|
|
57
|
-
const tools = toolSchemas.map(
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
type: "function",
|
|
61
|
-
name: s.name,
|
|
62
|
-
description: s.description,
|
|
63
|
-
parameters: schema,
|
|
64
|
-
strict: false
|
|
65
|
-
};
|
|
66
|
-
});
|
|
138
|
+
const tools = toolSchemas.map(toOpenAIResponsesTool);
|
|
139
|
+
const effort = toReasoningEffort(this.getThinkingLevel(), this.config);
|
|
67
140
|
const params = {
|
|
68
141
|
model: this.model,
|
|
69
142
|
input,
|
|
70
143
|
stream: true,
|
|
71
144
|
max_output_tokens: this.maxOutputTokens,
|
|
72
145
|
...tools.length > 0 ? { tools } : {},
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
...
|
|
146
|
+
// Only explicit reasoning:false omits the field. Off sends none to defeat
|
|
147
|
+
// server-default reasoning; requesting a summary while off is unnecessary.
|
|
148
|
+
...effort !== null ? { reasoning: { effort, ...effort !== "none" ? { summary: "auto" } : {} } } : {}
|
|
76
149
|
};
|
|
77
150
|
let inputTokens = 0;
|
|
78
151
|
let outputTokens = 0;
|
|
@@ -119,6 +192,12 @@ var OpenAIClient = class {
|
|
|
119
192
|
toolName: currentToolName,
|
|
120
193
|
toolId: currentToolId
|
|
121
194
|
};
|
|
195
|
+
} else if (event.item.type === "computer_call") {
|
|
196
|
+
yield {
|
|
197
|
+
type: "tool_call_start",
|
|
198
|
+
toolName: "ComputerUse",
|
|
199
|
+
toolId: event.item.call_id
|
|
200
|
+
};
|
|
122
201
|
} else if (event.item.type === "reasoning") {
|
|
123
202
|
reasoningId = event.item.id ?? "";
|
|
124
203
|
reasoningText = "";
|
|
@@ -144,6 +223,14 @@ var OpenAIClient = class {
|
|
|
144
223
|
currentToolName = "";
|
|
145
224
|
currentToolId = "";
|
|
146
225
|
jsonAccumulate = "";
|
|
226
|
+
} else if (event.item.type === "computer_call") {
|
|
227
|
+
yield {
|
|
228
|
+
type: "tool_call_complete",
|
|
229
|
+
toolId: event.item.call_id,
|
|
230
|
+
toolName: "ComputerUse",
|
|
231
|
+
arguments: computerCallArguments(event.item),
|
|
232
|
+
providerItemId: event.item.id
|
|
233
|
+
};
|
|
147
234
|
}
|
|
148
235
|
} else if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
149
236
|
sawTerminalResponse = true;
|
|
@@ -198,11 +285,15 @@ var OpenAIClient = class {
|
|
|
198
285
|
this.maxOutputTokens = maxTokens;
|
|
199
286
|
}
|
|
200
287
|
setThinkingLevel(level) {
|
|
201
|
-
this.thinkingLevel = level;
|
|
288
|
+
this.thinkingLevel = clampThinkingLevel(this.config, level);
|
|
289
|
+
return this.thinkingLevel;
|
|
202
290
|
}
|
|
203
291
|
getThinkingLevel() {
|
|
204
292
|
return this.thinkingLevel;
|
|
205
293
|
}
|
|
294
|
+
getSupportedThinkingLevels() {
|
|
295
|
+
return getSupportedThinkingLevels(this.config);
|
|
296
|
+
}
|
|
206
297
|
};
|
|
207
298
|
function imageDataUrl(block) {
|
|
208
299
|
if (!isRecord(block) || block.type !== "image" || !isRecord(block.source)) {
|
|
@@ -283,6 +374,56 @@ function toolOutputForResponses(tr) {
|
|
|
283
374
|
}
|
|
284
375
|
return rich.length > 0 ? rich : tr.content;
|
|
285
376
|
}
|
|
377
|
+
function computerActionsForResponses(args) {
|
|
378
|
+
if (!Array.isArray(args.actions)) {
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
const actions = [];
|
|
382
|
+
for (const raw of args.actions) {
|
|
383
|
+
if (!isRecord(raw) || typeof raw.type !== "string") {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (raw.type === "scroll") {
|
|
387
|
+
actions.push({
|
|
388
|
+
type: "scroll",
|
|
389
|
+
x: Number(raw.x),
|
|
390
|
+
y: Number(raw.y),
|
|
391
|
+
scroll_x: Number(raw.scrollX),
|
|
392
|
+
scroll_y: Number(raw.scrollY),
|
|
393
|
+
...Array.isArray(raw.keys) ? { keys: raw.keys.map(String) } : {}
|
|
394
|
+
});
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
actions.push(raw);
|
|
398
|
+
}
|
|
399
|
+
return actions;
|
|
400
|
+
}
|
|
401
|
+
function safetyChecksForResponses(args) {
|
|
402
|
+
if (!Array.isArray(args.pendingSafetyChecks)) {
|
|
403
|
+
return [];
|
|
404
|
+
}
|
|
405
|
+
return args.pendingSafetyChecks.flatMap((raw) => {
|
|
406
|
+
if (!isRecord(raw) || typeof raw.id !== "string") {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
return [
|
|
410
|
+
{
|
|
411
|
+
id: raw.id,
|
|
412
|
+
...typeof raw.code === "string" ? { code: raw.code } : {},
|
|
413
|
+
...typeof raw.message === "string" ? { message: raw.message } : {}
|
|
414
|
+
}
|
|
415
|
+
];
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
function computerScreenshotUrl(tr) {
|
|
419
|
+
for (const block of tr.contentBlocks ?? []) {
|
|
420
|
+
const url = imageDataUrl(block);
|
|
421
|
+
if (url) {
|
|
422
|
+
return url;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return void 0;
|
|
426
|
+
}
|
|
286
427
|
function collectRichParts(tr) {
|
|
287
428
|
if (!tr.contentBlocks?.length) {
|
|
288
429
|
return [];
|
|
@@ -340,6 +481,14 @@ function userPartsFor(content) {
|
|
|
340
481
|
}
|
|
341
482
|
function buildOpenAIInput(messages) {
|
|
342
483
|
const result = [];
|
|
484
|
+
const computerCalls = /* @__PURE__ */ new Map();
|
|
485
|
+
for (const message of messages) {
|
|
486
|
+
for (const toolUse of message.toolUses ?? []) {
|
|
487
|
+
if (toolUse.toolName === "ComputerUse") {
|
|
488
|
+
computerCalls.set(toolUse.toolUseId, toolUse);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
343
492
|
for (const m of messages) {
|
|
344
493
|
if (m.thinkingBlocks) {
|
|
345
494
|
for (const tb of m.thinkingBlocks) {
|
|
@@ -359,20 +508,49 @@ function buildOpenAIInput(messages) {
|
|
|
359
508
|
});
|
|
360
509
|
}
|
|
361
510
|
for (const tu of m.toolUses) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
511
|
+
if (tu.toolName === "ComputerUse") {
|
|
512
|
+
const status = tu.arguments.status;
|
|
513
|
+
result.push({
|
|
514
|
+
type: "computer_call",
|
|
515
|
+
id: tu.providerItemId ?? tu.toolUseId,
|
|
516
|
+
call_id: tu.toolUseId,
|
|
517
|
+
status: status === "in_progress" || status === "incomplete" ? status : "completed",
|
|
518
|
+
actions: computerActionsForResponses(tu.arguments),
|
|
519
|
+
pending_safety_checks: safetyChecksForResponses(tu.arguments)
|
|
520
|
+
});
|
|
521
|
+
} else {
|
|
522
|
+
result.push({
|
|
523
|
+
type: "function_call",
|
|
524
|
+
name: tu.toolName,
|
|
525
|
+
call_id: tu.toolUseId,
|
|
526
|
+
arguments: JSON.stringify(tu.arguments)
|
|
527
|
+
});
|
|
528
|
+
}
|
|
368
529
|
}
|
|
369
530
|
} else if (m.toolResults && m.toolResults.length > 0) {
|
|
370
531
|
for (const tr of m.toolResults) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
532
|
+
const computerCall = computerCalls.get(tr.toolUseId);
|
|
533
|
+
if (computerCall) {
|
|
534
|
+
const imageUrl = computerScreenshotUrl(tr);
|
|
535
|
+
result.push({
|
|
536
|
+
type: "computer_call_output",
|
|
537
|
+
call_id: tr.toolUseId,
|
|
538
|
+
output: {
|
|
539
|
+
type: "computer_screenshot",
|
|
540
|
+
...imageUrl ? { image_url: imageUrl } : {}
|
|
541
|
+
},
|
|
542
|
+
acknowledged_safety_checks: safetyChecksForResponses(computerCall.arguments)
|
|
543
|
+
});
|
|
544
|
+
if (tr.isError || !imageUrl) {
|
|
545
|
+
result.push({ role: "user", content: tr.content });
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
result.push({
|
|
549
|
+
type: "function_call_output",
|
|
550
|
+
call_id: tr.toolUseId,
|
|
551
|
+
output: toolOutputForResponses(tr)
|
|
552
|
+
});
|
|
553
|
+
}
|
|
376
554
|
}
|
|
377
555
|
if (m.content.length > 0) {
|
|
378
556
|
result.push({ role: "user", content: userContentsFor(m.content) });
|
|
@@ -395,11 +573,13 @@ function containsContextLengthError(msg) {
|
|
|
395
573
|
return /context_length_exceeded/i.test(msg) || /maximum\scontext\slength/i.test(msg) || /prompts?\s+too\s+long/i.test(msg);
|
|
396
574
|
}
|
|
397
575
|
var OpenAICompatClient = class {
|
|
576
|
+
protocol = "openai-compat";
|
|
398
577
|
client;
|
|
399
578
|
model;
|
|
400
579
|
systemPrompt;
|
|
401
580
|
maxOutputTokens;
|
|
402
581
|
thinkingLevel;
|
|
582
|
+
config;
|
|
403
583
|
constructor(config, systemPrompt) {
|
|
404
584
|
const apiKey = resolveAPIKey(config);
|
|
405
585
|
if (!apiKey) {
|
|
@@ -411,6 +591,7 @@ var OpenAICompatClient = class {
|
|
|
411
591
|
this.model = config.model;
|
|
412
592
|
this.systemPrompt = systemPrompt;
|
|
413
593
|
this.maxOutputTokens = getMaxOutputTokens(config);
|
|
594
|
+
this.config = { ...config };
|
|
414
595
|
this.thinkingLevel = getThinkingLevel(config);
|
|
415
596
|
}
|
|
416
597
|
setSystemPrompt(prompt) {
|
|
@@ -420,11 +601,15 @@ var OpenAICompatClient = class {
|
|
|
420
601
|
this.maxOutputTokens = maxTokens;
|
|
421
602
|
}
|
|
422
603
|
setThinkingLevel(level) {
|
|
423
|
-
this.thinkingLevel = level;
|
|
604
|
+
this.thinkingLevel = clampThinkingLevel(this.config, level);
|
|
605
|
+
return this.thinkingLevel;
|
|
424
606
|
}
|
|
425
607
|
getThinkingLevel() {
|
|
426
608
|
return this.thinkingLevel;
|
|
427
609
|
}
|
|
610
|
+
getSupportedThinkingLevels() {
|
|
611
|
+
return getSupportedThinkingLevels(this.config);
|
|
612
|
+
}
|
|
428
613
|
async *stream(conversation, toolSchemas, abortSignal) {
|
|
429
614
|
const messages = [
|
|
430
615
|
{
|
|
@@ -433,17 +618,8 @@ var OpenAICompatClient = class {
|
|
|
433
618
|
},
|
|
434
619
|
...buildChatCompletionMessages(ensureToolPairing(conversation.getMessages()))
|
|
435
620
|
];
|
|
436
|
-
const tools = toolSchemas.map(
|
|
437
|
-
|
|
438
|
-
// description: ts.description,
|
|
439
|
-
type: "function",
|
|
440
|
-
function: {
|
|
441
|
-
name: ts.name,
|
|
442
|
-
description: ts.description,
|
|
443
|
-
parameters: ts.input_schema,
|
|
444
|
-
strict: false
|
|
445
|
-
}
|
|
446
|
-
}));
|
|
621
|
+
const tools = toolSchemas.map(toOpenAICompatTool);
|
|
622
|
+
const effort = toReasoningEffort(this.getThinkingLevel(), this.config);
|
|
447
623
|
const params = {
|
|
448
624
|
model: this.model,
|
|
449
625
|
messages,
|
|
@@ -451,9 +627,9 @@ var OpenAICompatClient = class {
|
|
|
451
627
|
stream_options: { include_usage: true },
|
|
452
628
|
max_tokens: this.maxOutputTokens,
|
|
453
629
|
...tools.length > 0 ? { tools } : {},
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
...
|
|
630
|
+
// Configured non-reasoning providers omit the field; off otherwise sends
|
|
631
|
+
// none explicitly so a server default cannot silently enable reasoning.
|
|
632
|
+
...effort !== null ? { reasoning_effort: effort } : {}
|
|
457
633
|
};
|
|
458
634
|
let inputTokens = 0;
|
|
459
635
|
let outputTokens = 0;
|
|
@@ -40,7 +40,7 @@ var ContextTooLongError = class extends LLMError {
|
|
|
40
40
|
import { existsSync, readFileSync } from "fs";
|
|
41
41
|
import { homedir } from "os";
|
|
42
42
|
import { join } from "path";
|
|
43
|
-
import { safeParse } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
43
|
+
import { getParseErrorMessage, safeParse } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
44
44
|
import yaml from "js-yaml";
|
|
45
45
|
import { z } from "zod";
|
|
46
46
|
var log = createChildLogger({ module: "config" });
|
|
@@ -63,8 +63,18 @@ function globalConfigPath() {
|
|
|
63
63
|
return join(homedir(), ".swifty", "config.yaml");
|
|
64
64
|
}
|
|
65
65
|
var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
66
|
-
var
|
|
67
|
-
var
|
|
66
|
+
var ReasoningEffortSchema = z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
67
|
+
var AnthropicEffortSchema = z.enum(["low", "medium", "high", "xhigh", "max"]);
|
|
68
|
+
var ThinkingLevelMapSchema = z.strictObject({
|
|
69
|
+
off: z.literal("none").nullable().optional(),
|
|
70
|
+
minimal: ReasoningEffortSchema.nullable().optional(),
|
|
71
|
+
low: ReasoningEffortSchema.nullable().optional(),
|
|
72
|
+
medium: ReasoningEffortSchema.nullable().optional(),
|
|
73
|
+
high: ReasoningEffortSchema.nullable().optional(),
|
|
74
|
+
xhigh: ReasoningEffortSchema.nullable().optional(),
|
|
75
|
+
max: ReasoningEffortSchema.nullable().optional()
|
|
76
|
+
});
|
|
77
|
+
var ProviderConfigSchema = z.looseObject({
|
|
68
78
|
name: z.string(),
|
|
69
79
|
/**
|
|
70
80
|
* enum: ["anthropic", "openai", "openai-compat"]
|
|
@@ -73,7 +83,12 @@ var ProviderConfigSchema = z.object({
|
|
|
73
83
|
base_url: z.string(),
|
|
74
84
|
model: z.string(),
|
|
75
85
|
api_key: z.string().optional(),
|
|
76
|
-
thinking:
|
|
86
|
+
thinking: z.enum(THINKING_LEVELS).optional(),
|
|
87
|
+
/** Explicit capability metadata, never inferred from model names. */
|
|
88
|
+
reasoning: z.boolean().optional(),
|
|
89
|
+
thinking_level_map: ThinkingLevelMapSchema.optional(),
|
|
90
|
+
/** Only Anthropic uses this mode; existing configurations use budgets. */
|
|
91
|
+
thinking_mode: z.enum(["budget", "adaptive"]).optional(),
|
|
77
92
|
context_window: z.coerce.number().optional(),
|
|
78
93
|
/**
|
|
79
94
|
* The model's output ceiling (PI's `model.maxTokens`). Clamped to the
|
|
@@ -92,27 +107,69 @@ var THINKING_BUDGETS = {
|
|
|
92
107
|
xhigh: 32768,
|
|
93
108
|
max: 65536
|
|
94
109
|
};
|
|
110
|
+
var MIN_THINKING_BUDGET_TOKENS = 1024;
|
|
111
|
+
var MIN_THINKING_ANSWER_TOKENS = 1024;
|
|
95
112
|
function isValidThinkingLevel(value) {
|
|
96
|
-
return THINKING_LEVELS.
|
|
97
|
-
}
|
|
98
|
-
function defaultThinkingLevelFor(protocol) {
|
|
99
|
-
return protocol === "anthropic" ? DEFAULT_THINKING_LEVEL : "off";
|
|
113
|
+
return THINKING_LEVELS.some((level) => level === value);
|
|
100
114
|
}
|
|
101
115
|
function getThinkingLevel(provider) {
|
|
102
|
-
|
|
103
|
-
if (thinking === void 0) {
|
|
104
|
-
return defaultThinkingLevelFor(provider.protocol);
|
|
105
|
-
}
|
|
106
|
-
if (typeof thinking === "boolean") {
|
|
107
|
-
return thinking ? defaultThinkingLevelFor(provider.protocol) : "off";
|
|
108
|
-
}
|
|
109
|
-
return thinking;
|
|
116
|
+
return clampThinkingLevel(provider, provider.thinking ?? DEFAULT_THINKING_LEVEL);
|
|
110
117
|
}
|
|
111
118
|
function thinkingBudgetForLevel(level) {
|
|
112
119
|
return level === "off" ? 0 : THINKING_BUDGETS[level];
|
|
113
120
|
}
|
|
114
|
-
function toReasoningEffort(level) {
|
|
115
|
-
|
|
121
|
+
function toReasoningEffort(level, provider) {
|
|
122
|
+
if (provider?.reasoning === false) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if (level === "off") {
|
|
126
|
+
return "none";
|
|
127
|
+
}
|
|
128
|
+
const mapped = provider?.thinking_level_map?.[level];
|
|
129
|
+
if (mapped !== void 0) {
|
|
130
|
+
return mapped;
|
|
131
|
+
}
|
|
132
|
+
if (provider?.protocol === "anthropic" && provider.thinking_mode === "adaptive") {
|
|
133
|
+
if (level === "minimal") {
|
|
134
|
+
return "low";
|
|
135
|
+
}
|
|
136
|
+
if (level === "xhigh") {
|
|
137
|
+
return "high";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return level;
|
|
141
|
+
}
|
|
142
|
+
function toAnthropicThinkingEffort(level, provider) {
|
|
143
|
+
const parsed = AnthropicEffortSchema.safeParse(toReasoningEffort(level, provider));
|
|
144
|
+
return parsed.success ? parsed.data : null;
|
|
145
|
+
}
|
|
146
|
+
function getSupportedThinkingLevels(provider) {
|
|
147
|
+
if (provider.reasoning === false || provider.protocol === "anthropic" && provider.thinking_mode !== "adaptive" && getMaxOutputTokens(provider) < MIN_THINKING_BUDGET_TOKENS + MIN_THINKING_ANSWER_TOKENS) {
|
|
148
|
+
return ["off"];
|
|
149
|
+
}
|
|
150
|
+
return THINKING_LEVELS.filter((level) => {
|
|
151
|
+
if (level === "off") {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
if (provider.protocol === "anthropic" && provider.thinking_mode === "adaptive") {
|
|
155
|
+
return toAnthropicThinkingEffort(level, provider) !== null;
|
|
156
|
+
}
|
|
157
|
+
const effort = toReasoningEffort(level, provider);
|
|
158
|
+
return effort !== null && effort !== "none";
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function clampThinkingLevel(provider, level) {
|
|
162
|
+
const supported = getSupportedThinkingLevels(provider);
|
|
163
|
+
let effective = "off";
|
|
164
|
+
for (const candidate of THINKING_LEVELS) {
|
|
165
|
+
if (supported.includes(candidate)) {
|
|
166
|
+
effective = candidate;
|
|
167
|
+
}
|
|
168
|
+
if (candidate === level) {
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return effective;
|
|
116
173
|
}
|
|
117
174
|
function withProviderDefaults(provider) {
|
|
118
175
|
return {
|
|
@@ -218,6 +275,10 @@ function loadSingleFile(path) {
|
|
|
218
275
|
const parsed2 = safeParse(z.array(ProviderConfigSchema), raw.providers);
|
|
219
276
|
if (parsed2.success) {
|
|
220
277
|
providers = parsed2.data.map(withProviderDefaults);
|
|
278
|
+
} else {
|
|
279
|
+
throw new ConfigError(
|
|
280
|
+
`Invalid provider configuration in ${path}: ${getParseErrorMessage(parsed2.error)}`
|
|
281
|
+
);
|
|
221
282
|
}
|
|
222
283
|
}
|
|
223
284
|
if ("permission_mode" in raw && typeof raw.permission_mode === "string") {
|
|
@@ -294,13 +355,7 @@ function loadConfig(path, options = {}) {
|
|
|
294
355
|
if (options.allowEmptyProviders) {
|
|
295
356
|
return { providers: [], mcp_servers: [], hooks: [] };
|
|
296
357
|
}
|
|
297
|
-
|
|
298
|
-
join(process.cwd(), ".swifty/config.yaml"),
|
|
299
|
-
join(process.cwd(), ".swifty/config.local.yaml")
|
|
300
|
-
].filter((legacyPath) => existsSync(legacyPath)).join(", ");
|
|
301
|
-
throw new ConfigError(
|
|
302
|
-
`No config file found, expected ${candidate}.` + (legacy ? ` Found project config at ${legacy}; move it to ${candidate}.` : "")
|
|
303
|
-
);
|
|
358
|
+
throw new ConfigError(`No config file found, expected ${candidate}.`);
|
|
304
359
|
}
|
|
305
360
|
const config = loadSingleFile(candidate);
|
|
306
361
|
if (!options.allowEmptyProviders || config.providers.length > 0) {
|
|
@@ -374,11 +429,15 @@ export {
|
|
|
374
429
|
DEFAULT_CONTEXT_WINDOW,
|
|
375
430
|
DEFAULT_MAX_OUTPUT_TOKENS,
|
|
376
431
|
THINKING_BUDGETS,
|
|
432
|
+
MIN_THINKING_BUDGET_TOKENS,
|
|
433
|
+
MIN_THINKING_ANSWER_TOKENS,
|
|
377
434
|
isValidThinkingLevel,
|
|
378
|
-
defaultThinkingLevelFor,
|
|
379
435
|
getThinkingLevel,
|
|
380
436
|
thinkingBudgetForLevel,
|
|
381
437
|
toReasoningEffort,
|
|
438
|
+
toAnthropicThinkingEffort,
|
|
439
|
+
getSupportedThinkingLevels,
|
|
440
|
+
clampThinkingLevel,
|
|
382
441
|
withProviderDefaults,
|
|
383
442
|
getContextWindow,
|
|
384
443
|
getMaxOutputTokens,
|
|
@@ -41,9 +41,17 @@ function normalizeDocumentBlock(value) {
|
|
|
41
41
|
if (value.source.type === "url" && typeof value.source.url === "string") {
|
|
42
42
|
source = { type: "url", url: value.source.url };
|
|
43
43
|
} else if (value.source.type === "base64" && value.source.media_type === "application/pdf" && typeof value.source.data === "string") {
|
|
44
|
-
source = {
|
|
44
|
+
source = {
|
|
45
|
+
type: "base64",
|
|
46
|
+
media_type: "application/pdf",
|
|
47
|
+
data: value.source.data
|
|
48
|
+
};
|
|
45
49
|
} else if (value.source.type === "text" && value.source.media_type === "text/plain" && typeof value.source.data === "string") {
|
|
46
|
-
source = {
|
|
50
|
+
source = {
|
|
51
|
+
type: "text",
|
|
52
|
+
media_type: "text/plain",
|
|
53
|
+
data: value.source.data
|
|
54
|
+
};
|
|
47
55
|
} else if (value.source.type === "content") {
|
|
48
56
|
if (typeof value.source.content === "string") {
|
|
49
57
|
source = { type: "content", content: value.source.content };
|
|
@@ -93,7 +101,12 @@ function normalizeToolResultContentBlock(value) {
|
|
|
93
101
|
}
|
|
94
102
|
content.push(block);
|
|
95
103
|
}
|
|
96
|
-
return {
|
|
104
|
+
return {
|
|
105
|
+
type: "search_result",
|
|
106
|
+
source: value.source,
|
|
107
|
+
title: value.title,
|
|
108
|
+
content
|
|
109
|
+
};
|
|
97
110
|
}
|
|
98
111
|
return normalizeDocumentBlock(value);
|
|
99
112
|
}
|