@justin06lee/yagami 0.6.1 → 0.8.1
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 +29 -7
- package/dist/{chunk-D2PNH6GV.js → chunk-4S5QNDQK.js} +2 -2
- package/dist/{chunk-ZYHC7PXX.js → chunk-U3RFT7QV.js} +547 -60
- package/dist/chunk-U3RFT7QV.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{hostConfig-HmZ3z297.d.ts → hostConfig-CbGD5-lN.d.ts} +115 -2
- package/dist/index.d.ts +15 -12
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-ZYHC7PXX.js.map +0 -1
- /package/dist/{chunk-D2PNH6GV.js.map → chunk-4S5QNDQK.js.map} +0 -0
|
@@ -183,7 +183,7 @@ function resolveClaudeExecutable(explicit) {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// src/version.ts
|
|
186
|
-
var VERSION = "0.
|
|
186
|
+
var VERSION = "0.8.1";
|
|
187
187
|
|
|
188
188
|
// src/core/providers/acp.ts
|
|
189
189
|
import { spawn, spawnSync } from "child_process";
|
|
@@ -198,6 +198,96 @@ import {
|
|
|
198
198
|
PROTOCOL_VERSION
|
|
199
199
|
} from "@agentclientprotocol/sdk";
|
|
200
200
|
|
|
201
|
+
// src/core/interaction.ts
|
|
202
|
+
function record(value) {
|
|
203
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
204
|
+
}
|
|
205
|
+
function optionsOf(schema) {
|
|
206
|
+
const oneOf = Array.isArray(schema["oneOf"]) ? schema["oneOf"] : void 0;
|
|
207
|
+
if (oneOf) {
|
|
208
|
+
const options = oneOf.flatMap((item) => {
|
|
209
|
+
const value = record(item);
|
|
210
|
+
if (!value || typeof value["const"] !== "string") return [];
|
|
211
|
+
return [{
|
|
212
|
+
value: value["const"],
|
|
213
|
+
label: typeof value["title"] === "string" ? value["title"] : value["const"],
|
|
214
|
+
...typeof value["description"] === "string" ? { description: value["description"] } : {}
|
|
215
|
+
}];
|
|
216
|
+
});
|
|
217
|
+
if (options.length > 0) return options;
|
|
218
|
+
}
|
|
219
|
+
const values = Array.isArray(schema["enum"]) ? schema["enum"].filter((value) => typeof value === "string") : [];
|
|
220
|
+
return values.length > 0 ? values.map((value) => ({ value, label: value })) : void 0;
|
|
221
|
+
}
|
|
222
|
+
function inputFields(schema) {
|
|
223
|
+
const root = record(schema);
|
|
224
|
+
const properties = record(root?.["properties"]);
|
|
225
|
+
if (!properties) return [];
|
|
226
|
+
const required = new Set(
|
|
227
|
+
Array.isArray(root?.["required"]) ? root["required"].filter((value) => typeof value === "string") : []
|
|
228
|
+
);
|
|
229
|
+
return Object.entries(properties).flatMap(([id, value]) => {
|
|
230
|
+
const property = record(value);
|
|
231
|
+
if (!property || typeof property["type"] !== "string") return [];
|
|
232
|
+
let type;
|
|
233
|
+
let options = optionsOf(property);
|
|
234
|
+
if (property["type"] === "array") {
|
|
235
|
+
type = "multiselect";
|
|
236
|
+
options = optionsOf(record(property["items"]) ?? {});
|
|
237
|
+
} else if (property["type"] === "string" && options) {
|
|
238
|
+
type = "select";
|
|
239
|
+
} else if (["string", "number", "integer", "boolean"].includes(property["type"])) {
|
|
240
|
+
type = property["type"];
|
|
241
|
+
} else {
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
const defaultValue = property["default"];
|
|
245
|
+
return [{
|
|
246
|
+
id,
|
|
247
|
+
label: typeof property["title"] === "string" ? property["title"] : id,
|
|
248
|
+
type,
|
|
249
|
+
required: required.has(id),
|
|
250
|
+
...typeof property["description"] === "string" ? { description: property["description"] } : {},
|
|
251
|
+
...options ? { options } : {},
|
|
252
|
+
...typeof property["format"] === "string" ? { format: property["format"] } : {},
|
|
253
|
+
...typeof property["minimum"] === "number" ? { minimum: property["minimum"] } : {},
|
|
254
|
+
...typeof property["maximum"] === "number" ? { maximum: property["maximum"] } : {},
|
|
255
|
+
...typeof property["minLength"] === "number" ? { minLength: property["minLength"] } : {},
|
|
256
|
+
...typeof property["maxLength"] === "number" ? { maxLength: property["maxLength"] } : {},
|
|
257
|
+
...typeof defaultValue === "string" || typeof defaultValue === "number" || typeof defaultValue === "boolean" || Array.isArray(defaultValue) && defaultValue.every((item) => typeof item === "string") ? { default: defaultValue } : {}
|
|
258
|
+
}];
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function elicitationRequest(provider, sessionId, raw) {
|
|
262
|
+
const mode = raw["mode"];
|
|
263
|
+
if (mode === "url") {
|
|
264
|
+
return {
|
|
265
|
+
provider,
|
|
266
|
+
...sessionId ? { sessionId } : {},
|
|
267
|
+
kind: "url",
|
|
268
|
+
message: typeof raw["message"] === "string" ? raw["message"] : "Open the requested URL",
|
|
269
|
+
...typeof raw["serverName"] === "string" ? { source: raw["serverName"] } : {},
|
|
270
|
+
...typeof raw["url"] === "string" ? { url: raw["url"] } : {},
|
|
271
|
+
raw
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
provider,
|
|
276
|
+
...sessionId ? { sessionId } : {},
|
|
277
|
+
kind: "form",
|
|
278
|
+
message: typeof raw["message"] === "string" ? raw["message"] : "Input requested",
|
|
279
|
+
...typeof raw["serverName"] === "string" ? { source: raw["serverName"] } : {},
|
|
280
|
+
fields: inputFields(raw["requestedSchema"]),
|
|
281
|
+
raw
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function declineInput() {
|
|
285
|
+
return { action: "decline" };
|
|
286
|
+
}
|
|
287
|
+
function elicitationResponse(response) {
|
|
288
|
+
return response.action === "accept" ? { action: "accept", content: response.values ?? null } : { action: response.action };
|
|
289
|
+
}
|
|
290
|
+
|
|
201
291
|
// src/core/providers/queue.ts
|
|
202
292
|
var AsyncQueue = class {
|
|
203
293
|
buffer = [];
|
|
@@ -277,8 +367,10 @@ var AcpProvider = class {
|
|
|
277
367
|
systemPrompt: false,
|
|
278
368
|
thinking: false,
|
|
279
369
|
effort: false,
|
|
280
|
-
streaming: "tokens"
|
|
370
|
+
streaming: "tokens",
|
|
371
|
+
serverTools: false
|
|
281
372
|
};
|
|
373
|
+
sessionCapabilities = { fork: false };
|
|
282
374
|
args;
|
|
283
375
|
env;
|
|
284
376
|
workDir;
|
|
@@ -323,6 +415,9 @@ var AcpProvider = class {
|
|
|
323
415
|
const agent = new ClientSideConnection(
|
|
324
416
|
() => ({
|
|
325
417
|
requestPermission: (p) => handlers.onPermission ? handlers.onPermission(p) : rejectOption(p),
|
|
418
|
+
unstable_createElicitation: (p) => handlers.onInput ? handlers.onInput(p) : Promise.resolve({ action: "decline" }),
|
|
419
|
+
unstable_completeElicitation: () => {
|
|
420
|
+
},
|
|
326
421
|
sessionUpdate: (n) => {
|
|
327
422
|
handlers.onUpdate?.(n);
|
|
328
423
|
}
|
|
@@ -343,7 +438,13 @@ var AcpProvider = class {
|
|
|
343
438
|
agent.initialize({
|
|
344
439
|
protocolVersion: PROTOCOL_VERSION,
|
|
345
440
|
clientInfo: { name: this.appName, version: VERSION },
|
|
346
|
-
clientCapabilities: {
|
|
441
|
+
clientCapabilities: {
|
|
442
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
443
|
+
terminal: false,
|
|
444
|
+
session: { configOptions: { boolean: {} } },
|
|
445
|
+
plan: {},
|
|
446
|
+
elicitation: { form: {}, url: {} }
|
|
447
|
+
}
|
|
347
448
|
}).then((init) => {
|
|
348
449
|
if (settled) return;
|
|
349
450
|
settled = true;
|
|
@@ -410,6 +511,7 @@ var AcpProvider = class {
|
|
|
410
511
|
});
|
|
411
512
|
}
|
|
412
513
|
if (req.model) await this.selectModel(conn, sessionId, configOptions, req.model);
|
|
514
|
+
if (req.effort) await this.selectEffort(conn, sessionId, configOptions, req.effort);
|
|
413
515
|
const sid = sessionId;
|
|
414
516
|
conn.setHandlers({
|
|
415
517
|
onPermission: async (p) => rejectOption(p),
|
|
@@ -455,6 +557,7 @@ var AcpProvider = class {
|
|
|
455
557
|
connect: (cwd) => this.connectImpl(cwd),
|
|
456
558
|
classify: (err, ctx) => this.classify(err, ctx),
|
|
457
559
|
selectModel: (conn, sessionId, configOptions, model) => this.selectModel(conn, sessionId, configOptions, model),
|
|
560
|
+
selectEffort: (conn, sessionId, configOptions, effort) => this.selectEffort(conn, sessionId, configOptions, effort),
|
|
458
561
|
options
|
|
459
562
|
});
|
|
460
563
|
}
|
|
@@ -468,6 +571,16 @@ var AcpProvider = class {
|
|
|
468
571
|
throw this.classify(err);
|
|
469
572
|
});
|
|
470
573
|
}
|
|
574
|
+
async selectEffort(conn, sessionId, configOptions, effort) {
|
|
575
|
+
const option = configOptions?.find(
|
|
576
|
+
(candidate) => candidate.category === "thought_level" || /^(?:thought[_-]?level|reasoning[_-]?effort|effort)$/i.test(candidate.id)
|
|
577
|
+
);
|
|
578
|
+
if (!option || option.type !== "select" || option.currentValue === effort) return;
|
|
579
|
+
if (!flattenSelectOptions(option).some((candidate) => candidate.value === effort)) return;
|
|
580
|
+
await conn.agent.setSessionConfigOption({ sessionId, configId: option.id, value: effort }).catch((err) => {
|
|
581
|
+
throw this.classify(err);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
471
584
|
async listModels() {
|
|
472
585
|
const conn = await this.connectImpl(this.workDir);
|
|
473
586
|
try {
|
|
@@ -476,10 +589,19 @@ var AcpProvider = class {
|
|
|
476
589
|
});
|
|
477
590
|
const option = created.configOptions?.find((o) => o.id === this.modelConfigId) ?? created.configOptions?.find((o) => o.category === "model");
|
|
478
591
|
if (!option || option.type !== "select") return [];
|
|
592
|
+
const effortOption = created.configOptions?.find(
|
|
593
|
+
(candidate) => candidate.type === "select" && (candidate.category === "thought_level" || /^(?:thought[_-]?level|reasoning[_-]?effort|effort)$/i.test(candidate.id))
|
|
594
|
+
);
|
|
595
|
+
const efforts = effortOption?.type === "select" ? flattenSelectOptions(effortOption).map((entry) => ({
|
|
596
|
+
id: entry.value,
|
|
597
|
+
...entry.description ? { description: entry.description } : {}
|
|
598
|
+
})) : [];
|
|
479
599
|
return flattenSelectOptions(option).map((o) => ({
|
|
480
600
|
id: o.value,
|
|
481
601
|
display_name: o.name,
|
|
482
|
-
...o.description ? { description: o.description } : {}
|
|
602
|
+
...o.description ? { description: o.description } : {},
|
|
603
|
+
...efforts.length > 0 ? { reasoning_efforts: efforts } : {},
|
|
604
|
+
...effortOption?.type === "select" ? { default_reasoning_effort: effortOption.currentValue } : {}
|
|
483
605
|
}));
|
|
484
606
|
} finally {
|
|
485
607
|
conn.close();
|
|
@@ -559,8 +681,10 @@ var AcpAgentSession = class {
|
|
|
559
681
|
if (mode) await conn.agent.setSessionMode({ sessionId, modeId: mode }).catch(() => {
|
|
560
682
|
});
|
|
561
683
|
if (options.model) await this.cfg.selectModel(conn, sessionId, configOptions, options.model);
|
|
684
|
+
if (options.effort) await this.cfg.selectEffort(conn, sessionId, configOptions, options.effort);
|
|
562
685
|
conn.setHandlers({
|
|
563
686
|
onPermission: (p) => this.onPermission(p),
|
|
687
|
+
onInput: (p) => this.onInput(p),
|
|
564
688
|
onUpdate: (n) => this.onUpdate(n)
|
|
565
689
|
});
|
|
566
690
|
}
|
|
@@ -593,6 +717,23 @@ var AcpAgentSession = class {
|
|
|
593
717
|
}
|
|
594
718
|
return rejectOption(p);
|
|
595
719
|
}
|
|
720
|
+
async onInput(p) {
|
|
721
|
+
const request = elicitationRequest(
|
|
722
|
+
this.provider,
|
|
723
|
+
this.sessionId,
|
|
724
|
+
p
|
|
725
|
+
);
|
|
726
|
+
const handler = this.cfg.options.input;
|
|
727
|
+
let response = declineInput();
|
|
728
|
+
if (handler) {
|
|
729
|
+
try {
|
|
730
|
+
response = await handler.respond(request);
|
|
731
|
+
} catch {
|
|
732
|
+
response = { action: "cancel" };
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return elicitationResponse(response);
|
|
736
|
+
}
|
|
596
737
|
onUpdate(n) {
|
|
597
738
|
if (n.sessionId !== this.sessionId) return;
|
|
598
739
|
const u = n.update;
|
|
@@ -603,6 +744,21 @@ var AcpAgentSession = class {
|
|
|
603
744
|
case "agent_thought_chunk":
|
|
604
745
|
if (u.content.type === "text") this.queue?.push({ type: "thinking", text: u.content.text });
|
|
605
746
|
break;
|
|
747
|
+
case "plan":
|
|
748
|
+
this.queue?.push({ type: "plan", plan: acpPlan(u) });
|
|
749
|
+
break;
|
|
750
|
+
case "plan_update":
|
|
751
|
+
this.queue?.push({ type: "plan", plan: acpPlan(u.plan ?? {}) });
|
|
752
|
+
break;
|
|
753
|
+
case "plan_removed":
|
|
754
|
+
this.queue?.push({
|
|
755
|
+
type: "plan",
|
|
756
|
+
plan: {
|
|
757
|
+
...typeof u.planId === "string" ? { id: u.planId } : {},
|
|
758
|
+
removed: true
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
break;
|
|
606
762
|
case "tool_call": {
|
|
607
763
|
const t = u;
|
|
608
764
|
const meta = { name: t.kind ?? "tool", ...t.title ? { title: t.title } : {}, ...t.kind ? { kind: t.kind } : {} };
|
|
@@ -683,6 +839,24 @@ var AcpAgentSession = class {
|
|
|
683
839
|
this.conn = void 0;
|
|
684
840
|
}
|
|
685
841
|
};
|
|
842
|
+
function acpPlan(raw) {
|
|
843
|
+
const entries = Array.isArray(raw["entries"]) ? raw["entries"].flatMap((value) => {
|
|
844
|
+
const entry = value;
|
|
845
|
+
if (typeof entry["content"] !== "string") return [];
|
|
846
|
+
const item = {
|
|
847
|
+
content: entry["content"],
|
|
848
|
+
status: entry["status"] === "completed" ? "completed" : entry["status"] === "in_progress" ? "in_progress" : "pending",
|
|
849
|
+
...["high", "medium", "low"].includes(String(entry["priority"])) ? { priority: entry["priority"] } : {}
|
|
850
|
+
};
|
|
851
|
+
return [item];
|
|
852
|
+
}) : void 0;
|
|
853
|
+
return {
|
|
854
|
+
...typeof raw["planId"] === "string" ? { id: raw["planId"] } : {},
|
|
855
|
+
...entries ? { entries } : {},
|
|
856
|
+
...typeof raw["content"] === "string" ? { markdown: raw["content"] } : {},
|
|
857
|
+
...typeof raw["uri"] === "string" ? { uri: raw["uri"] } : {}
|
|
858
|
+
};
|
|
859
|
+
}
|
|
686
860
|
function supportsResume(init) {
|
|
687
861
|
const caps = init.agentCapabilities;
|
|
688
862
|
return caps?.sessionCapabilities?.resume !== void 0;
|
|
@@ -763,6 +937,15 @@ var DENY_ALL_TOOLS = async (toolName) => ({
|
|
|
763
937
|
message: `yagami is a completions-only endpoint; tool "${toolName}" is disabled.`,
|
|
764
938
|
interrupt: true
|
|
765
939
|
});
|
|
940
|
+
var allowOnly = (enabled) => {
|
|
941
|
+
const allowed = new Set(enabled);
|
|
942
|
+
return async (toolName, input) => allowed.has(toolName) ? { behavior: "allow", updatedInput: input } : {
|
|
943
|
+
behavior: "deny",
|
|
944
|
+
message: `yagami is a completions-only endpoint; tool "${toolName}" is disabled.`,
|
|
945
|
+
interrupt: true
|
|
946
|
+
};
|
|
947
|
+
};
|
|
948
|
+
var SERVER_TOOL_MAX_TURNS = 24;
|
|
766
949
|
var ClaudeProvider = class {
|
|
767
950
|
id = "claude";
|
|
768
951
|
label = "Claude Code";
|
|
@@ -776,7 +959,8 @@ var ClaudeProvider = class {
|
|
|
776
959
|
systemPrompt: true,
|
|
777
960
|
thinking: true,
|
|
778
961
|
effort: true,
|
|
779
|
-
streaming: "tokens"
|
|
962
|
+
streaming: "tokens",
|
|
963
|
+
serverTools: true
|
|
780
964
|
};
|
|
781
965
|
configDir;
|
|
782
966
|
workDir;
|
|
@@ -811,6 +995,11 @@ var ClaudeProvider = class {
|
|
|
811
995
|
const onAbort = () => abortController.abort();
|
|
812
996
|
req.signal?.addEventListener("abort", onAbort, { once: true });
|
|
813
997
|
const options = { ...this.baseOptions(), abortController, includePartialMessages: true };
|
|
998
|
+
if (req.serverTools && req.serverTools.length > 0) {
|
|
999
|
+
options.tools = [...req.serverTools];
|
|
1000
|
+
options.canUseTool = allowOnly(req.serverTools);
|
|
1001
|
+
options.maxTurns = SERVER_TOOL_MAX_TURNS;
|
|
1002
|
+
}
|
|
814
1003
|
if (req.model) options.model = req.model;
|
|
815
1004
|
if (req.system !== void 0) options.systemPrompt = req.system;
|
|
816
1005
|
if (req.resume) {
|
|
@@ -889,7 +1078,11 @@ var ClaudeProvider = class {
|
|
|
889
1078
|
id: m.value,
|
|
890
1079
|
display_name: m.displayName,
|
|
891
1080
|
...m.description ? { description: m.description } : {},
|
|
892
|
-
...m.resolvedModel ? { resolved_model: m.resolvedModel } : {}
|
|
1081
|
+
...m.resolvedModel ? { resolved_model: m.resolvedModel } : {},
|
|
1082
|
+
...m.supportedEffortLevels?.length ? { reasoning_efforts: m.supportedEffortLevels.map((id) => ({ id })) } : {},
|
|
1083
|
+
...m.supportsAdaptiveThinking ? { supports_adaptive_thinking: true } : {},
|
|
1084
|
+
...m.supportsFastMode ? { supports_fast_mode: true } : {},
|
|
1085
|
+
...m.supportsAutoMode ? { supports_auto_mode: true } : {}
|
|
893
1086
|
}));
|
|
894
1087
|
} catch (err) {
|
|
895
1088
|
throw classifyProviderFailure(this.id, this.loginCommand, err);
|
|
@@ -999,12 +1192,17 @@ var CodexAgentSession = class {
|
|
|
999
1192
|
lastUsage;
|
|
1000
1193
|
opening;
|
|
1001
1194
|
closed = false;
|
|
1195
|
+
sending = false;
|
|
1196
|
+
turnAbort;
|
|
1197
|
+
reasoningEmitted = /* @__PURE__ */ new Map();
|
|
1198
|
+
incoming = /* @__PURE__ */ new Map();
|
|
1002
1199
|
/** Item text already emitted as deltas, so item/completed only fills gaps. */
|
|
1003
1200
|
emitted = /* @__PURE__ */ new Map();
|
|
1004
1201
|
get id() {
|
|
1005
1202
|
return this.threadId;
|
|
1006
1203
|
}
|
|
1007
1204
|
fail(err) {
|
|
1205
|
+
this.turnAbort?.abort();
|
|
1008
1206
|
for (const [, p] of this.pending) p.reject(err);
|
|
1009
1207
|
this.pending.clear();
|
|
1010
1208
|
this.queue?.fail(err);
|
|
@@ -1029,6 +1227,7 @@ var CodexAgentSession = class {
|
|
|
1029
1227
|
return promise;
|
|
1030
1228
|
}
|
|
1031
1229
|
respond(id, result) {
|
|
1230
|
+
if (this.incoming.get(id)?.signal.aborted) return;
|
|
1032
1231
|
this.child?.stdin?.write(`${JSON.stringify({ jsonrpc: "2.0", id, result })}
|
|
1033
1232
|
`);
|
|
1034
1233
|
}
|
|
@@ -1082,13 +1281,20 @@ var CodexAgentSession = class {
|
|
|
1082
1281
|
...native.config ? { config: native.config } : {},
|
|
1083
1282
|
...options.systemPrompt ? { developerInstructions: options.systemPrompt } : {}
|
|
1084
1283
|
};
|
|
1284
|
+
if (options.resume && (options.fork || options.forkAt)) {
|
|
1285
|
+
const forked = await this.request("thread/fork", {
|
|
1286
|
+
threadId: options.resume,
|
|
1287
|
+
...options.forkAt ? { lastTurnId: options.forkAt } : {},
|
|
1288
|
+
...overrides
|
|
1289
|
+
});
|
|
1290
|
+
this.threadId = forked["thread"]?.id;
|
|
1291
|
+
if (!this.threadId) throw new ProviderError("codex", "thread/fork returned no thread id");
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1085
1294
|
if (options.resume) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
return;
|
|
1090
|
-
} catch {
|
|
1091
|
-
}
|
|
1295
|
+
const resumed = await this.request("thread/resume", { threadId: options.resume, ...overrides });
|
|
1296
|
+
this.threadId = resumed["thread"]?.id ?? options.resume;
|
|
1297
|
+
return;
|
|
1092
1298
|
}
|
|
1093
1299
|
const started = await this.request("thread/start", overrides);
|
|
1094
1300
|
this.threadId = started["thread"]?.id;
|
|
@@ -1106,7 +1312,17 @@ var CodexAgentSession = class {
|
|
|
1106
1312
|
}
|
|
1107
1313
|
if (!msg.method) return;
|
|
1108
1314
|
if (msg.id !== void 0) {
|
|
1109
|
-
|
|
1315
|
+
const id = msg.id;
|
|
1316
|
+
const controller = new AbortController();
|
|
1317
|
+
const parent = this.turnAbort?.signal;
|
|
1318
|
+
const cancel = () => controller.abort();
|
|
1319
|
+
if (parent?.aborted) controller.abort();
|
|
1320
|
+
else parent?.addEventListener("abort", cancel, { once: true });
|
|
1321
|
+
this.incoming.set(id, controller);
|
|
1322
|
+
void this.handleServerRequest(msg.method, id, msg.params ?? {}, controller.signal).finally(() => {
|
|
1323
|
+
parent?.removeEventListener("abort", cancel);
|
|
1324
|
+
this.incoming.delete(id);
|
|
1325
|
+
});
|
|
1110
1326
|
return;
|
|
1111
1327
|
}
|
|
1112
1328
|
this.handleNotification(msg.method, msg.params ?? {});
|
|
@@ -1116,7 +1332,13 @@ var CodexAgentSession = class {
|
|
|
1116
1332
|
}
|
|
1117
1333
|
handleNotification(method, params) {
|
|
1118
1334
|
if (params["threadId"] !== void 0 && params["threadId"] !== this.threadId) return;
|
|
1335
|
+
if (this.currentTurnId && typeof params["turnId"] === "string" && params["turnId"] !== this.currentTurnId) return;
|
|
1119
1336
|
switch (method) {
|
|
1337
|
+
case "serverRequest/resolved": {
|
|
1338
|
+
const requestId = params["requestId"];
|
|
1339
|
+
if (typeof requestId === "string" || typeof requestId === "number") this.incoming.get(requestId)?.abort();
|
|
1340
|
+
break;
|
|
1341
|
+
}
|
|
1120
1342
|
case "item/agentMessage/delta": {
|
|
1121
1343
|
const itemId = params["itemId"];
|
|
1122
1344
|
const delta = params["delta"];
|
|
@@ -1124,6 +1346,14 @@ var CodexAgentSession = class {
|
|
|
1124
1346
|
this.push({ type: "text", text: delta });
|
|
1125
1347
|
break;
|
|
1126
1348
|
}
|
|
1349
|
+
case "item/reasoning/summaryTextDelta": {
|
|
1350
|
+
const delta = params["delta"];
|
|
1351
|
+
if (typeof delta !== "string") break;
|
|
1352
|
+
const key = `${String(params["itemId"])}:${String(params["summaryIndex"] ?? 0)}`;
|
|
1353
|
+
this.reasoningEmitted.set(key, (this.reasoningEmitted.get(key) ?? 0) + delta.length);
|
|
1354
|
+
this.push({ type: "thinking", text: delta });
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1127
1357
|
case "item/started":
|
|
1128
1358
|
case "item/completed": {
|
|
1129
1359
|
this.handleItem(params["item"], method === "item/completed");
|
|
@@ -1142,11 +1372,32 @@ var CodexAgentSession = class {
|
|
|
1142
1372
|
}
|
|
1143
1373
|
break;
|
|
1144
1374
|
}
|
|
1375
|
+
case "turn/plan/updated": {
|
|
1376
|
+
const steps = Array.isArray(params["plan"]) ? params["plan"] : [];
|
|
1377
|
+
this.push({
|
|
1378
|
+
type: "plan",
|
|
1379
|
+
plan: {
|
|
1380
|
+
...typeof params["explanation"] === "string" ? { explanation: params["explanation"] } : {},
|
|
1381
|
+
entries: steps.flatMap((value) => {
|
|
1382
|
+
const step = value;
|
|
1383
|
+
if (typeof step["step"] !== "string") return [];
|
|
1384
|
+
return [{
|
|
1385
|
+
content: step["step"],
|
|
1386
|
+
status: codexPlanStatus(step["status"])
|
|
1387
|
+
}];
|
|
1388
|
+
})
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
break;
|
|
1392
|
+
}
|
|
1145
1393
|
case "turn/completed": {
|
|
1146
1394
|
const turn = params["turn"];
|
|
1395
|
+
const turnId = params["turn"]?.id;
|
|
1396
|
+
if (this.currentTurnId && turnId && turnId !== this.currentTurnId) break;
|
|
1147
1397
|
const queue = this.queue;
|
|
1148
1398
|
this.queue = null;
|
|
1149
1399
|
this.currentTurnId = void 0;
|
|
1400
|
+
this.turnAbort?.abort();
|
|
1150
1401
|
if (!queue) break;
|
|
1151
1402
|
if (turn.status === "failed") {
|
|
1152
1403
|
queue.fail(this.classify(new Error(turn.error?.message ?? "turn failed")));
|
|
@@ -1183,8 +1434,13 @@ var CodexAgentSession = class {
|
|
|
1183
1434
|
}
|
|
1184
1435
|
case "reasoning": {
|
|
1185
1436
|
if (!completed) break;
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1437
|
+
const summaries = item["summary"] ?? [];
|
|
1438
|
+
summaries.forEach((summary, index) => {
|
|
1439
|
+
const key = `${id}:${index}`;
|
|
1440
|
+
const seen = this.reasoningEmitted.get(key) ?? 0;
|
|
1441
|
+
if (summary.length > seen) this.push({ type: "thinking", text: summary.slice(seen) });
|
|
1442
|
+
this.reasoningEmitted.delete(key);
|
|
1443
|
+
});
|
|
1188
1444
|
break;
|
|
1189
1445
|
}
|
|
1190
1446
|
case "commandExecution": {
|
|
@@ -1237,8 +1493,59 @@ var CodexAgentSession = class {
|
|
|
1237
1493
|
});
|
|
1238
1494
|
break;
|
|
1239
1495
|
}
|
|
1240
|
-
case "
|
|
1496
|
+
case "dynamicToolCall": {
|
|
1497
|
+
const failed = item["status"] === "failed" || item["success"] === false;
|
|
1498
|
+
const namespace = typeof item["namespace"] === "string" ? `${item["namespace"]}.` : "";
|
|
1499
|
+
this.push({
|
|
1500
|
+
type: "tool_call",
|
|
1501
|
+
id,
|
|
1502
|
+
name: `${namespace}${String(item["tool"] ?? "tool")}`,
|
|
1503
|
+
status: completed ? failed ? "failed" : "completed" : "started",
|
|
1504
|
+
kind: "other",
|
|
1505
|
+
input: item["arguments"],
|
|
1506
|
+
...completed ? { output: item["contentItems"] } : {}
|
|
1507
|
+
});
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
case "collabAgentToolCall": {
|
|
1511
|
+
const status = item["status"];
|
|
1512
|
+
const failed = status === "failed" || status === "interrupted";
|
|
1513
|
+
const tool = collabToolName(item["tool"]);
|
|
1514
|
+
this.push({
|
|
1515
|
+
type: "tool_call",
|
|
1516
|
+
id,
|
|
1517
|
+
name: tool,
|
|
1518
|
+
status: completed ? failed ? "failed" : "completed" : "started",
|
|
1519
|
+
title: typeof item["prompt"] === "string" && item["prompt"] ? item["prompt"] : tool,
|
|
1520
|
+
kind: "other",
|
|
1521
|
+
input: {
|
|
1522
|
+
prompt: item["prompt"],
|
|
1523
|
+
model: item["model"],
|
|
1524
|
+
effort: item["reasoningEffort"],
|
|
1525
|
+
receiverThreadIds: item["receiverThreadIds"]
|
|
1526
|
+
},
|
|
1527
|
+
...completed ? { output: item["agentsStates"] } : {}
|
|
1528
|
+
});
|
|
1529
|
+
break;
|
|
1530
|
+
}
|
|
1531
|
+
case "imageView": {
|
|
1532
|
+
this.push({
|
|
1533
|
+
type: "tool_call",
|
|
1534
|
+
id,
|
|
1535
|
+
name: "read_file",
|
|
1536
|
+
status: completed ? "completed" : "started",
|
|
1537
|
+
title: String(item["path"] ?? "image"),
|
|
1538
|
+
kind: "read",
|
|
1539
|
+
input: { path: item["path"] }
|
|
1540
|
+
});
|
|
1541
|
+
break;
|
|
1542
|
+
}
|
|
1241
1543
|
case "plan":
|
|
1544
|
+
if (completed && typeof item["text"] === "string") {
|
|
1545
|
+
this.push({ type: "plan", plan: { id, markdown: item["text"] } });
|
|
1546
|
+
}
|
|
1547
|
+
break;
|
|
1548
|
+
case "userMessage":
|
|
1242
1549
|
break;
|
|
1243
1550
|
default:
|
|
1244
1551
|
this.push({ type: "raw", provider: "codex", payload: item });
|
|
@@ -1246,16 +1553,17 @@ var CodexAgentSession = class {
|
|
|
1246
1553
|
}
|
|
1247
1554
|
}
|
|
1248
1555
|
// ── approvals: forwarded to the host, answered like the TUI would ──
|
|
1249
|
-
async decide(request) {
|
|
1556
|
+
async decide(request, signal) {
|
|
1557
|
+
if (signal?.aborted) return "deny";
|
|
1250
1558
|
try {
|
|
1251
|
-
const decision = await this.config.options.permissions.decide(request);
|
|
1559
|
+
const decision = await this.config.options.permissions.decide(request, signal);
|
|
1252
1560
|
this.push({ type: "permission", request, decision });
|
|
1253
1561
|
return decision;
|
|
1254
1562
|
} catch {
|
|
1255
1563
|
return "deny";
|
|
1256
1564
|
}
|
|
1257
1565
|
}
|
|
1258
|
-
async handleServerRequest(method, id, params) {
|
|
1566
|
+
async handleServerRequest(method, id, params, signal) {
|
|
1259
1567
|
switch (method) {
|
|
1260
1568
|
case "item/commandExecution/requestApproval": {
|
|
1261
1569
|
const decision = await this.decide({
|
|
@@ -1266,7 +1574,7 @@ var CodexAgentSession = class {
|
|
|
1266
1574
|
title: String(params["command"] ?? "command"),
|
|
1267
1575
|
input: { command: params["command"], cwd: params["cwd"], reason: params["reason"] },
|
|
1268
1576
|
raw: params
|
|
1269
|
-
});
|
|
1577
|
+
}, signal);
|
|
1270
1578
|
this.respond(id, {
|
|
1271
1579
|
decision: decision === "allow" ? "accept" : decision === "allow_always" ? "acceptForSession" : "decline"
|
|
1272
1580
|
});
|
|
@@ -1281,7 +1589,7 @@ var CodexAgentSession = class {
|
|
|
1281
1589
|
title: String(params["reason"] ?? "apply file changes"),
|
|
1282
1590
|
input: { reason: params["reason"], grantRoot: params["grantRoot"] },
|
|
1283
1591
|
raw: params
|
|
1284
|
-
});
|
|
1592
|
+
}, signal);
|
|
1285
1593
|
this.respond(id, {
|
|
1286
1594
|
decision: decision === "allow" ? "accept" : decision === "allow_always" ? "acceptForSession" : "decline"
|
|
1287
1595
|
});
|
|
@@ -1297,7 +1605,7 @@ var CodexAgentSession = class {
|
|
|
1297
1605
|
title: String(params["reason"] ?? "extra permissions"),
|
|
1298
1606
|
input: requested,
|
|
1299
1607
|
raw: params
|
|
1300
|
-
});
|
|
1608
|
+
}, signal);
|
|
1301
1609
|
const granted = decision === "allow" || decision === "allow_always";
|
|
1302
1610
|
this.respond(id, {
|
|
1303
1611
|
permissions: granted ? { network: requested?.["network"] ?? void 0, fileSystem: requested?.["fileSystem"] ?? void 0 } : {},
|
|
@@ -1316,18 +1624,32 @@ var CodexAgentSession = class {
|
|
|
1316
1624
|
title: String(params["command"] ?? params["reason"] ?? "approval"),
|
|
1317
1625
|
input: params,
|
|
1318
1626
|
raw: params
|
|
1319
|
-
});
|
|
1627
|
+
}, signal);
|
|
1320
1628
|
this.respond(id, {
|
|
1321
1629
|
decision: decision === "allow" ? "approved" : decision === "allow_always" ? "approved_for_session" : { denied: { rejection: "denied by the user" } }
|
|
1322
1630
|
});
|
|
1323
1631
|
break;
|
|
1324
1632
|
}
|
|
1325
1633
|
case "item/tool/requestUserInput": {
|
|
1326
|
-
this.
|
|
1634
|
+
const response = await this.input(codexQuestionRequest(this.threadId, params), signal);
|
|
1635
|
+
const values = response.action === "accept" ? response.values ?? {} : {};
|
|
1636
|
+
this.respond(id, {
|
|
1637
|
+
answers: Object.fromEntries(
|
|
1638
|
+
Object.entries(values).map(([key, value]) => [
|
|
1639
|
+
key,
|
|
1640
|
+
{ answers: (Array.isArray(value) ? value : [value]).map(String) }
|
|
1641
|
+
])
|
|
1642
|
+
)
|
|
1643
|
+
});
|
|
1327
1644
|
break;
|
|
1328
1645
|
}
|
|
1329
1646
|
case "mcpServer/elicitation/request": {
|
|
1330
|
-
this.
|
|
1647
|
+
const response = await this.input(elicitationRequest("codex", this.threadId, params), signal);
|
|
1648
|
+
this.respond(id, { ...elicitationResponse(response), _meta: null });
|
|
1649
|
+
break;
|
|
1650
|
+
}
|
|
1651
|
+
case "currentTime/read": {
|
|
1652
|
+
this.respond(id, { currentTimeAt: Math.floor(Date.now() / 1e3) });
|
|
1331
1653
|
break;
|
|
1332
1654
|
}
|
|
1333
1655
|
default: {
|
|
@@ -1339,42 +1661,73 @@ var CodexAgentSession = class {
|
|
|
1339
1661
|
}
|
|
1340
1662
|
}
|
|
1341
1663
|
}
|
|
1664
|
+
async input(request, signal) {
|
|
1665
|
+
const handler = this.config.options.input;
|
|
1666
|
+
if (!handler) return declineInput();
|
|
1667
|
+
try {
|
|
1668
|
+
if (signal?.aborted) return { action: "cancel" };
|
|
1669
|
+
return await handler.respond(request, signal);
|
|
1670
|
+
} catch {
|
|
1671
|
+
return { action: "cancel" };
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1342
1674
|
// ── the ProviderSession surface ────────────────────────────────────
|
|
1343
1675
|
async *send(input) {
|
|
1344
1676
|
if (this.closed) throw new ProviderError("codex", "session is closed");
|
|
1345
|
-
if (this.
|
|
1346
|
-
|
|
1347
|
-
const
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
if (block.type === "text" && typeof block.text === "string") {
|
|
1352
|
-
items.push({ type: "text", text: block.text, text_elements: [] });
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
for (const p of paths) items.push({ type: "localImage", path: p });
|
|
1356
|
-
if (items.length === 0) items.push({ type: "text", text: "", text_elements: [] });
|
|
1677
|
+
if (this.sending) throw new ProviderError("codex", "a turn is already running");
|
|
1678
|
+
this.sending = true;
|
|
1679
|
+
const controller = new AbortController();
|
|
1680
|
+
this.turnAbort = controller;
|
|
1681
|
+
let cleanup = () => {
|
|
1682
|
+
};
|
|
1357
1683
|
const queue = new AsyncQueue();
|
|
1358
|
-
this.queue = queue;
|
|
1359
|
-
this.lastUsage = void 0;
|
|
1360
1684
|
try {
|
|
1685
|
+
await this.ensureOpen();
|
|
1686
|
+
if (controller.signal.aborted) {
|
|
1687
|
+
yield { type: "done", stopReason: "interrupted" };
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
const blocks = typeof input === "string" ? [{ type: "text", text: input }] : input;
|
|
1691
|
+
const images = writeTempImages(blocks);
|
|
1692
|
+
cleanup = images.cleanup;
|
|
1693
|
+
const items = [];
|
|
1694
|
+
for (const block of blocks) {
|
|
1695
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
1696
|
+
items.push({ type: "text", text: block.text, text_elements: [] });
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
for (const p of images.paths) items.push({ type: "localImage", path: p });
|
|
1700
|
+
if (items.length === 0) items.push({ type: "text", text: "", text_elements: [] });
|
|
1701
|
+
this.queue = queue;
|
|
1702
|
+
this.lastUsage = void 0;
|
|
1703
|
+
this.emitted.clear();
|
|
1704
|
+
this.reasoningEmitted.clear();
|
|
1361
1705
|
const result = await this.request("turn/start", {
|
|
1362
1706
|
threadId: this.threadId,
|
|
1363
1707
|
input: items,
|
|
1364
1708
|
...this.config.options.effort ? { effort: this.config.options.effort } : {}
|
|
1365
1709
|
});
|
|
1366
|
-
|
|
1710
|
+
const turnId = result["turn"]?.id;
|
|
1711
|
+
if (this.queue === queue) this.currentTurnId = turnId;
|
|
1712
|
+
if (controller.signal.aborted && this.currentTurnId) await this.interrupt();
|
|
1367
1713
|
yield { type: "session", sessionId: this.threadId };
|
|
1714
|
+
if (turnId) yield { type: "turn", id: turnId };
|
|
1368
1715
|
for await (const event of queue) yield event;
|
|
1369
1716
|
} finally {
|
|
1370
1717
|
cleanup();
|
|
1718
|
+
controller.abort();
|
|
1719
|
+
if (this.queue === queue) await this.interrupt();
|
|
1371
1720
|
if (this.queue === queue) this.queue = null;
|
|
1721
|
+
this.currentTurnId = void 0;
|
|
1722
|
+
this.turnAbort = void 0;
|
|
1723
|
+
this.sending = false;
|
|
1372
1724
|
}
|
|
1373
1725
|
}
|
|
1374
1726
|
async interrupt() {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1727
|
+
const request = this.threadId && this.currentTurnId ? this.request("turn/interrupt", { threadId: this.threadId, turnId: this.currentTurnId }).catch(() => {
|
|
1728
|
+
}) : Promise.resolve();
|
|
1729
|
+
this.turnAbort?.abort();
|
|
1730
|
+
await request;
|
|
1378
1731
|
}
|
|
1379
1732
|
async close() {
|
|
1380
1733
|
if (this.closed) return;
|
|
@@ -1384,6 +1737,57 @@ var CodexAgentSession = class {
|
|
|
1384
1737
|
this.child = void 0;
|
|
1385
1738
|
}
|
|
1386
1739
|
};
|
|
1740
|
+
function collabToolName(value) {
|
|
1741
|
+
const names = {
|
|
1742
|
+
spawnAgent: "spawn_agent",
|
|
1743
|
+
sendInput: "send_input",
|
|
1744
|
+
resumeAgent: "resume_agent",
|
|
1745
|
+
closeAgent: "close_agent",
|
|
1746
|
+
sendMessage: "send_message",
|
|
1747
|
+
followupTask: "followup_task",
|
|
1748
|
+
interruptAgent: "interrupt_agent",
|
|
1749
|
+
listAgents: "list_agents"
|
|
1750
|
+
};
|
|
1751
|
+
return names[String(value)] ?? String(value ?? "agent");
|
|
1752
|
+
}
|
|
1753
|
+
function codexPlanStatus(value) {
|
|
1754
|
+
return value === "completed" ? "completed" : value === "inProgress" || value === "in_progress" ? "in_progress" : "pending";
|
|
1755
|
+
}
|
|
1756
|
+
function codexQuestionRequest(sessionId, raw) {
|
|
1757
|
+
const questions = Array.isArray(raw["questions"]) ? raw["questions"] : [];
|
|
1758
|
+
const fields = questions.flatMap((value) => {
|
|
1759
|
+
const question = value;
|
|
1760
|
+
if (typeof question["id"] !== "string" || typeof question["question"] !== "string") return [];
|
|
1761
|
+
const choices = Array.isArray(question["options"]) ? question["options"].flatMap((option) => {
|
|
1762
|
+
const item = option;
|
|
1763
|
+
if (typeof item["label"] !== "string") return [];
|
|
1764
|
+
return [{
|
|
1765
|
+
value: item["label"],
|
|
1766
|
+
label: item["label"],
|
|
1767
|
+
...typeof item["description"] === "string" ? { description: item["description"] } : {}
|
|
1768
|
+
}];
|
|
1769
|
+
}) : [];
|
|
1770
|
+
return [{
|
|
1771
|
+
id: question["id"],
|
|
1772
|
+
label: question["question"],
|
|
1773
|
+
...typeof question["header"] === "string" ? { description: question["header"] } : {},
|
|
1774
|
+
type: choices.length > 0 ? "select" : "string",
|
|
1775
|
+
required: true,
|
|
1776
|
+
secret: question["isSecret"] === true,
|
|
1777
|
+
allowOther: question["isOther"] === true,
|
|
1778
|
+
...choices.length > 0 ? { options: choices } : {}
|
|
1779
|
+
}];
|
|
1780
|
+
});
|
|
1781
|
+
return {
|
|
1782
|
+
provider: "codex",
|
|
1783
|
+
...sessionId ? { sessionId } : {},
|
|
1784
|
+
kind: "questions",
|
|
1785
|
+
message: fields.length === 1 ? fields[0].label : "Input requested",
|
|
1786
|
+
fields,
|
|
1787
|
+
blocking: raw["isBlocking"] !== false,
|
|
1788
|
+
raw
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1387
1791
|
|
|
1388
1792
|
// src/core/providers/jsonl.ts
|
|
1389
1793
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -1452,8 +1856,10 @@ var CodexProvider = class {
|
|
|
1452
1856
|
systemPrompt: false,
|
|
1453
1857
|
thinking: false,
|
|
1454
1858
|
effort: true,
|
|
1455
|
-
streaming: "chunks"
|
|
1859
|
+
streaming: "chunks",
|
|
1860
|
+
serverTools: false
|
|
1456
1861
|
};
|
|
1862
|
+
sessionCapabilities = { fork: true };
|
|
1457
1863
|
workDir;
|
|
1458
1864
|
sandbox;
|
|
1459
1865
|
env;
|
|
@@ -1578,11 +1984,34 @@ var CodexProvider = class {
|
|
|
1578
1984
|
finish(() => reject(classifyProviderFailure(this.id, this.loginCommand, new Error(msg.error?.message ?? "model/list failed"))));
|
|
1579
1985
|
return;
|
|
1580
1986
|
}
|
|
1581
|
-
const models = (msg.result?.data ?? []).filter((m) => m["hidden"] !== true).map((m) =>
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1987
|
+
const models = (msg.result?.data ?? []).filter((m) => m["hidden"] !== true).map((m) => {
|
|
1988
|
+
const efforts = Array.isArray(m["supportedReasoningEfforts"]) ? m["supportedReasoningEfforts"].flatMap(
|
|
1989
|
+
(entry) => typeof entry["reasoningEffort"] === "string" ? [{
|
|
1990
|
+
id: entry["reasoningEffort"],
|
|
1991
|
+
...typeof entry["description"] === "string" ? { description: entry["description"] } : {}
|
|
1992
|
+
}] : []
|
|
1993
|
+
) : [];
|
|
1994
|
+
const tiers = Array.isArray(m["serviceTiers"]) ? m["serviceTiers"].flatMap(
|
|
1995
|
+
(entry) => typeof entry["id"] === "string" ? [{
|
|
1996
|
+
id: entry["id"],
|
|
1997
|
+
display_name: typeof entry["name"] === "string" ? entry["name"] : entry["id"],
|
|
1998
|
+
...typeof entry["description"] === "string" ? { description: entry["description"] } : {}
|
|
1999
|
+
}] : []
|
|
2000
|
+
) : [];
|
|
2001
|
+
return {
|
|
2002
|
+
id: String(m["id"] ?? m["model"]),
|
|
2003
|
+
display_name: String(m["displayName"] ?? m["id"] ?? m["model"]),
|
|
2004
|
+
...typeof m["description"] === "string" ? { description: m["description"] } : {},
|
|
2005
|
+
...efforts.length > 0 ? { reasoning_efforts: efforts } : {},
|
|
2006
|
+
...typeof m["defaultReasoningEffort"] === "string" ? { default_reasoning_effort: m["defaultReasoningEffort"] } : {},
|
|
2007
|
+
...Array.isArray(m["inputModalities"]) ? { input_modalities: m["inputModalities"].filter((value) => typeof value === "string") } : {},
|
|
2008
|
+
...m["supportsPersonality"] === true ? { supports_personality: true } : {},
|
|
2009
|
+
...typeof m["multiAgentVersion"] === "string" ? { multi_agent: m["multiAgentVersion"] } : {},
|
|
2010
|
+
...tiers.length > 0 ? { service_tiers: tiers } : {},
|
|
2011
|
+
...typeof m["defaultServiceTier"] === "string" ? { default_service_tier: m["defaultServiceTier"] } : {},
|
|
2012
|
+
...m["isDefault"] === true ? { is_default: true } : {}
|
|
2013
|
+
};
|
|
2014
|
+
});
|
|
1586
2015
|
finish(() => resolve(models));
|
|
1587
2016
|
}
|
|
1588
2017
|
});
|
|
@@ -1901,6 +2330,61 @@ var SseSynthesizer = class {
|
|
|
1901
2330
|
|
|
1902
2331
|
// src/core/transcript.ts
|
|
1903
2332
|
import { createHash } from "crypto";
|
|
2333
|
+
|
|
2334
|
+
// src/core/serverTools.ts
|
|
2335
|
+
var SERVER_TOOLS = {
|
|
2336
|
+
web_search: "WebSearch",
|
|
2337
|
+
web_fetch: "WebFetch"
|
|
2338
|
+
};
|
|
2339
|
+
function serverToolFor(type) {
|
|
2340
|
+
if (typeof type !== "string") return void 0;
|
|
2341
|
+
for (const [prefix, tool] of Object.entries(SERVER_TOOLS)) {
|
|
2342
|
+
if (type === prefix || type.startsWith(`${prefix}_`)) return tool;
|
|
2343
|
+
}
|
|
2344
|
+
return void 0;
|
|
2345
|
+
}
|
|
2346
|
+
function resolveServerTools(tools, toolChoice) {
|
|
2347
|
+
if (tools == null) {
|
|
2348
|
+
if (toolChoice != null) {
|
|
2349
|
+
throw new ApiError(
|
|
2350
|
+
400,
|
|
2351
|
+
"invalid_request_error",
|
|
2352
|
+
"`tool_choice` was given without `tools`."
|
|
2353
|
+
);
|
|
2354
|
+
}
|
|
2355
|
+
return void 0;
|
|
2356
|
+
}
|
|
2357
|
+
if (!Array.isArray(tools)) {
|
|
2358
|
+
throw new ApiError(400, "invalid_request_error", "`tools` must be an array");
|
|
2359
|
+
}
|
|
2360
|
+
if (tools.length === 0) return void 0;
|
|
2361
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
2362
|
+
for (const tool of tools) {
|
|
2363
|
+
const entry = tool;
|
|
2364
|
+
const mapped = serverToolFor(entry?.type);
|
|
2365
|
+
if (!mapped) {
|
|
2366
|
+
const label = typeof entry?.name === "string" ? `"${entry.name}"` : `type "${String(entry?.type)}"`;
|
|
2367
|
+
throw new ApiError(
|
|
2368
|
+
400,
|
|
2369
|
+
"invalid_request_error",
|
|
2370
|
+
`yagami supports Anthropic server tools (${Object.keys(SERVER_TOOLS).join(", ")}) but not custom tools: ${label} would have to be executed by you, and this endpoint never emits tool_use blocks. Drop it, or ask for the result as text/JSON instead.`
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
resolved.add(mapped);
|
|
2374
|
+
}
|
|
2375
|
+
const choice = toolChoice?.type;
|
|
2376
|
+
if (choice != null && choice !== "auto" && choice !== "none") {
|
|
2377
|
+
throw new ApiError(
|
|
2378
|
+
400,
|
|
2379
|
+
"invalid_request_error",
|
|
2380
|
+
`\`tool_choice.type\` must be "auto" or "none" with server tools (got "${String(choice)}"): server tools run on the engine's side and cannot be forced.`
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
if (choice === "none") return void 0;
|
|
2384
|
+
return [...resolved];
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
// src/core/transcript.ts
|
|
1904
2388
|
var IGNORABLE_PARAMS = [
|
|
1905
2389
|
"max_tokens",
|
|
1906
2390
|
"temperature",
|
|
@@ -1962,13 +2446,7 @@ function normalizeRequest(req) {
|
|
|
1962
2446
|
if (req == null || typeof req !== "object") {
|
|
1963
2447
|
throw new ApiError(400, "invalid_request_error", "request body must be a JSON object");
|
|
1964
2448
|
}
|
|
1965
|
-
|
|
1966
|
-
throw new ApiError(
|
|
1967
|
-
400,
|
|
1968
|
-
"invalid_request_error",
|
|
1969
|
-
"yagami does not support `tools`/`tool_choice`: the backing engine runs as a pure completions endpoint and never executes or emits tool calls."
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
2449
|
+
const serverTools = resolveServerTools(req.tools, req.tool_choice);
|
|
1972
2450
|
if (!Array.isArray(req.messages) || req.messages.length === 0) {
|
|
1973
2451
|
throw new ApiError(400, "invalid_request_error", "`messages` must be a non-empty array");
|
|
1974
2452
|
}
|
|
@@ -2004,7 +2482,8 @@ function normalizeRequest(req) {
|
|
|
2004
2482
|
messages,
|
|
2005
2483
|
lastUserText: last.text,
|
|
2006
2484
|
...prefill !== void 0 ? { prefill } : {},
|
|
2007
|
-
ignored: [...ignored]
|
|
2485
|
+
ignored: [...ignored],
|
|
2486
|
+
...serverTools ? { serverTools } : {}
|
|
2008
2487
|
};
|
|
2009
2488
|
}
|
|
2010
2489
|
function prefillDirective(prefill) {
|
|
@@ -2232,6 +2711,13 @@ ${norm.system}
|
|
|
2232
2711
|
|
|
2233
2712
|
${promptText}`;
|
|
2234
2713
|
}
|
|
2714
|
+
if (norm.serverTools && !caps.serverTools) {
|
|
2715
|
+
throw new ApiError(
|
|
2716
|
+
400,
|
|
2717
|
+
"invalid_request_error",
|
|
2718
|
+
`provider "${provider.id}" cannot run server tools (${norm.serverTools.join(", ")}). Answering without them would silently drop the lookup you asked for, so the request is refused instead. Use the claude provider, or drop \`tools\`.`
|
|
2719
|
+
);
|
|
2720
|
+
}
|
|
2235
2721
|
const turn = {
|
|
2236
2722
|
prompt: promptText,
|
|
2237
2723
|
...lastMedia.length > 0 ? { media: lastMedia } : {},
|
|
@@ -2239,7 +2725,8 @@ ${promptText}`;
|
|
|
2239
2725
|
...model ? { model } : {},
|
|
2240
2726
|
...resume ? { resume } : {},
|
|
2241
2727
|
...req.thinking != null && caps.thinking ? { thinking: req.thinking } : {},
|
|
2242
|
-
...typeof req.effort === "string" && caps.effort ? { effort: req.effort } : {}
|
|
2728
|
+
...typeof req.effort === "string" && caps.effort ? { effort: req.effort } : {},
|
|
2729
|
+
...norm.serverTools ? { serverTools: norm.serverTools } : {}
|
|
2243
2730
|
};
|
|
2244
2731
|
const requestedModel = model ? provider.id === this.defaultProviderId ? model : qualifiedModel(provider.id, model) : provider.id;
|
|
2245
2732
|
return { provider, turn, norm, requestedModel, ignored, ...resume && resumeKey ? { resumeKey } : {} };
|
|
@@ -2499,7 +2986,7 @@ function chatToMessagesRequest(body) {
|
|
|
2499
2986
|
throw new ApiError(
|
|
2500
2987
|
400,
|
|
2501
2988
|
"invalid_request_error",
|
|
2502
|
-
"yagami does not support
|
|
2989
|
+
"yagami does not support OpenAI function calling: the backing engine never emits tool calls for you to execute. Anthropic **server** tools (web_search, web_fetch) do run \u2014 request them through the Anthropic dialect at /v1/messages."
|
|
2503
2990
|
);
|
|
2504
2991
|
}
|
|
2505
2992
|
if (body.n != null && body.n !== 1) {
|
|
@@ -2692,4 +3179,4 @@ export {
|
|
|
2692
3179
|
ChatChunkTranslator,
|
|
2693
3180
|
modelListBody
|
|
2694
3181
|
};
|
|
2695
|
-
//# sourceMappingURL=chunk-
|
|
3182
|
+
//# sourceMappingURL=chunk-U3RFT7QV.js.map
|