@rynfar/meridian 1.51.0 → 1.53.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 +47 -14
- package/dist/{cli-7df5eg5d.js → cli-027as0fx.js} +564 -31
- package/dist/{cli-aybvv9nb.js → cli-vjeftz4z.js} +10 -2
- package/dist/cli.js +8 -4
- package/dist/{profileCli-j01rr99j.js → profileCli-s1h4vh8w.js} +1 -1
- package/dist/proxy/adapters/codex.d.ts +22 -0
- package/dist/proxy/adapters/codex.d.ts.map +1 -0
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/errors.d.ts +9 -0
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/messages.d.ts +20 -0
- package/dist/proxy/messages.d.ts.map +1 -1
- package/dist/proxy/models.d.ts +16 -1
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts +5 -0
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/openaiResponses.d.ts +137 -0
- package/dist/proxy/openaiResponses.d.ts.map +1 -0
- package/dist/proxy/query.d.ts +4 -0
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/transforms/codex.d.ts +12 -0
- package/dist/proxy/transforms/codex.d.ts.map +1 -0
- package/dist/proxy/transforms/opencode.d.ts.map +1 -1
- package/dist/proxy/transforms/registry.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/plugin/meridian.ts +58 -13
|
@@ -22,9 +22,11 @@ import {
|
|
|
22
22
|
themeCss
|
|
23
23
|
} from "./cli-xmweegb1.js";
|
|
24
24
|
import {
|
|
25
|
+
CANONICAL_SONNET_MODEL,
|
|
25
26
|
env,
|
|
26
27
|
envBool,
|
|
27
28
|
envInt,
|
|
29
|
+
explicitModelPin,
|
|
28
30
|
getAuthCacheInfo,
|
|
29
31
|
getClaudeAuthStatusAsync,
|
|
30
32
|
getResolvedClaudeExecutableInfo,
|
|
@@ -37,7 +39,7 @@ import {
|
|
|
37
39
|
resolvePassthrough,
|
|
38
40
|
resolveSdkModelDefaults,
|
|
39
41
|
stripExtendedContext
|
|
40
|
-
} from "./cli-
|
|
42
|
+
} from "./cli-vjeftz4z.js";
|
|
41
43
|
import {
|
|
42
44
|
getSetting
|
|
43
45
|
} from "./cli-340h1chz.js";
|
|
@@ -1532,7 +1534,7 @@ function getExplicitThinking(adapterName) {
|
|
|
1532
1534
|
return typeof explicit === "string" && VALID_THINKING_VALUES.has(explicit) ? explicit : undefined;
|
|
1533
1535
|
}
|
|
1534
1536
|
function getAllFeatureConfigs() {
|
|
1535
|
-
const adapters = ["opencode", "crush", "forgecode", "pi", "droid", "passthrough", "openai"];
|
|
1537
|
+
const adapters = ["opencode", "crush", "forgecode", "pi", "droid", "passthrough", "openai", "codex"];
|
|
1536
1538
|
const result = {};
|
|
1537
1539
|
for (const name of adapters) {
|
|
1538
1540
|
result[name] = getFeaturesForAdapter(name);
|
|
@@ -1610,6 +1612,9 @@ var init_sdkFeatures = __esm(() => {
|
|
|
1610
1612
|
},
|
|
1611
1613
|
cherry: {
|
|
1612
1614
|
codeSystemPrompt: false
|
|
1615
|
+
},
|
|
1616
|
+
codex: {
|
|
1617
|
+
codeSystemPrompt: false
|
|
1613
1618
|
}
|
|
1614
1619
|
};
|
|
1615
1620
|
VALID_CLAUDE_MD_VALUES = new Set(["off", "project", "full"]);
|
|
@@ -10179,6 +10184,11 @@ function isStaleSessionError(error) {
|
|
|
10179
10184
|
const msg = error.message;
|
|
10180
10185
|
return msg.includes("No message found with message.uuid") || msg.includes("No conversation found with session ID") || msg.includes("No conversation found to continue") || msg.includes("No conversations found to resume");
|
|
10181
10186
|
}
|
|
10187
|
+
function isBusySessionError(error, stderr) {
|
|
10188
|
+
const needle = "is currently running as a background agent";
|
|
10189
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
10190
|
+
return msg.includes(needle) || (stderr?.includes(needle) ?? false);
|
|
10191
|
+
}
|
|
10182
10192
|
function isRateLimitError(errMsg) {
|
|
10183
10193
|
const lower = errMsg.toLowerCase();
|
|
10184
10194
|
return lower.includes("429") || lower.includes("rate limit") || lower.includes("too many requests");
|
|
@@ -10459,7 +10469,7 @@ ${historyBlock}` : historyBlock;
|
|
|
10459
10469
|
messagesToSend = turns.slice(-1);
|
|
10460
10470
|
}
|
|
10461
10471
|
const result = {
|
|
10462
|
-
model: body.model ??
|
|
10472
|
+
model: body.model ?? CANONICAL_SONNET_MODEL,
|
|
10463
10473
|
messages: messagesToSend,
|
|
10464
10474
|
max_tokens: body.max_tokens ?? body.max_completion_tokens ?? 8192,
|
|
10465
10475
|
tools,
|
|
@@ -10665,6 +10675,15 @@ var FULL_CAPABILITIES = Object.freeze({
|
|
|
10665
10675
|
});
|
|
10666
10676
|
function buildModelList(isMaxSubscription, now = Math.floor(Date.now() / 1000)) {
|
|
10667
10677
|
return [
|
|
10678
|
+
{
|
|
10679
|
+
id: "claude-sonnet-5",
|
|
10680
|
+
object: "model",
|
|
10681
|
+
created: now,
|
|
10682
|
+
owned_by: "anthropic",
|
|
10683
|
+
display_name: "Claude Sonnet 5",
|
|
10684
|
+
context_window: 200000,
|
|
10685
|
+
capabilities: FULL_CAPABILITIES
|
|
10686
|
+
},
|
|
10668
10687
|
{
|
|
10669
10688
|
id: "claude-sonnet-4-6",
|
|
10670
10689
|
object: "model",
|
|
@@ -10722,6 +10741,331 @@ function buildModelList(isMaxSubscription, now = Math.floor(Date.now() / 1000))
|
|
|
10722
10741
|
];
|
|
10723
10742
|
}
|
|
10724
10743
|
|
|
10744
|
+
// src/proxy/openaiResponses.ts
|
|
10745
|
+
function partsToText(content) {
|
|
10746
|
+
if (typeof content === "string")
|
|
10747
|
+
return content;
|
|
10748
|
+
return content.filter((p) => typeof p.text === "string").map((p) => p.text).join("");
|
|
10749
|
+
}
|
|
10750
|
+
function mapToolChoice(tc) {
|
|
10751
|
+
if (tc === "auto")
|
|
10752
|
+
return { type: "auto" };
|
|
10753
|
+
if (tc === "required")
|
|
10754
|
+
return { type: "any" };
|
|
10755
|
+
if (tc && typeof tc === "object") {
|
|
10756
|
+
const o = tc;
|
|
10757
|
+
if (o.type === "function" && o.name)
|
|
10758
|
+
return { type: "tool", name: o.name };
|
|
10759
|
+
if (o.type === "auto")
|
|
10760
|
+
return { type: "auto" };
|
|
10761
|
+
if (o.type === "any" || o.type === "required")
|
|
10762
|
+
return { type: "any" };
|
|
10763
|
+
}
|
|
10764
|
+
return;
|
|
10765
|
+
}
|
|
10766
|
+
function translateResponsesToAnthropic(body) {
|
|
10767
|
+
if (body.input === undefined || body.input === null)
|
|
10768
|
+
return null;
|
|
10769
|
+
const items = typeof body.input === "string" ? [{ type: "message", role: "user", content: [{ type: "input_text", text: body.input }] }] : body.input;
|
|
10770
|
+
const systemParts = [];
|
|
10771
|
+
if (body.instructions)
|
|
10772
|
+
systemParts.push(body.instructions);
|
|
10773
|
+
const messages = [];
|
|
10774
|
+
const pushBlock = (role, block) => {
|
|
10775
|
+
const last = messages[messages.length - 1];
|
|
10776
|
+
if (last && last.role === role && Array.isArray(last.content)) {
|
|
10777
|
+
last.content.push(block);
|
|
10778
|
+
} else {
|
|
10779
|
+
messages.push({ role, content: [block] });
|
|
10780
|
+
}
|
|
10781
|
+
};
|
|
10782
|
+
for (const item of items) {
|
|
10783
|
+
switch (item.type) {
|
|
10784
|
+
case "message": {
|
|
10785
|
+
const msg = item;
|
|
10786
|
+
if (msg.role === "developer" || msg.role === "system") {
|
|
10787
|
+
const t = partsToText(msg.content);
|
|
10788
|
+
if (t)
|
|
10789
|
+
systemParts.push(t);
|
|
10790
|
+
break;
|
|
10791
|
+
}
|
|
10792
|
+
const text = partsToText(msg.content);
|
|
10793
|
+
if (text)
|
|
10794
|
+
pushBlock(msg.role === "assistant" ? "assistant" : "user", { type: "text", text });
|
|
10795
|
+
break;
|
|
10796
|
+
}
|
|
10797
|
+
case "function_call": {
|
|
10798
|
+
const fc = item;
|
|
10799
|
+
let input = {};
|
|
10800
|
+
try {
|
|
10801
|
+
input = fc.arguments ? JSON.parse(fc.arguments) : {};
|
|
10802
|
+
} catch {
|
|
10803
|
+
input = {};
|
|
10804
|
+
}
|
|
10805
|
+
pushBlock("assistant", { type: "tool_use", id: fc.call_id, name: fc.name, input });
|
|
10806
|
+
break;
|
|
10807
|
+
}
|
|
10808
|
+
case "function_call_output": {
|
|
10809
|
+
const fo = item;
|
|
10810
|
+
pushBlock("user", { type: "tool_result", tool_use_id: fo.call_id, content: fo.output });
|
|
10811
|
+
break;
|
|
10812
|
+
}
|
|
10813
|
+
case "reasoning":
|
|
10814
|
+
break;
|
|
10815
|
+
default:
|
|
10816
|
+
break;
|
|
10817
|
+
}
|
|
10818
|
+
}
|
|
10819
|
+
const result = {
|
|
10820
|
+
model: typeof body.model === "string" ? body.model : "",
|
|
10821
|
+
messages,
|
|
10822
|
+
max_tokens: body.max_output_tokens ?? 8192,
|
|
10823
|
+
stream: body.stream ?? false
|
|
10824
|
+
};
|
|
10825
|
+
if (systemParts.length > 0)
|
|
10826
|
+
result.system = systemParts.join(`
|
|
10827
|
+
|
|
10828
|
+
`);
|
|
10829
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
10830
|
+
result.tools = body.tools.filter((t) => t.type === "function").map((t) => ({
|
|
10831
|
+
name: t.name,
|
|
10832
|
+
description: t.description ?? "",
|
|
10833
|
+
input_schema: t.parameters ?? { type: "object", properties: {} }
|
|
10834
|
+
}));
|
|
10835
|
+
}
|
|
10836
|
+
const tc = mapToolChoice(body.tool_choice);
|
|
10837
|
+
if (tc)
|
|
10838
|
+
result.tool_choice = tc;
|
|
10839
|
+
if (body.temperature !== undefined)
|
|
10840
|
+
result.temperature = body.temperature;
|
|
10841
|
+
if (body.top_p !== undefined)
|
|
10842
|
+
result.top_p = body.top_p;
|
|
10843
|
+
if (body.reasoning?.effort !== undefined)
|
|
10844
|
+
result.reasoning_effort = body.reasoning.effort;
|
|
10845
|
+
return result;
|
|
10846
|
+
}
|
|
10847
|
+
function reasoningRequested(body) {
|
|
10848
|
+
if (body.reasoning && typeof body.reasoning === "object")
|
|
10849
|
+
return true;
|
|
10850
|
+
const include = body.include;
|
|
10851
|
+
return Array.isArray(include) && include.some((v) => typeof v === "string" && v.startsWith("reasoning"));
|
|
10852
|
+
}
|
|
10853
|
+
function mapUsage(usage) {
|
|
10854
|
+
const input = usage?.input_tokens ?? 0;
|
|
10855
|
+
const output = usage?.output_tokens ?? 0;
|
|
10856
|
+
return { input_tokens: input, output_tokens: output, total_tokens: input + output };
|
|
10857
|
+
}
|
|
10858
|
+
function translateAnthropicToResponses(res, ctx) {
|
|
10859
|
+
const output = [];
|
|
10860
|
+
const textParts = [];
|
|
10861
|
+
for (const block of res.content ?? []) {
|
|
10862
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
10863
|
+
textParts.push({ type: "output_text", text: block.text, annotations: [] });
|
|
10864
|
+
} else if (block.type === "tool_use") {
|
|
10865
|
+
output.push({
|
|
10866
|
+
type: "function_call",
|
|
10867
|
+
id: `fc_${block.id}`,
|
|
10868
|
+
call_id: block.id,
|
|
10869
|
+
name: block.name,
|
|
10870
|
+
arguments: JSON.stringify(block.input ?? {}),
|
|
10871
|
+
status: "completed"
|
|
10872
|
+
});
|
|
10873
|
+
}
|
|
10874
|
+
}
|
|
10875
|
+
if (textParts.length > 0) {
|
|
10876
|
+
output.unshift({
|
|
10877
|
+
type: "message",
|
|
10878
|
+
id: `msg_${ctx.responseId}`,
|
|
10879
|
+
status: "completed",
|
|
10880
|
+
role: "assistant",
|
|
10881
|
+
content: textParts
|
|
10882
|
+
});
|
|
10883
|
+
}
|
|
10884
|
+
if (ctx.reasoningRequested) {
|
|
10885
|
+
output.unshift({
|
|
10886
|
+
type: "reasoning",
|
|
10887
|
+
id: `rs_${ctx.responseId}`,
|
|
10888
|
+
summary: [],
|
|
10889
|
+
encrypted_content: null,
|
|
10890
|
+
status: "completed"
|
|
10891
|
+
});
|
|
10892
|
+
}
|
|
10893
|
+
return {
|
|
10894
|
+
id: ctx.responseId,
|
|
10895
|
+
object: "response",
|
|
10896
|
+
created_at: ctx.created,
|
|
10897
|
+
model: ctx.model,
|
|
10898
|
+
status: "completed",
|
|
10899
|
+
output,
|
|
10900
|
+
usage: mapUsage(res.usage),
|
|
10901
|
+
parallel_tool_calls: true,
|
|
10902
|
+
tool_choice: "auto",
|
|
10903
|
+
tools: []
|
|
10904
|
+
};
|
|
10905
|
+
}
|
|
10906
|
+
function createResponsesSseTranslator(ctx) {
|
|
10907
|
+
let seq = 0;
|
|
10908
|
+
let outputIndex = 0;
|
|
10909
|
+
let inputTokens = 0;
|
|
10910
|
+
let outputTokens = 0;
|
|
10911
|
+
let createdEmitted = false;
|
|
10912
|
+
const blocks = new Map;
|
|
10913
|
+
const finalOutput = [];
|
|
10914
|
+
const emit = (event, data) => ({
|
|
10915
|
+
event,
|
|
10916
|
+
data: { type: event, ...data, sequence_number: seq++ }
|
|
10917
|
+
});
|
|
10918
|
+
const responseEnvelope = (status, extra = {}) => ({
|
|
10919
|
+
id: ctx.responseId,
|
|
10920
|
+
object: "response",
|
|
10921
|
+
created_at: ctx.created,
|
|
10922
|
+
model: ctx.model,
|
|
10923
|
+
status,
|
|
10924
|
+
...extra
|
|
10925
|
+
});
|
|
10926
|
+
return (event) => {
|
|
10927
|
+
const out = [];
|
|
10928
|
+
switch (event.type) {
|
|
10929
|
+
case "message_start": {
|
|
10930
|
+
inputTokens = event.message?.usage?.input_tokens ?? 0;
|
|
10931
|
+
if (!createdEmitted) {
|
|
10932
|
+
createdEmitted = true;
|
|
10933
|
+
out.push(emit("response.created", { response: responseEnvelope("in_progress", { output: [] }) }));
|
|
10934
|
+
out.push(emit("response.in_progress", { response: responseEnvelope("in_progress", { output: [] }) }));
|
|
10935
|
+
if (ctx.reasoningRequested) {
|
|
10936
|
+
const oi = outputIndex++;
|
|
10937
|
+
const itemId = `rs_${ctx.responseId}`;
|
|
10938
|
+
const item = { type: "reasoning", id: itemId, summary: [], encrypted_content: null, status: "completed" };
|
|
10939
|
+
out.push(emit("response.output_item.added", { output_index: oi, item: { ...item, status: "in_progress" } }));
|
|
10940
|
+
finalOutput.push(item);
|
|
10941
|
+
out.push(emit("response.output_item.done", { output_index: oi, item }));
|
|
10942
|
+
}
|
|
10943
|
+
}
|
|
10944
|
+
break;
|
|
10945
|
+
}
|
|
10946
|
+
case "content_block_start": {
|
|
10947
|
+
const idx = event.index ?? 0;
|
|
10948
|
+
const cb = event.content_block ?? {};
|
|
10949
|
+
if (cb.type === "text") {
|
|
10950
|
+
const oi = outputIndex++;
|
|
10951
|
+
const itemId = `msg_${ctx.responseId}_${oi}`;
|
|
10952
|
+
blocks.set(idx, { kind: "text", outputIndex: oi, itemId, text: "", args: "" });
|
|
10953
|
+
out.push(emit("response.output_item.added", {
|
|
10954
|
+
output_index: oi,
|
|
10955
|
+
item: { type: "message", id: itemId, status: "in_progress", role: "assistant", content: [] }
|
|
10956
|
+
}));
|
|
10957
|
+
out.push(emit("response.content_part.added", {
|
|
10958
|
+
item_id: itemId,
|
|
10959
|
+
output_index: oi,
|
|
10960
|
+
content_index: 0,
|
|
10961
|
+
part: { type: "output_text", text: "", annotations: [] }
|
|
10962
|
+
}));
|
|
10963
|
+
} else if (cb.type === "tool_use") {
|
|
10964
|
+
const oi = outputIndex++;
|
|
10965
|
+
const itemId = `fc_${cb.id}`;
|
|
10966
|
+
blocks.set(idx, { kind: "tool", outputIndex: oi, itemId, text: "", args: "", callId: cb.id, name: cb.name });
|
|
10967
|
+
out.push(emit("response.output_item.added", {
|
|
10968
|
+
output_index: oi,
|
|
10969
|
+
item: { type: "function_call", id: itemId, call_id: cb.id, name: cb.name, arguments: "", status: "in_progress" }
|
|
10970
|
+
}));
|
|
10971
|
+
} else {
|
|
10972
|
+
blocks.set(idx, { kind: "skip", outputIndex: -1, itemId: "", text: "", args: "" });
|
|
10973
|
+
}
|
|
10974
|
+
break;
|
|
10975
|
+
}
|
|
10976
|
+
case "content_block_delta": {
|
|
10977
|
+
const idx = event.index ?? 0;
|
|
10978
|
+
const st = blocks.get(idx);
|
|
10979
|
+
if (!st || st.kind === "skip")
|
|
10980
|
+
break;
|
|
10981
|
+
if (st.kind === "text" && event.delta?.type === "text_delta" && typeof event.delta.text === "string") {
|
|
10982
|
+
st.text += event.delta.text;
|
|
10983
|
+
out.push(emit("response.output_text.delta", {
|
|
10984
|
+
item_id: st.itemId,
|
|
10985
|
+
output_index: st.outputIndex,
|
|
10986
|
+
content_index: 0,
|
|
10987
|
+
delta: event.delta.text
|
|
10988
|
+
}));
|
|
10989
|
+
} else if (st.kind === "tool" && event.delta?.type === "input_json_delta" && typeof event.delta.partial_json === "string") {
|
|
10990
|
+
st.args += event.delta.partial_json;
|
|
10991
|
+
out.push(emit("response.function_call_arguments.delta", {
|
|
10992
|
+
item_id: st.itemId,
|
|
10993
|
+
output_index: st.outputIndex,
|
|
10994
|
+
delta: event.delta.partial_json
|
|
10995
|
+
}));
|
|
10996
|
+
}
|
|
10997
|
+
break;
|
|
10998
|
+
}
|
|
10999
|
+
case "content_block_stop": {
|
|
11000
|
+
const idx = event.index ?? 0;
|
|
11001
|
+
const st = blocks.get(idx);
|
|
11002
|
+
if (!st || st.kind === "skip")
|
|
11003
|
+
break;
|
|
11004
|
+
if (st.kind === "text") {
|
|
11005
|
+
out.push(emit("response.output_text.done", {
|
|
11006
|
+
item_id: st.itemId,
|
|
11007
|
+
output_index: st.outputIndex,
|
|
11008
|
+
content_index: 0,
|
|
11009
|
+
text: st.text
|
|
11010
|
+
}));
|
|
11011
|
+
out.push(emit("response.content_part.done", {
|
|
11012
|
+
item_id: st.itemId,
|
|
11013
|
+
output_index: st.outputIndex,
|
|
11014
|
+
content_index: 0,
|
|
11015
|
+
part: { type: "output_text", text: st.text, annotations: [] }
|
|
11016
|
+
}));
|
|
11017
|
+
const item = {
|
|
11018
|
+
type: "message",
|
|
11019
|
+
id: st.itemId,
|
|
11020
|
+
status: "completed",
|
|
11021
|
+
role: "assistant",
|
|
11022
|
+
content: [{ type: "output_text", text: st.text, annotations: [] }]
|
|
11023
|
+
};
|
|
11024
|
+
finalOutput.push(item);
|
|
11025
|
+
out.push(emit("response.output_item.done", { output_index: st.outputIndex, item }));
|
|
11026
|
+
} else if (st.kind === "tool") {
|
|
11027
|
+
out.push(emit("response.function_call_arguments.done", {
|
|
11028
|
+
item_id: st.itemId,
|
|
11029
|
+
output_index: st.outputIndex,
|
|
11030
|
+
arguments: st.args
|
|
11031
|
+
}));
|
|
11032
|
+
const item = {
|
|
11033
|
+
type: "function_call",
|
|
11034
|
+
id: st.itemId,
|
|
11035
|
+
call_id: st.callId,
|
|
11036
|
+
name: st.name,
|
|
11037
|
+
arguments: st.args,
|
|
11038
|
+
status: "completed"
|
|
11039
|
+
};
|
|
11040
|
+
finalOutput.push(item);
|
|
11041
|
+
out.push(emit("response.output_item.done", { output_index: st.outputIndex, item }));
|
|
11042
|
+
}
|
|
11043
|
+
break;
|
|
11044
|
+
}
|
|
11045
|
+
case "message_delta": {
|
|
11046
|
+
if (typeof event.usage?.output_tokens === "number")
|
|
11047
|
+
outputTokens = event.usage.output_tokens;
|
|
11048
|
+
break;
|
|
11049
|
+
}
|
|
11050
|
+
case "message_stop": {
|
|
11051
|
+
out.push(emit("response.completed", {
|
|
11052
|
+
response: responseEnvelope("completed", {
|
|
11053
|
+
output: finalOutput,
|
|
11054
|
+
usage: { input_tokens: inputTokens, output_tokens: outputTokens, total_tokens: inputTokens + outputTokens },
|
|
11055
|
+
parallel_tool_calls: true,
|
|
11056
|
+
tool_choice: "auto",
|
|
11057
|
+
tools: []
|
|
11058
|
+
})
|
|
11059
|
+
}));
|
|
11060
|
+
break;
|
|
11061
|
+
}
|
|
11062
|
+
default:
|
|
11063
|
+
break;
|
|
11064
|
+
}
|
|
11065
|
+
return out;
|
|
11066
|
+
};
|
|
11067
|
+
}
|
|
11068
|
+
|
|
10725
11069
|
// src/proxy/messages.ts
|
|
10726
11070
|
function stripCacheControlForHashing(obj) {
|
|
10727
11071
|
if (!obj || typeof obj !== "object")
|
|
@@ -10780,6 +11124,27 @@ function getLastUserMessage(messages) {
|
|
|
10780
11124
|
}
|
|
10781
11125
|
return messages.slice(-1);
|
|
10782
11126
|
}
|
|
11127
|
+
function frameReplayTurns(turns) {
|
|
11128
|
+
const nonEmpty = turns.filter((t) => t.text);
|
|
11129
|
+
const joined = nonEmpty.map((t) => t.text).join(`
|
|
11130
|
+
|
|
11131
|
+
`);
|
|
11132
|
+
if (nonEmpty.length < 2)
|
|
11133
|
+
return joined;
|
|
11134
|
+
const last = nonEmpty[nonEmpty.length - 1];
|
|
11135
|
+
if (last.role !== "user")
|
|
11136
|
+
return joined;
|
|
11137
|
+
const history = nonEmpty.slice(0, -1).map((t) => t.text).join(`
|
|
11138
|
+
|
|
11139
|
+
`);
|
|
11140
|
+
return `<conversation_history>
|
|
11141
|
+
${history}
|
|
11142
|
+
</conversation_history>
|
|
11143
|
+
|
|
11144
|
+
` + `The above is a replay of your prior conversation with this user — the original session could not be resumed. ` + `It is context only: do not continue or imitate its transcript format, do not write "[Assistant: ...]" markers, ` + `and never invent tool output — use your actual tools when action is needed. ` + `Respond only as the assistant to the user's message below.
|
|
11145
|
+
|
|
11146
|
+
` + last.text;
|
|
11147
|
+
}
|
|
10783
11148
|
function stripNonStandardStreamFields(event) {
|
|
10784
11149
|
if (event && typeof event === "object") {
|
|
10785
11150
|
const e = event;
|
|
@@ -11099,7 +11464,7 @@ init_env();
|
|
|
11099
11464
|
var openCodeTransforms = [
|
|
11100
11465
|
{
|
|
11101
11466
|
name: "opencode-core",
|
|
11102
|
-
adapters: ["opencode", "openai"],
|
|
11467
|
+
adapters: ["opencode", "openai", "codex"],
|
|
11103
11468
|
onRequest(ctx) {
|
|
11104
11469
|
const body = ctx.body;
|
|
11105
11470
|
const blockedTools = BLOCKED_BUILTIN_TOOLS;
|
|
@@ -11903,6 +12268,15 @@ var openAiAdapter = {
|
|
|
11903
12268
|
name: "openai"
|
|
11904
12269
|
};
|
|
11905
12270
|
|
|
12271
|
+
// src/proxy/adapters/codex.ts
|
|
12272
|
+
var codexAdapter = {
|
|
12273
|
+
...openCodeAdapter,
|
|
12274
|
+
name: "codex",
|
|
12275
|
+
usesPassthrough() {
|
|
12276
|
+
return true;
|
|
12277
|
+
}
|
|
12278
|
+
};
|
|
12279
|
+
|
|
11906
12280
|
// src/proxy/adapters/cherry.ts
|
|
11907
12281
|
var CHERRY_WEB_TOOLS = ["WebSearch", "WebFetch"];
|
|
11908
12282
|
var isWebTool = (t) => CHERRY_WEB_TOOLS.includes(t);
|
|
@@ -12024,7 +12398,8 @@ var ADAPTER_MAP = {
|
|
|
12024
12398
|
claudecode: claudeCodeAdapter,
|
|
12025
12399
|
cherry: cherryAdapter,
|
|
12026
12400
|
cherrystudio: cherryAdapter,
|
|
12027
|
-
openai: openAiAdapter
|
|
12401
|
+
openai: openAiAdapter,
|
|
12402
|
+
codex: codexAdapter
|
|
12028
12403
|
};
|
|
12029
12404
|
var envDefault = process.env.MERIDIAN_DEFAULT_AGENT || "";
|
|
12030
12405
|
if (envDefault && !ADAPTER_MAP[envDefault]) {
|
|
@@ -17852,6 +18227,7 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
17852
18227
|
resumeSessionId,
|
|
17853
18228
|
isUndo,
|
|
17854
18229
|
undoRollbackUuid,
|
|
18230
|
+
forkSession,
|
|
17855
18231
|
sdkHooks,
|
|
17856
18232
|
blockedTools,
|
|
17857
18233
|
incompatibleTools,
|
|
@@ -17891,7 +18267,6 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
17891
18267
|
...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt, cwdNote),
|
|
17892
18268
|
...passthrough ? {
|
|
17893
18269
|
tools: [],
|
|
17894
|
-
settingSources: [],
|
|
17895
18270
|
disallowedTools: [...allBlockedTools],
|
|
17896
18271
|
...passthroughMcp ? {
|
|
17897
18272
|
allowedTools: [...passthroughMcp.toolNames],
|
|
@@ -17903,13 +18278,11 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
17903
18278
|
mcpServers: { [mcpServerName]: createOpencodeMcpServer() }
|
|
17904
18279
|
},
|
|
17905
18280
|
plugins: [],
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
17910
|
-
|
|
17911
|
-
}
|
|
17912
|
-
} : {},
|
|
18281
|
+
settings: {
|
|
18282
|
+
autoMemoryEnabled: ctx.memory ?? true,
|
|
18283
|
+
autoDreamEnabled: ctx.dreaming ?? false
|
|
18284
|
+
},
|
|
18285
|
+
settingSources: settingSources ?? [],
|
|
17913
18286
|
...onStderr ? { stderr: onStderr } : {},
|
|
17914
18287
|
env: {
|
|
17915
18288
|
...sharedMemory ? stripConfigDir(cleanEnv) : cleanEnv,
|
|
@@ -17921,7 +18294,8 @@ function buildQueryOptions(ctx, abortController) {
|
|
|
17921
18294
|
},
|
|
17922
18295
|
...Object.keys(sdkAgents).length > 0 ? { agents: sdkAgents } : {},
|
|
17923
18296
|
...resumeSessionId ? { resume: resumeSessionId } : {},
|
|
17924
|
-
...isUndo
|
|
18297
|
+
...isUndo || forkSession ? { forkSession: true } : {},
|
|
18298
|
+
...isUndo && undoRollbackUuid ? { resumeSessionAt: undoRollbackUuid } : {},
|
|
17925
18299
|
...sdkHooks ? { hooks: sdkHooks } : {},
|
|
17926
18300
|
...effort ? { effort } : {},
|
|
17927
18301
|
...thinking ? { thinking } : {},
|
|
@@ -17998,6 +18372,17 @@ var cherryTransforms = [
|
|
|
17998
18372
|
}
|
|
17999
18373
|
];
|
|
18000
18374
|
|
|
18375
|
+
// src/proxy/transforms/codex.ts
|
|
18376
|
+
var codexTransforms = [
|
|
18377
|
+
{
|
|
18378
|
+
name: "codex-force-passthrough",
|
|
18379
|
+
adapters: ["codex"],
|
|
18380
|
+
onRequest(ctx) {
|
|
18381
|
+
return { ...ctx, passthrough: true };
|
|
18382
|
+
}
|
|
18383
|
+
}
|
|
18384
|
+
];
|
|
18385
|
+
|
|
18001
18386
|
// src/proxy/transforms/registry.ts
|
|
18002
18387
|
var ADAPTER_TRANSFORMS = {
|
|
18003
18388
|
opencode: openCodeTransforms,
|
|
@@ -18007,7 +18392,8 @@ var ADAPTER_TRANSFORMS = {
|
|
|
18007
18392
|
forgecode: forgeCodeTransforms,
|
|
18008
18393
|
passthrough: passthroughTransforms,
|
|
18009
18394
|
cherry: cherryTransforms,
|
|
18010
|
-
openai: openCodeTransforms
|
|
18395
|
+
openai: openCodeTransforms,
|
|
18396
|
+
codex: [...openCodeTransforms, ...codexTransforms]
|
|
18011
18397
|
};
|
|
18012
18398
|
function getAdapterTransforms(adapterName) {
|
|
18013
18399
|
return ADAPTER_TRANSFORMS[adapterName] ?? [];
|
|
@@ -19019,15 +19405,13 @@ function buildFreshPrompt(messages, sanitizeOpts = {}) {
|
|
|
19019
19405
|
yield msg;
|
|
19020
19406
|
}();
|
|
19021
19407
|
}
|
|
19022
|
-
return messages.map((m) => {
|
|
19408
|
+
return frameReplayTurns(messages.map((m) => {
|
|
19023
19409
|
if (m.role === "assistant") {
|
|
19024
19410
|
const assistantText = flattenAssistantContent(m.content);
|
|
19025
|
-
return assistantText ? `[Assistant: ${assistantText}]` : "";
|
|
19411
|
+
return { role: "assistant", text: assistantText ? `[Assistant: ${assistantText}]` : "" };
|
|
19026
19412
|
}
|
|
19027
|
-
return flattenUserContent(m.content, sanitizeOpts, toolIndex);
|
|
19028
|
-
})
|
|
19029
|
-
|
|
19030
|
-
`) || "";
|
|
19413
|
+
return { role: "user", text: flattenUserContent(m.content, sanitizeOpts, toolIndex) };
|
|
19414
|
+
}));
|
|
19031
19415
|
}
|
|
19032
19416
|
var proxyLogSilent = false;
|
|
19033
19417
|
function plog(message) {
|
|
@@ -19090,6 +19474,8 @@ function createProxyServer(config = {}) {
|
|
|
19090
19474
|
const sessionMcpCache = new LRUMap(getMaxSessionsLimit());
|
|
19091
19475
|
const PENDING_STORE_WAIT_MS = 3000;
|
|
19092
19476
|
const PENDING_STORE_AUTO_RESOLVE_MS = 1e4;
|
|
19477
|
+
const BUSY_SESSION_MAX_RETRIES = 3;
|
|
19478
|
+
const BUSY_SESSION_RETRY_DELAY_MS = parseInt(process.env.MERIDIAN_BUSY_RETRY_DELAY_MS ?? "500", 10);
|
|
19093
19479
|
const pendingSessionStores = new Map;
|
|
19094
19480
|
const registerPendingStore = (key) => {
|
|
19095
19481
|
let resolveFn = () => {};
|
|
@@ -19133,7 +19519,7 @@ function createProxyServer(config = {}) {
|
|
|
19133
19519
|
status: "ok",
|
|
19134
19520
|
service: "meridian",
|
|
19135
19521
|
format: "anthropic",
|
|
19136
|
-
endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/models", "/telemetry", "/metrics", "/health"]
|
|
19522
|
+
endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/responses", "/v1/models", "/telemetry", "/metrics", "/health"]
|
|
19137
19523
|
});
|
|
19138
19524
|
}
|
|
19139
19525
|
return c.html(landingHtml);
|
|
@@ -19198,7 +19584,7 @@ function createProxyServer(config = {}) {
|
|
|
19198
19584
|
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
19199
19585
|
const requestedModel = typeof body.model === "string" ? body.model : "sonnet";
|
|
19200
19586
|
let model = mapModelToClaudeModel(requestedModel, authStatus?.subscriptionType, agentMode);
|
|
19201
|
-
const envOverrides =
|
|
19587
|
+
const envOverrides = explicitModelPin(requestedModel);
|
|
19202
19588
|
const cwdResolution = resolveSdkWorkingDirectory({
|
|
19203
19589
|
envOverride: process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR,
|
|
19204
19590
|
adapterCwd: adapter.extractWorkingDirectory(body),
|
|
@@ -19407,17 +19793,18 @@ function createProxyServer(config = {}) {
|
|
|
19407
19793
|
}
|
|
19408
19794
|
} else {
|
|
19409
19795
|
const toolIndex = buildToolUseIndex(allMessages ?? messagesToConvert ?? []);
|
|
19410
|
-
|
|
19796
|
+
const promptTurns = (messagesToConvert ?? []).map((m) => {
|
|
19411
19797
|
if (m.role === "assistant") {
|
|
19412
19798
|
if (isResume)
|
|
19413
|
-
return "";
|
|
19799
|
+
return { role: "assistant", text: "" };
|
|
19414
19800
|
const assistantText = flattenAssistantContent(m.content);
|
|
19415
|
-
return assistantText ? `[Assistant: ${assistantText}]` : "";
|
|
19801
|
+
return { role: "assistant", text: assistantText ? `[Assistant: ${assistantText}]` : "" };
|
|
19416
19802
|
}
|
|
19417
|
-
return flattenUserContent(m.content, sanitizeOpts, toolIndex);
|
|
19418
|
-
})
|
|
19803
|
+
return { role: "user", text: flattenUserContent(m.content, sanitizeOpts, toolIndex) };
|
|
19804
|
+
});
|
|
19805
|
+
textPrompt = isResume ? promptTurns.map((t) => t.text).filter(Boolean).join(`
|
|
19419
19806
|
|
|
19420
|
-
`) || "";
|
|
19807
|
+
`) || "" : frameReplayTurns(promptTurns);
|
|
19421
19808
|
}
|
|
19422
19809
|
const passthrough = adapter.instancePassthrough !== undefined ? adapter.instancePassthrough : pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
19423
19810
|
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
|
|
@@ -19543,7 +19930,7 @@ function createProxyServer(config = {}) {
|
|
|
19543
19930
|
input: toolInput
|
|
19544
19931
|
});
|
|
19545
19932
|
}
|
|
19546
|
-
if (
|
|
19933
|
+
if (earlyStopEnabled && turnGenerating && !requestAbort.controller.signal.aborted) {
|
|
19547
19934
|
await holdDenyUntilTurnEnd();
|
|
19548
19935
|
}
|
|
19549
19936
|
if (isExactDuplicate) {
|
|
@@ -19600,8 +19987,12 @@ function createProxyServer(config = {}) {
|
|
|
19600
19987
|
}
|
|
19601
19988
|
let tokenRefreshed = false;
|
|
19602
19989
|
let didFreshBaseRetry = false;
|
|
19990
|
+
let busySessionRetries = 0;
|
|
19991
|
+
let busySessionFork = false;
|
|
19603
19992
|
while (true) {
|
|
19604
19993
|
let didYieldContent = false;
|
|
19994
|
+
const attemptStderrStart = stderrLines.length;
|
|
19995
|
+
turnGenerating = true;
|
|
19605
19996
|
try {
|
|
19606
19997
|
for await (const event of query(buildQueryOptions({
|
|
19607
19998
|
prompt: makePrompt(),
|
|
@@ -19620,6 +20011,7 @@ function createProxyServer(config = {}) {
|
|
|
19620
20011
|
resumeSessionId,
|
|
19621
20012
|
isUndo,
|
|
19622
20013
|
undoRollbackUuid,
|
|
20014
|
+
forkSession: busySessionFork || undefined,
|
|
19623
20015
|
sdkHooks,
|
|
19624
20016
|
blockedTools: pipelineCtx.blockedTools,
|
|
19625
20017
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -19654,8 +20046,25 @@ function createProxyServer(config = {}) {
|
|
|
19654
20046
|
return;
|
|
19655
20047
|
} catch (error) {
|
|
19656
20048
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
20049
|
+
releaseHeldDenies("non_stream_attempt_error");
|
|
19657
20050
|
if (didYieldContent)
|
|
19658
20051
|
throw error;
|
|
20052
|
+
if (resumeSessionId && isBusySessionError(error, stderrLines.slice(attemptStderrStart).join(`
|
|
20053
|
+
`))) {
|
|
20054
|
+
if (busySessionRetries < BUSY_SESSION_MAX_RETRIES) {
|
|
20055
|
+
busySessionRetries++;
|
|
20056
|
+
claudeLog("session.busy_retry", { mode: "non_stream", attempt: busySessionRetries, resumeSessionId });
|
|
20057
|
+
plog(`[PROXY] ${requestMeta.requestId} session busy (bg agent), retrying resume ${busySessionRetries}/${BUSY_SESSION_MAX_RETRIES}`);
|
|
20058
|
+
await new Promise((resolve3) => setTimeout(resolve3, BUSY_SESSION_RETRY_DELAY_MS * busySessionRetries));
|
|
20059
|
+
continue;
|
|
20060
|
+
}
|
|
20061
|
+
if (!busySessionFork) {
|
|
20062
|
+
busySessionFork = true;
|
|
20063
|
+
claudeLog("session.busy_fork", { mode: "non_stream", resumeSessionId });
|
|
20064
|
+
plog(`[PROXY] ${requestMeta.requestId} session still busy after ${BUSY_SESSION_MAX_RETRIES} retries — forking session`);
|
|
20065
|
+
continue;
|
|
20066
|
+
}
|
|
20067
|
+
}
|
|
19659
20068
|
if (isStaleSessionError(error)) {
|
|
19660
20069
|
claudeLog("session.stale_uuid_retry", {
|
|
19661
20070
|
mode: "non_stream",
|
|
@@ -19839,6 +20248,7 @@ function createProxyServer(config = {}) {
|
|
|
19839
20248
|
}
|
|
19840
20249
|
}
|
|
19841
20250
|
if (message.type === "assistant") {
|
|
20251
|
+
releaseHeldDenies("assistant_message");
|
|
19842
20252
|
assistantMessages += 1;
|
|
19843
20253
|
if (message.uuid) {
|
|
19844
20254
|
sdkUuidMap.push(message.uuid);
|
|
@@ -19899,6 +20309,7 @@ function createProxyServer(config = {}) {
|
|
|
19899
20309
|
}
|
|
19900
20310
|
}
|
|
19901
20311
|
}
|
|
20312
|
+
releaseHeldDenies("non_stream_loop_exit");
|
|
19902
20313
|
claudeLog("upstream.completed", {
|
|
19903
20314
|
mode: "non_stream",
|
|
19904
20315
|
model,
|
|
@@ -19918,6 +20329,7 @@ function createProxyServer(config = {}) {
|
|
|
19918
20329
|
plog(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
|
|
19919
20330
|
}
|
|
19920
20331
|
} catch (error) {
|
|
20332
|
+
releaseHeldDenies("non_stream_error");
|
|
19921
20333
|
const stderrOutput = stderrLines.join(`
|
|
19922
20334
|
`).trim();
|
|
19923
20335
|
if (stderrOutput && error instanceof Error && !error.message.includes(stderrOutput)) {
|
|
@@ -20158,8 +20570,11 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
20158
20570
|
}
|
|
20159
20571
|
let tokenRefreshed = false;
|
|
20160
20572
|
let didFreshBaseRetry = false;
|
|
20573
|
+
let busySessionRetries = 0;
|
|
20574
|
+
let busySessionFork = false;
|
|
20161
20575
|
while (true) {
|
|
20162
20576
|
let didYieldClientEvent = false;
|
|
20577
|
+
const attemptStderrStart = stderrLines.length;
|
|
20163
20578
|
try {
|
|
20164
20579
|
for await (const event of query(buildQueryOptions({
|
|
20165
20580
|
prompt: makePrompt(),
|
|
@@ -20178,6 +20593,7 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
20178
20593
|
resumeSessionId,
|
|
20179
20594
|
isUndo,
|
|
20180
20595
|
undoRollbackUuid,
|
|
20596
|
+
forkSession: busySessionFork || undefined,
|
|
20181
20597
|
sdkHooks,
|
|
20182
20598
|
blockedTools: pipelineCtx.blockedTools,
|
|
20183
20599
|
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
@@ -20214,6 +20630,22 @@ data: ${JSON.stringify({ type: "content_block_stop", index: idx })}
|
|
|
20214
20630
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
20215
20631
|
if (didYieldClientEvent)
|
|
20216
20632
|
throw error;
|
|
20633
|
+
if (resumeSessionId && isBusySessionError(error, stderrLines.slice(attemptStderrStart).join(`
|
|
20634
|
+
`))) {
|
|
20635
|
+
if (busySessionRetries < BUSY_SESSION_MAX_RETRIES) {
|
|
20636
|
+
busySessionRetries++;
|
|
20637
|
+
claudeLog("session.busy_retry", { mode: "stream", attempt: busySessionRetries, resumeSessionId });
|
|
20638
|
+
plog(`[PROXY] ${requestMeta.requestId} session busy (bg agent), retrying resume ${busySessionRetries}/${BUSY_SESSION_MAX_RETRIES}`);
|
|
20639
|
+
await new Promise((resolve3) => setTimeout(resolve3, BUSY_SESSION_RETRY_DELAY_MS * busySessionRetries));
|
|
20640
|
+
continue;
|
|
20641
|
+
}
|
|
20642
|
+
if (!busySessionFork) {
|
|
20643
|
+
busySessionFork = true;
|
|
20644
|
+
claudeLog("session.busy_fork", { mode: "stream", resumeSessionId });
|
|
20645
|
+
plog(`[PROXY] ${requestMeta.requestId} session still busy after ${BUSY_SESSION_MAX_RETRIES} retries — forking session`);
|
|
20646
|
+
continue;
|
|
20647
|
+
}
|
|
20648
|
+
}
|
|
20217
20649
|
if (isStaleSessionError(error)) {
|
|
20218
20650
|
claudeLog("session.stale_uuid_retry", {
|
|
20219
20651
|
mode: "stream",
|
|
@@ -21373,7 +21805,7 @@ data: ${JSON.stringify({
|
|
|
21373
21805
|
}
|
|
21374
21806
|
const completionId = `chatcmpl-${randomUUID()}`;
|
|
21375
21807
|
const created = Math.floor(Date.now() / 1000);
|
|
21376
|
-
const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model :
|
|
21808
|
+
const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : CANONICAL_SONNET_MODEL;
|
|
21377
21809
|
const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
21378
21810
|
const sdkFeatures = getFeaturesForAdapter2("openai");
|
|
21379
21811
|
if (!anthropicBody.stream) {
|
|
@@ -21452,6 +21884,107 @@ data: ${JSON.stringify({
|
|
|
21452
21884
|
}
|
|
21453
21885
|
});
|
|
21454
21886
|
});
|
|
21887
|
+
app.post("/v1/responses", async (c) => {
|
|
21888
|
+
const rawBody = await c.req.json();
|
|
21889
|
+
const anthropicBody = translateResponsesToAnthropic(rawBody);
|
|
21890
|
+
if (!anthropicBody) {
|
|
21891
|
+
return c.json({ error: { type: "invalid_request_error", message: "input: Field required", code: null } }, 400);
|
|
21892
|
+
}
|
|
21893
|
+
if (!anthropicBody.model) {
|
|
21894
|
+
return c.json({ error: { type: "invalid_request_error", message: "model: Field required", code: null } }, 400);
|
|
21895
|
+
}
|
|
21896
|
+
const internalHeaders = {
|
|
21897
|
+
"Content-Type": "application/json",
|
|
21898
|
+
"x-meridian-agent": "codex"
|
|
21899
|
+
};
|
|
21900
|
+
const xApiKey = c.req.header("x-api-key");
|
|
21901
|
+
if (xApiKey)
|
|
21902
|
+
internalHeaders["x-api-key"] = xApiKey;
|
|
21903
|
+
const authz = c.req.header("authorization");
|
|
21904
|
+
if (authz)
|
|
21905
|
+
internalHeaders["authorization"] = authz;
|
|
21906
|
+
const xProfile = c.req.header("x-meridian-profile");
|
|
21907
|
+
if (xProfile)
|
|
21908
|
+
internalHeaders["x-meridian-profile"] = xProfile;
|
|
21909
|
+
const internalReq = new Request("http://internal/v1/messages", {
|
|
21910
|
+
method: "POST",
|
|
21911
|
+
headers: internalHeaders,
|
|
21912
|
+
body: JSON.stringify(anthropicBody)
|
|
21913
|
+
});
|
|
21914
|
+
const internalRes = await app.fetch(internalReq);
|
|
21915
|
+
if (!internalRes.ok) {
|
|
21916
|
+
const errBody = await internalRes.text();
|
|
21917
|
+
return c.json({ error: { type: "upstream_error", message: errBody, code: null } }, internalRes.status);
|
|
21918
|
+
}
|
|
21919
|
+
const responseId = `resp_${randomUUID().replace(/-/g, "")}`;
|
|
21920
|
+
const created = Math.floor(Date.now() / 1000);
|
|
21921
|
+
const model = typeof rawBody.model === "string" && rawBody.model ? rawBody.model : CANONICAL_SONNET_MODEL;
|
|
21922
|
+
const ctx = { responseId, model, created, reasoningRequested: reasoningRequested(rawBody) };
|
|
21923
|
+
if (!anthropicBody.stream) {
|
|
21924
|
+
const anthropicRes = await internalRes.json();
|
|
21925
|
+
return c.json(translateAnthropicToResponses(anthropicRes, ctx));
|
|
21926
|
+
}
|
|
21927
|
+
const encoder = new TextEncoder;
|
|
21928
|
+
const readable = new ReadableStream({
|
|
21929
|
+
async start(controller) {
|
|
21930
|
+
const reader = internalRes.body?.getReader();
|
|
21931
|
+
if (!reader) {
|
|
21932
|
+
controller.close();
|
|
21933
|
+
return;
|
|
21934
|
+
}
|
|
21935
|
+
const decoder = new TextDecoder;
|
|
21936
|
+
let buffer = "";
|
|
21937
|
+
const translate = createResponsesSseTranslator(ctx);
|
|
21938
|
+
try {
|
|
21939
|
+
while (true) {
|
|
21940
|
+
const { done, value } = await reader.read();
|
|
21941
|
+
if (done)
|
|
21942
|
+
break;
|
|
21943
|
+
buffer += decoder.decode(value, { stream: true });
|
|
21944
|
+
const lines = buffer.split(`
|
|
21945
|
+
`);
|
|
21946
|
+
buffer = lines.pop() ?? "";
|
|
21947
|
+
for (const line of lines) {
|
|
21948
|
+
if (!line.startsWith("data: "))
|
|
21949
|
+
continue;
|
|
21950
|
+
const dataStr = line.slice(6).trim();
|
|
21951
|
+
if (!dataStr)
|
|
21952
|
+
continue;
|
|
21953
|
+
let event;
|
|
21954
|
+
try {
|
|
21955
|
+
event = JSON.parse(dataStr);
|
|
21956
|
+
} catch {
|
|
21957
|
+
continue;
|
|
21958
|
+
}
|
|
21959
|
+
if (typeof event.type !== "string")
|
|
21960
|
+
continue;
|
|
21961
|
+
for (const emission of translate(event)) {
|
|
21962
|
+
controller.enqueue(encoder.encode(`event: ${emission.event}
|
|
21963
|
+
data: ${JSON.stringify(emission.data)}
|
|
21964
|
+
|
|
21965
|
+
`));
|
|
21966
|
+
}
|
|
21967
|
+
}
|
|
21968
|
+
}
|
|
21969
|
+
} catch (err) {
|
|
21970
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
21971
|
+
controller.enqueue(encoder.encode(`event: response.failed
|
|
21972
|
+
data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: { message } } })}
|
|
21973
|
+
|
|
21974
|
+
`));
|
|
21975
|
+
} finally {
|
|
21976
|
+
controller.close();
|
|
21977
|
+
}
|
|
21978
|
+
}
|
|
21979
|
+
});
|
|
21980
|
+
return new Response(readable, {
|
|
21981
|
+
headers: {
|
|
21982
|
+
"Content-Type": "text/event-stream",
|
|
21983
|
+
"Cache-Control": "no-cache",
|
|
21984
|
+
Connection: "keep-alive"
|
|
21985
|
+
}
|
|
21986
|
+
});
|
|
21987
|
+
});
|
|
21455
21988
|
app.get("/v1/models", async (c) => {
|
|
21456
21989
|
const authStatus = await getClaudeAuthStatusAsync();
|
|
21457
21990
|
const isMax = authStatus?.subscriptionType === "max";
|