opencode-anthropic-multi-account 0.2.17 → 0.2.19

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/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Plugin } from '@opencode-ai/plugin';
2
2
 
3
3
  declare const ClaudeMultiAuthPlugin: Plugin;
4
+ declare function setProviderModelsObserverForTest(observer: ((models: Record<string, unknown>) => void) | null): void;
5
+ declare function resetProviderModelsObserverForTest(): void;
4
6
 
5
- export { ClaudeMultiAuthPlugin };
7
+ export { ClaudeMultiAuthPlugin, resetProviderModelsObserverForTest, setProviderModelsObserverForTest };
package/dist/index.js CHANGED
@@ -1529,8 +1529,52 @@ function loadClaudeIdentity() {
1529
1529
 
1530
1530
  // src/upstream-request.ts
1531
1531
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
1532
+
1533
+ // src/model-capabilities.ts
1534
+ var runtimeModelCapabilities = /* @__PURE__ */ new Map();
1535
+ function isRecord(value) {
1536
+ return typeof value === "object" && value !== null;
1537
+ }
1538
+ function readNumber(value) {
1539
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1540
+ }
1541
+ function readBoolean(value) {
1542
+ return typeof value === "boolean" ? value : void 0;
1543
+ }
1544
+ function normalizeModelId(modelId) {
1545
+ const trimmed = modelId.trim().toLowerCase();
1546
+ const slashIndex = trimmed.indexOf("/");
1547
+ return slashIndex >= 0 ? trimmed.slice(slashIndex + 1) : trimmed;
1548
+ }
1549
+ function readLimitOutput(raw) {
1550
+ const limit = isRecord(raw.limit) ? raw.limit : void 0;
1551
+ const capabilityLimit = isRecord(raw.capabilities) && isRecord(raw.capabilities.limit) ? raw.capabilities.limit : void 0;
1552
+ return readNumber(limit?.output) ?? readNumber(capabilityLimit?.output);
1553
+ }
1554
+ function readThinkingSupport(raw) {
1555
+ return readBoolean(raw.reasoning) ?? readBoolean(raw.thinking) ?? readBoolean(raw.supportsThinking) ?? (isRecord(raw.capabilities) ? readBoolean(raw.capabilities.reasoning) ?? readBoolean(raw.capabilities.thinking) ?? readBoolean(raw.capabilities.supportsThinking) : void 0);
1556
+ }
1557
+ function ingestProviderModelsCapabilities(models) {
1558
+ runtimeModelCapabilities.clear();
1559
+ for (const [key, value] of Object.entries(models)) {
1560
+ if (!isRecord(value)) {
1561
+ continue;
1562
+ }
1563
+ const resolvedId = typeof value.id === "string" ? value.id : key;
1564
+ const capability = {
1565
+ maxOutputTokens: readLimitOutput(value),
1566
+ supportsThinking: readThinkingSupport(value)
1567
+ };
1568
+ runtimeModelCapabilities.set(normalizeModelId(resolvedId), capability);
1569
+ runtimeModelCapabilities.set(normalizeModelId(key), capability);
1570
+ }
1571
+ }
1572
+ function getRuntimeModelCapability(modelId) {
1573
+ return runtimeModelCapabilities.get(normalizeModelId(modelId));
1574
+ }
1575
+
1576
+ // src/upstream-request.ts
1532
1577
  var BILLING_SEED = "59cf53e54c78";
1533
- var DEFAULT_CC_VERSION = "2.1.100";
1534
1578
  var SESSION_IDLE_ROTATE_MS = 15 * 60 * 1e3;
1535
1579
  var MAX_TOOL_RESULT_TEXT_LENGTH = 30 * 1024;
1536
1580
  var TRUNCATION_SUFFIX = "[...truncated]";
@@ -1587,7 +1631,7 @@ function getActiveSessionId() {
1587
1631
  function getUpstreamSessionId() {
1588
1632
  return getActiveSessionId();
1589
1633
  }
1590
- function isRecord(value) {
1634
+ function isRecord2(value) {
1591
1635
  return typeof value === "object" && value !== null;
1592
1636
  }
1593
1637
  function cloneBody(value) {
@@ -1611,7 +1655,7 @@ function stripCacheControl(value) {
1611
1655
  }
1612
1656
  return;
1613
1657
  }
1614
- if (!isRecord(value)) {
1658
+ if (!isRecord2(value)) {
1615
1659
  return;
1616
1660
  }
1617
1661
  delete value.cache_control;
@@ -1633,11 +1677,15 @@ function sanitizeMessageBlock(block) {
1633
1677
  if (!Array.isArray(block.content)) {
1634
1678
  return;
1635
1679
  }
1636
- for (const item of block.content) {
1637
- if (isRecord(item) && typeof item.text === "string") {
1638
- item.text = truncateToolResultText(sanitizeAndScrubText(item.text));
1680
+ block.content = block.content.map((item) => {
1681
+ if (isRecord2(item) && typeof item.text === "string") {
1682
+ return {
1683
+ ...item,
1684
+ text: truncateToolResultText(sanitizeAndScrubText(item.text))
1685
+ };
1639
1686
  }
1640
- }
1687
+ return item;
1688
+ }).filter((item) => !isRecord2(item) || typeof item.text !== "string" || item.text.trim().length > 0);
1641
1689
  }
1642
1690
  function stripAssistantThinkingBlocks(messages) {
1643
1691
  for (const message of messages) {
@@ -1655,9 +1703,12 @@ function hasMeaningfulContent(content) {
1655
1703
  return false;
1656
1704
  }
1657
1705
  return content.some((block) => {
1658
- if (!isRecord(block)) {
1706
+ if (!isRecord2(block)) {
1659
1707
  return false;
1660
1708
  }
1709
+ if (block.type === "tool_use") {
1710
+ return true;
1711
+ }
1661
1712
  if (typeof block.text === "string" && block.text.trim().length > 0) {
1662
1713
  return true;
1663
1714
  }
@@ -1676,6 +1727,79 @@ function trimTrailingEmptyTurns(messages) {
1676
1727
  messages.pop();
1677
1728
  }
1678
1729
  }
1730
+ function compactMessageContent(messages) {
1731
+ for (const message of messages) {
1732
+ if (!Array.isArray(message.content)) {
1733
+ continue;
1734
+ }
1735
+ message.content = message.content.filter((block) => {
1736
+ if (!isRecord2(block)) {
1737
+ return false;
1738
+ }
1739
+ if (block.type === "text") {
1740
+ return typeof block.text !== "string" || block.text.trim().length > 0;
1741
+ }
1742
+ if (block.type === "tool_result" && Array.isArray(block.content)) {
1743
+ return block.content.length > 0;
1744
+ }
1745
+ return true;
1746
+ });
1747
+ }
1748
+ }
1749
+ function stripUnsupportedSamplingFields(body) {
1750
+ delete body.temperature;
1751
+ delete body.top_p;
1752
+ delete body.top_k;
1753
+ }
1754
+ function stripThinkingControlFields(body) {
1755
+ delete body.thinking;
1756
+ delete body.context_management;
1757
+ delete body.output_config;
1758
+ }
1759
+ var ADAPTIVE_THINKING_MODEL_MATCHERS = [
1760
+ (modelId) => modelId.includes("claude-sonnet-4-6") || modelId.includes("claude-sonnet-4.6"),
1761
+ (modelId) => modelId.includes("claude-opus-4-6") || modelId.includes("claude-opus-4.6"),
1762
+ (modelId) => /claude-opus-4[-._]([7-9]|\d{2,})/.test(modelId)
1763
+ ];
1764
+ var LARGE_OUTPUT_MODEL_MATCHERS = [
1765
+ (modelId) => modelId.includes("claude-opus-4-6") || modelId.includes("claude-opus-4.6"),
1766
+ (modelId) => /claude-opus-4[-._]([7-9]|\d{2,})/.test(modelId)
1767
+ ];
1768
+ var DEFAULT_MAX_OUTPUT_TOKENS = 64e3;
1769
+ var LARGE_MODEL_MAX_OUTPUT_TOKENS = 128e3;
1770
+ function normalizeModelId2(modelId) {
1771
+ return modelId.trim().toLowerCase();
1772
+ }
1773
+ function supportsAdaptiveThinking(modelId) {
1774
+ const runtimeCapability = getRuntimeModelCapability(modelId);
1775
+ if (typeof runtimeCapability?.supportsThinking === "boolean") {
1776
+ return runtimeCapability.supportsThinking;
1777
+ }
1778
+ const normalized = normalizeModelId2(modelId);
1779
+ if (normalized.includes("haiku")) {
1780
+ return false;
1781
+ }
1782
+ return ADAPTIVE_THINKING_MODEL_MATCHERS.some((matches) => matches(normalized));
1783
+ }
1784
+ function getModelMaxOutputTokens(modelId) {
1785
+ const runtimeCapability = getRuntimeModelCapability(modelId);
1786
+ if (typeof runtimeCapability?.maxOutputTokens === "number") {
1787
+ return runtimeCapability.maxOutputTokens;
1788
+ }
1789
+ const normalized = normalizeModelId2(modelId);
1790
+ return LARGE_OUTPUT_MODEL_MATCHERS.some((matches) => matches(normalized)) ? LARGE_MODEL_MAX_OUTPUT_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS;
1791
+ }
1792
+ function resolveMaxTokens(modelId, requestedMaxTokens) {
1793
+ const modelCap = getModelMaxOutputTokens(modelId);
1794
+ if (typeof requestedMaxTokens !== "number" || !Number.isFinite(requestedMaxTokens)) {
1795
+ return modelCap;
1796
+ }
1797
+ const normalized = Math.floor(requestedMaxTokens);
1798
+ if (normalized <= 0) {
1799
+ return modelCap;
1800
+ }
1801
+ return Math.min(normalized, modelCap);
1802
+ }
1679
1803
  function normalizeSystemTexts(system) {
1680
1804
  if (typeof system === "string") {
1681
1805
  const next = sanitizeAndScrubText(system);
@@ -1693,7 +1817,7 @@ function normalizeSystemTexts(system) {
1693
1817
  }
1694
1818
  continue;
1695
1819
  }
1696
- if (isRecord(entry) && typeof entry.text === "string") {
1820
+ if (isRecord2(entry) && typeof entry.text === "string") {
1697
1821
  const next = sanitizeAndScrubText(entry.text);
1698
1822
  if (next) {
1699
1823
  texts.push(next);
@@ -1727,8 +1851,29 @@ function extractFirstUserMessage(messages) {
1727
1851
  function hasCompleteToolSchemas(tools) {
1728
1852
  return tools.length > 0 && tools.every((tool2) => typeof tool2 === "object" && tool2 !== null && "input_schema" in tool2);
1729
1853
  }
1854
+ function enrichIncomingToolsWithTemplateSchemas(incomingTools, templateTools) {
1855
+ if (!hasCompleteToolSchemas(templateTools) || incomingTools.length !== templateTools.length) {
1856
+ return incomingTools;
1857
+ }
1858
+ return incomingTools.map((tool2, index) => {
1859
+ if ("input_schema" in tool2) {
1860
+ return tool2;
1861
+ }
1862
+ const templateTool = templateTools[index];
1863
+ return templateTool && "input_schema" in templateTool ? { ...tool2, input_schema: templateTool.input_schema } : tool2;
1864
+ });
1865
+ }
1866
+ function buildOutboundTools(incomingTools, templateTools) {
1867
+ if (incomingTools.length > 0) {
1868
+ return enrichIncomingToolsWithTemplateSchemas(incomingTools, templateTools);
1869
+ }
1870
+ if (!hasCompleteToolSchemas(templateTools)) {
1871
+ return incomingTools;
1872
+ }
1873
+ return templateTools.map((tool2) => ({ ...tool2 }));
1874
+ }
1730
1875
  function getCcVersion(template) {
1731
- return template.cc_version ?? DEFAULT_CC_VERSION;
1876
+ return template.cc_version ?? detectCliVersion();
1732
1877
  }
1733
1878
  function buildBillingHeader(firstUserMessage, template) {
1734
1879
  const version = getCcVersion(template);
@@ -1754,7 +1899,7 @@ function reverseMapToolUseNames(value, reverseLookup) {
1754
1899
  if (Array.isArray(value)) {
1755
1900
  return value.map((item) => reverseMapToolUseNames(item, reverseLookup));
1756
1901
  }
1757
- if (!isRecord(value)) {
1902
+ if (!isRecord2(value)) {
1758
1903
  return value;
1759
1904
  }
1760
1905
  const cloned = {};
@@ -1787,7 +1932,7 @@ function sanitizeMessages(body) {
1787
1932
  return;
1788
1933
  }
1789
1934
  for (const message of messages) {
1790
- if (!isRecord(message)) {
1935
+ if (!isRecord2(message)) {
1791
1936
  continue;
1792
1937
  }
1793
1938
  if (typeof message.content === "string") {
@@ -1798,7 +1943,7 @@ function sanitizeMessages(body) {
1798
1943
  continue;
1799
1944
  }
1800
1945
  for (const block of message.content) {
1801
- if (isRecord(block) && typeof block.text === "string") {
1946
+ if (isRecord2(block) && typeof block.text === "string") {
1802
1947
  block.text = sanitizeContent(block.text);
1803
1948
  }
1804
1949
  }
@@ -1850,6 +1995,7 @@ function buildUpstreamRequest(inputBody, identity, template, options) {
1850
1995
  sanitizeMessageBlock(block);
1851
1996
  }
1852
1997
  }
1998
+ compactMessageContent(messages);
1853
1999
  trimTrailingEmptyTurns(messages);
1854
2000
  const firstUserMessage = extractFirstUserMessage(messages);
1855
2001
  const billingHeader = buildBillingHeader(firstUserMessage, template);
@@ -1859,8 +2005,10 @@ function buildUpstreamRequest(inputBody, identity, template, options) {
1859
2005
  ].map((entry) => sanitizeAndScrubText(entry)).filter(Boolean).join("\n\n");
1860
2006
  const activeSessionId = options?.sessionId ?? getActiveSessionId();
1861
2007
  body.messages = messages;
2008
+ stripUnsupportedSamplingFields(body);
2009
+ stripThinkingControlFields(body);
1862
2010
  const incomingTools = Array.isArray(body.tools) ? body.tools : [];
1863
- body.tools = hasCompleteToolSchemas(template.tools) ? template.tools.map((tool2) => ({ ...tool2 })) : incomingTools;
2011
+ body.tools = buildOutboundTools(incomingTools, template.tools);
1864
2012
  body.system = [
1865
2013
  {
1866
2014
  type: "text",
@@ -1878,17 +2026,20 @@ function buildUpstreamRequest(inputBody, identity, template, options) {
1878
2026
  }
1879
2027
  ];
1880
2028
  body.metadata = {
1881
- ...isRecord(body.metadata) ? body.metadata : {},
2029
+ ...isRecord2(body.metadata) ? body.metadata : {},
1882
2030
  user_id: JSON.stringify({
1883
2031
  device_id: identity.deviceId,
1884
2032
  account_uuid: identity.accountUuid,
1885
2033
  session_id: activeSessionId
1886
2034
  })
1887
2035
  };
1888
- body.thinking = { type: "adaptive" };
1889
- body.context_management = DEFAULT_CONTEXT_MANAGEMENT;
1890
- body.output_config = DEFAULT_OUTPUT_CONFIG;
1891
- body.max_tokens = 64e3;
2036
+ const modelId = typeof body.model === "string" ? body.model : "";
2037
+ if (supportsAdaptiveThinking(modelId)) {
2038
+ body.thinking = { type: "adaptive" };
2039
+ body.context_management = DEFAULT_CONTEXT_MANAGEMENT;
2040
+ body.output_config = DEFAULT_OUTPUT_CONFIG;
2041
+ }
2042
+ body.max_tokens = resolveMaxTokens(modelId, body.max_tokens);
1892
2043
  return orderBodyForOutbound(body, template.body_field_order);
1893
2044
  }
1894
2045
  function orderBodyForOutbound(body, overrideOrder) {
@@ -1962,6 +2113,149 @@ function createStreamingReverseMapper(response, reverseLookup) {
1962
2113
  });
1963
2114
  }
1964
2115
 
2116
+ // src/tool-flow.ts
2117
+ import { createHash as createHash3 } from "crypto";
2118
+ var TOOL_MASK_PREFIX = "tool_";
2119
+ function isRecord3(value) {
2120
+ return typeof value === "object" && value !== null;
2121
+ }
2122
+ function shouldMaskToolName(name, claudeToolNames) {
2123
+ if (!name) {
2124
+ return false;
2125
+ }
2126
+ return !claudeToolNames.has(name) && !name.startsWith("mcp__") && !name.startsWith(TOOL_MASK_PREFIX);
2127
+ }
2128
+ function extractFirstUserText(parsed) {
2129
+ if (!Array.isArray(parsed.messages)) {
2130
+ return "";
2131
+ }
2132
+ const firstUser = parsed.messages.find((message) => message.role === "user");
2133
+ if (!isRecord3(firstUser)) {
2134
+ return "";
2135
+ }
2136
+ const content = firstUser.content;
2137
+ if (typeof content === "string") {
2138
+ return content.trim();
2139
+ }
2140
+ if (!Array.isArray(content)) {
2141
+ return "";
2142
+ }
2143
+ return content.filter((block) => isRecord3(block) && block.type === "text" && typeof block.text === "string").map((block) => String(block.text)).join("\n\n").trim();
2144
+ }
2145
+ function buildMaskedToolName(seed, toolName, length = 8) {
2146
+ const digest = createHash3("sha256").update(`tool-mask:${seed}:${toolName}`).digest("hex").slice(0, length);
2147
+ return `${TOOL_MASK_PREFIX}${digest}`;
2148
+ }
2149
+ function collectToolNames(parsed) {
2150
+ const names = /* @__PURE__ */ new Set();
2151
+ if (Array.isArray(parsed.tools)) {
2152
+ for (const tool2 of parsed.tools) {
2153
+ if (isRecord3(tool2) && typeof tool2.name === "string") {
2154
+ names.add(tool2.name);
2155
+ }
2156
+ }
2157
+ }
2158
+ if (Array.isArray(parsed.messages)) {
2159
+ for (const message of parsed.messages) {
2160
+ if (!isRecord3(message) || !Array.isArray(message.content)) {
2161
+ continue;
2162
+ }
2163
+ for (const block of message.content) {
2164
+ if (isRecord3(block) && block.type === "tool_use" && typeof block.name === "string") {
2165
+ names.add(block.name);
2166
+ }
2167
+ }
2168
+ }
2169
+ }
2170
+ if (isRecord3(parsed.tool_choice) && parsed.tool_choice.type === "tool" && typeof parsed.tool_choice.name === "string") {
2171
+ names.add(parsed.tool_choice.name);
2172
+ }
2173
+ return [...names];
2174
+ }
2175
+ function buildClaudeToolNameSet(claudeToolNames) {
2176
+ return new Set(claudeToolNames.filter((name) => typeof name === "string" && name.length > 0));
2177
+ }
2178
+ function buildRequestScopedToolLookup(parsed, claudeToolNames) {
2179
+ const lookup = /* @__PURE__ */ new Map();
2180
+ const usedOutgoing = /* @__PURE__ */ new Set();
2181
+ const seed = extractFirstUserText(parsed);
2182
+ const claudeToolSet = buildClaudeToolNameSet(claudeToolNames);
2183
+ for (const originalName of collectToolNames(parsed)) {
2184
+ if (!shouldMaskToolName(originalName, claudeToolSet)) {
2185
+ lookup.set(originalName, originalName);
2186
+ usedOutgoing.add(originalName);
2187
+ continue;
2188
+ }
2189
+ let length = 8;
2190
+ let masked = buildMaskedToolName(seed, originalName, length);
2191
+ while (usedOutgoing.has(masked)) {
2192
+ length += 2;
2193
+ masked = buildMaskedToolName(seed, originalName, length);
2194
+ }
2195
+ lookup.set(masked, originalName);
2196
+ usedOutgoing.add(masked);
2197
+ }
2198
+ return lookup;
2199
+ }
2200
+ function getOutgoingName(name, reverseLookup) {
2201
+ if (!name) {
2202
+ return name;
2203
+ }
2204
+ for (const [outgoing, original] of reverseLookup) {
2205
+ if (original === name) {
2206
+ return outgoing;
2207
+ }
2208
+ }
2209
+ return name;
2210
+ }
2211
+ function rewriteToolUseNames(value, reverseLookup) {
2212
+ if (Array.isArray(value)) {
2213
+ return value.map((item) => rewriteToolUseNames(item, reverseLookup));
2214
+ }
2215
+ if (!isRecord3(value)) {
2216
+ return value;
2217
+ }
2218
+ const cloned = {};
2219
+ for (const [key, nested] of Object.entries(value)) {
2220
+ cloned[key] = rewriteToolUseNames(nested, reverseLookup);
2221
+ }
2222
+ if (cloned.type === "tool_use" && typeof cloned.name === "string") {
2223
+ cloned.name = getOutgoingName(cloned.name, reverseLookup);
2224
+ }
2225
+ return cloned;
2226
+ }
2227
+ function applyOutboundToolFlow(parsed, claudeToolNames) {
2228
+ const reverseLookup = buildRequestScopedToolLookup(parsed, claudeToolNames);
2229
+ const next = { ...parsed };
2230
+ if (Array.isArray(parsed.tools)) {
2231
+ next.tools = parsed.tools.map((tool2) => ({
2232
+ ...tool2,
2233
+ name: getOutgoingName(tool2.name, reverseLookup)
2234
+ }));
2235
+ }
2236
+ if (Array.isArray(parsed.messages)) {
2237
+ next.messages = parsed.messages.map((message) => {
2238
+ if (!isRecord3(message) || !Array.isArray(message.content)) {
2239
+ return message;
2240
+ }
2241
+ return {
2242
+ ...message,
2243
+ content: rewriteToolUseNames(message.content, reverseLookup)
2244
+ };
2245
+ });
2246
+ }
2247
+ if (isRecord3(parsed.tool_choice) && parsed.tool_choice.type === "tool") {
2248
+ next.tool_choice = {
2249
+ ...parsed.tool_choice,
2250
+ name: getOutgoingName(parsed.tool_choice.name, reverseLookup)
2251
+ };
2252
+ }
2253
+ return {
2254
+ body: JSON.stringify(next),
2255
+ reverseLookup
2256
+ };
2257
+ }
2258
+
1965
2259
  // src/upstream-headers.ts
1966
2260
  import { randomUUID as randomUUID3 } from "crypto";
1967
2261
  var UPSTREAM_TIMEOUT_MS = 3e5;
@@ -2048,6 +2342,9 @@ function filterBillableBetas(betas) {
2048
2342
  }
2049
2343
 
2050
2344
  // src/request-transform.ts
2345
+ function applyRequestToolMasking(parsed, claudeToolNames) {
2346
+ return applyOutboundToolFlow(parsed, claudeToolNames);
2347
+ }
2051
2348
  function extractModelIdFromBody(body) {
2052
2349
  if (typeof body !== "string") {
2053
2350
  return "unknown";
@@ -2258,18 +2555,38 @@ function transformBodyToUpstream(body, identity, sessionId2) {
2258
2555
  try {
2259
2556
  const parsed = JSON.parse(body);
2260
2557
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2261
- return body;
2262
- }
2263
- return JSON.stringify(
2264
- buildUpstreamRequest(
2265
- parsed,
2266
- identity,
2267
- loadTemplate(),
2268
- { sessionId: sessionId2 }
2269
- )
2558
+ return { body, reverseLookup: /* @__PURE__ */ new Map() };
2559
+ }
2560
+ const template = loadTemplate();
2561
+ const upstreamRequest = buildUpstreamRequest(
2562
+ parsed,
2563
+ identity,
2564
+ template,
2565
+ { sessionId: sessionId2 }
2270
2566
  );
2567
+ return applyRequestToolMasking(upstreamRequest, template.tool_names);
2271
2568
  } catch {
2272
- return body;
2569
+ return { body, reverseLookup: /* @__PURE__ */ new Map() };
2570
+ }
2571
+ }
2572
+ async function applyResponseReverseLookup(response, reverseLookup) {
2573
+ const contentType = response.headers.get("content-type") ?? "";
2574
+ if (contentType.includes("text/event-stream")) {
2575
+ return createStreamingReverseMapper(response, reverseLookup);
2576
+ }
2577
+ if (!contentType.includes("application/json") || reverseLookup.size === 0) {
2578
+ return response;
2579
+ }
2580
+ try {
2581
+ const payload = await response.clone().json();
2582
+ const remapped = reverseMapResponse(payload, reverseLookup);
2583
+ return new Response(JSON.stringify(remapped), {
2584
+ status: response.status,
2585
+ statusText: response.statusText,
2586
+ headers: new Headers(response.headers)
2587
+ });
2588
+ } catch {
2589
+ return response;
2273
2590
  }
2274
2591
  }
2275
2592
  async function enrichRateLimitResponse(response) {
@@ -2393,7 +2710,7 @@ var AccountRuntimeFactory = class {
2393
2710
  void recordObservedToolNames(extractToolNamesFromRequestBody(init.body)).catch(() => {
2394
2711
  });
2395
2712
  }
2396
- const transformedBody = typeof init?.body === "string" ? transformBodyToUpstream(init.body, this.identity, sessionId2) : init?.body;
2713
+ const transformedRequest = typeof init?.body === "string" ? transformBodyToUpstream(init.body, this.identity, sessionId2) : { body: init?.body, reverseLookup: /* @__PURE__ */ new Map() };
2397
2714
  const pacingCfg = resolvePacingConfig();
2398
2715
  const getNow = this.pacingTestOverrides.now ?? Date.now;
2399
2716
  const sleepFn = this.pacingTestOverrides.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
@@ -2420,7 +2737,7 @@ var AccountRuntimeFactory = class {
2420
2737
  const response2 = await fetch(transformedInput, {
2421
2738
  ...init,
2422
2739
  headers: requestHeaders,
2423
- body: transformedBody
2740
+ body: transformedRequest.body
2424
2741
  });
2425
2742
  return await enrichRateLimitResponse(response2);
2426
2743
  } catch (error) {
@@ -2453,7 +2770,7 @@ var AccountRuntimeFactory = class {
2453
2770
  );
2454
2771
  response = await performFetch(retryHeaders);
2455
2772
  }
2456
- return createStreamingReverseMapper(response);
2773
+ return applyResponseReverseLookup(response, transformedRequest.reverseLookup);
2457
2774
  }
2458
2775
  async createRuntime(uuid) {
2459
2776
  const fetchWithAccount = async (input, init) => {
@@ -2463,9 +2780,8 @@ var AccountRuntimeFactory = class {
2463
2780
  throw new Error(`No credentials found for account ${uuid}`);
2464
2781
  }
2465
2782
  let accessToken = storedAccount.accessToken;
2466
- let expiresAt = storedAccount.expiresAt;
2467
- if (!accessToken || !expiresAt || isTokenExpired({ accessToken, expiresAt })) {
2468
- ({ accessToken, expiresAt } = await this.ensureFreshToken(storedAccount, uuid));
2783
+ if (!accessToken || !storedAccount.expiresAt || isTokenExpired({ accessToken, expiresAt: storedAccount.expiresAt })) {
2784
+ ({ accessToken } = await this.ensureFreshToken(storedAccount, uuid));
2469
2785
  }
2470
2786
  if (!accessToken) {
2471
2787
  throw new Error(`No access token available for account ${uuid}`);
@@ -2626,7 +2942,8 @@ var EMPTY_OAUTH_CREDENTIALS = {
2626
2942
  access: "",
2627
2943
  expires: 0
2628
2944
  };
2629
- function extractFirstUserText(input) {
2945
+ var providerModelsObserverForTest = null;
2946
+ function extractFirstUserText2(input) {
2630
2947
  try {
2631
2948
  const raw = input;
2632
2949
  const messages = raw.messages ?? raw.request?.messages;
@@ -2819,7 +3136,7 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
2819
3136
  });
2820
3137
  return {
2821
3138
  "experimental.chat.system.transform": (input, output) => {
2822
- const billingHeader = composeBillingSystemEntry(extractFirstUserText(input), claudeCodeVersion);
3139
+ const billingHeader = composeBillingSystemEntry(extractFirstUserText2(input), claudeCodeVersion);
2823
3140
  prependMissingSystemEntries(output, [
2824
3141
  billingHeader,
2825
3142
  upstreamAgentIdentity,
@@ -2894,6 +3211,8 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
2894
3211
  { type: "api", label: "Manually enter API Key" }
2895
3212
  ],
2896
3213
  async loader(getAuth, provider) {
3214
+ providerModelsObserverForTest?.(provider.models ?? {});
3215
+ ingestProviderModelsCapabilities(provider.models ?? {});
2897
3216
  const auth = await getAuth();
2898
3217
  if (auth.type !== "oauth") {
2899
3218
  stopHeartbeat();
@@ -2979,7 +3298,15 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
2979
3298
  }
2980
3299
  };
2981
3300
  };
3301
+ function setProviderModelsObserverForTest(observer) {
3302
+ providerModelsObserverForTest = observer;
3303
+ }
3304
+ function resetProviderModelsObserverForTest() {
3305
+ providerModelsObserverForTest = null;
3306
+ }
2982
3307
  export {
2983
- ClaudeMultiAuthPlugin
3308
+ ClaudeMultiAuthPlugin,
3309
+ resetProviderModelsObserverForTest,
3310
+ setProviderModelsObserverForTest
2984
3311
  };
2985
3312
  //# sourceMappingURL=index.js.map