@jacobbd/relay-ai 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-LNQ46VW7.js → chunk-5LPUIWNJ.js} +116 -13
- package/dist/chunk-5LPUIWNJ.js.map +1 -0
- package/dist/cli.js +5 -50
- package/dist/cli.js.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/ui/public/app.js +139 -7
- package/dist/ui/public/provider-model-browser.js +27 -8
- package/dist/ui/public/style.css +122 -5
- package/dist/{ui-command-5VEFZ5GM.js → ui-command-DMPYSK7W.js} +74 -5
- package/dist/ui-command-DMPYSK7W.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-LNQ46VW7.js.map +0 -1
- package/dist/ui-command-5VEFZ5GM.js.map +0 -1
|
@@ -11,7 +11,7 @@ import { join } from "path";
|
|
|
11
11
|
// package.json
|
|
12
12
|
var package_default = {
|
|
13
13
|
name: "@jacobbd/relay-ai",
|
|
14
|
-
version: "0.7.
|
|
14
|
+
version: "0.7.3",
|
|
15
15
|
publishConfig: {
|
|
16
16
|
access: "public"
|
|
17
17
|
},
|
|
@@ -1900,6 +1900,24 @@ function setServerListenMode(listenMode) {
|
|
|
1900
1900
|
};
|
|
1901
1901
|
writeConfig(config);
|
|
1902
1902
|
}
|
|
1903
|
+
function getServerAutostart() {
|
|
1904
|
+
return readConfig().server?.autostart ?? false;
|
|
1905
|
+
}
|
|
1906
|
+
function setServerAutostart(autostart) {
|
|
1907
|
+
const config = readConfig();
|
|
1908
|
+
config.server = {
|
|
1909
|
+
...config.server ?? {},
|
|
1910
|
+
autostart
|
|
1911
|
+
};
|
|
1912
|
+
writeConfig(config);
|
|
1913
|
+
}
|
|
1914
|
+
function resolveServerAutostart(env = process.env) {
|
|
1915
|
+
const envVal = env["RELAY_AI_SERVER_AUTOSTART"]?.trim().toLowerCase();
|
|
1916
|
+
if (envVal !== void 0 && envVal !== "") {
|
|
1917
|
+
return ["1", "true", "yes", "on"].includes(envVal);
|
|
1918
|
+
}
|
|
1919
|
+
return getServerAutostart();
|
|
1920
|
+
}
|
|
1903
1921
|
|
|
1904
1922
|
// src/launch.ts
|
|
1905
1923
|
import { execSync, spawn } from "child_process";
|
|
@@ -4429,6 +4447,52 @@ function formatOpenAIModels(models) {
|
|
|
4429
4447
|
};
|
|
4430
4448
|
}
|
|
4431
4449
|
|
|
4450
|
+
// src/anthropic-endpoints.ts
|
|
4451
|
+
var MESSAGE_PATH = "/v1/messages";
|
|
4452
|
+
var COUNT_TOKENS_PATH = "/v1/messages/count_tokens";
|
|
4453
|
+
var MODELS_PATH = "/v1/models";
|
|
4454
|
+
function anthropicModelsEndpoint(url) {
|
|
4455
|
+
if (!url) return null;
|
|
4456
|
+
try {
|
|
4457
|
+
const pathname = new URL(url, "http://relay.local").pathname;
|
|
4458
|
+
if (pathname === MODELS_PATH || pathname === `${MODELS_PATH}/`) return "list";
|
|
4459
|
+
if (pathname.startsWith(`${MODELS_PATH}/`)) {
|
|
4460
|
+
const id = decodeURIComponent(pathname.slice(MODELS_PATH.length + 1));
|
|
4461
|
+
if (id) return { id };
|
|
4462
|
+
}
|
|
4463
|
+
} catch {
|
|
4464
|
+
}
|
|
4465
|
+
return null;
|
|
4466
|
+
}
|
|
4467
|
+
function anthropicMessagesEndpoint(url) {
|
|
4468
|
+
if (!url) return null;
|
|
4469
|
+
try {
|
|
4470
|
+
const pathname = new URL(url, "http://relay.local").pathname;
|
|
4471
|
+
if (pathname === MESSAGE_PATH) return "messages";
|
|
4472
|
+
if (pathname === COUNT_TOKENS_PATH) return "count_tokens";
|
|
4473
|
+
} catch {
|
|
4474
|
+
}
|
|
4475
|
+
return null;
|
|
4476
|
+
}
|
|
4477
|
+
var NON_CONTEXT_FIELDS = /* @__PURE__ */ new Set([
|
|
4478
|
+
"model",
|
|
4479
|
+
"stream",
|
|
4480
|
+
"max_tokens",
|
|
4481
|
+
"temperature",
|
|
4482
|
+
"top_p",
|
|
4483
|
+
"top_k",
|
|
4484
|
+
"stop_sequences",
|
|
4485
|
+
"metadata"
|
|
4486
|
+
]);
|
|
4487
|
+
function estimateAnthropicInputTokens(body) {
|
|
4488
|
+
const contextBody = Object.fromEntries(
|
|
4489
|
+
Object.entries(body).filter(([key]) => !NON_CONTEXT_FIELDS.has(key))
|
|
4490
|
+
);
|
|
4491
|
+
const serialized = JSON.stringify(contextBody);
|
|
4492
|
+
if (!serialized || serialized === "{}") return 0;
|
|
4493
|
+
return Math.max(1, Math.ceil(Buffer.byteLength(serialized, "utf8") / 4));
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4432
4496
|
// src/upstream-forward.ts
|
|
4433
4497
|
import { Readable } from "stream";
|
|
4434
4498
|
|
|
@@ -4646,7 +4710,9 @@ function encodeToolUseId(rawId, thoughtSignature, inline = true) {
|
|
|
4646
4710
|
return `${rawId}${TOOL_USE_SIG_SEP}${encoded}`;
|
|
4647
4711
|
}
|
|
4648
4712
|
function serializeToolResultContent(content) {
|
|
4649
|
-
|
|
4713
|
+
if (typeof content === "string") return content;
|
|
4714
|
+
if (content === void 0) return "";
|
|
4715
|
+
return JSON.stringify(content);
|
|
4650
4716
|
}
|
|
4651
4717
|
|
|
4652
4718
|
// src/antigravity/request-adapter.ts
|
|
@@ -5432,6 +5498,8 @@ function sanitizeMessage(message) {
|
|
|
5432
5498
|
}
|
|
5433
5499
|
|
|
5434
5500
|
// src/sdk-adapter.ts
|
|
5501
|
+
var NEEDS_TRAILING_TOOL_NUDGE = /* @__PURE__ */ new Set(["@ai-sdk/alibaba"]);
|
|
5502
|
+
var TRAILING_TOOL_NUDGE_TEXT = "Continue.";
|
|
5435
5503
|
function anthropicEffortFromRequest(body) {
|
|
5436
5504
|
const effort = body.output_config?.effort;
|
|
5437
5505
|
if (typeof effort === "string" && effort.trim()) return effort.trim();
|
|
@@ -5492,7 +5560,7 @@ function thinkingToSdkPart(block, npm) {
|
|
|
5492
5560
|
}
|
|
5493
5561
|
return part;
|
|
5494
5562
|
}
|
|
5495
|
-
function translateMessages(messages, npm) {
|
|
5563
|
+
function translateMessages(messages, npm, onDebug) {
|
|
5496
5564
|
const isGoogle = npm === "@ai-sdk/google";
|
|
5497
5565
|
const out = [];
|
|
5498
5566
|
for (const msg of messages) {
|
|
@@ -5507,6 +5575,10 @@ function translateMessages(messages, npm) {
|
|
|
5507
5575
|
if (p8) parts.push(p8);
|
|
5508
5576
|
}
|
|
5509
5577
|
}
|
|
5578
|
+
if (blocks.length && !toolResults.length && !parts.length) {
|
|
5579
|
+
const types = blocks.map((b) => b.type).join(", ");
|
|
5580
|
+
onDebug?.(`sdk: dropped user turn with unrecognized block types: [${types}]`);
|
|
5581
|
+
}
|
|
5510
5582
|
if (toolResults.length) {
|
|
5511
5583
|
out.push({
|
|
5512
5584
|
role: "tool",
|
|
@@ -5542,6 +5614,10 @@ function translateMessages(messages, npm) {
|
|
|
5542
5614
|
if (parts.length) out.push({ role: "assistant", content: parts });
|
|
5543
5615
|
}
|
|
5544
5616
|
}
|
|
5617
|
+
if (NEEDS_TRAILING_TOOL_NUDGE.has(npm) && out[out.length - 1]?.role === "tool") {
|
|
5618
|
+
out.push({ role: "user", content: [{ type: "text", text: TRAILING_TOOL_NUDGE_TEXT }] });
|
|
5619
|
+
onDebug?.("sdk: appended continuation nudge (request ended on tool result)");
|
|
5620
|
+
}
|
|
5545
5621
|
return out;
|
|
5546
5622
|
}
|
|
5547
5623
|
function stripNullInputs(input) {
|
|
@@ -5592,7 +5668,7 @@ function translateRequest2(body, npm, options) {
|
|
|
5592
5668
|
}
|
|
5593
5669
|
return {
|
|
5594
5670
|
system: options?.openAiOAuth ? void 0 : systemText,
|
|
5595
|
-
messages: translateMessages(messages, npm),
|
|
5671
|
+
messages: translateMessages(messages, npm, options?.onDebug),
|
|
5596
5672
|
tools: translateTools3(upstreamTools.length ? upstreamTools : void 0),
|
|
5597
5673
|
toolChoice: translateToolChoice(body.tool_choice),
|
|
5598
5674
|
maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
|
|
@@ -5600,7 +5676,7 @@ function translateRequest2(body, npm, options) {
|
|
|
5600
5676
|
providerOptions
|
|
5601
5677
|
};
|
|
5602
5678
|
}
|
|
5603
|
-
async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
5679
|
+
async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedInputTokens = 0) {
|
|
5604
5680
|
const messageId = "msg_" + Date.now();
|
|
5605
5681
|
let blockIndex = -1;
|
|
5606
5682
|
let started = false;
|
|
@@ -5608,7 +5684,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5608
5684
|
let pendingThinkingSig;
|
|
5609
5685
|
const idToBlock = /* @__PURE__ */ new Map();
|
|
5610
5686
|
let finishReason = "end_turn";
|
|
5611
|
-
let usage = { input_tokens:
|
|
5687
|
+
let usage = { input_tokens: estimatedInputTokens, output_tokens: 0 };
|
|
5612
5688
|
const emit = (event, data) => write(sseChunk(event, data));
|
|
5613
5689
|
const ensureStart = () => {
|
|
5614
5690
|
if (started) return;
|
|
@@ -5622,7 +5698,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5622
5698
|
model: modelId,
|
|
5623
5699
|
stop_reason: null,
|
|
5624
5700
|
stop_sequence: null,
|
|
5625
|
-
usage: { input_tokens:
|
|
5701
|
+
usage: { input_tokens: estimatedInputTokens, output_tokens: 0 }
|
|
5626
5702
|
}
|
|
5627
5703
|
});
|
|
5628
5704
|
started = true;
|
|
@@ -5721,7 +5797,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5721
5797
|
case "finish":
|
|
5722
5798
|
if (part.totalUsage) {
|
|
5723
5799
|
usage = {
|
|
5724
|
-
input_tokens: part.totalUsage.inputTokens ??
|
|
5800
|
+
input_tokens: part.totalUsage.inputTokens ?? estimatedInputTokens,
|
|
5725
5801
|
output_tokens: part.totalUsage.outputTokens ?? 0
|
|
5726
5802
|
};
|
|
5727
5803
|
}
|
|
@@ -5747,7 +5823,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5747
5823
|
emit("message_delta", { type: "message_delta", delta: { stop_reason: finishReason, stop_sequence: null }, usage });
|
|
5748
5824
|
emit("message_stop", { type: "message_stop" });
|
|
5749
5825
|
}
|
|
5750
|
-
async function streamAnthropicResponse(model, params, modelId, write, log7) {
|
|
5826
|
+
async function streamAnthropicResponse(model, params, modelId, write, log7, estimatedInputTokens = 0) {
|
|
5751
5827
|
const result = streamText({ model, ...params, onError: () => {
|
|
5752
5828
|
} });
|
|
5753
5829
|
Promise.resolve(result.text).catch(() => {
|
|
@@ -5760,7 +5836,13 @@ async function streamAnthropicResponse(model, params, modelId, write, log7) {
|
|
|
5760
5836
|
});
|
|
5761
5837
|
Promise.resolve(result.usage).catch(() => {
|
|
5762
5838
|
});
|
|
5763
|
-
await writeAnthropicStream(
|
|
5839
|
+
await writeAnthropicStream(
|
|
5840
|
+
result.fullStream,
|
|
5841
|
+
modelId,
|
|
5842
|
+
write,
|
|
5843
|
+
log7,
|
|
5844
|
+
estimatedInputTokens
|
|
5845
|
+
);
|
|
5764
5846
|
}
|
|
5765
5847
|
async function generateAnthropicResponse(model, params, modelId, options) {
|
|
5766
5848
|
let text4;
|
|
@@ -5965,6 +6047,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
|
|
|
5965
6047
|
const params = translateRequest2(anthropicBody, route.npm, {
|
|
5966
6048
|
openAiOAuth,
|
|
5967
6049
|
maxTools: maxToolsForNpm(route.npm),
|
|
6050
|
+
onDebug: (msg) => plog(() => msg),
|
|
5968
6051
|
reasoningMetadata: {
|
|
5969
6052
|
providerId: route.providerId,
|
|
5970
6053
|
apiBaseUrl: route.baseURL,
|
|
@@ -5998,7 +6081,14 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
|
|
|
5998
6081
|
"Cache-Control": "no-cache",
|
|
5999
6082
|
"Connection": "keep-alive"
|
|
6000
6083
|
});
|
|
6001
|
-
await streamAnthropicResponse(
|
|
6084
|
+
await streamAnthropicResponse(
|
|
6085
|
+
model,
|
|
6086
|
+
params,
|
|
6087
|
+
originalModel,
|
|
6088
|
+
(c) => res.write(c),
|
|
6089
|
+
plog,
|
|
6090
|
+
estimateAnthropicInputTokens(anthropicBody)
|
|
6091
|
+
);
|
|
6002
6092
|
res.end();
|
|
6003
6093
|
} else {
|
|
6004
6094
|
const anthropicResponse = await generateAnthropicResponse(
|
|
@@ -9870,6 +9960,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
9870
9960
|
const params = translateRequest2(body, model.npm, {
|
|
9871
9961
|
defaultEffort: anthropicEffortFromRequest(body) ? void 0 : model.defaultEffort,
|
|
9872
9962
|
openAiOAuth: model.npm === "@ai-sdk/openai" && model.authType === "oauth",
|
|
9963
|
+
onDebug: plog,
|
|
9873
9964
|
reasoningMetadata: {
|
|
9874
9965
|
providerId: model.providerId,
|
|
9875
9966
|
apiBaseUrl: model.apiBaseUrl,
|
|
@@ -9890,7 +9981,14 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
9890
9981
|
"Cache-Control": "no-cache",
|
|
9891
9982
|
"Connection": "keep-alive"
|
|
9892
9983
|
});
|
|
9893
|
-
await streamAnthropicResponse(
|
|
9984
|
+
await streamAnthropicResponse(
|
|
9985
|
+
languageModel,
|
|
9986
|
+
params,
|
|
9987
|
+
responseModelId,
|
|
9988
|
+
(chunk) => res.write(chunk),
|
|
9989
|
+
void 0,
|
|
9990
|
+
estimateAnthropicInputTokens(body)
|
|
9991
|
+
);
|
|
9894
9992
|
res.end();
|
|
9895
9993
|
} else {
|
|
9896
9994
|
const anthropicResponse = await generateAnthropicResponse(languageModel, params, responseModelId);
|
|
@@ -11818,6 +11916,8 @@ export {
|
|
|
11818
11916
|
setServerFreeModelsOnly,
|
|
11819
11917
|
getServerListenMode,
|
|
11820
11918
|
setServerListenMode,
|
|
11919
|
+
setServerAutostart,
|
|
11920
|
+
resolveServerAutostart,
|
|
11821
11921
|
findBinaryOnPath,
|
|
11822
11922
|
findClaudeBinary,
|
|
11823
11923
|
launchClaude,
|
|
@@ -11891,6 +11991,9 @@ export {
|
|
|
11891
11991
|
openAiIdCollisions,
|
|
11892
11992
|
createGatewayModelCatalog,
|
|
11893
11993
|
buildDedupedModelRows,
|
|
11994
|
+
anthropicModelsEndpoint,
|
|
11995
|
+
anthropicMessagesEndpoint,
|
|
11996
|
+
estimateAnthropicInputTokens,
|
|
11894
11997
|
grabRoundTripSignature,
|
|
11895
11998
|
silenceSdkWarnings,
|
|
11896
11999
|
parseToolArguments,
|
|
@@ -11966,4 +12069,4 @@ export {
|
|
|
11966
12069
|
supportsClaudeTransparentMode,
|
|
11967
12070
|
buildHttpProxyRoutes
|
|
11968
12071
|
};
|
|
11969
|
-
//# sourceMappingURL=chunk-
|
|
12072
|
+
//# sourceMappingURL=chunk-5LPUIWNJ.js.map
|