@jacobbd/relay-ai 0.7.2 → 0.7.4
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-EUY2MVOS.js} +121 -16
- package/dist/chunk-EUY2MVOS.js.map +1 -0
- package/dist/cli.js +13 -53
- package/dist/cli.js.map +1 -1
- package/dist/core/index.js +3 -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-CF3IEIZP.js} +74 -5
- package/dist/ui-command-CF3IEIZP.js.map +1 -0
- package/package.json +3 -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.4",
|
|
15
15
|
publishConfig: {
|
|
16
16
|
access: "public"
|
|
17
17
|
},
|
|
@@ -75,6 +75,7 @@ var package_default = {
|
|
|
75
75
|
"@clack/prompts": "^0.9.1",
|
|
76
76
|
"@openrouter/ai-sdk-provider": "^2.9.0",
|
|
77
77
|
ai: "^6.0.197",
|
|
78
|
+
"cross-spawn": "^7.0.6",
|
|
78
79
|
"gitlab-ai-provider": "^6.8.0",
|
|
79
80
|
graphql: "^16.14.2",
|
|
80
81
|
"ipaddr.js": "^2.4.0",
|
|
@@ -87,6 +88,7 @@ var package_default = {
|
|
|
87
88
|
zod: "^3.25.76"
|
|
88
89
|
},
|
|
89
90
|
devDependencies: {
|
|
91
|
+
"@types/cross-spawn": "^6.0.6",
|
|
90
92
|
"@types/node": "^22.0.0",
|
|
91
93
|
"@types/node-forge": "^1.3.14",
|
|
92
94
|
"@types/ws": "^8.18.1",
|
|
@@ -1900,9 +1902,28 @@ function setServerListenMode(listenMode) {
|
|
|
1900
1902
|
};
|
|
1901
1903
|
writeConfig(config);
|
|
1902
1904
|
}
|
|
1905
|
+
function getServerAutostart() {
|
|
1906
|
+
return readConfig().server?.autostart ?? false;
|
|
1907
|
+
}
|
|
1908
|
+
function setServerAutostart(autostart) {
|
|
1909
|
+
const config = readConfig();
|
|
1910
|
+
config.server = {
|
|
1911
|
+
...config.server ?? {},
|
|
1912
|
+
autostart
|
|
1913
|
+
};
|
|
1914
|
+
writeConfig(config);
|
|
1915
|
+
}
|
|
1916
|
+
function resolveServerAutostart(env = process.env) {
|
|
1917
|
+
const envVal = env["RELAY_AI_SERVER_AUTOSTART"]?.trim().toLowerCase();
|
|
1918
|
+
if (envVal !== void 0 && envVal !== "") {
|
|
1919
|
+
return ["1", "true", "yes", "on"].includes(envVal);
|
|
1920
|
+
}
|
|
1921
|
+
return getServerAutostart();
|
|
1922
|
+
}
|
|
1903
1923
|
|
|
1904
1924
|
// src/launch.ts
|
|
1905
|
-
import { execSync
|
|
1925
|
+
import { execSync } from "child_process";
|
|
1926
|
+
import spawn from "cross-spawn";
|
|
1906
1927
|
import { existsSync as existsSync3, appendFileSync } from "fs";
|
|
1907
1928
|
import { homedir as homedir3 } from "os";
|
|
1908
1929
|
import { join as join4 } from "path";
|
|
@@ -1993,8 +2014,7 @@ function launchClaude(env, model, extraArgs) {
|
|
|
1993
2014
|
};
|
|
1994
2015
|
const child = spawn(claudePath, args, {
|
|
1995
2016
|
stdio: "inherit",
|
|
1996
|
-
env
|
|
1997
|
-
shell: isWindows
|
|
2017
|
+
env
|
|
1998
2018
|
});
|
|
1999
2019
|
const forward = (signal) => {
|
|
2000
2020
|
child.kill(signal);
|
|
@@ -4429,6 +4449,52 @@ function formatOpenAIModels(models) {
|
|
|
4429
4449
|
};
|
|
4430
4450
|
}
|
|
4431
4451
|
|
|
4452
|
+
// src/anthropic-endpoints.ts
|
|
4453
|
+
var MESSAGE_PATH = "/v1/messages";
|
|
4454
|
+
var COUNT_TOKENS_PATH = "/v1/messages/count_tokens";
|
|
4455
|
+
var MODELS_PATH = "/v1/models";
|
|
4456
|
+
function anthropicModelsEndpoint(url) {
|
|
4457
|
+
if (!url) return null;
|
|
4458
|
+
try {
|
|
4459
|
+
const pathname = new URL(url, "http://relay.local").pathname;
|
|
4460
|
+
if (pathname === MODELS_PATH || pathname === `${MODELS_PATH}/`) return "list";
|
|
4461
|
+
if (pathname.startsWith(`${MODELS_PATH}/`)) {
|
|
4462
|
+
const id = decodeURIComponent(pathname.slice(MODELS_PATH.length + 1));
|
|
4463
|
+
if (id) return { id };
|
|
4464
|
+
}
|
|
4465
|
+
} catch {
|
|
4466
|
+
}
|
|
4467
|
+
return null;
|
|
4468
|
+
}
|
|
4469
|
+
function anthropicMessagesEndpoint(url) {
|
|
4470
|
+
if (!url) return null;
|
|
4471
|
+
try {
|
|
4472
|
+
const pathname = new URL(url, "http://relay.local").pathname;
|
|
4473
|
+
if (pathname === MESSAGE_PATH) return "messages";
|
|
4474
|
+
if (pathname === COUNT_TOKENS_PATH) return "count_tokens";
|
|
4475
|
+
} catch {
|
|
4476
|
+
}
|
|
4477
|
+
return null;
|
|
4478
|
+
}
|
|
4479
|
+
var NON_CONTEXT_FIELDS = /* @__PURE__ */ new Set([
|
|
4480
|
+
"model",
|
|
4481
|
+
"stream",
|
|
4482
|
+
"max_tokens",
|
|
4483
|
+
"temperature",
|
|
4484
|
+
"top_p",
|
|
4485
|
+
"top_k",
|
|
4486
|
+
"stop_sequences",
|
|
4487
|
+
"metadata"
|
|
4488
|
+
]);
|
|
4489
|
+
function estimateAnthropicInputTokens(body) {
|
|
4490
|
+
const contextBody = Object.fromEntries(
|
|
4491
|
+
Object.entries(body).filter(([key]) => !NON_CONTEXT_FIELDS.has(key))
|
|
4492
|
+
);
|
|
4493
|
+
const serialized = JSON.stringify(contextBody);
|
|
4494
|
+
if (!serialized || serialized === "{}") return 0;
|
|
4495
|
+
return Math.max(1, Math.ceil(Buffer.byteLength(serialized, "utf8") / 4));
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4432
4498
|
// src/upstream-forward.ts
|
|
4433
4499
|
import { Readable } from "stream";
|
|
4434
4500
|
|
|
@@ -4646,7 +4712,9 @@ function encodeToolUseId(rawId, thoughtSignature, inline = true) {
|
|
|
4646
4712
|
return `${rawId}${TOOL_USE_SIG_SEP}${encoded}`;
|
|
4647
4713
|
}
|
|
4648
4714
|
function serializeToolResultContent(content) {
|
|
4649
|
-
|
|
4715
|
+
if (typeof content === "string") return content;
|
|
4716
|
+
if (content === void 0) return "";
|
|
4717
|
+
return JSON.stringify(content);
|
|
4650
4718
|
}
|
|
4651
4719
|
|
|
4652
4720
|
// src/antigravity/request-adapter.ts
|
|
@@ -5432,6 +5500,8 @@ function sanitizeMessage(message) {
|
|
|
5432
5500
|
}
|
|
5433
5501
|
|
|
5434
5502
|
// src/sdk-adapter.ts
|
|
5503
|
+
var NEEDS_TRAILING_TOOL_NUDGE = /* @__PURE__ */ new Set(["@ai-sdk/alibaba"]);
|
|
5504
|
+
var TRAILING_TOOL_NUDGE_TEXT = "Continue.";
|
|
5435
5505
|
function anthropicEffortFromRequest(body) {
|
|
5436
5506
|
const effort = body.output_config?.effort;
|
|
5437
5507
|
if (typeof effort === "string" && effort.trim()) return effort.trim();
|
|
@@ -5492,7 +5562,7 @@ function thinkingToSdkPart(block, npm) {
|
|
|
5492
5562
|
}
|
|
5493
5563
|
return part;
|
|
5494
5564
|
}
|
|
5495
|
-
function translateMessages(messages, npm) {
|
|
5565
|
+
function translateMessages(messages, npm, onDebug) {
|
|
5496
5566
|
const isGoogle = npm === "@ai-sdk/google";
|
|
5497
5567
|
const out = [];
|
|
5498
5568
|
for (const msg of messages) {
|
|
@@ -5507,6 +5577,10 @@ function translateMessages(messages, npm) {
|
|
|
5507
5577
|
if (p8) parts.push(p8);
|
|
5508
5578
|
}
|
|
5509
5579
|
}
|
|
5580
|
+
if (blocks.length && !toolResults.length && !parts.length) {
|
|
5581
|
+
const types = blocks.map((b) => b.type).join(", ");
|
|
5582
|
+
onDebug?.(`sdk: dropped user turn with unrecognized block types: [${types}]`);
|
|
5583
|
+
}
|
|
5510
5584
|
if (toolResults.length) {
|
|
5511
5585
|
out.push({
|
|
5512
5586
|
role: "tool",
|
|
@@ -5542,6 +5616,10 @@ function translateMessages(messages, npm) {
|
|
|
5542
5616
|
if (parts.length) out.push({ role: "assistant", content: parts });
|
|
5543
5617
|
}
|
|
5544
5618
|
}
|
|
5619
|
+
if (NEEDS_TRAILING_TOOL_NUDGE.has(npm) && out[out.length - 1]?.role === "tool") {
|
|
5620
|
+
out.push({ role: "user", content: [{ type: "text", text: TRAILING_TOOL_NUDGE_TEXT }] });
|
|
5621
|
+
onDebug?.("sdk: appended continuation nudge (request ended on tool result)");
|
|
5622
|
+
}
|
|
5545
5623
|
return out;
|
|
5546
5624
|
}
|
|
5547
5625
|
function stripNullInputs(input) {
|
|
@@ -5592,7 +5670,7 @@ function translateRequest2(body, npm, options) {
|
|
|
5592
5670
|
}
|
|
5593
5671
|
return {
|
|
5594
5672
|
system: options?.openAiOAuth ? void 0 : systemText,
|
|
5595
|
-
messages: translateMessages(messages, npm),
|
|
5673
|
+
messages: translateMessages(messages, npm, options?.onDebug),
|
|
5596
5674
|
tools: translateTools3(upstreamTools.length ? upstreamTools : void 0),
|
|
5597
5675
|
toolChoice: translateToolChoice(body.tool_choice),
|
|
5598
5676
|
maxOutputTokens: options?.openAiOAuth ? void 0 : body.max_tokens,
|
|
@@ -5600,7 +5678,7 @@ function translateRequest2(body, npm, options) {
|
|
|
5600
5678
|
providerOptions
|
|
5601
5679
|
};
|
|
5602
5680
|
}
|
|
5603
|
-
async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
5681
|
+
async function writeAnthropicStream(fullStream, modelId, write, log7, estimatedInputTokens = 0) {
|
|
5604
5682
|
const messageId = "msg_" + Date.now();
|
|
5605
5683
|
let blockIndex = -1;
|
|
5606
5684
|
let started = false;
|
|
@@ -5608,7 +5686,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5608
5686
|
let pendingThinkingSig;
|
|
5609
5687
|
const idToBlock = /* @__PURE__ */ new Map();
|
|
5610
5688
|
let finishReason = "end_turn";
|
|
5611
|
-
let usage = { input_tokens:
|
|
5689
|
+
let usage = { input_tokens: estimatedInputTokens, output_tokens: 0 };
|
|
5612
5690
|
const emit = (event, data) => write(sseChunk(event, data));
|
|
5613
5691
|
const ensureStart = () => {
|
|
5614
5692
|
if (started) return;
|
|
@@ -5622,7 +5700,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5622
5700
|
model: modelId,
|
|
5623
5701
|
stop_reason: null,
|
|
5624
5702
|
stop_sequence: null,
|
|
5625
|
-
usage: { input_tokens:
|
|
5703
|
+
usage: { input_tokens: estimatedInputTokens, output_tokens: 0 }
|
|
5626
5704
|
}
|
|
5627
5705
|
});
|
|
5628
5706
|
started = true;
|
|
@@ -5721,7 +5799,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5721
5799
|
case "finish":
|
|
5722
5800
|
if (part.totalUsage) {
|
|
5723
5801
|
usage = {
|
|
5724
|
-
input_tokens: part.totalUsage.inputTokens ??
|
|
5802
|
+
input_tokens: part.totalUsage.inputTokens ?? estimatedInputTokens,
|
|
5725
5803
|
output_tokens: part.totalUsage.outputTokens ?? 0
|
|
5726
5804
|
};
|
|
5727
5805
|
}
|
|
@@ -5747,7 +5825,7 @@ async function writeAnthropicStream(fullStream, modelId, write, log7) {
|
|
|
5747
5825
|
emit("message_delta", { type: "message_delta", delta: { stop_reason: finishReason, stop_sequence: null }, usage });
|
|
5748
5826
|
emit("message_stop", { type: "message_stop" });
|
|
5749
5827
|
}
|
|
5750
|
-
async function streamAnthropicResponse(model, params, modelId, write, log7) {
|
|
5828
|
+
async function streamAnthropicResponse(model, params, modelId, write, log7, estimatedInputTokens = 0) {
|
|
5751
5829
|
const result = streamText({ model, ...params, onError: () => {
|
|
5752
5830
|
} });
|
|
5753
5831
|
Promise.resolve(result.text).catch(() => {
|
|
@@ -5760,7 +5838,13 @@ async function streamAnthropicResponse(model, params, modelId, write, log7) {
|
|
|
5760
5838
|
});
|
|
5761
5839
|
Promise.resolve(result.usage).catch(() => {
|
|
5762
5840
|
});
|
|
5763
|
-
await writeAnthropicStream(
|
|
5841
|
+
await writeAnthropicStream(
|
|
5842
|
+
result.fullStream,
|
|
5843
|
+
modelId,
|
|
5844
|
+
write,
|
|
5845
|
+
log7,
|
|
5846
|
+
estimatedInputTokens
|
|
5847
|
+
);
|
|
5764
5848
|
}
|
|
5765
5849
|
async function generateAnthropicResponse(model, params, modelId, options) {
|
|
5766
5850
|
let text4;
|
|
@@ -5965,6 +6049,7 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
|
|
|
5965
6049
|
const params = translateRequest2(anthropicBody, route.npm, {
|
|
5966
6050
|
openAiOAuth,
|
|
5967
6051
|
maxTools: maxToolsForNpm(route.npm),
|
|
6052
|
+
onDebug: (msg) => plog(() => msg),
|
|
5968
6053
|
reasoningMetadata: {
|
|
5969
6054
|
providerId: route.providerId,
|
|
5970
6055
|
apiBaseUrl: route.baseURL,
|
|
@@ -5998,7 +6083,14 @@ function startProxyCatalog(routes, defaultAliasId, debug = false) {
|
|
|
5998
6083
|
"Cache-Control": "no-cache",
|
|
5999
6084
|
"Connection": "keep-alive"
|
|
6000
6085
|
});
|
|
6001
|
-
await streamAnthropicResponse(
|
|
6086
|
+
await streamAnthropicResponse(
|
|
6087
|
+
model,
|
|
6088
|
+
params,
|
|
6089
|
+
originalModel,
|
|
6090
|
+
(c) => res.write(c),
|
|
6091
|
+
plog,
|
|
6092
|
+
estimateAnthropicInputTokens(anthropicBody)
|
|
6093
|
+
);
|
|
6002
6094
|
res.end();
|
|
6003
6095
|
} else {
|
|
6004
6096
|
const anthropicResponse = await generateAnthropicResponse(
|
|
@@ -9870,6 +9962,7 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
9870
9962
|
const params = translateRequest2(body, model.npm, {
|
|
9871
9963
|
defaultEffort: anthropicEffortFromRequest(body) ? void 0 : model.defaultEffort,
|
|
9872
9964
|
openAiOAuth: model.npm === "@ai-sdk/openai" && model.authType === "oauth",
|
|
9965
|
+
onDebug: plog,
|
|
9873
9966
|
reasoningMetadata: {
|
|
9874
9967
|
providerId: model.providerId,
|
|
9875
9968
|
apiBaseUrl: model.apiBaseUrl,
|
|
@@ -9890,7 +9983,14 @@ async function handleAnthropicMessages(req, res, options, modelCache, plog) {
|
|
|
9890
9983
|
"Cache-Control": "no-cache",
|
|
9891
9984
|
"Connection": "keep-alive"
|
|
9892
9985
|
});
|
|
9893
|
-
await streamAnthropicResponse(
|
|
9986
|
+
await streamAnthropicResponse(
|
|
9987
|
+
languageModel,
|
|
9988
|
+
params,
|
|
9989
|
+
responseModelId,
|
|
9990
|
+
(chunk) => res.write(chunk),
|
|
9991
|
+
void 0,
|
|
9992
|
+
estimateAnthropicInputTokens(body)
|
|
9993
|
+
);
|
|
9894
9994
|
res.end();
|
|
9895
9995
|
} else {
|
|
9896
9996
|
const anthropicResponse = await generateAnthropicResponse(languageModel, params, responseModelId);
|
|
@@ -11818,6 +11918,8 @@ export {
|
|
|
11818
11918
|
setServerFreeModelsOnly,
|
|
11819
11919
|
getServerListenMode,
|
|
11820
11920
|
setServerListenMode,
|
|
11921
|
+
setServerAutostart,
|
|
11922
|
+
resolveServerAutostart,
|
|
11821
11923
|
findBinaryOnPath,
|
|
11822
11924
|
findClaudeBinary,
|
|
11823
11925
|
launchClaude,
|
|
@@ -11891,6 +11993,9 @@ export {
|
|
|
11891
11993
|
openAiIdCollisions,
|
|
11892
11994
|
createGatewayModelCatalog,
|
|
11893
11995
|
buildDedupedModelRows,
|
|
11996
|
+
anthropicModelsEndpoint,
|
|
11997
|
+
anthropicMessagesEndpoint,
|
|
11998
|
+
estimateAnthropicInputTokens,
|
|
11894
11999
|
grabRoundTripSignature,
|
|
11895
12000
|
silenceSdkWarnings,
|
|
11896
12001
|
parseToolArguments,
|
|
@@ -11966,4 +12071,4 @@ export {
|
|
|
11966
12071
|
supportsClaudeTransparentMode,
|
|
11967
12072
|
buildHttpProxyRoutes
|
|
11968
12073
|
};
|
|
11969
|
-
//# sourceMappingURL=chunk-
|
|
12074
|
+
//# sourceMappingURL=chunk-EUY2MVOS.js.map
|