@jacobbd/relay-ai 0.7.4 → 0.7.6

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.
@@ -11,7 +11,7 @@ import { join } from "path";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@jacobbd/relay-ai",
14
- version: "0.7.4",
14
+ version: "0.7.6",
15
15
  publishConfig: {
16
16
  access: "public"
17
17
  },
@@ -48,11 +48,13 @@ var package_default = {
48
48
  scripts: {
49
49
  build: "tsup && tsup --config tsup.core.config.ts && node scripts/copy-ui-assets.mjs",
50
50
  dev: "tsup --watch",
51
- test: "vitest run",
51
+ test: 'vitest run --exclude "tests/debug-*.test.ts"',
52
+ "test:live": "vitest run tests/debug-xai.test.ts tests/debug-openai-oauth.test.ts",
52
53
  "test:watch": "vitest",
53
54
  typecheck: "tsc --noEmit",
55
+ "release:check": "node scripts/release-metadata.mjs",
54
56
  "refresh:models-dev": "node scripts/refresh-models-dev-cache.mjs",
55
- prepublishOnly: `node -e "if (require('./package.json').version !== require('./package-lock.json').version) { console.error('Error: package.json and package-lock.json versions are out of sync! Run npm install to sync.'); process.exit(1); }" && npm run build`
57
+ prepublishOnly: "npm run release:check && npm run build"
56
58
  },
57
59
  dependencies: {
58
60
  "@ai-sdk/alibaba": "^1.0.26",
@@ -4174,6 +4176,10 @@ function getUiDebugLogPath() {
4174
4176
  function getServerDebugLogPath() {
4175
4177
  return join8(ensureLogsDir(), SERVER_DEBUG_LOG);
4176
4178
  }
4179
+ function getAntigravityDebugLogPath(tracePrefix) {
4180
+ const surface = tracePrefix === "antigravity" ? "app" : tracePrefix;
4181
+ return join8(ensureLogsDir(), `antigravity-${surface}-debug.log`);
4182
+ }
4177
4183
  function makeTraceLogger(logPath) {
4178
4184
  resetTraceLog(logPath);
4179
4185
  return (message) => writeSecureLogLine(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${message}`);
@@ -4309,6 +4315,240 @@ function maskGatewayModelId(aliasId) {
4309
4315
  return `anthropic-${reverseSegment(providerSlug)}__${reverseSegment(modelSuffix)}`;
4310
4316
  }
4311
4317
 
4318
+ // src/subagent-route-registry.ts
4319
+ import { randomUUID as randomUUID2 } from "crypto";
4320
+ var DEFAULT_TTL_MS = 5 * 6e4;
4321
+ var DEFAULT_MAX_ENTRIES = 1024;
4322
+ var ROUTE_MARKER_PATTERN = /(?:\n\n)?<relay-ai-subagent-route token="([0-9a-f-]{36})"\s*\/>/gi;
4323
+ function firstHeader(value) {
4324
+ const first = Array.isArray(value) ? value[0] : value;
4325
+ return typeof first === "string" && first.trim() ? first.trim() : void 0;
4326
+ }
4327
+ function extractClaudeSessionId(headers, body) {
4328
+ const headerSession = firstHeader(headers["x-claude-code-session-id"]);
4329
+ if (headerSession) return headerSession;
4330
+ const userId = body?.metadata?.user_id;
4331
+ if (typeof userId !== "string") return void 0;
4332
+ try {
4333
+ const parsed = JSON.parse(userId);
4334
+ return typeof parsed.session_id === "string" && parsed.session_id.trim() ? parsed.session_id.trim() : void 0;
4335
+ } catch {
4336
+ return void 0;
4337
+ }
4338
+ }
4339
+ function appendSubagentRouteMarker(prompt, token) {
4340
+ return `${prompt}
4341
+
4342
+ <relay-ai-subagent-route token="${token}"/>`;
4343
+ }
4344
+ function findMarkersInUserMessages(body) {
4345
+ if (!Array.isArray(body.messages)) return void 0;
4346
+ const tokens = [];
4347
+ const messages = [...body.messages];
4348
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
4349
+ const message = body.messages[messageIndex];
4350
+ if (!message || message.role !== "user") continue;
4351
+ if (typeof message.content === "string") {
4352
+ const matches = [...message.content.matchAll(ROUTE_MARKER_PATTERN)];
4353
+ if (matches.length === 0) continue;
4354
+ tokens.push(...matches.flatMap((match) => match[1] ? [match[1]] : []));
4355
+ messages[messageIndex] = {
4356
+ ...message,
4357
+ content: message.content.replace(ROUTE_MARKER_PATTERN, "").trimEnd()
4358
+ };
4359
+ continue;
4360
+ }
4361
+ if (!Array.isArray(message.content)) continue;
4362
+ const content = [...message.content];
4363
+ for (let partIndex = 0; partIndex < message.content.length; partIndex++) {
4364
+ const part = message.content[partIndex];
4365
+ if (!part || part.type !== "text" || typeof part.text !== "string") continue;
4366
+ const matches = [...part.text.matchAll(ROUTE_MARKER_PATTERN)];
4367
+ if (matches.length === 0) continue;
4368
+ tokens.push(...matches.flatMap((match) => match[1] ? [match[1]] : []));
4369
+ content[partIndex] = {
4370
+ ...part,
4371
+ text: part.text.replace(ROUTE_MARKER_PATTERN, "").trimEnd()
4372
+ };
4373
+ }
4374
+ messages[messageIndex] = { ...message, content };
4375
+ }
4376
+ return tokens.length > 0 ? { tokens, body: { ...body, messages } } : void 0;
4377
+ }
4378
+ var SubagentRouteRegistry = class {
4379
+ entries = /* @__PURE__ */ new Map();
4380
+ ttlMs;
4381
+ maxEntries;
4382
+ now;
4383
+ constructor(options = {}) {
4384
+ this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
4385
+ this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
4386
+ this.now = options.now ?? Date.now;
4387
+ }
4388
+ register(sessionId, modelId) {
4389
+ this.cleanup();
4390
+ while (this.entries.size >= this.maxEntries) {
4391
+ const oldest = this.entries.keys().next().value;
4392
+ if (!oldest) break;
4393
+ this.entries.delete(oldest);
4394
+ }
4395
+ const token = randomUUID2();
4396
+ this.entries.set(token, { sessionId, modelId, createdAt: this.now() });
4397
+ return token;
4398
+ }
4399
+ consume(headers, body) {
4400
+ this.cleanup();
4401
+ if (!firstHeader(headers["x-claude-code-agent-id"])) return void 0;
4402
+ const sessionId = extractClaudeSessionId(headers, body);
4403
+ if (!sessionId) return void 0;
4404
+ const marked = findMarkersInUserMessages(body);
4405
+ if (!marked) return void 0;
4406
+ const token = [...marked.tokens].reverse().find((candidate) => this.entries.get(candidate)?.sessionId === sessionId);
4407
+ if (!token) return void 0;
4408
+ const entry = this.entries.get(token);
4409
+ this.entries.delete(token);
4410
+ return { modelId: entry.modelId, body: marked.body };
4411
+ }
4412
+ cleanup() {
4413
+ const cutoff = this.now() - this.ttlMs;
4414
+ for (const [token, entry] of this.entries) {
4415
+ if (entry.createdAt < cutoff) this.entries.delete(token);
4416
+ }
4417
+ }
4418
+ };
4419
+
4420
+ // src/subagent-model-routing.ts
4421
+ var CLAUDE_MODEL_FAMILIES = ["sonnet", "opus", "haiku", "fable"];
4422
+ var CLAUDE_MODEL_FAMILY_SET = new Set(CLAUDE_MODEL_FAMILIES);
4423
+ function isRecord(value) {
4424
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4425
+ }
4426
+ function claudeModelFamily(modelId) {
4427
+ const normalized = modelId.toLowerCase();
4428
+ if (!normalized.startsWith("claude-")) return void 0;
4429
+ return CLAUDE_MODEL_FAMILIES.find((family) => normalized.includes(family));
4430
+ }
4431
+ function isClaudeAgentTool(tool4) {
4432
+ if (tool4.name !== "Agent" || !isRecord(tool4.input_schema)) return false;
4433
+ const properties = tool4.input_schema.properties;
4434
+ if (!isRecord(properties)) return false;
4435
+ return ["description", "prompt", "subagent_type"].every((name) => isRecord(properties[name]));
4436
+ }
4437
+ var UnavailableSubagentModelError = class extends Error {
4438
+ constructor(selector, routing) {
4439
+ const visible = routing.models.slice(0, MAX_MODEL_CATALOG).map((model) => model.id);
4440
+ const omitted = routing.models.length - visible.length;
4441
+ const suffix = omitted > 0 ? `, and ${omitted} more` : "";
4442
+ super(
4443
+ `Subagent model "${selector}" is unavailable in this Relay AI session. Available model ids: ${visible.join(", ")}${suffix}.`
4444
+ );
4445
+ this.selector = selector;
4446
+ this.name = "UnavailableSubagentModelError";
4447
+ }
4448
+ selector;
4449
+ statusCode = 400;
4450
+ };
4451
+ function normalizeClaudeAgentInput(input, routing) {
4452
+ const source = isRecord(input) ? input : {};
4453
+ const normalized = { ...source };
4454
+ if (source.subagent_type === "fork") {
4455
+ return { input: normalized, decision: { kind: "fork" } };
4456
+ }
4457
+ const rawModel = source.model;
4458
+ if (rawModel == null) {
4459
+ normalized.model = routing.parentModelId;
4460
+ return {
4461
+ input: normalized,
4462
+ decision: { kind: "inherit", resolvedModelId: routing.parentModelId }
4463
+ };
4464
+ }
4465
+ if (typeof rawModel !== "string") {
4466
+ throw new UnavailableSubagentModelError(String(rawModel), routing);
4467
+ }
4468
+ const selector = rawModel.trim();
4469
+ if (selector === "" || selector === "inherit") {
4470
+ normalized.model = routing.parentModelId;
4471
+ return {
4472
+ input: normalized,
4473
+ decision: { kind: "inherit", resolvedModelId: routing.parentModelId }
4474
+ };
4475
+ }
4476
+ const exposed = routing.models.find((model) => model.id === selector);
4477
+ if (exposed) {
4478
+ normalized.model = exposed.id;
4479
+ return {
4480
+ input: normalized,
4481
+ decision: { kind: "explicit", resolvedModelId: exposed.id }
4482
+ };
4483
+ }
4484
+ const compatible = routing.models.find((model) => model.compatibilityIds.includes(selector));
4485
+ if (compatible) {
4486
+ normalized.model = compatible.id;
4487
+ return {
4488
+ input: normalized,
4489
+ decision: {
4490
+ kind: "compatibility",
4491
+ requestedModelId: selector,
4492
+ resolvedModelId: compatible.id
4493
+ }
4494
+ };
4495
+ }
4496
+ if (CLAUDE_MODEL_FAMILY_SET.has(selector)) {
4497
+ const family = selector;
4498
+ const nativeModel = routing.models.find((model) => model.family === family);
4499
+ const resolvedModelId = nativeModel?.id ?? routing.parentModelId;
4500
+ normalized.model = resolvedModelId;
4501
+ return {
4502
+ input: normalized,
4503
+ decision: nativeModel ? { kind: "family", requestedModelId: family, resolvedModelId } : { kind: "family-fallback", requestedModelId: family, resolvedModelId }
4504
+ };
4505
+ }
4506
+ throw new UnavailableSubagentModelError(selector, routing);
4507
+ }
4508
+ function prepareClaudeAgentInput(input, routing) {
4509
+ const normalized = normalizeClaudeAgentInput(input, routing);
4510
+ const decision = normalized.decision;
4511
+ if (decision.kind === "fork") return normalized;
4512
+ if (!routing.registerSubagentRoute) return normalized;
4513
+ const prompt = normalized.input.prompt;
4514
+ if (typeof prompt !== "string") return normalized;
4515
+ const token = routing.registerSubagentRoute(decision.resolvedModelId);
4516
+ const clientInput = { ...normalized.input };
4517
+ const target = routing.models.find((model) => model.id === decision.resolvedModelId);
4518
+ if (target?.family) clientInput.model = target.family;
4519
+ else delete clientInput.model;
4520
+ clientInput.prompt = appendSubagentRouteMarker(prompt, token);
4521
+ return { input: clientInput, decision };
4522
+ }
4523
+ function augmentClaudeAgentTool(tool4, routing) {
4524
+ const inputSchema = isRecord(tool4.input_schema) ? tool4.input_schema : {};
4525
+ const properties = isRecord(inputSchema.properties) ? inputSchema.properties : {};
4526
+ const originalModel = isRecord(properties.model) ? properties.model : {};
4527
+ const smallCatalog = routing.models.length <= MAX_MODEL_CATALOG;
4528
+ const modelProperty = {
4529
+ ...originalModel,
4530
+ type: "string"
4531
+ };
4532
+ if (smallCatalog) {
4533
+ const originalEnum = Array.isArray(originalModel.enum) ? originalModel.enum.filter((value) => typeof value === "string") : CLAUDE_MODEL_FAMILIES;
4534
+ modelProperty.enum = [.../* @__PURE__ */ new Set([...originalEnum, ...routing.models.map((model) => model.id)])];
4535
+ } else {
4536
+ delete modelProperty.enum;
4537
+ }
4538
+ const guidance = smallCatalog ? `Relay AI subagent model routing (default: ${routing.parentModelId}). ` + routing.models.map((model) => `${model.displayName}: ${model.id}`).join("; ") : `Relay AI subagent model routing (default: ${routing.parentModelId}). Other explicit model values must be exact ids from the current session catalog.`;
4539
+ return {
4540
+ ...tool4,
4541
+ description: [tool4.description?.trim(), guidance].filter(Boolean).join("\n\n"),
4542
+ input_schema: {
4543
+ ...inputSchema,
4544
+ properties: {
4545
+ ...properties,
4546
+ model: modelProperty
4547
+ }
4548
+ }
4549
+ };
4550
+ }
4551
+
4312
4552
  // src/server/models.ts
4313
4553
  var CREATED_AT_ISO = "2025-01-01T00:00:00Z";
4314
4554
  var CREATED_AT_UNIX = 1735689600;
@@ -4362,6 +4602,52 @@ function exposedGatewayAliasId(model, opts) {
4362
4602
  const exposed = opts?.maskGatewayIds ? maskGatewayModelId(alias) : alias;
4363
4603
  return singleOneM ? `${stripOneMContextSuffix(exposed)}[1m]` : exposed;
4364
4604
  }
4605
+ function gatewayModelIdentity(model, models, opts) {
4606
+ const collisions = openAiIdCollisions(models);
4607
+ const ids = [];
4608
+ const modelIndex = models.indexOf(model);
4609
+ const firstBareIndex = models.findIndex((candidate) => candidate.id === model.id);
4610
+ if (modelIndex === firstBareIndex || modelIndex < 0) ids.push(model.id);
4611
+ const scopedId = openAiExposedId(model, collisions);
4612
+ if (scopedId !== model.id) ids.push(scopedId);
4613
+ const publicId = exposedGatewayAliasId(model, opts);
4614
+ if (publicId !== model.id) ids.push(publicId);
4615
+ const singleOneM = usesSingleOneMEntry(model, opts);
4616
+ if (singleOneM) {
4617
+ const bareModel = { ...model, id: stripOneMContextSuffix(model.id) };
4618
+ const rawBareAlias = gatewayAliasId(bareModel);
4619
+ const exposedBareAlias = opts?.maskGatewayIds ? maskGatewayModelId(rawBareAlias) : rawBareAlias;
4620
+ ids.push(
4621
+ stripOneMContextSuffix(model.id),
4622
+ rawBareAlias,
4623
+ `${rawBareAlias}[1m]`,
4624
+ exposedBareAlias,
4625
+ `${exposedBareAlias}[1m]`
4626
+ );
4627
+ }
4628
+ if (opts?.maskGatewayIds) {
4629
+ const rawAlias = gatewayAliasId(singleOneM ? { ...model, id: stripOneMContextSuffix(model.id) } : model);
4630
+ if (rawAlias !== publicId) ids.push(rawAlias);
4631
+ }
4632
+ return {
4633
+ publicId,
4634
+ compatibilityIds: [...new Set(ids)]
4635
+ };
4636
+ }
4637
+ function buildServerSubagentModelRouting(models, parentModel, opts) {
4638
+ const identities = models.map((model) => gatewayModelIdentity(model, models, opts));
4639
+ const parentIndex = models.indexOf(parentModel);
4640
+ const parentModelId = parentIndex >= 0 ? identities[parentIndex].publicId : exposedGatewayAliasId(parentModel, opts);
4641
+ return {
4642
+ parentModelId,
4643
+ models: models.map((model, index) => ({
4644
+ id: identities[index].publicId,
4645
+ compatibilityIds: identities[index].compatibilityIds,
4646
+ displayName: gatewayDisplayName(model, opts),
4647
+ family: model.modelFormat === "anthropic" ? claudeModelFamily(model.upstreamModelId ?? model.id) : void 0
4648
+ }))
4649
+ };
4650
+ }
4365
4651
  function gatewayDisplayName(model, opts) {
4366
4652
  const name = opts?.maskGatewayIds ? `${model.name} (${gatewayProviderLabel(model)})` : model.name;
4367
4653
  return usesSingleOneMEntry(model, opts) && !/\b1m$/i.test(name) ? `${name} 1M` : name;
@@ -4381,31 +4667,10 @@ function usesSingleOneMEntry(model, opts) {
4381
4667
  }
4382
4668
  function createGatewayModelCatalog(models, opts) {
4383
4669
  const byId = /* @__PURE__ */ new Map();
4384
- const collisions = openAiIdCollisions(models);
4385
4670
  for (const model of models) {
4386
- if (!byId.has(model.id)) byId.set(model.id, model);
4387
- const scopedId = openAiExposedId(model, collisions);
4388
- if (scopedId !== model.id) byId.set(scopedId, model);
4389
- const alias = exposedGatewayAliasId(model, opts);
4390
- if (alias !== model.id) byId.set(alias, model);
4391
- const singleOneM = usesSingleOneMEntry(model, opts);
4392
- if (singleOneM) {
4393
- const bareModel = { ...model, id: stripOneMContextSuffix(model.id) };
4394
- const rawBareAlias = gatewayAliasId(bareModel);
4395
- const exposedBareAlias = opts?.maskGatewayIds ? maskGatewayModelId(rawBareAlias) : rawBareAlias;
4396
- for (const compatibleId of [
4397
- stripOneMContextSuffix(model.id),
4398
- rawBareAlias,
4399
- `${rawBareAlias}[1m]`,
4400
- exposedBareAlias,
4401
- `${exposedBareAlias}[1m]`
4402
- ]) {
4403
- byId.set(compatibleId, model);
4404
- }
4405
- }
4406
- if (opts?.maskGatewayIds) {
4407
- const rawAlias = gatewayAliasId(singleOneM ? { ...model, id: stripOneMContextSuffix(model.id) } : model);
4408
- if (rawAlias !== alias) byId.set(rawAlias, model);
4671
+ const identity = gatewayModelIdentity(model, models, opts);
4672
+ for (const compatibleId of identity.compatibilityIds) {
4673
+ byId.set(compatibleId, model);
4409
4674
  }
4410
4675
  }
4411
4676
  return {
@@ -4605,10 +4870,10 @@ async function relayAnthropicMessages(res, messagesUrl, body, apiKey, clientWant
4605
4870
  }
4606
4871
 
4607
4872
  // src/antigravity/anthropic-to-cloudcode.ts
4608
- import { randomUUID as randomUUID3 } from "crypto";
4873
+ import { randomUUID as randomUUID4 } from "crypto";
4609
4874
 
4610
4875
  // src/antigravity/request-adapter.ts
4611
- import { randomUUID as randomUUID2 } from "crypto";
4876
+ import { randomUUID as randomUUID3 } from "crypto";
4612
4877
  import { tool, jsonSchema } from "ai";
4613
4878
 
4614
4879
  // src/proxy-shared.ts
@@ -4718,6 +4983,83 @@ function serializeToolResultContent(content) {
4718
4983
  }
4719
4984
 
4720
4985
  // src/antigravity/request-adapter.ts
4986
+ var UNSUPPORTED_VOICE_MESSAGE = "Voice transcription isn\u2019t supported by Relay AI yet. Please type your message. Your coding session remains active.";
4987
+ var OMITTED_VOICE_TEXT = "[Voice recording omitted because transcription is not supported by Relay AI.]";
4988
+ function isSupportedImage(part) {
4989
+ return part.inlineData?.mimeType.toLowerCase().startsWith("image/") ?? false;
4990
+ }
4991
+ function isUnsupportedInlineData(part) {
4992
+ return !!part.inlineData && !isSupportedImage(part);
4993
+ }
4994
+ function sanitizeUnsupportedInlineData(ccReq) {
4995
+ const contents = ccReq.request?.contents ?? [];
4996
+ let latestUserIndex = -1;
4997
+ for (let i = contents.length - 1; i >= 0; i--) {
4998
+ if (contents[i].role === "user") {
4999
+ latestUserIndex = i;
5000
+ break;
5001
+ }
5002
+ }
5003
+ let latestUserTurnHasUnsupportedMedia = false;
5004
+ const sanitizedContents = contents.map((message, index) => ({
5005
+ ...message,
5006
+ parts: message.parts.map((part) => {
5007
+ if (!isUnsupportedInlineData(part)) return part;
5008
+ if (index === latestUserIndex) latestUserTurnHasUnsupportedMedia = true;
5009
+ return { text: OMITTED_VOICE_TEXT };
5010
+ })
5011
+ }));
5012
+ return {
5013
+ request: {
5014
+ ...ccReq,
5015
+ request: {
5016
+ ...ccReq.request,
5017
+ contents: sanitizedContents
5018
+ }
5019
+ },
5020
+ latestUserTurnHasUnsupportedMedia
5021
+ };
5022
+ }
5023
+ function tracePartChars(part) {
5024
+ if (typeof part.text === "string") return part.text.length;
5025
+ if (part.type !== "tool-result") return void 0;
5026
+ const output = part.output;
5027
+ if (typeof output === "string") return output.length;
5028
+ if (output && typeof output === "object" && typeof output.value === "string") {
5029
+ return output.value.length;
5030
+ }
5031
+ try {
5032
+ return output === void 0 ? void 0 : JSON.stringify(output).length;
5033
+ } catch {
5034
+ return void 0;
5035
+ }
5036
+ }
5037
+ function summarizeSdkRequestForTrace(request) {
5038
+ const messages = request.messages.map((message) => {
5039
+ const content = message.content;
5040
+ if (typeof content === "string") {
5041
+ return { role: message.role, parts: [{ type: "text", chars: content.length }] };
5042
+ }
5043
+ const parts = Array.isArray(content) ? content.map((rawPart) => {
5044
+ const part = rawPart;
5045
+ const summary = {
5046
+ type: typeof part.type === "string" ? part.type : typeof rawPart
5047
+ };
5048
+ const chars = tracePartChars(part);
5049
+ if (chars !== void 0) summary.chars = chars;
5050
+ if (typeof part.toolName === "string") summary.toolName = part.toolName;
5051
+ if (typeof part.toolCallId === "string") summary.toolCallId = part.toolCallId;
5052
+ return summary;
5053
+ }) : [{ type: typeof content }];
5054
+ return { role: message.role, parts };
5055
+ });
5056
+ return {
5057
+ systemChars: request.system?.length ?? 0,
5058
+ messages,
5059
+ toolNames: Object.keys(request.tools ?? {}),
5060
+ ...request.toolChoice ? { toolChoice: request.toolChoice } : {}
5061
+ };
5062
+ }
4721
5063
  var JSON_SCHEMA_TYPES = /* @__PURE__ */ new Map([
4722
5064
  ["ARRAY", "array"],
4723
5065
  ["BOOLEAN", "boolean"],
@@ -4837,13 +5179,17 @@ function translateRequest(ccReq, options = {}) {
4837
5179
  }
4838
5180
  }
4839
5181
  } else if (part.inlineData) {
4840
- contentParts.push({
4841
- type: "image",
4842
- image: part.inlineData.data,
4843
- mimeType: part.inlineData.mimeType
4844
- });
5182
+ if (isSupportedImage(part)) {
5183
+ contentParts.push({
5184
+ type: "image",
5185
+ image: part.inlineData.data,
5186
+ mimeType: part.inlineData.mimeType
5187
+ });
5188
+ } else {
5189
+ contentParts.push({ type: "text", text: OMITTED_VOICE_TEXT });
5190
+ }
4845
5191
  } else if (part.functionCall) {
4846
- const id = "call_" + randomUUID2().replace(/-/g, "");
5192
+ const id = "call_" + randomUUID3().replace(/-/g, "");
4847
5193
  const name = part.functionCall.name;
4848
5194
  if (!nameToIdList.has(name)) nameToIdList.set(name, []);
4849
5195
  nameToIdList.get(name).push(id);
@@ -4856,7 +5202,7 @@ function translateRequest(ccReq, options = {}) {
4856
5202
  } else if (part.functionResponse) {
4857
5203
  const name = part.functionResponse.name;
4858
5204
  const idList = nameToIdList.get(name) || [];
4859
- const id = idList.shift() || "call_" + randomUUID2().replace(/-/g, "");
5205
+ const id = idList.shift() || "call_" + randomUUID3().replace(/-/g, "");
4860
5206
  toolResults.push({
4861
5207
  type: "tool-result",
4862
5208
  toolCallId: id,
@@ -5065,7 +5411,7 @@ function anthropicToCloudCode(body, realModelId, projectId) {
5065
5411
  }
5066
5412
  return {
5067
5413
  project: projectId,
5068
- requestId: randomUUID3(),
5414
+ requestId: randomUUID4(),
5069
5415
  model: realModelId,
5070
5416
  userAgent: ANTIGRAVITY_USER_AGENT2,
5071
5417
  requestType: "agent",
@@ -5075,7 +5421,7 @@ function anthropicToCloudCode(body, realModelId, projectId) {
5075
5421
  }
5076
5422
 
5077
5423
  // src/antigravity/cloudcode-to-anthropic.ts
5078
- import { randomUUID as randomUUID4 } from "crypto";
5424
+ import { randomUUID as randomUUID5 } from "crypto";
5079
5425
  function writeEvent(res, event, data) {
5080
5426
  res.write(`event: ${event}
5081
5427
  data: ${JSON.stringify(data)}
@@ -5165,7 +5511,7 @@ function closeBlock(res, state) {
5165
5511
  }
5166
5512
  async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
5167
5513
  const state = {
5168
- messageId: `msg_${randomUUID4().replace(/-/g, "").slice(0, 24)}`,
5514
+ messageId: `msg_${randomUUID5().replace(/-/g, "").slice(0, 24)}`,
5169
5515
  model,
5170
5516
  blockIdx: 0,
5171
5517
  textBlockOpen: false,
@@ -5254,7 +5600,7 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
5254
5600
  closeBlock(res, state);
5255
5601
  }
5256
5602
  for (const tc of state.toolCalls) {
5257
- const rawToolId = `toolu_${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
5603
+ const rawToolId = `toolu_${randomUUID5().replace(/-/g, "").slice(0, 16)}`;
5258
5604
  const toolId = encodeToolUseId(rawToolId, tc.signature);
5259
5605
  writeEvent(res, "content_block_start", {
5260
5606
  type: "content_block_start",
@@ -5305,7 +5651,7 @@ async function streamCloudCodeToAnthropic(res, upstreamRes, model, log7) {
5305
5651
  }
5306
5652
  async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
5307
5653
  const text4 = await upstreamRes.text();
5308
- const messageId = `msg_${randomUUID4().replace(/-/g, "").slice(0, 24)}`;
5654
+ const messageId = `msg_${randomUUID5().replace(/-/g, "").slice(0, 24)}`;
5309
5655
  const content = [];
5310
5656
  let stopReason = "end_turn";
5311
5657
  let inputTokens = 0;
@@ -5334,7 +5680,7 @@ async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
5334
5680
  else content.push({ type: "text", text: part.text });
5335
5681
  } else if (part.functionCall && typeof part.functionCall === "object") {
5336
5682
  const fc = part.functionCall;
5337
- const rawToolId = `toolu_${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
5683
+ const rawToolId = `toolu_${randomUUID5().replace(/-/g, "").slice(0, 16)}`;
5338
5684
  content.push({
5339
5685
  type: "tool_use",
5340
5686
  id: encodeToolUseId(rawToolId, signature ?? pendingThoughtSignature),
@@ -5367,7 +5713,7 @@ async function collectCloudCodeToAnthropic(upstreamRes, model, log7) {
5367
5713
  }
5368
5714
 
5369
5715
  // src/proxy.ts
5370
- import { randomUUID as randomUUID5 } from "crypto";
5716
+ import { randomUUID as randomUUID6 } from "crypto";
5371
5717
 
5372
5718
  // src/sdk-adapter.ts
5373
5719
  import { streamText, generateText, tool as tool2, jsonSchema as jsonSchema2 } from "ai";
@@ -5430,6 +5776,48 @@ function resolveUpstreamTools(tools, messages) {
5430
5776
  }
5431
5777
 
5432
5778
  // src/codex/upstream-error.ts
5779
+ var TRACE_FIELD_LIMIT = 4e3;
5780
+ function clipTraceField(value) {
5781
+ return value.length <= TRACE_FIELD_LIMIT ? value : `${value.slice(0, TRACE_FIELD_LIMIT)}\u2026`;
5782
+ }
5783
+ function safeUpstreamErrorFields(err, includeCause) {
5784
+ if (!err || typeof err !== "object") {
5785
+ return { message: clipTraceField(String(err)) };
5786
+ }
5787
+ const rec = err;
5788
+ const result = {};
5789
+ if (rec.name) result.name = rec.name;
5790
+ if (rec.message) result.message = clipTraceField(rec.message);
5791
+ if (rec.statusCode !== void 0) result.statusCode = rec.statusCode;
5792
+ if (rec.responseBody) result.responseBody = clipTraceField(rec.responseBody);
5793
+ if (rec.data?.error) {
5794
+ result.data = {
5795
+ error: {
5796
+ ...rec.data.error.type ? { type: rec.data.error.type } : {},
5797
+ ...rec.data.error.message ? { message: clipTraceField(rec.data.error.message) } : {}
5798
+ }
5799
+ };
5800
+ }
5801
+ if (rec.lastError) {
5802
+ result.lastError = {
5803
+ ...rec.lastError.message ? { message: clipTraceField(rec.lastError.message) } : {},
5804
+ ...rec.lastError.statusCode !== void 0 ? { statusCode: rec.lastError.statusCode } : {}
5805
+ };
5806
+ }
5807
+ if (rec.errors?.length) {
5808
+ result.errors = rec.errors.map((item) => ({
5809
+ ...item.message ? { message: clipTraceField(item.message) } : {},
5810
+ ...item.statusCode !== void 0 ? { statusCode: item.statusCode } : {}
5811
+ }));
5812
+ }
5813
+ if (includeCause && rec.cause !== void 0) {
5814
+ result.cause = safeUpstreamErrorFields(rec.cause, false);
5815
+ }
5816
+ return result;
5817
+ }
5818
+ function formatUpstreamErrorTrace(err) {
5819
+ return JSON.stringify(safeUpstreamErrorFields(err, true));
5820
+ }
5433
5821
  function formatUpstreamError(err) {
5434
5822
  if (!err || typeof err !== "object") return "Upstream model request failed.";
5435
5823
  const rec = err;
@@ -5658,6 +6046,17 @@ function translateRequest2(body, npm, options) {
5658
6046
  if (options?.maxTools !== void 0 && upstreamTools.length > options.maxTools) {
5659
6047
  upstreamTools = upstreamTools.slice(0, options.maxTools);
5660
6048
  }
6049
+ let responseSubagentRouting;
6050
+ if (options?.subagentRouting) {
6051
+ const agentIndex = upstreamTools.findIndex((toolDefinition) => isClaudeAgentTool(toolDefinition));
6052
+ if (agentIndex >= 0) {
6053
+ upstreamTools = upstreamTools.map((toolDefinition, index) => index === agentIndex ? augmentClaudeAgentTool(
6054
+ toolDefinition,
6055
+ options.subagentRouting
6056
+ ) : toolDefinition);
6057
+ responseSubagentRouting = options.subagentRouting;
6058
+ }
6059
+ }
5661
6060
  const effort = anthropicEffortFromRequest(body) ?? options?.defaultEffort;
5662
6061
  let providerOptions = deepMergeProviderOptions(
5663
6062
  thinkingProviderOptions(npm),
@@ -5675,16 +6074,22 @@ function translateRequest2(body, npm, options) {
5675
6074
  toolChoice: translateToolChoice(body.tool_choice),
5676
6075
  maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
5677
6076
  temperature: body.temperature,
5678
- providerOptions
6077
+ providerOptions,
6078
+ subagentRouting: responseSubagentRouting
5679
6079
  };
5680
6080
  }
5681
- async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedInputTokens = 0) {
6081
+ function logSubagentDecision(log7, decision) {
6082
+ if (!log7 || decision.kind === "fork" || decision.kind === "explicit") return;
6083
+ log7(() => decision.kind === "family-fallback" ? `sdk Agent model "${decision.requestedModelId}" unavailable; using parent ${decision.resolvedModelId}` : `sdk Agent model ${decision.kind}: ${"requestedModelId" in decision ? `${decision.requestedModelId} -> ` : ""}${decision.resolvedModelId}`);
6084
+ }
6085
+ async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedInputTokens = 0, subagentRouting) {
5682
6086
  const messageId = "msg_" + Date.now();
5683
6087
  let blockIndex = -1;
5684
6088
  let started = false;
5685
6089
  let openType = null;
5686
6090
  let pendingThinkingSig;
5687
6091
  const idToBlock = /* @__PURE__ */ new Map();
6092
+ const bufferedAgentCalls = /* @__PURE__ */ new Map();
5688
6093
  let finishReason = "end_turn";
5689
6094
  let usage = { input_tokens: estimatedInputTokens, output_tokens: 0 };
5690
6095
  const emit = (event, data) => write(sseChunk(event, data));
@@ -5767,9 +6172,13 @@ async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedI
5767
6172
  input: {}
5768
6173
  });
5769
6174
  idToBlock.set(part.id ?? "", blockIndex);
6175
+ if (subagentRouting && part.toolName === "Agent") {
6176
+ bufferedAgentCalls.set(part.id ?? "", { blockIndex });
6177
+ }
5770
6178
  break;
5771
6179
  }
5772
6180
  case "tool-input-delta":
6181
+ if (bufferedAgentCalls.has(part.id ?? "")) break;
5773
6182
  emit("content_block_delta", {
5774
6183
  type: "content_block_delta",
5775
6184
  index: idToBlock.get(part.id ?? "") ?? blockIndex,
@@ -5780,11 +6189,53 @@ async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedI
5780
6189
  break;
5781
6190
  case "tool-call": {
5782
6191
  finishReason = "tool_use";
5783
- if (!idToBlock.has(part.toolCallId ?? "") && openType !== "tool") {
6192
+ const toolCallId = part.toolCallId ?? "";
6193
+ if (subagentRouting && part.toolName === "Agent") {
6194
+ try {
6195
+ const normalized = prepareClaudeAgentInput(part.input, subagentRouting);
6196
+ logSubagentDecision(log7, normalized.decision);
6197
+ const buffered = bufferedAgentCalls.get(toolCallId);
6198
+ if (!buffered && !idToBlock.has(toolCallId)) {
6199
+ const sig = grabRoundTripSignature(part);
6200
+ openBlock("tool", {
6201
+ type: "tool_use",
6202
+ id: encodeToolUseId(toolCallId, sig),
6203
+ name: part.toolName,
6204
+ input: {}
6205
+ });
6206
+ idToBlock.set(toolCallId, blockIndex);
6207
+ }
6208
+ emit("content_block_delta", {
6209
+ type: "content_block_delta",
6210
+ index: buffered?.blockIndex ?? idToBlock.get(toolCallId) ?? blockIndex,
6211
+ delta: {
6212
+ type: "input_json_delta",
6213
+ partial_json: JSON.stringify(stripNullInputs(normalized.input))
6214
+ }
6215
+ });
6216
+ bufferedAgentCalls.delete(toolCallId);
6217
+ } catch (error) {
6218
+ if (error instanceof UnavailableSubagentModelError) {
6219
+ bufferedAgentCalls.delete(toolCallId);
6220
+ closeOpen();
6221
+ emit("error", {
6222
+ type: "error",
6223
+ error: {
6224
+ type: anthropicErrorType(error.statusCode),
6225
+ message: error.message
6226
+ }
6227
+ });
6228
+ return;
6229
+ }
6230
+ throw error;
6231
+ }
6232
+ break;
6233
+ }
6234
+ if (!idToBlock.has(toolCallId) && openType !== "tool") {
5784
6235
  const sig = grabRoundTripSignature(part);
5785
6236
  openBlock("tool", {
5786
6237
  type: "tool_use",
5787
- id: encodeToolUseId(part.toolCallId ?? "", sig),
6238
+ id: encodeToolUseId(toolCallId, sig),
5788
6239
  name: part.toolName,
5789
6240
  input: {}
5790
6241
  });
@@ -5812,6 +6263,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedI
5812
6263
  const errMsg = e?.message || (typeof part.error === "string" ? part.error : JSON.stringify(e?.data ?? part.error));
5813
6264
  const errorType = anthropicErrorType(upstreamHttpStatus(part.error, errMsg));
5814
6265
  log7?.(() => `sdk stream error (${errorType}): ${errMsg}`);
6266
+ bufferedAgentCalls.clear();
5815
6267
  closeOpen();
5816
6268
  emit("error", { type: "error", error: { type: errorType, message: errMsg } });
5817
6269
  return;
@@ -5826,7 +6278,8 @@ async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedI
5826
6278
  emit("message_stop", { type: "message_stop" });
5827
6279
  }
5828
6280
  async function streamAnthropicResponse(model, params, modelId, write, log7, estimatedInputTokens = 0) {
5829
- const result = streamText({ model, ...params, onError: () => {
6281
+ const { subagentRouting, ...providerParams } = params;
6282
+ const result = streamText({ model, ...providerParams, onError: () => {
5830
6283
  } });
5831
6284
  Promise.resolve(result.text).catch(() => {
5832
6285
  });
@@ -5843,22 +6296,24 @@ async function streamAnthropicResponse(model, params, modelId, write, log7, esti
5843
6296
  modelId,
5844
6297
  write,
5845
6298
  log7,
5846
- estimatedInputTokens
6299
+ estimatedInputTokens,
6300
+ subagentRouting
5847
6301
  );
5848
6302
  }
5849
6303
  async function generateAnthropicResponse(model, params, modelId, options) {
6304
+ const { subagentRouting, ...providerParams } = params;
5850
6305
  let text4;
5851
6306
  let toolCalls;
5852
6307
  let finishReason;
5853
6308
  let usage;
5854
6309
  if (options?.forceStream) {
5855
- const r = streamText({ model, ...params, onError: () => {
6310
+ const r = streamText({ model, ...providerParams, onError: () => {
5856
6311
  } });
5857
6312
  Promise.resolve(r.toolResults).catch(() => {
5858
6313
  });
5859
6314
  [text4, toolCalls, finishReason, usage] = await Promise.all([r.text, r.toolCalls, r.finishReason, r.usage]);
5860
6315
  } else {
5861
- const r = await generateText({ model, ...params });
6316
+ const r = await generateText({ model, ...providerParams });
5862
6317
  ({ text: text4, toolCalls, finishReason, usage } = r);
5863
6318
  }
5864
6319
  return {
@@ -5868,12 +6323,20 @@ async function generateAnthropicResponse(model, params, modelId, options) {
5868
6323
  model: modelId,
5869
6324
  content: [
5870
6325
  ...text4 ? [{ type: "text", text: text4 }] : [],
5871
- ...toolCalls.map((tc) => ({
5872
- type: "tool_use",
5873
- id: encodeToolUseId(tc.toolCallId, grabRoundTripSignature(tc)),
5874
- name: tc.toolName,
5875
- input: stripNullInputs(tc.input)
5876
- }))
6326
+ ...toolCalls.map((tc) => {
6327
+ let input = tc.input;
6328
+ if (subagentRouting && tc.toolName === "Agent") {
6329
+ const normalized = prepareClaudeAgentInput(tc.input, subagentRouting);
6330
+ logSubagentDecision(options?.log, normalized.decision);
6331
+ input = normalized.input;
6332
+ }
6333
+ return {
6334
+ type: "tool_use",
6335
+ id: encodeToolUseId(tc.toolCallId, grabRoundTripSignature(tc)),
6336
+ name: tc.toolName,
6337
+ input: stripNullInputs(input)
6338
+ };
6339
+ })
5877
6340
  ],
5878
6341
  stop_reason: finishReason === "tool-calls" ? "tool_use" : "end_turn",
5879
6342
  usage: { input_tokens: usage?.inputTokens ?? 0, output_tokens: usage?.outputTokens ?? 0 }
@@ -5920,6 +6383,21 @@ function aliasModelId(realId, providerId) {
5920
6383
  const sanitized = providerId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5921
6384
  return `anthropic-${sanitized}__${realId}`;
5922
6385
  }
6386
+ function buildProxySubagentModelRouting(routes, parentRoute) {
6387
+ const publicId = (route) => route.gatewayAliasId ?? route.aliasId;
6388
+ return {
6389
+ parentModelId: publicId(parentRoute),
6390
+ models: routes.map((route) => ({
6391
+ id: publicId(route),
6392
+ compatibilityIds: [.../* @__PURE__ */ new Set([
6393
+ ...routeLookupIds(route.aliasId),
6394
+ ...route.gatewayAliasId ? routeLookupIds(route.gatewayAliasId) : []
6395
+ ])],
6396
+ displayName: route.displayName,
6397
+ family: route.modelFormat === "anthropic" ? claudeModelFamily(route.realModelId) : void 0
6398
+ }))
6399
+ };
6400
+ }
5923
6401
  function lookupRoute(byAlias, id) {
5924
6402
  for (const key of routeLookupIds(id)) {
5925
6403
  const route = byAlias.get(key);
@@ -5928,13 +6406,14 @@ function lookupRoute(byAlias, id) {
5928
6406
  return void 0;
5929
6407
  }
5930
6408
  function startProxyCatalog(routes, defaultAliasId, debug = false) {
5931
- const proxyToken = randomUUID5();
6409
+ const proxyToken = randomUUID6();
5932
6410
  silenceSdkWarnings();
5933
6411
  if (routes.length === 0) {
5934
6412
  return Promise.reject(new Error("Proxy catalog requires at least one route"));
5935
6413
  }
5936
6414
  const byAlias = new Map(routes.map((r) => [r.aliasId, r]));
5937
6415
  const defaultRoute = byAlias.get(defaultAliasId) ?? routes[0];
6416
+ const subagentRouteRegistry = new SubagentRouteRegistry();
5938
6417
  const plog = makeProxyLog(debug);
5939
6418
  const onRejection = (reason) => {
5940
6419
  plog(() => `Unhandled Rejection: ${reason instanceof Error ? reason.stack || reason.message : String(reason)}`);
@@ -5988,9 +6467,12 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
5988
6467
  anthropicError(res, 400, "Invalid JSON body");
5989
6468
  return;
5990
6469
  }
6470
+ const correlatedSubagent = subagentRouteRegistry.consume(req.headers, anthropicBody);
6471
+ if (correlatedSubagent) anthropicBody = correlatedSubagent.body;
5991
6472
  const originalModel = anthropicBody.model;
5992
6473
  const clientWantsStream = Boolean(anthropicBody.stream);
5993
- const route = lookupRoute(byAlias, originalModel) ?? defaultRoute;
6474
+ const correlatedRoute = correlatedSubagent ? routes.find((candidate) => (candidate.gatewayAliasId ?? candidate.aliasId) === correlatedSubagent.modelId) : void 0;
6475
+ const route = correlatedRoute ?? lookupRoute(byAlias, originalModel) ?? defaultRoute;
5994
6476
  const apiKey = route.apiKey;
5995
6477
  const upstreamUrl = route.upstreamUrl;
5996
6478
  plog(
@@ -6046,10 +6528,16 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
6046
6528
  }
6047
6529
  if (usesSdkAdapter) {
6048
6530
  const openAiOAuth = route.npm === "@ai-sdk/openai" && route.authType === "oauth";
6531
+ const subagentRouting = buildProxySubagentModelRouting(routes, route);
6532
+ const sessionId = extractClaudeSessionId(req.headers, anthropicBody);
6533
+ if (sessionId) {
6534
+ subagentRouting.registerSubagentRoute = (modelId) => subagentRouteRegistry.register(sessionId, modelId);
6535
+ }
6049
6536
  const params = translateRequest2(anthropicBody, route.npm, {
6050
6537
  openAiOAuth,
6051
6538
  maxTools: maxToolsForNpm(route.npm),
6052
6539
  onDebug: (msg) => plog(() => msg),
6540
+ subagentRouting,
6053
6541
  reasoningMetadata: {
6054
6542
  providerId: route.providerId,
6055
6543
  apiBaseUrl: route.baseURL,
@@ -6097,7 +6585,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
6097
6585
  model,
6098
6586
  params,
6099
6587
  originalModel,
6100
- { forceStream: openAiOAuth }
6588
+ { forceStream: openAiOAuth, log: plog }
6101
6589
  );
6102
6590
  sendJson(res, 200, anthropicResponse);
6103
6591
  }
@@ -7838,6 +8326,14 @@ function injectRelayModels(fixture, routes, templateKey) {
7838
8326
  }]
7839
8327
  }
7840
8328
  ];
8329
+ for (const entry of Object.values(result.models)) {
8330
+ const mimeTypes = entry.supportedMimeTypes;
8331
+ if (!mimeTypes || typeof mimeTypes !== "object" || Array.isArray(mimeTypes)) continue;
8332
+ entry.supportedMimeTypes = Object.fromEntries(
8333
+ Object.entries(mimeTypes).filter(([mime]) => !mime.toLowerCase().includes("audio/"))
8334
+ );
8335
+ }
8336
+ result.audioTranscriptionModelIds = [];
7841
8337
  return result;
7842
8338
  }
7843
8339
  if (!result.agentModelSorts?.[0]?.groups?.[0]) {
@@ -9833,8 +10329,9 @@ async function startServer(options) {
9833
10329
  silenceSdkWarnings();
9834
10330
  const languageModelCache = /* @__PURE__ */ new Map();
9835
10331
  const plog = makeServerLog(options.debugLogPath);
10332
+ const subagentRouteRegistry = new SubagentRouteRegistry();
9836
10333
  const server = createServer2((req, res) => {
9837
- void routeRequest(req, res, options, languageModelCache, plog);
10334
+ void routeRequest(req, res, options, languageModelCache, plog, subagentRouteRegistry);
9838
10335
  });
9839
10336
  await new Promise((resolve, reject) => {
9840
10337
  server.once("error", reject);
@@ -9857,7 +10354,7 @@ async function startServer(options) {
9857
10354
  })
9858
10355
  };
9859
10356
  }
9860
- async function routeRequest(req, res, options, modelCache, plog) {
10357
+ async function routeRequest(req, res, options, modelCache, plog, subagentRouteRegistry) {
9861
10358
  try {
9862
10359
  const pathname = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`).pathname;
9863
10360
  plog(`${req.method} ${pathname}`);
@@ -9882,7 +10379,7 @@ async function routeRequest(req, res, options, modelCache, plog) {
9882
10379
  return;
9883
10380
  }
9884
10381
  if (req.method === "POST" && pathname === "/anthropic/v1/messages") {
9885
- await handleAnthropicMessages(req, res, options, modelCache, plog);
10382
+ await handleAnthropicMessages(req, res, options, modelCache, plog, subagentRouteRegistry);
9886
10383
  return;
9887
10384
  }
9888
10385
  if (req.method === "POST" && pathname === "/openai/v1/chat/completions") {
@@ -9894,13 +10391,16 @@ async function routeRequest(req, res, options, modelCache, plog) {
9894
10391
  sendJson(res, 500, { error: { message: err instanceof Error ? err.message : String(err) } });
9895
10392
  }
9896
10393
  }
9897
- async function handleAnthropicMessages(req, res, options, modelCache, plog) {
9898
- const body = await readJson(req);
10394
+ async function handleAnthropicMessages(req, res, options, modelCache, plog, subagentRouteRegistry) {
10395
+ let body = await readJson(req);
9899
10396
  if (!body) {
9900
10397
  sendJson(res, 400, { error: { message: "Invalid JSON body" } });
9901
10398
  return;
9902
10399
  }
9903
- const model = lookupModel(res, options.catalog, body.model);
10400
+ const correlatedSubagent = subagentRouteRegistry.consume(req.headers, body);
10401
+ if (correlatedSubagent) body = correlatedSubagent.body;
10402
+ const requestedModelId = correlatedSubagent?.modelId ?? body.model;
10403
+ const model = lookupModel(res, options.catalog, requestedModelId);
9904
10404
  if (!model) {
9905
10405
  plog(`model not found: ${body.model}`);
9906
10406
  return;
@@ -9959,10 +10459,20 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
9959
10459
  if (npmMaxTools !== void 0 && toolCount > npmMaxTools) {
9960
10460
  plog(`tools truncated: ${toolCount} \u2192 ${npmMaxTools} (provider limit)`);
9961
10461
  }
10462
+ const subagentRouting = buildServerSubagentModelRouting(
10463
+ options.catalog.list(),
10464
+ model,
10465
+ options.gateway
10466
+ );
10467
+ const sessionId = extractClaudeSessionId(req.headers, body);
10468
+ if (sessionId) {
10469
+ subagentRouting.registerSubagentRoute = (modelId) => subagentRouteRegistry.register(sessionId, modelId);
10470
+ }
9962
10471
  const params = translateRequest2(body, model.npm, {
9963
10472
  defaultEffort: anthropicEffortFromRequest(body) ? void 0 : model.defaultEffort,
9964
10473
  openAiOAuth: model.npm === "@ai-sdk/openai" && model.authType === "oauth",
9965
10474
  onDebug: plog,
10475
+ subagentRouting,
9966
10476
  reasoningMetadata: {
9967
10477
  providerId: model.providerId,
9968
10478
  apiBaseUrl: model.apiBaseUrl,
@@ -9988,12 +10498,17 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
9988
10498
  params,
9989
10499
  responseModelId,
9990
10500
  (chunk) => res.write(chunk),
9991
- void 0,
10501
+ plog,
9992
10502
  estimateAnthropicInputTokens(body)
9993
10503
  );
9994
10504
  res.end();
9995
10505
  } else {
9996
- const anthropicResponse = await generateAnthropicResponse(languageModel, params, responseModelId);
10506
+ const anthropicResponse = await generateAnthropicResponse(
10507
+ languageModel,
10508
+ params,
10509
+ responseModelId,
10510
+ { log: plog }
10511
+ );
9997
10512
  sendJson(res, 200, anthropicResponse);
9998
10513
  }
9999
10514
  } catch (err) {
@@ -11973,6 +12488,7 @@ export {
11973
12488
  getGeminiProxyDebugLogPath,
11974
12489
  getUiDebugLogPath,
11975
12490
  getServerDebugLogPath,
12491
+ getAntigravityDebugLogPath,
11976
12492
  makeTraceLogger,
11977
12493
  writeSecureLogLine,
11978
12494
  printTraceLog,
@@ -12004,7 +12520,11 @@ export {
12004
12520
  splitToolUseId,
12005
12521
  encodeToolUseId,
12006
12522
  serializeToolResultContent,
12523
+ UNSUPPORTED_VOICE_MESSAGE,
12524
+ sanitizeUnsupportedInlineData,
12525
+ summarizeSdkRequestForTrace,
12007
12526
  translateRequest,
12527
+ formatUpstreamErrorTrace,
12008
12528
  formatUpstreamError,
12009
12529
  upstreamHttpStatus,
12010
12530
  aliasModelId,
@@ -12071,4 +12591,4 @@ export {
12071
12591
  supportsClaudeTransparentMode,
12072
12592
  buildHttpProxyRoutes
12073
12593
  };
12074
- //# sourceMappingURL=chunk-EUY2MVOS.js.map
12594
+ //# sourceMappingURL=chunk-GHSURQOK.js.map