@justin06lee/yagami 0.6.1 → 0.8.2
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 +30 -8
- package/dist/{chunk-ZYHC7PXX.js → chunk-EKN223KD.js} +685 -84
- package/dist/chunk-EKN223KD.js.map +1 -0
- package/dist/{chunk-D2PNH6GV.js → chunk-UGIJV6FZ.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/{hostConfig-HmZ3z297.d.ts → hostConfig-CbGD5-lN.d.ts} +115 -2
- package/dist/index.d.ts +31 -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 +1 -1
- package/dist/chunk-ZYHC7PXX.js.map +0 -1
- /package/dist/{chunk-D2PNH6GV.js.map → chunk-UGIJV6FZ.js.map} +0 -0
|
@@ -183,10 +183,10 @@ function resolveClaudeExecutable(explicit) {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// src/version.ts
|
|
186
|
-
var VERSION = "0.
|
|
186
|
+
var VERSION = "0.8.2";
|
|
187
187
|
|
|
188
188
|
// src/core/providers/acp.ts
|
|
189
|
-
import { spawn, spawnSync } from "child_process";
|
|
189
|
+
import { spawn, spawnSync as spawnSync2 } from "child_process";
|
|
190
190
|
import * as fs2 from "fs";
|
|
191
191
|
import * as os2 from "os";
|
|
192
192
|
import * as path2 from "path";
|
|
@@ -198,12 +198,165 @@ 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
|
+
|
|
291
|
+
// src/core/providers/process.ts
|
|
292
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
293
|
+
var GRACE_MS = 3e3;
|
|
294
|
+
var ending = /* @__PURE__ */ new WeakSet();
|
|
295
|
+
function descendants(root) {
|
|
296
|
+
let listing;
|
|
297
|
+
try {
|
|
298
|
+
listing = execFileSync("ps", ["-A", "-o", "pid=,ppid="], { encoding: "utf8", timeout: 2e3 });
|
|
299
|
+
} catch {
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
302
|
+
const children = /* @__PURE__ */ new Map();
|
|
303
|
+
for (const line of listing.split("\n")) {
|
|
304
|
+
const [pid, ppid] = line.trim().split(/\s+/).map(Number);
|
|
305
|
+
if (!pid || ppid === void 0 || Number.isNaN(ppid)) continue;
|
|
306
|
+
const list = children.get(ppid);
|
|
307
|
+
if (list) list.push(pid);
|
|
308
|
+
else children.set(ppid, [pid]);
|
|
309
|
+
}
|
|
310
|
+
const found = [];
|
|
311
|
+
const stack = [root];
|
|
312
|
+
while (stack.length > 0) {
|
|
313
|
+
for (const child of children.get(stack.pop()) ?? []) {
|
|
314
|
+
found.push(child);
|
|
315
|
+
stack.push(child);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return found;
|
|
319
|
+
}
|
|
320
|
+
function isAlive(pid) {
|
|
321
|
+
try {
|
|
322
|
+
process.kill(pid, 0);
|
|
323
|
+
return true;
|
|
324
|
+
} catch (err) {
|
|
325
|
+
return err.code === "EPERM";
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function signal(pid, sig) {
|
|
329
|
+
try {
|
|
330
|
+
process.kill(pid, sig);
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function killTree(child, graceMs = GRACE_MS) {
|
|
335
|
+
if (!child || child.pid === void 0 || ending.has(child)) return;
|
|
336
|
+
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
337
|
+
ending.add(child);
|
|
338
|
+
const pid = child.pid;
|
|
339
|
+
if (process.platform === "win32") {
|
|
340
|
+
spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const tree = [pid, ...descendants(pid)];
|
|
344
|
+
for (const member of tree) signal(member, "SIGTERM");
|
|
345
|
+
const timer = setTimeout(() => {
|
|
346
|
+
for (const member of tree) if (isAlive(member)) signal(member, "SIGKILL");
|
|
347
|
+
}, graceMs);
|
|
348
|
+
timer.unref?.();
|
|
349
|
+
}
|
|
350
|
+
|
|
201
351
|
// src/core/providers/queue.ts
|
|
202
352
|
var AsyncQueue = class {
|
|
203
353
|
buffer = [];
|
|
204
354
|
waiting = null;
|
|
205
355
|
ended = false;
|
|
206
356
|
error = void 0;
|
|
357
|
+
/** Called once if the consumer stops iterating before the queue ends —
|
|
358
|
+
* the producer's cue to stop whatever is feeding it. */
|
|
359
|
+
onReturn;
|
|
207
360
|
push(value) {
|
|
208
361
|
if (this.ended) return;
|
|
209
362
|
if (this.waiting) {
|
|
@@ -251,7 +404,10 @@ var AsyncQueue = class {
|
|
|
251
404
|
});
|
|
252
405
|
},
|
|
253
406
|
return: () => {
|
|
407
|
+
const stop = this.ended ? void 0 : this.onReturn;
|
|
408
|
+
this.onReturn = void 0;
|
|
254
409
|
this.ended = true;
|
|
410
|
+
stop?.();
|
|
255
411
|
return Promise.resolve({ value: void 0, done: true });
|
|
256
412
|
}
|
|
257
413
|
};
|
|
@@ -259,6 +415,8 @@ var AsyncQueue = class {
|
|
|
259
415
|
};
|
|
260
416
|
|
|
261
417
|
// src/core/providers/acp.ts
|
|
418
|
+
var HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
419
|
+
var PROBE_TIMEOUT_MS = 2e4;
|
|
262
420
|
function rejectOption(p) {
|
|
263
421
|
const pick = p.options.find((o) => o.kind === "reject_once") ?? p.options.find((o) => o.kind === "reject_always") ?? p.options[0];
|
|
264
422
|
if (!pick) return { outcome: { outcome: "cancelled" } };
|
|
@@ -277,14 +435,18 @@ var AcpProvider = class {
|
|
|
277
435
|
systemPrompt: false,
|
|
278
436
|
thinking: false,
|
|
279
437
|
effort: false,
|
|
280
|
-
streaming: "tokens"
|
|
438
|
+
streaming: "tokens",
|
|
439
|
+
serverTools: false
|
|
281
440
|
};
|
|
441
|
+
sessionCapabilities = { fork: false };
|
|
282
442
|
args;
|
|
283
443
|
env;
|
|
284
444
|
workDir;
|
|
285
445
|
appName;
|
|
286
446
|
modelConfigId;
|
|
287
447
|
connectImpl;
|
|
448
|
+
handshakeTimeoutMs;
|
|
449
|
+
probeTimeoutMs;
|
|
288
450
|
constructor(options) {
|
|
289
451
|
this.id = options.id;
|
|
290
452
|
this.label = options.label;
|
|
@@ -298,6 +460,8 @@ var AcpProvider = class {
|
|
|
298
460
|
this.appName = options.appName ?? "yagami";
|
|
299
461
|
this.modelConfigId = options.modelConfigId ?? "model";
|
|
300
462
|
this.connectImpl = options.connect ?? ((cwd) => this.spawnConnection(cwd));
|
|
463
|
+
this.handshakeTimeoutMs = options.handshakeTimeoutMs ?? HANDSHAKE_TIMEOUT_MS;
|
|
464
|
+
this.probeTimeoutMs = options.probeTimeoutMs ?? PROBE_TIMEOUT_MS;
|
|
301
465
|
fs2.mkdirSync(this.workDir, { recursive: true });
|
|
302
466
|
}
|
|
303
467
|
spawnConnection(cwd) {
|
|
@@ -323,6 +487,9 @@ var AcpProvider = class {
|
|
|
323
487
|
const agent = new ClientSideConnection(
|
|
324
488
|
() => ({
|
|
325
489
|
requestPermission: (p) => handlers.onPermission ? handlers.onPermission(p) : rejectOption(p),
|
|
490
|
+
unstable_createElicitation: (p) => handlers.onInput ? handlers.onInput(p) : Promise.resolve({ action: "decline" }),
|
|
491
|
+
unstable_completeElicitation: () => {
|
|
492
|
+
},
|
|
326
493
|
sessionUpdate: (n) => {
|
|
327
494
|
handlers.onUpdate?.(n);
|
|
328
495
|
}
|
|
@@ -330,37 +497,52 @@ var AcpProvider = class {
|
|
|
330
497
|
stream
|
|
331
498
|
);
|
|
332
499
|
let settled = false;
|
|
500
|
+
const handshake = setTimeout(() => {
|
|
501
|
+
if (settled) return;
|
|
502
|
+
settled = true;
|
|
503
|
+
killTree(child);
|
|
504
|
+
reject(new ProviderError(this.id, `${this.label} did not finish the ACP handshake within ${Math.round(this.handshakeTimeoutMs / 1e3)}s`));
|
|
505
|
+
}, this.handshakeTimeoutMs);
|
|
506
|
+
handshake.unref?.();
|
|
333
507
|
child.on("error", (err) => {
|
|
334
508
|
if (settled) return;
|
|
335
509
|
settled = true;
|
|
510
|
+
clearTimeout(handshake);
|
|
336
511
|
reject(classifyProviderFailure(this.id, this.loginCommand, err));
|
|
337
512
|
});
|
|
338
513
|
child.on("exit", (code) => {
|
|
339
514
|
if (settled) return;
|
|
340
515
|
settled = true;
|
|
516
|
+
clearTimeout(handshake);
|
|
341
517
|
reject(classifyProviderFailure(this.id, this.loginCommand, new Error(`${this.executable} exited with code ${code}${stderr ? `: ${stderr.trim().slice(-400)}` : ""}`)));
|
|
342
518
|
});
|
|
343
519
|
agent.initialize({
|
|
344
520
|
protocolVersion: PROTOCOL_VERSION,
|
|
345
521
|
clientInfo: { name: this.appName, version: VERSION },
|
|
346
|
-
clientCapabilities: {
|
|
522
|
+
clientCapabilities: {
|
|
523
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
524
|
+
terminal: false,
|
|
525
|
+
session: { configOptions: { boolean: {} } },
|
|
526
|
+
plan: {},
|
|
527
|
+
elicitation: { form: {}, url: {} }
|
|
528
|
+
}
|
|
347
529
|
}).then((init) => {
|
|
348
530
|
if (settled) return;
|
|
349
531
|
settled = true;
|
|
532
|
+
clearTimeout(handshake);
|
|
350
533
|
resolve({
|
|
351
534
|
agent,
|
|
352
535
|
init,
|
|
353
536
|
setHandlers: (h) => {
|
|
354
537
|
handlers = h;
|
|
355
538
|
},
|
|
356
|
-
close: () =>
|
|
357
|
-
child.kill("SIGTERM");
|
|
358
|
-
}
|
|
539
|
+
close: () => killTree(child)
|
|
359
540
|
});
|
|
360
541
|
}).catch((err) => {
|
|
361
542
|
if (settled) return;
|
|
362
543
|
settled = true;
|
|
363
|
-
|
|
544
|
+
clearTimeout(handshake);
|
|
545
|
+
killTree(child);
|
|
364
546
|
reject(this.classify(err, stderr));
|
|
365
547
|
});
|
|
366
548
|
});
|
|
@@ -381,7 +563,13 @@ var AcpProvider = class {
|
|
|
381
563
|
const onAbort = () => {
|
|
382
564
|
if (sessionId) void conn.agent.cancel({ sessionId }).catch(() => {
|
|
383
565
|
});
|
|
566
|
+
else conn.close();
|
|
384
567
|
};
|
|
568
|
+
if (req.signal?.aborted) {
|
|
569
|
+
conn.close();
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
req.signal?.addEventListener("abort", onAbort, { once: true });
|
|
385
573
|
try {
|
|
386
574
|
let configOptions;
|
|
387
575
|
let modes;
|
|
@@ -410,6 +598,7 @@ var AcpProvider = class {
|
|
|
410
598
|
});
|
|
411
599
|
}
|
|
412
600
|
if (req.model) await this.selectModel(conn, sessionId, configOptions, req.model);
|
|
601
|
+
if (req.effort) await this.selectEffort(conn, sessionId, configOptions, req.effort);
|
|
413
602
|
const sid = sessionId;
|
|
414
603
|
conn.setHandlers({
|
|
415
604
|
onPermission: async (p) => rejectOption(p),
|
|
@@ -426,7 +615,6 @@ var AcpProvider = class {
|
|
|
426
615
|
}
|
|
427
616
|
}
|
|
428
617
|
});
|
|
429
|
-
req.signal?.addEventListener("abort", onAbort, { once: true });
|
|
430
618
|
conn.agent.prompt({ sessionId, prompt: toAcpBlocks(req.prompt, req.media ?? [], this.id) }).then((res) => {
|
|
431
619
|
queue.push({
|
|
432
620
|
type: "done",
|
|
@@ -455,6 +643,7 @@ var AcpProvider = class {
|
|
|
455
643
|
connect: (cwd) => this.connectImpl(cwd),
|
|
456
644
|
classify: (err, ctx) => this.classify(err, ctx),
|
|
457
645
|
selectModel: (conn, sessionId, configOptions, model) => this.selectModel(conn, sessionId, configOptions, model),
|
|
646
|
+
selectEffort: (conn, sessionId, configOptions, effort) => this.selectEffort(conn, sessionId, configOptions, effort),
|
|
458
647
|
options
|
|
459
648
|
});
|
|
460
649
|
}
|
|
@@ -468,22 +657,64 @@ var AcpProvider = class {
|
|
|
468
657
|
throw this.classify(err);
|
|
469
658
|
});
|
|
470
659
|
}
|
|
471
|
-
async
|
|
660
|
+
async selectEffort(conn, sessionId, configOptions, effort) {
|
|
661
|
+
const option = configOptions?.find(
|
|
662
|
+
(candidate) => candidate.category === "thought_level" || /^(?:thought[_-]?level|reasoning[_-]?effort|effort)$/i.test(candidate.id)
|
|
663
|
+
);
|
|
664
|
+
if (!option || option.type !== "select" || option.currentValue === effort) return;
|
|
665
|
+
if (!flattenSelectOptions(option).some((candidate) => candidate.value === effort)) return;
|
|
666
|
+
await conn.agent.setSessionConfigOption({ sessionId, configId: option.id, value: effort }).catch((err) => {
|
|
667
|
+
throw this.classify(err);
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Run a short question against a fresh agent and close it, whatever
|
|
672
|
+
* happens. The deadline covers the whole exchange: an agent that answers
|
|
673
|
+
* the handshake and then sits on newSession forever (Gemini, signed out
|
|
674
|
+
* or mid-update) used to hold the probe open — and its process alive —
|
|
675
|
+
* for as long as the host ran.
|
|
676
|
+
*/
|
|
677
|
+
async probe(ask) {
|
|
472
678
|
const conn = await this.connectImpl(this.workDir);
|
|
679
|
+
let timer;
|
|
473
680
|
try {
|
|
681
|
+
return await Promise.race([
|
|
682
|
+
ask(conn),
|
|
683
|
+
new Promise((_, reject) => {
|
|
684
|
+
timer = setTimeout(
|
|
685
|
+
() => reject(new ProviderError(this.id, `${this.label} did not answer within ${Math.round(this.probeTimeoutMs / 1e3)}s`)),
|
|
686
|
+
this.probeTimeoutMs
|
|
687
|
+
);
|
|
688
|
+
timer.unref?.();
|
|
689
|
+
})
|
|
690
|
+
]);
|
|
691
|
+
} finally {
|
|
692
|
+
if (timer) clearTimeout(timer);
|
|
693
|
+
conn.close();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
async listModels() {
|
|
697
|
+
return this.probe(async (conn) => {
|
|
474
698
|
const created = await conn.agent.newSession({ cwd: this.workDir, mcpServers: [] }).catch((err) => {
|
|
475
699
|
throw this.classify(err);
|
|
476
700
|
});
|
|
477
701
|
const option = created.configOptions?.find((o) => o.id === this.modelConfigId) ?? created.configOptions?.find((o) => o.category === "model");
|
|
478
702
|
if (!option || option.type !== "select") return [];
|
|
703
|
+
const effortOption = created.configOptions?.find(
|
|
704
|
+
(candidate) => candidate.type === "select" && (candidate.category === "thought_level" || /^(?:thought[_-]?level|reasoning[_-]?effort|effort)$/i.test(candidate.id))
|
|
705
|
+
);
|
|
706
|
+
const efforts = effortOption?.type === "select" ? flattenSelectOptions(effortOption).map((entry) => ({
|
|
707
|
+
id: entry.value,
|
|
708
|
+
...entry.description ? { description: entry.description } : {}
|
|
709
|
+
})) : [];
|
|
479
710
|
return flattenSelectOptions(option).map((o) => ({
|
|
480
711
|
id: o.value,
|
|
481
712
|
display_name: o.name,
|
|
482
|
-
...o.description ? { description: o.description } : {}
|
|
713
|
+
...o.description ? { description: o.description } : {},
|
|
714
|
+
...efforts.length > 0 ? { reasoning_efforts: efforts } : {},
|
|
715
|
+
...effortOption?.type === "select" ? { default_reasoning_effort: effortOption.currentValue } : {}
|
|
483
716
|
}));
|
|
484
|
-
}
|
|
485
|
-
conn.close();
|
|
486
|
-
}
|
|
717
|
+
});
|
|
487
718
|
}
|
|
488
719
|
/**
|
|
489
720
|
* The agent's self-reported name/version from the ACP handshake. When the
|
|
@@ -506,7 +737,7 @@ var AcpProvider = class {
|
|
|
506
737
|
}
|
|
507
738
|
let plain;
|
|
508
739
|
try {
|
|
509
|
-
const out =
|
|
740
|
+
const out = spawnSync2(this.executable, ["--version"], { encoding: "utf8", timeout: 1e4 });
|
|
510
741
|
plain = out.stdout?.trim().split("\n")[0] || void 0;
|
|
511
742
|
} catch {
|
|
512
743
|
plain = void 0;
|
|
@@ -559,8 +790,10 @@ var AcpAgentSession = class {
|
|
|
559
790
|
if (mode) await conn.agent.setSessionMode({ sessionId, modeId: mode }).catch(() => {
|
|
560
791
|
});
|
|
561
792
|
if (options.model) await this.cfg.selectModel(conn, sessionId, configOptions, options.model);
|
|
793
|
+
if (options.effort) await this.cfg.selectEffort(conn, sessionId, configOptions, options.effort);
|
|
562
794
|
conn.setHandlers({
|
|
563
795
|
onPermission: (p) => this.onPermission(p),
|
|
796
|
+
onInput: (p) => this.onInput(p),
|
|
564
797
|
onUpdate: (n) => this.onUpdate(n)
|
|
565
798
|
});
|
|
566
799
|
}
|
|
@@ -593,6 +826,23 @@ var AcpAgentSession = class {
|
|
|
593
826
|
}
|
|
594
827
|
return rejectOption(p);
|
|
595
828
|
}
|
|
829
|
+
async onInput(p) {
|
|
830
|
+
const request = elicitationRequest(
|
|
831
|
+
this.provider,
|
|
832
|
+
this.sessionId,
|
|
833
|
+
p
|
|
834
|
+
);
|
|
835
|
+
const handler = this.cfg.options.input;
|
|
836
|
+
let response = declineInput();
|
|
837
|
+
if (handler) {
|
|
838
|
+
try {
|
|
839
|
+
response = await handler.respond(request);
|
|
840
|
+
} catch {
|
|
841
|
+
response = { action: "cancel" };
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return elicitationResponse(response);
|
|
845
|
+
}
|
|
596
846
|
onUpdate(n) {
|
|
597
847
|
if (n.sessionId !== this.sessionId) return;
|
|
598
848
|
const u = n.update;
|
|
@@ -603,6 +853,21 @@ var AcpAgentSession = class {
|
|
|
603
853
|
case "agent_thought_chunk":
|
|
604
854
|
if (u.content.type === "text") this.queue?.push({ type: "thinking", text: u.content.text });
|
|
605
855
|
break;
|
|
856
|
+
case "plan":
|
|
857
|
+
this.queue?.push({ type: "plan", plan: acpPlan(u) });
|
|
858
|
+
break;
|
|
859
|
+
case "plan_update":
|
|
860
|
+
this.queue?.push({ type: "plan", plan: acpPlan(u.plan ?? {}) });
|
|
861
|
+
break;
|
|
862
|
+
case "plan_removed":
|
|
863
|
+
this.queue?.push({
|
|
864
|
+
type: "plan",
|
|
865
|
+
plan: {
|
|
866
|
+
...typeof u.planId === "string" ? { id: u.planId } : {},
|
|
867
|
+
removed: true
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
break;
|
|
606
871
|
case "tool_call": {
|
|
607
872
|
const t = u;
|
|
608
873
|
const meta = { name: t.kind ?? "tool", ...t.title ? { title: t.title } : {}, ...t.kind ? { kind: t.kind } : {} };
|
|
@@ -683,6 +948,24 @@ var AcpAgentSession = class {
|
|
|
683
948
|
this.conn = void 0;
|
|
684
949
|
}
|
|
685
950
|
};
|
|
951
|
+
function acpPlan(raw) {
|
|
952
|
+
const entries = Array.isArray(raw["entries"]) ? raw["entries"].flatMap((value) => {
|
|
953
|
+
const entry = value;
|
|
954
|
+
if (typeof entry["content"] !== "string") return [];
|
|
955
|
+
const item = {
|
|
956
|
+
content: entry["content"],
|
|
957
|
+
status: entry["status"] === "completed" ? "completed" : entry["status"] === "in_progress" ? "in_progress" : "pending",
|
|
958
|
+
...["high", "medium", "low"].includes(String(entry["priority"])) ? { priority: entry["priority"] } : {}
|
|
959
|
+
};
|
|
960
|
+
return [item];
|
|
961
|
+
}) : void 0;
|
|
962
|
+
return {
|
|
963
|
+
...typeof raw["planId"] === "string" ? { id: raw["planId"] } : {},
|
|
964
|
+
...entries ? { entries } : {},
|
|
965
|
+
...typeof raw["content"] === "string" ? { markdown: raw["content"] } : {},
|
|
966
|
+
...typeof raw["uri"] === "string" ? { uri: raw["uri"] } : {}
|
|
967
|
+
};
|
|
968
|
+
}
|
|
686
969
|
function supportsResume(init) {
|
|
687
970
|
const caps = init.agentCapabilities;
|
|
688
971
|
return caps?.sessionCapabilities?.resume !== void 0;
|
|
@@ -751,7 +1034,7 @@ function jsonLinesOnly(input, onNoise) {
|
|
|
751
1034
|
|
|
752
1035
|
// src/core/providers/claude.ts
|
|
753
1036
|
import { createRequire } from "module";
|
|
754
|
-
import { spawnSync as
|
|
1037
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
755
1038
|
import * as fs3 from "fs";
|
|
756
1039
|
import * as os3 from "os";
|
|
757
1040
|
import * as path3 from "path";
|
|
@@ -763,6 +1046,15 @@ var DENY_ALL_TOOLS = async (toolName) => ({
|
|
|
763
1046
|
message: `yagami is a completions-only endpoint; tool "${toolName}" is disabled.`,
|
|
764
1047
|
interrupt: true
|
|
765
1048
|
});
|
|
1049
|
+
var allowOnly = (enabled) => {
|
|
1050
|
+
const allowed = new Set(enabled);
|
|
1051
|
+
return async (toolName, input) => allowed.has(toolName) ? { behavior: "allow", updatedInput: input } : {
|
|
1052
|
+
behavior: "deny",
|
|
1053
|
+
message: `yagami is a completions-only endpoint; tool "${toolName}" is disabled.`,
|
|
1054
|
+
interrupt: true
|
|
1055
|
+
};
|
|
1056
|
+
};
|
|
1057
|
+
var SERVER_TOOL_MAX_TURNS = 24;
|
|
766
1058
|
var ClaudeProvider = class {
|
|
767
1059
|
id = "claude";
|
|
768
1060
|
label = "Claude Code";
|
|
@@ -776,7 +1068,8 @@ var ClaudeProvider = class {
|
|
|
776
1068
|
systemPrompt: true,
|
|
777
1069
|
thinking: true,
|
|
778
1070
|
effort: true,
|
|
779
|
-
streaming: "tokens"
|
|
1071
|
+
streaming: "tokens",
|
|
1072
|
+
serverTools: true
|
|
780
1073
|
};
|
|
781
1074
|
configDir;
|
|
782
1075
|
workDir;
|
|
@@ -811,6 +1104,11 @@ var ClaudeProvider = class {
|
|
|
811
1104
|
const onAbort = () => abortController.abort();
|
|
812
1105
|
req.signal?.addEventListener("abort", onAbort, { once: true });
|
|
813
1106
|
const options = { ...this.baseOptions(), abortController, includePartialMessages: true };
|
|
1107
|
+
if (req.serverTools && req.serverTools.length > 0) {
|
|
1108
|
+
options.tools = [...req.serverTools];
|
|
1109
|
+
options.canUseTool = allowOnly(req.serverTools);
|
|
1110
|
+
options.maxTurns = SERVER_TOOL_MAX_TURNS;
|
|
1111
|
+
}
|
|
814
1112
|
if (req.model) options.model = req.model;
|
|
815
1113
|
if (req.system !== void 0) options.systemPrompt = req.system;
|
|
816
1114
|
if (req.resume) {
|
|
@@ -889,7 +1187,11 @@ var ClaudeProvider = class {
|
|
|
889
1187
|
id: m.value,
|
|
890
1188
|
display_name: m.displayName,
|
|
891
1189
|
...m.description ? { description: m.description } : {},
|
|
892
|
-
...m.resolvedModel ? { resolved_model: m.resolvedModel } : {}
|
|
1190
|
+
...m.resolvedModel ? { resolved_model: m.resolvedModel } : {},
|
|
1191
|
+
...m.supportedEffortLevels?.length ? { reasoning_efforts: m.supportedEffortLevels.map((id) => ({ id })) } : {},
|
|
1192
|
+
...m.supportsAdaptiveThinking ? { supports_adaptive_thinking: true } : {},
|
|
1193
|
+
...m.supportsFastMode ? { supports_fast_mode: true } : {},
|
|
1194
|
+
...m.supportsAutoMode ? { supports_auto_mode: true } : {}
|
|
893
1195
|
}));
|
|
894
1196
|
} catch (err) {
|
|
895
1197
|
throw classifyProviderFailure(this.id, this.loginCommand, err);
|
|
@@ -901,7 +1203,7 @@ var ClaudeProvider = class {
|
|
|
901
1203
|
}
|
|
902
1204
|
async version() {
|
|
903
1205
|
try {
|
|
904
|
-
const out =
|
|
1206
|
+
const out = spawnSync3(this.executable, ["--version"], { encoding: "utf8", timeout: 1e4 });
|
|
905
1207
|
return out.stdout?.trim().split("\n")[0] || void 0;
|
|
906
1208
|
} catch {
|
|
907
1209
|
return void 0;
|
|
@@ -975,7 +1277,7 @@ function mediaPrompt(text, media) {
|
|
|
975
1277
|
}
|
|
976
1278
|
|
|
977
1279
|
// src/core/providers/codex.ts
|
|
978
|
-
import { spawn as spawn4, spawnSync as
|
|
1280
|
+
import { spawn as spawn4, spawnSync as spawnSync4 } from "child_process";
|
|
979
1281
|
import * as fs4 from "fs";
|
|
980
1282
|
import * as os4 from "os";
|
|
981
1283
|
import * as path4 from "path";
|
|
@@ -999,12 +1301,17 @@ var CodexAgentSession = class {
|
|
|
999
1301
|
lastUsage;
|
|
1000
1302
|
opening;
|
|
1001
1303
|
closed = false;
|
|
1304
|
+
sending = false;
|
|
1305
|
+
turnAbort;
|
|
1306
|
+
reasoningEmitted = /* @__PURE__ */ new Map();
|
|
1307
|
+
incoming = /* @__PURE__ */ new Map();
|
|
1002
1308
|
/** Item text already emitted as deltas, so item/completed only fills gaps. */
|
|
1003
1309
|
emitted = /* @__PURE__ */ new Map();
|
|
1004
1310
|
get id() {
|
|
1005
1311
|
return this.threadId;
|
|
1006
1312
|
}
|
|
1007
1313
|
fail(err) {
|
|
1314
|
+
this.turnAbort?.abort();
|
|
1008
1315
|
for (const [, p] of this.pending) p.reject(err);
|
|
1009
1316
|
this.pending.clear();
|
|
1010
1317
|
this.queue?.fail(err);
|
|
@@ -1029,6 +1336,7 @@ var CodexAgentSession = class {
|
|
|
1029
1336
|
return promise;
|
|
1030
1337
|
}
|
|
1031
1338
|
respond(id, result) {
|
|
1339
|
+
if (this.incoming.get(id)?.signal.aborted) return;
|
|
1032
1340
|
this.child?.stdin?.write(`${JSON.stringify({ jsonrpc: "2.0", id, result })}
|
|
1033
1341
|
`);
|
|
1034
1342
|
}
|
|
@@ -1082,13 +1390,20 @@ var CodexAgentSession = class {
|
|
|
1082
1390
|
...native.config ? { config: native.config } : {},
|
|
1083
1391
|
...options.systemPrompt ? { developerInstructions: options.systemPrompt } : {}
|
|
1084
1392
|
};
|
|
1393
|
+
if (options.resume && (options.fork || options.forkAt)) {
|
|
1394
|
+
const forked = await this.request("thread/fork", {
|
|
1395
|
+
threadId: options.resume,
|
|
1396
|
+
...options.forkAt ? { lastTurnId: options.forkAt } : {},
|
|
1397
|
+
...overrides
|
|
1398
|
+
});
|
|
1399
|
+
this.threadId = forked["thread"]?.id;
|
|
1400
|
+
if (!this.threadId) throw new ProviderError("codex", "thread/fork returned no thread id");
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1085
1403
|
if (options.resume) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
return;
|
|
1090
|
-
} catch {
|
|
1091
|
-
}
|
|
1404
|
+
const resumed = await this.request("thread/resume", { threadId: options.resume, ...overrides });
|
|
1405
|
+
this.threadId = resumed["thread"]?.id ?? options.resume;
|
|
1406
|
+
return;
|
|
1092
1407
|
}
|
|
1093
1408
|
const started = await this.request("thread/start", overrides);
|
|
1094
1409
|
this.threadId = started["thread"]?.id;
|
|
@@ -1106,7 +1421,17 @@ var CodexAgentSession = class {
|
|
|
1106
1421
|
}
|
|
1107
1422
|
if (!msg.method) return;
|
|
1108
1423
|
if (msg.id !== void 0) {
|
|
1109
|
-
|
|
1424
|
+
const id = msg.id;
|
|
1425
|
+
const controller = new AbortController();
|
|
1426
|
+
const parent = this.turnAbort?.signal;
|
|
1427
|
+
const cancel = () => controller.abort();
|
|
1428
|
+
if (parent?.aborted) controller.abort();
|
|
1429
|
+
else parent?.addEventListener("abort", cancel, { once: true });
|
|
1430
|
+
this.incoming.set(id, controller);
|
|
1431
|
+
void this.handleServerRequest(msg.method, id, msg.params ?? {}, controller.signal).finally(() => {
|
|
1432
|
+
parent?.removeEventListener("abort", cancel);
|
|
1433
|
+
this.incoming.delete(id);
|
|
1434
|
+
});
|
|
1110
1435
|
return;
|
|
1111
1436
|
}
|
|
1112
1437
|
this.handleNotification(msg.method, msg.params ?? {});
|
|
@@ -1116,7 +1441,13 @@ var CodexAgentSession = class {
|
|
|
1116
1441
|
}
|
|
1117
1442
|
handleNotification(method, params) {
|
|
1118
1443
|
if (params["threadId"] !== void 0 && params["threadId"] !== this.threadId) return;
|
|
1444
|
+
if (this.currentTurnId && typeof params["turnId"] === "string" && params["turnId"] !== this.currentTurnId) return;
|
|
1119
1445
|
switch (method) {
|
|
1446
|
+
case "serverRequest/resolved": {
|
|
1447
|
+
const requestId = params["requestId"];
|
|
1448
|
+
if (typeof requestId === "string" || typeof requestId === "number") this.incoming.get(requestId)?.abort();
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1120
1451
|
case "item/agentMessage/delta": {
|
|
1121
1452
|
const itemId = params["itemId"];
|
|
1122
1453
|
const delta = params["delta"];
|
|
@@ -1124,6 +1455,14 @@ var CodexAgentSession = class {
|
|
|
1124
1455
|
this.push({ type: "text", text: delta });
|
|
1125
1456
|
break;
|
|
1126
1457
|
}
|
|
1458
|
+
case "item/reasoning/summaryTextDelta": {
|
|
1459
|
+
const delta = params["delta"];
|
|
1460
|
+
if (typeof delta !== "string") break;
|
|
1461
|
+
const key = `${String(params["itemId"])}:${String(params["summaryIndex"] ?? 0)}`;
|
|
1462
|
+
this.reasoningEmitted.set(key, (this.reasoningEmitted.get(key) ?? 0) + delta.length);
|
|
1463
|
+
this.push({ type: "thinking", text: delta });
|
|
1464
|
+
break;
|
|
1465
|
+
}
|
|
1127
1466
|
case "item/started":
|
|
1128
1467
|
case "item/completed": {
|
|
1129
1468
|
this.handleItem(params["item"], method === "item/completed");
|
|
@@ -1142,11 +1481,32 @@ var CodexAgentSession = class {
|
|
|
1142
1481
|
}
|
|
1143
1482
|
break;
|
|
1144
1483
|
}
|
|
1484
|
+
case "turn/plan/updated": {
|
|
1485
|
+
const steps = Array.isArray(params["plan"]) ? params["plan"] : [];
|
|
1486
|
+
this.push({
|
|
1487
|
+
type: "plan",
|
|
1488
|
+
plan: {
|
|
1489
|
+
...typeof params["explanation"] === "string" ? { explanation: params["explanation"] } : {},
|
|
1490
|
+
entries: steps.flatMap((value) => {
|
|
1491
|
+
const step = value;
|
|
1492
|
+
if (typeof step["step"] !== "string") return [];
|
|
1493
|
+
return [{
|
|
1494
|
+
content: step["step"],
|
|
1495
|
+
status: codexPlanStatus(step["status"])
|
|
1496
|
+
}];
|
|
1497
|
+
})
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
break;
|
|
1501
|
+
}
|
|
1145
1502
|
case "turn/completed": {
|
|
1146
1503
|
const turn = params["turn"];
|
|
1504
|
+
const turnId = params["turn"]?.id;
|
|
1505
|
+
if (this.currentTurnId && turnId && turnId !== this.currentTurnId) break;
|
|
1147
1506
|
const queue = this.queue;
|
|
1148
1507
|
this.queue = null;
|
|
1149
1508
|
this.currentTurnId = void 0;
|
|
1509
|
+
this.turnAbort?.abort();
|
|
1150
1510
|
if (!queue) break;
|
|
1151
1511
|
if (turn.status === "failed") {
|
|
1152
1512
|
queue.fail(this.classify(new Error(turn.error?.message ?? "turn failed")));
|
|
@@ -1183,8 +1543,13 @@ var CodexAgentSession = class {
|
|
|
1183
1543
|
}
|
|
1184
1544
|
case "reasoning": {
|
|
1185
1545
|
if (!completed) break;
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1546
|
+
const summaries = item["summary"] ?? [];
|
|
1547
|
+
summaries.forEach((summary, index) => {
|
|
1548
|
+
const key = `${id}:${index}`;
|
|
1549
|
+
const seen = this.reasoningEmitted.get(key) ?? 0;
|
|
1550
|
+
if (summary.length > seen) this.push({ type: "thinking", text: summary.slice(seen) });
|
|
1551
|
+
this.reasoningEmitted.delete(key);
|
|
1552
|
+
});
|
|
1188
1553
|
break;
|
|
1189
1554
|
}
|
|
1190
1555
|
case "commandExecution": {
|
|
@@ -1237,8 +1602,59 @@ var CodexAgentSession = class {
|
|
|
1237
1602
|
});
|
|
1238
1603
|
break;
|
|
1239
1604
|
}
|
|
1240
|
-
case "
|
|
1605
|
+
case "dynamicToolCall": {
|
|
1606
|
+
const failed = item["status"] === "failed" || item["success"] === false;
|
|
1607
|
+
const namespace = typeof item["namespace"] === "string" ? `${item["namespace"]}.` : "";
|
|
1608
|
+
this.push({
|
|
1609
|
+
type: "tool_call",
|
|
1610
|
+
id,
|
|
1611
|
+
name: `${namespace}${String(item["tool"] ?? "tool")}`,
|
|
1612
|
+
status: completed ? failed ? "failed" : "completed" : "started",
|
|
1613
|
+
kind: "other",
|
|
1614
|
+
input: item["arguments"],
|
|
1615
|
+
...completed ? { output: item["contentItems"] } : {}
|
|
1616
|
+
});
|
|
1617
|
+
break;
|
|
1618
|
+
}
|
|
1619
|
+
case "collabAgentToolCall": {
|
|
1620
|
+
const status = item["status"];
|
|
1621
|
+
const failed = status === "failed" || status === "interrupted";
|
|
1622
|
+
const tool = collabToolName(item["tool"]);
|
|
1623
|
+
this.push({
|
|
1624
|
+
type: "tool_call",
|
|
1625
|
+
id,
|
|
1626
|
+
name: tool,
|
|
1627
|
+
status: completed ? failed ? "failed" : "completed" : "started",
|
|
1628
|
+
title: typeof item["prompt"] === "string" && item["prompt"] ? item["prompt"] : tool,
|
|
1629
|
+
kind: "other",
|
|
1630
|
+
input: {
|
|
1631
|
+
prompt: item["prompt"],
|
|
1632
|
+
model: item["model"],
|
|
1633
|
+
effort: item["reasoningEffort"],
|
|
1634
|
+
receiverThreadIds: item["receiverThreadIds"]
|
|
1635
|
+
},
|
|
1636
|
+
...completed ? { output: item["agentsStates"] } : {}
|
|
1637
|
+
});
|
|
1638
|
+
break;
|
|
1639
|
+
}
|
|
1640
|
+
case "imageView": {
|
|
1641
|
+
this.push({
|
|
1642
|
+
type: "tool_call",
|
|
1643
|
+
id,
|
|
1644
|
+
name: "read_file",
|
|
1645
|
+
status: completed ? "completed" : "started",
|
|
1646
|
+
title: String(item["path"] ?? "image"),
|
|
1647
|
+
kind: "read",
|
|
1648
|
+
input: { path: item["path"] }
|
|
1649
|
+
});
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1241
1652
|
case "plan":
|
|
1653
|
+
if (completed && typeof item["text"] === "string") {
|
|
1654
|
+
this.push({ type: "plan", plan: { id, markdown: item["text"] } });
|
|
1655
|
+
}
|
|
1656
|
+
break;
|
|
1657
|
+
case "userMessage":
|
|
1242
1658
|
break;
|
|
1243
1659
|
default:
|
|
1244
1660
|
this.push({ type: "raw", provider: "codex", payload: item });
|
|
@@ -1246,16 +1662,17 @@ var CodexAgentSession = class {
|
|
|
1246
1662
|
}
|
|
1247
1663
|
}
|
|
1248
1664
|
// ── approvals: forwarded to the host, answered like the TUI would ──
|
|
1249
|
-
async decide(request) {
|
|
1665
|
+
async decide(request, signal2) {
|
|
1666
|
+
if (signal2?.aborted) return "deny";
|
|
1250
1667
|
try {
|
|
1251
|
-
const decision = await this.config.options.permissions.decide(request);
|
|
1668
|
+
const decision = await this.config.options.permissions.decide(request, signal2);
|
|
1252
1669
|
this.push({ type: "permission", request, decision });
|
|
1253
1670
|
return decision;
|
|
1254
1671
|
} catch {
|
|
1255
1672
|
return "deny";
|
|
1256
1673
|
}
|
|
1257
1674
|
}
|
|
1258
|
-
async handleServerRequest(method, id, params) {
|
|
1675
|
+
async handleServerRequest(method, id, params, signal2) {
|
|
1259
1676
|
switch (method) {
|
|
1260
1677
|
case "item/commandExecution/requestApproval": {
|
|
1261
1678
|
const decision = await this.decide({
|
|
@@ -1266,7 +1683,7 @@ var CodexAgentSession = class {
|
|
|
1266
1683
|
title: String(params["command"] ?? "command"),
|
|
1267
1684
|
input: { command: params["command"], cwd: params["cwd"], reason: params["reason"] },
|
|
1268
1685
|
raw: params
|
|
1269
|
-
});
|
|
1686
|
+
}, signal2);
|
|
1270
1687
|
this.respond(id, {
|
|
1271
1688
|
decision: decision === "allow" ? "accept" : decision === "allow_always" ? "acceptForSession" : "decline"
|
|
1272
1689
|
});
|
|
@@ -1281,7 +1698,7 @@ var CodexAgentSession = class {
|
|
|
1281
1698
|
title: String(params["reason"] ?? "apply file changes"),
|
|
1282
1699
|
input: { reason: params["reason"], grantRoot: params["grantRoot"] },
|
|
1283
1700
|
raw: params
|
|
1284
|
-
});
|
|
1701
|
+
}, signal2);
|
|
1285
1702
|
this.respond(id, {
|
|
1286
1703
|
decision: decision === "allow" ? "accept" : decision === "allow_always" ? "acceptForSession" : "decline"
|
|
1287
1704
|
});
|
|
@@ -1297,7 +1714,7 @@ var CodexAgentSession = class {
|
|
|
1297
1714
|
title: String(params["reason"] ?? "extra permissions"),
|
|
1298
1715
|
input: requested,
|
|
1299
1716
|
raw: params
|
|
1300
|
-
});
|
|
1717
|
+
}, signal2);
|
|
1301
1718
|
const granted = decision === "allow" || decision === "allow_always";
|
|
1302
1719
|
this.respond(id, {
|
|
1303
1720
|
permissions: granted ? { network: requested?.["network"] ?? void 0, fileSystem: requested?.["fileSystem"] ?? void 0 } : {},
|
|
@@ -1316,18 +1733,32 @@ var CodexAgentSession = class {
|
|
|
1316
1733
|
title: String(params["command"] ?? params["reason"] ?? "approval"),
|
|
1317
1734
|
input: params,
|
|
1318
1735
|
raw: params
|
|
1319
|
-
});
|
|
1736
|
+
}, signal2);
|
|
1320
1737
|
this.respond(id, {
|
|
1321
1738
|
decision: decision === "allow" ? "approved" : decision === "allow_always" ? "approved_for_session" : { denied: { rejection: "denied by the user" } }
|
|
1322
1739
|
});
|
|
1323
1740
|
break;
|
|
1324
1741
|
}
|
|
1325
1742
|
case "item/tool/requestUserInput": {
|
|
1326
|
-
this.
|
|
1743
|
+
const response = await this.input(codexQuestionRequest(this.threadId, params), signal2);
|
|
1744
|
+
const values = response.action === "accept" ? response.values ?? {} : {};
|
|
1745
|
+
this.respond(id, {
|
|
1746
|
+
answers: Object.fromEntries(
|
|
1747
|
+
Object.entries(values).map(([key, value]) => [
|
|
1748
|
+
key,
|
|
1749
|
+
{ answers: (Array.isArray(value) ? value : [value]).map(String) }
|
|
1750
|
+
])
|
|
1751
|
+
)
|
|
1752
|
+
});
|
|
1327
1753
|
break;
|
|
1328
1754
|
}
|
|
1329
1755
|
case "mcpServer/elicitation/request": {
|
|
1330
|
-
this.
|
|
1756
|
+
const response = await this.input(elicitationRequest("codex", this.threadId, params), signal2);
|
|
1757
|
+
this.respond(id, { ...elicitationResponse(response), _meta: null });
|
|
1758
|
+
break;
|
|
1759
|
+
}
|
|
1760
|
+
case "currentTime/read": {
|
|
1761
|
+
this.respond(id, { currentTimeAt: Math.floor(Date.now() / 1e3) });
|
|
1331
1762
|
break;
|
|
1332
1763
|
}
|
|
1333
1764
|
default: {
|
|
@@ -1339,51 +1770,133 @@ var CodexAgentSession = class {
|
|
|
1339
1770
|
}
|
|
1340
1771
|
}
|
|
1341
1772
|
}
|
|
1773
|
+
async input(request, signal2) {
|
|
1774
|
+
const handler = this.config.options.input;
|
|
1775
|
+
if (!handler) return declineInput();
|
|
1776
|
+
try {
|
|
1777
|
+
if (signal2?.aborted) return { action: "cancel" };
|
|
1778
|
+
return await handler.respond(request, signal2);
|
|
1779
|
+
} catch {
|
|
1780
|
+
return { action: "cancel" };
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1342
1783
|
// ── the ProviderSession surface ────────────────────────────────────
|
|
1343
1784
|
async *send(input) {
|
|
1344
1785
|
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: [] });
|
|
1786
|
+
if (this.sending) throw new ProviderError("codex", "a turn is already running");
|
|
1787
|
+
this.sending = true;
|
|
1788
|
+
const controller = new AbortController();
|
|
1789
|
+
this.turnAbort = controller;
|
|
1790
|
+
let cleanup = () => {
|
|
1791
|
+
};
|
|
1357
1792
|
const queue = new AsyncQueue();
|
|
1358
|
-
this.queue = queue;
|
|
1359
|
-
this.lastUsage = void 0;
|
|
1360
1793
|
try {
|
|
1794
|
+
await this.ensureOpen();
|
|
1795
|
+
if (controller.signal.aborted) {
|
|
1796
|
+
yield { type: "done", stopReason: "interrupted" };
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
const blocks = typeof input === "string" ? [{ type: "text", text: input }] : input;
|
|
1800
|
+
const images = writeTempImages(blocks);
|
|
1801
|
+
cleanup = images.cleanup;
|
|
1802
|
+
const items = [];
|
|
1803
|
+
for (const block of blocks) {
|
|
1804
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
1805
|
+
items.push({ type: "text", text: block.text, text_elements: [] });
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
for (const p of images.paths) items.push({ type: "localImage", path: p });
|
|
1809
|
+
if (items.length === 0) items.push({ type: "text", text: "", text_elements: [] });
|
|
1810
|
+
this.queue = queue;
|
|
1811
|
+
this.lastUsage = void 0;
|
|
1812
|
+
this.emitted.clear();
|
|
1813
|
+
this.reasoningEmitted.clear();
|
|
1361
1814
|
const result = await this.request("turn/start", {
|
|
1362
1815
|
threadId: this.threadId,
|
|
1363
1816
|
input: items,
|
|
1364
1817
|
...this.config.options.effort ? { effort: this.config.options.effort } : {}
|
|
1365
1818
|
});
|
|
1366
|
-
|
|
1819
|
+
const turnId = result["turn"]?.id;
|
|
1820
|
+
if (this.queue === queue) this.currentTurnId = turnId;
|
|
1821
|
+
if (controller.signal.aborted && this.currentTurnId) await this.interrupt();
|
|
1367
1822
|
yield { type: "session", sessionId: this.threadId };
|
|
1823
|
+
if (turnId) yield { type: "turn", id: turnId };
|
|
1368
1824
|
for await (const event of queue) yield event;
|
|
1369
1825
|
} finally {
|
|
1370
1826
|
cleanup();
|
|
1827
|
+
controller.abort();
|
|
1828
|
+
if (this.queue === queue) await this.interrupt();
|
|
1371
1829
|
if (this.queue === queue) this.queue = null;
|
|
1830
|
+
this.currentTurnId = void 0;
|
|
1831
|
+
this.turnAbort = void 0;
|
|
1832
|
+
this.sending = false;
|
|
1372
1833
|
}
|
|
1373
1834
|
}
|
|
1374
1835
|
async interrupt() {
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1836
|
+
const request = this.threadId && this.currentTurnId ? this.request("turn/interrupt", { threadId: this.threadId, turnId: this.currentTurnId }).catch(() => {
|
|
1837
|
+
}) : Promise.resolve();
|
|
1838
|
+
this.turnAbort?.abort();
|
|
1839
|
+
await request;
|
|
1378
1840
|
}
|
|
1379
1841
|
async close() {
|
|
1380
1842
|
if (this.closed) return;
|
|
1381
1843
|
this.closed = true;
|
|
1382
1844
|
this.fail(new ProviderError("codex", "session closed"));
|
|
1383
|
-
this.child
|
|
1845
|
+
killTree(this.child);
|
|
1384
1846
|
this.child = void 0;
|
|
1385
1847
|
}
|
|
1386
1848
|
};
|
|
1849
|
+
function collabToolName(value) {
|
|
1850
|
+
const names = {
|
|
1851
|
+
spawnAgent: "spawn_agent",
|
|
1852
|
+
sendInput: "send_input",
|
|
1853
|
+
resumeAgent: "resume_agent",
|
|
1854
|
+
closeAgent: "close_agent",
|
|
1855
|
+
sendMessage: "send_message",
|
|
1856
|
+
followupTask: "followup_task",
|
|
1857
|
+
interruptAgent: "interrupt_agent",
|
|
1858
|
+
listAgents: "list_agents"
|
|
1859
|
+
};
|
|
1860
|
+
return names[String(value)] ?? String(value ?? "agent");
|
|
1861
|
+
}
|
|
1862
|
+
function codexPlanStatus(value) {
|
|
1863
|
+
return value === "completed" ? "completed" : value === "inProgress" || value === "in_progress" ? "in_progress" : "pending";
|
|
1864
|
+
}
|
|
1865
|
+
function codexQuestionRequest(sessionId, raw) {
|
|
1866
|
+
const questions = Array.isArray(raw["questions"]) ? raw["questions"] : [];
|
|
1867
|
+
const fields = questions.flatMap((value) => {
|
|
1868
|
+
const question = value;
|
|
1869
|
+
if (typeof question["id"] !== "string" || typeof question["question"] !== "string") return [];
|
|
1870
|
+
const choices = Array.isArray(question["options"]) ? question["options"].flatMap((option) => {
|
|
1871
|
+
const item = option;
|
|
1872
|
+
if (typeof item["label"] !== "string") return [];
|
|
1873
|
+
return [{
|
|
1874
|
+
value: item["label"],
|
|
1875
|
+
label: item["label"],
|
|
1876
|
+
...typeof item["description"] === "string" ? { description: item["description"] } : {}
|
|
1877
|
+
}];
|
|
1878
|
+
}) : [];
|
|
1879
|
+
return [{
|
|
1880
|
+
id: question["id"],
|
|
1881
|
+
label: question["question"],
|
|
1882
|
+
...typeof question["header"] === "string" ? { description: question["header"] } : {},
|
|
1883
|
+
type: choices.length > 0 ? "select" : "string",
|
|
1884
|
+
required: true,
|
|
1885
|
+
secret: question["isSecret"] === true,
|
|
1886
|
+
allowOther: question["isOther"] === true,
|
|
1887
|
+
...choices.length > 0 ? { options: choices } : {}
|
|
1888
|
+
}];
|
|
1889
|
+
});
|
|
1890
|
+
return {
|
|
1891
|
+
provider: "codex",
|
|
1892
|
+
...sessionId ? { sessionId } : {},
|
|
1893
|
+
kind: "questions",
|
|
1894
|
+
message: fields.length === 1 ? fields[0].label : "Input requested",
|
|
1895
|
+
fields,
|
|
1896
|
+
blocking: raw["isBlocking"] !== false,
|
|
1897
|
+
raw
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1387
1900
|
|
|
1388
1901
|
// src/core/providers/jsonl.ts
|
|
1389
1902
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -1420,12 +1933,17 @@ function spawnJsonl(options) {
|
|
|
1420
1933
|
}
|
|
1421
1934
|
});
|
|
1422
1935
|
const onAbort = () => {
|
|
1423
|
-
child
|
|
1936
|
+
killTree(child);
|
|
1424
1937
|
queue.end();
|
|
1425
1938
|
};
|
|
1426
1939
|
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1940
|
+
queue.onReturn = () => {
|
|
1941
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
1942
|
+
killTree(child);
|
|
1943
|
+
};
|
|
1427
1944
|
child.on("error", (err) => queue.fail(err));
|
|
1428
1945
|
child.on("close", (code) => {
|
|
1946
|
+
queue.onReturn = void 0;
|
|
1429
1947
|
options.signal?.removeEventListener("abort", onAbort);
|
|
1430
1948
|
if (options.signal?.aborted) return queue.end();
|
|
1431
1949
|
if (code !== 0) queue.fail(new ProcessExitError(code, stderr));
|
|
@@ -1452,8 +1970,10 @@ var CodexProvider = class {
|
|
|
1452
1970
|
systemPrompt: false,
|
|
1453
1971
|
thinking: false,
|
|
1454
1972
|
effort: true,
|
|
1455
|
-
streaming: "chunks"
|
|
1973
|
+
streaming: "chunks",
|
|
1974
|
+
serverTools: false
|
|
1456
1975
|
};
|
|
1976
|
+
sessionCapabilities = { fork: true };
|
|
1457
1977
|
workDir;
|
|
1458
1978
|
sandbox;
|
|
1459
1979
|
env;
|
|
@@ -1549,7 +2069,7 @@ var CodexProvider = class {
|
|
|
1549
2069
|
if (settled) return;
|
|
1550
2070
|
settled = true;
|
|
1551
2071
|
clearTimeout(timer);
|
|
1552
|
-
child
|
|
2072
|
+
killTree(child);
|
|
1553
2073
|
fn();
|
|
1554
2074
|
};
|
|
1555
2075
|
const timer = setTimeout(() => finish(() => reject(new ProviderError(this.id, "timed out listing models via app-server"))), 15e3);
|
|
@@ -1578,11 +2098,34 @@ var CodexProvider = class {
|
|
|
1578
2098
|
finish(() => reject(classifyProviderFailure(this.id, this.loginCommand, new Error(msg.error?.message ?? "model/list failed"))));
|
|
1579
2099
|
return;
|
|
1580
2100
|
}
|
|
1581
|
-
const models = (msg.result?.data ?? []).filter((m) => m["hidden"] !== true).map((m) =>
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2101
|
+
const models = (msg.result?.data ?? []).filter((m) => m["hidden"] !== true).map((m) => {
|
|
2102
|
+
const efforts = Array.isArray(m["supportedReasoningEfforts"]) ? m["supportedReasoningEfforts"].flatMap(
|
|
2103
|
+
(entry) => typeof entry["reasoningEffort"] === "string" ? [{
|
|
2104
|
+
id: entry["reasoningEffort"],
|
|
2105
|
+
...typeof entry["description"] === "string" ? { description: entry["description"] } : {}
|
|
2106
|
+
}] : []
|
|
2107
|
+
) : [];
|
|
2108
|
+
const tiers = Array.isArray(m["serviceTiers"]) ? m["serviceTiers"].flatMap(
|
|
2109
|
+
(entry) => typeof entry["id"] === "string" ? [{
|
|
2110
|
+
id: entry["id"],
|
|
2111
|
+
display_name: typeof entry["name"] === "string" ? entry["name"] : entry["id"],
|
|
2112
|
+
...typeof entry["description"] === "string" ? { description: entry["description"] } : {}
|
|
2113
|
+
}] : []
|
|
2114
|
+
) : [];
|
|
2115
|
+
return {
|
|
2116
|
+
id: String(m["id"] ?? m["model"]),
|
|
2117
|
+
display_name: String(m["displayName"] ?? m["id"] ?? m["model"]),
|
|
2118
|
+
...typeof m["description"] === "string" ? { description: m["description"] } : {},
|
|
2119
|
+
...efforts.length > 0 ? { reasoning_efforts: efforts } : {},
|
|
2120
|
+
...typeof m["defaultReasoningEffort"] === "string" ? { default_reasoning_effort: m["defaultReasoningEffort"] } : {},
|
|
2121
|
+
...Array.isArray(m["inputModalities"]) ? { input_modalities: m["inputModalities"].filter((value) => typeof value === "string") } : {},
|
|
2122
|
+
...m["supportsPersonality"] === true ? { supports_personality: true } : {},
|
|
2123
|
+
...typeof m["multiAgentVersion"] === "string" ? { multi_agent: m["multiAgentVersion"] } : {},
|
|
2124
|
+
...tiers.length > 0 ? { service_tiers: tiers } : {},
|
|
2125
|
+
...typeof m["defaultServiceTier"] === "string" ? { default_service_tier: m["defaultServiceTier"] } : {},
|
|
2126
|
+
...m["isDefault"] === true ? { is_default: true } : {}
|
|
2127
|
+
};
|
|
2128
|
+
});
|
|
1586
2129
|
finish(() => resolve(models));
|
|
1587
2130
|
}
|
|
1588
2131
|
});
|
|
@@ -1599,7 +2142,7 @@ var CodexProvider = class {
|
|
|
1599
2142
|
}
|
|
1600
2143
|
async version() {
|
|
1601
2144
|
try {
|
|
1602
|
-
const out =
|
|
2145
|
+
const out = spawnSync4(this.executable, ["--version"], { encoding: "utf8", timeout: 1e4 });
|
|
1603
2146
|
return out.stdout?.trim().split("\n")[0] || void 0;
|
|
1604
2147
|
} catch {
|
|
1605
2148
|
return void 0;
|
|
@@ -1901,6 +2444,61 @@ var SseSynthesizer = class {
|
|
|
1901
2444
|
|
|
1902
2445
|
// src/core/transcript.ts
|
|
1903
2446
|
import { createHash } from "crypto";
|
|
2447
|
+
|
|
2448
|
+
// src/core/serverTools.ts
|
|
2449
|
+
var SERVER_TOOLS = {
|
|
2450
|
+
web_search: "WebSearch",
|
|
2451
|
+
web_fetch: "WebFetch"
|
|
2452
|
+
};
|
|
2453
|
+
function serverToolFor(type) {
|
|
2454
|
+
if (typeof type !== "string") return void 0;
|
|
2455
|
+
for (const [prefix, tool] of Object.entries(SERVER_TOOLS)) {
|
|
2456
|
+
if (type === prefix || type.startsWith(`${prefix}_`)) return tool;
|
|
2457
|
+
}
|
|
2458
|
+
return void 0;
|
|
2459
|
+
}
|
|
2460
|
+
function resolveServerTools(tools, toolChoice) {
|
|
2461
|
+
if (tools == null) {
|
|
2462
|
+
if (toolChoice != null) {
|
|
2463
|
+
throw new ApiError(
|
|
2464
|
+
400,
|
|
2465
|
+
"invalid_request_error",
|
|
2466
|
+
"`tool_choice` was given without `tools`."
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
return void 0;
|
|
2470
|
+
}
|
|
2471
|
+
if (!Array.isArray(tools)) {
|
|
2472
|
+
throw new ApiError(400, "invalid_request_error", "`tools` must be an array");
|
|
2473
|
+
}
|
|
2474
|
+
if (tools.length === 0) return void 0;
|
|
2475
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
2476
|
+
for (const tool of tools) {
|
|
2477
|
+
const entry = tool;
|
|
2478
|
+
const mapped = serverToolFor(entry?.type);
|
|
2479
|
+
if (!mapped) {
|
|
2480
|
+
const label = typeof entry?.name === "string" ? `"${entry.name}"` : `type "${String(entry?.type)}"`;
|
|
2481
|
+
throw new ApiError(
|
|
2482
|
+
400,
|
|
2483
|
+
"invalid_request_error",
|
|
2484
|
+
`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.`
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
resolved.add(mapped);
|
|
2488
|
+
}
|
|
2489
|
+
const choice = toolChoice?.type;
|
|
2490
|
+
if (choice != null && choice !== "auto" && choice !== "none") {
|
|
2491
|
+
throw new ApiError(
|
|
2492
|
+
400,
|
|
2493
|
+
"invalid_request_error",
|
|
2494
|
+
`\`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.`
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
if (choice === "none") return void 0;
|
|
2498
|
+
return [...resolved];
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
// src/core/transcript.ts
|
|
1904
2502
|
var IGNORABLE_PARAMS = [
|
|
1905
2503
|
"max_tokens",
|
|
1906
2504
|
"temperature",
|
|
@@ -1962,13 +2560,7 @@ function normalizeRequest(req) {
|
|
|
1962
2560
|
if (req == null || typeof req !== "object") {
|
|
1963
2561
|
throw new ApiError(400, "invalid_request_error", "request body must be a JSON object");
|
|
1964
2562
|
}
|
|
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
|
-
}
|
|
2563
|
+
const serverTools = resolveServerTools(req.tools, req.tool_choice);
|
|
1972
2564
|
if (!Array.isArray(req.messages) || req.messages.length === 0) {
|
|
1973
2565
|
throw new ApiError(400, "invalid_request_error", "`messages` must be a non-empty array");
|
|
1974
2566
|
}
|
|
@@ -2004,7 +2596,8 @@ function normalizeRequest(req) {
|
|
|
2004
2596
|
messages,
|
|
2005
2597
|
lastUserText: last.text,
|
|
2006
2598
|
...prefill !== void 0 ? { prefill } : {},
|
|
2007
|
-
ignored: [...ignored]
|
|
2599
|
+
ignored: [...ignored],
|
|
2600
|
+
...serverTools ? { serverTools } : {}
|
|
2008
2601
|
};
|
|
2009
2602
|
}
|
|
2010
2603
|
function prefillDirective(prefill) {
|
|
@@ -2232,6 +2825,13 @@ ${norm.system}
|
|
|
2232
2825
|
|
|
2233
2826
|
${promptText}`;
|
|
2234
2827
|
}
|
|
2828
|
+
if (norm.serverTools && !caps.serverTools) {
|
|
2829
|
+
throw new ApiError(
|
|
2830
|
+
400,
|
|
2831
|
+
"invalid_request_error",
|
|
2832
|
+
`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\`.`
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2235
2835
|
const turn = {
|
|
2236
2836
|
prompt: promptText,
|
|
2237
2837
|
...lastMedia.length > 0 ? { media: lastMedia } : {},
|
|
@@ -2239,7 +2839,8 @@ ${promptText}`;
|
|
|
2239
2839
|
...model ? { model } : {},
|
|
2240
2840
|
...resume ? { resume } : {},
|
|
2241
2841
|
...req.thinking != null && caps.thinking ? { thinking: req.thinking } : {},
|
|
2242
|
-
...typeof req.effort === "string" && caps.effort ? { effort: req.effort } : {}
|
|
2842
|
+
...typeof req.effort === "string" && caps.effort ? { effort: req.effort } : {},
|
|
2843
|
+
...norm.serverTools ? { serverTools: norm.serverTools } : {}
|
|
2243
2844
|
};
|
|
2244
2845
|
const requestedModel = model ? provider.id === this.defaultProviderId ? model : qualifiedModel(provider.id, model) : provider.id;
|
|
2245
2846
|
return { provider, turn, norm, requestedModel, ignored, ...resume && resumeKey ? { resumeKey } : {} };
|
|
@@ -2330,7 +2931,7 @@ ${promptText}`;
|
|
|
2330
2931
|
};
|
|
2331
2932
|
}
|
|
2332
2933
|
async *runStream(req, prepared, streamOptions) {
|
|
2333
|
-
const { signal } = streamOptions;
|
|
2934
|
+
const { signal: signal2 } = streamOptions;
|
|
2334
2935
|
let emitted = false;
|
|
2335
2936
|
try {
|
|
2336
2937
|
for await (const ev of this.attemptStream(prepared, streamOptions)) {
|
|
@@ -2339,7 +2940,7 @@ ${promptText}`;
|
|
|
2339
2940
|
}
|
|
2340
2941
|
return;
|
|
2341
2942
|
} catch (err) {
|
|
2342
|
-
if (
|
|
2943
|
+
if (signal2?.aborted) return;
|
|
2343
2944
|
const fallback = emitted ? void 0 : this.prepareResumeFallback(req, prepared);
|
|
2344
2945
|
if (!fallback) {
|
|
2345
2946
|
yield { event: "error", data: toApiError(err).toBody() };
|
|
@@ -2348,13 +2949,13 @@ ${promptText}`;
|
|
|
2348
2949
|
try {
|
|
2349
2950
|
yield* this.attemptStream(fallback, streamOptions);
|
|
2350
2951
|
} catch (err2) {
|
|
2351
|
-
if (!
|
|
2952
|
+
if (!signal2?.aborted) yield { event: "error", data: toApiError(err2).toBody() };
|
|
2352
2953
|
}
|
|
2353
2954
|
}
|
|
2354
2955
|
}
|
|
2355
2956
|
async *attemptStream(prepared, streamOptions) {
|
|
2356
2957
|
const { provider, turn, norm, requestedModel } = prepared;
|
|
2357
|
-
const { signal } = streamOptions;
|
|
2958
|
+
const { signal: signal2 } = streamOptions;
|
|
2358
2959
|
const stripper = norm.prefill ? new PrefillStripper(norm.prefill) : void 0;
|
|
2359
2960
|
const sse = new SseSynthesizer(`msg_${randomUUID().replace(/-/g, "")}`, requestedModel);
|
|
2360
2961
|
let sessionId;
|
|
@@ -2366,7 +2967,7 @@ ${promptText}`;
|
|
|
2366
2967
|
started = true;
|
|
2367
2968
|
return sse.start();
|
|
2368
2969
|
};
|
|
2369
|
-
for await (const ev of provider.run({ ...turn, ...
|
|
2970
|
+
for await (const ev of provider.run({ ...turn, ...signal2 ? { signal: signal2 } : {} })) {
|
|
2370
2971
|
if (ev.type === "session") {
|
|
2371
2972
|
sessionId = ev.sessionId;
|
|
2372
2973
|
} else if (ev.type === "text") {
|
|
@@ -2381,7 +2982,7 @@ ${promptText}`;
|
|
|
2381
2982
|
done = ev;
|
|
2382
2983
|
}
|
|
2383
2984
|
}
|
|
2384
|
-
if (
|
|
2985
|
+
if (signal2?.aborted) return;
|
|
2385
2986
|
if (!done) throw new ProviderError(provider.id, "turn ended without a result");
|
|
2386
2987
|
yield* start();
|
|
2387
2988
|
if (stripper) {
|
|
@@ -2499,7 +3100,7 @@ function chatToMessagesRequest(body) {
|
|
|
2499
3100
|
throw new ApiError(
|
|
2500
3101
|
400,
|
|
2501
3102
|
"invalid_request_error",
|
|
2502
|
-
"yagami does not support
|
|
3103
|
+
"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
3104
|
);
|
|
2504
3105
|
}
|
|
2505
3106
|
if (body.n != null && body.n !== 1) {
|
|
@@ -2692,4 +3293,4 @@ export {
|
|
|
2692
3293
|
ChatChunkTranslator,
|
|
2693
3294
|
modelListBody
|
|
2694
3295
|
};
|
|
2695
|
-
//# sourceMappingURL=chunk-
|
|
3296
|
+
//# sourceMappingURL=chunk-EKN223KD.js.map
|