@rynfar/meridian 1.40.0 → 1.41.0
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/{cli-m9pfb7h9.js → cli-0eky480v.js} +76 -46
- package/dist/{cli-3azh7s3k.js → cli-swjr844z.js} +675 -31
- package/dist/cli.js +3 -3
- package/dist/{profilePage-77z05e0r.js → profilePage-k0faye28.js} +196 -4
- package/dist/proxy/agentDefs.d.ts +2 -0
- package/dist/proxy/agentDefs.d.ts.map +1 -1
- package/dist/proxy/errors.d.ts +42 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/oauthUsage.d.ts +67 -0
- package/dist/proxy/oauthUsage.d.ts.map +1 -0
- package/dist/proxy/openai.d.ts +140 -14
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/tokenRefresh.d.ts +22 -1
- package/dist/proxy/tokenRefresh.d.ts.map +1 -1
- package/dist/proxy/tools.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/profileUsage.d.ts +57 -0
- package/dist/telemetry/profileUsage.d.ts.map +1 -0
- package/dist/tokenRefresh-3kh1e8q8.js +17 -0
- package/package.json +3 -3
- package/dist/tokenRefresh-y7d1qvb3.js +0 -11
|
@@ -25,9 +25,10 @@ import {
|
|
|
25
25
|
} from "./cli-rtab0qa6.js";
|
|
26
26
|
import {
|
|
27
27
|
claudeLog,
|
|
28
|
+
createPlatformCredentialStore,
|
|
28
29
|
refreshOAuthToken,
|
|
29
30
|
withClaudeLogContext
|
|
30
|
-
} from "./cli-
|
|
31
|
+
} from "./cli-0eky480v.js";
|
|
31
32
|
import {
|
|
32
33
|
__commonJS,
|
|
33
34
|
__esm,
|
|
@@ -3730,6 +3731,120 @@ class RateLimitStore {
|
|
|
3730
3731
|
}
|
|
3731
3732
|
var rateLimitStore = new RateLimitStore;
|
|
3732
3733
|
|
|
3734
|
+
// src/proxy/oauthUsage.ts
|
|
3735
|
+
var OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
3736
|
+
var OAUTH_BETA_HEADER = "oauth-2025-04-20";
|
|
3737
|
+
var CACHE_TTL_MS_DEFAULT = 30000;
|
|
3738
|
+
var cacheByProfile = new Map;
|
|
3739
|
+
var inflightByProfile = new Map;
|
|
3740
|
+
var DEFAULT_KEY = "__default__";
|
|
3741
|
+
var WINDOW_TYPES = [
|
|
3742
|
+
"five_hour",
|
|
3743
|
+
"seven_day",
|
|
3744
|
+
"seven_day_opus",
|
|
3745
|
+
"seven_day_sonnet",
|
|
3746
|
+
"seven_day_oauth_apps",
|
|
3747
|
+
"seven_day_cowork",
|
|
3748
|
+
"seven_day_omelette"
|
|
3749
|
+
];
|
|
3750
|
+
function parseIsoToMs(raw2) {
|
|
3751
|
+
if (!raw2)
|
|
3752
|
+
return null;
|
|
3753
|
+
const ms = Date.parse(raw2);
|
|
3754
|
+
return Number.isFinite(ms) ? ms : null;
|
|
3755
|
+
}
|
|
3756
|
+
function normalizeUtilization(raw2) {
|
|
3757
|
+
if (typeof raw2 !== "number" || !Number.isFinite(raw2))
|
|
3758
|
+
return null;
|
|
3759
|
+
return Math.max(0, raw2 / 100);
|
|
3760
|
+
}
|
|
3761
|
+
function buildSnapshot(raw2) {
|
|
3762
|
+
const windows = [];
|
|
3763
|
+
for (const key of WINDOW_TYPES) {
|
|
3764
|
+
const w = raw2[key];
|
|
3765
|
+
if (!w)
|
|
3766
|
+
continue;
|
|
3767
|
+
const utilization = normalizeUtilization(w.utilization);
|
|
3768
|
+
const resetsAt = parseIsoToMs(w.resets_at);
|
|
3769
|
+
if (utilization === null && resetsAt === null)
|
|
3770
|
+
continue;
|
|
3771
|
+
windows.push({ type: key, utilization, resetsAt });
|
|
3772
|
+
}
|
|
3773
|
+
const extra = raw2.extra_usage;
|
|
3774
|
+
const extraUsage = extra ? {
|
|
3775
|
+
isEnabled: !!extra.is_enabled,
|
|
3776
|
+
monthlyLimit: extra.monthly_limit ?? 0,
|
|
3777
|
+
usedCredits: extra.used_credits ?? 0,
|
|
3778
|
+
utilization: normalizeUtilization(extra.utilization ?? null),
|
|
3779
|
+
currency: extra.currency ?? "USD"
|
|
3780
|
+
} : null;
|
|
3781
|
+
return { windows, extraUsage, fetchedAt: Date.now() };
|
|
3782
|
+
}
|
|
3783
|
+
async function readAccessToken(store) {
|
|
3784
|
+
const creds = await store.read();
|
|
3785
|
+
return creds?.claudeAiOauth?.accessToken ?? null;
|
|
3786
|
+
}
|
|
3787
|
+
async function callAnthropic(token, signal) {
|
|
3788
|
+
const res = await fetch(OAUTH_USAGE_URL, {
|
|
3789
|
+
headers: {
|
|
3790
|
+
Authorization: `Bearer ${token}`,
|
|
3791
|
+
"anthropic-beta": OAUTH_BETA_HEADER,
|
|
3792
|
+
Accept: "application/json"
|
|
3793
|
+
},
|
|
3794
|
+
signal: signal ?? AbortSignal.timeout(1e4)
|
|
3795
|
+
});
|
|
3796
|
+
if (!res.ok)
|
|
3797
|
+
return { __status: res.status };
|
|
3798
|
+
return await res.json();
|
|
3799
|
+
}
|
|
3800
|
+
async function fetchOAuthUsage(opts) {
|
|
3801
|
+
const ttl = opts?.ttlMs ?? CACHE_TTL_MS_DEFAULT;
|
|
3802
|
+
const cacheKey2 = opts?.profileId ?? DEFAULT_KEY;
|
|
3803
|
+
if (!opts?.force) {
|
|
3804
|
+
const cached = cacheByProfile.get(cacheKey2);
|
|
3805
|
+
if (cached && Date.now() - cached.fetchedAt < ttl)
|
|
3806
|
+
return cached;
|
|
3807
|
+
}
|
|
3808
|
+
const existing = inflightByProfile.get(cacheKey2);
|
|
3809
|
+
if (existing)
|
|
3810
|
+
return existing;
|
|
3811
|
+
const store = opts?.store ?? createPlatformCredentialStore({ claudeConfigDir: opts?.claudeConfigDir });
|
|
3812
|
+
const promise = (async () => {
|
|
3813
|
+
try {
|
|
3814
|
+
const token = await readAccessToken(store);
|
|
3815
|
+
if (!token)
|
|
3816
|
+
return null;
|
|
3817
|
+
let result = await callAnthropic(token);
|
|
3818
|
+
if ("__status" in result && result.__status === 401) {
|
|
3819
|
+
claudeLog("oauth_usage.token_refresh_attempt", { profile: cacheKey2 });
|
|
3820
|
+
const refreshed = await refreshOAuthToken(store);
|
|
3821
|
+
if (!refreshed) {
|
|
3822
|
+
claudeLog("oauth_usage.refresh_failed", { profile: cacheKey2 });
|
|
3823
|
+
return null;
|
|
3824
|
+
}
|
|
3825
|
+
const newToken = await readAccessToken(store);
|
|
3826
|
+
if (!newToken)
|
|
3827
|
+
return null;
|
|
3828
|
+
result = await callAnthropic(newToken);
|
|
3829
|
+
}
|
|
3830
|
+
if ("__status" in result) {
|
|
3831
|
+
claudeLog("oauth_usage.upstream_error", { profile: cacheKey2, status: result.__status });
|
|
3832
|
+
return null;
|
|
3833
|
+
}
|
|
3834
|
+
const snapshot = buildSnapshot(result);
|
|
3835
|
+
cacheByProfile.set(cacheKey2, snapshot);
|
|
3836
|
+
return snapshot;
|
|
3837
|
+
} catch (err) {
|
|
3838
|
+
claudeLog("oauth_usage.fetch_failed", { profile: cacheKey2, error: err instanceof Error ? err.message : String(err) });
|
|
3839
|
+
return null;
|
|
3840
|
+
} finally {
|
|
3841
|
+
inflightByProfile.delete(cacheKey2);
|
|
3842
|
+
}
|
|
3843
|
+
})();
|
|
3844
|
+
inflightByProfile.set(cacheKey2, promise);
|
|
3845
|
+
return promise;
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3733
3848
|
// src/proxy/types.ts
|
|
3734
3849
|
var DEFAULT_PROXY_CONFIG = {
|
|
3735
3850
|
port: 3456,
|
|
@@ -7993,13 +8108,20 @@ function ensureDefaultAgents(agents, mcpToolNames) {
|
|
|
7993
8108
|
}
|
|
7994
8109
|
}
|
|
7995
8110
|
}
|
|
8111
|
+
function cloneAgentDefinition(def) {
|
|
8112
|
+
return {
|
|
8113
|
+
...def,
|
|
8114
|
+
...def.tools ? { tools: [...def.tools] } : {},
|
|
8115
|
+
...def.disallowedTools ? { disallowedTools: [...def.disallowedTools] } : {}
|
|
8116
|
+
};
|
|
8117
|
+
}
|
|
7996
8118
|
function addCaseVariants(agents) {
|
|
7997
8119
|
const baseNames = Object.keys(agents);
|
|
7998
8120
|
for (const name of baseNames) {
|
|
7999
8121
|
const def = agents[name];
|
|
8000
8122
|
const titleCase = name.replace(/(^|-)(\w)/g, (_m, sep, ch) => sep + ch.toUpperCase());
|
|
8001
8123
|
if (titleCase !== name && !agents[titleCase]) {
|
|
8002
|
-
agents[titleCase] = def;
|
|
8124
|
+
agents[titleCase] = cloneAgentDefinition(def);
|
|
8003
8125
|
}
|
|
8004
8126
|
}
|
|
8005
8127
|
const ALIASES = {
|
|
@@ -8008,10 +8130,50 @@ function addCaseVariants(agents) {
|
|
|
8008
8130
|
};
|
|
8009
8131
|
for (const [alias, target] of Object.entries(ALIASES)) {
|
|
8010
8132
|
if (!agents[alias] && agents[target]) {
|
|
8011
|
-
agents[alias] = agents[target];
|
|
8133
|
+
agents[alias] = cloneAgentDefinition(agents[target]);
|
|
8012
8134
|
}
|
|
8013
8135
|
}
|
|
8014
8136
|
}
|
|
8137
|
+
function getNested(obj, ...keys) {
|
|
8138
|
+
let cur = obj;
|
|
8139
|
+
for (const key of keys) {
|
|
8140
|
+
if (cur === null || typeof cur !== "object")
|
|
8141
|
+
return;
|
|
8142
|
+
cur = cur[key];
|
|
8143
|
+
}
|
|
8144
|
+
return cur;
|
|
8145
|
+
}
|
|
8146
|
+
function parseAgentNamesFromSchema(taskTool) {
|
|
8147
|
+
const enumNames = getNested(taskTool, "input_schema", "properties", "subagent_type", "enum");
|
|
8148
|
+
if (!Array.isArray(enumNames))
|
|
8149
|
+
return [];
|
|
8150
|
+
return enumNames.filter((n) => typeof n === "string");
|
|
8151
|
+
}
|
|
8152
|
+
function buildAgentDefinitionsFromTool(taskTool, mcpToolNames) {
|
|
8153
|
+
const rawDescription = getNested(taskTool, "description");
|
|
8154
|
+
const description = typeof rawDescription === "string" ? rawDescription : "";
|
|
8155
|
+
const fromDescription = buildAgentDefinitions(description, mcpToolNames);
|
|
8156
|
+
if (Object.keys(fromDescription).length > 0)
|
|
8157
|
+
return fromDescription;
|
|
8158
|
+
const names = parseAgentNamesFromSchema(taskTool);
|
|
8159
|
+
if (names.length === 0)
|
|
8160
|
+
return {};
|
|
8161
|
+
const agents = {};
|
|
8162
|
+
for (const name of names) {
|
|
8163
|
+
if (agents[name])
|
|
8164
|
+
continue;
|
|
8165
|
+
const desc = `User-defined agent: ${name}`;
|
|
8166
|
+
agents[name] = {
|
|
8167
|
+
description: desc,
|
|
8168
|
+
prompt: buildAgentPrompt(name, desc),
|
|
8169
|
+
model: "inherit",
|
|
8170
|
+
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
8171
|
+
};
|
|
8172
|
+
}
|
|
8173
|
+
ensureDefaultAgents(agents, mcpToolNames);
|
|
8174
|
+
addCaseVariants(agents);
|
|
8175
|
+
return agents;
|
|
8176
|
+
}
|
|
8015
8177
|
function buildAgentPrompt(name, description) {
|
|
8016
8178
|
return `You are the "${name}" agent. ${description}
|
|
8017
8179
|
|
|
@@ -8388,8 +8550,6 @@ let timer;
|
|
|
8388
8550
|
let activeTab = 'requests';
|
|
8389
8551
|
let activeLogFilter = 'all';
|
|
8390
8552
|
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
8553
|
function ms(v) {
|
|
8394
8554
|
if (v == null) return '—';
|
|
8395
8555
|
if (v < 1000) return v + 'ms';
|
|
@@ -8991,6 +9151,82 @@ function isExtraUsageRequiredError(errMsg) {
|
|
|
8991
9151
|
const lower = errMsg.toLowerCase();
|
|
8992
9152
|
return lower.includes("extra usage") && lower.includes("1m");
|
|
8993
9153
|
}
|
|
9154
|
+
var STDERR_TAIL_MAX = 500;
|
|
9155
|
+
var RAW_TAIL_MAX = 300;
|
|
9156
|
+
function extractStderrTail(errMsg) {
|
|
9157
|
+
const marker = "Subprocess stderr:";
|
|
9158
|
+
const idx = errMsg.indexOf(marker);
|
|
9159
|
+
if (idx < 0)
|
|
9160
|
+
return;
|
|
9161
|
+
const tail = errMsg.slice(idx + marker.length).trim();
|
|
9162
|
+
if (!tail)
|
|
9163
|
+
return;
|
|
9164
|
+
return tail.length > STDERR_TAIL_MAX ? tail.slice(0, STDERR_TAIL_MAX) : tail;
|
|
9165
|
+
}
|
|
9166
|
+
function makeRawTail(errMsg) {
|
|
9167
|
+
const marker = "Subprocess stderr:";
|
|
9168
|
+
const idx = errMsg.indexOf(marker);
|
|
9169
|
+
const head = (idx >= 0 ? errMsg.slice(0, idx) : errMsg).trim();
|
|
9170
|
+
if (!head)
|
|
9171
|
+
return;
|
|
9172
|
+
return head.length > RAW_TAIL_MAX ? head.slice(0, RAW_TAIL_MAX) : head;
|
|
9173
|
+
}
|
|
9174
|
+
function extractSdkTermination(errMsg) {
|
|
9175
|
+
const stderrTail = extractStderrTail(errMsg);
|
|
9176
|
+
const haystack = `${errMsg}
|
|
9177
|
+
${stderrTail ?? ""}`;
|
|
9178
|
+
const lower = haystack.toLowerCase();
|
|
9179
|
+
if (lower.includes("reached maximum number of turns")) {
|
|
9180
|
+
const m = haystack.match(/Reached maximum number of turns \((\d+)\)/i);
|
|
9181
|
+
return {
|
|
9182
|
+
reason: "max_turns",
|
|
9183
|
+
...m ? { turns: Number(m[1]) } : {},
|
|
9184
|
+
...stderrTail ? { stderrTail } : {}
|
|
9185
|
+
};
|
|
9186
|
+
}
|
|
9187
|
+
if (lower.includes("exited with code") || lower.includes("process exited")) {
|
|
9188
|
+
const m = haystack.match(/exited with code (\d+)/i);
|
|
9189
|
+
return {
|
|
9190
|
+
reason: "process_exit",
|
|
9191
|
+
...m ? { exitCode: Number(m[1]) } : {},
|
|
9192
|
+
...stderrTail ? { stderrTail } : {}
|
|
9193
|
+
};
|
|
9194
|
+
}
|
|
9195
|
+
if (lower.includes("aborterror") || /\baborted\b/.test(lower)) {
|
|
9196
|
+
return {
|
|
9197
|
+
reason: "aborted",
|
|
9198
|
+
...stderrTail ? { stderrTail } : {}
|
|
9199
|
+
};
|
|
9200
|
+
}
|
|
9201
|
+
const rawTail = makeRawTail(errMsg);
|
|
9202
|
+
return {
|
|
9203
|
+
reason: "unknown",
|
|
9204
|
+
...stderrTail ? { stderrTail } : {},
|
|
9205
|
+
...rawTail ? { rawTail } : {}
|
|
9206
|
+
};
|
|
9207
|
+
}
|
|
9208
|
+
function formatSdkTermination(t, ctx) {
|
|
9209
|
+
const parts = [`reason=${t.reason}`];
|
|
9210
|
+
if (t.turns !== undefined)
|
|
9211
|
+
parts.push(`turns=${t.turns}`);
|
|
9212
|
+
if (t.exitCode !== undefined)
|
|
9213
|
+
parts.push(`exit=${t.exitCode}`);
|
|
9214
|
+
if (ctx.model)
|
|
9215
|
+
parts.push(`model=${ctx.model}`);
|
|
9216
|
+
if (ctx.requestSource)
|
|
9217
|
+
parts.push(`source=${ctx.requestSource}`);
|
|
9218
|
+
if (ctx.isResume !== undefined)
|
|
9219
|
+
parts.push(`resume=${ctx.isResume}`);
|
|
9220
|
+
if (ctx.hasDeferredTools !== undefined)
|
|
9221
|
+
parts.push(`deferred=${ctx.hasDeferredTools}`);
|
|
9222
|
+
if (ctx.sdkSessionId)
|
|
9223
|
+
parts.push(`session=${ctx.sdkSessionId.slice(0, 8)}`);
|
|
9224
|
+
if (t.rawTail)
|
|
9225
|
+
parts.push(`raw=${JSON.stringify(t.rawTail)}`);
|
|
9226
|
+
if (t.stderrTail)
|
|
9227
|
+
parts.push(`stderr=${JSON.stringify(t.stderrTail)}`);
|
|
9228
|
+
return `sdk_termination ${parts.join(" ")}`;
|
|
9229
|
+
}
|
|
8994
9230
|
|
|
8995
9231
|
// src/proxy/models.ts
|
|
8996
9232
|
import { exec as execCallback } from "child_process";
|
|
@@ -9216,7 +9452,7 @@ function parseDataUrlImage(url) {
|
|
|
9216
9452
|
}
|
|
9217
9453
|
function translateOpenAiContentToAnthropic(content) {
|
|
9218
9454
|
if (typeof content === "string")
|
|
9219
|
-
return content;
|
|
9455
|
+
return [{ type: "text", text: content }];
|
|
9220
9456
|
const parts = [];
|
|
9221
9457
|
for (const part of content) {
|
|
9222
9458
|
if (part.type === "text" && typeof part.text === "string") {
|
|
@@ -9235,9 +9471,6 @@ function translateOpenAiContentToAnthropic(content) {
|
|
|
9235
9471
|
parts.push({ type: "text", text: "[Unsupported image_url omitted: only data URLs are currently supported]" });
|
|
9236
9472
|
}
|
|
9237
9473
|
}
|
|
9238
|
-
if (parts.length === 1 && parts[0]?.type === "text") {
|
|
9239
|
-
return parts[0].text;
|
|
9240
|
-
}
|
|
9241
9474
|
return parts;
|
|
9242
9475
|
}
|
|
9243
9476
|
function summarizeAnthropicContent(content) {
|
|
@@ -9246,6 +9479,32 @@ function summarizeAnthropicContent(content) {
|
|
|
9246
9479
|
return content.map((part) => {
|
|
9247
9480
|
if (part.type === "text")
|
|
9248
9481
|
return part.text;
|
|
9482
|
+
if (part.type === "thinking")
|
|
9483
|
+
return `
|
|
9484
|
+
<think>
|
|
9485
|
+
` + part.thinking + `
|
|
9486
|
+
</think>
|
|
9487
|
+
`;
|
|
9488
|
+
if (part.type === "tool_use")
|
|
9489
|
+
return `
|
|
9490
|
+
<tool_call name="` + part.name + `">
|
|
9491
|
+
` + JSON.stringify(part.input) + `
|
|
9492
|
+
</tool_call>
|
|
9493
|
+
`;
|
|
9494
|
+
if (part.type === "tool_result") {
|
|
9495
|
+
if (typeof part.content === "string")
|
|
9496
|
+
return `
|
|
9497
|
+
<tool_result>
|
|
9498
|
+
` + part.content + `
|
|
9499
|
+
</tool_result>
|
|
9500
|
+
`;
|
|
9501
|
+
else
|
|
9502
|
+
return part.content.map((c) => c.type === "text" ? `
|
|
9503
|
+
<tool_result>
|
|
9504
|
+
${c.text}
|
|
9505
|
+
</tool_result>
|
|
9506
|
+
` : "").join("");
|
|
9507
|
+
}
|
|
9249
9508
|
if (part.type === "image")
|
|
9250
9509
|
return "[Image attached]";
|
|
9251
9510
|
return "";
|
|
@@ -9257,18 +9516,89 @@ function translateOpenAiToAnthropic(body) {
|
|
|
9257
9516
|
return null;
|
|
9258
9517
|
const systemParts = [];
|
|
9259
9518
|
const turns = [];
|
|
9519
|
+
const tools = [];
|
|
9260
9520
|
for (const msg of messages) {
|
|
9261
9521
|
const text = extractOpenAiContent(msg.content ?? "");
|
|
9262
9522
|
if (msg.role === "system") {
|
|
9263
9523
|
if (text)
|
|
9264
9524
|
systemParts.push(text);
|
|
9525
|
+
} else if (msg.role === "tool") {
|
|
9526
|
+
turns.push({
|
|
9527
|
+
role: "user",
|
|
9528
|
+
content: [{
|
|
9529
|
+
type: "tool_result",
|
|
9530
|
+
tool_use_id: msg.tool_call_id ?? "",
|
|
9531
|
+
content: translateOpenAiContentToAnthropic(msg.content ?? "")
|
|
9532
|
+
}]
|
|
9533
|
+
});
|
|
9534
|
+
} else if (msg.role === "assistant") {
|
|
9535
|
+
const msgContent = translateOpenAiContentToAnthropic(msg.content ?? "");
|
|
9536
|
+
const content = [];
|
|
9537
|
+
const toolCalls = msg.tool_calls ?? null;
|
|
9538
|
+
const firstBlock = msgContent[0];
|
|
9539
|
+
const endOfThink = firstBlock?.type === "text" && firstBlock.text.startsWith("<think>") ? firstBlock.text.indexOf("</think>") : -1;
|
|
9540
|
+
if (firstBlock?.type === "text" && firstBlock.text.startsWith("<think>") && endOfThink !== -1) {
|
|
9541
|
+
const thinking = firstBlock.text.substring("<think>".length, endOfThink);
|
|
9542
|
+
let textStart = endOfThink + "</think>".length;
|
|
9543
|
+
if (firstBlock.text[textStart] === `
|
|
9544
|
+
`)
|
|
9545
|
+
textStart += 1;
|
|
9546
|
+
const text2 = firstBlock.text.substring(textStart);
|
|
9547
|
+
content.push({ type: "thinking", thinking });
|
|
9548
|
+
if (text2.length)
|
|
9549
|
+
content.push({ type: "text", text: text2 });
|
|
9550
|
+
if (msgContent.length > 1)
|
|
9551
|
+
content.push(...msgContent.slice(1));
|
|
9552
|
+
} else {
|
|
9553
|
+
content.push(...msgContent);
|
|
9554
|
+
}
|
|
9555
|
+
if (toolCalls) {
|
|
9556
|
+
const calls = toolCalls.filter((call) => call.type === "function").map((call) => {
|
|
9557
|
+
let input;
|
|
9558
|
+
try {
|
|
9559
|
+
const parsed = JSON.parse(call.function.arguments);
|
|
9560
|
+
input = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : { __raw: call.function.arguments };
|
|
9561
|
+
} catch {
|
|
9562
|
+
input = { __raw: call.function.arguments };
|
|
9563
|
+
}
|
|
9564
|
+
return {
|
|
9565
|
+
type: "tool_use",
|
|
9566
|
+
id: call.id,
|
|
9567
|
+
name: call.function.name,
|
|
9568
|
+
input
|
|
9569
|
+
};
|
|
9570
|
+
});
|
|
9571
|
+
content.push(...calls);
|
|
9572
|
+
}
|
|
9573
|
+
let finalContent = content;
|
|
9574
|
+
if (content.length === 1 && content[0]?.type === "text") {
|
|
9575
|
+
finalContent = content[0].text;
|
|
9576
|
+
}
|
|
9577
|
+
turns.push({
|
|
9578
|
+
role: "assistant",
|
|
9579
|
+
content: finalContent
|
|
9580
|
+
});
|
|
9265
9581
|
} else {
|
|
9266
9582
|
turns.push({
|
|
9267
|
-
role:
|
|
9583
|
+
role: "user",
|
|
9268
9584
|
content: translateOpenAiContentToAnthropic(msg.content ?? "")
|
|
9269
9585
|
});
|
|
9270
9586
|
}
|
|
9271
9587
|
}
|
|
9588
|
+
const reqTools = body.tools ?? [];
|
|
9589
|
+
for (const reqTool of reqTools) {
|
|
9590
|
+
if (reqTool.type === "function") {
|
|
9591
|
+
const tool = reqTool.function;
|
|
9592
|
+
tools.push({
|
|
9593
|
+
name: tool.name,
|
|
9594
|
+
description: tool.description ?? "",
|
|
9595
|
+
input_schema: tool.parameters,
|
|
9596
|
+
strict: tool.strict
|
|
9597
|
+
});
|
|
9598
|
+
} else {
|
|
9599
|
+
return null;
|
|
9600
|
+
}
|
|
9601
|
+
}
|
|
9272
9602
|
let systemPrompt = systemParts.join(`
|
|
9273
9603
|
`);
|
|
9274
9604
|
let messagesToSend = turns;
|
|
@@ -9289,6 +9619,7 @@ ${historyBlock}` : historyBlock;
|
|
|
9289
9619
|
model: body.model ?? "claude-sonnet-4-6",
|
|
9290
9620
|
messages: messagesToSend,
|
|
9291
9621
|
max_tokens: body.max_tokens ?? body.max_completion_tokens ?? 8192,
|
|
9622
|
+
tools,
|
|
9292
9623
|
stream: body.stream ?? false
|
|
9293
9624
|
};
|
|
9294
9625
|
if (systemPrompt)
|
|
@@ -9302,10 +9633,23 @@ ${historyBlock}` : historyBlock;
|
|
|
9302
9633
|
function toFinishReason(stopReason) {
|
|
9303
9634
|
if (stopReason === "max_tokens")
|
|
9304
9635
|
return "length";
|
|
9636
|
+
else if (stopReason === "tool_use")
|
|
9637
|
+
return "tool_calls";
|
|
9305
9638
|
return "stop";
|
|
9306
9639
|
}
|
|
9307
|
-
function translateAnthropicToOpenAi(response, completionId, model, created) {
|
|
9308
|
-
const
|
|
9640
|
+
function translateAnthropicToOpenAi(response, completionId, model, created, options) {
|
|
9641
|
+
const contentBlocks = response.content ?? [];
|
|
9642
|
+
const content = contentBlocks.filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("");
|
|
9643
|
+
const toolCalls = contentBlocks.filter((b) => b.type === "tool_use").map((b) => ({
|
|
9644
|
+
type: "function",
|
|
9645
|
+
id: b.id,
|
|
9646
|
+
function: {
|
|
9647
|
+
name: b.name,
|
|
9648
|
+
arguments: JSON.stringify(b.input)
|
|
9649
|
+
}
|
|
9650
|
+
}));
|
|
9651
|
+
const thinkingPassthrough = options?.thinkingPassthrough;
|
|
9652
|
+
const thinking = thinkingPassthrough !== false ? contentBlocks.filter((b) => b.type === "thinking").map((b) => b.thinking).join("") : "";
|
|
9309
9653
|
const promptTokens = response.usage?.input_tokens ?? 0;
|
|
9310
9654
|
const completionTokens = response.usage?.output_tokens ?? 0;
|
|
9311
9655
|
return {
|
|
@@ -9315,7 +9659,12 @@ function translateAnthropicToOpenAi(response, completionId, model, created) {
|
|
|
9315
9659
|
model,
|
|
9316
9660
|
choices: [{
|
|
9317
9661
|
index: 0,
|
|
9318
|
-
message: {
|
|
9662
|
+
message: {
|
|
9663
|
+
role: "assistant",
|
|
9664
|
+
content: content || null,
|
|
9665
|
+
reasoning_content: thinking.length ? thinking : undefined,
|
|
9666
|
+
tool_calls: toolCalls.length ? toolCalls : undefined
|
|
9667
|
+
},
|
|
9319
9668
|
finish_reason: toFinishReason(response.stop_reason)
|
|
9320
9669
|
}],
|
|
9321
9670
|
usage: {
|
|
@@ -9325,7 +9674,16 @@ function translateAnthropicToOpenAi(response, completionId, model, created) {
|
|
|
9325
9674
|
}
|
|
9326
9675
|
};
|
|
9327
9676
|
}
|
|
9328
|
-
function
|
|
9677
|
+
function createSseTranslator(ctx) {
|
|
9678
|
+
let toolCallIndex = -1;
|
|
9679
|
+
return (event) => {
|
|
9680
|
+
if (event.type === "content_block_start" && event.content_block?.type === "tool_use" && typeof event.content_block.name === "string") {
|
|
9681
|
+
toolCallIndex++;
|
|
9682
|
+
}
|
|
9683
|
+
return translateAnthropicSseEvent(event, ctx.completionId, ctx.model, ctx.created, toolCallIndex, ctx.thinkingPassthrough);
|
|
9684
|
+
};
|
|
9685
|
+
}
|
|
9686
|
+
function translateAnthropicSseEvent(event, completionId, model, created, toolCallNum, thinkingPassthrough) {
|
|
9329
9687
|
if (event.type === "message_start") {
|
|
9330
9688
|
return {
|
|
9331
9689
|
id: completionId,
|
|
@@ -9344,6 +9702,69 @@ function translateAnthropicSseEvent(event, completionId, model, created) {
|
|
|
9344
9702
|
choices: [{ index: 0, delta: { content: event.delta.text }, finish_reason: null }]
|
|
9345
9703
|
};
|
|
9346
9704
|
}
|
|
9705
|
+
if (event.type === "content_block_start" && event.content_block?.type === "tool_use" && typeof event.content_block?.name === "string") {
|
|
9706
|
+
return {
|
|
9707
|
+
id: completionId,
|
|
9708
|
+
object: "chat.completion.chunk",
|
|
9709
|
+
created,
|
|
9710
|
+
model,
|
|
9711
|
+
choices: [{
|
|
9712
|
+
index: 0,
|
|
9713
|
+
delta: {
|
|
9714
|
+
tool_calls: [{
|
|
9715
|
+
type: "function",
|
|
9716
|
+
index: toolCallNum,
|
|
9717
|
+
id: event.content_block?.id,
|
|
9718
|
+
function: {
|
|
9719
|
+
name: event.content_block.name,
|
|
9720
|
+
arguments: ""
|
|
9721
|
+
}
|
|
9722
|
+
}]
|
|
9723
|
+
},
|
|
9724
|
+
finish_reason: null
|
|
9725
|
+
}]
|
|
9726
|
+
};
|
|
9727
|
+
}
|
|
9728
|
+
if (event.type === "content_block_delta" && event.delta?.type === "input_json_delta" && typeof event.delta?.partial_json === "string") {
|
|
9729
|
+
return {
|
|
9730
|
+
id: completionId,
|
|
9731
|
+
object: "chat.completion.chunk",
|
|
9732
|
+
created,
|
|
9733
|
+
model,
|
|
9734
|
+
choices: [{
|
|
9735
|
+
index: 0,
|
|
9736
|
+
delta: {
|
|
9737
|
+
tool_calls: [{
|
|
9738
|
+
index: toolCallNum,
|
|
9739
|
+
function: {
|
|
9740
|
+
arguments: event.delta.partial_json
|
|
9741
|
+
}
|
|
9742
|
+
}]
|
|
9743
|
+
},
|
|
9744
|
+
finish_reason: null
|
|
9745
|
+
}]
|
|
9746
|
+
};
|
|
9747
|
+
}
|
|
9748
|
+
if (event.type === "content_block_delta" && event.delta?.type === "thinking_delta") {
|
|
9749
|
+
if (thinkingPassthrough === false) {
|
|
9750
|
+
return null;
|
|
9751
|
+
}
|
|
9752
|
+
if (typeof event.delta?.thinking === "string") {
|
|
9753
|
+
return {
|
|
9754
|
+
id: completionId,
|
|
9755
|
+
object: "chat.completion.chunk",
|
|
9756
|
+
created,
|
|
9757
|
+
model,
|
|
9758
|
+
choices: [{
|
|
9759
|
+
index: 0,
|
|
9760
|
+
delta: {
|
|
9761
|
+
reasoning_content: event.delta?.thinking
|
|
9762
|
+
},
|
|
9763
|
+
finish_reason: null
|
|
9764
|
+
}]
|
|
9765
|
+
};
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9347
9768
|
if (event.type === "message_delta" && event.delta?.stop_reason) {
|
|
9348
9769
|
return {
|
|
9349
9770
|
id: completionId,
|
|
@@ -9660,7 +10081,11 @@ var CLAUDE_CODE_ONLY_TOOLS = [
|
|
|
9660
10081
|
"ExitPlanMode",
|
|
9661
10082
|
"EnterWorktree",
|
|
9662
10083
|
"ExitWorktree",
|
|
10084
|
+
"Monitor",
|
|
9663
10085
|
"NotebookEdit",
|
|
10086
|
+
"PushNotification",
|
|
10087
|
+
"RemoteTrigger",
|
|
10088
|
+
"ScheduleWakeup",
|
|
9664
10089
|
"TodoWrite",
|
|
9665
10090
|
"AskUserQuestion",
|
|
9666
10091
|
"Skill",
|
|
@@ -9695,8 +10120,8 @@ var openCodeTransforms = [
|
|
|
9695
10120
|
let sdkAgents = {};
|
|
9696
10121
|
if (Array.isArray(body.tools)) {
|
|
9697
10122
|
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
9698
|
-
if (taskTool
|
|
9699
|
-
sdkAgents =
|
|
10123
|
+
if (taskTool) {
|
|
10124
|
+
sdkAgents = buildAgentDefinitionsFromTool(taskTool, [...allowedMcpTools]);
|
|
9700
10125
|
}
|
|
9701
10126
|
}
|
|
9702
10127
|
let sdkHooks = undefined;
|
|
@@ -9802,9 +10227,9 @@ var openCodeAdapter = {
|
|
|
9802
10227
|
if (!Array.isArray(body.tools))
|
|
9803
10228
|
return {};
|
|
9804
10229
|
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
9805
|
-
if (!taskTool
|
|
10230
|
+
if (!taskTool)
|
|
9806
10231
|
return {};
|
|
9807
|
-
return
|
|
10232
|
+
return buildAgentDefinitionsFromTool(taskTool, [...mcpToolNames]);
|
|
9808
10233
|
},
|
|
9809
10234
|
buildSdkHooks(body, sdkAgents) {
|
|
9810
10235
|
const validAgentNames = Object.keys(sdkAgents);
|
|
@@ -11962,7 +12387,7 @@ var emitWarning = (msg, type, code, fn) => {
|
|
|
11962
12387
|
var AC = globalThis.AbortController;
|
|
11963
12388
|
var AS = globalThis.AbortSignal;
|
|
11964
12389
|
if (typeof AC === "undefined") {
|
|
11965
|
-
AS = class
|
|
12390
|
+
AS = class AbortSignal2 {
|
|
11966
12391
|
onabort;
|
|
11967
12392
|
_onabort = [];
|
|
11968
12393
|
reason;
|
|
@@ -16202,7 +16627,7 @@ function createOpencodeMcpServer() {
|
|
|
16202
16627
|
// src/proxy/query.ts
|
|
16203
16628
|
function computePassthroughMaxTurns(resumeSessionId, hasDeferredTools, advisorModel) {
|
|
16204
16629
|
const hasResume = !!resumeSessionId;
|
|
16205
|
-
const base = hasResume && hasDeferredTools ? 4 :
|
|
16630
|
+
const base = hasResume && hasDeferredTools ? 4 : 3;
|
|
16206
16631
|
const advisorBump = advisorModel ? 3 : 0;
|
|
16207
16632
|
return base + advisorBump;
|
|
16208
16633
|
}
|
|
@@ -17698,7 +18123,7 @@ function createProxyServer(config = {}) {
|
|
|
17698
18123
|
});
|
|
17699
18124
|
return {
|
|
17700
18125
|
decision: "block",
|
|
17701
|
-
reason: "
|
|
18126
|
+
reason: "This tool call has been forwarded to the client for execution. " + "The result will be delivered in a future turn. " + "Do not retry, do not call additional tools, and do not generate further text — end your turn now."
|
|
17702
18127
|
};
|
|
17703
18128
|
}]
|
|
17704
18129
|
}]
|
|
@@ -18119,6 +18544,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
18119
18544
|
sdkUuidMap.push(null);
|
|
18120
18545
|
let messageStartEmitted = false;
|
|
18121
18546
|
let lastUsage;
|
|
18547
|
+
const streamedToolUseIds = new Set;
|
|
18122
18548
|
try {
|
|
18123
18549
|
let currentSessionId;
|
|
18124
18550
|
const MAX_RATE_LIMIT_RETRIES = 2;
|
|
@@ -18309,7 +18735,6 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
18309
18735
|
const skipBlockIndices = new Set;
|
|
18310
18736
|
const taskToolBlockIndices = new Set;
|
|
18311
18737
|
const taskToolJsonBuffer = new Map;
|
|
18312
|
-
const streamedToolUseIds = new Set;
|
|
18313
18738
|
let nextClientBlockIndex = 0;
|
|
18314
18739
|
const sdkToClientIndex = new Map;
|
|
18315
18740
|
try {
|
|
@@ -18672,6 +19097,127 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
18672
19097
|
});
|
|
18673
19098
|
const streamErr = classifyError(errMsg);
|
|
18674
19099
|
claudeLog("proxy.anthropic.error", { error: errMsg, classified: streamErr.type });
|
|
19100
|
+
const sdkTerm = extractSdkTermination(errMsg);
|
|
19101
|
+
const canRecoverAsToolUse = sdkTerm.reason === "max_turns" && passthrough && capturedToolUses.length > 0 && messageStartEmitted;
|
|
19102
|
+
if (canRecoverAsToolUse) {
|
|
19103
|
+
diagnosticLog2.session(`${requestMeta.requestId} sdk_termination_recovered ${formatSdkTermination(sdkTerm, {
|
|
19104
|
+
model,
|
|
19105
|
+
requestSource,
|
|
19106
|
+
isResume,
|
|
19107
|
+
hasDeferredTools,
|
|
19108
|
+
sdkSessionId: resumeSessionId
|
|
19109
|
+
})} captured=${capturedToolUses.length}`, requestMeta.requestId);
|
|
19110
|
+
const unseenToolUses = capturedToolUses.filter((tu) => !streamedToolUseIds.has(tu.id));
|
|
19111
|
+
for (let i = 0;i < unseenToolUses.length; i++) {
|
|
19112
|
+
const tu = unseenToolUses[i];
|
|
19113
|
+
const blockIndex = eventsForwarded + i;
|
|
19114
|
+
safeEnqueue(encoder.encode(`event: content_block_start
|
|
19115
|
+
data: ${JSON.stringify({
|
|
19116
|
+
type: "content_block_start",
|
|
19117
|
+
index: blockIndex,
|
|
19118
|
+
content_block: { type: "tool_use", id: tu.id, name: tu.name, input: {} }
|
|
19119
|
+
})}
|
|
19120
|
+
|
|
19121
|
+
`), "recover_tool_block_start");
|
|
19122
|
+
safeEnqueue(encoder.encode(`event: content_block_delta
|
|
19123
|
+
data: ${JSON.stringify({
|
|
19124
|
+
type: "content_block_delta",
|
|
19125
|
+
index: blockIndex,
|
|
19126
|
+
delta: { type: "input_json_delta", partial_json: JSON.stringify(tu.input) }
|
|
19127
|
+
})}
|
|
19128
|
+
|
|
19129
|
+
`), "recover_tool_input");
|
|
19130
|
+
safeEnqueue(encoder.encode(`event: content_block_stop
|
|
19131
|
+
data: ${JSON.stringify({
|
|
19132
|
+
type: "content_block_stop",
|
|
19133
|
+
index: blockIndex
|
|
19134
|
+
})}
|
|
19135
|
+
|
|
19136
|
+
`), "recover_tool_block_stop");
|
|
19137
|
+
}
|
|
19138
|
+
safeEnqueue(encoder.encode(`event: message_delta
|
|
19139
|
+
data: ${JSON.stringify({
|
|
19140
|
+
type: "message_delta",
|
|
19141
|
+
delta: { stop_reason: "tool_use", stop_sequence: null },
|
|
19142
|
+
usage: { output_tokens: 0 }
|
|
19143
|
+
})}
|
|
19144
|
+
|
|
19145
|
+
`), "recover_message_delta");
|
|
19146
|
+
safeEnqueue(encoder.encode(`event: message_stop
|
|
19147
|
+
data: {"type":"message_stop"}
|
|
19148
|
+
|
|
19149
|
+
`), "recover_message_stop");
|
|
19150
|
+
const recoverTotalMs = Date.now() - requestStartAt;
|
|
19151
|
+
const recoverQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
19152
|
+
telemetryStore2.record({
|
|
19153
|
+
requestId: requestMeta.requestId,
|
|
19154
|
+
timestamp: Date.now(),
|
|
19155
|
+
adapter: adapter.name,
|
|
19156
|
+
requestSource,
|
|
19157
|
+
model,
|
|
19158
|
+
requestModel: body.model || undefined,
|
|
19159
|
+
mode: "stream",
|
|
19160
|
+
isResume,
|
|
19161
|
+
isPassthrough: passthrough,
|
|
19162
|
+
hasDeferredTools,
|
|
19163
|
+
deferredToolCount: hasDeferredTools ? deferredToolCount : undefined,
|
|
19164
|
+
toolCount,
|
|
19165
|
+
lineageType,
|
|
19166
|
+
messageCount: allMessages.length,
|
|
19167
|
+
sdkSessionId: resumeSessionId,
|
|
19168
|
+
status: 200,
|
|
19169
|
+
queueWaitMs: recoverQueueWaitMs,
|
|
19170
|
+
proxyOverheadMs: upstreamStartAt - requestStartAt - recoverQueueWaitMs,
|
|
19171
|
+
ttfbMs: firstChunkAt ? firstChunkAt - upstreamStartAt : null,
|
|
19172
|
+
upstreamDurationMs: Date.now() - upstreamStartAt,
|
|
19173
|
+
totalDurationMs: recoverTotalMs,
|
|
19174
|
+
contentBlocks: eventsForwarded + unseenToolUses.length,
|
|
19175
|
+
textEvents: textEventsForwarded,
|
|
19176
|
+
error: null
|
|
19177
|
+
});
|
|
19178
|
+
if (!streamClosed) {
|
|
19179
|
+
try {
|
|
19180
|
+
controller.close();
|
|
19181
|
+
} catch {}
|
|
19182
|
+
streamClosed = true;
|
|
19183
|
+
}
|
|
19184
|
+
return;
|
|
19185
|
+
}
|
|
19186
|
+
diagnosticLog2.error(`${requestMeta.requestId} ${formatSdkTermination(sdkTerm, {
|
|
19187
|
+
model,
|
|
19188
|
+
requestSource,
|
|
19189
|
+
isResume,
|
|
19190
|
+
hasDeferredTools,
|
|
19191
|
+
sdkSessionId: resumeSessionId
|
|
19192
|
+
})}`, requestMeta.requestId);
|
|
19193
|
+
const streamErrTotalMs = Date.now() - requestStartAt;
|
|
19194
|
+
const streamErrQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
19195
|
+
telemetryStore2.record({
|
|
19196
|
+
requestId: requestMeta.requestId,
|
|
19197
|
+
timestamp: Date.now(),
|
|
19198
|
+
adapter: adapter.name,
|
|
19199
|
+
requestSource,
|
|
19200
|
+
model,
|
|
19201
|
+
requestModel: body.model || undefined,
|
|
19202
|
+
mode: "stream",
|
|
19203
|
+
isResume,
|
|
19204
|
+
isPassthrough: passthrough,
|
|
19205
|
+
hasDeferredTools,
|
|
19206
|
+
deferredToolCount: hasDeferredTools ? deferredToolCount : undefined,
|
|
19207
|
+
toolCount,
|
|
19208
|
+
lineageType,
|
|
19209
|
+
messageCount: allMessages.length,
|
|
19210
|
+
sdkSessionId: resumeSessionId,
|
|
19211
|
+
status: streamErr.status,
|
|
19212
|
+
queueWaitMs: streamErrQueueWaitMs,
|
|
19213
|
+
proxyOverheadMs: upstreamStartAt - requestStartAt - streamErrQueueWaitMs,
|
|
19214
|
+
ttfbMs: firstChunkAt ? firstChunkAt - upstreamStartAt : null,
|
|
19215
|
+
upstreamDurationMs: Date.now() - upstreamStartAt,
|
|
19216
|
+
totalDurationMs: streamErrTotalMs,
|
|
19217
|
+
contentBlocks: eventsForwarded,
|
|
19218
|
+
textEvents: textEventsForwarded,
|
|
19219
|
+
error: streamErr.type
|
|
19220
|
+
});
|
|
18675
19221
|
if (messageStartEmitted) {
|
|
18676
19222
|
safeEnqueue(encoder.encode(`event: message_delta
|
|
18677
19223
|
data: ${JSON.stringify({
|
|
@@ -18719,6 +19265,10 @@ data: ${JSON.stringify({
|
|
|
18719
19265
|
});
|
|
18720
19266
|
const classified = classifyError(errMsg);
|
|
18721
19267
|
claudeLog("proxy.error", { error: errMsg, classified: classified.type });
|
|
19268
|
+
const sdkTerm = extractSdkTermination(errMsg);
|
|
19269
|
+
diagnosticLog2.error(`${requestMeta.requestId} ${formatSdkTermination(sdkTerm, {
|
|
19270
|
+
requestSource: c.req.header("x-meridian-source")?.slice(0, 64) || undefined
|
|
19271
|
+
})}`, requestMeta.requestId);
|
|
18722
19272
|
const errorQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
18723
19273
|
telemetryStore2.record({
|
|
18724
19274
|
requestId: requestMeta.requestId,
|
|
@@ -18860,7 +19410,7 @@ data: ${JSON.stringify({
|
|
|
18860
19410
|
});
|
|
18861
19411
|
});
|
|
18862
19412
|
app.get("/profiles", async (c) => {
|
|
18863
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
19413
|
+
const { profilePageHtml } = await import("./profilePage-k0faye28.js");
|
|
18864
19414
|
return c.html(profilePageHtml);
|
|
18865
19415
|
});
|
|
18866
19416
|
app.post("/profiles/active", async (c) => {
|
|
@@ -18952,9 +19502,14 @@ data: ${JSON.stringify({
|
|
|
18952
19502
|
const completionId = `chatcmpl-${randomUUID()}`;
|
|
18953
19503
|
const created = Math.floor(Date.now() / 1000);
|
|
18954
19504
|
const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : "claude-sonnet-4-6";
|
|
19505
|
+
const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
19506
|
+
const adapter = detectAdapter(c);
|
|
19507
|
+
const sdkFeatures = getFeaturesForAdapter2(adapter.name);
|
|
18955
19508
|
if (!anthropicBody.stream) {
|
|
18956
19509
|
const anthropicRes = await internalRes.json();
|
|
18957
|
-
return c.json(translateAnthropicToOpenAi(anthropicRes, completionId, model, created
|
|
19510
|
+
return c.json(translateAnthropicToOpenAi(anthropicRes, completionId, model, created, {
|
|
19511
|
+
thinkingPassthrough: sdkFeatures.thinkingPassthrough
|
|
19512
|
+
}));
|
|
18958
19513
|
}
|
|
18959
19514
|
const encoder = new TextEncoder;
|
|
18960
19515
|
const readable = new ReadableStream({
|
|
@@ -18967,6 +19522,7 @@ data: ${JSON.stringify({
|
|
|
18967
19522
|
const decoder = new TextDecoder;
|
|
18968
19523
|
let buffer = "";
|
|
18969
19524
|
let streamError = null;
|
|
19525
|
+
const translate = createSseTranslator({ completionId, model, created, thinkingPassthrough: sdkFeatures.thinkingPassthrough });
|
|
18970
19526
|
try {
|
|
18971
19527
|
while (true) {
|
|
18972
19528
|
const { done, value } = await reader.read();
|
|
@@ -18990,7 +19546,7 @@ data: ${JSON.stringify({
|
|
|
18990
19546
|
}
|
|
18991
19547
|
if (typeof event.type !== "string")
|
|
18992
19548
|
continue;
|
|
18993
|
-
const chunk =
|
|
19549
|
+
const chunk = translate(event);
|
|
18994
19550
|
if (chunk)
|
|
18995
19551
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}
|
|
18996
19552
|
|
|
@@ -19021,11 +19577,21 @@ data: ${JSON.stringify({
|
|
|
19021
19577
|
const isMax = authStatus?.subscriptionType === "max";
|
|
19022
19578
|
return c.json({ object: "list", data: buildModelList(isMax) });
|
|
19023
19579
|
});
|
|
19024
|
-
app.get("/v1/usage/quota", (c) => {
|
|
19025
|
-
const
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19580
|
+
app.get("/v1/usage/quota", async (c) => {
|
|
19581
|
+
const sdkEntries = rateLimitStore.getAll().filter((entry) => entry.rateLimitType !== undefined);
|
|
19582
|
+
const requestedProfile = c.req.query("profile");
|
|
19583
|
+
const profilesList = getEffectiveProfiles(finalConfig.profiles);
|
|
19584
|
+
const targetProfileId = requestedProfile || getActiveProfileId() || finalConfig.defaultProfile || profilesList[0]?.id || null;
|
|
19585
|
+
const targetProfile = targetProfileId ? profilesList.find((p) => p.id === targetProfileId) : undefined;
|
|
19586
|
+
const oauth = await fetchOAuthUsage({
|
|
19587
|
+
profileId: targetProfileId ?? undefined,
|
|
19588
|
+
claudeConfigDir: targetProfile?.claudeConfigDir
|
|
19589
|
+
});
|
|
19590
|
+
const byType = new Map;
|
|
19591
|
+
for (const entry of sdkEntries) {
|
|
19592
|
+
const type = entry.rateLimitType;
|
|
19593
|
+
byType.set(type, {
|
|
19594
|
+
type,
|
|
19029
19595
|
status: entry.status,
|
|
19030
19596
|
utilization: entry.utilization ?? null,
|
|
19031
19597
|
resetsAt: entry.resetsAt ?? null,
|
|
@@ -19035,7 +19601,85 @@ data: ${JSON.stringify({
|
|
|
19035
19601
|
overageDisabledReason: entry.overageDisabledReason ?? null,
|
|
19036
19602
|
surpassedThreshold: entry.surpassedThreshold ?? null,
|
|
19037
19603
|
observedAt: entry.observedAt
|
|
19038
|
-
})
|
|
19604
|
+
});
|
|
19605
|
+
}
|
|
19606
|
+
if (oauth) {
|
|
19607
|
+
for (const w of oauth.windows) {
|
|
19608
|
+
const existing = byType.get(w.type);
|
|
19609
|
+
const status = (w.utilization ?? 0) >= 1 ? "rejected" : (w.utilization ?? 0) >= 0.8 ? "allowed_warning" : "allowed";
|
|
19610
|
+
byType.set(w.type, {
|
|
19611
|
+
type: w.type,
|
|
19612
|
+
status: existing?.status === "rejected" ? "rejected" : status,
|
|
19613
|
+
utilization: w.utilization ?? existing?.utilization ?? null,
|
|
19614
|
+
resetsAt: w.resetsAt ?? existing?.resetsAt ?? null,
|
|
19615
|
+
isUsingOverage: existing?.isUsingOverage ?? false,
|
|
19616
|
+
overageStatus: existing?.overageStatus ?? null,
|
|
19617
|
+
overageResetsAt: existing?.overageResetsAt ?? null,
|
|
19618
|
+
overageDisabledReason: existing?.overageDisabledReason ?? null,
|
|
19619
|
+
surpassedThreshold: existing?.surpassedThreshold ?? null,
|
|
19620
|
+
observedAt: oauth.fetchedAt
|
|
19621
|
+
});
|
|
19622
|
+
}
|
|
19623
|
+
}
|
|
19624
|
+
return c.json({
|
|
19625
|
+
profile: targetProfileId ?? null,
|
|
19626
|
+
buckets: Array.from(byType.values()),
|
|
19627
|
+
extraUsage: oauth?.extraUsage ?? null,
|
|
19628
|
+
sources: {
|
|
19629
|
+
oauth: oauth ? { fetchedAt: oauth.fetchedAt } : null,
|
|
19630
|
+
sdk: { entryCount: sdkEntries.length }
|
|
19631
|
+
},
|
|
19632
|
+
asOf: Date.now()
|
|
19633
|
+
});
|
|
19634
|
+
});
|
|
19635
|
+
app.get("/v1/usage/quota/all", async (c) => {
|
|
19636
|
+
const profilesList = getEffectiveProfiles(finalConfig.profiles);
|
|
19637
|
+
const activeId = getActiveProfileId() || finalConfig.defaultProfile || profilesList[0]?.id || null;
|
|
19638
|
+
if (profilesList.length === 0) {
|
|
19639
|
+
const oauth = await fetchOAuthUsage({});
|
|
19640
|
+
return c.json({
|
|
19641
|
+
profiles: [{
|
|
19642
|
+
id: "default",
|
|
19643
|
+
isActive: true,
|
|
19644
|
+
windows: oauth?.windows ?? [],
|
|
19645
|
+
extraUsage: oauth?.extraUsage ?? null,
|
|
19646
|
+
fetchedAt: oauth?.fetchedAt ?? null,
|
|
19647
|
+
error: oauth ? null : "no_token"
|
|
19648
|
+
}],
|
|
19649
|
+
activeProfile: "default",
|
|
19650
|
+
asOf: Date.now()
|
|
19651
|
+
});
|
|
19652
|
+
}
|
|
19653
|
+
const results = await Promise.all(profilesList.map(async (p) => {
|
|
19654
|
+
const type = p.type ?? "claude-max";
|
|
19655
|
+
if (type !== "claude-max") {
|
|
19656
|
+
return {
|
|
19657
|
+
id: p.id,
|
|
19658
|
+
isActive: p.id === activeId,
|
|
19659
|
+
type,
|
|
19660
|
+
windows: [],
|
|
19661
|
+
extraUsage: null,
|
|
19662
|
+
fetchedAt: null,
|
|
19663
|
+
error: "not_oauth"
|
|
19664
|
+
};
|
|
19665
|
+
}
|
|
19666
|
+
const oauth = await fetchOAuthUsage({
|
|
19667
|
+
profileId: p.id,
|
|
19668
|
+
claudeConfigDir: p.claudeConfigDir
|
|
19669
|
+
});
|
|
19670
|
+
return {
|
|
19671
|
+
id: p.id,
|
|
19672
|
+
isActive: p.id === activeId,
|
|
19673
|
+
type,
|
|
19674
|
+
windows: oauth?.windows ?? [],
|
|
19675
|
+
extraUsage: oauth?.extraUsage ?? null,
|
|
19676
|
+
fetchedAt: oauth?.fetchedAt ?? null,
|
|
19677
|
+
error: oauth ? null : "no_token"
|
|
19678
|
+
};
|
|
19679
|
+
}));
|
|
19680
|
+
return c.json({
|
|
19681
|
+
profiles: results,
|
|
19682
|
+
activeProfile: activeId,
|
|
19039
19683
|
asOf: Date.now()
|
|
19040
19684
|
});
|
|
19041
19685
|
});
|