@jacobbd/relay-ai 0.9.1 → 0.9.3
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/dist/{chunk-Q2FTCICO.js → chunk-NYKVDBQC.js} +2 -2
- package/dist/{chunk-Q2FTCICO.js.map → chunk-NYKVDBQC.js.map} +1 -1
- package/dist/{chunk-MFKBK6YL.js → chunk-PVGAE7HA.js} +693 -144
- package/dist/chunk-PVGAE7HA.js.map +1 -0
- package/dist/cli.js +148 -9
- package/dist/cli.js.map +1 -1
- package/dist/core/index.d.ts +40 -5
- package/dist/core/index.js +976 -28
- package/dist/core/index.js.map +1 -1
- package/dist/{provider-templates-XKNRKAQU.js → provider-templates-CGWE66TD.js} +2 -2
- package/dist/ui/public/app.js +190 -1
- package/dist/{ui-command-ZJBZZZ4X.js → ui-command-JQPEZAMN.js} +59 -7
- package/dist/ui-command-JQPEZAMN.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-MFKBK6YL.js.map +0 -1
- package/dist/ui-command-ZJBZZZ4X.js.map +0 -1
- /package/dist/{provider-templates-XKNRKAQU.js.map → provider-templates-CGWE66TD.js.map} +0 -0
package/dist/core/index.js
CHANGED
|
@@ -50,7 +50,7 @@ import { join as join2 } from "path";
|
|
|
50
50
|
// package.json
|
|
51
51
|
var package_default = {
|
|
52
52
|
name: "@jacobbd/relay-ai",
|
|
53
|
-
version: "0.9.
|
|
53
|
+
version: "0.9.3",
|
|
54
54
|
publishConfig: {
|
|
55
55
|
access: "public"
|
|
56
56
|
},
|
|
@@ -288,7 +288,320 @@ async function refreshOpenAiAccessToken(refreshToken) {
|
|
|
288
288
|
|
|
289
289
|
// src/oauth/responses-websocket.ts
|
|
290
290
|
var RESPONSES_LITE_HEADER = "x-openai-internal-codex-responses-lite";
|
|
291
|
-
var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set(["response.completed", "response.failed", "response.incomplete"]);
|
|
291
|
+
var TERMINAL_EVENT_TYPES = /* @__PURE__ */ new Set(["response.completed", "response.failed", "response.incomplete", "error"]);
|
|
292
|
+
function isRecord(value) {
|
|
293
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
294
|
+
}
|
|
295
|
+
function recordKeys(value) {
|
|
296
|
+
return isRecord(value) ? Object.keys(value).sort().join(",") : "";
|
|
297
|
+
}
|
|
298
|
+
function summarizeResponsesLiteEvent(event) {
|
|
299
|
+
if (!isRecord(event)) return `kind=${event == null ? "null" : typeof event}`;
|
|
300
|
+
const parts = [`type=${typeof event.type === "string" ? event.type : "unknown"}`, `keys=${recordKeys(event)}`];
|
|
301
|
+
if (typeof event.delta === "string") parts.push(`deltaChars=${event.delta.length}`);
|
|
302
|
+
if (typeof event.output_index === "number") parts.push(`hasOutputIndex=1`);
|
|
303
|
+
if (typeof event.item_id === "string") parts.push(`hasItemId=1`);
|
|
304
|
+
if (isRecord(event.item)) {
|
|
305
|
+
parts.push(`itemType=${typeof event.item.type === "string" ? event.item.type : "unknown"}`);
|
|
306
|
+
parts.push(`itemKeys=${recordKeys(event.item)}`);
|
|
307
|
+
if (typeof event.item.arguments === "string") parts.push(`argumentsChars=${event.item.arguments.length}`);
|
|
308
|
+
}
|
|
309
|
+
if (isRecord(event.response)) {
|
|
310
|
+
parts.push(`responseKeys=${recordKeys(event.response)}`);
|
|
311
|
+
if (Array.isArray(event.response.output)) {
|
|
312
|
+
parts.push(`outputCount=${event.response.output.length}`);
|
|
313
|
+
parts.push(`outputTypes=${event.response.output.map((item) => isRecord(item) && typeof item.type === "string" ? item.type : "unknown").join(",")}`);
|
|
314
|
+
}
|
|
315
|
+
if (isRecord(event.response.usage)) parts.push(`usageKeys=${recordKeys(event.response.usage)}`);
|
|
316
|
+
if (typeof event.response.status === "string") parts.push(`status=${event.response.status}`);
|
|
317
|
+
}
|
|
318
|
+
if (isRecord(event.error)) {
|
|
319
|
+
parts.push(`errorKeys=${recordKeys(event.error)}`);
|
|
320
|
+
if (typeof event.error.message === "string") parts.push(`messageChars=${event.error.message.length}`);
|
|
321
|
+
}
|
|
322
|
+
return parts.join(" ");
|
|
323
|
+
}
|
|
324
|
+
function createResponsesLiteNormalizeState() {
|
|
325
|
+
return {
|
|
326
|
+
nextId: 1,
|
|
327
|
+
lastOutputIndex: 0,
|
|
328
|
+
textDeltaForwarded: false,
|
|
329
|
+
messageAddedIds: /* @__PURE__ */ new Set(),
|
|
330
|
+
messageDoneIds: /* @__PURE__ */ new Set(),
|
|
331
|
+
functionCalls: []
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function nextId(state, prefix) {
|
|
335
|
+
const id = `${prefix}_${state.nextId}`;
|
|
336
|
+
state.nextId += 1;
|
|
337
|
+
return id;
|
|
338
|
+
}
|
|
339
|
+
function asString(value) {
|
|
340
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
341
|
+
}
|
|
342
|
+
function normalizeErrorEvent(event) {
|
|
343
|
+
const raw = isRecord(event.error) ? event.error : { message: typeof event.error === "string" ? event.error : "upstream error" };
|
|
344
|
+
return {
|
|
345
|
+
type: "error",
|
|
346
|
+
sequence_number: typeof event.sequence_number === "number" ? event.sequence_number : 0,
|
|
347
|
+
error: {
|
|
348
|
+
type: asString(raw.type) ?? "server_error",
|
|
349
|
+
code: asString(raw.code) ?? "unknown",
|
|
350
|
+
message: asString(raw.message) ?? "upstream error",
|
|
351
|
+
...raw.param == null ? {} : { param: raw.param }
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function resolveFunctionCall(state, hint) {
|
|
356
|
+
if (hint.callId) {
|
|
357
|
+
const byCallId = state.functionCalls.find((entry2) => entry2.callId === hint.callId);
|
|
358
|
+
if (byCallId) return byCallId;
|
|
359
|
+
}
|
|
360
|
+
if (hint.itemId) {
|
|
361
|
+
const byItemId = state.functionCalls.find((entry2) => entry2.itemId === hint.itemId);
|
|
362
|
+
if (byItemId) return byItemId;
|
|
363
|
+
}
|
|
364
|
+
if (hint.outputIndex !== void 0) {
|
|
365
|
+
const open3 = [...state.functionCalls].reverse().find((entry2) => entry2.outputIndex === hint.outputIndex && !entry2.done && !(hint.callId && entry2.callId !== hint.callId));
|
|
366
|
+
if (open3) return open3;
|
|
367
|
+
}
|
|
368
|
+
if (hint.callId === void 0 && hint.itemId === void 0 && hint.outputIndex === void 0 && state.lastFunctionCall) {
|
|
369
|
+
return state.lastFunctionCall;
|
|
370
|
+
}
|
|
371
|
+
const entry = {
|
|
372
|
+
itemId: hint.itemId ?? nextId(state, "fc"),
|
|
373
|
+
callId: hint.callId ?? hint.itemId ?? nextId(state, "call"),
|
|
374
|
+
name: "",
|
|
375
|
+
args: "",
|
|
376
|
+
upstream: {},
|
|
377
|
+
outputIndex: hint.outputIndex ?? state.lastOutputIndex,
|
|
378
|
+
added: false,
|
|
379
|
+
deltaForwarded: false,
|
|
380
|
+
doneSeen: false,
|
|
381
|
+
done: false
|
|
382
|
+
};
|
|
383
|
+
state.functionCalls.push(entry);
|
|
384
|
+
return entry;
|
|
385
|
+
}
|
|
386
|
+
function absorbFunctionItem(entry, item, authoritative) {
|
|
387
|
+
entry.upstream = { ...entry.upstream, ...item };
|
|
388
|
+
const name = asString(item.name);
|
|
389
|
+
if (name) entry.name = name;
|
|
390
|
+
const callId = asString(item.call_id);
|
|
391
|
+
if (callId) entry.callId = callId;
|
|
392
|
+
if (authoritative && typeof item.arguments === "string") entry.upstreamArgs = item.arguments;
|
|
393
|
+
}
|
|
394
|
+
function resolveFunctionArgs(entry) {
|
|
395
|
+
if (entry.upstreamArgs) return entry.upstreamArgs;
|
|
396
|
+
if (entry.args) return entry.args;
|
|
397
|
+
return entry.upstreamArgs;
|
|
398
|
+
}
|
|
399
|
+
function functionItemPayload(entry, extra) {
|
|
400
|
+
return {
|
|
401
|
+
...entry.upstream,
|
|
402
|
+
type: "function_call",
|
|
403
|
+
id: entry.itemId,
|
|
404
|
+
call_id: entry.callId,
|
|
405
|
+
name: entry.name,
|
|
406
|
+
...extra
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function functionAddedEvent(entry) {
|
|
410
|
+
entry.added = true;
|
|
411
|
+
return {
|
|
412
|
+
type: "response.output_item.added",
|
|
413
|
+
output_index: entry.outputIndex,
|
|
414
|
+
item: functionItemPayload(entry, { arguments: "" })
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function functionDoneEvent(entry, args) {
|
|
418
|
+
entry.done = true;
|
|
419
|
+
return {
|
|
420
|
+
type: "response.output_item.done",
|
|
421
|
+
output_index: entry.outputIndex,
|
|
422
|
+
item: functionItemPayload(entry, { arguments: args, status: "completed" })
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function completeFunctionCall(entry, args) {
|
|
426
|
+
if (entry.done) return [];
|
|
427
|
+
const events = [];
|
|
428
|
+
if (!entry.added) events.push(functionAddedEvent(entry));
|
|
429
|
+
if (!entry.deltaForwarded && args.length > 0) {
|
|
430
|
+
entry.deltaForwarded = true;
|
|
431
|
+
events.push({
|
|
432
|
+
type: "response.function_call_arguments.delta",
|
|
433
|
+
item_id: entry.itemId,
|
|
434
|
+
output_index: entry.outputIndex,
|
|
435
|
+
delta: args
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
events.push(functionDoneEvent(entry, args));
|
|
439
|
+
return events;
|
|
440
|
+
}
|
|
441
|
+
function messageText(item) {
|
|
442
|
+
if (typeof item.text === "string") return item.text;
|
|
443
|
+
if (!Array.isArray(item.content)) return "";
|
|
444
|
+
let out = "";
|
|
445
|
+
for (const part of item.content) {
|
|
446
|
+
if (isRecord(part) && typeof part.text === "string" && (part.type === "output_text" || part.type === "text")) {
|
|
447
|
+
out += part.text;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return out;
|
|
451
|
+
}
|
|
452
|
+
function synthesizeMessage(item, outputIndex, state) {
|
|
453
|
+
const text = messageText(item);
|
|
454
|
+
if (!text) return [];
|
|
455
|
+
const id = asString(item.id) ?? nextId(state, "msg");
|
|
456
|
+
state.lastMessageItemId = id;
|
|
457
|
+
state.textDeltaForwarded = true;
|
|
458
|
+
state.messageAddedIds.add(id);
|
|
459
|
+
state.messageDoneIds.add(id);
|
|
460
|
+
return [
|
|
461
|
+
{ type: "response.output_item.added", output_index: outputIndex, item: { type: "message", id } },
|
|
462
|
+
{ type: "response.output_text.delta", item_id: id, delta: text },
|
|
463
|
+
{ type: "response.output_item.done", output_index: outputIndex, item: { type: "message", id } }
|
|
464
|
+
];
|
|
465
|
+
}
|
|
466
|
+
function synthesizeFunctionCall(item, outputIndex, state) {
|
|
467
|
+
const entry = resolveFunctionCall(state, {
|
|
468
|
+
itemId: asString(item.id),
|
|
469
|
+
callId: asString(item.call_id),
|
|
470
|
+
outputIndex
|
|
471
|
+
});
|
|
472
|
+
absorbFunctionItem(entry, item, true);
|
|
473
|
+
state.lastFunctionCall = entry;
|
|
474
|
+
state.lastOutputIndex = entry.outputIndex;
|
|
475
|
+
const args = resolveFunctionArgs(entry);
|
|
476
|
+
if (args === void 0) {
|
|
477
|
+
entry.doneSeen = true;
|
|
478
|
+
return [];
|
|
479
|
+
}
|
|
480
|
+
return completeFunctionCall(entry, args);
|
|
481
|
+
}
|
|
482
|
+
function recoverFromCompletedOutput(response, state) {
|
|
483
|
+
const recovered = [];
|
|
484
|
+
if (Array.isArray(response.output)) {
|
|
485
|
+
response.output.forEach((item, index) => {
|
|
486
|
+
if (!isRecord(item) || typeof item.type !== "string") return;
|
|
487
|
+
if (item.type === "message" && !state.textDeltaForwarded) {
|
|
488
|
+
recovered.push(...synthesizeMessage(item, index, state));
|
|
489
|
+
} else if (item.type === "function_call") {
|
|
490
|
+
recovered.push(...synthesizeFunctionCall(item, index, state));
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
for (const entry of state.functionCalls) {
|
|
495
|
+
if (entry.done || !entry.doneSeen) continue;
|
|
496
|
+
recovered.push(normalizeErrorEvent({
|
|
497
|
+
error: {
|
|
498
|
+
type: "invalid_response",
|
|
499
|
+
code: "incomplete_function_call",
|
|
500
|
+
message: `Provider ended the response without arguments for function call "${entry.callId}"${entry.name ? ` (${entry.name})` : ""}.`
|
|
501
|
+
}
|
|
502
|
+
}));
|
|
503
|
+
}
|
|
504
|
+
return recovered;
|
|
505
|
+
}
|
|
506
|
+
function normalizeResponsesLiteEvent(event, state) {
|
|
507
|
+
if (!isRecord(event) || typeof event.type !== "string") return [event];
|
|
508
|
+
if (event.type === "error") return [normalizeErrorEvent(event)];
|
|
509
|
+
if (event.type === "response.output_item.added" && isRecord(event.item)) {
|
|
510
|
+
const outputIndex = typeof event.output_index === "number" ? event.output_index : state.lastOutputIndex;
|
|
511
|
+
state.lastOutputIndex = outputIndex;
|
|
512
|
+
if (event.item.type === "message") {
|
|
513
|
+
const id = asString(event.item.id) ?? nextId(state, "msg");
|
|
514
|
+
state.lastMessageItemId = id;
|
|
515
|
+
state.messageAddedIds.add(id);
|
|
516
|
+
return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];
|
|
517
|
+
}
|
|
518
|
+
if (event.item.type === "function_call") {
|
|
519
|
+
const entry = resolveFunctionCall(state, {
|
|
520
|
+
itemId: asString(event.item.id),
|
|
521
|
+
callId: asString(event.item.call_id),
|
|
522
|
+
outputIndex
|
|
523
|
+
});
|
|
524
|
+
absorbFunctionItem(entry, event.item, false);
|
|
525
|
+
entry.outputIndex = outputIndex;
|
|
526
|
+
entry.added = true;
|
|
527
|
+
state.lastFunctionCall = entry;
|
|
528
|
+
return [{ ...event, output_index: outputIndex, item: functionItemPayload(entry, { arguments: "" }) }];
|
|
529
|
+
}
|
|
530
|
+
return [{ ...event, output_index: outputIndex }];
|
|
531
|
+
}
|
|
532
|
+
if (event.type === "response.output_item.done" && isRecord(event.item)) {
|
|
533
|
+
const outputIndex = typeof event.output_index === "number" ? event.output_index : state.lastOutputIndex;
|
|
534
|
+
if (event.item.type === "function_call") {
|
|
535
|
+
const entry = resolveFunctionCall(state, {
|
|
536
|
+
itemId: asString(event.item.id),
|
|
537
|
+
callId: asString(event.item.call_id),
|
|
538
|
+
outputIndex
|
|
539
|
+
});
|
|
540
|
+
absorbFunctionItem(entry, event.item, true);
|
|
541
|
+
entry.outputIndex = outputIndex;
|
|
542
|
+
entry.doneSeen = true;
|
|
543
|
+
state.lastFunctionCall = entry;
|
|
544
|
+
state.lastOutputIndex = outputIndex;
|
|
545
|
+
const args = resolveFunctionArgs(entry);
|
|
546
|
+
if (args === void 0 || !entry.name) return [];
|
|
547
|
+
if (entry.done) return [];
|
|
548
|
+
const events = [];
|
|
549
|
+
if (!entry.added) events.push(functionAddedEvent(entry));
|
|
550
|
+
events.push({ ...event, output_index: outputIndex, item: functionItemPayload(entry, { arguments: args, status: "completed" }) });
|
|
551
|
+
entry.done = true;
|
|
552
|
+
return events;
|
|
553
|
+
}
|
|
554
|
+
if (event.item.type === "message") {
|
|
555
|
+
const id = asString(event.item.id) ?? state.lastMessageItemId ?? nextId(state, "msg");
|
|
556
|
+
state.lastMessageItemId = id;
|
|
557
|
+
state.messageDoneIds.add(id);
|
|
558
|
+
return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];
|
|
559
|
+
}
|
|
560
|
+
return [{ ...event, output_index: outputIndex }];
|
|
561
|
+
}
|
|
562
|
+
if (event.type === "response.output_text.delta") {
|
|
563
|
+
const itemId = asString(event.item_id) ?? state.lastMessageItemId ?? nextId(state, "msg");
|
|
564
|
+
state.lastMessageItemId = itemId;
|
|
565
|
+
state.textDeltaForwarded = true;
|
|
566
|
+
const events = [];
|
|
567
|
+
if (!state.messageAddedIds.has(itemId)) {
|
|
568
|
+
events.push({
|
|
569
|
+
type: "response.output_item.added",
|
|
570
|
+
output_index: state.lastOutputIndex,
|
|
571
|
+
item: { type: "message", id: itemId }
|
|
572
|
+
});
|
|
573
|
+
state.messageAddedIds.add(itemId);
|
|
574
|
+
}
|
|
575
|
+
events.push({ ...event, item_id: itemId, delta: typeof event.delta === "string" ? event.delta : "" });
|
|
576
|
+
return events;
|
|
577
|
+
}
|
|
578
|
+
if (event.type === "response.function_call_arguments.delta") {
|
|
579
|
+
const entry = resolveFunctionCall(state, {
|
|
580
|
+
itemId: asString(event.item_id),
|
|
581
|
+
outputIndex: typeof event.output_index === "number" ? event.output_index : void 0
|
|
582
|
+
});
|
|
583
|
+
const delta = typeof event.delta === "string" ? event.delta : "";
|
|
584
|
+
entry.args += delta;
|
|
585
|
+
entry.deltaForwarded = true;
|
|
586
|
+
state.lastFunctionCall = entry;
|
|
587
|
+
state.lastOutputIndex = entry.outputIndex;
|
|
588
|
+
return [{ ...event, item_id: entry.itemId, output_index: entry.outputIndex, delta }];
|
|
589
|
+
}
|
|
590
|
+
if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
591
|
+
const response = isRecord(event.response) ? event.response : {};
|
|
592
|
+
const recovered = recoverFromCompletedOutput(response, state);
|
|
593
|
+
if (state.lastMessageItemId && state.textDeltaForwarded && !state.messageDoneIds.has(state.lastMessageItemId)) {
|
|
594
|
+
recovered.push({
|
|
595
|
+
type: "response.output_item.done",
|
|
596
|
+
output_index: state.lastOutputIndex,
|
|
597
|
+
item: { type: "message", id: state.lastMessageItemId }
|
|
598
|
+
});
|
|
599
|
+
state.messageDoneIds.add(state.lastMessageItemId);
|
|
600
|
+
}
|
|
601
|
+
return [...recovered, event];
|
|
602
|
+
}
|
|
603
|
+
return [event];
|
|
604
|
+
}
|
|
292
605
|
function toHeaderRecord(headers) {
|
|
293
606
|
const out = {};
|
|
294
607
|
if (!headers) return out;
|
|
@@ -346,10 +659,14 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
346
659
|
if (hasResponsesLiteHeader(headers)) {
|
|
347
660
|
payload = applyResponsesLiteShape(payload);
|
|
348
661
|
}
|
|
662
|
+
debug(
|
|
663
|
+
`request type=response.create keys=${Object.keys(payload).sort().join(",")} toolCount=${Array.isArray(payload.tools) ? payload.tools.length : 0} store=${String(payload.store)} parallelToolCalls=${String(payload.parallel_tool_calls)} reasoningKeys=${recordKeys(payload.reasoning)}`
|
|
664
|
+
);
|
|
349
665
|
const outgoing = JSON.stringify({ type: "response.create", ...payload });
|
|
350
666
|
const encoder = new TextEncoder();
|
|
351
667
|
let socket;
|
|
352
668
|
let frameCount = 0;
|
|
669
|
+
const normalizeState = createResponsesLiteNormalizeState();
|
|
353
670
|
const stream = new ReadableStream({
|
|
354
671
|
start(controller) {
|
|
355
672
|
let closed = false;
|
|
@@ -367,13 +684,12 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
367
684
|
};
|
|
368
685
|
const fail = (message) => {
|
|
369
686
|
if (closed) return;
|
|
370
|
-
debug(`fail
|
|
687
|
+
debug(`fail messageChars=${message.length}`);
|
|
371
688
|
try {
|
|
372
|
-
|
|
373
|
-
|
|
689
|
+
const [errorEvent] = normalizeResponsesLiteEvent({ type: "error", error: { message } }, normalizeState);
|
|
690
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(errorEvent)}
|
|
374
691
|
|
|
375
|
-
`
|
|
376
|
-
));
|
|
692
|
+
`));
|
|
377
693
|
} catch {
|
|
378
694
|
}
|
|
379
695
|
close();
|
|
@@ -389,28 +705,31 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
389
705
|
socket.on("message", (data) => {
|
|
390
706
|
const text = Array.isArray(data) ? Buffer.concat(data).toString("utf8") : data.toString("utf8");
|
|
391
707
|
frameCount += 1;
|
|
392
|
-
if (frameCount <= 3) debug(`frame#${frameCount}: ${text.slice(0, 200)}`);
|
|
393
708
|
let event;
|
|
394
709
|
try {
|
|
395
710
|
event = JSON.parse(text);
|
|
396
711
|
} catch {
|
|
712
|
+
debug(`frame#${frameCount} non-json chars=${text.length}`);
|
|
397
713
|
controller.enqueue(encoder.encode(`data: ${text.replace(/\r?\n/g, " ")}
|
|
398
714
|
|
|
399
715
|
`));
|
|
400
716
|
return;
|
|
401
717
|
}
|
|
402
|
-
|
|
718
|
+
if (frameCount <= 8) debug(`frame#${frameCount} ${summarizeResponsesLiteEvent(event)}`);
|
|
719
|
+
for (const next of normalizeResponsesLiteEvent(event, normalizeState)) {
|
|
720
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(next)}
|
|
403
721
|
|
|
404
722
|
`));
|
|
405
|
-
|
|
406
|
-
|
|
723
|
+
}
|
|
724
|
+
const type = isRecord(event) && typeof event.type === "string" ? event.type : void 0;
|
|
725
|
+
if (type && TERMINAL_EVENT_TYPES.has(type)) {
|
|
407
726
|
debug(`terminal event: ${type} (after ${frameCount} frames)`);
|
|
408
727
|
close();
|
|
409
728
|
}
|
|
410
729
|
});
|
|
411
730
|
socket.on("error", (err) => fail(err.message));
|
|
412
731
|
socket.on("close", (code, reason) => {
|
|
413
|
-
debug(`close code=${code} frames=${frameCount}${reason?.length ? `
|
|
732
|
+
debug(`close code=${code} frames=${frameCount}${reason?.length ? ` reasonChars=${reason.length}` : ""}`);
|
|
414
733
|
if (closed) return;
|
|
415
734
|
if (code === 1e3 || code === 1005) {
|
|
416
735
|
close();
|
|
@@ -694,10 +1013,11 @@ async function createLanguageModel(spec) {
|
|
|
694
1013
|
return model;
|
|
695
1014
|
}
|
|
696
1015
|
var ANTHROPIC_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
697
|
-
var OPENAI_EFFORT_LEVELS = ["low", "medium", "high"
|
|
1016
|
+
var OPENAI_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
698
1017
|
var GEMINI_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
699
1018
|
var MISTRAL_EFFORT_LEVELS = ["high", "off"];
|
|
700
|
-
var
|
|
1019
|
+
var XAI_CHAT_EFFORT_LEVELS = ["low", "high"];
|
|
1020
|
+
var XAI_RESPONSES_EFFORT_LEVELS = ["low", "medium", "high"];
|
|
701
1021
|
var OPENROUTER_EFFORT_LEVELS = ["none", "minimal", "low", "medium", "high", "xhigh"];
|
|
702
1022
|
var DEEPSEEK_EFFORT_LEVELS = ["high", "max", "off"];
|
|
703
1023
|
var GLM_52_EFFORT_LEVELS = ["high", "xhigh"];
|
|
@@ -709,6 +1029,15 @@ var EMPTY_REASONING = {
|
|
|
709
1029
|
source: "none",
|
|
710
1030
|
confidence: "inferred"
|
|
711
1031
|
};
|
|
1032
|
+
var GEMINI_25_BUDGETS = {
|
|
1033
|
+
low: 1024,
|
|
1034
|
+
medium: 4096,
|
|
1035
|
+
high: 8192,
|
|
1036
|
+
xhigh: 16384,
|
|
1037
|
+
max: 16384,
|
|
1038
|
+
minimal: 512,
|
|
1039
|
+
none: 0
|
|
1040
|
+
};
|
|
712
1041
|
function isClaudeReasoningModel(modelId) {
|
|
713
1042
|
const lower = modelId.toLowerCase();
|
|
714
1043
|
if (!lower.startsWith("claude-")) return false;
|
|
@@ -723,6 +1052,10 @@ function isGeminiReasoningModel(modelId) {
|
|
|
723
1052
|
const lower = modelId.toLowerCase();
|
|
724
1053
|
return lower.startsWith("gemini-2.5-") || lower.startsWith("gemini-3") || lower.startsWith("gemini-3.");
|
|
725
1054
|
}
|
|
1055
|
+
function isGemini3Model(modelId) {
|
|
1056
|
+
const lower = modelId.toLowerCase();
|
|
1057
|
+
return lower.startsWith("gemini-3") || lower.startsWith("gemini-3.");
|
|
1058
|
+
}
|
|
726
1059
|
function isMistralReasoningModel(modelId) {
|
|
727
1060
|
const lower = modelId.toLowerCase();
|
|
728
1061
|
return lower.startsWith("mistral-") || lower.startsWith("magistral-") || lower.startsWith("ministral-") || lower.includes("reasoning");
|
|
@@ -755,6 +1088,9 @@ function isGlm52ReasoningModel(modelId) {
|
|
|
755
1088
|
const lower = modelId.toLowerCase();
|
|
756
1089
|
return lower === "glm-5.2" || lower === "z-ai/glm-5.2" || lower === "zai/glm-5.2" || lower === "zai-org/glm-5.2" || lower === "zai-org/glm5.2" || lower === "glm5.2";
|
|
757
1090
|
}
|
|
1091
|
+
function toCamelCase(str) {
|
|
1092
|
+
return str.replace(/[-_]([a-z])/g, (_, g) => g.toUpperCase());
|
|
1093
|
+
}
|
|
758
1094
|
function hasSupportedParameter(metadata, param) {
|
|
759
1095
|
return (metadata?.supportedParameters ?? []).some((p) => p === param);
|
|
760
1096
|
}
|
|
@@ -790,7 +1126,179 @@ function openRouterReasoningCapabilities(metadata) {
|
|
|
790
1126
|
}
|
|
791
1127
|
return EMPTY_REASONING;
|
|
792
1128
|
}
|
|
1129
|
+
function mapCodexEffortToDeepSeek(effort) {
|
|
1130
|
+
switch (effort) {
|
|
1131
|
+
case "off":
|
|
1132
|
+
case "none":
|
|
1133
|
+
return "off";
|
|
1134
|
+
case "low":
|
|
1135
|
+
case "medium":
|
|
1136
|
+
case "high":
|
|
1137
|
+
return "high";
|
|
1138
|
+
case "xhigh":
|
|
1139
|
+
case "max":
|
|
1140
|
+
return "max";
|
|
1141
|
+
default:
|
|
1142
|
+
if (effort === "high" || effort === "max") return effort;
|
|
1143
|
+
return void 0;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
function deepSeekEffortProviderOptions(effort) {
|
|
1147
|
+
const mapped = mapCodexEffortToDeepSeek(effort);
|
|
1148
|
+
if (!mapped) return void 0;
|
|
1149
|
+
const thinking = { type: mapped === "off" ? "disabled" : "enabled" };
|
|
1150
|
+
const spread = { thinking };
|
|
1151
|
+
if (mapped === "off") {
|
|
1152
|
+
return {
|
|
1153
|
+
deepseek: spread,
|
|
1154
|
+
openaiCompatible: spread
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
return {
|
|
1158
|
+
openaiCompatible: { reasoningEffort: mapped, ...spread },
|
|
1159
|
+
deepseek: spread
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
function mapCodexEffortToAnthropic(effort) {
|
|
1163
|
+
switch (effort) {
|
|
1164
|
+
case "none":
|
|
1165
|
+
case "minimal":
|
|
1166
|
+
case "low":
|
|
1167
|
+
return "low";
|
|
1168
|
+
case "medium":
|
|
1169
|
+
return "medium";
|
|
1170
|
+
case "high":
|
|
1171
|
+
case "xhigh":
|
|
1172
|
+
case "max":
|
|
1173
|
+
return effort === "xhigh" ? "high" : effort === "max" ? "max" : "high";
|
|
1174
|
+
default:
|
|
1175
|
+
if (ANTHROPIC_EFFORT_LEVELS.includes(effort)) {
|
|
1176
|
+
return effort;
|
|
1177
|
+
}
|
|
1178
|
+
return void 0;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
var OPENAI_MODEL_REASONING = {
|
|
1182
|
+
"gpt-5-pro": { levels: ["high"], defaultLevel: "high" },
|
|
1183
|
+
"gpt-5.1": { levels: ["none", "low", "medium", "high"], defaultLevel: "none" },
|
|
1184
|
+
"gpt-5.1-codex-max": { levels: ["low", "medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1185
|
+
"gpt-5.2": { levels: ["none", "low", "medium", "high", "xhigh"], defaultLevel: "none" },
|
|
1186
|
+
"gpt-5.2-codex": { levels: ["low", "medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1187
|
+
"gpt-5.2-pro": { levels: ["medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1188
|
+
"gpt-5.3-codex": { levels: ["low", "medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1189
|
+
"gpt-5.4": { levels: ["none", "low", "medium", "high", "xhigh"], defaultLevel: "none" },
|
|
1190
|
+
"gpt-5.4-mini": { levels: ["none", "low", "medium", "high", "xhigh"], defaultLevel: "none" },
|
|
1191
|
+
"gpt-5.4-nano": { levels: ["none", "low", "medium", "high", "xhigh"], defaultLevel: "none" },
|
|
1192
|
+
"gpt-5.4-pro": { levels: ["medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1193
|
+
"gpt-5.5": { levels: ["none", "low", "medium", "high", "xhigh"], defaultLevel: "medium" },
|
|
1194
|
+
"gpt-5.5-pro": { levels: ["medium", "high", "xhigh"], defaultLevel: "high" },
|
|
1195
|
+
"gpt-5.6": { levels: ["none", "low", "medium", "high", "xhigh", "max"], defaultLevel: "medium" },
|
|
1196
|
+
"gpt-5.6-luna": { levels: ["none", "low", "medium", "high", "xhigh", "max"], defaultLevel: "medium" },
|
|
1197
|
+
"gpt-5.6-sol": { levels: ["none", "low", "medium", "high", "xhigh", "max"], defaultLevel: "medium" },
|
|
1198
|
+
"gpt-5.6-terra": { levels: ["none", "low", "medium", "high", "xhigh", "max"], defaultLevel: "medium" }
|
|
1199
|
+
};
|
|
1200
|
+
var OPENAI_NON_REASONING_MODELS = /* @__PURE__ */ new Set([
|
|
1201
|
+
"chat-latest",
|
|
1202
|
+
"gpt-5-chat-latest",
|
|
1203
|
+
"gpt-5.1-chat-latest",
|
|
1204
|
+
"gpt-5.2-chat-latest",
|
|
1205
|
+
"gpt-5.3-chat-latest"
|
|
1206
|
+
]);
|
|
1207
|
+
var OPENAI_DATED_SNAPSHOT_SUFFIX = /-\d{4}-\d{2}-\d{2}$/;
|
|
1208
|
+
function canonicalOpenAiModelId(modelId, metadata) {
|
|
1209
|
+
return (metadata?.upstreamModelId ?? modelId ?? "").toLowerCase();
|
|
1210
|
+
}
|
|
1211
|
+
function openAiReasoningProfile(modelId, metadata) {
|
|
1212
|
+
const id = canonicalOpenAiModelId(modelId, metadata);
|
|
1213
|
+
if (!id) return void 0;
|
|
1214
|
+
return OPENAI_MODEL_REASONING[id] ?? OPENAI_MODEL_REASONING[id.replace(OPENAI_DATED_SNAPSHOT_SUFFIX, "")];
|
|
1215
|
+
}
|
|
1216
|
+
function openAiModelReasons(modelId, metadata) {
|
|
1217
|
+
const id = canonicalOpenAiModelId(modelId, metadata);
|
|
1218
|
+
if (OPENAI_NON_REASONING_MODELS.has(id.replace(OPENAI_DATED_SNAPSHOT_SUFFIX, ""))) return false;
|
|
1219
|
+
return !!openAiReasoningProfile(modelId, metadata) || modelPrefersResponsesApi(id) || !!metadata?.reasoning;
|
|
1220
|
+
}
|
|
1221
|
+
function mapCodexEffortToOpenAI(effort, allowed) {
|
|
1222
|
+
return allowed.includes(effort) ? effort : void 0;
|
|
1223
|
+
}
|
|
1224
|
+
function mapCodexEffortToOpenAICompatible(effort) {
|
|
1225
|
+
if (effort === "xhigh") return "high";
|
|
1226
|
+
const allowed = ["low", "medium", "high"];
|
|
1227
|
+
return allowed.includes(effort) ? effort : void 0;
|
|
1228
|
+
}
|
|
1229
|
+
function mapCodexEffortToGlm52(effort) {
|
|
1230
|
+
switch (effort) {
|
|
1231
|
+
case "high":
|
|
1232
|
+
return "high";
|
|
1233
|
+
case "xhigh":
|
|
1234
|
+
case "max":
|
|
1235
|
+
return "max";
|
|
1236
|
+
default:
|
|
1237
|
+
return void 0;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
function mapCodexEffortToXai(effort, supportsMedium) {
|
|
1241
|
+
switch (effort) {
|
|
1242
|
+
case "low":
|
|
1243
|
+
return "low";
|
|
1244
|
+
case "medium":
|
|
1245
|
+
return supportsMedium ? "medium" : void 0;
|
|
1246
|
+
case "high":
|
|
1247
|
+
case "xhigh":
|
|
1248
|
+
case "max":
|
|
1249
|
+
return "high";
|
|
1250
|
+
default:
|
|
1251
|
+
return void 0;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
function mapCodexEffortToGeminiLevel(effort) {
|
|
1255
|
+
switch (effort) {
|
|
1256
|
+
case "none":
|
|
1257
|
+
case "minimal":
|
|
1258
|
+
case "low":
|
|
1259
|
+
return "low";
|
|
1260
|
+
case "medium":
|
|
1261
|
+
return "medium";
|
|
1262
|
+
case "high":
|
|
1263
|
+
case "xhigh":
|
|
1264
|
+
case "max":
|
|
1265
|
+
return "high";
|
|
1266
|
+
default:
|
|
1267
|
+
return GEMINI_EFFORT_LEVELS.includes(effort) ? effort : void 0;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
function mapCodexEffortToGeminiBudget(effort) {
|
|
1271
|
+
const direct = GEMINI_25_BUDGETS[effort];
|
|
1272
|
+
if (direct !== void 0) return direct > 0 ? direct : void 0;
|
|
1273
|
+
const level = mapCodexEffortToGeminiLevel(effort);
|
|
1274
|
+
if (!level) return void 0;
|
|
1275
|
+
return GEMINI_25_BUDGETS[level];
|
|
1276
|
+
}
|
|
1277
|
+
function withMappableLevels(caps, npm, modelId, metadata) {
|
|
1278
|
+
if (caps.mode !== "controllable") return caps;
|
|
1279
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1280
|
+
const levels = caps.levels.filter((level) => {
|
|
1281
|
+
const mapped = effortProviderOptions(npm, level, modelId, metadata);
|
|
1282
|
+
if (mapped === void 0) return false;
|
|
1283
|
+
const wire = JSON.stringify(mapped);
|
|
1284
|
+
if (seen.has(wire)) return false;
|
|
1285
|
+
seen.add(wire);
|
|
1286
|
+
return true;
|
|
1287
|
+
});
|
|
1288
|
+
if (levels.length === caps.levels.length) return caps;
|
|
1289
|
+
if (levels.length === 0) {
|
|
1290
|
+
return { ...caps, levels: [], defaultLevel: "", mode: "internal-only" };
|
|
1291
|
+
}
|
|
1292
|
+
return {
|
|
1293
|
+
...caps,
|
|
1294
|
+
levels,
|
|
1295
|
+
defaultLevel: levels.includes(caps.defaultLevel) ? caps.defaultLevel : levels[levels.length - 1]
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
793
1298
|
function getReasoningCapabilities(npm, modelId, metadata) {
|
|
1299
|
+
return withMappableLevels(resolveRawReasoningCapabilities(npm, modelId, metadata), npm, modelId, metadata);
|
|
1300
|
+
}
|
|
1301
|
+
function resolveRawReasoningCapabilities(npm, modelId, metadata) {
|
|
794
1302
|
const id = modelId.toLowerCase();
|
|
795
1303
|
if (isOpenRouterRoute(npm, metadata)) {
|
|
796
1304
|
return openRouterReasoningCapabilities(metadata);
|
|
@@ -811,15 +1319,18 @@ function getReasoningCapabilities(npm, modelId, metadata) {
|
|
|
811
1319
|
return EMPTY_REASONING;
|
|
812
1320
|
}
|
|
813
1321
|
if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure") {
|
|
814
|
-
const
|
|
815
|
-
|
|
1322
|
+
const canonicalId = canonicalOpenAiModelId(modelId, metadata);
|
|
1323
|
+
const profile = openAiReasoningProfile(modelId, metadata);
|
|
1324
|
+
const prefersResponses = modelPrefersResponsesApi(canonicalId);
|
|
1325
|
+
if (openAiModelReasons(modelId, metadata) && shouldUseOpenAiResponsesEndpoint(canonicalId)) {
|
|
1326
|
+
const levels = profile?.levels ?? [...OPENAI_EFFORT_LEVELS];
|
|
816
1327
|
return {
|
|
817
|
-
levels: [...
|
|
818
|
-
defaultLevel: "medium",
|
|
1328
|
+
levels: [...levels],
|
|
1329
|
+
defaultLevel: profile?.defaultLevel ?? (levels.includes("medium") ? "medium" : levels[levels.length - 1]),
|
|
819
1330
|
supportsSummaries: true,
|
|
1331
|
+
source: profile || prefersResponses ? "provider-rule" : "model-metadata",
|
|
1332
|
+
confidence: profile || prefersResponses ? "documented" : "inferred",
|
|
820
1333
|
mode: "controllable",
|
|
821
|
-
source: prefersResponses ? "provider-rule" : "model-metadata",
|
|
822
|
-
confidence: prefersResponses ? "documented" : "inferred",
|
|
823
1334
|
wireFormat: { kind: "openai-reasoning-effort" }
|
|
824
1335
|
};
|
|
825
1336
|
}
|
|
@@ -855,7 +1366,7 @@ function getReasoningCapabilities(npm, modelId, metadata) {
|
|
|
855
1366
|
}
|
|
856
1367
|
if (npm === "@ai-sdk/xai") {
|
|
857
1368
|
if (isXaiReasoningEffortModel(modelId)) {
|
|
858
|
-
const levels = modelPrefersResponsesApi(modelId) ? [
|
|
1369
|
+
const levels = modelPrefersResponsesApi(modelId) ? [...XAI_RESPONSES_EFFORT_LEVELS] : [...XAI_CHAT_EFFORT_LEVELS];
|
|
859
1370
|
return {
|
|
860
1371
|
levels,
|
|
861
1372
|
defaultLevel: xaiDefaultReasoningEffort(modelId),
|
|
@@ -936,6 +1447,91 @@ function getReasoningCapabilities(npm, modelId, metadata) {
|
|
|
936
1447
|
}
|
|
937
1448
|
return EMPTY_REASONING;
|
|
938
1449
|
}
|
|
1450
|
+
function effortProviderOptions(npm, effort, modelId, metadata) {
|
|
1451
|
+
if (!effort) return void 0;
|
|
1452
|
+
if (isOpenRouterRoute(npm, metadata)) {
|
|
1453
|
+
const caps = openRouterReasoningCapabilities(metadata);
|
|
1454
|
+
if (caps.mode !== "controllable") return void 0;
|
|
1455
|
+
const allowed = new Set(OPENROUTER_EFFORT_LEVELS);
|
|
1456
|
+
const mapped = allowed.has(effort) ? effort : effort === "max" ? "xhigh" : void 0;
|
|
1457
|
+
return mapped ? { openrouter: { reasoning: { effort: mapped, exclude: false } } } : void 0;
|
|
1458
|
+
}
|
|
1459
|
+
if (npm === "@ai-sdk/openai" || npm === "@ai-sdk/azure") {
|
|
1460
|
+
if (!modelId || !shouldUseOpenAiResponsesEndpoint(canonicalOpenAiModelId(modelId, metadata))) return void 0;
|
|
1461
|
+
if (!openAiModelReasons(modelId, metadata)) return void 0;
|
|
1462
|
+
const allowed = openAiReasoningProfile(modelId, metadata)?.levels ?? OPENAI_EFFORT_LEVELS;
|
|
1463
|
+
const reasoningEffort = mapCodexEffortToOpenAI(effort, allowed);
|
|
1464
|
+
return reasoningEffort ? { openai: { reasoningEffort } } : void 0;
|
|
1465
|
+
}
|
|
1466
|
+
if (npm === "@ai-sdk/xai") {
|
|
1467
|
+
if (!modelId || !isXaiReasoningEffortModel(modelId)) return void 0;
|
|
1468
|
+
const reasoningEffort = mapCodexEffortToXai(effort, modelPrefersResponsesApi(modelId));
|
|
1469
|
+
return reasoningEffort ? { xai: { reasoningEffort } } : void 0;
|
|
1470
|
+
}
|
|
1471
|
+
if (npm === "@ai-sdk/anthropic" || npm === VERTEX_ANTHROPIC_NPM) {
|
|
1472
|
+
if (!modelId || !isClaudeReasoningModel(modelId)) return void 0;
|
|
1473
|
+
const mapped = mapCodexEffortToAnthropic(effort);
|
|
1474
|
+
return mapped ? { anthropic: { thinking: { type: "adaptive", effort: mapped } } } : void 0;
|
|
1475
|
+
}
|
|
1476
|
+
if (npm === "@ai-sdk/google") {
|
|
1477
|
+
const id = modelId ?? "";
|
|
1478
|
+
if (isGemini3Model(id)) {
|
|
1479
|
+
const thinkingLevel = mapCodexEffortToGeminiLevel(effort);
|
|
1480
|
+
return thinkingLevel ? { google: { thinkingConfig: { thinkingLevel, includeThoughts: true } } } : void 0;
|
|
1481
|
+
}
|
|
1482
|
+
const thinkingBudget = mapCodexEffortToGeminiBudget(effort);
|
|
1483
|
+
return thinkingBudget ? { google: { thinkingConfig: { thinkingBudget, includeThoughts: true } } } : void 0;
|
|
1484
|
+
}
|
|
1485
|
+
if (npm === "@ai-sdk/mistral") {
|
|
1486
|
+
if (!modelId || !isMistralReasoningModel(modelId)) return void 0;
|
|
1487
|
+
const reasoningEffort = effort === "off" || effort === "none" ? "none" : "high";
|
|
1488
|
+
return { mistral: { reasoningEffort } };
|
|
1489
|
+
}
|
|
1490
|
+
if (npm === "@ai-sdk/openai-compatible" || npm === "@ai-sdk/openai") {
|
|
1491
|
+
if (!modelId) return void 0;
|
|
1492
|
+
if (isDeepSeekReasoningModel(modelId)) {
|
|
1493
|
+
return deepSeekEffortProviderOptions(effort);
|
|
1494
|
+
}
|
|
1495
|
+
if (isKimiReasoningModel(modelId)) {
|
|
1496
|
+
const reasoningEffort = mapCodexEffortToOpenAICompatible(effort);
|
|
1497
|
+
if (reasoningEffort) {
|
|
1498
|
+
const key = metadata?.providerId ? toCamelCase(metadata.providerId) : "openaiCompatible";
|
|
1499
|
+
return { [key]: { reasoningEffort } };
|
|
1500
|
+
}
|
|
1501
|
+
return void 0;
|
|
1502
|
+
}
|
|
1503
|
+
if (isGlm52ReasoningModel(modelId)) {
|
|
1504
|
+
const reasoningEffort = mapCodexEffortToGlm52(effort);
|
|
1505
|
+
if (reasoningEffort) {
|
|
1506
|
+
const key = metadata?.providerId ? toCamelCase(metadata.providerId) : "openaiCompatible";
|
|
1507
|
+
return { [key]: { reasoningEffort } };
|
|
1508
|
+
}
|
|
1509
|
+
return void 0;
|
|
1510
|
+
}
|
|
1511
|
+
if (hasSupportedParameter(metadata, "reasoning_effort")) {
|
|
1512
|
+
const reasoningEffort = mapCodexEffortToOpenAICompatible(effort);
|
|
1513
|
+
return reasoningEffort ? { openai: { reasoningEffort }, openaiCompatible: { reasoningEffort } } : void 0;
|
|
1514
|
+
}
|
|
1515
|
+
if (hasSupportedParameter(metadata, "reasoning")) {
|
|
1516
|
+
const allowed = new Set(OPENROUTER_EFFORT_LEVELS);
|
|
1517
|
+
const mapped = allowed.has(effort) ? effort : effort === "max" ? "xhigh" : void 0;
|
|
1518
|
+
return mapped ? { openrouter: { reasoning: { effort: mapped, exclude: false } } } : void 0;
|
|
1519
|
+
}
|
|
1520
|
+
return void 0;
|
|
1521
|
+
}
|
|
1522
|
+
return void 0;
|
|
1523
|
+
}
|
|
1524
|
+
function deepMergeProviderOptions(a, b) {
|
|
1525
|
+
if (!a && !b) return void 0;
|
|
1526
|
+
if (!a) return b;
|
|
1527
|
+
if (!b) return a;
|
|
1528
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
1529
|
+
const out = {};
|
|
1530
|
+
for (const key of keys) {
|
|
1531
|
+
out[key] = { ...a[key] ?? {}, ...b[key] ?? {} };
|
|
1532
|
+
}
|
|
1533
|
+
return out;
|
|
1534
|
+
}
|
|
939
1535
|
|
|
940
1536
|
// src/registry/io.ts
|
|
941
1537
|
import {
|
|
@@ -1151,6 +1747,7 @@ var DEFAULT_RETRYABLE = {
|
|
|
1151
1747
|
CREDENTIAL_UNAVAILABLE: false,
|
|
1152
1748
|
OAUTH_REFRESH_FAILED: true,
|
|
1153
1749
|
UNSUPPORTED_MODEL: false,
|
|
1750
|
+
UNSUPPORTED_REASONING_LEVEL: false,
|
|
1154
1751
|
UNSUPPORTED_REGISTRY_VERSION: false,
|
|
1155
1752
|
PROVIDER_LOAD_FAILED: true
|
|
1156
1753
|
};
|
|
@@ -1182,6 +1779,80 @@ function isRelayCoreError(err) {
|
|
|
1182
1779
|
return err instanceof RelayCoreError;
|
|
1183
1780
|
}
|
|
1184
1781
|
|
|
1782
|
+
// src/core/reasoning.ts
|
|
1783
|
+
var RELAY_REASONING_LEVELS = [
|
|
1784
|
+
"off",
|
|
1785
|
+
"none",
|
|
1786
|
+
"minimal",
|
|
1787
|
+
"low",
|
|
1788
|
+
"medium",
|
|
1789
|
+
"high",
|
|
1790
|
+
"xhigh",
|
|
1791
|
+
"max"
|
|
1792
|
+
];
|
|
1793
|
+
function isRelayReasoningLevel(value) {
|
|
1794
|
+
return typeof value === "string" && RELAY_REASONING_LEVELS.includes(value);
|
|
1795
|
+
}
|
|
1796
|
+
function reasoningNpmForRoute(provider, model) {
|
|
1797
|
+
if (model.modelFormat === "cloud-code") return "@ai-sdk/google";
|
|
1798
|
+
return model.npm ?? provider.api.npm ?? "";
|
|
1799
|
+
}
|
|
1800
|
+
function resolveReasoningProviderOptions(level, provider, model, routeId) {
|
|
1801
|
+
if (!isRelayReasoningLevel(level)) {
|
|
1802
|
+
throw new RelayCoreError(
|
|
1803
|
+
"UNSUPPORTED_REASONING_LEVEL",
|
|
1804
|
+
`Unknown reasoning level "${String(level)}" \u2014 expected one of: ${RELAY_REASONING_LEVELS.join(", ")}.`,
|
|
1805
|
+
{ providerId: provider.id, routeId }
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
const npm = reasoningNpmForRoute(provider, model);
|
|
1809
|
+
const upstreamModelId = model.upstreamModelId ?? model.id;
|
|
1810
|
+
const metadata = {
|
|
1811
|
+
providerId: provider.id,
|
|
1812
|
+
upstreamModelId,
|
|
1813
|
+
...model.apiUrl ?? provider.api.url ? { apiBaseUrl: model.apiUrl ?? provider.api.url } : {},
|
|
1814
|
+
...model.supportedParameters ? { supportedParameters: model.supportedParameters } : {},
|
|
1815
|
+
...model.reasoning !== void 0 ? { reasoning: model.reasoning } : {},
|
|
1816
|
+
...model.interleavedReasoningField ? { interleavedReasoningField: model.interleavedReasoningField } : {}
|
|
1817
|
+
};
|
|
1818
|
+
const caps = getReasoningCapabilities(npm, upstreamModelId, metadata);
|
|
1819
|
+
if (caps.mode !== "controllable" || !caps.levels.includes(level)) {
|
|
1820
|
+
const available = caps.levels.length > 0 ? caps.levels.join(", ") : "none";
|
|
1821
|
+
throw new RelayCoreError(
|
|
1822
|
+
"UNSUPPORTED_REASONING_LEVEL",
|
|
1823
|
+
`Model "${model.id}" on provider "${provider.name}" does not support reasoning level "${level}" \u2014 available levels: ${available}. See capabilities.reasoningLevels from listRelayModels().`,
|
|
1824
|
+
{ providerId: provider.id, routeId }
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
const resolved = effortProviderOptions(npm, level, upstreamModelId, metadata);
|
|
1828
|
+
if (!resolved) {
|
|
1829
|
+
throw new RelayCoreError(
|
|
1830
|
+
"UNSUPPORTED_REASONING_LEVEL",
|
|
1831
|
+
`Model "${model.id}" on provider "${provider.name}" advertises reasoning level "${level}" but Relay has no request mapping for it \u2014 this is a relay-ai bug, please report it.`,
|
|
1832
|
+
{ providerId: provider.id, routeId }
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
return resolved;
|
|
1836
|
+
}
|
|
1837
|
+
async function withReasoningProviderOptions(model, providerOptions) {
|
|
1838
|
+
const { wrapLanguageModel: wrapLanguageModel2 } = await import("ai");
|
|
1839
|
+
return wrapLanguageModel2({
|
|
1840
|
+
// `LanguageModel` also admits a bare model-id string and the legacy v2
|
|
1841
|
+
// interface; everything Core builds is a concrete current-spec model.
|
|
1842
|
+
model,
|
|
1843
|
+
middleware: {
|
|
1844
|
+
specificationVersion: "v3",
|
|
1845
|
+
transformParams: async ({ params }) => ({
|
|
1846
|
+
...params,
|
|
1847
|
+
providerOptions: deepMergeProviderOptions(
|
|
1848
|
+
providerOptions,
|
|
1849
|
+
params.providerOptions
|
|
1850
|
+
)
|
|
1851
|
+
})
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1185
1856
|
// src/core/route-id.ts
|
|
1186
1857
|
var SEPARATOR = "::";
|
|
1187
1858
|
function toRelayRouteId(providerId, modelId) {
|
|
@@ -1219,7 +1890,7 @@ function loadCoreRegistry(path) {
|
|
|
1219
1890
|
}
|
|
1220
1891
|
function mapReasoning(provider, model) {
|
|
1221
1892
|
const base = { tools: "unknown", vision: "unknown" };
|
|
1222
|
-
const npm =
|
|
1893
|
+
const npm = reasoningNpmForRoute(provider, model);
|
|
1223
1894
|
const upstreamModelId = model.upstreamModelId ?? model.id;
|
|
1224
1895
|
try {
|
|
1225
1896
|
const caps = getReasoningCapabilities(npm, upstreamModelId, {
|
|
@@ -1235,13 +1906,16 @@ function mapReasoning(provider, model) {
|
|
|
1235
1906
|
return { ...base, reasoning: "none" };
|
|
1236
1907
|
case "internal-only":
|
|
1237
1908
|
return { ...base, reasoning: "fixed" };
|
|
1238
|
-
case "controllable":
|
|
1909
|
+
case "controllable": {
|
|
1910
|
+
const levels = caps.levels.filter(isRelayReasoningLevel);
|
|
1911
|
+
if (levels.length === 0) return { ...base, reasoning: "fixed" };
|
|
1239
1912
|
return {
|
|
1240
1913
|
...base,
|
|
1241
1914
|
reasoning: "adjustable",
|
|
1242
|
-
reasoningLevels:
|
|
1243
|
-
defaultReasoningLevel: caps.defaultLevel
|
|
1915
|
+
reasoningLevels: levels,
|
|
1916
|
+
...isRelayReasoningLevel(caps.defaultLevel) ? { defaultReasoningLevel: caps.defaultLevel } : {}
|
|
1244
1917
|
};
|
|
1918
|
+
}
|
|
1245
1919
|
default:
|
|
1246
1920
|
return { ...base, reasoning: "unknown" };
|
|
1247
1921
|
}
|
|
@@ -1513,6 +2187,12 @@ var SCOPES = [
|
|
|
1513
2187
|
].join(" ");
|
|
1514
2188
|
var ANTIGRAVITY_VERSION = "4.2.0";
|
|
1515
2189
|
var ANTIGRAVITY_USER_AGENT = `vscode/1.X.X (Antigravity/${ANTIGRAVITY_VERSION})`;
|
|
2190
|
+
var ANTIGRAVITY_BASE_URLS = [
|
|
2191
|
+
"https://daily-cloudcode-pa.googleapis.com",
|
|
2192
|
+
"https://cloudcode-pa.googleapis.com",
|
|
2193
|
+
"https://daily-cloudcode-pa.sandbox.googleapis.com"
|
|
2194
|
+
];
|
|
2195
|
+
var ANTIGRAVITY_API_VERSION = "v1internal";
|
|
1516
2196
|
async function refreshAntigravityToken(refreshToken) {
|
|
1517
2197
|
return postOAuthRefresh(
|
|
1518
2198
|
TOKEN_URL3,
|
|
@@ -2401,7 +3081,244 @@ function providerRefreshToken(providerId, authType, authRef) {
|
|
|
2401
3081
|
return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));
|
|
2402
3082
|
}
|
|
2403
3083
|
|
|
3084
|
+
// src/core/antigravity-model.ts
|
|
3085
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3086
|
+
var CLOUD_CODE_BASES = ANTIGRAVITY_BASE_URLS.map((base) => base.replace(/\/+$/, ""));
|
|
3087
|
+
var CLOUD_CODE_BASE = CLOUD_CODE_BASES[0];
|
|
3088
|
+
var STREAM_URLS = CLOUD_CODE_BASES.map((base) => `${base}/${ANTIGRAVITY_API_VERSION}:streamGenerateContent?alt=sse`);
|
|
3089
|
+
var UNARY_URLS = CLOUD_CODE_BASES.map((base) => `${base}/${ANTIGRAVITY_API_VERSION}:generateContent`);
|
|
3090
|
+
var SDK_BASE_URL = `${CLOUD_CODE_BASE}/v1beta`;
|
|
3091
|
+
var ENDPOINT_FAILOVER_STATUSES = /* @__PURE__ */ new Set([404, 408, 429]);
|
|
3092
|
+
function shouldTryNextEndpoint(status) {
|
|
3093
|
+
return ENDPOINT_FAILOVER_STATUSES.has(status) || status >= 500;
|
|
3094
|
+
}
|
|
3095
|
+
function discardResponse(response) {
|
|
3096
|
+
try {
|
|
3097
|
+
void response.body?.cancel();
|
|
3098
|
+
} catch {
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
function unwrapCloudCodeSsePayload(payload) {
|
|
3102
|
+
const trimmed = payload.trim();
|
|
3103
|
+
if (trimmed === "" || trimmed === "[DONE]") return payload;
|
|
3104
|
+
try {
|
|
3105
|
+
const parsed = JSON.parse(trimmed);
|
|
3106
|
+
if (isWrappedCloudCodeBody(parsed)) {
|
|
3107
|
+
return JSON.stringify(parsed.response);
|
|
3108
|
+
}
|
|
3109
|
+
} catch {
|
|
3110
|
+
}
|
|
3111
|
+
return payload;
|
|
3112
|
+
}
|
|
3113
|
+
function unwrapCloudCodeJsonBody(text) {
|
|
3114
|
+
try {
|
|
3115
|
+
const parsed = JSON.parse(text);
|
|
3116
|
+
if (isWrappedCloudCodeBody(parsed)) {
|
|
3117
|
+
return JSON.stringify(parsed.response);
|
|
3118
|
+
}
|
|
3119
|
+
} catch {
|
|
3120
|
+
}
|
|
3121
|
+
return text;
|
|
3122
|
+
}
|
|
3123
|
+
function consumeCloudCodeSseBuffer(buffer) {
|
|
3124
|
+
const separator = /\r?\n\r?\n/;
|
|
3125
|
+
let rest = buffer;
|
|
3126
|
+
let emitted = "";
|
|
3127
|
+
while (true) {
|
|
3128
|
+
const match = separator.exec(rest);
|
|
3129
|
+
if (!match || match.index === void 0) break;
|
|
3130
|
+
const rawEvent = rest.slice(0, match.index);
|
|
3131
|
+
const sep = match[0];
|
|
3132
|
+
rest = rest.slice(match.index + sep.length);
|
|
3133
|
+
emitted += transformSseEvent(rawEvent) + sep;
|
|
3134
|
+
}
|
|
3135
|
+
return { emitted, rest };
|
|
3136
|
+
}
|
|
3137
|
+
function createCloudCodeSseUnwrapper() {
|
|
3138
|
+
const decoder = new TextDecoder();
|
|
3139
|
+
const encoder = new TextEncoder();
|
|
3140
|
+
let pending = "";
|
|
3141
|
+
return new TransformStream({
|
|
3142
|
+
transform(chunk, controller) {
|
|
3143
|
+
pending += decoder.decode(chunk, { stream: true });
|
|
3144
|
+
const { emitted, rest } = consumeCloudCodeSseBuffer(pending);
|
|
3145
|
+
pending = rest;
|
|
3146
|
+
if (emitted) controller.enqueue(encoder.encode(emitted));
|
|
3147
|
+
},
|
|
3148
|
+
flush(controller) {
|
|
3149
|
+
pending += decoder.decode();
|
|
3150
|
+
if (!pending) return;
|
|
3151
|
+
const { emitted, rest } = consumeCloudCodeSseBuffer(pending);
|
|
3152
|
+
const tail = emitted + (rest ? transformSseEvent(rest) : "");
|
|
3153
|
+
if (tail) controller.enqueue(encoder.encode(tail));
|
|
3154
|
+
}
|
|
3155
|
+
});
|
|
3156
|
+
}
|
|
3157
|
+
function createCloudCodeFetch(options, fetchImpl) {
|
|
3158
|
+
let accessToken = options.accessToken;
|
|
3159
|
+
const debug = (msg) => {
|
|
3160
|
+
try {
|
|
3161
|
+
options.onDebug?.(`cloud-code: ${msg}`);
|
|
3162
|
+
} catch {
|
|
3163
|
+
}
|
|
3164
|
+
};
|
|
3165
|
+
return async (input, init) => {
|
|
3166
|
+
const url = requestUrl(input);
|
|
3167
|
+
const streaming = url.includes("streamGenerateContent");
|
|
3168
|
+
const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
|
|
3169
|
+
const geminiBody = await readJsonBody(input, init);
|
|
3170
|
+
const envelope = {
|
|
3171
|
+
project: options.projectId,
|
|
3172
|
+
requestId: randomUUID2(),
|
|
3173
|
+
model: options.modelId,
|
|
3174
|
+
userAgent: ANTIGRAVITY_USER_AGENT,
|
|
3175
|
+
requestType: "agent",
|
|
3176
|
+
enabledCreditTypes: ["GOOGLE_ONE_AI"],
|
|
3177
|
+
request: geminiBody
|
|
3178
|
+
};
|
|
3179
|
+
const body = JSON.stringify(envelope);
|
|
3180
|
+
const bodyByteLength = Buffer.byteLength(body, "utf8");
|
|
3181
|
+
const upstreamUrls = streaming ? STREAM_URLS : UNARY_URLS;
|
|
3182
|
+
const doFetch = fetchImpl ?? ((input2, init2) => globalThis.fetch(input2, init2));
|
|
3183
|
+
const send = async (url2, token) => {
|
|
3184
|
+
try {
|
|
3185
|
+
return await doFetch(url2, {
|
|
3186
|
+
method: "POST",
|
|
3187
|
+
headers: {
|
|
3188
|
+
"Content-Type": "application/json",
|
|
3189
|
+
Authorization: `Bearer ${token}`,
|
|
3190
|
+
"User-Agent": ANTIGRAVITY_USER_AGENT
|
|
3191
|
+
},
|
|
3192
|
+
body,
|
|
3193
|
+
signal
|
|
3194
|
+
});
|
|
3195
|
+
} catch (err) {
|
|
3196
|
+
if (isAbortError(err, signal)) throw abortError(signal, err);
|
|
3197
|
+
throw err;
|
|
3198
|
+
}
|
|
3199
|
+
};
|
|
3200
|
+
const sendWithFailover = async (token, startIndex = 0) => {
|
|
3201
|
+
let lastError;
|
|
3202
|
+
for (let i = startIndex; i < upstreamUrls.length; i += 1) {
|
|
3203
|
+
const url2 = upstreamUrls[i];
|
|
3204
|
+
const isLast = i === upstreamUrls.length - 1;
|
|
3205
|
+
const where = `endpoint=${i + 1}/${upstreamUrls.length} host=${endpointHost(url2)}`;
|
|
3206
|
+
let response2;
|
|
3207
|
+
try {
|
|
3208
|
+
debug(`request ${where} kind=${streaming ? "stream" : "unary"} payloadBytes=${bodyByteLength}`);
|
|
3209
|
+
response2 = await send(url2, token);
|
|
3210
|
+
} catch (err) {
|
|
3211
|
+
if (isAbortError(err, signal)) throw err;
|
|
3212
|
+
lastError = err;
|
|
3213
|
+
debug(`network failure ${where} errorName=${errorName(err)}`);
|
|
3214
|
+
}
|
|
3215
|
+
if (response2) {
|
|
3216
|
+
if (isLast || !shouldTryNextEndpoint(response2.status)) {
|
|
3217
|
+
debug(`response ${where} status=${response2.status}`);
|
|
3218
|
+
return { response: response2, url: url2, index: i };
|
|
3219
|
+
}
|
|
3220
|
+
discardResponse(response2);
|
|
3221
|
+
lastError = new Error(`Cloud Code Assist endpoint returned ${response2.status}`);
|
|
3222
|
+
debug(`retryable status=${response2.status} ${where} \u2014 trying next endpoint`);
|
|
3223
|
+
}
|
|
3224
|
+
if (signal?.aborted) throw abortError(signal);
|
|
3225
|
+
}
|
|
3226
|
+
throw lastError ?? new Error("All Cloud Code Assist endpoints failed");
|
|
3227
|
+
};
|
|
3228
|
+
const tokenUsed = accessToken;
|
|
3229
|
+
let { response, index: servedByIndex } = await sendWithFailover(tokenUsed);
|
|
3230
|
+
if (response.status === 401 && options.refreshToken && !signal?.aborted) {
|
|
3231
|
+
debug("status=401 \u2014 refreshing credential");
|
|
3232
|
+
const refreshed = await options.refreshToken().catch(() => null);
|
|
3233
|
+
if (refreshed && refreshed !== tokenUsed && !signal?.aborted) {
|
|
3234
|
+
accessToken = refreshed;
|
|
3235
|
+
discardResponse(response);
|
|
3236
|
+
({ response } = await sendWithFailover(refreshed, servedByIndex));
|
|
3237
|
+
debug(`retry after refresh status=${response.status}`);
|
|
3238
|
+
} else {
|
|
3239
|
+
debug(`refresh did not yield a new credential (refreshed=${refreshed ? "same" : "none"})`);
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
return adaptUpstreamResponse(response, streaming);
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
async function createAntigravityCloudCodeModel(options) {
|
|
3246
|
+
const { createGoogleGenerativeAI } = await import("@ai-sdk/google");
|
|
3247
|
+
const google = createGoogleGenerativeAI({
|
|
3248
|
+
apiKey: "relay-cloud-code",
|
|
3249
|
+
baseURL: SDK_BASE_URL,
|
|
3250
|
+
fetch: createCloudCodeFetch(options)
|
|
3251
|
+
});
|
|
3252
|
+
return google(options.modelId);
|
|
3253
|
+
}
|
|
3254
|
+
function endpointHost(url) {
|
|
3255
|
+
try {
|
|
3256
|
+
return new URL(url).host;
|
|
3257
|
+
} catch {
|
|
3258
|
+
return "unknown";
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
function errorName(err) {
|
|
3262
|
+
if (err instanceof Error) return err.name || "Error";
|
|
3263
|
+
return typeof err;
|
|
3264
|
+
}
|
|
3265
|
+
function isWrappedCloudCodeBody(parsed) {
|
|
3266
|
+
return !!parsed && typeof parsed === "object" && !Array.isArray(parsed) && "response" in parsed && parsed.response !== null && typeof parsed.response === "object";
|
|
3267
|
+
}
|
|
3268
|
+
function transformSseEvent(event) {
|
|
3269
|
+
return event.replace(/^(data:[ \t]*)(.*)$/gm, (_all, prefix, payload) => `${prefix}${unwrapCloudCodeSsePayload(payload)}`);
|
|
3270
|
+
}
|
|
3271
|
+
function requestUrl(input) {
|
|
3272
|
+
if (typeof input === "string") return input;
|
|
3273
|
+
if (input instanceof URL) return input.href;
|
|
3274
|
+
return input.url;
|
|
3275
|
+
}
|
|
3276
|
+
async function readJsonBody(input, init) {
|
|
3277
|
+
const body = init?.body;
|
|
3278
|
+
if (typeof body === "string") return JSON.parse(body);
|
|
3279
|
+
if (body instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(body));
|
|
3280
|
+
if (body instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(body));
|
|
3281
|
+
const request = input instanceof Request ? input.clone() : new Request(input, init);
|
|
3282
|
+
return request.json();
|
|
3283
|
+
}
|
|
3284
|
+
async function adaptUpstreamResponse(upstream, streaming) {
|
|
3285
|
+
const fallbackType = streaming ? "text/event-stream" : "application/json";
|
|
3286
|
+
const contentType = upstream.headers.get("content-type") ?? fallbackType;
|
|
3287
|
+
const headers = new Headers({ "Content-Type": contentType });
|
|
3288
|
+
if (!upstream.ok) {
|
|
3289
|
+
const errBody = await upstream.text();
|
|
3290
|
+
return new Response(errBody, {
|
|
3291
|
+
status: upstream.status,
|
|
3292
|
+
statusText: upstream.statusText,
|
|
3293
|
+
headers
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
if (streaming) {
|
|
3297
|
+
const body = upstream.body ? upstream.body.pipeThrough(createCloudCodeSseUnwrapper()) : null;
|
|
3298
|
+
return new Response(body, {
|
|
3299
|
+
status: upstream.status,
|
|
3300
|
+
statusText: upstream.statusText,
|
|
3301
|
+
headers
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3304
|
+
const text = await upstream.text();
|
|
3305
|
+
headers.set("Content-Type", "application/json");
|
|
3306
|
+
return new Response(unwrapCloudCodeJsonBody(text), { status: 200, headers });
|
|
3307
|
+
}
|
|
3308
|
+
function isAbortError(err, signal) {
|
|
3309
|
+
if (signal?.aborted) return true;
|
|
3310
|
+
return !!err && typeof err === "object" && err.name === "AbortError";
|
|
3311
|
+
}
|
|
3312
|
+
function abortError(signal, cause) {
|
|
3313
|
+
if (signal?.reason instanceof Error) return signal.reason;
|
|
3314
|
+
if (cause instanceof Error) return cause;
|
|
3315
|
+
return new DOMException("This operation was aborted", "AbortError");
|
|
3316
|
+
}
|
|
3317
|
+
|
|
2404
3318
|
// src/core/model.ts
|
|
3319
|
+
function isAntigravityCloudCodeRoute(provider, model) {
|
|
3320
|
+
return provider.id === "antigravity" && provider.authType === "oauth" && model.modelFormat === "cloud-code";
|
|
3321
|
+
}
|
|
2405
3322
|
function findRoute(registry, providerId, modelId, routeId) {
|
|
2406
3323
|
const provider = registry.providers.find((p) => p.id === providerId);
|
|
2407
3324
|
if (!provider) {
|
|
@@ -2442,10 +3359,40 @@ async function resolveCredential(provider, routeId) {
|
|
|
2442
3359
|
);
|
|
2443
3360
|
}
|
|
2444
3361
|
}
|
|
2445
|
-
async function createRelayModel(routeId) {
|
|
3362
|
+
async function createRelayModel(routeId, options) {
|
|
2446
3363
|
const { providerId, modelId } = parseRelayRouteId(routeId);
|
|
2447
3364
|
const registry = loadCoreRegistry();
|
|
2448
3365
|
const { provider, model } = findRoute(registry, providerId, modelId, routeId);
|
|
3366
|
+
const reasoningOptions = options?.reasoning === void 0 ? void 0 : resolveReasoningProviderOptions(options.reasoning, provider, model, routeId);
|
|
3367
|
+
const finish = (built) => reasoningOptions ? withReasoningProviderOptions(built, reasoningOptions) : Promise.resolve(built);
|
|
3368
|
+
if (isAntigravityCloudCodeRoute(provider, model)) {
|
|
3369
|
+
const apiKey2 = await resolveCredential(provider, routeId);
|
|
3370
|
+
const providerData2 = await resolveProviderOAuthProviderData(provider.authRef);
|
|
3371
|
+
const projectId = typeof providerData2?.projectId === "string" ? providerData2.projectId.trim() : "";
|
|
3372
|
+
if (!projectId) {
|
|
3373
|
+
throw new RelayCoreError(
|
|
3374
|
+
"CREDENTIAL_UNAVAILABLE",
|
|
3375
|
+
`Provider "${provider.name}" is missing project metadata \u2014 re-authenticate in relay-ai ui.`,
|
|
3376
|
+
{ providerId: provider.id, routeId }
|
|
3377
|
+
);
|
|
3378
|
+
}
|
|
3379
|
+
try {
|
|
3380
|
+
return await finish(await createAntigravityCloudCodeModel({
|
|
3381
|
+
modelId: model.upstreamModelId ?? model.id,
|
|
3382
|
+
accessToken: apiKey2,
|
|
3383
|
+
projectId,
|
|
3384
|
+
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),
|
|
3385
|
+
...options?.onDebug ? { onDebug: options.onDebug } : {}
|
|
3386
|
+
}));
|
|
3387
|
+
} catch (err) {
|
|
3388
|
+
if (isRelayCoreError(err)) throw err;
|
|
3389
|
+
throw new RelayCoreError(
|
|
3390
|
+
"PROVIDER_LOAD_FAILED",
|
|
3391
|
+
`Failed to construct model "${modelId}" for provider "${provider.name}".`,
|
|
3392
|
+
{ providerId, routeId, cause: err }
|
|
3393
|
+
);
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
2449
3396
|
const npm = model.npm ?? provider.api.npm;
|
|
2450
3397
|
if (!npm) {
|
|
2451
3398
|
throw new RelayCoreError("UNSUPPORTED_MODEL", `Model "${modelId}" has no SDK provider package \u2014 refresh the provider's models in relay-ai ui.`, { providerId, routeId });
|
|
@@ -2469,10 +3416,11 @@ async function createRelayModel(routeId) {
|
|
|
2469
3416
|
headers: provider.api.headers,
|
|
2470
3417
|
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),
|
|
2471
3418
|
useResponsesLite: model.useResponsesLite,
|
|
2472
|
-
preferWebSockets: model.preferWebSockets
|
|
3419
|
+
preferWebSockets: model.preferWebSockets,
|
|
3420
|
+
...options?.onDebug ? { onDebug: options.onDebug } : {}
|
|
2473
3421
|
};
|
|
2474
3422
|
try {
|
|
2475
|
-
return await createLanguageModel(spec);
|
|
3423
|
+
return await finish(await createLanguageModel(spec));
|
|
2476
3424
|
} catch (err) {
|
|
2477
3425
|
if (isRelayCoreError(err)) throw err;
|
|
2478
3426
|
throw new RelayCoreError(
|