opencode-anthropic-multi-account 0.2.17 → 0.2.18
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.js +208 -19
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1658,6 +1658,9 @@ function hasMeaningfulContent(content) {
|
|
|
1658
1658
|
if (!isRecord(block)) {
|
|
1659
1659
|
return false;
|
|
1660
1660
|
}
|
|
1661
|
+
if (block.type === "tool_use") {
|
|
1662
|
+
return true;
|
|
1663
|
+
}
|
|
1661
1664
|
if (typeof block.text === "string" && block.text.trim().length > 0) {
|
|
1662
1665
|
return true;
|
|
1663
1666
|
}
|
|
@@ -1727,6 +1730,27 @@ function extractFirstUserMessage(messages) {
|
|
|
1727
1730
|
function hasCompleteToolSchemas(tools) {
|
|
1728
1731
|
return tools.length > 0 && tools.every((tool2) => typeof tool2 === "object" && tool2 !== null && "input_schema" in tool2);
|
|
1729
1732
|
}
|
|
1733
|
+
function enrichIncomingToolsWithTemplateSchemas(incomingTools, templateTools) {
|
|
1734
|
+
if (!hasCompleteToolSchemas(templateTools) || incomingTools.length !== templateTools.length) {
|
|
1735
|
+
return incomingTools;
|
|
1736
|
+
}
|
|
1737
|
+
return incomingTools.map((tool2, index) => {
|
|
1738
|
+
if ("input_schema" in tool2) {
|
|
1739
|
+
return tool2;
|
|
1740
|
+
}
|
|
1741
|
+
const templateTool = templateTools[index];
|
|
1742
|
+
return templateTool && "input_schema" in templateTool ? { ...tool2, input_schema: templateTool.input_schema } : tool2;
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
function buildOutboundTools(incomingTools, templateTools) {
|
|
1746
|
+
if (incomingTools.length > 0) {
|
|
1747
|
+
return enrichIncomingToolsWithTemplateSchemas(incomingTools, templateTools);
|
|
1748
|
+
}
|
|
1749
|
+
if (!hasCompleteToolSchemas(templateTools)) {
|
|
1750
|
+
return incomingTools;
|
|
1751
|
+
}
|
|
1752
|
+
return templateTools.map((tool2) => ({ ...tool2 }));
|
|
1753
|
+
}
|
|
1730
1754
|
function getCcVersion(template) {
|
|
1731
1755
|
return template.cc_version ?? DEFAULT_CC_VERSION;
|
|
1732
1756
|
}
|
|
@@ -1860,7 +1884,7 @@ function buildUpstreamRequest(inputBody, identity, template, options) {
|
|
|
1860
1884
|
const activeSessionId = options?.sessionId ?? getActiveSessionId();
|
|
1861
1885
|
body.messages = messages;
|
|
1862
1886
|
const incomingTools = Array.isArray(body.tools) ? body.tools : [];
|
|
1863
|
-
body.tools =
|
|
1887
|
+
body.tools = buildOutboundTools(incomingTools, template.tools);
|
|
1864
1888
|
body.system = [
|
|
1865
1889
|
{
|
|
1866
1890
|
type: "text",
|
|
@@ -1962,6 +1986,149 @@ function createStreamingReverseMapper(response, reverseLookup) {
|
|
|
1962
1986
|
});
|
|
1963
1987
|
}
|
|
1964
1988
|
|
|
1989
|
+
// src/tool-flow.ts
|
|
1990
|
+
import { createHash as createHash3 } from "crypto";
|
|
1991
|
+
var TOOL_MASK_PREFIX = "tool_";
|
|
1992
|
+
function isRecord2(value) {
|
|
1993
|
+
return typeof value === "object" && value !== null;
|
|
1994
|
+
}
|
|
1995
|
+
function shouldMaskToolName(name, claudeToolNames) {
|
|
1996
|
+
if (!name) {
|
|
1997
|
+
return false;
|
|
1998
|
+
}
|
|
1999
|
+
return !claudeToolNames.has(name) && !name.startsWith("mcp__") && !name.startsWith(TOOL_MASK_PREFIX);
|
|
2000
|
+
}
|
|
2001
|
+
function extractFirstUserText(parsed) {
|
|
2002
|
+
if (!Array.isArray(parsed.messages)) {
|
|
2003
|
+
return "";
|
|
2004
|
+
}
|
|
2005
|
+
const firstUser = parsed.messages.find((message) => message.role === "user");
|
|
2006
|
+
if (!isRecord2(firstUser)) {
|
|
2007
|
+
return "";
|
|
2008
|
+
}
|
|
2009
|
+
const content = firstUser.content;
|
|
2010
|
+
if (typeof content === "string") {
|
|
2011
|
+
return content.trim();
|
|
2012
|
+
}
|
|
2013
|
+
if (!Array.isArray(content)) {
|
|
2014
|
+
return "";
|
|
2015
|
+
}
|
|
2016
|
+
return content.filter((block) => isRecord2(block) && block.type === "text" && typeof block.text === "string").map((block) => String(block.text)).join("\n\n").trim();
|
|
2017
|
+
}
|
|
2018
|
+
function buildMaskedToolName(seed, toolName, length = 8) {
|
|
2019
|
+
const digest = createHash3("sha256").update(`tool-mask:${seed}:${toolName}`).digest("hex").slice(0, length);
|
|
2020
|
+
return `${TOOL_MASK_PREFIX}${digest}`;
|
|
2021
|
+
}
|
|
2022
|
+
function collectToolNames(parsed) {
|
|
2023
|
+
const names = /* @__PURE__ */ new Set();
|
|
2024
|
+
if (Array.isArray(parsed.tools)) {
|
|
2025
|
+
for (const tool2 of parsed.tools) {
|
|
2026
|
+
if (isRecord2(tool2) && typeof tool2.name === "string") {
|
|
2027
|
+
names.add(tool2.name);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
if (Array.isArray(parsed.messages)) {
|
|
2032
|
+
for (const message of parsed.messages) {
|
|
2033
|
+
if (!isRecord2(message) || !Array.isArray(message.content)) {
|
|
2034
|
+
continue;
|
|
2035
|
+
}
|
|
2036
|
+
for (const block of message.content) {
|
|
2037
|
+
if (isRecord2(block) && block.type === "tool_use" && typeof block.name === "string") {
|
|
2038
|
+
names.add(block.name);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
if (isRecord2(parsed.tool_choice) && parsed.tool_choice.type === "tool" && typeof parsed.tool_choice.name === "string") {
|
|
2044
|
+
names.add(parsed.tool_choice.name);
|
|
2045
|
+
}
|
|
2046
|
+
return [...names];
|
|
2047
|
+
}
|
|
2048
|
+
function buildClaudeToolNameSet(claudeToolNames) {
|
|
2049
|
+
return new Set(claudeToolNames.filter((name) => typeof name === "string" && name.length > 0));
|
|
2050
|
+
}
|
|
2051
|
+
function buildRequestScopedToolLookup(parsed, claudeToolNames) {
|
|
2052
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
2053
|
+
const usedOutgoing = /* @__PURE__ */ new Set();
|
|
2054
|
+
const seed = extractFirstUserText(parsed);
|
|
2055
|
+
const claudeToolSet = buildClaudeToolNameSet(claudeToolNames);
|
|
2056
|
+
for (const originalName of collectToolNames(parsed)) {
|
|
2057
|
+
if (!shouldMaskToolName(originalName, claudeToolSet)) {
|
|
2058
|
+
lookup.set(originalName, originalName);
|
|
2059
|
+
usedOutgoing.add(originalName);
|
|
2060
|
+
continue;
|
|
2061
|
+
}
|
|
2062
|
+
let length = 8;
|
|
2063
|
+
let masked = buildMaskedToolName(seed, originalName, length);
|
|
2064
|
+
while (usedOutgoing.has(masked)) {
|
|
2065
|
+
length += 2;
|
|
2066
|
+
masked = buildMaskedToolName(seed, originalName, length);
|
|
2067
|
+
}
|
|
2068
|
+
lookup.set(masked, originalName);
|
|
2069
|
+
usedOutgoing.add(masked);
|
|
2070
|
+
}
|
|
2071
|
+
return lookup;
|
|
2072
|
+
}
|
|
2073
|
+
function getOutgoingName(name, reverseLookup) {
|
|
2074
|
+
if (!name) {
|
|
2075
|
+
return name;
|
|
2076
|
+
}
|
|
2077
|
+
for (const [outgoing, original] of reverseLookup) {
|
|
2078
|
+
if (original === name) {
|
|
2079
|
+
return outgoing;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
return name;
|
|
2083
|
+
}
|
|
2084
|
+
function rewriteToolUseNames(value, reverseLookup) {
|
|
2085
|
+
if (Array.isArray(value)) {
|
|
2086
|
+
return value.map((item) => rewriteToolUseNames(item, reverseLookup));
|
|
2087
|
+
}
|
|
2088
|
+
if (!isRecord2(value)) {
|
|
2089
|
+
return value;
|
|
2090
|
+
}
|
|
2091
|
+
const cloned = {};
|
|
2092
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
2093
|
+
cloned[key] = rewriteToolUseNames(nested, reverseLookup);
|
|
2094
|
+
}
|
|
2095
|
+
if (cloned.type === "tool_use" && typeof cloned.name === "string") {
|
|
2096
|
+
cloned.name = getOutgoingName(cloned.name, reverseLookup);
|
|
2097
|
+
}
|
|
2098
|
+
return cloned;
|
|
2099
|
+
}
|
|
2100
|
+
function applyOutboundToolFlow(parsed, claudeToolNames) {
|
|
2101
|
+
const reverseLookup = buildRequestScopedToolLookup(parsed, claudeToolNames);
|
|
2102
|
+
const next = { ...parsed };
|
|
2103
|
+
if (Array.isArray(parsed.tools)) {
|
|
2104
|
+
next.tools = parsed.tools.map((tool2) => ({
|
|
2105
|
+
...tool2,
|
|
2106
|
+
name: getOutgoingName(tool2.name, reverseLookup)
|
|
2107
|
+
}));
|
|
2108
|
+
}
|
|
2109
|
+
if (Array.isArray(parsed.messages)) {
|
|
2110
|
+
next.messages = parsed.messages.map((message) => {
|
|
2111
|
+
if (!isRecord2(message) || !Array.isArray(message.content)) {
|
|
2112
|
+
return message;
|
|
2113
|
+
}
|
|
2114
|
+
return {
|
|
2115
|
+
...message,
|
|
2116
|
+
content: rewriteToolUseNames(message.content, reverseLookup)
|
|
2117
|
+
};
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
if (isRecord2(parsed.tool_choice) && parsed.tool_choice.type === "tool") {
|
|
2121
|
+
next.tool_choice = {
|
|
2122
|
+
...parsed.tool_choice,
|
|
2123
|
+
name: getOutgoingName(parsed.tool_choice.name, reverseLookup)
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
return {
|
|
2127
|
+
body: JSON.stringify(next),
|
|
2128
|
+
reverseLookup
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
|
|
1965
2132
|
// src/upstream-headers.ts
|
|
1966
2133
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1967
2134
|
var UPSTREAM_TIMEOUT_MS = 3e5;
|
|
@@ -2048,6 +2215,9 @@ function filterBillableBetas(betas) {
|
|
|
2048
2215
|
}
|
|
2049
2216
|
|
|
2050
2217
|
// src/request-transform.ts
|
|
2218
|
+
function applyRequestToolMasking(parsed, claudeToolNames) {
|
|
2219
|
+
return applyOutboundToolFlow(parsed, claudeToolNames);
|
|
2220
|
+
}
|
|
2051
2221
|
function extractModelIdFromBody(body) {
|
|
2052
2222
|
if (typeof body !== "string") {
|
|
2053
2223
|
return "unknown";
|
|
@@ -2258,18 +2428,38 @@ function transformBodyToUpstream(body, identity, sessionId2) {
|
|
|
2258
2428
|
try {
|
|
2259
2429
|
const parsed = JSON.parse(body);
|
|
2260
2430
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2261
|
-
return body;
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
)
|
|
2431
|
+
return { body, reverseLookup: /* @__PURE__ */ new Map() };
|
|
2432
|
+
}
|
|
2433
|
+
const template = loadTemplate();
|
|
2434
|
+
const upstreamRequest = buildUpstreamRequest(
|
|
2435
|
+
parsed,
|
|
2436
|
+
identity,
|
|
2437
|
+
template,
|
|
2438
|
+
{ sessionId: sessionId2 }
|
|
2270
2439
|
);
|
|
2440
|
+
return applyRequestToolMasking(upstreamRequest, template.tool_names);
|
|
2271
2441
|
} catch {
|
|
2272
|
-
return body;
|
|
2442
|
+
return { body, reverseLookup: /* @__PURE__ */ new Map() };
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
async function applyResponseReverseLookup(response, reverseLookup) {
|
|
2446
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
2447
|
+
if (contentType.includes("text/event-stream")) {
|
|
2448
|
+
return createStreamingReverseMapper(response, reverseLookup);
|
|
2449
|
+
}
|
|
2450
|
+
if (!contentType.includes("application/json") || reverseLookup.size === 0) {
|
|
2451
|
+
return response;
|
|
2452
|
+
}
|
|
2453
|
+
try {
|
|
2454
|
+
const payload = await response.clone().json();
|
|
2455
|
+
const remapped = reverseMapResponse(payload, reverseLookup);
|
|
2456
|
+
return new Response(JSON.stringify(remapped), {
|
|
2457
|
+
status: response.status,
|
|
2458
|
+
statusText: response.statusText,
|
|
2459
|
+
headers: new Headers(response.headers)
|
|
2460
|
+
});
|
|
2461
|
+
} catch {
|
|
2462
|
+
return response;
|
|
2273
2463
|
}
|
|
2274
2464
|
}
|
|
2275
2465
|
async function enrichRateLimitResponse(response) {
|
|
@@ -2393,7 +2583,7 @@ var AccountRuntimeFactory = class {
|
|
|
2393
2583
|
void recordObservedToolNames(extractToolNamesFromRequestBody(init.body)).catch(() => {
|
|
2394
2584
|
});
|
|
2395
2585
|
}
|
|
2396
|
-
const
|
|
2586
|
+
const transformedRequest = typeof init?.body === "string" ? transformBodyToUpstream(init.body, this.identity, sessionId2) : { body: init?.body, reverseLookup: /* @__PURE__ */ new Map() };
|
|
2397
2587
|
const pacingCfg = resolvePacingConfig();
|
|
2398
2588
|
const getNow = this.pacingTestOverrides.now ?? Date.now;
|
|
2399
2589
|
const sleepFn = this.pacingTestOverrides.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
@@ -2420,7 +2610,7 @@ var AccountRuntimeFactory = class {
|
|
|
2420
2610
|
const response2 = await fetch(transformedInput, {
|
|
2421
2611
|
...init,
|
|
2422
2612
|
headers: requestHeaders,
|
|
2423
|
-
body:
|
|
2613
|
+
body: transformedRequest.body
|
|
2424
2614
|
});
|
|
2425
2615
|
return await enrichRateLimitResponse(response2);
|
|
2426
2616
|
} catch (error) {
|
|
@@ -2453,7 +2643,7 @@ var AccountRuntimeFactory = class {
|
|
|
2453
2643
|
);
|
|
2454
2644
|
response = await performFetch(retryHeaders);
|
|
2455
2645
|
}
|
|
2456
|
-
return
|
|
2646
|
+
return applyResponseReverseLookup(response, transformedRequest.reverseLookup);
|
|
2457
2647
|
}
|
|
2458
2648
|
async createRuntime(uuid) {
|
|
2459
2649
|
const fetchWithAccount = async (input, init) => {
|
|
@@ -2463,9 +2653,8 @@ var AccountRuntimeFactory = class {
|
|
|
2463
2653
|
throw new Error(`No credentials found for account ${uuid}`);
|
|
2464
2654
|
}
|
|
2465
2655
|
let accessToken = storedAccount.accessToken;
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
({ accessToken, expiresAt } = await this.ensureFreshToken(storedAccount, uuid));
|
|
2656
|
+
if (!accessToken || !storedAccount.expiresAt || isTokenExpired({ accessToken, expiresAt: storedAccount.expiresAt })) {
|
|
2657
|
+
({ accessToken } = await this.ensureFreshToken(storedAccount, uuid));
|
|
2469
2658
|
}
|
|
2470
2659
|
if (!accessToken) {
|
|
2471
2660
|
throw new Error(`No access token available for account ${uuid}`);
|
|
@@ -2626,7 +2815,7 @@ var EMPTY_OAUTH_CREDENTIALS = {
|
|
|
2626
2815
|
access: "",
|
|
2627
2816
|
expires: 0
|
|
2628
2817
|
};
|
|
2629
|
-
function
|
|
2818
|
+
function extractFirstUserText2(input) {
|
|
2630
2819
|
try {
|
|
2631
2820
|
const raw = input;
|
|
2632
2821
|
const messages = raw.messages ?? raw.request?.messages;
|
|
@@ -2819,7 +3008,7 @@ var ClaudeMultiAuthPlugin = async (ctx) => {
|
|
|
2819
3008
|
});
|
|
2820
3009
|
return {
|
|
2821
3010
|
"experimental.chat.system.transform": (input, output) => {
|
|
2822
|
-
const billingHeader = composeBillingSystemEntry(
|
|
3011
|
+
const billingHeader = composeBillingSystemEntry(extractFirstUserText2(input), claudeCodeVersion);
|
|
2823
3012
|
prependMissingSystemEntries(output, [
|
|
2824
3013
|
billingHeader,
|
|
2825
3014
|
upstreamAgentIdentity,
|