@jacobbd/relay-ai 0.9.0 → 0.9.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/dist/{chunk-R4AWEK7T.js → chunk-GQCFLSEM.js} +260 -37
- package/dist/chunk-GQCFLSEM.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/core/index.d.ts +9 -2
- package/dist/core/index.js +454 -14
- package/dist/core/index.js.map +1 -1
- package/dist/{ui-command-FARF2BF4.js → ui-command-SDMYDYT6.js} +11 -6
- package/dist/ui-command-SDMYDYT6.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-R4AWEK7T.js.map +0 -1
- package/dist/ui-command-FARF2BF4.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -197,7 +197,7 @@ import {
|
|
|
197
197
|
validateCustomEndpointUrl,
|
|
198
198
|
writeSecureLogLine,
|
|
199
199
|
zenRegistryStub
|
|
200
|
-
} from "./chunk-
|
|
200
|
+
} from "./chunk-GQCFLSEM.js";
|
|
201
201
|
import {
|
|
202
202
|
filterTemplates,
|
|
203
203
|
getTemplateById,
|
|
@@ -14869,7 +14869,7 @@ Options:
|
|
|
14869
14869
|
--trace Write debug logs under ~/.relay-ai/logs/`);
|
|
14870
14870
|
return 0;
|
|
14871
14871
|
}
|
|
14872
|
-
const { runUiCommand } = await import("./ui-command-
|
|
14872
|
+
const { runUiCommand } = await import("./ui-command-SDMYDYT6.js");
|
|
14873
14873
|
return runUiCommand({ trace: parsed.trace, serverMode: parsed.uiServerMode });
|
|
14874
14874
|
}
|
|
14875
14875
|
if (parsed.command === "models") {
|
package/dist/core/index.d.ts
CHANGED
|
@@ -3,6 +3,13 @@ import { LanguageModel } from 'ai';
|
|
|
3
3
|
/** Unconditionally-scoped route id: `${providerId}::${modelId}`. Never bare. */
|
|
4
4
|
type RelayRouteId = `${string}::${string}`;
|
|
5
5
|
type RelayCoreErrorCode = 'INVALID_ROUTE_ID' | 'ROUTE_NOT_FOUND' | 'PROVIDER_DISABLED' | 'CREDENTIAL_UNAVAILABLE' | 'OAUTH_REFRESH_FAILED' | 'UNSUPPORTED_MODEL' | 'UNSUPPORTED_REGISTRY_VERSION' | 'PROVIDER_LOAD_FAILED';
|
|
6
|
+
interface CreateRelayModelOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Optional sanitized transport diagnostics. Messages contain event types,
|
|
9
|
+
* field names, counts, and lengths — never credentials, prompts, or bodies.
|
|
10
|
+
*/
|
|
11
|
+
onDebug?: (message: string) => void;
|
|
12
|
+
}
|
|
6
13
|
interface RelayModelDescriptor {
|
|
7
14
|
routeId: RelayRouteId;
|
|
8
15
|
providerId: string;
|
|
@@ -50,7 +57,7 @@ declare function listRelayModels(registryPath?: string): RelayModelDescriptor[];
|
|
|
50
57
|
* resolved (and OAuth tokens refreshed) by Relay's existing machinery; the
|
|
51
58
|
* credential and the intermediate spec never leave this function.
|
|
52
59
|
*/
|
|
53
|
-
declare function createRelayModel(routeId: RelayRouteId): Promise<LanguageModel>;
|
|
60
|
+
declare function createRelayModel(routeId: RelayRouteId, options?: CreateRelayModelOptions): Promise<LanguageModel>;
|
|
54
61
|
|
|
55
62
|
/**
|
|
56
63
|
* Build a route id from a provider id and a model id. The provider id must pass
|
|
@@ -88,4 +95,4 @@ declare class RelayCoreError extends Error {
|
|
|
88
95
|
}
|
|
89
96
|
declare function isRelayCoreError(err: unknown): err is RelayCoreError;
|
|
90
97
|
|
|
91
|
-
export { RelayCoreError, type RelayCoreErrorCode, type RelayModelDescriptor, type RelayRouteId, createRelayModel, isRelayCoreError, listRelayModels, parseRelayRouteId, toRelayRouteId };
|
|
98
|
+
export { type CreateRelayModelOptions, RelayCoreError, type RelayCoreErrorCode, type RelayModelDescriptor, type RelayRouteId, createRelayModel, isRelayCoreError, listRelayModels, parseRelayRouteId, toRelayRouteId };
|
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.2",
|
|
54
54
|
publishConfig: {
|
|
55
55
|
access: "public"
|
|
56
56
|
},
|
|
@@ -288,7 +288,229 @@ 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
|
+
functionAddedIndexes: /* @__PURE__ */ new Set(),
|
|
332
|
+
functionDeltaIndexes: /* @__PURE__ */ new Set(),
|
|
333
|
+
functionDoneCallIds: /* @__PURE__ */ new Set()
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function nextId(state, prefix) {
|
|
337
|
+
const id = `${prefix}_${state.nextId}`;
|
|
338
|
+
state.nextId += 1;
|
|
339
|
+
return id;
|
|
340
|
+
}
|
|
341
|
+
function asString(value) {
|
|
342
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
343
|
+
}
|
|
344
|
+
function normalizeErrorEvent(event) {
|
|
345
|
+
const raw = isRecord(event.error) ? event.error : { message: typeof event.error === "string" ? event.error : "upstream error" };
|
|
346
|
+
return {
|
|
347
|
+
type: "error",
|
|
348
|
+
sequence_number: typeof event.sequence_number === "number" ? event.sequence_number : 0,
|
|
349
|
+
error: {
|
|
350
|
+
type: asString(raw.type) ?? "server_error",
|
|
351
|
+
code: asString(raw.code) ?? "unknown",
|
|
352
|
+
message: asString(raw.message) ?? "upstream error",
|
|
353
|
+
...raw.param == null ? {} : { param: raw.param }
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function normalizeFunctionItem(item, state, forDone = false) {
|
|
358
|
+
const callId = asString(item.call_id) ?? asString(item.id) ?? nextId(state, "call");
|
|
359
|
+
const id = asString(item.id) ?? nextId(state, "fc");
|
|
360
|
+
state.lastFunctionItemId = id;
|
|
361
|
+
return {
|
|
362
|
+
...item,
|
|
363
|
+
type: "function_call",
|
|
364
|
+
id,
|
|
365
|
+
call_id: callId,
|
|
366
|
+
name: asString(item.name) ?? "",
|
|
367
|
+
arguments: typeof item.arguments === "string" ? item.arguments : "",
|
|
368
|
+
...forDone ? { status: "completed" } : {}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function messageText(item) {
|
|
372
|
+
if (typeof item.text === "string") return item.text;
|
|
373
|
+
if (!Array.isArray(item.content)) return "";
|
|
374
|
+
let out = "";
|
|
375
|
+
for (const part of item.content) {
|
|
376
|
+
if (isRecord(part) && typeof part.text === "string" && (part.type === "output_text" || part.type === "text")) {
|
|
377
|
+
out += part.text;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return out;
|
|
381
|
+
}
|
|
382
|
+
function synthesizeMessage(item, outputIndex, state) {
|
|
383
|
+
const text = messageText(item);
|
|
384
|
+
if (!text) return [];
|
|
385
|
+
const id = asString(item.id) ?? nextId(state, "msg");
|
|
386
|
+
state.lastMessageItemId = id;
|
|
387
|
+
state.textDeltaForwarded = true;
|
|
388
|
+
state.messageAddedIds.add(id);
|
|
389
|
+
state.messageDoneIds.add(id);
|
|
390
|
+
return [
|
|
391
|
+
{ type: "response.output_item.added", output_index: outputIndex, item: { type: "message", id } },
|
|
392
|
+
{ type: "response.output_text.delta", item_id: id, delta: text },
|
|
393
|
+
{ type: "response.output_item.done", output_index: outputIndex, item: { type: "message", id } }
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
function synthesizeFunctionCall(item, outputIndex, state) {
|
|
397
|
+
const normalized = normalizeFunctionItem(item, state);
|
|
398
|
+
const callId = String(normalized.call_id);
|
|
399
|
+
if (state.functionDoneCallIds.has(callId)) return [];
|
|
400
|
+
const events = [];
|
|
401
|
+
if (!state.functionAddedIndexes.has(outputIndex)) {
|
|
402
|
+
events.push({
|
|
403
|
+
type: "response.output_item.added",
|
|
404
|
+
output_index: outputIndex,
|
|
405
|
+
item: { ...normalized, arguments: "" }
|
|
406
|
+
});
|
|
407
|
+
state.functionAddedIndexes.add(outputIndex);
|
|
408
|
+
}
|
|
409
|
+
if (!state.functionDeltaIndexes.has(outputIndex) && typeof normalized.arguments === "string" && normalized.arguments.length > 0) {
|
|
410
|
+
events.push({
|
|
411
|
+
type: "response.function_call_arguments.delta",
|
|
412
|
+
item_id: normalized.id,
|
|
413
|
+
output_index: outputIndex,
|
|
414
|
+
delta: normalized.arguments
|
|
415
|
+
});
|
|
416
|
+
state.functionDeltaIndexes.add(outputIndex);
|
|
417
|
+
}
|
|
418
|
+
events.push({
|
|
419
|
+
type: "response.output_item.done",
|
|
420
|
+
output_index: outputIndex,
|
|
421
|
+
item: { ...normalized, status: "completed" }
|
|
422
|
+
});
|
|
423
|
+
state.functionDoneCallIds.add(callId);
|
|
424
|
+
state.lastOutputIndex = outputIndex;
|
|
425
|
+
return events;
|
|
426
|
+
}
|
|
427
|
+
function recoverFromCompletedOutput(response, state) {
|
|
428
|
+
if (!Array.isArray(response.output)) return [];
|
|
429
|
+
const recovered = [];
|
|
430
|
+
response.output.forEach((item, index) => {
|
|
431
|
+
if (!isRecord(item) || typeof item.type !== "string") return;
|
|
432
|
+
if (item.type === "message" && !state.textDeltaForwarded) {
|
|
433
|
+
recovered.push(...synthesizeMessage(item, index, state));
|
|
434
|
+
} else if (item.type === "function_call") {
|
|
435
|
+
recovered.push(...synthesizeFunctionCall(item, index, state));
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
return recovered;
|
|
439
|
+
}
|
|
440
|
+
function normalizeResponsesLiteEvent(event, state) {
|
|
441
|
+
if (!isRecord(event) || typeof event.type !== "string") return [event];
|
|
442
|
+
if (event.type === "error") return [normalizeErrorEvent(event)];
|
|
443
|
+
if (event.type === "response.output_item.added" && isRecord(event.item)) {
|
|
444
|
+
const outputIndex = typeof event.output_index === "number" ? event.output_index : state.lastOutputIndex;
|
|
445
|
+
state.lastOutputIndex = outputIndex;
|
|
446
|
+
if (event.item.type === "message") {
|
|
447
|
+
const id = asString(event.item.id) ?? nextId(state, "msg");
|
|
448
|
+
state.lastMessageItemId = id;
|
|
449
|
+
state.messageAddedIds.add(id);
|
|
450
|
+
return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];
|
|
451
|
+
}
|
|
452
|
+
if (event.item.type === "function_call") {
|
|
453
|
+
const item = normalizeFunctionItem(event.item, state);
|
|
454
|
+
state.functionAddedIndexes.add(outputIndex);
|
|
455
|
+
return [{ ...event, output_index: outputIndex, item }];
|
|
456
|
+
}
|
|
457
|
+
return [{ ...event, output_index: outputIndex }];
|
|
458
|
+
}
|
|
459
|
+
if (event.type === "response.output_item.done" && isRecord(event.item)) {
|
|
460
|
+
const outputIndex = typeof event.output_index === "number" ? event.output_index : state.lastOutputIndex;
|
|
461
|
+
if (event.item.type === "function_call") {
|
|
462
|
+
const item = normalizeFunctionItem(event.item, state, true);
|
|
463
|
+
const callId = String(item.call_id);
|
|
464
|
+
state.functionDoneCallIds.add(callId);
|
|
465
|
+
return [{ ...event, output_index: outputIndex, item }];
|
|
466
|
+
}
|
|
467
|
+
if (event.item.type === "message") {
|
|
468
|
+
const id = asString(event.item.id) ?? state.lastMessageItemId ?? nextId(state, "msg");
|
|
469
|
+
state.lastMessageItemId = id;
|
|
470
|
+
state.messageDoneIds.add(id);
|
|
471
|
+
return [{ ...event, output_index: outputIndex, item: { ...event.item, id } }];
|
|
472
|
+
}
|
|
473
|
+
return [{ ...event, output_index: outputIndex }];
|
|
474
|
+
}
|
|
475
|
+
if (event.type === "response.output_text.delta") {
|
|
476
|
+
const itemId = asString(event.item_id) ?? state.lastMessageItemId ?? nextId(state, "msg");
|
|
477
|
+
state.lastMessageItemId = itemId;
|
|
478
|
+
state.textDeltaForwarded = true;
|
|
479
|
+
const events = [];
|
|
480
|
+
if (!state.messageAddedIds.has(itemId)) {
|
|
481
|
+
events.push({
|
|
482
|
+
type: "response.output_item.added",
|
|
483
|
+
output_index: state.lastOutputIndex,
|
|
484
|
+
item: { type: "message", id: itemId }
|
|
485
|
+
});
|
|
486
|
+
state.messageAddedIds.add(itemId);
|
|
487
|
+
}
|
|
488
|
+
events.push({ ...event, item_id: itemId, delta: typeof event.delta === "string" ? event.delta : "" });
|
|
489
|
+
return events;
|
|
490
|
+
}
|
|
491
|
+
if (event.type === "response.function_call_arguments.delta") {
|
|
492
|
+
const itemId = asString(event.item_id) ?? state.lastFunctionItemId ?? nextId(state, "fc");
|
|
493
|
+
const outputIndex = typeof event.output_index === "number" ? event.output_index : state.lastOutputIndex;
|
|
494
|
+
state.lastFunctionItemId = itemId;
|
|
495
|
+
state.lastOutputIndex = outputIndex;
|
|
496
|
+
state.functionDeltaIndexes.add(outputIndex);
|
|
497
|
+
return [{ ...event, item_id: itemId, output_index: outputIndex, delta: typeof event.delta === "string" ? event.delta : "" }];
|
|
498
|
+
}
|
|
499
|
+
if (event.type === "response.completed" || event.type === "response.incomplete") {
|
|
500
|
+
const response = isRecord(event.response) ? event.response : {};
|
|
501
|
+
const recovered = recoverFromCompletedOutput(response, state);
|
|
502
|
+
if (state.lastMessageItemId && state.textDeltaForwarded && !state.messageDoneIds.has(state.lastMessageItemId)) {
|
|
503
|
+
recovered.push({
|
|
504
|
+
type: "response.output_item.done",
|
|
505
|
+
output_index: state.lastOutputIndex,
|
|
506
|
+
item: { type: "message", id: state.lastMessageItemId }
|
|
507
|
+
});
|
|
508
|
+
state.messageDoneIds.add(state.lastMessageItemId);
|
|
509
|
+
}
|
|
510
|
+
return [...recovered, event];
|
|
511
|
+
}
|
|
512
|
+
return [event];
|
|
513
|
+
}
|
|
292
514
|
function toHeaderRecord(headers) {
|
|
293
515
|
const out = {};
|
|
294
516
|
if (!headers) return out;
|
|
@@ -346,10 +568,14 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
346
568
|
if (hasResponsesLiteHeader(headers)) {
|
|
347
569
|
payload = applyResponsesLiteShape(payload);
|
|
348
570
|
}
|
|
571
|
+
debug(
|
|
572
|
+
`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)}`
|
|
573
|
+
);
|
|
349
574
|
const outgoing = JSON.stringify({ type: "response.create", ...payload });
|
|
350
575
|
const encoder = new TextEncoder();
|
|
351
576
|
let socket;
|
|
352
577
|
let frameCount = 0;
|
|
578
|
+
const normalizeState = createResponsesLiteNormalizeState();
|
|
353
579
|
const stream = new ReadableStream({
|
|
354
580
|
start(controller) {
|
|
355
581
|
let closed = false;
|
|
@@ -367,13 +593,12 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
367
593
|
};
|
|
368
594
|
const fail = (message) => {
|
|
369
595
|
if (closed) return;
|
|
370
|
-
debug(`fail
|
|
596
|
+
debug(`fail messageChars=${message.length}`);
|
|
371
597
|
try {
|
|
372
|
-
|
|
373
|
-
|
|
598
|
+
const [errorEvent] = normalizeResponsesLiteEvent({ type: "error", error: { message } }, normalizeState);
|
|
599
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(errorEvent)}
|
|
374
600
|
|
|
375
|
-
`
|
|
376
|
-
));
|
|
601
|
+
`));
|
|
377
602
|
} catch {
|
|
378
603
|
}
|
|
379
604
|
close();
|
|
@@ -389,28 +614,31 @@ function createResponsesWebSocketFetch(wsUrl, log) {
|
|
|
389
614
|
socket.on("message", (data) => {
|
|
390
615
|
const text = Array.isArray(data) ? Buffer.concat(data).toString("utf8") : data.toString("utf8");
|
|
391
616
|
frameCount += 1;
|
|
392
|
-
if (frameCount <= 3) debug(`frame#${frameCount}: ${text.slice(0, 200)}`);
|
|
393
617
|
let event;
|
|
394
618
|
try {
|
|
395
619
|
event = JSON.parse(text);
|
|
396
620
|
} catch {
|
|
621
|
+
debug(`frame#${frameCount} non-json chars=${text.length}`);
|
|
397
622
|
controller.enqueue(encoder.encode(`data: ${text.replace(/\r?\n/g, " ")}
|
|
398
623
|
|
|
399
624
|
`));
|
|
400
625
|
return;
|
|
401
626
|
}
|
|
402
|
-
|
|
627
|
+
if (frameCount <= 8) debug(`frame#${frameCount} ${summarizeResponsesLiteEvent(event)}`);
|
|
628
|
+
for (const next of normalizeResponsesLiteEvent(event, normalizeState)) {
|
|
629
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(next)}
|
|
403
630
|
|
|
404
631
|
`));
|
|
405
|
-
|
|
406
|
-
|
|
632
|
+
}
|
|
633
|
+
const type = isRecord(event) && typeof event.type === "string" ? event.type : void 0;
|
|
634
|
+
if (type && TERMINAL_EVENT_TYPES.has(type)) {
|
|
407
635
|
debug(`terminal event: ${type} (after ${frameCount} frames)`);
|
|
408
636
|
close();
|
|
409
637
|
}
|
|
410
638
|
});
|
|
411
639
|
socket.on("error", (err) => fail(err.message));
|
|
412
640
|
socket.on("close", (code, reason) => {
|
|
413
|
-
debug(`close code=${code} frames=${frameCount}${reason?.length ? `
|
|
641
|
+
debug(`close code=${code} frames=${frameCount}${reason?.length ? ` reasonChars=${reason.length}` : ""}`);
|
|
414
642
|
if (closed) return;
|
|
415
643
|
if (code === 1e3 || code === 1005) {
|
|
416
644
|
close();
|
|
@@ -1513,6 +1741,12 @@ var SCOPES = [
|
|
|
1513
1741
|
].join(" ");
|
|
1514
1742
|
var ANTIGRAVITY_VERSION = "4.2.0";
|
|
1515
1743
|
var ANTIGRAVITY_USER_AGENT = `vscode/1.X.X (Antigravity/${ANTIGRAVITY_VERSION})`;
|
|
1744
|
+
var ANTIGRAVITY_BASE_URLS = [
|
|
1745
|
+
"https://daily-cloudcode-pa.googleapis.com",
|
|
1746
|
+
"https://cloudcode-pa.googleapis.com",
|
|
1747
|
+
"https://daily-cloudcode-pa.sandbox.googleapis.com"
|
|
1748
|
+
];
|
|
1749
|
+
var ANTIGRAVITY_API_VERSION = "v1internal";
|
|
1516
1750
|
async function refreshAntigravityToken(refreshToken) {
|
|
1517
1751
|
return postOAuthRefresh(
|
|
1518
1752
|
TOKEN_URL3,
|
|
@@ -2401,7 +2635,185 @@ function providerRefreshToken(providerId, authType, authRef) {
|
|
|
2401
2635
|
return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));
|
|
2402
2636
|
}
|
|
2403
2637
|
|
|
2638
|
+
// src/core/antigravity-model.ts
|
|
2639
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2640
|
+
var CLOUD_CODE_BASE = ANTIGRAVITY_BASE_URLS[0].replace(/\/+$/, "");
|
|
2641
|
+
var STREAM_URL = `${CLOUD_CODE_BASE}/${ANTIGRAVITY_API_VERSION}:streamGenerateContent?alt=sse`;
|
|
2642
|
+
var UNARY_URL = `${CLOUD_CODE_BASE}/${ANTIGRAVITY_API_VERSION}:generateContent`;
|
|
2643
|
+
var SDK_BASE_URL = `${CLOUD_CODE_BASE}/v1beta`;
|
|
2644
|
+
function unwrapCloudCodeSsePayload(payload) {
|
|
2645
|
+
const trimmed = payload.trim();
|
|
2646
|
+
if (trimmed === "" || trimmed === "[DONE]") return payload;
|
|
2647
|
+
try {
|
|
2648
|
+
const parsed = JSON.parse(trimmed);
|
|
2649
|
+
if (isWrappedCloudCodeBody(parsed)) {
|
|
2650
|
+
return JSON.stringify(parsed.response);
|
|
2651
|
+
}
|
|
2652
|
+
} catch {
|
|
2653
|
+
}
|
|
2654
|
+
return payload;
|
|
2655
|
+
}
|
|
2656
|
+
function unwrapCloudCodeJsonBody(text) {
|
|
2657
|
+
try {
|
|
2658
|
+
const parsed = JSON.parse(text);
|
|
2659
|
+
if (isWrappedCloudCodeBody(parsed)) {
|
|
2660
|
+
return JSON.stringify(parsed.response);
|
|
2661
|
+
}
|
|
2662
|
+
} catch {
|
|
2663
|
+
}
|
|
2664
|
+
return text;
|
|
2665
|
+
}
|
|
2666
|
+
function consumeCloudCodeSseBuffer(buffer) {
|
|
2667
|
+
const separator = /\r?\n\r?\n/;
|
|
2668
|
+
let rest = buffer;
|
|
2669
|
+
let emitted = "";
|
|
2670
|
+
while (true) {
|
|
2671
|
+
const match = separator.exec(rest);
|
|
2672
|
+
if (!match || match.index === void 0) break;
|
|
2673
|
+
const rawEvent = rest.slice(0, match.index);
|
|
2674
|
+
const sep = match[0];
|
|
2675
|
+
rest = rest.slice(match.index + sep.length);
|
|
2676
|
+
emitted += transformSseEvent(rawEvent) + sep;
|
|
2677
|
+
}
|
|
2678
|
+
return { emitted, rest };
|
|
2679
|
+
}
|
|
2680
|
+
function createCloudCodeSseUnwrapper() {
|
|
2681
|
+
const decoder = new TextDecoder();
|
|
2682
|
+
const encoder = new TextEncoder();
|
|
2683
|
+
let pending = "";
|
|
2684
|
+
return new TransformStream({
|
|
2685
|
+
transform(chunk, controller) {
|
|
2686
|
+
pending += decoder.decode(chunk, { stream: true });
|
|
2687
|
+
const { emitted, rest } = consumeCloudCodeSseBuffer(pending);
|
|
2688
|
+
pending = rest;
|
|
2689
|
+
if (emitted) controller.enqueue(encoder.encode(emitted));
|
|
2690
|
+
},
|
|
2691
|
+
flush(controller) {
|
|
2692
|
+
pending += decoder.decode();
|
|
2693
|
+
if (!pending) return;
|
|
2694
|
+
const { emitted, rest } = consumeCloudCodeSseBuffer(pending);
|
|
2695
|
+
const tail = emitted + (rest ? transformSseEvent(rest) : "");
|
|
2696
|
+
if (tail) controller.enqueue(encoder.encode(tail));
|
|
2697
|
+
}
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
function createCloudCodeFetch(options, fetchImpl) {
|
|
2701
|
+
let accessToken = options.accessToken;
|
|
2702
|
+
return async (input, init) => {
|
|
2703
|
+
const url = requestUrl(input);
|
|
2704
|
+
const streaming = url.includes("streamGenerateContent");
|
|
2705
|
+
const signal = init?.signal ?? (input instanceof Request ? input.signal : void 0);
|
|
2706
|
+
const geminiBody = await readJsonBody(input, init);
|
|
2707
|
+
const envelope = {
|
|
2708
|
+
project: options.projectId,
|
|
2709
|
+
requestId: randomUUID2(),
|
|
2710
|
+
model: options.modelId,
|
|
2711
|
+
userAgent: ANTIGRAVITY_USER_AGENT,
|
|
2712
|
+
requestType: "agent",
|
|
2713
|
+
enabledCreditTypes: ["GOOGLE_ONE_AI"],
|
|
2714
|
+
request: geminiBody
|
|
2715
|
+
};
|
|
2716
|
+
const body = JSON.stringify(envelope);
|
|
2717
|
+
const upstreamUrl = streaming ? STREAM_URL : UNARY_URL;
|
|
2718
|
+
const doFetch = fetchImpl ?? ((input2, init2) => globalThis.fetch(input2, init2));
|
|
2719
|
+
const send = (token) => doFetch(upstreamUrl, {
|
|
2720
|
+
method: "POST",
|
|
2721
|
+
headers: {
|
|
2722
|
+
"Content-Type": "application/json",
|
|
2723
|
+
Authorization: `Bearer ${token}`,
|
|
2724
|
+
"User-Agent": ANTIGRAVITY_USER_AGENT
|
|
2725
|
+
},
|
|
2726
|
+
body,
|
|
2727
|
+
signal
|
|
2728
|
+
});
|
|
2729
|
+
let response;
|
|
2730
|
+
try {
|
|
2731
|
+
response = await send(accessToken);
|
|
2732
|
+
} catch (err) {
|
|
2733
|
+
if (isAbortError(err, signal)) throw abortError(signal, err);
|
|
2734
|
+
throw err;
|
|
2735
|
+
}
|
|
2736
|
+
if (response.status === 401 && options.refreshToken && !signal?.aborted) {
|
|
2737
|
+
const refreshed = await options.refreshToken().catch(() => null);
|
|
2738
|
+
if (refreshed && refreshed !== accessToken && !signal?.aborted) {
|
|
2739
|
+
accessToken = refreshed;
|
|
2740
|
+
try {
|
|
2741
|
+
response = await send(accessToken);
|
|
2742
|
+
} catch (err) {
|
|
2743
|
+
if (isAbortError(err, signal)) throw abortError(signal, err);
|
|
2744
|
+
throw err;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
return adaptUpstreamResponse(response, streaming);
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
async function createAntigravityCloudCodeModel(options) {
|
|
2752
|
+
const { createGoogleGenerativeAI } = await import("@ai-sdk/google");
|
|
2753
|
+
const google = createGoogleGenerativeAI({
|
|
2754
|
+
apiKey: "relay-cloud-code",
|
|
2755
|
+
baseURL: SDK_BASE_URL,
|
|
2756
|
+
fetch: createCloudCodeFetch(options)
|
|
2757
|
+
});
|
|
2758
|
+
return google(options.modelId);
|
|
2759
|
+
}
|
|
2760
|
+
function isWrappedCloudCodeBody(parsed) {
|
|
2761
|
+
return !!parsed && typeof parsed === "object" && !Array.isArray(parsed) && "response" in parsed && parsed.response !== null && typeof parsed.response === "object";
|
|
2762
|
+
}
|
|
2763
|
+
function transformSseEvent(event) {
|
|
2764
|
+
return event.replace(/^(data:[ \t]*)(.*)$/gm, (_all, prefix, payload) => `${prefix}${unwrapCloudCodeSsePayload(payload)}`);
|
|
2765
|
+
}
|
|
2766
|
+
function requestUrl(input) {
|
|
2767
|
+
if (typeof input === "string") return input;
|
|
2768
|
+
if (input instanceof URL) return input.href;
|
|
2769
|
+
return input.url;
|
|
2770
|
+
}
|
|
2771
|
+
async function readJsonBody(input, init) {
|
|
2772
|
+
const body = init?.body;
|
|
2773
|
+
if (typeof body === "string") return JSON.parse(body);
|
|
2774
|
+
if (body instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(body));
|
|
2775
|
+
if (body instanceof ArrayBuffer) return JSON.parse(new TextDecoder().decode(body));
|
|
2776
|
+
const request = input instanceof Request ? input.clone() : new Request(input, init);
|
|
2777
|
+
return request.json();
|
|
2778
|
+
}
|
|
2779
|
+
async function adaptUpstreamResponse(upstream, streaming) {
|
|
2780
|
+
const fallbackType = streaming ? "text/event-stream" : "application/json";
|
|
2781
|
+
const contentType = upstream.headers.get("content-type") ?? fallbackType;
|
|
2782
|
+
const headers = new Headers({ "Content-Type": contentType });
|
|
2783
|
+
if (!upstream.ok) {
|
|
2784
|
+
const errBody = await upstream.text();
|
|
2785
|
+
return new Response(errBody, {
|
|
2786
|
+
status: upstream.status,
|
|
2787
|
+
statusText: upstream.statusText,
|
|
2788
|
+
headers
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2791
|
+
if (streaming) {
|
|
2792
|
+
const body = upstream.body ? upstream.body.pipeThrough(createCloudCodeSseUnwrapper()) : null;
|
|
2793
|
+
return new Response(body, {
|
|
2794
|
+
status: upstream.status,
|
|
2795
|
+
statusText: upstream.statusText,
|
|
2796
|
+
headers
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
const text = await upstream.text();
|
|
2800
|
+
headers.set("Content-Type", "application/json");
|
|
2801
|
+
return new Response(unwrapCloudCodeJsonBody(text), { status: 200, headers });
|
|
2802
|
+
}
|
|
2803
|
+
function isAbortError(err, signal) {
|
|
2804
|
+
if (signal?.aborted) return true;
|
|
2805
|
+
return !!err && typeof err === "object" && err.name === "AbortError";
|
|
2806
|
+
}
|
|
2807
|
+
function abortError(signal, cause) {
|
|
2808
|
+
if (signal?.reason instanceof Error) return signal.reason;
|
|
2809
|
+
if (cause instanceof Error) return cause;
|
|
2810
|
+
return new DOMException("This operation was aborted", "AbortError");
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2404
2813
|
// src/core/model.ts
|
|
2814
|
+
function isAntigravityCloudCodeRoute(provider, model) {
|
|
2815
|
+
return provider.id === "antigravity" && provider.authType === "oauth" && model.modelFormat === "cloud-code";
|
|
2816
|
+
}
|
|
2405
2817
|
function findRoute(registry, providerId, modelId, routeId) {
|
|
2406
2818
|
const provider = registry.providers.find((p) => p.id === providerId);
|
|
2407
2819
|
if (!provider) {
|
|
@@ -2442,10 +2854,37 @@ async function resolveCredential(provider, routeId) {
|
|
|
2442
2854
|
);
|
|
2443
2855
|
}
|
|
2444
2856
|
}
|
|
2445
|
-
async function createRelayModel(routeId) {
|
|
2857
|
+
async function createRelayModel(routeId, options) {
|
|
2446
2858
|
const { providerId, modelId } = parseRelayRouteId(routeId);
|
|
2447
2859
|
const registry = loadCoreRegistry();
|
|
2448
2860
|
const { provider, model } = findRoute(registry, providerId, modelId, routeId);
|
|
2861
|
+
if (isAntigravityCloudCodeRoute(provider, model)) {
|
|
2862
|
+
const apiKey2 = await resolveCredential(provider, routeId);
|
|
2863
|
+
const providerData2 = await resolveProviderOAuthProviderData(provider.authRef);
|
|
2864
|
+
const projectId = typeof providerData2?.projectId === "string" ? providerData2.projectId.trim() : "";
|
|
2865
|
+
if (!projectId) {
|
|
2866
|
+
throw new RelayCoreError(
|
|
2867
|
+
"CREDENTIAL_UNAVAILABLE",
|
|
2868
|
+
`Provider "${provider.name}" is missing project metadata \u2014 re-authenticate in relay-ai ui.`,
|
|
2869
|
+
{ providerId: provider.id, routeId }
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
try {
|
|
2873
|
+
return await createAntigravityCloudCodeModel({
|
|
2874
|
+
modelId: model.upstreamModelId ?? model.id,
|
|
2875
|
+
accessToken: apiKey2,
|
|
2876
|
+
projectId,
|
|
2877
|
+
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef)
|
|
2878
|
+
});
|
|
2879
|
+
} catch (err) {
|
|
2880
|
+
if (isRelayCoreError(err)) throw err;
|
|
2881
|
+
throw new RelayCoreError(
|
|
2882
|
+
"PROVIDER_LOAD_FAILED",
|
|
2883
|
+
`Failed to construct model "${modelId}" for provider "${provider.name}".`,
|
|
2884
|
+
{ providerId, routeId, cause: err }
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2449
2888
|
const npm = model.npm ?? provider.api.npm;
|
|
2450
2889
|
if (!npm) {
|
|
2451
2890
|
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,7 +2908,8 @@ async function createRelayModel(routeId) {
|
|
|
2469
2908
|
headers: provider.api.headers,
|
|
2470
2909
|
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),
|
|
2471
2910
|
useResponsesLite: model.useResponsesLite,
|
|
2472
|
-
preferWebSockets: model.preferWebSockets
|
|
2911
|
+
preferWebSockets: model.preferWebSockets,
|
|
2912
|
+
...options?.onDebug ? { onDebug: options.onDebug } : {}
|
|
2473
2913
|
};
|
|
2474
2914
|
try {
|
|
2475
2915
|
return await createLanguageModel(spec);
|