open-agents-ai 0.184.44 → 0.184.45
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/index.js +191 -96
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -672,20 +672,20 @@ var init_VllmBackend = __esm({
|
|
|
672
672
|
// -------------------------------------------------------------------------
|
|
673
673
|
// LLMBackend — complete
|
|
674
674
|
// -------------------------------------------------------------------------
|
|
675
|
-
async complete(
|
|
676
|
-
const messages =
|
|
675
|
+
async complete(request) {
|
|
676
|
+
const messages = request.messages.map(agentMessageToChatMessage);
|
|
677
677
|
const body = {
|
|
678
678
|
model: this.model,
|
|
679
679
|
messages,
|
|
680
|
-
temperature:
|
|
681
|
-
max_tokens:
|
|
680
|
+
temperature: request.temperature ?? 0,
|
|
681
|
+
max_tokens: request.maxTokens ?? 4096
|
|
682
682
|
};
|
|
683
|
-
if (
|
|
684
|
-
body.tools =
|
|
683
|
+
if (request.tools && request.tools.length > 0) {
|
|
684
|
+
body.tools = request.tools;
|
|
685
685
|
body.tool_choice = "auto";
|
|
686
686
|
}
|
|
687
|
-
if (
|
|
688
|
-
body.response_format =
|
|
687
|
+
if (request.responseFormat) {
|
|
688
|
+
body.response_format = request.responseFormat;
|
|
689
689
|
}
|
|
690
690
|
const start = Date.now();
|
|
691
691
|
const rawResponse = await this.postWithRetry("/v1/chat/completions", body);
|
|
@@ -822,24 +822,24 @@ var init_OllamaBackend = __esm({
|
|
|
822
822
|
// -------------------------------------------------------------------------
|
|
823
823
|
// LLMBackend — complete
|
|
824
824
|
// -------------------------------------------------------------------------
|
|
825
|
-
async complete(
|
|
826
|
-
const messages =
|
|
825
|
+
async complete(request) {
|
|
826
|
+
const messages = request.messages.map(agentMessageToChatMessage2);
|
|
827
827
|
const body = {
|
|
828
828
|
model: this.model,
|
|
829
829
|
messages,
|
|
830
|
-
temperature:
|
|
831
|
-
max_tokens:
|
|
830
|
+
temperature: request.temperature ?? 0,
|
|
831
|
+
max_tokens: request.maxTokens ?? 4096,
|
|
832
832
|
// Disable Qwen thinking mode by default so tokens go to content,
|
|
833
833
|
// not reasoning. The model still produces good output without it
|
|
834
834
|
// and coding agents need structured JSON in the content field.
|
|
835
835
|
think: false
|
|
836
836
|
};
|
|
837
|
-
if (
|
|
838
|
-
body.tools =
|
|
837
|
+
if (request.tools && request.tools.length > 0) {
|
|
838
|
+
body.tools = request.tools;
|
|
839
839
|
body.tool_choice = "auto";
|
|
840
840
|
}
|
|
841
|
-
if (
|
|
842
|
-
body.response_format =
|
|
841
|
+
if (request.responseFormat) {
|
|
842
|
+
body.response_format = request.responseFormat;
|
|
843
843
|
}
|
|
844
844
|
const start = Date.now();
|
|
845
845
|
const rawResponse = await this.postWithRetry("/v1/chat/completions", body);
|
|
@@ -1003,19 +1003,19 @@ var init_FakeBackend = __esm({
|
|
|
1003
1003
|
this._healthCheckCount++;
|
|
1004
1004
|
return this.options.healthy;
|
|
1005
1005
|
}
|
|
1006
|
-
async complete(
|
|
1006
|
+
async complete(request) {
|
|
1007
1007
|
this._completeCount++;
|
|
1008
1008
|
if (this.options.shouldThrow) {
|
|
1009
1009
|
throw new Error(this.options.errorMessage);
|
|
1010
1010
|
}
|
|
1011
|
-
const lastMessage =
|
|
1011
|
+
const lastMessage = request.messages[request.messages.length - 1];
|
|
1012
1012
|
const inputKey = lastMessage ? `${lastMessage.role}:${lastMessage.content}` : "empty";
|
|
1013
1013
|
const hash = fnv1a32(inputKey);
|
|
1014
1014
|
const deterministicContent = `fake-response-${hash.toString(16).padStart(8, "0")}`;
|
|
1015
1015
|
const usage = {
|
|
1016
|
-
prompt_tokens:
|
|
1016
|
+
prompt_tokens: request.messages.length * 10,
|
|
1017
1017
|
completion_tokens: 20,
|
|
1018
|
-
total_tokens:
|
|
1018
|
+
total_tokens: request.messages.length * 10 + 20
|
|
1019
1019
|
};
|
|
1020
1020
|
if (this.options.toolCallResponses.length > 0) {
|
|
1021
1021
|
return {
|
|
@@ -11711,13 +11711,13 @@ Validation: ${validation.pass ? "PASS" : "NEEDS IMPROVEMENT"} (${validation.over
|
|
|
11711
11711
|
// -------------------------------------------------------------------------
|
|
11712
11712
|
// Phase 1: Seed Analysis
|
|
11713
11713
|
// -------------------------------------------------------------------------
|
|
11714
|
-
async analyzeSeed(
|
|
11714
|
+
async analyzeSeed(request) {
|
|
11715
11715
|
const prompt = loadBuilderPrompt("seed-analysis.md", {
|
|
11716
|
-
skill_request:
|
|
11716
|
+
skill_request: request
|
|
11717
11717
|
});
|
|
11718
11718
|
const response = await this.llmCall([
|
|
11719
11719
|
{ role: "system", content: prompt },
|
|
11720
|
-
{ role: "user", content: `Analyze this skill request: "${
|
|
11720
|
+
{ role: "user", content: `Analyze this skill request: "${request}"` }
|
|
11721
11721
|
]);
|
|
11722
11722
|
const jsonStr = extractJSON(response);
|
|
11723
11723
|
const seed = JSON.parse(jsonStr);
|
|
@@ -24287,22 +24287,22 @@ var init_snippetPacker = __esm({
|
|
|
24287
24287
|
});
|
|
24288
24288
|
|
|
24289
24289
|
// packages/retrieval/dist/contextAssembler.js
|
|
24290
|
-
async function assembleContext(
|
|
24290
|
+
async function assembleContext(request, opts) {
|
|
24291
24291
|
const { repoRoot, graph, semanticEngine, summaryMap, maxFiles = 8, maxSnippets = 20, maxLogs = 3, maxTokens = 24e3, expandNeighbors = true, architectureNote, priorAttemptNote } = opts;
|
|
24292
24292
|
const lexOpts = {
|
|
24293
24293
|
rootDir: repoRoot,
|
|
24294
24294
|
includePatterns: [],
|
|
24295
|
-
includeTests:
|
|
24296
|
-
includeConfigs:
|
|
24295
|
+
includeTests: request.includeTests,
|
|
24296
|
+
includeConfigs: request.includeConfigs,
|
|
24297
24297
|
maxMatches: 30
|
|
24298
24298
|
};
|
|
24299
24299
|
const [pathMatches, symbolMatches, errorMatches, semanticResults] = await Promise.all([
|
|
24300
|
-
Promise.all(
|
|
24301
|
-
Promise.all(
|
|
24302
|
-
Promise.all(
|
|
24303
|
-
semanticEngine?.isAvailable ? semanticEngine.search(
|
|
24300
|
+
Promise.all(request.pathsHint.map((p) => searchByPath(p, { rootDir: repoRoot, maxMatches: 10 }))).then((res) => res.flat()),
|
|
24301
|
+
Promise.all(request.symbolHint.map((s) => searchBySymbol(s, { rootDir: repoRoot, maxMatches: 10 }))).then((res) => res.flat()),
|
|
24302
|
+
Promise.all(request.errorHint.slice(0, maxLogs).map((e) => searchByError(e, { rootDir: repoRoot, maxMatches: 5 }))).then((res) => res.flat()),
|
|
24303
|
+
semanticEngine?.isAvailable ? semanticEngine.search(request.query, maxFiles) : Promise.resolve([])
|
|
24304
24304
|
]);
|
|
24305
|
-
const queryType = classifyQuery(
|
|
24305
|
+
const queryType = classifyQuery(request.query);
|
|
24306
24306
|
const rrfK = adaptiveK(queryType, opts.rrfConfig?.k);
|
|
24307
24307
|
const wFts = opts.rrfConfig?.weightFts ?? 1;
|
|
24308
24308
|
const wSem = opts.rrfConfig?.weightSemantic ?? 1;
|
|
@@ -24373,7 +24373,7 @@ async function assembleContext(request2, opts) {
|
|
|
24373
24373
|
}
|
|
24374
24374
|
}
|
|
24375
24375
|
return {
|
|
24376
|
-
request
|
|
24376
|
+
request,
|
|
24377
24377
|
files,
|
|
24378
24378
|
snippets: packed.slice(0, maxSnippets),
|
|
24379
24379
|
architectureNote,
|
|
@@ -28232,14 +28232,14 @@ ${transcript}`
|
|
|
28232
28232
|
* assembles and returns the same response format as chatCompletion().
|
|
28233
28233
|
* The non-streaming chatCompletion path is NEVER touched by this code.
|
|
28234
28234
|
*/
|
|
28235
|
-
async streamingRequest(
|
|
28235
|
+
async streamingRequest(request, turn) {
|
|
28236
28236
|
const backend = this.backend;
|
|
28237
28237
|
let content = "";
|
|
28238
28238
|
let inThinkTag = false;
|
|
28239
28239
|
const toolCallAccumulators = /* @__PURE__ */ new Map();
|
|
28240
28240
|
let streamUsage;
|
|
28241
28241
|
this.emit({ type: "stream_start", turn, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
28242
|
-
for await (const chunk of backend.chatCompletionStream(
|
|
28242
|
+
for await (const chunk of backend.chatCompletionStream(request)) {
|
|
28243
28243
|
if (this.aborted)
|
|
28244
28244
|
break;
|
|
28245
28245
|
if (chunk.type === "usage" && chunk.usage) {
|
|
@@ -28349,13 +28349,13 @@ ${transcript}`
|
|
|
28349
28349
|
}
|
|
28350
28350
|
return headers;
|
|
28351
28351
|
}
|
|
28352
|
-
async chatCompletion(
|
|
28352
|
+
async chatCompletion(request) {
|
|
28353
28353
|
const body = {
|
|
28354
28354
|
model: this.model,
|
|
28355
|
-
messages:
|
|
28356
|
-
tools:
|
|
28357
|
-
temperature:
|
|
28358
|
-
max_tokens:
|
|
28355
|
+
messages: request.messages,
|
|
28356
|
+
tools: request.tools,
|
|
28357
|
+
temperature: request.temperature,
|
|
28358
|
+
max_tokens: request.maxTokens,
|
|
28359
28359
|
think: this.thinking
|
|
28360
28360
|
};
|
|
28361
28361
|
const fetchOpts = {
|
|
@@ -28412,13 +28412,13 @@ ${transcript}`
|
|
|
28412
28412
|
* Uses `stream: true` and the current thinking setting.
|
|
28413
28413
|
* The existing chatCompletion() method is completely unmodified.
|
|
28414
28414
|
*/
|
|
28415
|
-
async *chatCompletionStream(
|
|
28415
|
+
async *chatCompletionStream(request) {
|
|
28416
28416
|
const body = {
|
|
28417
28417
|
model: this.model,
|
|
28418
|
-
messages:
|
|
28419
|
-
tools:
|
|
28420
|
-
temperature:
|
|
28421
|
-
max_tokens:
|
|
28418
|
+
messages: request.messages,
|
|
28419
|
+
tools: request.tools,
|
|
28420
|
+
temperature: request.temperature,
|
|
28421
|
+
max_tokens: request.maxTokens,
|
|
28422
28422
|
stream: true,
|
|
28423
28423
|
stream_options: { include_usage: true },
|
|
28424
28424
|
think: this.thinking
|
|
@@ -28538,7 +28538,7 @@ var init_nexusBackend = __esm({
|
|
|
28538
28538
|
this.targetPeer = peerId;
|
|
28539
28539
|
this.consecutiveFailures = 0;
|
|
28540
28540
|
}
|
|
28541
|
-
async chatCompletion(
|
|
28541
|
+
async chatCompletion(request) {
|
|
28542
28542
|
if (this.consecutiveFailures >= _NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES) {
|
|
28543
28543
|
const err = new Error(`Remote peer unreachable after ${this.consecutiveFailures} attempts. Use /endpoint to switch to a local model or reconnect.`);
|
|
28544
28544
|
err.fatal = true;
|
|
@@ -28546,10 +28546,10 @@ var init_nexusBackend = __esm({
|
|
|
28546
28546
|
}
|
|
28547
28547
|
const daemonArgs = {
|
|
28548
28548
|
model: this.model,
|
|
28549
|
-
messages: JSON.stringify(
|
|
28550
|
-
tools: JSON.stringify(
|
|
28551
|
-
temperature: String(
|
|
28552
|
-
max_tokens: String(
|
|
28549
|
+
messages: JSON.stringify(request.messages),
|
|
28550
|
+
tools: JSON.stringify(request.tools),
|
|
28551
|
+
temperature: String(request.temperature),
|
|
28552
|
+
max_tokens: String(request.maxTokens)
|
|
28553
28553
|
};
|
|
28554
28554
|
if (this.targetPeer) {
|
|
28555
28555
|
daemonArgs.target_peer = this.targetPeer;
|
|
@@ -28560,7 +28560,7 @@ var init_nexusBackend = __esm({
|
|
|
28560
28560
|
daemonArgs.think = String(this.thinking);
|
|
28561
28561
|
let rawResult;
|
|
28562
28562
|
try {
|
|
28563
|
-
rawResult = await this.sendFn("remote_infer", daemonArgs,
|
|
28563
|
+
rawResult = await this.sendFn("remote_infer", daemonArgs, request.timeoutMs || 12e4);
|
|
28564
28564
|
} catch (sendErr) {
|
|
28565
28565
|
this.consecutiveFailures++;
|
|
28566
28566
|
throw sendErr;
|
|
@@ -28653,15 +28653,15 @@ var init_nexusBackend = __esm({
|
|
|
28653
28653
|
* the file for token-by-token delivery from the remote peer.
|
|
28654
28654
|
* Falls back to unary + word-split if streaming setup fails.
|
|
28655
28655
|
*/
|
|
28656
|
-
async *chatCompletionStream(
|
|
28656
|
+
async *chatCompletionStream(request) {
|
|
28657
28657
|
const streamFile = join47(tmpdir7(), `nexus-stream-${randomBytes11(6).toString("hex")}.jsonl`);
|
|
28658
28658
|
writeFileSync11(streamFile, "", "utf8");
|
|
28659
28659
|
const daemonArgs = {
|
|
28660
28660
|
model: this.model,
|
|
28661
|
-
messages: JSON.stringify(
|
|
28662
|
-
tools: JSON.stringify(
|
|
28663
|
-
temperature: String(
|
|
28664
|
-
max_tokens: String(
|
|
28661
|
+
messages: JSON.stringify(request.messages),
|
|
28662
|
+
tools: JSON.stringify(request.tools),
|
|
28663
|
+
temperature: String(request.temperature),
|
|
28664
|
+
max_tokens: String(request.maxTokens),
|
|
28665
28665
|
stream_file: streamFile
|
|
28666
28666
|
};
|
|
28667
28667
|
if (this.targetPeer)
|
|
@@ -28671,7 +28671,7 @@ var init_nexusBackend = __esm({
|
|
|
28671
28671
|
daemonArgs.think = String(this.thinking);
|
|
28672
28672
|
let rawResult;
|
|
28673
28673
|
try {
|
|
28674
|
-
rawResult = await this.sendFn("remote_infer", daemonArgs,
|
|
28674
|
+
rawResult = await this.sendFn("remote_infer", daemonArgs, request.timeoutMs || 12e4);
|
|
28675
28675
|
} catch (sendErr) {
|
|
28676
28676
|
this.consecutiveFailures++;
|
|
28677
28677
|
try {
|
|
@@ -28744,7 +28744,7 @@ var init_nexusBackend = __esm({
|
|
|
28744
28744
|
this.consecutiveFailures = 0;
|
|
28745
28745
|
let position = 0;
|
|
28746
28746
|
let done = false;
|
|
28747
|
-
const deadline = Date.now() + (
|
|
28747
|
+
const deadline = Date.now() + (request.timeoutMs ?? 12e4);
|
|
28748
28748
|
try {
|
|
28749
28749
|
while (!done && Date.now() < deadline) {
|
|
28750
28750
|
await new Promise((resolve36) => {
|
|
@@ -28917,10 +28917,10 @@ var init_cascadeBackend = __esm({
|
|
|
28917
28917
|
get fallbackCount() {
|
|
28918
28918
|
return this.endpoints.filter((ep, i) => i !== this.activeIndex && ep.modelAvailable !== false).length;
|
|
28919
28919
|
}
|
|
28920
|
-
async chatCompletion(
|
|
28920
|
+
async chatCompletion(request) {
|
|
28921
28921
|
const backend = this.getActiveBackend();
|
|
28922
28922
|
try {
|
|
28923
|
-
const result = await backend.chatCompletion(
|
|
28923
|
+
const result = await backend.chatCompletion(request);
|
|
28924
28924
|
this.consecutiveFailures = 0;
|
|
28925
28925
|
return result;
|
|
28926
28926
|
} catch (err) {
|
|
@@ -28936,7 +28936,7 @@ var init_cascadeBackend = __esm({
|
|
|
28936
28936
|
this.onSwitch?.(from, to, reason);
|
|
28937
28937
|
const newBackend = this.getActiveBackend();
|
|
28938
28938
|
try {
|
|
28939
|
-
const result = await newBackend.chatCompletion(
|
|
28939
|
+
const result = await newBackend.chatCompletion(request);
|
|
28940
28940
|
return result;
|
|
28941
28941
|
} catch (cascadeErr) {
|
|
28942
28942
|
this.consecutiveFailures++;
|
|
@@ -28950,11 +28950,11 @@ var init_cascadeBackend = __esm({
|
|
|
28950
28950
|
/**
|
|
28951
28951
|
* Streaming support — delegates to active backend's stream method if available.
|
|
28952
28952
|
*/
|
|
28953
|
-
async *chatCompletionStream(
|
|
28953
|
+
async *chatCompletionStream(request) {
|
|
28954
28954
|
const backend = this.getActiveBackend();
|
|
28955
28955
|
const streamable = backend;
|
|
28956
28956
|
if (typeof streamable.chatCompletionStream !== "function") {
|
|
28957
|
-
const result = await this.chatCompletion(
|
|
28957
|
+
const result = await this.chatCompletion(request);
|
|
28958
28958
|
const choice = result.choices[0];
|
|
28959
28959
|
if (choice?.message.content) {
|
|
28960
28960
|
yield { type: "content", content: choice.message.content };
|
|
@@ -28985,7 +28985,7 @@ var init_cascadeBackend = __esm({
|
|
|
28985
28985
|
return;
|
|
28986
28986
|
}
|
|
28987
28987
|
try {
|
|
28988
|
-
for await (const chunk of streamable.chatCompletionStream(
|
|
28988
|
+
for await (const chunk of streamable.chatCompletionStream(request)) {
|
|
28989
28989
|
yield chunk;
|
|
28990
28990
|
}
|
|
28991
28991
|
this.consecutiveFailures = 0;
|
|
@@ -28999,7 +28999,7 @@ var init_cascadeBackend = __esm({
|
|
|
28999
28999
|
this.activeIndex = nextIdx;
|
|
29000
29000
|
this.consecutiveFailures = 0;
|
|
29001
29001
|
this.onSwitch?.(from, to, err instanceof Error ? err.message : String(err));
|
|
29002
|
-
const result = await this.chatCompletion(
|
|
29002
|
+
const result = await this.chatCompletion(request);
|
|
29003
29003
|
const choice = result.choices[0];
|
|
29004
29004
|
if (choice?.message.content) {
|
|
29005
29005
|
yield { type: "content", content: choice.message.content };
|
|
@@ -32596,7 +32596,7 @@ var require_websocket = __commonJS({
|
|
|
32596
32596
|
"node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
32597
32597
|
"use strict";
|
|
32598
32598
|
var EventEmitter7 = __require("events");
|
|
32599
|
-
var
|
|
32599
|
+
var https2 = __require("https");
|
|
32600
32600
|
var http2 = __require("http");
|
|
32601
32601
|
var net = __require("net");
|
|
32602
32602
|
var tls = __require("tls");
|
|
@@ -33131,7 +33131,7 @@ var require_websocket = __commonJS({
|
|
|
33131
33131
|
}
|
|
33132
33132
|
const defaultPort = isSecure ? 443 : 80;
|
|
33133
33133
|
const key = randomBytes18(16).toString("base64");
|
|
33134
|
-
const
|
|
33134
|
+
const request = isSecure ? https2.request : http2.request;
|
|
33135
33135
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
33136
33136
|
let perMessageDeflate;
|
|
33137
33137
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -33208,12 +33208,12 @@ var require_websocket = __commonJS({
|
|
|
33208
33208
|
if (opts.auth && !options.headers.authorization) {
|
|
33209
33209
|
options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
|
|
33210
33210
|
}
|
|
33211
|
-
req = websocket._req =
|
|
33211
|
+
req = websocket._req = request(opts);
|
|
33212
33212
|
if (websocket._redirects) {
|
|
33213
33213
|
websocket.emit("redirect", websocket.url, req);
|
|
33214
33214
|
}
|
|
33215
33215
|
} else {
|
|
33216
|
-
req = websocket._req =
|
|
33216
|
+
req = websocket._req = request(opts);
|
|
33217
33217
|
}
|
|
33218
33218
|
if (opts.timeout) {
|
|
33219
33219
|
req.on("timeout", () => {
|
|
@@ -37601,7 +37601,7 @@ var init_peer_mesh = __esm({
|
|
|
37601
37601
|
* Send an inference request to a specific peer.
|
|
37602
37602
|
* Returns a promise that resolves when the response arrives.
|
|
37603
37603
|
*/
|
|
37604
|
-
async requestInference(peerId,
|
|
37604
|
+
async requestInference(peerId, request, timeoutMs = 12e4) {
|
|
37605
37605
|
const ws = this.connections.get(peerId);
|
|
37606
37606
|
if (!ws || ws.readyState !== import_websocket.default.OPEN) {
|
|
37607
37607
|
throw new Error(`Peer ${peerId} not connected`);
|
|
@@ -37613,7 +37613,7 @@ var init_peer_mesh = __esm({
|
|
|
37613
37613
|
reject(new Error(`Inference timeout (${timeoutMs}ms)`));
|
|
37614
37614
|
}, timeoutMs);
|
|
37615
37615
|
this.pendingRequests.set(msgId, { resolve: resolve36, reject, timeout, chunks: [] });
|
|
37616
|
-
this.sendMsg(ws, "infer_request",
|
|
37616
|
+
this.sendMsg(ws, "infer_request", request, msgId);
|
|
37617
37617
|
});
|
|
37618
37618
|
}
|
|
37619
37619
|
// ── Inbound connection handling ─────────────────────────────────────────
|
|
@@ -37955,7 +37955,7 @@ var init_inference_router = __esm({
|
|
|
37955
37955
|
}
|
|
37956
37956
|
}));
|
|
37957
37957
|
}
|
|
37958
|
-
const
|
|
37958
|
+
const request = {
|
|
37959
37959
|
model,
|
|
37960
37960
|
messages: redactedMessages,
|
|
37961
37961
|
tools: redactedTools,
|
|
@@ -37968,7 +37968,7 @@ var init_inference_router = __esm({
|
|
|
37968
37968
|
if (redactedCount > 0)
|
|
37969
37969
|
this._totalRedacted++;
|
|
37970
37970
|
try {
|
|
37971
|
-
const response = await this.mesh.requestInference(peer.peerId,
|
|
37971
|
+
const response = await this.mesh.requestInference(peer.peerId, request, options?.timeoutMs ?? this.defaultTimeoutMs);
|
|
37972
37972
|
const injectedContent = this.vault.inject(response.content);
|
|
37973
37973
|
const injectedToolCalls = response.toolCalls?.map((tc) => ({
|
|
37974
37974
|
...tc,
|
|
@@ -38001,8 +38001,8 @@ var init_inference_router = __esm({
|
|
|
38001
38001
|
* The response text may contain placeholders from the requester's vault,
|
|
38002
38002
|
* which is fine — we don't have their secrets and don't need them.
|
|
38003
38003
|
*/
|
|
38004
|
-
async handleInboundRequest(
|
|
38005
|
-
for (const msg of
|
|
38004
|
+
async handleInboundRequest(request, inferFn) {
|
|
38005
|
+
for (const msg of request.messages) {
|
|
38006
38006
|
const found = this.vault.scan(msg.content);
|
|
38007
38007
|
if (found.length > 0) {
|
|
38008
38008
|
this.emit("leaked_secrets_detected", {
|
|
@@ -38011,7 +38011,7 @@ var init_inference_router = __esm({
|
|
|
38011
38011
|
});
|
|
38012
38012
|
}
|
|
38013
38013
|
}
|
|
38014
|
-
return inferFn(
|
|
38014
|
+
return inferFn(request);
|
|
38015
38015
|
}
|
|
38016
38016
|
// ── Scoring ────────────────────────────────────────────────────────────
|
|
38017
38017
|
scoreRoute(peer, model) {
|
|
@@ -61892,6 +61892,7 @@ __export(serve_exports, {
|
|
|
61892
61892
|
startApiServer: () => startApiServer
|
|
61893
61893
|
});
|
|
61894
61894
|
import * as http from "node:http";
|
|
61895
|
+
import * as https from "node:https";
|
|
61895
61896
|
import { createRequire as createRequire2 } from "node:module";
|
|
61896
61897
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
61897
61898
|
import { dirname as dirname20, join as join69, resolve as resolve31 } from "node:path";
|
|
@@ -61977,20 +61978,29 @@ async function parseJsonBody(req) {
|
|
|
61977
61978
|
return null;
|
|
61978
61979
|
}
|
|
61979
61980
|
}
|
|
61981
|
+
function backendAuthHeaders() {
|
|
61982
|
+
const config = loadConfig();
|
|
61983
|
+
if (config.apiKey)
|
|
61984
|
+
return { Authorization: `Bearer ${config.apiKey}` };
|
|
61985
|
+
return {};
|
|
61986
|
+
}
|
|
61980
61987
|
function ollamaRequest(ollamaUrl, path, method, body) {
|
|
61981
61988
|
return new Promise((resolve36, reject) => {
|
|
61982
61989
|
const url = new URL(path, ollamaUrl);
|
|
61990
|
+
const isHttps = url.protocol === "https:";
|
|
61983
61991
|
const options = {
|
|
61984
61992
|
hostname: url.hostname,
|
|
61985
|
-
port: url.port,
|
|
61993
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
61986
61994
|
path: url.pathname + url.search,
|
|
61987
61995
|
method,
|
|
61988
61996
|
headers: {
|
|
61989
61997
|
"Content-Type": "application/json",
|
|
61990
|
-
...body ? { "Content-Length": Buffer.byteLength(body) } : {}
|
|
61998
|
+
...body ? { "Content-Length": Buffer.byteLength(body) } : {},
|
|
61999
|
+
...backendAuthHeaders()
|
|
61991
62000
|
}
|
|
61992
62001
|
};
|
|
61993
|
-
const
|
|
62002
|
+
const transport = isHttps ? https : http;
|
|
62003
|
+
const proxyReq = transport.request(options, (proxyRes) => {
|
|
61994
62004
|
const chunks = [];
|
|
61995
62005
|
proxyRes.on("data", (chunk) => chunks.push(chunk));
|
|
61996
62006
|
proxyRes.on("end", () => {
|
|
@@ -62012,17 +62022,20 @@ function ollamaRequest(ollamaUrl, path, method, body) {
|
|
|
62012
62022
|
}
|
|
62013
62023
|
function ollamaStream(ollamaUrl, path, method, body, onData, onEnd, onError) {
|
|
62014
62024
|
const url = new URL(path, ollamaUrl);
|
|
62025
|
+
const isHttps = url.protocol === "https:";
|
|
62015
62026
|
const options = {
|
|
62016
62027
|
hostname: url.hostname,
|
|
62017
|
-
port: url.port,
|
|
62028
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
62018
62029
|
path: url.pathname + url.search,
|
|
62019
62030
|
method,
|
|
62020
62031
|
headers: {
|
|
62021
62032
|
"Content-Type": "application/json",
|
|
62022
|
-
...body ? { "Content-Length": Buffer.byteLength(body) } : {}
|
|
62033
|
+
...body ? { "Content-Length": Buffer.byteLength(body) } : {},
|
|
62034
|
+
...backendAuthHeaders()
|
|
62023
62035
|
}
|
|
62024
62036
|
};
|
|
62025
|
-
const
|
|
62037
|
+
const transport = isHttps ? https : http;
|
|
62038
|
+
const proxyReq = transport.request(options, (proxyRes) => {
|
|
62026
62039
|
proxyRes.setEncoding("utf-8");
|
|
62027
62040
|
proxyRes.on("data", onData);
|
|
62028
62041
|
proxyRes.on("end", onEnd);
|
|
@@ -62117,14 +62130,17 @@ function handleHealth(res) {
|
|
|
62117
62130
|
}
|
|
62118
62131
|
async function handleHealthReady(res, ollamaUrl) {
|
|
62119
62132
|
try {
|
|
62120
|
-
const
|
|
62133
|
+
const config = loadConfig();
|
|
62134
|
+
const isVllm = config.backendType === "vllm";
|
|
62135
|
+
const checkPath = isVllm ? "/v1/models" : "/api/tags";
|
|
62136
|
+
const result = await ollamaRequest(ollamaUrl, checkPath, "GET");
|
|
62121
62137
|
if (result.status === 200) {
|
|
62122
|
-
jsonResponse(res, 200, { status: "ready",
|
|
62138
|
+
jsonResponse(res, 200, { status: "ready", backend: "reachable", type: config.backendType || "ollama" });
|
|
62123
62139
|
} else {
|
|
62124
|
-
jsonResponse(res, 503, { status: "not_ready",
|
|
62140
|
+
jsonResponse(res, 503, { status: "not_ready", backend: "unreachable", code: result.status });
|
|
62125
62141
|
}
|
|
62126
62142
|
} catch {
|
|
62127
|
-
jsonResponse(res, 503, { status: "not_ready",
|
|
62143
|
+
jsonResponse(res, 503, { status: "not_ready", backend: "unreachable" });
|
|
62128
62144
|
}
|
|
62129
62145
|
}
|
|
62130
62146
|
function handleHealthStartup(res) {
|
|
@@ -62143,9 +62159,20 @@ function handleMetrics(res) {
|
|
|
62143
62159
|
}
|
|
62144
62160
|
async function handleV1Models(res, ollamaUrl) {
|
|
62145
62161
|
try {
|
|
62162
|
+
const config = loadConfig();
|
|
62163
|
+
const isVllm = config.backendType === "vllm";
|
|
62164
|
+
if (isVllm) {
|
|
62165
|
+
const result2 = await ollamaRequest(ollamaUrl, "/v1/models", "GET");
|
|
62166
|
+
if (result2.status !== 200) {
|
|
62167
|
+
jsonResponse(res, result2.status, { error: "Failed to fetch models from backend" });
|
|
62168
|
+
return;
|
|
62169
|
+
}
|
|
62170
|
+
jsonResponse(res, 200, JSON.parse(result2.body));
|
|
62171
|
+
return;
|
|
62172
|
+
}
|
|
62146
62173
|
const result = await ollamaRequest(ollamaUrl, "/api/tags", "GET");
|
|
62147
62174
|
if (result.status !== 200) {
|
|
62148
|
-
jsonResponse(res, result.status, { error: "Failed to fetch models from
|
|
62175
|
+
jsonResponse(res, result.status, { error: "Failed to fetch models from backend" });
|
|
62149
62176
|
return;
|
|
62150
62177
|
}
|
|
62151
62178
|
const ollamaBody = JSON.parse(result.body);
|
|
@@ -62158,7 +62185,7 @@ async function handleV1Models(res, ollamaUrl) {
|
|
|
62158
62185
|
jsonResponse(res, 200, { object: "list", data: models });
|
|
62159
62186
|
} catch (err) {
|
|
62160
62187
|
jsonResponse(res, 502, {
|
|
62161
|
-
error: "Failed to proxy to
|
|
62188
|
+
error: "Failed to proxy to backend",
|
|
62162
62189
|
message: err instanceof Error ? err.message : String(err)
|
|
62163
62190
|
});
|
|
62164
62191
|
}
|
|
@@ -62172,6 +62199,51 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62172
62199
|
const requestBody = body;
|
|
62173
62200
|
const stream = requestBody["stream"] === true;
|
|
62174
62201
|
const model = requestBody["model"] || "unknown";
|
|
62202
|
+
const config = loadConfig();
|
|
62203
|
+
const isVllm = config.backendType === "vllm";
|
|
62204
|
+
if (isVllm) {
|
|
62205
|
+
const payload = JSON.stringify(requestBody);
|
|
62206
|
+
if (stream) {
|
|
62207
|
+
res.writeHead(200, {
|
|
62208
|
+
"Content-Type": "text/event-stream",
|
|
62209
|
+
"Cache-Control": "no-cache",
|
|
62210
|
+
"Connection": "keep-alive",
|
|
62211
|
+
"Access-Control-Allow-Origin": "*",
|
|
62212
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
62213
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
62214
|
+
});
|
|
62215
|
+
ollamaStream(ollamaUrl, "/v1/chat/completions", "POST", payload, (chunk) => {
|
|
62216
|
+
res.write(chunk);
|
|
62217
|
+
}, () => {
|
|
62218
|
+
res.end();
|
|
62219
|
+
}, (err) => {
|
|
62220
|
+
try {
|
|
62221
|
+
res.write(`data: ${JSON.stringify({ error: err.message })}
|
|
62222
|
+
|
|
62223
|
+
`);
|
|
62224
|
+
} catch {
|
|
62225
|
+
}
|
|
62226
|
+
res.end();
|
|
62227
|
+
});
|
|
62228
|
+
} else {
|
|
62229
|
+
try {
|
|
62230
|
+
const result = await ollamaRequest(ollamaUrl, "/v1/chat/completions", "POST", payload);
|
|
62231
|
+
if (result.status !== 200) {
|
|
62232
|
+
jsonResponse(res, result.status, { error: "Backend request failed", details: result.body });
|
|
62233
|
+
return;
|
|
62234
|
+
}
|
|
62235
|
+
const parsed = JSON.parse(result.body);
|
|
62236
|
+
if (parsed.usage) {
|
|
62237
|
+
metrics.totalTokensIn += parsed.usage.prompt_tokens ?? 0;
|
|
62238
|
+
metrics.totalTokensOut += parsed.usage.completion_tokens ?? 0;
|
|
62239
|
+
}
|
|
62240
|
+
jsonResponse(res, 200, parsed);
|
|
62241
|
+
} catch (err) {
|
|
62242
|
+
jsonResponse(res, 502, { error: "Failed to proxy to backend", message: err instanceof Error ? err.message : String(err) });
|
|
62243
|
+
}
|
|
62244
|
+
}
|
|
62245
|
+
return;
|
|
62246
|
+
}
|
|
62175
62247
|
const ollamaPayload = JSON.stringify({
|
|
62176
62248
|
...requestBody,
|
|
62177
62249
|
stream,
|
|
@@ -62329,6 +62401,22 @@ async function handleV1Embeddings(req, res, ollamaUrl) {
|
|
|
62329
62401
|
return;
|
|
62330
62402
|
}
|
|
62331
62403
|
const requestBody = body;
|
|
62404
|
+
const config = loadConfig();
|
|
62405
|
+
const isVllm = config.backendType === "vllm";
|
|
62406
|
+
if (isVllm) {
|
|
62407
|
+
try {
|
|
62408
|
+
const payload = JSON.stringify(requestBody);
|
|
62409
|
+
const result = await ollamaRequest(ollamaUrl, "/v1/embeddings", "POST", payload);
|
|
62410
|
+
if (result.status !== 200) {
|
|
62411
|
+
jsonResponse(res, result.status, { error: "Backend embeddings request failed", details: result.body });
|
|
62412
|
+
return;
|
|
62413
|
+
}
|
|
62414
|
+
jsonResponse(res, 200, JSON.parse(result.body));
|
|
62415
|
+
} catch (err) {
|
|
62416
|
+
jsonResponse(res, 502, { error: "Failed to proxy to backend", message: err instanceof Error ? err.message : String(err) });
|
|
62417
|
+
}
|
|
62418
|
+
return;
|
|
62419
|
+
}
|
|
62332
62420
|
const ollamaPayload = JSON.stringify({
|
|
62333
62421
|
model: requestBody["model"],
|
|
62334
62422
|
input: requestBody["input"]
|
|
@@ -62337,7 +62425,7 @@ async function handleV1Embeddings(req, res, ollamaUrl) {
|
|
|
62337
62425
|
const result = await ollamaRequest(ollamaUrl, "/api/embed", "POST", ollamaPayload);
|
|
62338
62426
|
if (result.status !== 200) {
|
|
62339
62427
|
jsonResponse(res, result.status, {
|
|
62340
|
-
error: "
|
|
62428
|
+
error: "Backend embeddings request failed",
|
|
62341
62429
|
details: result.body
|
|
62342
62430
|
});
|
|
62343
62431
|
return;
|
|
@@ -62356,7 +62444,7 @@ async function handleV1Embeddings(req, res, ollamaUrl) {
|
|
|
62356
62444
|
});
|
|
62357
62445
|
} catch (err) {
|
|
62358
62446
|
jsonResponse(res, 502, {
|
|
62359
|
-
error: "Failed to proxy to
|
|
62447
|
+
error: "Failed to proxy to backend",
|
|
62360
62448
|
message: err instanceof Error ? err.message : String(err)
|
|
62361
62449
|
});
|
|
62362
62450
|
}
|
|
@@ -62564,10 +62652,16 @@ function handleV1RunsDelete(res, id) {
|
|
|
62564
62652
|
}
|
|
62565
62653
|
jsonResponse(res, 200, { run_id: id, status: "aborted" });
|
|
62566
62654
|
}
|
|
62655
|
+
function redactSecrets(obj) {
|
|
62656
|
+
const copy = { ...obj };
|
|
62657
|
+
if (typeof copy.apiKey === "string" && copy.apiKey)
|
|
62658
|
+
copy.apiKey = "[redacted]";
|
|
62659
|
+
return copy;
|
|
62660
|
+
}
|
|
62567
62661
|
function handleGetConfig(res) {
|
|
62568
62662
|
const config = loadConfig();
|
|
62569
62663
|
const settings = loadGlobalSettings();
|
|
62570
|
-
jsonResponse(res, 200, { config, settings });
|
|
62664
|
+
jsonResponse(res, 200, { config: redactSecrets(config), settings: redactSecrets(settings) });
|
|
62571
62665
|
}
|
|
62572
62666
|
async function handlePatchConfig(req, res) {
|
|
62573
62667
|
const body = await parseJsonBody(req);
|
|
@@ -62595,7 +62689,7 @@ async function handlePatchConfig(req, res) {
|
|
|
62595
62689
|
settingsUpdate.timeoutMs = updates["timeoutMs"];
|
|
62596
62690
|
saveGlobalSettings(settingsUpdate);
|
|
62597
62691
|
const updatedConfig = loadConfig();
|
|
62598
|
-
jsonResponse(res, 200, { config: updatedConfig, updated: Object.keys(settingsUpdate) });
|
|
62692
|
+
jsonResponse(res, 200, { config: redactSecrets(updatedConfig), updated: Object.keys(settingsUpdate) });
|
|
62599
62693
|
}
|
|
62600
62694
|
function handleGetConfigModel(res) {
|
|
62601
62695
|
const config = loadConfig();
|
|
@@ -62936,7 +63030,8 @@ function startApiServer(options = {}) {
|
|
|
62936
63030
|
`);
|
|
62937
63031
|
process.stderr.write(` Listening on http://${host}:${port}
|
|
62938
63032
|
`);
|
|
62939
|
-
|
|
63033
|
+
const beType = config.backendType || "ollama";
|
|
63034
|
+
process.stderr.write(` Backend (${beType}): ${ollamaUrl}
|
|
62940
63035
|
`);
|
|
62941
63036
|
if (process.env["OA_API_KEYS"]) {
|
|
62942
63037
|
const keyCount = process.env["OA_API_KEYS"].split(",").length;
|
|
@@ -68616,17 +68711,17 @@ async function evalCommand(opts, config) {
|
|
|
68616
68711
|
rawBackend = new FakeBackend();
|
|
68617
68712
|
}
|
|
68618
68713
|
const backend = {
|
|
68619
|
-
async complete(
|
|
68714
|
+
async complete(request) {
|
|
68620
68715
|
const result = await rawBackend.complete({
|
|
68621
|
-
messages:
|
|
68716
|
+
messages: request.messages.map((m) => ({
|
|
68622
68717
|
id: globalThis.crypto.randomUUID(),
|
|
68623
68718
|
sessionId: globalThis.crypto.randomUUID(),
|
|
68624
68719
|
role: m.role,
|
|
68625
68720
|
content: m.content,
|
|
68626
68721
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
68627
68722
|
})),
|
|
68628
|
-
maxTokens:
|
|
68629
|
-
temperature:
|
|
68723
|
+
maxTokens: request.maxTokens,
|
|
68724
|
+
temperature: request.temperature
|
|
68630
68725
|
});
|
|
68631
68726
|
return { content: result.content ?? "" };
|
|
68632
68727
|
}
|
package/package.json
CHANGED