clawmux 0.3.13 → 0.3.14
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 +1 -1
- package/dist/cli.cjs +100 -192
- package/dist/index.cjs +100 -192
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ ClawMux resolves each model's context window using this priority chain:
|
|
|
109
109
|
|
|
110
110
|
1. **~/.openclaw/clawmux.json** `routing.contextWindows` — explicit per-model override
|
|
111
111
|
2. **openclaw.json** `models.providers[provider].models[].contextWindow` — user config
|
|
112
|
-
3. **OpenClaw built-in catalog** — pi-ai model database (
|
|
112
|
+
3. **OpenClaw built-in catalog** — pi-ai model database (830+ models)
|
|
113
113
|
4. **Default: 200,000 tokens**
|
|
114
114
|
|
|
115
115
|
Compression threshold uses the **minimum** context window across all routing models, since compression happens before routing decides which model to use.
|
package/dist/cli.cjs
CHANGED
|
@@ -112220,7 +112220,7 @@ var import_node_child_process = require("node:child_process");
|
|
|
112220
112220
|
var import_node_os2 = require("node:os");
|
|
112221
112221
|
|
|
112222
112222
|
// src/proxy/router.ts
|
|
112223
|
-
var VERSION = process.env.npm_package_version ?? "0.3.
|
|
112223
|
+
var VERSION = process.env.npm_package_version ?? "0.3.14";
|
|
112224
112224
|
function jsonResponse(body, status = 200) {
|
|
112225
112225
|
return new Response(JSON.stringify(body), {
|
|
112226
112226
|
status,
|
|
@@ -115091,6 +115091,9 @@ function djb2Hash(text) {
|
|
|
115091
115091
|
return (hash >>> 0).toString(16);
|
|
115092
115092
|
}
|
|
115093
115093
|
function extractText(content) {
|
|
115094
|
+
if (content === null || content === undefined) {
|
|
115095
|
+
return "";
|
|
115096
|
+
}
|
|
115094
115097
|
if (typeof content === "string") {
|
|
115095
115098
|
return content.slice(0, 200);
|
|
115096
115099
|
}
|
|
@@ -115103,6 +115106,9 @@ function extractText(content) {
|
|
|
115103
115106
|
return concatenated.slice(0, 200);
|
|
115104
115107
|
}
|
|
115105
115108
|
function contentLength(content) {
|
|
115109
|
+
if (content === null || content === undefined) {
|
|
115110
|
+
return 0;
|
|
115111
|
+
}
|
|
115106
115112
|
if (typeof content === "string") {
|
|
115107
115113
|
return content.length;
|
|
115108
115114
|
}
|
|
@@ -115178,7 +115184,7 @@ class EscalationMemory {
|
|
|
115178
115184
|
}
|
|
115179
115185
|
|
|
115180
115186
|
// src/routing/instruction-injector.ts
|
|
115181
|
-
var INJECT_FOR_TIERS = new Set(["LIGHT"]);
|
|
115187
|
+
var INJECT_FOR_TIERS = new Set(["LIGHT", "MEDIUM"]);
|
|
115182
115188
|
var ESCALATION_INSTRUCTION = `If you cannot handle this request fully (due to complexity, missing context, or capability limits), output EXACTLY the following marker with no other text on that line: ${ESCALATE_SIGNAL}
|
|
115183
115189
|
Do not explain. Do not ask permission. Just emit the marker and stop.`;
|
|
115184
115190
|
function injectEscalationInstruction(messages) {
|
|
@@ -115194,6 +115200,12 @@ function injectEscalationInstruction(messages) {
|
|
|
115194
115200
|
...rest
|
|
115195
115201
|
];
|
|
115196
115202
|
}
|
|
115203
|
+
if (first.content === null) {
|
|
115204
|
+
return [
|
|
115205
|
+
{ role: "system", content: ESCALATION_INSTRUCTION },
|
|
115206
|
+
...rest
|
|
115207
|
+
];
|
|
115208
|
+
}
|
|
115197
115209
|
if (typeof first.content === "string") {
|
|
115198
115210
|
return [
|
|
115199
115211
|
{ role: "system", content: first.content + `
|
|
@@ -119730,8 +119742,7 @@ function piStreamToAnthropicSse(piStream) {
|
|
|
119730
119742
|
}
|
|
119731
119743
|
});
|
|
119732
119744
|
}
|
|
119733
|
-
|
|
119734
|
-
const msg = await piStream.result();
|
|
119745
|
+
function anthropicMessageFromAssistant(msg) {
|
|
119735
119746
|
if ((msg.stopReason === "error" || msg.stopReason === "aborted") && msg.errorMessage) {
|
|
119736
119747
|
console.error(`[clawmux] pi-ai upstream error (${msg.stopReason}): ${msg.errorMessage}`);
|
|
119737
119748
|
}
|
|
@@ -119769,6 +119780,10 @@ async function piStreamToAnthropicJson(piStream) {
|
|
|
119769
119780
|
...msg.errorMessage ? { error_message: msg.errorMessage } : {}
|
|
119770
119781
|
};
|
|
119771
119782
|
}
|
|
119783
|
+
async function piStreamToAnthropicJson(piStream) {
|
|
119784
|
+
const msg = await piStream.result();
|
|
119785
|
+
return anthropicMessageFromAssistant(msg);
|
|
119786
|
+
}
|
|
119772
119787
|
|
|
119773
119788
|
// src/pi-bridge/event-to-openai-completions.ts
|
|
119774
119789
|
var encoder3 = new TextEncoder;
|
|
@@ -119992,8 +120007,7 @@ function piStreamToOpenAiCompletionsSse(piStream) {
|
|
|
119992
120007
|
}
|
|
119993
120008
|
});
|
|
119994
120009
|
}
|
|
119995
|
-
|
|
119996
|
-
const msg = await piStream.result();
|
|
120010
|
+
function openAiCompletionsMessageFromAssistant(msg) {
|
|
119997
120011
|
let textContent = "";
|
|
119998
120012
|
const toolCalls = [];
|
|
119999
120013
|
let reasoning = "";
|
|
@@ -120043,6 +120057,10 @@ async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
|
120043
120057
|
}
|
|
120044
120058
|
};
|
|
120045
120059
|
}
|
|
120060
|
+
async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
120061
|
+
const msg = await piStream.result();
|
|
120062
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120063
|
+
}
|
|
120046
120064
|
|
|
120047
120065
|
// src/pi-bridge/event-to-openai-responses.ts
|
|
120048
120066
|
var encoder4 = new TextEncoder;
|
|
@@ -120205,8 +120223,7 @@ function piStreamToOpenAiResponsesSse(piStream) {
|
|
|
120205
120223
|
}
|
|
120206
120224
|
});
|
|
120207
120225
|
}
|
|
120208
|
-
|
|
120209
|
-
const msg = await piStream.result();
|
|
120226
|
+
function openAiResponsesMessageFromAssistant(msg) {
|
|
120210
120227
|
const output = [];
|
|
120211
120228
|
for (const c of msg.content) {
|
|
120212
120229
|
if (c.type === "text") {
|
|
@@ -120247,6 +120264,10 @@ async function piStreamToOpenAiResponsesJson(piStream) {
|
|
|
120247
120264
|
}
|
|
120248
120265
|
};
|
|
120249
120266
|
}
|
|
120267
|
+
async function piStreamToOpenAiResponsesJson(piStream) {
|
|
120268
|
+
const msg = await piStream.result();
|
|
120269
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120270
|
+
}
|
|
120250
120271
|
|
|
120251
120272
|
// src/pi-bridge/event-to-google.ts
|
|
120252
120273
|
var encoder5 = new TextEncoder;
|
|
@@ -120363,8 +120384,7 @@ function piStreamToGoogleSse(piStream) {
|
|
|
120363
120384
|
}
|
|
120364
120385
|
});
|
|
120365
120386
|
}
|
|
120366
|
-
|
|
120367
|
-
const msg = await piStream.result();
|
|
120387
|
+
function googleMessageFromAssistant(msg) {
|
|
120368
120388
|
const parts = [];
|
|
120369
120389
|
for (const c of msg.content) {
|
|
120370
120390
|
if (c.type === "text") {
|
|
@@ -120396,6 +120416,10 @@ async function piStreamToGoogleJson(piStream) {
|
|
|
120396
120416
|
modelVersion: msg.model || ""
|
|
120397
120417
|
};
|
|
120398
120418
|
}
|
|
120419
|
+
async function piStreamToGoogleJson(piStream) {
|
|
120420
|
+
const msg = await piStream.result();
|
|
120421
|
+
return googleMessageFromAssistant(msg);
|
|
120422
|
+
}
|
|
120399
120423
|
|
|
120400
120424
|
// src/proxy/pipeline.ts
|
|
120401
120425
|
registerAdapter(new AnthropicAdapter);
|
|
@@ -120632,35 +120656,12 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120632
120656
|
}
|
|
120633
120657
|
const detector = signalRouter.createSignalDetector();
|
|
120634
120658
|
const detectionState = createSignalDetectionState();
|
|
120635
|
-
|
|
120636
|
-
const signalGen = detectSignalInStream(piStreamHandle, detector, detectionState, () => {});
|
|
120637
|
-
const sseBody = piStreamToAnthropicSseFromGenerator(signalGen);
|
|
120638
|
-
const response = new Response(sseBody, {
|
|
120639
|
-
status: 200,
|
|
120640
|
-
headers: { "content-type": "text/event-stream" }
|
|
120641
|
-
});
|
|
120642
|
-
response.clone().text().then(() => {
|
|
120643
|
-
if (detectionState.signalDetected) {
|
|
120644
|
-
abortCtrl.abort();
|
|
120645
|
-
const nextTier = signalRouter.handleEscalation(messages, currentTier);
|
|
120646
|
-
if (nextTier !== null) {
|
|
120647
|
-
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected)`);
|
|
120648
|
-
currentTier = nextTier;
|
|
120649
|
-
return;
|
|
120650
|
-
}
|
|
120651
|
-
}
|
|
120652
|
-
signalRouter.touchActivity(messages);
|
|
120653
|
-
if (attempt > 0) {
|
|
120654
|
-
signalRouter.recordSuccessfulEscalation(messages, currentTier);
|
|
120655
|
-
}
|
|
120656
|
-
});
|
|
120657
|
-
return response;
|
|
120658
|
-
}
|
|
120659
|
-
const fullText = await collectPiStreamText(piStreamHandle, detector, detectionState);
|
|
120659
|
+
const assistantMsg = await collectPiStreamWithSignalDetection(piStreamHandle, detector, detectionState);
|
|
120660
120660
|
if (detectionState.signalDetected) {
|
|
120661
|
+
abortCtrl.abort();
|
|
120661
120662
|
const nextTier = signalRouter.handleEscalation(messages, currentTier);
|
|
120662
120663
|
if (nextTier !== null) {
|
|
120663
|
-
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected
|
|
120664
|
+
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected)`);
|
|
120664
120665
|
currentTier = nextTier;
|
|
120665
120666
|
continue;
|
|
120666
120667
|
}
|
|
@@ -120669,7 +120670,15 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120669
120670
|
if (attempt > 0) {
|
|
120670
120671
|
signalRouter.recordSuccessfulEscalation(messages, currentTier);
|
|
120671
120672
|
}
|
|
120672
|
-
|
|
120673
|
+
if (wantsStream) {
|
|
120674
|
+
const sseBody = buildSseForApiType(apiType, replayAssistantMessageAsEvents(assistantMsg));
|
|
120675
|
+
return new Response(sseBody, {
|
|
120676
|
+
status: 200,
|
|
120677
|
+
headers: { "content-type": "text/event-stream" }
|
|
120678
|
+
});
|
|
120679
|
+
}
|
|
120680
|
+
const jsonBody = buildJsonForApiType(apiType, assistantMsg);
|
|
120681
|
+
return new Response(JSON.stringify(jsonBody), {
|
|
120673
120682
|
status: 200,
|
|
120674
120683
|
headers: { "content-type": "application/json" }
|
|
120675
120684
|
});
|
|
@@ -120915,164 +120924,63 @@ async function yieldPiAiResponse(piStreamHandle, apiType, wantsStream) {
|
|
|
120915
120924
|
}
|
|
120916
120925
|
throw new Error(`Unsupported pi-ai apiType: ${apiType}`);
|
|
120917
120926
|
}
|
|
120918
|
-
function
|
|
120919
|
-
|
|
120920
|
-
|
|
120921
|
-
|
|
120922
|
-
|
|
120923
|
-
|
|
120924
|
-
|
|
120925
|
-
|
|
120926
|
-
|
|
120927
|
-
|
|
120928
|
-
|
|
120929
|
-
|
|
120930
|
-
|
|
120931
|
-
|
|
120932
|
-
|
|
120933
|
-
|
|
120934
|
-
|
|
120935
|
-
|
|
120936
|
-
|
|
120937
|
-
|
|
120938
|
-
|
|
120939
|
-
|
|
120940
|
-
|
|
120941
|
-
|
|
120942
|
-
|
|
120943
|
-
|
|
120944
|
-
|
|
120945
|
-
|
|
120946
|
-
|
|
120947
|
-
|
|
120948
|
-
|
|
120949
|
-
|
|
120950
|
-
|
|
120951
|
-
|
|
120952
|
-
} else if (event.type === "text_start") {
|
|
120953
|
-
ensureMessageStart(event.partial.model || "");
|
|
120954
|
-
openBlocks.set(event.contentIndex, "text");
|
|
120955
|
-
controller.enqueue(sseFrame2("content_block_start", {
|
|
120956
|
-
type: "content_block_start",
|
|
120957
|
-
index: event.contentIndex,
|
|
120958
|
-
content_block: { type: "text", text: "" }
|
|
120959
|
-
}));
|
|
120960
|
-
} else if (event.type === "text_delta") {
|
|
120961
|
-
if (openBlocks.get(event.contentIndex) !== "text") {
|
|
120962
|
-
ensureMessageStart(event.partial.model || "");
|
|
120963
|
-
openBlocks.set(event.contentIndex, "text");
|
|
120964
|
-
controller.enqueue(sseFrame2("content_block_start", {
|
|
120965
|
-
type: "content_block_start",
|
|
120966
|
-
index: event.contentIndex,
|
|
120967
|
-
content_block: { type: "text", text: "" }
|
|
120968
|
-
}));
|
|
120969
|
-
}
|
|
120970
|
-
controller.enqueue(sseFrame2("content_block_delta", {
|
|
120971
|
-
type: "content_block_delta",
|
|
120972
|
-
index: event.contentIndex,
|
|
120973
|
-
delta: { type: "text_delta", text: event.delta }
|
|
120974
|
-
}));
|
|
120975
|
-
} else if (event.type === "text_end") {
|
|
120976
|
-
if (openBlocks.get(event.contentIndex) === "text") {
|
|
120977
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
120978
|
-
type: "content_block_stop",
|
|
120979
|
-
index: event.contentIndex
|
|
120980
|
-
}));
|
|
120981
|
-
openBlocks.delete(event.contentIndex);
|
|
120982
|
-
}
|
|
120983
|
-
} else if (event.type === "done") {
|
|
120984
|
-
for (const [idx] of openBlocks) {
|
|
120985
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
120986
|
-
type: "content_block_stop",
|
|
120987
|
-
index: idx
|
|
120988
|
-
}));
|
|
120989
|
-
}
|
|
120990
|
-
openBlocks.clear();
|
|
120991
|
-
controller.enqueue(sseFrame2("message_delta", {
|
|
120992
|
-
type: "message_delta",
|
|
120993
|
-
delta: { stop_reason: "end_turn", stop_sequence: null },
|
|
120994
|
-
usage: { output_tokens: event.message.usage?.output ?? 0 }
|
|
120995
|
-
}));
|
|
120996
|
-
controller.enqueue(sseFrame2("message_stop", { type: "message_stop" }));
|
|
120997
|
-
} else if (event.type === "error") {
|
|
120998
|
-
for (const [idx] of openBlocks) {
|
|
120999
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
121000
|
-
type: "content_block_stop",
|
|
121001
|
-
index: idx
|
|
121002
|
-
}));
|
|
121003
|
-
}
|
|
121004
|
-
openBlocks.clear();
|
|
121005
|
-
controller.enqueue(sseFrame2("error", {
|
|
121006
|
-
type: "error",
|
|
121007
|
-
error: {
|
|
121008
|
-
type: "api_error",
|
|
121009
|
-
message: event.error?.errorMessage ?? "Unknown error"
|
|
121010
|
-
}
|
|
121011
|
-
}));
|
|
121012
|
-
}
|
|
121013
|
-
}
|
|
121014
|
-
controller.close();
|
|
121015
|
-
} catch (err) {
|
|
121016
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
121017
|
-
controller.enqueue(sseFrame2("error", {
|
|
121018
|
-
type: "error",
|
|
121019
|
-
error: { type: "api_error", message: msg }
|
|
121020
|
-
}));
|
|
121021
|
-
controller.close();
|
|
120927
|
+
function buildSseForApiType(apiType, gen) {
|
|
120928
|
+
if (apiType === "anthropic-messages")
|
|
120929
|
+
return piStreamToAnthropicSse(gen);
|
|
120930
|
+
if (apiType === "openai-completions")
|
|
120931
|
+
return piStreamToOpenAiCompletionsSse(gen);
|
|
120932
|
+
if (apiType === "openai-responses")
|
|
120933
|
+
return piStreamToOpenAiResponsesSse(gen);
|
|
120934
|
+
if (apiType === "google-generative-ai")
|
|
120935
|
+
return piStreamToGoogleSse(gen);
|
|
120936
|
+
return piStreamToAnthropicSse(gen);
|
|
120937
|
+
}
|
|
120938
|
+
function buildJsonForApiType(apiType, msg) {
|
|
120939
|
+
if (apiType === "anthropic-messages")
|
|
120940
|
+
return anthropicMessageFromAssistant(msg);
|
|
120941
|
+
if (apiType === "openai-completions")
|
|
120942
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120943
|
+
if (apiType === "openai-responses")
|
|
120944
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120945
|
+
if (apiType === "google-generative-ai")
|
|
120946
|
+
return googleMessageFromAssistant(msg);
|
|
120947
|
+
return anthropicMessageFromAssistant(msg);
|
|
120948
|
+
}
|
|
120949
|
+
async function drainSignalGenerator(gen) {
|
|
120950
|
+
for await (const _event of gen) {}
|
|
120951
|
+
}
|
|
120952
|
+
async function* replayAssistantMessageAsEvents(msg) {
|
|
120953
|
+
const partial = msg;
|
|
120954
|
+
yield { type: "start", partial };
|
|
120955
|
+
for (let i2 = 0;i2 < msg.content.length; i2++) {
|
|
120956
|
+
const block = msg.content[i2];
|
|
120957
|
+
if (block.type === "text") {
|
|
120958
|
+
yield { type: "text_start", contentIndex: i2, partial };
|
|
120959
|
+
if (block.text.length > 0) {
|
|
120960
|
+
yield { type: "text_delta", contentIndex: i2, delta: block.text, partial };
|
|
121022
120961
|
}
|
|
121023
|
-
|
|
121024
|
-
|
|
121025
|
-
}
|
|
121026
|
-
|
|
121027
|
-
|
|
121028
|
-
|
|
121029
|
-
|
|
121030
|
-
|
|
121031
|
-
|
|
121032
|
-
|
|
121033
|
-
|
|
121034
|
-
|
|
121035
|
-
|
|
121036
|
-
|
|
121037
|
-
const STOP_REASON_MAP2 = {
|
|
121038
|
-
stop: "end_turn",
|
|
121039
|
-
length: "max_tokens",
|
|
121040
|
-
toolUse: "tool_use",
|
|
121041
|
-
error: "end_turn",
|
|
121042
|
-
aborted: "end_turn"
|
|
121043
|
-
};
|
|
121044
|
-
const blocks = [];
|
|
121045
|
-
for (const c of msg.content) {
|
|
121046
|
-
if (c.type === "text") {
|
|
121047
|
-
blocks.push({ type: "text", text: c.text });
|
|
121048
|
-
} else if (c.type === "thinking") {
|
|
121049
|
-
blocks.push({
|
|
121050
|
-
type: "thinking",
|
|
121051
|
-
thinking: c.thinking,
|
|
121052
|
-
...c.thinkingSignature ? { signature: c.thinkingSignature } : {}
|
|
121053
|
-
});
|
|
121054
|
-
} else if (c.type === "toolCall") {
|
|
121055
|
-
blocks.push({
|
|
121056
|
-
type: "tool_use",
|
|
121057
|
-
id: c.id,
|
|
121058
|
-
name: c.name,
|
|
121059
|
-
input: c.arguments ?? {}
|
|
121060
|
-
});
|
|
120962
|
+
yield { type: "text_end", contentIndex: i2, content: block.text, partial };
|
|
120963
|
+
} else if (block.type === "thinking") {
|
|
120964
|
+
yield { type: "thinking_start", contentIndex: i2, partial };
|
|
120965
|
+
if (block.thinking.length > 0) {
|
|
120966
|
+
yield { type: "thinking_delta", contentIndex: i2, delta: block.thinking, partial };
|
|
120967
|
+
}
|
|
120968
|
+
yield { type: "thinking_end", contentIndex: i2, content: block.thinking, partial };
|
|
120969
|
+
} else if (block.type === "toolCall") {
|
|
120970
|
+
yield { type: "toolcall_start", contentIndex: i2, partial };
|
|
120971
|
+
const argsJson = JSON.stringify(block.arguments ?? {});
|
|
120972
|
+
if (argsJson.length > 0 && argsJson !== "{}") {
|
|
120973
|
+
yield { type: "toolcall_delta", contentIndex: i2, delta: argsJson, partial };
|
|
120974
|
+
}
|
|
120975
|
+
yield { type: "toolcall_end", contentIndex: i2, toolCall: block, partial };
|
|
121061
120976
|
}
|
|
121062
120977
|
}
|
|
121063
|
-
|
|
121064
|
-
|
|
121065
|
-
|
|
121066
|
-
|
|
121067
|
-
|
|
121068
|
-
|
|
121069
|
-
stop_reason: STOP_REASON_MAP2[msg.stopReason] ?? "end_turn",
|
|
121070
|
-
stop_sequence: null,
|
|
121071
|
-
usage: {
|
|
121072
|
-
input_tokens: msg.usage?.input ?? 0,
|
|
121073
|
-
output_tokens: msg.usage?.output ?? 0
|
|
121074
|
-
}
|
|
121075
|
-
};
|
|
120978
|
+
yield { type: "done", reason: msg.stopReason, message: msg };
|
|
120979
|
+
}
|
|
120980
|
+
async function collectPiStreamWithSignalDetection(piStreamHandle, detector, state) {
|
|
120981
|
+
const signalGen = detectSignalInStream(piStreamHandle, detector, state, () => {});
|
|
120982
|
+
await drainSignalGenerator(signalGen);
|
|
120983
|
+
return await piStreamHandle.result();
|
|
121076
120984
|
}
|
|
121077
120985
|
var ROUTE_MAPPINGS = [
|
|
121078
120986
|
{ apiType: "anthropic-messages", key: "/v1/messages" },
|
package/dist/index.cjs
CHANGED
|
@@ -112238,7 +112238,7 @@ __export(exports_src2, {
|
|
|
112238
112238
|
module.exports = __toCommonJS(exports_src2);
|
|
112239
112239
|
|
|
112240
112240
|
// src/proxy/router.ts
|
|
112241
|
-
var VERSION = process.env.npm_package_version ?? "0.3.
|
|
112241
|
+
var VERSION = process.env.npm_package_version ?? "0.3.14";
|
|
112242
112242
|
function jsonResponse(body, status = 200) {
|
|
112243
112243
|
return new Response(JSON.stringify(body), {
|
|
112244
112244
|
status,
|
|
@@ -115109,6 +115109,9 @@ function djb2Hash(text) {
|
|
|
115109
115109
|
return (hash >>> 0).toString(16);
|
|
115110
115110
|
}
|
|
115111
115111
|
function extractText(content) {
|
|
115112
|
+
if (content === null || content === undefined) {
|
|
115113
|
+
return "";
|
|
115114
|
+
}
|
|
115112
115115
|
if (typeof content === "string") {
|
|
115113
115116
|
return content.slice(0, 200);
|
|
115114
115117
|
}
|
|
@@ -115121,6 +115124,9 @@ function extractText(content) {
|
|
|
115121
115124
|
return concatenated.slice(0, 200);
|
|
115122
115125
|
}
|
|
115123
115126
|
function contentLength(content) {
|
|
115127
|
+
if (content === null || content === undefined) {
|
|
115128
|
+
return 0;
|
|
115129
|
+
}
|
|
115124
115130
|
if (typeof content === "string") {
|
|
115125
115131
|
return content.length;
|
|
115126
115132
|
}
|
|
@@ -115196,7 +115202,7 @@ class EscalationMemory {
|
|
|
115196
115202
|
}
|
|
115197
115203
|
|
|
115198
115204
|
// src/routing/instruction-injector.ts
|
|
115199
|
-
var INJECT_FOR_TIERS = new Set(["LIGHT"]);
|
|
115205
|
+
var INJECT_FOR_TIERS = new Set(["LIGHT", "MEDIUM"]);
|
|
115200
115206
|
var ESCALATION_INSTRUCTION = `If you cannot handle this request fully (due to complexity, missing context, or capability limits), output EXACTLY the following marker with no other text on that line: ${ESCALATE_SIGNAL}
|
|
115201
115207
|
Do not explain. Do not ask permission. Just emit the marker and stop.`;
|
|
115202
115208
|
function injectEscalationInstruction(messages) {
|
|
@@ -115212,6 +115218,12 @@ function injectEscalationInstruction(messages) {
|
|
|
115212
115218
|
...rest
|
|
115213
115219
|
];
|
|
115214
115220
|
}
|
|
115221
|
+
if (first.content === null) {
|
|
115222
|
+
return [
|
|
115223
|
+
{ role: "system", content: ESCALATION_INSTRUCTION },
|
|
115224
|
+
...rest
|
|
115225
|
+
];
|
|
115226
|
+
}
|
|
115215
115227
|
if (typeof first.content === "string") {
|
|
115216
115228
|
return [
|
|
115217
115229
|
{ role: "system", content: first.content + `
|
|
@@ -119748,8 +119760,7 @@ function piStreamToAnthropicSse(piStream) {
|
|
|
119748
119760
|
}
|
|
119749
119761
|
});
|
|
119750
119762
|
}
|
|
119751
|
-
|
|
119752
|
-
const msg = await piStream.result();
|
|
119763
|
+
function anthropicMessageFromAssistant(msg) {
|
|
119753
119764
|
if ((msg.stopReason === "error" || msg.stopReason === "aborted") && msg.errorMessage) {
|
|
119754
119765
|
console.error(`[clawmux] pi-ai upstream error (${msg.stopReason}): ${msg.errorMessage}`);
|
|
119755
119766
|
}
|
|
@@ -119787,6 +119798,10 @@ async function piStreamToAnthropicJson(piStream) {
|
|
|
119787
119798
|
...msg.errorMessage ? { error_message: msg.errorMessage } : {}
|
|
119788
119799
|
};
|
|
119789
119800
|
}
|
|
119801
|
+
async function piStreamToAnthropicJson(piStream) {
|
|
119802
|
+
const msg = await piStream.result();
|
|
119803
|
+
return anthropicMessageFromAssistant(msg);
|
|
119804
|
+
}
|
|
119790
119805
|
|
|
119791
119806
|
// src/pi-bridge/event-to-openai-completions.ts
|
|
119792
119807
|
var encoder3 = new TextEncoder;
|
|
@@ -120010,8 +120025,7 @@ function piStreamToOpenAiCompletionsSse(piStream) {
|
|
|
120010
120025
|
}
|
|
120011
120026
|
});
|
|
120012
120027
|
}
|
|
120013
|
-
|
|
120014
|
-
const msg = await piStream.result();
|
|
120028
|
+
function openAiCompletionsMessageFromAssistant(msg) {
|
|
120015
120029
|
let textContent = "";
|
|
120016
120030
|
const toolCalls = [];
|
|
120017
120031
|
let reasoning = "";
|
|
@@ -120061,6 +120075,10 @@ async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
|
120061
120075
|
}
|
|
120062
120076
|
};
|
|
120063
120077
|
}
|
|
120078
|
+
async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
120079
|
+
const msg = await piStream.result();
|
|
120080
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120081
|
+
}
|
|
120064
120082
|
|
|
120065
120083
|
// src/pi-bridge/event-to-openai-responses.ts
|
|
120066
120084
|
var encoder4 = new TextEncoder;
|
|
@@ -120223,8 +120241,7 @@ function piStreamToOpenAiResponsesSse(piStream) {
|
|
|
120223
120241
|
}
|
|
120224
120242
|
});
|
|
120225
120243
|
}
|
|
120226
|
-
|
|
120227
|
-
const msg = await piStream.result();
|
|
120244
|
+
function openAiResponsesMessageFromAssistant(msg) {
|
|
120228
120245
|
const output = [];
|
|
120229
120246
|
for (const c of msg.content) {
|
|
120230
120247
|
if (c.type === "text") {
|
|
@@ -120265,6 +120282,10 @@ async function piStreamToOpenAiResponsesJson(piStream) {
|
|
|
120265
120282
|
}
|
|
120266
120283
|
};
|
|
120267
120284
|
}
|
|
120285
|
+
async function piStreamToOpenAiResponsesJson(piStream) {
|
|
120286
|
+
const msg = await piStream.result();
|
|
120287
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120288
|
+
}
|
|
120268
120289
|
|
|
120269
120290
|
// src/pi-bridge/event-to-google.ts
|
|
120270
120291
|
var encoder5 = new TextEncoder;
|
|
@@ -120381,8 +120402,7 @@ function piStreamToGoogleSse(piStream) {
|
|
|
120381
120402
|
}
|
|
120382
120403
|
});
|
|
120383
120404
|
}
|
|
120384
|
-
|
|
120385
|
-
const msg = await piStream.result();
|
|
120405
|
+
function googleMessageFromAssistant(msg) {
|
|
120386
120406
|
const parts = [];
|
|
120387
120407
|
for (const c of msg.content) {
|
|
120388
120408
|
if (c.type === "text") {
|
|
@@ -120414,6 +120434,10 @@ async function piStreamToGoogleJson(piStream) {
|
|
|
120414
120434
|
modelVersion: msg.model || ""
|
|
120415
120435
|
};
|
|
120416
120436
|
}
|
|
120437
|
+
async function piStreamToGoogleJson(piStream) {
|
|
120438
|
+
const msg = await piStream.result();
|
|
120439
|
+
return googleMessageFromAssistant(msg);
|
|
120440
|
+
}
|
|
120417
120441
|
|
|
120418
120442
|
// src/proxy/pipeline.ts
|
|
120419
120443
|
registerAdapter(new AnthropicAdapter);
|
|
@@ -120650,35 +120674,12 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120650
120674
|
}
|
|
120651
120675
|
const detector = signalRouter.createSignalDetector();
|
|
120652
120676
|
const detectionState = createSignalDetectionState();
|
|
120653
|
-
|
|
120654
|
-
const signalGen = detectSignalInStream(piStreamHandle, detector, detectionState, () => {});
|
|
120655
|
-
const sseBody = piStreamToAnthropicSseFromGenerator(signalGen);
|
|
120656
|
-
const response = new Response(sseBody, {
|
|
120657
|
-
status: 200,
|
|
120658
|
-
headers: { "content-type": "text/event-stream" }
|
|
120659
|
-
});
|
|
120660
|
-
response.clone().text().then(() => {
|
|
120661
|
-
if (detectionState.signalDetected) {
|
|
120662
|
-
abortCtrl.abort();
|
|
120663
|
-
const nextTier = signalRouter.handleEscalation(messages, currentTier);
|
|
120664
|
-
if (nextTier !== null) {
|
|
120665
|
-
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected)`);
|
|
120666
|
-
currentTier = nextTier;
|
|
120667
|
-
return;
|
|
120668
|
-
}
|
|
120669
|
-
}
|
|
120670
|
-
signalRouter.touchActivity(messages);
|
|
120671
|
-
if (attempt > 0) {
|
|
120672
|
-
signalRouter.recordSuccessfulEscalation(messages, currentTier);
|
|
120673
|
-
}
|
|
120674
|
-
});
|
|
120675
|
-
return response;
|
|
120676
|
-
}
|
|
120677
|
-
const fullText = await collectPiStreamText(piStreamHandle, detector, detectionState);
|
|
120677
|
+
const assistantMsg = await collectPiStreamWithSignalDetection(piStreamHandle, detector, detectionState);
|
|
120678
120678
|
if (detectionState.signalDetected) {
|
|
120679
|
+
abortCtrl.abort();
|
|
120679
120680
|
const nextTier = signalRouter.handleEscalation(messages, currentTier);
|
|
120680
120681
|
if (nextTier !== null) {
|
|
120681
|
-
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected
|
|
120682
|
+
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected)`);
|
|
120682
120683
|
currentTier = nextTier;
|
|
120683
120684
|
continue;
|
|
120684
120685
|
}
|
|
@@ -120687,7 +120688,15 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120687
120688
|
if (attempt > 0) {
|
|
120688
120689
|
signalRouter.recordSuccessfulEscalation(messages, currentTier);
|
|
120689
120690
|
}
|
|
120690
|
-
|
|
120691
|
+
if (wantsStream) {
|
|
120692
|
+
const sseBody = buildSseForApiType(apiType, replayAssistantMessageAsEvents(assistantMsg));
|
|
120693
|
+
return new Response(sseBody, {
|
|
120694
|
+
status: 200,
|
|
120695
|
+
headers: { "content-type": "text/event-stream" }
|
|
120696
|
+
});
|
|
120697
|
+
}
|
|
120698
|
+
const jsonBody = buildJsonForApiType(apiType, assistantMsg);
|
|
120699
|
+
return new Response(JSON.stringify(jsonBody), {
|
|
120691
120700
|
status: 200,
|
|
120692
120701
|
headers: { "content-type": "application/json" }
|
|
120693
120702
|
});
|
|
@@ -120933,164 +120942,63 @@ async function yieldPiAiResponse(piStreamHandle, apiType, wantsStream) {
|
|
|
120933
120942
|
}
|
|
120934
120943
|
throw new Error(`Unsupported pi-ai apiType: ${apiType}`);
|
|
120935
120944
|
}
|
|
120936
|
-
function
|
|
120937
|
-
|
|
120938
|
-
|
|
120939
|
-
|
|
120940
|
-
|
|
120941
|
-
|
|
120942
|
-
|
|
120943
|
-
|
|
120944
|
-
|
|
120945
|
-
|
|
120946
|
-
|
|
120947
|
-
|
|
120948
|
-
|
|
120949
|
-
|
|
120950
|
-
|
|
120951
|
-
|
|
120952
|
-
|
|
120953
|
-
|
|
120954
|
-
|
|
120955
|
-
|
|
120956
|
-
|
|
120957
|
-
|
|
120958
|
-
|
|
120959
|
-
|
|
120960
|
-
|
|
120961
|
-
|
|
120962
|
-
|
|
120963
|
-
|
|
120964
|
-
|
|
120965
|
-
|
|
120966
|
-
|
|
120967
|
-
|
|
120968
|
-
|
|
120969
|
-
|
|
120970
|
-
} else if (event.type === "text_start") {
|
|
120971
|
-
ensureMessageStart(event.partial.model || "");
|
|
120972
|
-
openBlocks.set(event.contentIndex, "text");
|
|
120973
|
-
controller.enqueue(sseFrame2("content_block_start", {
|
|
120974
|
-
type: "content_block_start",
|
|
120975
|
-
index: event.contentIndex,
|
|
120976
|
-
content_block: { type: "text", text: "" }
|
|
120977
|
-
}));
|
|
120978
|
-
} else if (event.type === "text_delta") {
|
|
120979
|
-
if (openBlocks.get(event.contentIndex) !== "text") {
|
|
120980
|
-
ensureMessageStart(event.partial.model || "");
|
|
120981
|
-
openBlocks.set(event.contentIndex, "text");
|
|
120982
|
-
controller.enqueue(sseFrame2("content_block_start", {
|
|
120983
|
-
type: "content_block_start",
|
|
120984
|
-
index: event.contentIndex,
|
|
120985
|
-
content_block: { type: "text", text: "" }
|
|
120986
|
-
}));
|
|
120987
|
-
}
|
|
120988
|
-
controller.enqueue(sseFrame2("content_block_delta", {
|
|
120989
|
-
type: "content_block_delta",
|
|
120990
|
-
index: event.contentIndex,
|
|
120991
|
-
delta: { type: "text_delta", text: event.delta }
|
|
120992
|
-
}));
|
|
120993
|
-
} else if (event.type === "text_end") {
|
|
120994
|
-
if (openBlocks.get(event.contentIndex) === "text") {
|
|
120995
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
120996
|
-
type: "content_block_stop",
|
|
120997
|
-
index: event.contentIndex
|
|
120998
|
-
}));
|
|
120999
|
-
openBlocks.delete(event.contentIndex);
|
|
121000
|
-
}
|
|
121001
|
-
} else if (event.type === "done") {
|
|
121002
|
-
for (const [idx] of openBlocks) {
|
|
121003
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
121004
|
-
type: "content_block_stop",
|
|
121005
|
-
index: idx
|
|
121006
|
-
}));
|
|
121007
|
-
}
|
|
121008
|
-
openBlocks.clear();
|
|
121009
|
-
controller.enqueue(sseFrame2("message_delta", {
|
|
121010
|
-
type: "message_delta",
|
|
121011
|
-
delta: { stop_reason: "end_turn", stop_sequence: null },
|
|
121012
|
-
usage: { output_tokens: event.message.usage?.output ?? 0 }
|
|
121013
|
-
}));
|
|
121014
|
-
controller.enqueue(sseFrame2("message_stop", { type: "message_stop" }));
|
|
121015
|
-
} else if (event.type === "error") {
|
|
121016
|
-
for (const [idx] of openBlocks) {
|
|
121017
|
-
controller.enqueue(sseFrame2("content_block_stop", {
|
|
121018
|
-
type: "content_block_stop",
|
|
121019
|
-
index: idx
|
|
121020
|
-
}));
|
|
121021
|
-
}
|
|
121022
|
-
openBlocks.clear();
|
|
121023
|
-
controller.enqueue(sseFrame2("error", {
|
|
121024
|
-
type: "error",
|
|
121025
|
-
error: {
|
|
121026
|
-
type: "api_error",
|
|
121027
|
-
message: event.error?.errorMessage ?? "Unknown error"
|
|
121028
|
-
}
|
|
121029
|
-
}));
|
|
121030
|
-
}
|
|
121031
|
-
}
|
|
121032
|
-
controller.close();
|
|
121033
|
-
} catch (err) {
|
|
121034
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
121035
|
-
controller.enqueue(sseFrame2("error", {
|
|
121036
|
-
type: "error",
|
|
121037
|
-
error: { type: "api_error", message: msg }
|
|
121038
|
-
}));
|
|
121039
|
-
controller.close();
|
|
120945
|
+
function buildSseForApiType(apiType, gen) {
|
|
120946
|
+
if (apiType === "anthropic-messages")
|
|
120947
|
+
return piStreamToAnthropicSse(gen);
|
|
120948
|
+
if (apiType === "openai-completions")
|
|
120949
|
+
return piStreamToOpenAiCompletionsSse(gen);
|
|
120950
|
+
if (apiType === "openai-responses")
|
|
120951
|
+
return piStreamToOpenAiResponsesSse(gen);
|
|
120952
|
+
if (apiType === "google-generative-ai")
|
|
120953
|
+
return piStreamToGoogleSse(gen);
|
|
120954
|
+
return piStreamToAnthropicSse(gen);
|
|
120955
|
+
}
|
|
120956
|
+
function buildJsonForApiType(apiType, msg) {
|
|
120957
|
+
if (apiType === "anthropic-messages")
|
|
120958
|
+
return anthropicMessageFromAssistant(msg);
|
|
120959
|
+
if (apiType === "openai-completions")
|
|
120960
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120961
|
+
if (apiType === "openai-responses")
|
|
120962
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120963
|
+
if (apiType === "google-generative-ai")
|
|
120964
|
+
return googleMessageFromAssistant(msg);
|
|
120965
|
+
return anthropicMessageFromAssistant(msg);
|
|
120966
|
+
}
|
|
120967
|
+
async function drainSignalGenerator(gen) {
|
|
120968
|
+
for await (const _event of gen) {}
|
|
120969
|
+
}
|
|
120970
|
+
async function* replayAssistantMessageAsEvents(msg) {
|
|
120971
|
+
const partial = msg;
|
|
120972
|
+
yield { type: "start", partial };
|
|
120973
|
+
for (let i2 = 0;i2 < msg.content.length; i2++) {
|
|
120974
|
+
const block = msg.content[i2];
|
|
120975
|
+
if (block.type === "text") {
|
|
120976
|
+
yield { type: "text_start", contentIndex: i2, partial };
|
|
120977
|
+
if (block.text.length > 0) {
|
|
120978
|
+
yield { type: "text_delta", contentIndex: i2, delta: block.text, partial };
|
|
121040
120979
|
}
|
|
121041
|
-
|
|
121042
|
-
|
|
121043
|
-
}
|
|
121044
|
-
|
|
121045
|
-
|
|
121046
|
-
|
|
121047
|
-
|
|
121048
|
-
|
|
121049
|
-
|
|
121050
|
-
|
|
121051
|
-
|
|
121052
|
-
|
|
121053
|
-
|
|
121054
|
-
|
|
121055
|
-
const STOP_REASON_MAP2 = {
|
|
121056
|
-
stop: "end_turn",
|
|
121057
|
-
length: "max_tokens",
|
|
121058
|
-
toolUse: "tool_use",
|
|
121059
|
-
error: "end_turn",
|
|
121060
|
-
aborted: "end_turn"
|
|
121061
|
-
};
|
|
121062
|
-
const blocks = [];
|
|
121063
|
-
for (const c of msg.content) {
|
|
121064
|
-
if (c.type === "text") {
|
|
121065
|
-
blocks.push({ type: "text", text: c.text });
|
|
121066
|
-
} else if (c.type === "thinking") {
|
|
121067
|
-
blocks.push({
|
|
121068
|
-
type: "thinking",
|
|
121069
|
-
thinking: c.thinking,
|
|
121070
|
-
...c.thinkingSignature ? { signature: c.thinkingSignature } : {}
|
|
121071
|
-
});
|
|
121072
|
-
} else if (c.type === "toolCall") {
|
|
121073
|
-
blocks.push({
|
|
121074
|
-
type: "tool_use",
|
|
121075
|
-
id: c.id,
|
|
121076
|
-
name: c.name,
|
|
121077
|
-
input: c.arguments ?? {}
|
|
121078
|
-
});
|
|
120980
|
+
yield { type: "text_end", contentIndex: i2, content: block.text, partial };
|
|
120981
|
+
} else if (block.type === "thinking") {
|
|
120982
|
+
yield { type: "thinking_start", contentIndex: i2, partial };
|
|
120983
|
+
if (block.thinking.length > 0) {
|
|
120984
|
+
yield { type: "thinking_delta", contentIndex: i2, delta: block.thinking, partial };
|
|
120985
|
+
}
|
|
120986
|
+
yield { type: "thinking_end", contentIndex: i2, content: block.thinking, partial };
|
|
120987
|
+
} else if (block.type === "toolCall") {
|
|
120988
|
+
yield { type: "toolcall_start", contentIndex: i2, partial };
|
|
120989
|
+
const argsJson = JSON.stringify(block.arguments ?? {});
|
|
120990
|
+
if (argsJson.length > 0 && argsJson !== "{}") {
|
|
120991
|
+
yield { type: "toolcall_delta", contentIndex: i2, delta: argsJson, partial };
|
|
120992
|
+
}
|
|
120993
|
+
yield { type: "toolcall_end", contentIndex: i2, toolCall: block, partial };
|
|
121079
120994
|
}
|
|
121080
120995
|
}
|
|
121081
|
-
|
|
121082
|
-
|
|
121083
|
-
|
|
121084
|
-
|
|
121085
|
-
|
|
121086
|
-
|
|
121087
|
-
stop_reason: STOP_REASON_MAP2[msg.stopReason] ?? "end_turn",
|
|
121088
|
-
stop_sequence: null,
|
|
121089
|
-
usage: {
|
|
121090
|
-
input_tokens: msg.usage?.input ?? 0,
|
|
121091
|
-
output_tokens: msg.usage?.output ?? 0
|
|
121092
|
-
}
|
|
121093
|
-
};
|
|
120996
|
+
yield { type: "done", reason: msg.stopReason, message: msg };
|
|
120997
|
+
}
|
|
120998
|
+
async function collectPiStreamWithSignalDetection(piStreamHandle, detector, state) {
|
|
120999
|
+
const signalGen = detectSignalInStream(piStreamHandle, detector, state, () => {});
|
|
121000
|
+
await drainSignalGenerator(signalGen);
|
|
121001
|
+
return await piStreamHandle.result();
|
|
121094
121002
|
}
|
|
121095
121003
|
var ROUTE_MAPPINGS = [
|
|
121096
121004
|
{ apiType: "anthropic-messages", key: "/v1/messages" },
|