@rynfar/meridian 1.59.0 → 1.61.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/README.md +2 -1
- package/dist/{cli-wqvrd0yy.js → cli-tbhba0cv.js} +687 -231
- package/dist/cli.js +1 -1
- package/dist/{profilePage-naychnb8.js → profilePage-gtazq15d.js} +9 -0
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/adapters/jcode.d.ts +13 -0
- package/dist/proxy/adapters/jcode.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/messages.d.ts +29 -0
- package/dist/proxy/messages.d.ts.map +1 -1
- package/dist/proxy/oauthUsage.d.ts +34 -1
- package/dist/proxy/oauthUsage.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts +5 -1
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/passthroughEarlyStop.d.ts +48 -0
- package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +5 -2
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts +8 -0
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/cache.d.ts +1 -1
- package/dist/proxy/session/cache.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts +12 -0
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/sessionStore.d.ts +5 -1
- package/dist/proxy/sessionStore.d.ts.map +1 -1
- package/dist/proxy/transforms/registry.d.ts.map +1 -1
- package/dist/proxy/turnOutcome.d.ts +179 -0
- package/dist/proxy/turnOutcome.d.ts.map +1 -0
- package/dist/server.js +1 -1
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +1 -1
- package/dist/telemetry/settingsPage.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1752,6 +1752,133 @@ var init_sqlite = __esm(() => {
|
|
|
1752
1752
|
];
|
|
1753
1753
|
});
|
|
1754
1754
|
|
|
1755
|
+
// src/proxy/fileChanges.ts
|
|
1756
|
+
function extractFileChange(toolName, toolInput, mcpPrefix) {
|
|
1757
|
+
if (!toolName.startsWith(mcpPrefix))
|
|
1758
|
+
return;
|
|
1759
|
+
const shortName = toolName.slice(mcpPrefix.length);
|
|
1760
|
+
const input = toolInput;
|
|
1761
|
+
if (shortName === "write" && input?.path) {
|
|
1762
|
+
return { operation: "wrote", path: String(input.path) };
|
|
1763
|
+
}
|
|
1764
|
+
if (shortName === "edit" && input?.path) {
|
|
1765
|
+
return { operation: "edited", path: String(input.path) };
|
|
1766
|
+
}
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
function createFileChangeHook(changes, mcpPrefix) {
|
|
1770
|
+
return {
|
|
1771
|
+
matcher: "",
|
|
1772
|
+
hooks: [async (input) => {
|
|
1773
|
+
const change = extractFileChange(input.tool_name, input.tool_input, mcpPrefix);
|
|
1774
|
+
if (change) {
|
|
1775
|
+
changes.push(change);
|
|
1776
|
+
return {};
|
|
1777
|
+
}
|
|
1778
|
+
if (input.tool_name === `${mcpPrefix}bash`) {
|
|
1779
|
+
const toolInput = input.tool_input;
|
|
1780
|
+
if (toolInput?.command) {
|
|
1781
|
+
const bashChanges = extractFileChangesFromBash(String(toolInput.command));
|
|
1782
|
+
changes.push(...bashChanges);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return {};
|
|
1786
|
+
}]
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
function isLikelyFilePath(s) {
|
|
1790
|
+
if (s.length > 4096)
|
|
1791
|
+
return false;
|
|
1792
|
+
if (/[<>$`\\()[\]{}=]/.test(s))
|
|
1793
|
+
return false;
|
|
1794
|
+
if (/^-?\d+$/.test(s))
|
|
1795
|
+
return false;
|
|
1796
|
+
if (s.includes("/"))
|
|
1797
|
+
return true;
|
|
1798
|
+
if (/\.[A-Za-z0-9]{1,16}$/.test(s))
|
|
1799
|
+
return true;
|
|
1800
|
+
return false;
|
|
1801
|
+
}
|
|
1802
|
+
function extractFileChangesFromBash(command) {
|
|
1803
|
+
const changes = [];
|
|
1804
|
+
const seen = new Set;
|
|
1805
|
+
const addChange = (operation, path) => {
|
|
1806
|
+
if (path === "/dev/null" || path === "/dev/stderr" || path === "/dev/stdout")
|
|
1807
|
+
return;
|
|
1808
|
+
if (!path.trim())
|
|
1809
|
+
return;
|
|
1810
|
+
const key = `${operation}:${path}`;
|
|
1811
|
+
if (!seen.has(key)) {
|
|
1812
|
+
seen.add(key);
|
|
1813
|
+
changes.push({ operation, path });
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
const redirectRegex = /(?<![0-9=])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
|
|
1817
|
+
let match2;
|
|
1818
|
+
while ((match2 = redirectRegex.exec(command)) !== null) {
|
|
1819
|
+
if (isLikelyFilePath(match2[1])) {
|
|
1820
|
+
addChange("wrote", match2[1]);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
const teeRegex = /\btee\s+(?:-[a-zA-Z]\s+)*['"]?([^\s'";&|)]+)['"]?/g;
|
|
1824
|
+
while ((match2 = teeRegex.exec(command)) !== null) {
|
|
1825
|
+
addChange("wrote", match2[1]);
|
|
1826
|
+
}
|
|
1827
|
+
const sedRegex = /\bsed\s+(?:-[a-zA-Z]*i[a-zA-Z]*|-i)\b.*?['"]?([^\s'";&|)]+)['"]?\s*$/gm;
|
|
1828
|
+
while ((match2 = sedRegex.exec(command)) !== null) {
|
|
1829
|
+
addChange("edited", match2[1]);
|
|
1830
|
+
}
|
|
1831
|
+
return changes;
|
|
1832
|
+
}
|
|
1833
|
+
function extractFileChangesFromMessages(messages, extractFn) {
|
|
1834
|
+
const changes = [];
|
|
1835
|
+
const executedToolIds = new Set;
|
|
1836
|
+
for (const msg of messages) {
|
|
1837
|
+
if (msg.role !== "user")
|
|
1838
|
+
continue;
|
|
1839
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
1840
|
+
for (const block of content) {
|
|
1841
|
+
if (block?.type === "tool_result" && block.tool_use_id) {
|
|
1842
|
+
executedToolIds.add(block.tool_use_id);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
for (const msg of messages) {
|
|
1847
|
+
if (msg.role !== "assistant")
|
|
1848
|
+
continue;
|
|
1849
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
1850
|
+
for (const block of content) {
|
|
1851
|
+
if (block?.type !== "tool_use")
|
|
1852
|
+
continue;
|
|
1853
|
+
if (!executedToolIds.has(block.id))
|
|
1854
|
+
continue;
|
|
1855
|
+
const blockChanges = extractFn(block.name, block.input);
|
|
1856
|
+
changes.push(...blockChanges);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
return changes;
|
|
1860
|
+
}
|
|
1861
|
+
function formatFileChangeSummary(changes) {
|
|
1862
|
+
if (changes.length === 0)
|
|
1863
|
+
return;
|
|
1864
|
+
const seen = new Set;
|
|
1865
|
+
const unique = [];
|
|
1866
|
+
for (const c of changes) {
|
|
1867
|
+
const key = `${c.operation}:${c.path}`;
|
|
1868
|
+
if (!seen.has(key)) {
|
|
1869
|
+
seen.add(key);
|
|
1870
|
+
unique.push(c);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
const lines = unique.map((c) => `- ${c.operation} ${c.path}`);
|
|
1874
|
+
return `
|
|
1875
|
+
|
|
1876
|
+
Files changed:
|
|
1877
|
+
${lines.join(`
|
|
1878
|
+
`)}`;
|
|
1879
|
+
}
|
|
1880
|
+
var init_fileChanges = () => {};
|
|
1881
|
+
|
|
1755
1882
|
// src/proxy/messages.ts
|
|
1756
1883
|
function stripCacheControlForHashing(obj) {
|
|
1757
1884
|
if (!obj || typeof obj !== "object")
|
|
@@ -1831,6 +1958,13 @@ ${history}
|
|
|
1831
1958
|
|
|
1832
1959
|
` + last.text;
|
|
1833
1960
|
}
|
|
1961
|
+
function framePassthroughContinuation(delta) {
|
|
1962
|
+
if (!delta)
|
|
1963
|
+
return delta;
|
|
1964
|
+
return `${PASSTHROUGH_CONTINUATION_LEAD_IN}
|
|
1965
|
+
|
|
1966
|
+
${delta}`;
|
|
1967
|
+
}
|
|
1834
1968
|
function stripNonStandardStreamFields(event) {
|
|
1835
1969
|
if (event && typeof event === "object") {
|
|
1836
1970
|
const e = event;
|
|
@@ -1949,7 +2083,15 @@ function describeToolCall(info) {
|
|
|
1949
2083
|
const head = info.target ? `your ${info.name} ${info.target}` : `your ${info.name}`;
|
|
1950
2084
|
return info.contentSummary ? `[${head} → "${info.contentSummary}"]` : `[${head}]`;
|
|
1951
2085
|
}
|
|
1952
|
-
|
|
2086
|
+
function extractSystemText(system) {
|
|
2087
|
+
if (typeof system === "string")
|
|
2088
|
+
return system;
|
|
2089
|
+
if (!Array.isArray(system))
|
|
2090
|
+
return "";
|
|
2091
|
+
return system.filter((b) => b?.type === "text" && typeof b.text === "string" && b.text).map((b) => b.text).filter((text) => !TRANSPORT_HEADER_BLOCK.test(text)).join(`
|
|
2092
|
+
`);
|
|
2093
|
+
}
|
|
2094
|
+
var HASH_IGNORED_BLOCK_TYPES, HASH_HANDLED_BLOCK_TYPES, HASH_SERIALIZED_BLOCK_TYPES, PASSTHROUGH_CONTINUATION_LEAD_IN, MULTIMODAL_TYPES, TOOL_TARGET_KEYS, CONTENT_SUMMARY_MAX = 120, TRANSPORT_HEADER_BLOCK;
|
|
1953
2095
|
var init_messages = __esm(() => {
|
|
1954
2096
|
HASH_IGNORED_BLOCK_TYPES = new Set(["thinking", "redacted_thinking"]);
|
|
1955
2097
|
HASH_HANDLED_BLOCK_TYPES = new Set(["text", "tool_use", "tool_result"]);
|
|
@@ -1966,137 +2108,12 @@ var init_messages = __esm(() => {
|
|
|
1966
2108
|
"tool_search_tool_result",
|
|
1967
2109
|
"container_upload"
|
|
1968
2110
|
]);
|
|
2111
|
+
PASSTHROUGH_CONTINUATION_LEAD_IN = "The tool calls from your previous turn were forwarded to the client, which has now executed them — " + "their results follow. The instruction to end that turn without further text applied to it alone and " + "is now discharged: continue the work and respond.";
|
|
1969
2112
|
MULTIMODAL_TYPES = new Set(["image", "document", "file"]);
|
|
1970
2113
|
TOOL_TARGET_KEYS = ["filePath", "file_path", "path", "command", "pattern", "query", "url"];
|
|
2114
|
+
TRANSPORT_HEADER_BLOCK = /^\s*x-anthropic-[a-z0-9-]*header\s*:/i;
|
|
1971
2115
|
});
|
|
1972
2116
|
|
|
1973
|
-
// src/proxy/fileChanges.ts
|
|
1974
|
-
function extractFileChange(toolName, toolInput, mcpPrefix) {
|
|
1975
|
-
if (!toolName.startsWith(mcpPrefix))
|
|
1976
|
-
return;
|
|
1977
|
-
const shortName = toolName.slice(mcpPrefix.length);
|
|
1978
|
-
const input = toolInput;
|
|
1979
|
-
if (shortName === "write" && input?.path) {
|
|
1980
|
-
return { operation: "wrote", path: String(input.path) };
|
|
1981
|
-
}
|
|
1982
|
-
if (shortName === "edit" && input?.path) {
|
|
1983
|
-
return { operation: "edited", path: String(input.path) };
|
|
1984
|
-
}
|
|
1985
|
-
return;
|
|
1986
|
-
}
|
|
1987
|
-
function createFileChangeHook(changes, mcpPrefix) {
|
|
1988
|
-
return {
|
|
1989
|
-
matcher: "",
|
|
1990
|
-
hooks: [async (input) => {
|
|
1991
|
-
const change = extractFileChange(input.tool_name, input.tool_input, mcpPrefix);
|
|
1992
|
-
if (change) {
|
|
1993
|
-
changes.push(change);
|
|
1994
|
-
return {};
|
|
1995
|
-
}
|
|
1996
|
-
if (input.tool_name === `${mcpPrefix}bash`) {
|
|
1997
|
-
const toolInput = input.tool_input;
|
|
1998
|
-
if (toolInput?.command) {
|
|
1999
|
-
const bashChanges = extractFileChangesFromBash(String(toolInput.command));
|
|
2000
|
-
changes.push(...bashChanges);
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
return {};
|
|
2004
|
-
}]
|
|
2005
|
-
};
|
|
2006
|
-
}
|
|
2007
|
-
function isLikelyFilePath(s) {
|
|
2008
|
-
if (s.length > 4096)
|
|
2009
|
-
return false;
|
|
2010
|
-
if (/[<>$`\\()[\]{}=]/.test(s))
|
|
2011
|
-
return false;
|
|
2012
|
-
if (/^-?\d+$/.test(s))
|
|
2013
|
-
return false;
|
|
2014
|
-
if (s.includes("/"))
|
|
2015
|
-
return true;
|
|
2016
|
-
if (/\.[A-Za-z0-9]{1,16}$/.test(s))
|
|
2017
|
-
return true;
|
|
2018
|
-
return false;
|
|
2019
|
-
}
|
|
2020
|
-
function extractFileChangesFromBash(command) {
|
|
2021
|
-
const changes = [];
|
|
2022
|
-
const seen = new Set;
|
|
2023
|
-
const addChange = (operation, path) => {
|
|
2024
|
-
if (path === "/dev/null" || path === "/dev/stderr" || path === "/dev/stdout")
|
|
2025
|
-
return;
|
|
2026
|
-
if (!path.trim())
|
|
2027
|
-
return;
|
|
2028
|
-
const key = `${operation}:${path}`;
|
|
2029
|
-
if (!seen.has(key)) {
|
|
2030
|
-
seen.add(key);
|
|
2031
|
-
changes.push({ operation, path });
|
|
2032
|
-
}
|
|
2033
|
-
};
|
|
2034
|
-
const redirectRegex = /(?<![0-9=])>{1,2}\s*['"]?([^\s'";&|)]+)['"]?/g;
|
|
2035
|
-
let match2;
|
|
2036
|
-
while ((match2 = redirectRegex.exec(command)) !== null) {
|
|
2037
|
-
if (isLikelyFilePath(match2[1])) {
|
|
2038
|
-
addChange("wrote", match2[1]);
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
const teeRegex = /\btee\s+(?:-[a-zA-Z]\s+)*['"]?([^\s'";&|)]+)['"]?/g;
|
|
2042
|
-
while ((match2 = teeRegex.exec(command)) !== null) {
|
|
2043
|
-
addChange("wrote", match2[1]);
|
|
2044
|
-
}
|
|
2045
|
-
const sedRegex = /\bsed\s+(?:-[a-zA-Z]*i[a-zA-Z]*|-i)\b.*?['"]?([^\s'";&|)]+)['"]?\s*$/gm;
|
|
2046
|
-
while ((match2 = sedRegex.exec(command)) !== null) {
|
|
2047
|
-
addChange("edited", match2[1]);
|
|
2048
|
-
}
|
|
2049
|
-
return changes;
|
|
2050
|
-
}
|
|
2051
|
-
function extractFileChangesFromMessages(messages, extractFn) {
|
|
2052
|
-
const changes = [];
|
|
2053
|
-
const executedToolIds = new Set;
|
|
2054
|
-
for (const msg of messages) {
|
|
2055
|
-
if (msg.role !== "user")
|
|
2056
|
-
continue;
|
|
2057
|
-
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
2058
|
-
for (const block of content) {
|
|
2059
|
-
if (block?.type === "tool_result" && block.tool_use_id) {
|
|
2060
|
-
executedToolIds.add(block.tool_use_id);
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
for (const msg of messages) {
|
|
2065
|
-
if (msg.role !== "assistant")
|
|
2066
|
-
continue;
|
|
2067
|
-
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
2068
|
-
for (const block of content) {
|
|
2069
|
-
if (block?.type !== "tool_use")
|
|
2070
|
-
continue;
|
|
2071
|
-
if (!executedToolIds.has(block.id))
|
|
2072
|
-
continue;
|
|
2073
|
-
const blockChanges = extractFn(block.name, block.input);
|
|
2074
|
-
changes.push(...blockChanges);
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
return changes;
|
|
2078
|
-
}
|
|
2079
|
-
function formatFileChangeSummary(changes) {
|
|
2080
|
-
if (changes.length === 0)
|
|
2081
|
-
return;
|
|
2082
|
-
const seen = new Set;
|
|
2083
|
-
const unique = [];
|
|
2084
|
-
for (const c of changes) {
|
|
2085
|
-
const key = `${c.operation}:${c.path}`;
|
|
2086
|
-
if (!seen.has(key)) {
|
|
2087
|
-
seen.add(key);
|
|
2088
|
-
unique.push(c);
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
const lines = unique.map((c) => `- ${c.operation} ${c.path}`);
|
|
2092
|
-
return `
|
|
2093
|
-
|
|
2094
|
-
Files changed:
|
|
2095
|
-
${lines.join(`
|
|
2096
|
-
`)}`;
|
|
2097
|
-
}
|
|
2098
|
-
var init_fileChanges = () => {};
|
|
2099
|
-
|
|
2100
2117
|
// src/proxy/session/fingerprint.ts
|
|
2101
2118
|
import { createHash } from "crypto";
|
|
2102
2119
|
function extractClientCwd(body) {
|
|
@@ -2142,7 +2159,7 @@ var init_opencode = __esm(() => {
|
|
|
2142
2159
|
openCodeTransforms = [
|
|
2143
2160
|
{
|
|
2144
2161
|
name: "opencode-core",
|
|
2145
|
-
adapters: ["opencode", "openai", "codex"],
|
|
2162
|
+
adapters: ["opencode", "openai", "jcode", "codex"],
|
|
2146
2163
|
onRequest(ctx) {
|
|
2147
2164
|
const body = ctx.body;
|
|
2148
2165
|
const blockedTools = BLOCKED_BUILTIN_TOOLS;
|
|
@@ -2316,6 +2333,51 @@ IMPORTANT: When using the task/Task tool, the subagent_type parameter must be on
|
|
|
2316
2333
|
};
|
|
2317
2334
|
});
|
|
2318
2335
|
|
|
2336
|
+
// src/proxy/adapters/openai.ts
|
|
2337
|
+
var openAiAdapter;
|
|
2338
|
+
var init_openai = __esm(() => {
|
|
2339
|
+
init_opencode2();
|
|
2340
|
+
openAiAdapter = {
|
|
2341
|
+
...openCodeAdapter,
|
|
2342
|
+
name: "openai"
|
|
2343
|
+
};
|
|
2344
|
+
});
|
|
2345
|
+
|
|
2346
|
+
// src/proxy/adapters/jcode.ts
|
|
2347
|
+
function normalizeJcodeSessionId(value) {
|
|
2348
|
+
const trimmed = value?.trim();
|
|
2349
|
+
return trimmed && JCODE_SESSION_ID.test(trimmed) ? trimmed : undefined;
|
|
2350
|
+
}
|
|
2351
|
+
function isTextSystemBlock(value) {
|
|
2352
|
+
if (value === null || typeof value !== "object")
|
|
2353
|
+
return false;
|
|
2354
|
+
const part = value;
|
|
2355
|
+
return part.type === "text" && typeof part.text === "string";
|
|
2356
|
+
}
|
|
2357
|
+
function extractJcodeWorkingDirectory(body) {
|
|
2358
|
+
if (body === null || typeof body !== "object")
|
|
2359
|
+
return;
|
|
2360
|
+
const system = body.system;
|
|
2361
|
+
const text = typeof system === "string" ? system : Array.isArray(system) ? system.filter(isTextSystemBlock).map((part) => part.text).join(`
|
|
2362
|
+
`) : "";
|
|
2363
|
+
return text.match(/(?:^|\n)Working directory:[^\S\n]*([^\n]+)/)?.[1]?.trim() || undefined;
|
|
2364
|
+
}
|
|
2365
|
+
var JCODE_SESSION_ID, jcodeAdapter;
|
|
2366
|
+
var init_jcode = __esm(() => {
|
|
2367
|
+
init_openai();
|
|
2368
|
+
JCODE_SESSION_ID = /^[A-Za-z0-9._:-]{1,256}$/;
|
|
2369
|
+
jcodeAdapter = {
|
|
2370
|
+
...openAiAdapter,
|
|
2371
|
+
name: "jcode",
|
|
2372
|
+
getSessionId(c) {
|
|
2373
|
+
return normalizeJcodeSessionId(c.req.header("x-jcode-session"));
|
|
2374
|
+
},
|
|
2375
|
+
extractWorkingDirectory(body) {
|
|
2376
|
+
return extractJcodeWorkingDirectory(body);
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
});
|
|
2380
|
+
|
|
2319
2381
|
// src/proxy/transforms/droid.ts
|
|
2320
2382
|
function resolveDroidPassthrough() {
|
|
2321
2383
|
return resolvePassthrough(false);
|
|
@@ -2999,16 +3061,6 @@ var init_forgecode2 = __esm(() => {
|
|
|
2999
3061
|
};
|
|
3000
3062
|
});
|
|
3001
3063
|
|
|
3002
|
-
// src/proxy/adapters/openai.ts
|
|
3003
|
-
var openAiAdapter;
|
|
3004
|
-
var init_openai = __esm(() => {
|
|
3005
|
-
init_opencode2();
|
|
3006
|
-
openAiAdapter = {
|
|
3007
|
-
...openCodeAdapter,
|
|
3008
|
-
name: "openai"
|
|
3009
|
-
};
|
|
3010
|
-
});
|
|
3011
|
-
|
|
3012
3064
|
// src/proxy/adapters/codex.ts
|
|
3013
3065
|
var codexAdapter;
|
|
3014
3066
|
var init_codex = __esm(() => {
|
|
@@ -3193,6 +3245,9 @@ function detectAdapter(c) {
|
|
|
3193
3245
|
return openCodeAdapter;
|
|
3194
3246
|
}
|
|
3195
3247
|
const userAgent = c.req.header("user-agent") || "";
|
|
3248
|
+
if (userAgent.startsWith("jcode/") && normalizeJcodeSessionId(c.req.header("x-jcode-session"))) {
|
|
3249
|
+
return jcodeAdapter;
|
|
3250
|
+
}
|
|
3196
3251
|
if (userAgent.startsWith("opencode/")) {
|
|
3197
3252
|
return openCodeAdapter;
|
|
3198
3253
|
}
|
|
@@ -3227,6 +3282,7 @@ var init_detect = __esm(() => {
|
|
|
3227
3282
|
init_forgecode2();
|
|
3228
3283
|
init_claudecode();
|
|
3229
3284
|
init_openai();
|
|
3285
|
+
init_jcode();
|
|
3230
3286
|
init_codex();
|
|
3231
3287
|
init_cherry();
|
|
3232
3288
|
init_adapterInstances();
|
|
@@ -3242,6 +3298,7 @@ var init_detect = __esm(() => {
|
|
|
3242
3298
|
cherry: cherryAdapter,
|
|
3243
3299
|
cherrystudio: cherryAdapter,
|
|
3244
3300
|
openai: openAiAdapter,
|
|
3301
|
+
jcode: jcodeAdapter,
|
|
3245
3302
|
codex: codexAdapter
|
|
3246
3303
|
};
|
|
3247
3304
|
envDefault = process.env.MERIDIAN_DEFAULT_AGENT || "";
|
|
@@ -3379,6 +3436,7 @@ var init_sdkFeatures = __esm(() => {
|
|
|
3379
3436
|
thinkingPassthrough: false,
|
|
3380
3437
|
sharedMemory: false,
|
|
3381
3438
|
webFetchPreflight: true,
|
|
3439
|
+
claudeAiConnectors: false,
|
|
3382
3440
|
maxBudgetUsd: 0,
|
|
3383
3441
|
fallbackModel: "",
|
|
3384
3442
|
sdkDebug: false,
|
|
@@ -3391,6 +3449,9 @@ var init_sdkFeatures = __esm(() => {
|
|
|
3391
3449
|
openai: {
|
|
3392
3450
|
codeSystemPrompt: false
|
|
3393
3451
|
},
|
|
3452
|
+
jcode: {
|
|
3453
|
+
codeSystemPrompt: false
|
|
3454
|
+
},
|
|
3394
3455
|
cherry: {
|
|
3395
3456
|
codeSystemPrompt: false
|
|
3396
3457
|
},
|
|
@@ -3587,6 +3648,7 @@ const FEATURES = [
|
|
|
3587
3648
|
{ key: 'thinkingPassthrough', label: 'Thinking Passthrough', desc: 'Forward thinking blocks to the client', type: 'toggle' },
|
|
3588
3649
|
{ key: 'sharedMemory', label: 'Shared Memory', desc: 'Share memory with Claude Code (~/.claude) instead of isolated storage', type: 'toggle' },
|
|
3589
3650
|
{ key: 'webFetchPreflight', label: 'WebFetch Preflight', desc: 'Check each WebFetch hostname against the Anthropic blocklist before fetching — off keeps hostnames local but fetches any URL unchecked. Only affects Cherry Studio; other adapters never run the SDK\\'s built-in WebFetch', type: 'toggle' },
|
|
3651
|
+
{ key: 'claudeAiConnectors', label: 'claude.ai Connectors', desc: 'Load the MCP connectors attached to your claude.ai account (Drive, Gmail, Calendar). Off by default; always off in passthrough mode', type: 'toggle' },
|
|
3590
3652
|
{ key: 'maxBudgetUsd', label: 'Max Budget (USD)', desc: 'Per-request cost cap — query aborts if exceeded (0 = disabled)', type: 'number' },
|
|
3591
3653
|
{ key: 'fallbackModel', label: 'Fallback Model', desc: 'Auto-fallback model if primary fails', type: 'select', options: ['', 'sonnet', 'opus', 'haiku', 'sonnet[1m]', 'opus[1m]'] },
|
|
3592
3654
|
{ key: 'sdkDebug', label: 'SDK Debug Logging', desc: 'Enable verbose SDK debug output to proxy stderr', type: 'toggle' },
|
|
@@ -3645,7 +3707,8 @@ function showSaved() {
|
|
|
3645
3707
|
function hasAnyEnabled(features) {
|
|
3646
3708
|
return features.codeSystemPrompt || !features.clientSystemPrompt || features.claudeMd !== 'off' || features.memory || features.dreaming ||
|
|
3647
3709
|
features.thinking !== 'disabled' || features.thinkingPassthrough ||
|
|
3648
|
-
features.sharedMemory || features.webFetchPreflight === false ||
|
|
3710
|
+
features.sharedMemory || features.webFetchPreflight === false ||
|
|
3711
|
+
features.claudeAiConnectors || features.maxBudgetUsd > 0 ||
|
|
3649
3712
|
features.fallbackModel || features.sdkDebug ||
|
|
3650
3713
|
features.additionalDirectories;
|
|
3651
3714
|
}
|
|
@@ -6282,8 +6345,10 @@ var OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
|
6282
6345
|
var OAUTH_BETA_HEADER = "oauth-2025-04-20";
|
|
6283
6346
|
var CACHE_TTL_MS_DEFAULT = 30000;
|
|
6284
6347
|
var STALE_MAX_MS_DEFAULT = 15 * 60000;
|
|
6348
|
+
var RATE_LIMIT_BACKOFF_MS_DEFAULT = 60000;
|
|
6285
6349
|
var cacheByProfile = new Map;
|
|
6286
6350
|
var inflightByProfile = new Map;
|
|
6351
|
+
var rateLimitedUntilByProfile = new Map;
|
|
6287
6352
|
var DEFAULT_KEY = "__default__";
|
|
6288
6353
|
var WINDOW_TYPES = [
|
|
6289
6354
|
"five_hour",
|
|
@@ -6305,6 +6370,15 @@ function normalizeUtilization(raw2) {
|
|
|
6305
6370
|
return null;
|
|
6306
6371
|
return Math.max(0, raw2 / 100);
|
|
6307
6372
|
}
|
|
6373
|
+
function parseRetryAfterMs(raw2) {
|
|
6374
|
+
if (!raw2)
|
|
6375
|
+
return null;
|
|
6376
|
+
const seconds = Number(raw2);
|
|
6377
|
+
if (Number.isFinite(seconds))
|
|
6378
|
+
return Math.max(0, seconds * 1000);
|
|
6379
|
+
const retryAt = Date.parse(raw2);
|
|
6380
|
+
return Number.isFinite(retryAt) ? Math.max(0, retryAt - Date.now()) : null;
|
|
6381
|
+
}
|
|
6308
6382
|
function modelScopedWindowType(limit) {
|
|
6309
6383
|
if (limit.kind !== "weekly_scoped")
|
|
6310
6384
|
return null;
|
|
@@ -6362,14 +6436,27 @@ async function callAnthropic(token, fetchImpl, signal) {
|
|
|
6362
6436
|
},
|
|
6363
6437
|
signal: signal ?? AbortSignal.timeout(1e4)
|
|
6364
6438
|
});
|
|
6365
|
-
if (!res.ok)
|
|
6366
|
-
return {
|
|
6439
|
+
if (!res.ok) {
|
|
6440
|
+
return {
|
|
6441
|
+
__status: res.status,
|
|
6442
|
+
retryAfterMs: parseRetryAfterMs(res.headers.get("retry-after"))
|
|
6443
|
+
};
|
|
6444
|
+
}
|
|
6367
6445
|
return await res.json();
|
|
6368
6446
|
}
|
|
6369
6447
|
var _testOverride = null;
|
|
6370
6448
|
async function fetchOAuthUsage(opts) {
|
|
6449
|
+
return (await fetchOAuthUsageResult(opts)).snapshot;
|
|
6450
|
+
}
|
|
6451
|
+
function missingReason(cacheKey2) {
|
|
6452
|
+
const until = rateLimitedUntilByProfile.get(cacheKey2);
|
|
6453
|
+
return until !== undefined && Date.now() < until ? "rate_limited" : "no_token";
|
|
6454
|
+
}
|
|
6455
|
+
async function fetchOAuthUsageResult(opts) {
|
|
6371
6456
|
if (_testOverride && !opts?.fetchImpl && !opts?.store) {
|
|
6372
|
-
|
|
6457
|
+
const snapshot = await _testOverride(opts);
|
|
6458
|
+
const error = snapshot ? null : missingReason(opts?.profileId ?? DEFAULT_KEY);
|
|
6459
|
+
return { snapshot, error };
|
|
6373
6460
|
}
|
|
6374
6461
|
return fetchOAuthUsageImpl(opts);
|
|
6375
6462
|
}
|
|
@@ -6377,30 +6464,37 @@ async function fetchOAuthUsageImpl(opts) {
|
|
|
6377
6464
|
const ttl = opts?.ttlMs ?? CACHE_TTL_MS_DEFAULT;
|
|
6378
6465
|
const cacheKey2 = opts?.profileId ?? DEFAULT_KEY;
|
|
6379
6466
|
const fetchImpl = opts?.fetchImpl ?? globalThis.fetch;
|
|
6467
|
+
const staleMaxMs = opts?.staleMaxMs ?? STALE_MAX_MS_DEFAULT;
|
|
6468
|
+
const staleOr = (reason, error) => {
|
|
6469
|
+
const last = cacheByProfile.get(cacheKey2);
|
|
6470
|
+
if (last && Date.now() - last.fetchedAt < staleMaxMs) {
|
|
6471
|
+
claudeLog("oauth_usage.serving_stale", { profile: cacheKey2, reason, ageMs: Date.now() - last.fetchedAt });
|
|
6472
|
+
return { snapshot: { ...last, stale: true }, error: null };
|
|
6473
|
+
}
|
|
6474
|
+
return { snapshot: null, error };
|
|
6475
|
+
};
|
|
6380
6476
|
if (!opts?.force) {
|
|
6381
6477
|
const cached = cacheByProfile.get(cacheKey2);
|
|
6382
6478
|
if (cached && Date.now() - cached.fetchedAt < ttl)
|
|
6383
|
-
return cached;
|
|
6479
|
+
return { snapshot: cached, error: null };
|
|
6384
6480
|
}
|
|
6385
6481
|
const existing = inflightByProfile.get(cacheKey2);
|
|
6386
6482
|
if (existing)
|
|
6387
6483
|
return existing;
|
|
6484
|
+
const rateLimitedUntil = rateLimitedUntilByProfile.get(cacheKey2);
|
|
6485
|
+
if (rateLimitedUntil !== undefined) {
|
|
6486
|
+
if (Date.now() < rateLimitedUntil)
|
|
6487
|
+
return staleOr("rate_limited", "rate_limited");
|
|
6488
|
+
rateLimitedUntilByProfile.delete(cacheKey2);
|
|
6489
|
+
}
|
|
6388
6490
|
const store = opts?.store ?? createPlatformCredentialStore({ claudeConfigDir: opts?.claudeConfigDir });
|
|
6389
|
-
const
|
|
6390
|
-
const staleOr = (reason) => {
|
|
6391
|
-
const last = cacheByProfile.get(cacheKey2);
|
|
6392
|
-
if (last && Date.now() - last.fetchedAt < staleMaxMs) {
|
|
6393
|
-
claudeLog("oauth_usage.serving_stale", { profile: cacheKey2, reason, ageMs: Date.now() - last.fetchedAt });
|
|
6394
|
-
return { ...last, stale: true };
|
|
6395
|
-
}
|
|
6396
|
-
return null;
|
|
6397
|
-
};
|
|
6491
|
+
const rateLimitBackoffMs = opts?.rateLimitBackoffMs ?? RATE_LIMIT_BACKOFF_MS_DEFAULT;
|
|
6398
6492
|
const promise = (async () => {
|
|
6399
6493
|
try {
|
|
6400
6494
|
const token = await readAccessToken(store);
|
|
6401
6495
|
if (!token) {
|
|
6402
6496
|
claudeLog("oauth_usage.no_token", { profile: cacheKey2 });
|
|
6403
|
-
return staleOr("no_token");
|
|
6497
|
+
return staleOr("no_token", "no_token");
|
|
6404
6498
|
}
|
|
6405
6499
|
let result = await callAnthropic(token, fetchImpl);
|
|
6406
6500
|
if ("__status" in result && result.__status === 401) {
|
|
@@ -6408,23 +6502,28 @@ async function fetchOAuthUsageImpl(opts) {
|
|
|
6408
6502
|
const refreshed = await refreshOAuthToken(store);
|
|
6409
6503
|
if (!refreshed) {
|
|
6410
6504
|
claudeLog("oauth_usage.refresh_failed", { profile: cacheKey2 });
|
|
6411
|
-
return staleOr("refresh_failed");
|
|
6505
|
+
return staleOr("refresh_failed", "upstream_error");
|
|
6412
6506
|
}
|
|
6413
6507
|
const newToken = await readAccessToken(store);
|
|
6414
6508
|
if (!newToken)
|
|
6415
|
-
return staleOr("no_token_after_refresh");
|
|
6509
|
+
return staleOr("no_token_after_refresh", "no_token");
|
|
6416
6510
|
result = await callAnthropic(newToken, fetchImpl);
|
|
6417
6511
|
}
|
|
6418
6512
|
if ("__status" in result) {
|
|
6513
|
+
if (result.__status === 429) {
|
|
6514
|
+
const retryAfterMs = Math.min(Math.max(rateLimitBackoffMs, result.retryAfterMs ?? 0), Math.max(staleMaxMs, rateLimitBackoffMs));
|
|
6515
|
+
rateLimitedUntilByProfile.set(cacheKey2, Date.now() + retryAfterMs);
|
|
6516
|
+
}
|
|
6419
6517
|
claudeLog("oauth_usage.upstream_error", { profile: cacheKey2, status: result.__status });
|
|
6420
|
-
return staleOr(`upstream_${result.__status}
|
|
6518
|
+
return staleOr(`upstream_${result.__status}`, result.__status === 429 ? "rate_limited" : "upstream_error");
|
|
6421
6519
|
}
|
|
6520
|
+
rateLimitedUntilByProfile.delete(cacheKey2);
|
|
6422
6521
|
const snapshot = buildSnapshot(result);
|
|
6423
6522
|
cacheByProfile.set(cacheKey2, snapshot);
|
|
6424
|
-
return snapshot;
|
|
6523
|
+
return { snapshot, error: null };
|
|
6425
6524
|
} catch (err) {
|
|
6426
6525
|
claudeLog("oauth_usage.fetch_failed", { profile: cacheKey2, error: err instanceof Error ? err.message : String(err) });
|
|
6427
|
-
return staleOr("exception");
|
|
6526
|
+
return staleOr("exception", "upstream_error");
|
|
6428
6527
|
} finally {
|
|
6429
6528
|
inflightByProfile.delete(cacheKey2);
|
|
6430
6529
|
}
|
|
@@ -10703,6 +10802,31 @@ function shouldEarlyStop(tracker) {
|
|
|
10703
10802
|
tracker.fired = true;
|
|
10704
10803
|
return true;
|
|
10705
10804
|
}
|
|
10805
|
+
function clientAbortDisposition(input) {
|
|
10806
|
+
if (input.isIndependentSession || !input.profileSessionId)
|
|
10807
|
+
return { action: "none" };
|
|
10808
|
+
if (!input.passthrough)
|
|
10809
|
+
return { action: "evict" };
|
|
10810
|
+
if (input.currentSessionId && !input.sawDuplicateToolUse && input.resumeBoundaryUuid) {
|
|
10811
|
+
return { action: "store", resumeUuid: input.resumeBoundaryUuid };
|
|
10812
|
+
}
|
|
10813
|
+
return { action: "evict" };
|
|
10814
|
+
}
|
|
10815
|
+
function resumeBoundaryUuid(message) {
|
|
10816
|
+
const m = message;
|
|
10817
|
+
if (m?.type !== "user")
|
|
10818
|
+
return;
|
|
10819
|
+
if (typeof m.uuid !== "string" || m.uuid.length === 0)
|
|
10820
|
+
return;
|
|
10821
|
+
const content = m.message?.content;
|
|
10822
|
+
if (!Array.isArray(content))
|
|
10823
|
+
return;
|
|
10824
|
+
const hasResult = content.some((block) => {
|
|
10825
|
+
const b = block;
|
|
10826
|
+
return b?.type === "tool_result";
|
|
10827
|
+
});
|
|
10828
|
+
return hasResult ? m.uuid : undefined;
|
|
10829
|
+
}
|
|
10706
10830
|
|
|
10707
10831
|
// src/proxy/envelopeIntegrity.ts
|
|
10708
10832
|
function checkEmptyToolInputs(contentBlocks, tools) {
|
|
@@ -10743,6 +10867,68 @@ function checkUndeliveredToolUses(captured, deliveredIds) {
|
|
|
10743
10867
|
return violations;
|
|
10744
10868
|
}
|
|
10745
10869
|
|
|
10870
|
+
// src/proxy/turnOutcome.ts
|
|
10871
|
+
function classifyTurnOutcome(input) {
|
|
10872
|
+
if (input.toolUses > 0)
|
|
10873
|
+
return { kind: "productive" };
|
|
10874
|
+
if (input.textEvents > 0)
|
|
10875
|
+
return { kind: "productive" };
|
|
10876
|
+
return {
|
|
10877
|
+
kind: "silent",
|
|
10878
|
+
reason: input.blocksForwarded > 0 ? "no_actionable_content" : "no_blocks"
|
|
10879
|
+
};
|
|
10880
|
+
}
|
|
10881
|
+
var SILENT_TURN_NUDGE = "Your previous turn produced no visible output — no text and no tool call — so the client received " + "nothing to act on. Any earlier instruction to end your turn without further text applied only to " + "that turn and is now discharged. Answer now, in text, addressing the most recent request and any " + "tool results above it. If a tool call is still required, make it.";
|
|
10882
|
+
function shouldInjectSilentTurn(input) {
|
|
10883
|
+
if (!input.raw)
|
|
10884
|
+
return false;
|
|
10885
|
+
if (input.raw === "1")
|
|
10886
|
+
return true;
|
|
10887
|
+
return Boolean(input.sessionId && input.raw === input.sessionId);
|
|
10888
|
+
}
|
|
10889
|
+
function createRecoveryLifter(allocateBlockIndex) {
|
|
10890
|
+
let blockIndex;
|
|
10891
|
+
return {
|
|
10892
|
+
lift(innerEvent) {
|
|
10893
|
+
const inner = innerEvent;
|
|
10894
|
+
if (!inner)
|
|
10895
|
+
return;
|
|
10896
|
+
if (inner.type === "content_block_start" && inner.content_block?.type === "text") {
|
|
10897
|
+
blockIndex = allocateBlockIndex();
|
|
10898
|
+
return {
|
|
10899
|
+
kind: "block_start",
|
|
10900
|
+
frame: { type: "content_block_start", index: blockIndex, content_block: { type: "text", text: "" } }
|
|
10901
|
+
};
|
|
10902
|
+
}
|
|
10903
|
+
if (inner.type === "content_block_delta" && inner.delta?.type === "text_delta" && blockIndex !== undefined) {
|
|
10904
|
+
const text = inner.delta.text;
|
|
10905
|
+
return {
|
|
10906
|
+
kind: "text_delta",
|
|
10907
|
+
frame: { type: "content_block_delta", index: blockIndex, delta: { type: "text_delta", text } },
|
|
10908
|
+
textChars: typeof text === "string" ? text.length : 0
|
|
10909
|
+
};
|
|
10910
|
+
}
|
|
10911
|
+
if (inner.type === "content_block_stop" && blockIndex !== undefined) {
|
|
10912
|
+
const index = blockIndex;
|
|
10913
|
+
blockIndex = undefined;
|
|
10914
|
+
return { kind: "block_stop", frame: { type: "content_block_stop", index } };
|
|
10915
|
+
}
|
|
10916
|
+
return;
|
|
10917
|
+
}
|
|
10918
|
+
};
|
|
10919
|
+
}
|
|
10920
|
+
function shouldAttemptRecovery(input) {
|
|
10921
|
+
if (!input.enabled)
|
|
10922
|
+
return false;
|
|
10923
|
+
if (input.outcome.kind === "productive")
|
|
10924
|
+
return false;
|
|
10925
|
+
if (input.alreadyAttempted)
|
|
10926
|
+
return false;
|
|
10927
|
+
if (input.clientGone)
|
|
10928
|
+
return false;
|
|
10929
|
+
return Boolean(input.sessionId);
|
|
10930
|
+
}
|
|
10931
|
+
|
|
10746
10932
|
// src/proxy/server.ts
|
|
10747
10933
|
init_agentMatch();
|
|
10748
10934
|
|
|
@@ -11768,6 +11954,7 @@ function extendedContextHint(model) {
|
|
|
11768
11954
|
return advise("MERIDIAN_SONNET_MODEL=sonnet");
|
|
11769
11955
|
return advise("MERIDIAN_1M_CONTEXT_SUPPORT=0");
|
|
11770
11956
|
}
|
|
11957
|
+
var HIT_YOUR_LIMIT = /hit your (?:[\w-]+ )?limit/;
|
|
11771
11958
|
function classifyError(errMsg, model) {
|
|
11772
11959
|
const lower = errMsg.toLowerCase();
|
|
11773
11960
|
if (lower.includes("oauth token has expired") || lower.includes("not logged in")) {
|
|
@@ -11784,7 +11971,7 @@ function classifyError(errMsg, model) {
|
|
|
11784
11971
|
message: "Claude authentication expired or invalid. Run 'claude login' in your terminal to re-authenticate, then restart the proxy."
|
|
11785
11972
|
};
|
|
11786
11973
|
}
|
|
11787
|
-
if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests") ||
|
|
11974
|
+
if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests") || HIT_YOUR_LIMIT.test(lower) || lower.includes("usage limit reached")) {
|
|
11788
11975
|
const hint = lower.includes("1m") || lower.includes("context") ? extendedContextHint(model) : "";
|
|
11789
11976
|
return {
|
|
11790
11977
|
status: 429,
|
|
@@ -12267,7 +12454,7 @@ ${c.text}
|
|
|
12267
12454
|
return "";
|
|
12268
12455
|
}).filter(Boolean).join("");
|
|
12269
12456
|
}
|
|
12270
|
-
function translateOpenAiToAnthropic(body) {
|
|
12457
|
+
function translateOpenAiToAnthropic(body, options = {}) {
|
|
12271
12458
|
const messages = body.messages ?? [];
|
|
12272
12459
|
if (messages.length === 0)
|
|
12273
12460
|
return null;
|
|
@@ -12359,7 +12546,7 @@ function translateOpenAiToAnthropic(body) {
|
|
|
12359
12546
|
let systemPrompt = systemParts.join(`
|
|
12360
12547
|
`);
|
|
12361
12548
|
let messagesToSend = turns;
|
|
12362
|
-
if (turns.length > 1) {
|
|
12549
|
+
if (turns.length > 1 && !options.preserveConversationHistory) {
|
|
12363
12550
|
const history = turns.slice(0, -1).map((m) => `${m.role}: ${summarizeAnthropicContent(m.content)}`).join(`
|
|
12364
12551
|
`);
|
|
12365
12552
|
const historyBlock = `<conversation_history>
|
|
@@ -12654,6 +12841,9 @@ function buildModelList(isMaxSubscription, now = Math.floor(Date.now() / 1000))
|
|
|
12654
12841
|
];
|
|
12655
12842
|
}
|
|
12656
12843
|
|
|
12844
|
+
// src/proxy/server.ts
|
|
12845
|
+
init_jcode();
|
|
12846
|
+
|
|
12657
12847
|
// src/proxy/openaiResponses.ts
|
|
12658
12848
|
function itemDiscriminator(item) {
|
|
12659
12849
|
if (typeof item !== "object" || item === null)
|
|
@@ -18846,7 +19036,7 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
18846
19036
|
hasDeferredTools,
|
|
18847
19037
|
resumeSessionId,
|
|
18848
19038
|
isUndo,
|
|
18849
|
-
|
|
19039
|
+
resumeSessionAtUuid,
|
|
18850
19040
|
forkSession,
|
|
18851
19041
|
sdkHooks,
|
|
18852
19042
|
blockedTools,
|
|
@@ -18909,7 +19099,7 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
18909
19099
|
...QUIET_SUBPROCESS_ENV,
|
|
18910
19100
|
...sharedMemory ? stripConfigDir(cleanEnv) : cleanEnv,
|
|
18911
19101
|
ENABLE_TOOL_SEARCH: hasDeferredTools ? "true" : "false",
|
|
18912
|
-
|
|
19102
|
+
ENABLE_CLAUDEAI_MCP_SERVERS: !passthrough && ctx.claudeAiConnectors === true ? "true" : "false",
|
|
18913
19103
|
...passthrough && process.env.MERIDIAN_SUPPRESS_SCRATCHPAD !== "0" ? { CLAUDE_CODE_SESSION_KIND: "bg" } : {},
|
|
18914
19104
|
...process.getuid?.() === 0 ? { IS_SANDBOX: "1" } : {},
|
|
18915
19105
|
...ctx.envOverrides
|
|
@@ -18917,7 +19107,7 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
18917
19107
|
...Object.keys(sdkAgents).length > 0 ? { agents: sdkAgents } : {},
|
|
18918
19108
|
...resumeSessionId ? { resume: resumeSessionId } : {},
|
|
18919
19109
|
...isUndo || forkSession ? { forkSession: true } : {},
|
|
18920
|
-
...
|
|
19110
|
+
...resumeSessionAtUuid ? { resumeSessionAt: resumeSessionAtUuid } : {},
|
|
18921
19111
|
...sdkHooks ? { hooks: sdkHooks } : {},
|
|
18922
19112
|
...effort ? { effort } : {},
|
|
18923
19113
|
...thinking ? { thinking } : {},
|
|
@@ -19064,6 +19254,7 @@ var ADAPTER_TRANSFORMS = {
|
|
|
19064
19254
|
cherry: cherryTransforms,
|
|
19065
19255
|
"claude-code": claudeCodeTransforms,
|
|
19066
19256
|
openai: openCodeTransforms,
|
|
19257
|
+
jcode: openCodeTransforms,
|
|
19067
19258
|
codex: [...openCodeTransforms, ...codexTransforms]
|
|
19068
19259
|
};
|
|
19069
19260
|
function getAdapterTransforms(adapterName) {
|
|
@@ -19076,7 +19267,7 @@ import { join as join5, isAbsolute as isAbsolute2, extname } from "path";
|
|
|
19076
19267
|
import { pathToFileURL } from "url";
|
|
19077
19268
|
|
|
19078
19269
|
// src/proxy/plugins/validation.ts
|
|
19079
|
-
var KNOWN_ADAPTERS = ["opencode", "openai", "crush", "droid", "pi", "forgecode", "passthrough"];
|
|
19270
|
+
var KNOWN_ADAPTERS = ["opencode", "openai", "jcode", "crush", "droid", "pi", "forgecode", "passthrough"];
|
|
19080
19271
|
var KNOWN_HOOKS = ["onRequest", "onResponse", "onTelemetry", "onSession", "onToolUse", "onToolResult", "onError"];
|
|
19081
19272
|
function validateTransform(exported) {
|
|
19082
19273
|
if (exported == null || typeof exported !== "object") {
|
|
@@ -19436,6 +19627,19 @@ function computeMessageHashes(messages) {
|
|
|
19436
19627
|
return [];
|
|
19437
19628
|
return messages.map(hashMessage);
|
|
19438
19629
|
}
|
|
19630
|
+
function hashNormalizedContent(content) {
|
|
19631
|
+
return createHash2("sha256").update(normalizeContent(content)).digest("hex").slice(0, 32);
|
|
19632
|
+
}
|
|
19633
|
+
function hashableContentBlocks(content) {
|
|
19634
|
+
if (!Array.isArray(content))
|
|
19635
|
+
return [content];
|
|
19636
|
+
return content.filter((block) => !HASH_IGNORED_BLOCK_TYPES.has(block?.type));
|
|
19637
|
+
}
|
|
19638
|
+
function computeMessageBlockHashes(messages) {
|
|
19639
|
+
if (!messages || messages.length === 0)
|
|
19640
|
+
return [];
|
|
19641
|
+
return messages.map((message) => hashableContentBlocks(message.content).map((block) => hashNormalizedContent(Array.isArray(message.content) ? [block] : block)));
|
|
19642
|
+
}
|
|
19439
19643
|
function measurePrefixOverlap(storedHashes, incomingHashes) {
|
|
19440
19644
|
let overlap = 0;
|
|
19441
19645
|
const minLen = Math.min(storedHashes.length, incomingHashes.length);
|
|
@@ -19518,6 +19722,34 @@ function verifyLineage(cached, messages) {
|
|
|
19518
19722
|
suffixOverlap
|
|
19519
19723
|
};
|
|
19520
19724
|
}
|
|
19725
|
+
const boundary = cached.messageCount - 1;
|
|
19726
|
+
if (boundary >= 0 && prefixOverlap === boundary && messages.length >= cached.messageCount && cached.messageBlockHashes?.length === cached.messageCount) {
|
|
19727
|
+
const incomingBoundary = messages[boundary];
|
|
19728
|
+
const storedBlocks = cached.messageBlockHashes[boundary];
|
|
19729
|
+
if (incomingBoundary?.role === "user" && storedBlocks && Array.isArray(incomingBoundary.content)) {
|
|
19730
|
+
const incomingBlocks = hashableContentBlocks(incomingBoundary.content);
|
|
19731
|
+
const incomingBlockHashes = incomingBlocks.map((block) => hashNormalizedContent([block]));
|
|
19732
|
+
const preservesStoredBlocks = incomingBlocks.length === incomingBoundary.content.length && incomingBlockHashes.length > storedBlocks.length && storedBlocks.every((hash, index) => incomingBlockHashes[index] === hash);
|
|
19733
|
+
const appendedBlocks = incomingBlocks.slice(storedBlocks.length);
|
|
19734
|
+
const seenToolResultIds = new Set(incomingBlocks.slice(0, storedBlocks.length).filter((block) => block?.type === "tool_result" && typeof block.tool_use_id === "string").map((block) => block.tool_use_id));
|
|
19735
|
+
const hasOnlyNewToolResults = appendedBlocks.every((block) => {
|
|
19736
|
+
if (block?.type !== "tool_result" || typeof block.tool_use_id !== "string")
|
|
19737
|
+
return false;
|
|
19738
|
+
if (seenToolResultIds.has(block.tool_use_id))
|
|
19739
|
+
return false;
|
|
19740
|
+
seenToolResultIds.add(block.tool_use_id);
|
|
19741
|
+
return true;
|
|
19742
|
+
});
|
|
19743
|
+
if (preservesStoredBlocks && hasOnlyNewToolResults) {
|
|
19744
|
+
return {
|
|
19745
|
+
type: "continuation",
|
|
19746
|
+
session: cached,
|
|
19747
|
+
resumeFrom: boundary,
|
|
19748
|
+
resumeContentFrom: storedBlocks.length
|
|
19749
|
+
};
|
|
19750
|
+
}
|
|
19751
|
+
}
|
|
19752
|
+
}
|
|
19521
19753
|
if (prefixOverlap > 0 && suffixOverlap === 0 && messages.length <= cached.messageCount) {
|
|
19522
19754
|
let rollbackUuid;
|
|
19523
19755
|
if (cached.sdkMessageUuids) {
|
|
@@ -19664,7 +19896,7 @@ function lookupSharedSessionByClaudeId(claudeSessionId) {
|
|
|
19664
19896
|
}
|
|
19665
19897
|
return newest;
|
|
19666
19898
|
}
|
|
19667
|
-
function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage) {
|
|
19899
|
+
function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage, messageBlockHashes, passthroughResumeUuid) {
|
|
19668
19900
|
const path3 = getStorePath();
|
|
19669
19901
|
const lockPath = `${path3}.lock`;
|
|
19670
19902
|
const hasLock = skipLocking ? false : acquireLock(lockPath);
|
|
@@ -19682,7 +19914,9 @@ function storeSharedSession(key, claudeSessionId, messageCount, lineageHash, mes
|
|
|
19682
19914
|
messageCount: messageCount ?? existing?.messageCount ?? 0,
|
|
19683
19915
|
lineageHash: lineageHash ?? existing?.lineageHash,
|
|
19684
19916
|
messageHashes: messageHashes ?? existing?.messageHashes,
|
|
19917
|
+
messageBlockHashes: messageBlockHashes ?? existing?.messageBlockHashes,
|
|
19685
19918
|
sdkMessageUuids: sdkMessageUuids ?? existing?.sdkMessageUuids,
|
|
19919
|
+
passthroughResumeUuid: passthroughResumeUuid === undefined ? existing?.passthroughResumeUuid : passthroughResumeUuid ?? undefined,
|
|
19686
19920
|
contextUsage: contextUsage ?? existing?.contextUsage,
|
|
19687
19921
|
...previousClaudeSessionId ? { previousClaudeSessionId } : {}
|
|
19688
19922
|
};
|
|
@@ -19840,7 +20074,11 @@ function touchSession(state) {
|
|
|
19840
20074
|
}
|
|
19841
20075
|
function classifyLineage(state, messages, cacheKey2) {
|
|
19842
20076
|
const result = verifyLineage(state, messages);
|
|
19843
|
-
if (result.type === "
|
|
20077
|
+
if (result.type === "continuation" && result.resumeContentFrom !== undefined) {
|
|
20078
|
+
const msg = `Parallel tool-result continuation (key=${cacheKey2.slice(0, 8)}…): resume from message ${result.resumeFrom}, content block ${result.resumeContentFrom}.`;
|
|
20079
|
+
console.error(`[PROXY] ${msg}`);
|
|
20080
|
+
diagnosticLog2.lineage(msg);
|
|
20081
|
+
} else if (result.type === "compaction") {
|
|
19844
20082
|
const msg = `Compaction detected (key=${cacheKey2.slice(0, 8)}…): suffix overlap ${result.suffixOverlap}/${state.messageCount}, resume from incoming message ${result.resumeFrom}.`;
|
|
19845
20083
|
console.error(`[PROXY] ${msg}`);
|
|
19846
20084
|
diagnosticLog2.lineage(msg);
|
|
@@ -19872,7 +20110,9 @@ function lookupSession(sessionId, messages, workingDirectory) {
|
|
|
19872
20110
|
messageCount: shared.messageCount || 0,
|
|
19873
20111
|
lineageHash: shared.lineageHash || "",
|
|
19874
20112
|
messageHashes: shared.messageHashes,
|
|
20113
|
+
messageBlockHashes: shared.messageBlockHashes,
|
|
19875
20114
|
sdkMessageUuids: shared.sdkMessageUuids,
|
|
20115
|
+
passthroughResumeUuid: shared.passthroughResumeUuid,
|
|
19876
20116
|
contextUsage: shared.contextUsage
|
|
19877
20117
|
};
|
|
19878
20118
|
const result = classifyLineage(state, messages, sessionId);
|
|
@@ -19900,7 +20140,9 @@ function lookupSession(sessionId, messages, workingDirectory) {
|
|
|
19900
20140
|
messageCount: shared.messageCount || 0,
|
|
19901
20141
|
lineageHash: shared.lineageHash || "",
|
|
19902
20142
|
messageHashes: shared.messageHashes,
|
|
20143
|
+
messageBlockHashes: shared.messageBlockHashes,
|
|
19903
20144
|
sdkMessageUuids: shared.sdkMessageUuids,
|
|
20145
|
+
passthroughResumeUuid: shared.passthroughResumeUuid,
|
|
19904
20146
|
contextUsage: shared.contextUsage
|
|
19905
20147
|
};
|
|
19906
20148
|
const result = classifyLineage(state, messages, fp);
|
|
@@ -19933,24 +20175,29 @@ function getSessionByClaudeId(claudeSessionId) {
|
|
|
19933
20175
|
messageCount: shared.messageCount || 0,
|
|
19934
20176
|
lineageHash: shared.lineageHash || "",
|
|
19935
20177
|
messageHashes: shared.messageHashes,
|
|
20178
|
+
messageBlockHashes: shared.messageBlockHashes,
|
|
19936
20179
|
sdkMessageUuids: shared.sdkMessageUuids,
|
|
20180
|
+
passthroughResumeUuid: shared.passthroughResumeUuid,
|
|
19937
20181
|
contextUsage: shared.contextUsage
|
|
19938
20182
|
});
|
|
19939
20183
|
}
|
|
19940
20184
|
return newest;
|
|
19941
20185
|
}
|
|
19942
|
-
function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sdkMessageUuids, contextUsage) {
|
|
20186
|
+
function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sdkMessageUuids, contextUsage, passthroughResumeUuid) {
|
|
19943
20187
|
if (!claudeSessionId)
|
|
19944
20188
|
return;
|
|
19945
20189
|
const lineageHash = computeLineageHash(messages);
|
|
19946
20190
|
const messageHashes = computeMessageHashes(messages);
|
|
20191
|
+
const messageBlockHashes = computeMessageBlockHashes(messages);
|
|
19947
20192
|
const state = {
|
|
19948
20193
|
claudeSessionId,
|
|
19949
20194
|
lastAccess: Date.now(),
|
|
19950
20195
|
messageCount: messages?.length || 0,
|
|
19951
20196
|
lineageHash,
|
|
19952
20197
|
messageHashes,
|
|
20198
|
+
messageBlockHashes,
|
|
19953
20199
|
sdkMessageUuids,
|
|
20200
|
+
...passthroughResumeUuid ? { passthroughResumeUuid } : {},
|
|
19954
20201
|
...contextUsage ? { contextUsage } : {}
|
|
19955
20202
|
};
|
|
19956
20203
|
if (sessionId)
|
|
@@ -19960,14 +20207,14 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
|
|
|
19960
20207
|
fingerprintCache.set(fp, state);
|
|
19961
20208
|
const key = sessionId || fp;
|
|
19962
20209
|
if (key) {
|
|
19963
|
-
storeSharedSession(key, claudeSessionId, state.messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage);
|
|
20210
|
+
storeSharedSession(key, claudeSessionId, state.messageCount, lineageHash, messageHashes, sdkMessageUuids, contextUsage, messageBlockHashes, passthroughResumeUuid ?? null);
|
|
19964
20211
|
}
|
|
19965
20212
|
}
|
|
19966
20213
|
|
|
19967
20214
|
// src/proxy/server.ts
|
|
19968
20215
|
var exec2 = promisify3(execCallback);
|
|
19969
20216
|
var claudeExecutable = "";
|
|
19970
|
-
var UPSTREAM_IDLE_MS = 90000;
|
|
20217
|
+
var UPSTREAM_IDLE_MS = envInt("UPSTREAM_IDLE_MS", 90000);
|
|
19971
20218
|
function credentialStoreForProfile(profile) {
|
|
19972
20219
|
if (profile.type !== "claude-max")
|
|
19973
20220
|
return;
|
|
@@ -20472,15 +20719,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
20472
20719
|
const sdkModelDefaults = resolveSdkModelDefaults();
|
|
20473
20720
|
const profileEnv = { ...sdkModelDefaults, ...cleanEnv, ...profile.env };
|
|
20474
20721
|
const profileCredentialStore = credentialStoreForProfile(profile);
|
|
20475
|
-
let systemContext =
|
|
20476
|
-
if (body.system) {
|
|
20477
|
-
if (typeof body.system === "string") {
|
|
20478
|
-
systemContext = body.system;
|
|
20479
|
-
} else if (Array.isArray(body.system)) {
|
|
20480
|
-
systemContext = body.system.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(`
|
|
20481
|
-
`);
|
|
20482
|
-
}
|
|
20483
|
-
}
|
|
20722
|
+
let systemContext = extractSystemText(body.system);
|
|
20484
20723
|
const adapterBase = adapter.baseName ?? adapter.name;
|
|
20485
20724
|
const adapterTransforms = getAdapterTransforms(adapterBase);
|
|
20486
20725
|
const pipeline = buildPipeline(adapterTransforms, pluginTransforms);
|
|
@@ -20562,8 +20801,11 @@ data: ${JSON.stringify(lastError)}
|
|
|
20562
20801
|
const isUndo = lineageResult.type === "undo";
|
|
20563
20802
|
const cachedSession = lineageResult.type !== "diverged" ? lineageResult.session : undefined;
|
|
20564
20803
|
const resumeSessionId = cachedSession?.claudeSessionId;
|
|
20804
|
+
const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
20565
20805
|
const resumeFrom = lineageResult.type === "continuation" || lineageResult.type === "compaction" ? lineageResult.resumeFrom : undefined;
|
|
20806
|
+
const resumeContentFrom = lineageResult.type === "continuation" ? lineageResult.resumeContentFrom : undefined;
|
|
20566
20807
|
const undoRollbackUuid = isUndo && lineageResult.type === "undo" ? lineageResult.rollbackUuid : undefined;
|
|
20808
|
+
const passthroughResumeUuid = passthrough && isResume ? cachedSession?.passthroughResumeUuid : undefined;
|
|
20567
20809
|
const msgSummary = body.messages?.map((m) => {
|
|
20568
20810
|
const contentTypes = Array.isArray(m.content) ? m.content.map((b) => b.type).join(",") : "string";
|
|
20569
20811
|
return `${m.role}[${contentTypes}]`;
|
|
@@ -20606,7 +20848,16 @@ data: ${JSON.stringify(lastError)}
|
|
|
20606
20848
|
if (isUndo && undoRollbackUuid) {
|
|
20607
20849
|
messagesToConvert = getLastUserMessage(allMessages);
|
|
20608
20850
|
} else if (isResume) {
|
|
20609
|
-
if (resumeFrom !== undefined && resumeFrom < allMessages.length) {
|
|
20851
|
+
if (resumeFrom !== undefined && resumeContentFrom !== undefined && resumeFrom < allMessages.length && Array.isArray(allMessages[resumeFrom]?.content)) {
|
|
20852
|
+
const boundaryMessage = allMessages[resumeFrom];
|
|
20853
|
+
messagesToConvert = [
|
|
20854
|
+
{
|
|
20855
|
+
...boundaryMessage,
|
|
20856
|
+
content: boundaryMessage.content.slice(resumeContentFrom)
|
|
20857
|
+
},
|
|
20858
|
+
...allMessages.slice(resumeFrom + 1)
|
|
20859
|
+
];
|
|
20860
|
+
} else if (resumeFrom !== undefined && resumeFrom < allMessages.length) {
|
|
20610
20861
|
messagesToConvert = allMessages.slice(resumeFrom);
|
|
20611
20862
|
} else {
|
|
20612
20863
|
messagesToConvert = getLastUserMessage(allMessages);
|
|
@@ -20655,6 +20906,13 @@ data: ${JSON.stringify(lastError)}
|
|
|
20655
20906
|
if (structuredMessages.length > 1) {
|
|
20656
20907
|
structuredMessages = consolidateMultimodalOntoLastUser(structuredMessages);
|
|
20657
20908
|
}
|
|
20909
|
+
if (passthroughResumeUuid && structuredMessages.length > 0) {
|
|
20910
|
+
structuredMessages.unshift({
|
|
20911
|
+
type: "user",
|
|
20912
|
+
message: { role: "user", content: PASSTHROUGH_CONTINUATION_LEAD_IN },
|
|
20913
|
+
parent_tool_use_id: null
|
|
20914
|
+
});
|
|
20915
|
+
}
|
|
20658
20916
|
} else {
|
|
20659
20917
|
const toolIndex = buildToolUseIndex(allMessages ?? messagesToConvert ?? []);
|
|
20660
20918
|
const promptTurns = (messagesToConvert ?? []).map((m) => {
|
|
@@ -20666,11 +20924,11 @@ data: ${JSON.stringify(lastError)}
|
|
|
20666
20924
|
}
|
|
20667
20925
|
return { role: "user", text: flattenUserContent(m.content, sanitizeOpts, toolIndex) };
|
|
20668
20926
|
});
|
|
20669
|
-
|
|
20927
|
+
const resumeDelta = promptTurns.map((t) => t.text).filter(Boolean).join(`
|
|
20670
20928
|
|
|
20671
|
-
`) || ""
|
|
20929
|
+
`) || "";
|
|
20930
|
+
textPrompt = isResume ? passthroughResumeUuid ? framePassthroughContinuation(resumeDelta) : resumeDelta : frameReplayTurns(promptTurns);
|
|
20672
20931
|
}
|
|
20673
|
-
const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
20674
20932
|
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
|
|
20675
20933
|
const capturedToolUses = [];
|
|
20676
20934
|
const capturedSignatures = new Set;
|
|
@@ -20838,6 +21096,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
20838
21096
|
claudeLog("upstream.start", { mode: "non_stream", model });
|
|
20839
21097
|
let lastUsage;
|
|
20840
21098
|
let lastStopReason;
|
|
21099
|
+
let nextPassthroughResumeUuid;
|
|
20841
21100
|
try {
|
|
20842
21101
|
if (!claudeExecutable) {
|
|
20843
21102
|
claudeExecutable = await resolveClaudeExecutableAsync();
|
|
@@ -20874,8 +21133,8 @@ data: ${JSON.stringify(lastError)}
|
|
|
20874
21133
|
hasDeferredTools,
|
|
20875
21134
|
resumeSessionId,
|
|
20876
21135
|
isUndo,
|
|
20877
|
-
undoRollbackUuid,
|
|
20878
|
-
forkSession: busySessionFork || undefined,
|
|
21136
|
+
resumeSessionAtUuid: undoRollbackUuid ?? passthroughResumeUuid,
|
|
21137
|
+
forkSession: busySessionFork || Boolean(passthroughResumeUuid) || undefined,
|
|
20879
21138
|
sdkHooks,
|
|
20880
21139
|
blockedTools: pipelineCtx.blockedTools,
|
|
20881
21140
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -20894,6 +21153,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
20894
21153
|
dreaming: sdkFeatures.dreaming,
|
|
20895
21154
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
20896
21155
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21156
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
20897
21157
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
20898
21158
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
20899
21159
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -20957,7 +21217,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
20957
21217
|
hasDeferredTools,
|
|
20958
21218
|
resumeSessionId: undefined,
|
|
20959
21219
|
isUndo: false,
|
|
20960
|
-
|
|
21220
|
+
resumeSessionAtUuid: undefined,
|
|
20961
21221
|
sdkHooks,
|
|
20962
21222
|
blockedTools: pipelineCtx.blockedTools,
|
|
20963
21223
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -20976,6 +21236,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
20976
21236
|
dreaming: sdkFeatures.dreaming,
|
|
20977
21237
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
20978
21238
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21239
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
20979
21240
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
20980
21241
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
20981
21242
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -21025,7 +21286,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
21025
21286
|
hasDeferredTools,
|
|
21026
21287
|
resumeSessionId: undefined,
|
|
21027
21288
|
isUndo: false,
|
|
21028
|
-
|
|
21289
|
+
resumeSessionAtUuid: undefined,
|
|
21029
21290
|
sdkHooks,
|
|
21030
21291
|
blockedTools: pipelineCtx.blockedTools,
|
|
21031
21292
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -21044,6 +21305,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
21044
21305
|
dreaming: sdkFeatures.dreaming,
|
|
21045
21306
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
21046
21307
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21308
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
21047
21309
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
21048
21310
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
21049
21311
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -21105,6 +21367,7 @@ data: ${JSON.stringify(lastError)}
|
|
|
21105
21367
|
if (message.type === "assistant") {
|
|
21106
21368
|
noteAssistantContent(earlyStop, message.message?.content);
|
|
21107
21369
|
} else if (message.type === "user") {
|
|
21370
|
+
nextPassthroughResumeUuid = resumeBoundaryUuid(message) ?? nextPassthroughResumeUuid;
|
|
21108
21371
|
noteUserContent(earlyStop, message.message?.content);
|
|
21109
21372
|
if (shouldEarlyStop(earlyStop)) {
|
|
21110
21373
|
earlyStopFired = true;
|
|
@@ -21344,7 +21607,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
21344
21607
|
]);
|
|
21345
21608
|
}
|
|
21346
21609
|
if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
|
|
21347
|
-
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
|
|
21610
|
+
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, earlyStopFired ? nextPassthroughResumeUuid : null);
|
|
21348
21611
|
}
|
|
21349
21612
|
const responseSessionId = currentSessionId || resumeSessionId || `session_${Date.now()}`;
|
|
21350
21613
|
return new Response(JSON.stringify({
|
|
@@ -21376,6 +21639,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
21376
21639
|
let streamEventsSeen = 0;
|
|
21377
21640
|
let eventsForwarded = 0;
|
|
21378
21641
|
let textEventsForwarded = 0;
|
|
21642
|
+
let textCharsForwarded = 0;
|
|
21379
21643
|
let bytesSent = 0;
|
|
21380
21644
|
let streamClosed = false;
|
|
21381
21645
|
let awaitingEarlyStopDrain = false;
|
|
@@ -21407,7 +21671,30 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
21407
21671
|
let lastUsage;
|
|
21408
21672
|
let hasStructuredOutput = false;
|
|
21409
21673
|
let structuredOutput;
|
|
21674
|
+
let nextPassthroughResumeUuid;
|
|
21675
|
+
const silentTurnRecoveryEnabled = env("SILENT_TURN_RECOVERY") !== "0";
|
|
21676
|
+
let silentTurnRecoveryAttempted = false;
|
|
21677
|
+
let silentTurnRecovered = false;
|
|
21410
21678
|
const streamedToolUseIds = new Set;
|
|
21679
|
+
let pendingTerminalDelta = null;
|
|
21680
|
+
let terminalDeltaSent = false;
|
|
21681
|
+
const sendTerminalDelta = (stopReasonOverride) => {
|
|
21682
|
+
if (terminalDeltaSent)
|
|
21683
|
+
return;
|
|
21684
|
+
const payload = stopReasonOverride ? encoder.encode(`event: message_delta
|
|
21685
|
+
data: ${JSON.stringify({
|
|
21686
|
+
type: "message_delta",
|
|
21687
|
+
delta: { stop_reason: stopReasonOverride, stop_sequence: null },
|
|
21688
|
+
usage: { output_tokens: lastUsage?.output_tokens ?? 0 }
|
|
21689
|
+
})}
|
|
21690
|
+
|
|
21691
|
+
`) : pendingTerminalDelta;
|
|
21692
|
+
if (!payload)
|
|
21693
|
+
return;
|
|
21694
|
+
terminalDeltaSent = true;
|
|
21695
|
+
if (safeEnqueue(payload, "terminal_message_delta"))
|
|
21696
|
+
eventsForwarded += 1;
|
|
21697
|
+
};
|
|
21411
21698
|
const openClientBlocks = new Set;
|
|
21412
21699
|
const resolvePendingStore = passthrough && earlyStopEnabled && !isIndependentSession && profileSessionId ? registerPendingStore(profileSessionId) : () => {};
|
|
21413
21700
|
let pendingEarlyStop = false;
|
|
@@ -21423,10 +21710,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
21423
21710
|
});
|
|
21424
21711
|
pendingEarlyStop = false;
|
|
21425
21712
|
flushOpenClientBlocks("early_stop");
|
|
21426
|
-
|
|
21427
|
-
data: ${JSON.stringify({ type: "message_delta", delta: { stop_reason: "tool_use", stop_sequence: null }, usage: { output_tokens: lastUsage?.output_tokens ?? 0 } })}
|
|
21428
|
-
|
|
21429
|
-
`), "early_stop");
|
|
21713
|
+
sendTerminalDelta("tool_use");
|
|
21430
21714
|
safeEnqueue(encoder.encode(`event: message_stop
|
|
21431
21715
|
data: ${JSON.stringify({ type: "message_stop" })}
|
|
21432
21716
|
|
|
@@ -21456,8 +21740,8 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21456
21740
|
}
|
|
21457
21741
|
openClientBlocks.clear();
|
|
21458
21742
|
};
|
|
21743
|
+
let currentSessionId;
|
|
21459
21744
|
try {
|
|
21460
|
-
let currentSessionId;
|
|
21461
21745
|
const MAX_RATE_LIMIT_RETRIES = 2;
|
|
21462
21746
|
const RATE_LIMIT_BASE_DELAY_MS = 1000;
|
|
21463
21747
|
const response = async function* () {
|
|
@@ -21489,8 +21773,8 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21489
21773
|
hasDeferredTools,
|
|
21490
21774
|
resumeSessionId,
|
|
21491
21775
|
isUndo,
|
|
21492
|
-
undoRollbackUuid,
|
|
21493
|
-
forkSession: busySessionFork || undefined,
|
|
21776
|
+
resumeSessionAtUuid: undoRollbackUuid ?? passthroughResumeUuid,
|
|
21777
|
+
forkSession: busySessionFork || Boolean(passthroughResumeUuid) || undefined,
|
|
21494
21778
|
sdkHooks,
|
|
21495
21779
|
blockedTools: pipelineCtx.blockedTools,
|
|
21496
21780
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -21509,6 +21793,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21509
21793
|
dreaming: sdkFeatures.dreaming,
|
|
21510
21794
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
21511
21795
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21796
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
21512
21797
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
21513
21798
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
21514
21799
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -21571,7 +21856,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21571
21856
|
hasDeferredTools,
|
|
21572
21857
|
resumeSessionId: undefined,
|
|
21573
21858
|
isUndo: false,
|
|
21574
|
-
|
|
21859
|
+
resumeSessionAtUuid: undefined,
|
|
21575
21860
|
sdkHooks,
|
|
21576
21861
|
blockedTools: pipelineCtx.blockedTools,
|
|
21577
21862
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -21590,6 +21875,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21590
21875
|
dreaming: sdkFeatures.dreaming,
|
|
21591
21876
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
21592
21877
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21878
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
21593
21879
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
21594
21880
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
21595
21881
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -21639,7 +21925,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21639
21925
|
hasDeferredTools,
|
|
21640
21926
|
resumeSessionId: undefined,
|
|
21641
21927
|
isUndo: false,
|
|
21642
|
-
|
|
21928
|
+
resumeSessionAtUuid: undefined,
|
|
21643
21929
|
sdkHooks,
|
|
21644
21930
|
blockedTools: pipelineCtx.blockedTools,
|
|
21645
21931
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -21658,6 +21944,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21658
21944
|
dreaming: sdkFeatures.dreaming,
|
|
21659
21945
|
sharedMemory: sdkFeatures.sharedMemory,
|
|
21660
21946
|
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
21947
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
21661
21948
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
21662
21949
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
21663
21950
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
@@ -21751,6 +22038,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21751
22038
|
if (message.type === "assistant" && message.uuid) {
|
|
21752
22039
|
sdkUuidMap.push(message.uuid);
|
|
21753
22040
|
}
|
|
22041
|
+
nextPassthroughResumeUuid = resumeBoundaryUuid(message) ?? nextPassthroughResumeUuid;
|
|
21754
22042
|
if (earlyStopEnabled) {
|
|
21755
22043
|
if (message.type === "assistant") {
|
|
21756
22044
|
noteAssistantContent(earlyStop, message.message?.content);
|
|
@@ -21822,10 +22110,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
21822
22110
|
if (messageStartEmitted) {
|
|
21823
22111
|
if (passthrough && streamedToolUseIds.size > 0) {
|
|
21824
22112
|
flushOpenClientBlocks("turn2_suppression");
|
|
21825
|
-
|
|
21826
|
-
data: ${JSON.stringify({ type: "message_delta", delta: { stop_reason: "tool_use", stop_sequence: null }, usage: { output_tokens: lastUsage?.output_tokens ?? 0 } })}
|
|
21827
|
-
|
|
21828
|
-
`), "passthrough_turn2_stop");
|
|
22113
|
+
sendTerminalDelta("tool_use");
|
|
21829
22114
|
safeEnqueue(encoder.encode(`event: message_stop
|
|
21830
22115
|
data: ${JSON.stringify({ type: "message_stop" })}
|
|
21831
22116
|
|
|
@@ -21929,15 +22214,26 @@ data: ${JSON.stringify({
|
|
|
21929
22214
|
}
|
|
21930
22215
|
}
|
|
21931
22216
|
}
|
|
22217
|
+
if (eventType === "content_block_delta" && event.delta?.type === "text_delta" && shouldInjectSilentTurn({
|
|
22218
|
+
raw: env("DEBUG_FORCE_SILENT_TURN"),
|
|
22219
|
+
sessionId: agentSessionId
|
|
22220
|
+
})) {
|
|
22221
|
+
claudeLog("debug.silent_turn_injected", { sessionId: agentSessionId });
|
|
22222
|
+
continue;
|
|
22223
|
+
}
|
|
21932
22224
|
stripNonStandardStreamFields(event);
|
|
21933
22225
|
const payload = encoder.encode(`event: ${eventType}
|
|
21934
22226
|
data: ${JSON.stringify(event)}
|
|
21935
22227
|
|
|
21936
22228
|
`);
|
|
21937
|
-
if (
|
|
21938
|
-
|
|
22229
|
+
if (eventType === "message_delta") {
|
|
22230
|
+
pendingTerminalDelta = payload;
|
|
22231
|
+
} else {
|
|
22232
|
+
if (!safeEnqueue(payload, `stream_event:${eventType}`)) {
|
|
22233
|
+
break;
|
|
22234
|
+
}
|
|
22235
|
+
eventsForwarded += 1;
|
|
21939
22236
|
}
|
|
21940
|
-
eventsForwarded += 1;
|
|
21941
22237
|
if (eventType === "content_block_start") {
|
|
21942
22238
|
const idx = event.index;
|
|
21943
22239
|
if (typeof idx === "number")
|
|
@@ -21953,6 +22249,7 @@ data: ${JSON.stringify(event)}
|
|
|
21953
22249
|
}
|
|
21954
22250
|
if (passthrough && eventType === "message_delta" && event.delta?.stop_reason === "tool_use" && streamedToolUseIds.size > 0) {
|
|
21955
22251
|
flushOpenClientBlocks("drain_close");
|
|
22252
|
+
sendTerminalDelta();
|
|
21956
22253
|
safeEnqueue(encoder.encode(`event: message_stop
|
|
21957
22254
|
data: ${JSON.stringify({ type: "message_stop" })}
|
|
21958
22255
|
|
|
@@ -21969,6 +22266,8 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
21969
22266
|
const delta = event.delta;
|
|
21970
22267
|
if (delta?.type === "text_delta") {
|
|
21971
22268
|
textEventsForwarded += 1;
|
|
22269
|
+
if (typeof delta.text === "string")
|
|
22270
|
+
textCharsForwarded += delta.text.length;
|
|
21972
22271
|
}
|
|
21973
22272
|
}
|
|
21974
22273
|
}
|
|
@@ -22030,6 +22329,7 @@ data: ${JSON.stringify({
|
|
|
22030
22329
|
messageStartEmitted = true;
|
|
22031
22330
|
eventsForwarded += 5;
|
|
22032
22331
|
textEventsForwarded += 1;
|
|
22332
|
+
textCharsForwarded += text.length;
|
|
22033
22333
|
}
|
|
22034
22334
|
if (passthrough) {
|
|
22035
22335
|
recordEnvelopeViolations(checkUndeliveredToolUses(capturedToolUses, streamedToolUseIds));
|
|
@@ -22055,9 +22355,125 @@ data: ${JSON.stringify({
|
|
|
22055
22355
|
plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
|
|
22056
22356
|
}
|
|
22057
22357
|
if (currentSessionId && !isIndependentSession && !sawDuplicateToolUse) {
|
|
22058
|
-
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
|
|
22358
|
+
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, earlyStopFired ? nextPassthroughResumeUuid : null);
|
|
22059
22359
|
}
|
|
22060
22360
|
resolvePendingStore();
|
|
22361
|
+
const classifyNow = () => classifyTurnOutcome({
|
|
22362
|
+
textEvents: textEventsForwarded,
|
|
22363
|
+
toolUses: streamedToolUseIds.size,
|
|
22364
|
+
blocksForwarded: eventsForwarded
|
|
22365
|
+
});
|
|
22366
|
+
const preRecoveryOutcome = classifyNow();
|
|
22367
|
+
if (!streamClosed && messageStartEmitted && shouldAttemptRecovery({
|
|
22368
|
+
outcome: preRecoveryOutcome,
|
|
22369
|
+
alreadyAttempted: silentTurnRecoveryAttempted,
|
|
22370
|
+
clientGone: streamClosed,
|
|
22371
|
+
sessionId: currentSessionId || resumeSessionId,
|
|
22372
|
+
enabled: silentTurnRecoveryEnabled
|
|
22373
|
+
})) {
|
|
22374
|
+
silentTurnRecoveryAttempted = true;
|
|
22375
|
+
const capturedBeforeRecovery = capturedToolUses.length;
|
|
22376
|
+
claudeLog("response.silent_turn_recovery", {
|
|
22377
|
+
mode: "stream",
|
|
22378
|
+
kind: preRecoveryOutcome.kind,
|
|
22379
|
+
reason: preRecoveryOutcome.kind === "silent" ? preRecoveryOutcome.reason : undefined,
|
|
22380
|
+
sdkSessionId: currentSessionId || resumeSessionId
|
|
22381
|
+
});
|
|
22382
|
+
const recoveryLifter = createRecoveryLifter(() => nextClientBlockIndex++);
|
|
22383
|
+
let recoverySessionId;
|
|
22384
|
+
let recoveryBoundaryUuid;
|
|
22385
|
+
try {
|
|
22386
|
+
for await (const event of guardUpstreamIdle(query(buildQueryOptions({
|
|
22387
|
+
prompt: SILENT_TURN_NUDGE,
|
|
22388
|
+
model,
|
|
22389
|
+
workingDirectory,
|
|
22390
|
+
clientWorkingDirectory,
|
|
22391
|
+
systemContext,
|
|
22392
|
+
claudeExecutable,
|
|
22393
|
+
passthrough,
|
|
22394
|
+
stream: true,
|
|
22395
|
+
sdkAgents,
|
|
22396
|
+
passthroughMcp,
|
|
22397
|
+
cleanEnv: profileEnv,
|
|
22398
|
+
envOverrides,
|
|
22399
|
+
hasDeferredTools,
|
|
22400
|
+
resumeSessionId: currentSessionId || resumeSessionId,
|
|
22401
|
+
isUndo: false,
|
|
22402
|
+
resumeSessionAtUuid: nextPassthroughResumeUuid,
|
|
22403
|
+
forkSession: true,
|
|
22404
|
+
sdkHooks,
|
|
22405
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
22406
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
22407
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
22408
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
22409
|
+
onStderr,
|
|
22410
|
+
effort,
|
|
22411
|
+
thinking,
|
|
22412
|
+
taskBudget,
|
|
22413
|
+
outputFormat,
|
|
22414
|
+
betas,
|
|
22415
|
+
settingSources,
|
|
22416
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt,
|
|
22417
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
22418
|
+
memory: sdkFeatures.memory,
|
|
22419
|
+
dreaming: sdkFeatures.dreaming,
|
|
22420
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
22421
|
+
webFetchPreflight: sdkFeatures.webFetchPreflight,
|
|
22422
|
+
claudeAiConnectors: sdkFeatures.claudeAiConnectors,
|
|
22423
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
22424
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
22425
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
22426
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
|
|
22427
|
+
advisorModel
|
|
22428
|
+
}, requestAbort.controller)), UPSTREAM_IDLE_MS, (sinceLastMs) => claudeLog("upstream.stalled", { mode: "silent_recovery", model, sinceLastMs }))) {
|
|
22429
|
+
const recoveryMessage = event;
|
|
22430
|
+
if (recoveryMessage.session_id)
|
|
22431
|
+
recoverySessionId = recoveryMessage.session_id;
|
|
22432
|
+
recoveryBoundaryUuid = resumeBoundaryUuid(recoveryMessage) ?? recoveryBoundaryUuid;
|
|
22433
|
+
if (recoveryMessage.type !== "stream_event")
|
|
22434
|
+
continue;
|
|
22435
|
+
const lifted = recoveryLifter.lift(event.event);
|
|
22436
|
+
if (!lifted)
|
|
22437
|
+
continue;
|
|
22438
|
+
safeEnqueue(encoder.encode(`event: ${lifted.frame.type}
|
|
22439
|
+
data: ${JSON.stringify(lifted.frame)}
|
|
22440
|
+
|
|
22441
|
+
`), `silent_recovery_${lifted.kind}`);
|
|
22442
|
+
if (lifted.kind === "block_start") {
|
|
22443
|
+
eventsForwarded += 1;
|
|
22444
|
+
} else if (lifted.kind === "text_delta") {
|
|
22445
|
+
textEventsForwarded += 1;
|
|
22446
|
+
textCharsForwarded += lifted.textChars;
|
|
22447
|
+
silentTurnRecovered = true;
|
|
22448
|
+
}
|
|
22449
|
+
}
|
|
22450
|
+
} catch (recoveryError) {
|
|
22451
|
+
claudeLog("response.silent_turn_recovery_failed", {
|
|
22452
|
+
mode: "stream",
|
|
22453
|
+
error: recoveryError instanceof Error ? recoveryError.message : String(recoveryError)
|
|
22454
|
+
});
|
|
22455
|
+
}
|
|
22456
|
+
if (capturedToolUses.length > capturedBeforeRecovery) {
|
|
22457
|
+
silentTurnRecovered = true;
|
|
22458
|
+
}
|
|
22459
|
+
if (silentTurnRecovered && recoverySessionId && !isIndependentSession && !sawDuplicateToolUse) {
|
|
22460
|
+
currentSessionId = recoverySessionId;
|
|
22461
|
+
nextPassthroughResumeUuid = recoveryBoundaryUuid;
|
|
22462
|
+
sdkUuidMap.length = 0;
|
|
22463
|
+
for (let i = 0;i < allMessages.length; i++)
|
|
22464
|
+
sdkUuidMap.push(null);
|
|
22465
|
+
storeSession(profileSessionId, body.messages || [], recoverySessionId, profileScopedCwd, sdkUuidMap, lastUsage, recoveryBoundaryUuid ?? null);
|
|
22466
|
+
}
|
|
22467
|
+
claudeLog("response.silent_turn_recovery_result", {
|
|
22468
|
+
mode: "stream",
|
|
22469
|
+
recovered: silentTurnRecovered,
|
|
22470
|
+
textEvents: textEventsForwarded,
|
|
22471
|
+
forkedSession: recoverySessionId ?? null
|
|
22472
|
+
});
|
|
22473
|
+
if (silentTurnRecovered && preRecoveryOutcome.kind === "silent") {
|
|
22474
|
+
diagnosticLog2.session(`${requestMeta.requestId} silent_turn reason=${preRecoveryOutcome.reason} ` + `blocks=${eventsForwarded} out=${lastUsage?.output_tokens ?? 0} ` + `recovery=succeeded`, requestMeta.requestId);
|
|
22475
|
+
}
|
|
22476
|
+
}
|
|
22061
22477
|
if (!streamClosed) {
|
|
22062
22478
|
const unseenToolUses = capturedToolUses.filter((tu) => !streamedToolUseIds.has(tu.id));
|
|
22063
22479
|
if (passthrough && unseenToolUses.length > 0 && messageStartEmitted) {
|
|
@@ -22089,14 +22505,7 @@ data: ${JSON.stringify({
|
|
|
22089
22505
|
|
|
22090
22506
|
`), "passthrough_tool_block_stop");
|
|
22091
22507
|
}
|
|
22092
|
-
|
|
22093
|
-
data: ${JSON.stringify({
|
|
22094
|
-
type: "message_delta",
|
|
22095
|
-
delta: { stop_reason: "tool_use", stop_sequence: null },
|
|
22096
|
-
usage: { output_tokens: 0 }
|
|
22097
|
-
})}
|
|
22098
|
-
|
|
22099
|
-
`), "passthrough_message_delta");
|
|
22508
|
+
sendTerminalDelta("tool_use");
|
|
22100
22509
|
}
|
|
22101
22510
|
if (trackFileChanges && passthrough && pipelineCtx.extractFileChangesFromToolUse) {
|
|
22102
22511
|
const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
|
|
@@ -22133,6 +22542,7 @@ data: ${JSON.stringify({
|
|
|
22133
22542
|
}
|
|
22134
22543
|
}
|
|
22135
22544
|
if (messageStartEmitted) {
|
|
22545
|
+
sendTerminalDelta();
|
|
22136
22546
|
safeEnqueue(encoder.encode(`event: message_stop
|
|
22137
22547
|
data: {"type":"message_stop"}
|
|
22138
22548
|
|
|
@@ -22198,13 +22608,18 @@ data: {"type":"message_stop"}
|
|
|
22198
22608
|
cacheHitRate: computeCacheHitRate(lastUsage),
|
|
22199
22609
|
...envelopeViolations.length > 0 ? { envelopeViolations: [...envelopeViolations] } : {}
|
|
22200
22610
|
});
|
|
22201
|
-
|
|
22202
|
-
|
|
22611
|
+
const turnOutcome = classifyNow();
|
|
22612
|
+
if (turnOutcome.kind === "silent") {
|
|
22613
|
+
claudeLog("response.silent_turn", {
|
|
22203
22614
|
model,
|
|
22615
|
+
reason: turnOutcome.reason,
|
|
22204
22616
|
streamEventsSeen,
|
|
22205
22617
|
eventsForwarded,
|
|
22206
|
-
|
|
22618
|
+
outputTokens: lastUsage?.output_tokens,
|
|
22619
|
+
recovered: silentTurnRecovered,
|
|
22620
|
+
recoveryAttempted: silentTurnRecoveryAttempted
|
|
22207
22621
|
});
|
|
22622
|
+
diagnosticLog2.session(`${requestMeta.requestId} silent_turn reason=${turnOutcome.reason} ` + `blocks=${eventsForwarded} out=${lastUsage?.output_tokens ?? 0} ` + `recovery=${silentTurnRecoveryAttempted ? silentTurnRecovered ? "succeeded" : "failed" : "off"}`, requestMeta.requestId);
|
|
22208
22623
|
}
|
|
22209
22624
|
}
|
|
22210
22625
|
} catch (error) {
|
|
@@ -22217,6 +22632,21 @@ data: {"type":"message_stop"}
|
|
|
22217
22632
|
textEventsForwarded,
|
|
22218
22633
|
durationMs: Date.now() - requestStartAt
|
|
22219
22634
|
});
|
|
22635
|
+
const disposition = clientAbortDisposition({
|
|
22636
|
+
isIndependentSession,
|
|
22637
|
+
profileSessionId,
|
|
22638
|
+
currentSessionId,
|
|
22639
|
+
sawDuplicateToolUse,
|
|
22640
|
+
resumeBoundaryUuid: nextPassthroughResumeUuid,
|
|
22641
|
+
passthrough
|
|
22642
|
+
});
|
|
22643
|
+
if (disposition.action === "store" && currentSessionId) {
|
|
22644
|
+
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage, disposition.resumeUuid);
|
|
22645
|
+
} else if (disposition.action === "evict") {
|
|
22646
|
+
evictSession(profileSessionId, profileScopedCwd, body.messages || []);
|
|
22647
|
+
}
|
|
22648
|
+
claudeLog("passthrough.client_abort_settled", { action: disposition.action });
|
|
22649
|
+
resolvePendingStore();
|
|
22220
22650
|
return;
|
|
22221
22651
|
}
|
|
22222
22652
|
resolvePendingStore();
|
|
@@ -22370,26 +22800,41 @@ data: {"type":"message_stop"}
|
|
|
22370
22800
|
error: streamErr.type
|
|
22371
22801
|
});
|
|
22372
22802
|
if (messageStartEmitted) {
|
|
22803
|
+
const errorStopReason = textEventsForwarded > 0 ? "end_turn" : "max_tokens";
|
|
22804
|
+
claudeLog("response.error_envelope", {
|
|
22805
|
+
mode: "stream",
|
|
22806
|
+
stopReason: errorStopReason,
|
|
22807
|
+
textEvents: textEventsForwarded,
|
|
22808
|
+
classified: streamErr.type
|
|
22809
|
+
});
|
|
22373
22810
|
safeEnqueue(encoder.encode(`event: message_delta
|
|
22374
22811
|
data: ${JSON.stringify({
|
|
22375
22812
|
type: "message_delta",
|
|
22376
|
-
delta: { stop_reason:
|
|
22813
|
+
delta: { stop_reason: errorStopReason, stop_sequence: null },
|
|
22377
22814
|
usage: { output_tokens: 0 }
|
|
22378
22815
|
})}
|
|
22379
22816
|
|
|
22380
22817
|
`), "error_message_delta");
|
|
22818
|
+
safeEnqueue(encoder.encode(`event: error
|
|
22819
|
+
data: ${JSON.stringify({
|
|
22820
|
+
type: "error",
|
|
22821
|
+
error: { type: streamErr.type, message: streamErr.message }
|
|
22822
|
+
})}
|
|
22823
|
+
|
|
22824
|
+
`), "error_event_before_stop");
|
|
22381
22825
|
safeEnqueue(encoder.encode(`event: message_stop
|
|
22382
22826
|
data: {"type":"message_stop"}
|
|
22383
22827
|
|
|
22384
22828
|
`), "error_message_stop");
|
|
22385
|
-
}
|
|
22386
|
-
|
|
22829
|
+
} else {
|
|
22830
|
+
safeEnqueue(encoder.encode(`event: error
|
|
22387
22831
|
data: ${JSON.stringify({
|
|
22388
|
-
|
|
22389
|
-
|
|
22390
|
-
|
|
22832
|
+
type: "error",
|
|
22833
|
+
error: { type: streamErr.type, message: streamErr.message }
|
|
22834
|
+
})}
|
|
22391
22835
|
|
|
22392
22836
|
`), "error_event");
|
|
22837
|
+
}
|
|
22393
22838
|
if (!streamClosed) {
|
|
22394
22839
|
try {
|
|
22395
22840
|
controller.close();
|
|
@@ -22647,7 +23092,7 @@ data: ${JSON.stringify({
|
|
|
22647
23092
|
});
|
|
22648
23093
|
});
|
|
22649
23094
|
app.get("/profiles", async (c) => {
|
|
22650
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
23095
|
+
const { profilePageHtml } = await import("./profilePage-gtazq15d.js");
|
|
22651
23096
|
return c.html(profilePageHtml);
|
|
22652
23097
|
});
|
|
22653
23098
|
app.post("/profiles/active", async (c) => {
|
|
@@ -22730,14 +23175,25 @@ data: ${JSON.stringify({
|
|
|
22730
23175
|
});
|
|
22731
23176
|
app.post("/v1/chat/completions", async (c) => {
|
|
22732
23177
|
const rawBody = await c.req.json();
|
|
22733
|
-
const
|
|
23178
|
+
const userAgent = c.req.header("user-agent") ?? "";
|
|
23179
|
+
const jcodeSessionId = userAgent.startsWith("jcode/") ? normalizeJcodeSessionId(c.req.header("x-jcode-session")) : undefined;
|
|
23180
|
+
const isJcode = jcodeSessionId !== undefined;
|
|
23181
|
+
const adapterName = isJcode ? "jcode" : "openai";
|
|
23182
|
+
const anthropicBody = translateOpenAiToAnthropic(rawBody, {
|
|
23183
|
+
preserveConversationHistory: isJcode
|
|
23184
|
+
});
|
|
22734
23185
|
if (!anthropicBody) {
|
|
22735
23186
|
return c.json({ type: "error", error: { type: "invalid_request_error", message: "messages: Field required" } }, 400);
|
|
22736
23187
|
}
|
|
22737
23188
|
const internalHeaders = {
|
|
22738
23189
|
"Content-Type": "application/json",
|
|
22739
|
-
"x-meridian-agent":
|
|
23190
|
+
"x-meridian-agent": adapterName
|
|
22740
23191
|
};
|
|
23192
|
+
if (jcodeSessionId)
|
|
23193
|
+
internalHeaders["x-jcode-session"] = jcodeSessionId;
|
|
23194
|
+
const requestedProfile = c.req.header("x-meridian-profile");
|
|
23195
|
+
if (requestedProfile)
|
|
23196
|
+
internalHeaders["x-meridian-profile"] = requestedProfile;
|
|
22741
23197
|
const xApiKey = c.req.header("x-api-key");
|
|
22742
23198
|
if (xApiKey)
|
|
22743
23199
|
internalHeaders["x-api-key"] = xApiKey;
|
|
@@ -22758,7 +23214,7 @@ data: ${JSON.stringify({
|
|
|
22758
23214
|
const created = Math.floor(Date.now() / 1000);
|
|
22759
23215
|
const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : CANONICAL_SONNET_MODEL;
|
|
22760
23216
|
const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
22761
|
-
const sdkFeatures = getFeaturesForAdapter2(
|
|
23217
|
+
const sdkFeatures = getFeaturesForAdapter2(adapterName);
|
|
22762
23218
|
if (!anthropicBody.stream) {
|
|
22763
23219
|
const anthropicRes = await internalRes.json();
|
|
22764
23220
|
return c.json(translateAnthropicToOpenAi(anthropicRes, completionId, model, created, {
|
|
@@ -23004,7 +23460,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
|
|
|
23004
23460
|
const profilesList = getEffectiveProfiles(finalConfig.profiles);
|
|
23005
23461
|
const activeId = getActiveProfileId() || finalConfig.defaultProfile || profilesList[0]?.id || null;
|
|
23006
23462
|
if (profilesList.length === 0) {
|
|
23007
|
-
const oauth = await
|
|
23463
|
+
const { snapshot: oauth, error } = await fetchOAuthUsageResult({});
|
|
23008
23464
|
return c.json({
|
|
23009
23465
|
profiles: [{
|
|
23010
23466
|
id: "default",
|
|
@@ -23012,7 +23468,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
|
|
|
23012
23468
|
windows: oauth?.windows ?? [],
|
|
23013
23469
|
extraUsage: oauth?.extraUsage ?? null,
|
|
23014
23470
|
fetchedAt: oauth?.fetchedAt ?? null,
|
|
23015
|
-
error
|
|
23471
|
+
error
|
|
23016
23472
|
}],
|
|
23017
23473
|
activeProfile: "default",
|
|
23018
23474
|
asOf: Date.now()
|
|
@@ -23031,7 +23487,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
|
|
|
23031
23487
|
error: "not_oauth"
|
|
23032
23488
|
};
|
|
23033
23489
|
}
|
|
23034
|
-
const oauth = await
|
|
23490
|
+
const { snapshot: oauth, error } = await fetchOAuthUsageResult({
|
|
23035
23491
|
profileId: p.id,
|
|
23036
23492
|
claudeConfigDir: p.claudeConfigDir
|
|
23037
23493
|
});
|
|
@@ -23042,7 +23498,7 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
|
|
|
23042
23498
|
windows: oauth?.windows ?? [],
|
|
23043
23499
|
extraUsage: oauth?.extraUsage ?? null,
|
|
23044
23500
|
fetchedAt: oauth?.fetchedAt ?? null,
|
|
23045
|
-
error
|
|
23501
|
+
error
|
|
23046
23502
|
};
|
|
23047
23503
|
}));
|
|
23048
23504
|
return c.json({
|