clawmux 0.3.13 → 0.3.15
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 +3 -1
- package/dist/cli.cjs +153 -202
- package/dist/index.cjs +100 -192
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,8 @@ ClawMux registers as a single provider `clawmux` in OpenClaw with model `auto`.
|
|
|
83
83
|
openclaw provider clawmux
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
`clawmux init` manages the `clawmux` provider entry in `openclaw.json` (and the per-agent `models.json` caches) for you. It sets `api` to match your MEDIUM tier's API format and computes the correct `baseUrl` from that — `http://localhost:<port>/v1` for OpenAI-style APIs (where the upstream SDK appends `/chat/completions` or `/responses`) and `http://localhost:<port>` for everything else. Do not hand-edit these fields; rerun `clawmux init` after changing the MEDIUM model in `~/.openclaw/clawmux.json`.
|
|
87
|
+
|
|
86
88
|
## How It Works
|
|
87
89
|
|
|
88
90
|
```
|
|
@@ -109,7 +111,7 @@ ClawMux resolves each model's context window using this priority chain:
|
|
|
109
111
|
|
|
110
112
|
1. **~/.openclaw/clawmux.json** `routing.contextWindows` — explicit per-model override
|
|
111
113
|
2. **openclaw.json** `models.providers[provider].models[].contextWindow` — user config
|
|
112
|
-
3. **OpenClaw built-in catalog** — pi-ai model database (
|
|
114
|
+
3. **OpenClaw built-in catalog** — pi-ai model database (830+ models)
|
|
113
115
|
4. **Default: 200,000 tokens**
|
|
114
116
|
|
|
115
117
|
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
|
@@ -3,6 +3,7 @@ var __create = Object.create;
|
|
|
3
3
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
8
|
function __accessProp(key) {
|
|
8
9
|
return this[key];
|
|
@@ -29,6 +30,23 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
29
30
|
cache.set(mod, to);
|
|
30
31
|
return to;
|
|
31
32
|
};
|
|
33
|
+
var __toCommonJS = (from) => {
|
|
34
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
35
|
+
if (entry)
|
|
36
|
+
return entry;
|
|
37
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
38
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
+
for (var key of __getOwnPropNames(from))
|
|
40
|
+
if (!__hasOwnProp.call(entry, key))
|
|
41
|
+
__defProp(entry, key, {
|
|
42
|
+
get: __accessProp.bind(from, key),
|
|
43
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
__moduleCache.set(from, entry);
|
|
47
|
+
return entry;
|
|
48
|
+
};
|
|
49
|
+
var __moduleCache;
|
|
32
50
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
51
|
var __returnValue = (v) => v;
|
|
34
52
|
function __exportSetter(name, newValue) {
|
|
@@ -112214,13 +112232,18 @@ var require_dist4 = __commonJS((exports2, module2) => {
|
|
|
112214
112232
|
});
|
|
112215
112233
|
|
|
112216
112234
|
// src/cli.ts
|
|
112235
|
+
var exports_cli = {};
|
|
112236
|
+
__export(exports_cli, {
|
|
112237
|
+
resolveProviderBaseUrl: () => resolveProviderBaseUrl
|
|
112238
|
+
});
|
|
112239
|
+
module.exports = __toCommonJS(exports_cli);
|
|
112217
112240
|
var import_promises8 = require("node:fs/promises");
|
|
112218
112241
|
var import_node_path7 = require("node:path");
|
|
112219
112242
|
var import_node_child_process = require("node:child_process");
|
|
112220
112243
|
var import_node_os2 = require("node:os");
|
|
112221
112244
|
|
|
112222
112245
|
// src/proxy/router.ts
|
|
112223
|
-
var VERSION = process.env.npm_package_version ?? "0.3.
|
|
112246
|
+
var VERSION = process.env.npm_package_version ?? "0.3.15";
|
|
112224
112247
|
function jsonResponse(body, status = 200) {
|
|
112225
112248
|
return new Response(JSON.stringify(body), {
|
|
112226
112249
|
status,
|
|
@@ -115091,6 +115114,9 @@ function djb2Hash(text) {
|
|
|
115091
115114
|
return (hash >>> 0).toString(16);
|
|
115092
115115
|
}
|
|
115093
115116
|
function extractText(content) {
|
|
115117
|
+
if (content === null || content === undefined) {
|
|
115118
|
+
return "";
|
|
115119
|
+
}
|
|
115094
115120
|
if (typeof content === "string") {
|
|
115095
115121
|
return content.slice(0, 200);
|
|
115096
115122
|
}
|
|
@@ -115103,6 +115129,9 @@ function extractText(content) {
|
|
|
115103
115129
|
return concatenated.slice(0, 200);
|
|
115104
115130
|
}
|
|
115105
115131
|
function contentLength(content) {
|
|
115132
|
+
if (content === null || content === undefined) {
|
|
115133
|
+
return 0;
|
|
115134
|
+
}
|
|
115106
115135
|
if (typeof content === "string") {
|
|
115107
115136
|
return content.length;
|
|
115108
115137
|
}
|
|
@@ -115178,7 +115207,7 @@ class EscalationMemory {
|
|
|
115178
115207
|
}
|
|
115179
115208
|
|
|
115180
115209
|
// src/routing/instruction-injector.ts
|
|
115181
|
-
var INJECT_FOR_TIERS = new Set(["LIGHT"]);
|
|
115210
|
+
var INJECT_FOR_TIERS = new Set(["LIGHT", "MEDIUM"]);
|
|
115182
115211
|
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
115212
|
Do not explain. Do not ask permission. Just emit the marker and stop.`;
|
|
115184
115213
|
function injectEscalationInstruction(messages) {
|
|
@@ -115194,6 +115223,12 @@ function injectEscalationInstruction(messages) {
|
|
|
115194
115223
|
...rest
|
|
115195
115224
|
];
|
|
115196
115225
|
}
|
|
115226
|
+
if (first.content === null) {
|
|
115227
|
+
return [
|
|
115228
|
+
{ role: "system", content: ESCALATION_INSTRUCTION },
|
|
115229
|
+
...rest
|
|
115230
|
+
];
|
|
115231
|
+
}
|
|
115197
115232
|
if (typeof first.content === "string") {
|
|
115198
115233
|
return [
|
|
115199
115234
|
{ role: "system", content: first.content + `
|
|
@@ -119730,8 +119765,7 @@ function piStreamToAnthropicSse(piStream) {
|
|
|
119730
119765
|
}
|
|
119731
119766
|
});
|
|
119732
119767
|
}
|
|
119733
|
-
|
|
119734
|
-
const msg = await piStream.result();
|
|
119768
|
+
function anthropicMessageFromAssistant(msg) {
|
|
119735
119769
|
if ((msg.stopReason === "error" || msg.stopReason === "aborted") && msg.errorMessage) {
|
|
119736
119770
|
console.error(`[clawmux] pi-ai upstream error (${msg.stopReason}): ${msg.errorMessage}`);
|
|
119737
119771
|
}
|
|
@@ -119769,6 +119803,10 @@ async function piStreamToAnthropicJson(piStream) {
|
|
|
119769
119803
|
...msg.errorMessage ? { error_message: msg.errorMessage } : {}
|
|
119770
119804
|
};
|
|
119771
119805
|
}
|
|
119806
|
+
async function piStreamToAnthropicJson(piStream) {
|
|
119807
|
+
const msg = await piStream.result();
|
|
119808
|
+
return anthropicMessageFromAssistant(msg);
|
|
119809
|
+
}
|
|
119772
119810
|
|
|
119773
119811
|
// src/pi-bridge/event-to-openai-completions.ts
|
|
119774
119812
|
var encoder3 = new TextEncoder;
|
|
@@ -119992,8 +120030,7 @@ function piStreamToOpenAiCompletionsSse(piStream) {
|
|
|
119992
120030
|
}
|
|
119993
120031
|
});
|
|
119994
120032
|
}
|
|
119995
|
-
|
|
119996
|
-
const msg = await piStream.result();
|
|
120033
|
+
function openAiCompletionsMessageFromAssistant(msg) {
|
|
119997
120034
|
let textContent = "";
|
|
119998
120035
|
const toolCalls = [];
|
|
119999
120036
|
let reasoning = "";
|
|
@@ -120043,6 +120080,10 @@ async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
|
120043
120080
|
}
|
|
120044
120081
|
};
|
|
120045
120082
|
}
|
|
120083
|
+
async function piStreamToOpenAiCompletionsJson(piStream) {
|
|
120084
|
+
const msg = await piStream.result();
|
|
120085
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120086
|
+
}
|
|
120046
120087
|
|
|
120047
120088
|
// src/pi-bridge/event-to-openai-responses.ts
|
|
120048
120089
|
var encoder4 = new TextEncoder;
|
|
@@ -120205,8 +120246,7 @@ function piStreamToOpenAiResponsesSse(piStream) {
|
|
|
120205
120246
|
}
|
|
120206
120247
|
});
|
|
120207
120248
|
}
|
|
120208
|
-
|
|
120209
|
-
const msg = await piStream.result();
|
|
120249
|
+
function openAiResponsesMessageFromAssistant(msg) {
|
|
120210
120250
|
const output = [];
|
|
120211
120251
|
for (const c of msg.content) {
|
|
120212
120252
|
if (c.type === "text") {
|
|
@@ -120247,6 +120287,10 @@ async function piStreamToOpenAiResponsesJson(piStream) {
|
|
|
120247
120287
|
}
|
|
120248
120288
|
};
|
|
120249
120289
|
}
|
|
120290
|
+
async function piStreamToOpenAiResponsesJson(piStream) {
|
|
120291
|
+
const msg = await piStream.result();
|
|
120292
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120293
|
+
}
|
|
120250
120294
|
|
|
120251
120295
|
// src/pi-bridge/event-to-google.ts
|
|
120252
120296
|
var encoder5 = new TextEncoder;
|
|
@@ -120363,8 +120407,7 @@ function piStreamToGoogleSse(piStream) {
|
|
|
120363
120407
|
}
|
|
120364
120408
|
});
|
|
120365
120409
|
}
|
|
120366
|
-
|
|
120367
|
-
const msg = await piStream.result();
|
|
120410
|
+
function googleMessageFromAssistant(msg) {
|
|
120368
120411
|
const parts = [];
|
|
120369
120412
|
for (const c of msg.content) {
|
|
120370
120413
|
if (c.type === "text") {
|
|
@@ -120396,6 +120439,10 @@ async function piStreamToGoogleJson(piStream) {
|
|
|
120396
120439
|
modelVersion: msg.model || ""
|
|
120397
120440
|
};
|
|
120398
120441
|
}
|
|
120442
|
+
async function piStreamToGoogleJson(piStream) {
|
|
120443
|
+
const msg = await piStream.result();
|
|
120444
|
+
return googleMessageFromAssistant(msg);
|
|
120445
|
+
}
|
|
120399
120446
|
|
|
120400
120447
|
// src/proxy/pipeline.ts
|
|
120401
120448
|
registerAdapter(new AnthropicAdapter);
|
|
@@ -120632,35 +120679,12 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120632
120679
|
}
|
|
120633
120680
|
const detector = signalRouter.createSignalDetector();
|
|
120634
120681
|
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);
|
|
120682
|
+
const assistantMsg = await collectPiStreamWithSignalDetection(piStreamHandle, detector, detectionState);
|
|
120660
120683
|
if (detectionState.signalDetected) {
|
|
120684
|
+
abortCtrl.abort();
|
|
120661
120685
|
const nextTier = signalRouter.handleEscalation(messages, currentTier);
|
|
120662
120686
|
if (nextTier !== null) {
|
|
120663
|
-
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected
|
|
120687
|
+
console.log(`[clawmux] [escalation] ${currentTier} → ${nextTier} (signal detected)`);
|
|
120664
120688
|
currentTier = nextTier;
|
|
120665
120689
|
continue;
|
|
120666
120690
|
}
|
|
@@ -120669,7 +120693,15 @@ async function handleApiRequest(req, body, apiType, config, openclawConfig, auth
|
|
|
120669
120693
|
if (attempt > 0) {
|
|
120670
120694
|
signalRouter.recordSuccessfulEscalation(messages, currentTier);
|
|
120671
120695
|
}
|
|
120672
|
-
|
|
120696
|
+
if (wantsStream) {
|
|
120697
|
+
const sseBody = buildSseForApiType(apiType, replayAssistantMessageAsEvents(assistantMsg));
|
|
120698
|
+
return new Response(sseBody, {
|
|
120699
|
+
status: 200,
|
|
120700
|
+
headers: { "content-type": "text/event-stream" }
|
|
120701
|
+
});
|
|
120702
|
+
}
|
|
120703
|
+
const jsonBody = buildJsonForApiType(apiType, assistantMsg);
|
|
120704
|
+
return new Response(JSON.stringify(jsonBody), {
|
|
120673
120705
|
status: 200,
|
|
120674
120706
|
headers: { "content-type": "application/json" }
|
|
120675
120707
|
});
|
|
@@ -120915,164 +120947,63 @@ async function yieldPiAiResponse(piStreamHandle, apiType, wantsStream) {
|
|
|
120915
120947
|
}
|
|
120916
120948
|
throw new Error(`Unsupported pi-ai apiType: ${apiType}`);
|
|
120917
120949
|
}
|
|
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();
|
|
120950
|
+
function buildSseForApiType(apiType, gen) {
|
|
120951
|
+
if (apiType === "anthropic-messages")
|
|
120952
|
+
return piStreamToAnthropicSse(gen);
|
|
120953
|
+
if (apiType === "openai-completions")
|
|
120954
|
+
return piStreamToOpenAiCompletionsSse(gen);
|
|
120955
|
+
if (apiType === "openai-responses")
|
|
120956
|
+
return piStreamToOpenAiResponsesSse(gen);
|
|
120957
|
+
if (apiType === "google-generative-ai")
|
|
120958
|
+
return piStreamToGoogleSse(gen);
|
|
120959
|
+
return piStreamToAnthropicSse(gen);
|
|
120960
|
+
}
|
|
120961
|
+
function buildJsonForApiType(apiType, msg) {
|
|
120962
|
+
if (apiType === "anthropic-messages")
|
|
120963
|
+
return anthropicMessageFromAssistant(msg);
|
|
120964
|
+
if (apiType === "openai-completions")
|
|
120965
|
+
return openAiCompletionsMessageFromAssistant(msg);
|
|
120966
|
+
if (apiType === "openai-responses")
|
|
120967
|
+
return openAiResponsesMessageFromAssistant(msg);
|
|
120968
|
+
if (apiType === "google-generative-ai")
|
|
120969
|
+
return googleMessageFromAssistant(msg);
|
|
120970
|
+
return anthropicMessageFromAssistant(msg);
|
|
120971
|
+
}
|
|
120972
|
+
async function drainSignalGenerator(gen) {
|
|
120973
|
+
for await (const _event of gen) {}
|
|
120974
|
+
}
|
|
120975
|
+
async function* replayAssistantMessageAsEvents(msg) {
|
|
120976
|
+
const partial = msg;
|
|
120977
|
+
yield { type: "start", partial };
|
|
120978
|
+
for (let i2 = 0;i2 < msg.content.length; i2++) {
|
|
120979
|
+
const block = msg.content[i2];
|
|
120980
|
+
if (block.type === "text") {
|
|
120981
|
+
yield { type: "text_start", contentIndex: i2, partial };
|
|
120982
|
+
if (block.text.length > 0) {
|
|
120983
|
+
yield { type: "text_delta", contentIndex: i2, delta: block.text, partial };
|
|
121022
120984
|
}
|
|
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
|
-
});
|
|
120985
|
+
yield { type: "text_end", contentIndex: i2, content: block.text, partial };
|
|
120986
|
+
} else if (block.type === "thinking") {
|
|
120987
|
+
yield { type: "thinking_start", contentIndex: i2, partial };
|
|
120988
|
+
if (block.thinking.length > 0) {
|
|
120989
|
+
yield { type: "thinking_delta", contentIndex: i2, delta: block.thinking, partial };
|
|
120990
|
+
}
|
|
120991
|
+
yield { type: "thinking_end", contentIndex: i2, content: block.thinking, partial };
|
|
120992
|
+
} else if (block.type === "toolCall") {
|
|
120993
|
+
yield { type: "toolcall_start", contentIndex: i2, partial };
|
|
120994
|
+
const argsJson = JSON.stringify(block.arguments ?? {});
|
|
120995
|
+
if (argsJson.length > 0 && argsJson !== "{}") {
|
|
120996
|
+
yield { type: "toolcall_delta", contentIndex: i2, delta: argsJson, partial };
|
|
120997
|
+
}
|
|
120998
|
+
yield { type: "toolcall_end", contentIndex: i2, toolCall: block, partial };
|
|
121061
120999
|
}
|
|
121062
121000
|
}
|
|
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
|
-
};
|
|
121001
|
+
yield { type: "done", reason: msg.stopReason, message: msg };
|
|
121002
|
+
}
|
|
121003
|
+
async function collectPiStreamWithSignalDetection(piStreamHandle, detector, state) {
|
|
121004
|
+
const signalGen = detectSignalInStream(piStreamHandle, detector, state, () => {});
|
|
121005
|
+
await drainSignalGenerator(signalGen);
|
|
121006
|
+
return await piStreamHandle.result();
|
|
121076
121007
|
}
|
|
121077
121008
|
var ROUTE_MAPPINGS = [
|
|
121078
121009
|
{ apiType: "anthropic-messages", key: "/v1/messages" },
|
|
@@ -121235,6 +121166,13 @@ function resolveProviderApi(mediumModel, openclawProviders) {
|
|
|
121235
121166
|
return api;
|
|
121236
121167
|
return PROVIDER_API_FALLBACK;
|
|
121237
121168
|
}
|
|
121169
|
+
function resolveProviderBaseUrl(apiType, port) {
|
|
121170
|
+
const origin = `http://localhost:${port}`;
|
|
121171
|
+
if (apiType === "openai-completions" || apiType === "openai-responses") {
|
|
121172
|
+
return `${origin}/v1`;
|
|
121173
|
+
}
|
|
121174
|
+
return origin;
|
|
121175
|
+
}
|
|
121238
121176
|
async function fileExistsLocal(path4) {
|
|
121239
121177
|
try {
|
|
121240
121178
|
await import_promises8.access(path4);
|
|
@@ -121513,7 +121451,7 @@ async function update() {
|
|
|
121513
121451
|
process.exit(1);
|
|
121514
121452
|
}
|
|
121515
121453
|
}
|
|
121516
|
-
async function fixAgentModelsJson(homeDir, providerKey,
|
|
121454
|
+
async function fixAgentModelsJson(homeDir, providerKey, servicePort, fallbackApiType) {
|
|
121517
121455
|
const agentsDir = import_node_path7.join(homeDir, ".openclaw", "agents");
|
|
121518
121456
|
let agentDirs;
|
|
121519
121457
|
try {
|
|
@@ -121531,13 +121469,15 @@ async function fixAgentModelsJson(homeDir, providerKey, correctBaseUrl) {
|
|
|
121531
121469
|
if (!agentProviders?.[providerKey])
|
|
121532
121470
|
continue;
|
|
121533
121471
|
const entry = agentProviders[providerKey];
|
|
121472
|
+
const agentApiType = typeof entry["api"] === "string" && entry["api"].length > 0 ? entry["api"] : fallbackApiType;
|
|
121473
|
+
const correctBaseUrl = resolveProviderBaseUrl(agentApiType, servicePort);
|
|
121534
121474
|
const current = String(entry["baseUrl"] ?? "");
|
|
121535
121475
|
if (current === correctBaseUrl)
|
|
121536
121476
|
continue;
|
|
121537
121477
|
entry["baseUrl"] = correctBaseUrl;
|
|
121538
121478
|
await import_promises8.writeFile(modelsPath, JSON.stringify(data, null, 2) + `
|
|
121539
121479
|
`);
|
|
121540
|
-
console.log(` fixed agent ${agentId} ${providerKey} baseUrl: ${current} → ${correctBaseUrl}`);
|
|
121480
|
+
console.log(` fixed agent ${agentId} ${providerKey} baseUrl: ${current} → ${correctBaseUrl} (api=${agentApiType})`);
|
|
121541
121481
|
} catch {}
|
|
121542
121482
|
}
|
|
121543
121483
|
}
|
|
@@ -121596,31 +121536,42 @@ async function init() {
|
|
|
121596
121536
|
} catch {
|
|
121597
121537
|
console.log(`[info] clawmux.json not readable, using default api: ${providerApi}`);
|
|
121598
121538
|
}
|
|
121539
|
+
const servicePort = process.env.CLAWMUX_PORT ?? "3456";
|
|
121540
|
+
const providerBaseUrl = resolveProviderBaseUrl(providerApi, servicePort);
|
|
121599
121541
|
if (providers[PROVIDER_KEY]) {
|
|
121600
121542
|
const existing = providers[PROVIDER_KEY];
|
|
121601
|
-
|
|
121543
|
+
const existingApi = existing["api"];
|
|
121544
|
+
const existingBaseUrl = existing["baseUrl"];
|
|
121545
|
+
let dirty = false;
|
|
121546
|
+
if (existingApi !== providerApi) {
|
|
121602
121547
|
existing["api"] = providerApi;
|
|
121548
|
+
dirty = true;
|
|
121549
|
+
}
|
|
121550
|
+
if (existingBaseUrl !== providerBaseUrl) {
|
|
121551
|
+
existing["baseUrl"] = providerBaseUrl;
|
|
121552
|
+
dirty = true;
|
|
121553
|
+
}
|
|
121554
|
+
if (dirty) {
|
|
121603
121555
|
await import_promises8.writeFile(openclawConfigPath, JSON.stringify(config, null, 2) + `
|
|
121604
121556
|
`);
|
|
121605
|
-
console.log(` updated ${PROVIDER_KEY} provider api
|
|
121557
|
+
console.log(` updated ${PROVIDER_KEY} provider (api=${providerApi}, baseUrl=${providerBaseUrl})`);
|
|
121606
121558
|
} else {
|
|
121607
|
-
console.log(` skip ${PROVIDER_KEY} (already exists, api=${providerApi})`);
|
|
121559
|
+
console.log(` skip ${PROVIDER_KEY} (already exists, api=${providerApi}, baseUrl=${providerBaseUrl})`);
|
|
121608
121560
|
}
|
|
121609
121561
|
} else {
|
|
121610
121562
|
providers[PROVIDER_KEY] = {
|
|
121611
|
-
baseUrl:
|
|
121563
|
+
baseUrl: providerBaseUrl,
|
|
121612
121564
|
api: providerApi,
|
|
121613
121565
|
models: [{ id: "auto", name: "ClawMux Auto Router" }]
|
|
121614
121566
|
};
|
|
121615
121567
|
await import_promises8.writeFile(openclawConfigPath, JSON.stringify(config, null, 2) + `
|
|
121616
121568
|
`);
|
|
121617
|
-
console.log(` added ${PROVIDER_KEY} provider to openclaw.json (api=${providerApi})`);
|
|
121569
|
+
console.log(` added ${PROVIDER_KEY} provider to openclaw.json (api=${providerApi}, baseUrl=${providerBaseUrl})`);
|
|
121618
121570
|
}
|
|
121619
|
-
await fixAgentModelsJson(homeDir, PROVIDER_KEY,
|
|
121620
|
-
const port = process.env.CLAWMUX_PORT ?? "3456";
|
|
121571
|
+
await fixAgentModelsJson(homeDir, PROVIDER_KEY, servicePort, providerApi);
|
|
121621
121572
|
if (!noService) {
|
|
121622
121573
|
console.log("");
|
|
121623
|
-
await installService(
|
|
121574
|
+
await installService(servicePort, process.cwd());
|
|
121624
121575
|
}
|
|
121625
121576
|
console.log(`
|
|
121626
121577
|
[info] ClawMux setup complete!`);
|
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.15";
|
|
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" },
|