open-agents-ai 0.187.454 → 0.187.456
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 +319 -16
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -575872,7 +575872,6 @@ const statusEl = document.getElementById('status');
|
|
|
575872
575872
|
let streaming = false;
|
|
575873
575873
|
let messages = [];
|
|
575874
575874
|
let chatAbortController = null; // for stop button
|
|
575875
|
-
let chatAbortController = null; // for stop button
|
|
575876
575875
|
// WO-CHAT-RESUME — interval id for the in-flight job poller. Set when we
|
|
575877
575876
|
// detect an active job on reload; cleared when the job reaches a terminal
|
|
575878
575877
|
// state OR the user navigates away.
|
|
@@ -580086,6 +580085,137 @@ function getSwaggerUI() {
|
|
|
580086
580085
|
</body>
|
|
580087
580086
|
</html>`;
|
|
580088
580087
|
}
|
|
580088
|
+
function getRedocHTML() {
|
|
580089
|
+
return `<!DOCTYPE html>
|
|
580090
|
+
<html lang="en">
|
|
580091
|
+
<head>
|
|
580092
|
+
<meta charset="UTF-8">
|
|
580093
|
+
<title>Open Agents — API Reference (ReDoc)</title>
|
|
580094
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
580095
|
+
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
|
580096
|
+
<style>
|
|
580097
|
+
body { margin: 0; padding: 0; }
|
|
580098
|
+
#oa-banner { padding: 8px 14px; background: #1e1e22; color: #b0b0b0; font: 12px ui-monospace, monospace; border-bottom: 1px solid #2a2a30; }
|
|
580099
|
+
#oa-banner a { color: #b2920a; text-decoration: none; margin-right: 14px; }
|
|
580100
|
+
#oa-banner b { color: #b2920a; }
|
|
580101
|
+
</style>
|
|
580102
|
+
</head>
|
|
580103
|
+
<body>
|
|
580104
|
+
<div id="oa-banner">
|
|
580105
|
+
<b>Open Agents — ReDoc view</b>
|
|
580106
|
+
<a href="/api/docs">Swagger UI (interactive)</a>
|
|
580107
|
+
<a href="/openapi.json">openapi.json</a>
|
|
580108
|
+
<a href="/openapi.yaml">openapi.yaml</a>
|
|
580109
|
+
<a href="/asyncapi.json">asyncapi.json</a>
|
|
580110
|
+
<a href="/v1/routes">routes summary</a>
|
|
580111
|
+
<a href="/">root</a>
|
|
580112
|
+
</div>
|
|
580113
|
+
<redoc spec-url="/openapi.json"></redoc>
|
|
580114
|
+
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
|
|
580115
|
+
</body>
|
|
580116
|
+
</html>`;
|
|
580117
|
+
}
|
|
580118
|
+
function getAsyncApiSpec() {
|
|
580119
|
+
const oa = getOpenApiSpec();
|
|
580120
|
+
const clientSchema = oa.components?.schemas?.VoicechatClientFrame;
|
|
580121
|
+
const serverSchema = oa.components?.schemas?.VoicechatServerFrame;
|
|
580122
|
+
return {
|
|
580123
|
+
asyncapi: "2.6.0",
|
|
580124
|
+
info: {
|
|
580125
|
+
title: "Open Agents — Voicechat (WebSocket)",
|
|
580126
|
+
version: "1.0.0",
|
|
580127
|
+
description: "Full-duplex voicechat over WebSocket. Binary frames carry PCM audio (mic in 16 kHz mono Int16 LE; TTS out at the model's native sample rate, announced in the preceding `tts_header` text frame). Text frames carry JSON control messages.",
|
|
580128
|
+
license: { name: "CC-BY-NC-4.0", url: "https://creativecommons.org/licenses/by-nc/4.0/" }
|
|
580129
|
+
},
|
|
580130
|
+
servers: {
|
|
580131
|
+
local: {
|
|
580132
|
+
url: "ws://localhost:11435",
|
|
580133
|
+
protocol: "ws",
|
|
580134
|
+
description: "Daemon on localhost. The same path works on LAN IP, public-IP forwarding, or behind a TLS-terminating proxy (then `wss://`)."
|
|
580135
|
+
}
|
|
580136
|
+
},
|
|
580137
|
+
defaultContentType: "application/json",
|
|
580138
|
+
channels: {
|
|
580139
|
+
"/v1/voicechat/ws": {
|
|
580140
|
+
description: "Voicechat full-duplex channel. Open with `?user=<displayName>` to set the connected-user name.",
|
|
580141
|
+
parameters: {
|
|
580142
|
+
user: { description: "Optional display name (default: 'browser').", schema: { type: "string" } }
|
|
580143
|
+
},
|
|
580144
|
+
publish: {
|
|
580145
|
+
summary: "Frames the client sends to the server (binary mic PCM + JSON control).",
|
|
580146
|
+
operationId: "publishToVoicechat",
|
|
580147
|
+
message: {
|
|
580148
|
+
oneOf: [
|
|
580149
|
+
{ name: "MicAudio", title: "Microphone PCM", contentType: "application/octet-stream", summary: "Binary frame: PCM Int16 mono 16 kHz from the user's mic (typically 4096 samples per frame).", payload: { type: "string", format: "binary" } },
|
|
580150
|
+
{ name: "ClientControl", title: "JSON control", payload: { $ref: "#/components/schemas/VoicechatClientFrame" } }
|
|
580151
|
+
]
|
|
580152
|
+
}
|
|
580153
|
+
},
|
|
580154
|
+
subscribe: {
|
|
580155
|
+
summary: "Frames the server sends to the client (binary TTS PCM + JSON control).",
|
|
580156
|
+
operationId: "subscribeToVoicechat",
|
|
580157
|
+
message: {
|
|
580158
|
+
oneOf: [
|
|
580159
|
+
{ name: "TtsAudio", title: "TTS PCM", contentType: "application/octet-stream", summary: "Binary frame: PCM Int16 mono at the model's native sample rate. ALWAYS preceded by a `tts_header` JSON frame announcing `sampleRate`.", payload: { type: "string", format: "binary" } },
|
|
580160
|
+
{ name: "ServerControl", title: "JSON control", payload: { $ref: "#/components/schemas/VoicechatServerFrame" } }
|
|
580161
|
+
]
|
|
580162
|
+
}
|
|
580163
|
+
}
|
|
580164
|
+
}
|
|
580165
|
+
},
|
|
580166
|
+
components: {
|
|
580167
|
+
schemas: {
|
|
580168
|
+
VoicechatClientFrame: clientSchema,
|
|
580169
|
+
VoicechatServerFrame: serverSchema
|
|
580170
|
+
}
|
|
580171
|
+
}
|
|
580172
|
+
};
|
|
580173
|
+
}
|
|
580174
|
+
function jsonToYaml(value2, indent = 0) {
|
|
580175
|
+
const pad = (n2) => " ".repeat(n2);
|
|
580176
|
+
if (value2 === null) return "null";
|
|
580177
|
+
if (value2 === void 0) return "null";
|
|
580178
|
+
if (typeof value2 === "boolean") return value2 ? "true" : "false";
|
|
580179
|
+
if (typeof value2 === "number") return Number.isFinite(value2) ? String(value2) : "null";
|
|
580180
|
+
if (typeof value2 === "string") {
|
|
580181
|
+
if (value2.length === 0) return '""';
|
|
580182
|
+
if (/[\n\r]/.test(value2)) {
|
|
580183
|
+
const lines = value2.replace(/\r\n?/g, "\n").split("\n");
|
|
580184
|
+
return "|-\n" + lines.map((l2) => pad(indent + 1) + l2).join("\n");
|
|
580185
|
+
}
|
|
580186
|
+
if (/^(true|false|null|yes|no|on|off|~|\d|-\d|\.\d|\.inf|\.nan|@|`|\*|&|!|\?|\||>|%|"|')/i.test(value2) || /[#:,\[\]{}]/.test(value2) || /^\s|\s$/.test(value2)) {
|
|
580187
|
+
return JSON.stringify(value2);
|
|
580188
|
+
}
|
|
580189
|
+
return value2;
|
|
580190
|
+
}
|
|
580191
|
+
if (Array.isArray(value2)) {
|
|
580192
|
+
if (value2.length === 0) return "[]";
|
|
580193
|
+
return "\n" + value2.map((item) => {
|
|
580194
|
+
const rendered = jsonToYaml(item, indent + 1);
|
|
580195
|
+
if (rendered.startsWith("\n")) {
|
|
580196
|
+
return pad(indent) + "-" + rendered.replace(/^\n/, "\n");
|
|
580197
|
+
}
|
|
580198
|
+
const lines = rendered.split("\n");
|
|
580199
|
+
if (lines.length === 1) return pad(indent) + "- " + lines[0];
|
|
580200
|
+
return pad(indent) + "- " + lines[0] + "\n" + lines.slice(1).map((l2) => pad(indent + 1) + l2.replace(/^ /, "")).join("\n");
|
|
580201
|
+
}).join("\n");
|
|
580202
|
+
}
|
|
580203
|
+
if (typeof value2 === "object") {
|
|
580204
|
+
const obj = value2;
|
|
580205
|
+
const keys = Object.keys(obj);
|
|
580206
|
+
if (keys.length === 0) return "{}";
|
|
580207
|
+
return "\n" + keys.map((k) => {
|
|
580208
|
+
const v = obj[k];
|
|
580209
|
+
const safeKey = /^[a-zA-Z_][a-zA-Z0-9_./-]*$/.test(k) && !/^(true|false|null|yes|no|on|off)$/i.test(k) ? k : JSON.stringify(k);
|
|
580210
|
+
const rendered = jsonToYaml(v, indent + 1);
|
|
580211
|
+
if (rendered.startsWith("\n")) {
|
|
580212
|
+
return pad(indent) + safeKey + ":" + rendered;
|
|
580213
|
+
}
|
|
580214
|
+
return pad(indent) + safeKey + ": " + rendered;
|
|
580215
|
+
}).join("\n");
|
|
580216
|
+
}
|
|
580217
|
+
return JSON.stringify(value2);
|
|
580218
|
+
}
|
|
580089
580219
|
var SWAGGER_VERSION;
|
|
580090
580220
|
var init_openapi = __esm({
|
|
580091
580221
|
"packages/cli/src/api/openapi.ts"() {
|
|
@@ -581217,14 +581347,14 @@ function sanitizeChatContent(raw) {
|
|
|
581217
581347
|
return cleaned.join("\n").trim();
|
|
581218
581348
|
}
|
|
581219
581349
|
async function directChatBackend(opts) {
|
|
581220
|
-
const { model, messages: messages2, stream, res, sessionId, ollamaUrl } = opts;
|
|
581350
|
+
const { model, messages: messages2, stream, res, sessionId, ollamaUrl, extraFields } = opts;
|
|
581221
581351
|
const cfg = loadConfig();
|
|
581222
581352
|
const isVllm = cfg.backendType === "vllm";
|
|
581223
581353
|
const cleanModel = model.replace(/^[a-z]+\//, "");
|
|
581224
581354
|
const headers = { "Content-Type": "application/json" };
|
|
581225
581355
|
if (cfg.apiKey) headers["Authorization"] = `Bearer ${cfg.apiKey}`;
|
|
581226
581356
|
if (isVllm) {
|
|
581227
|
-
const reqBody = JSON.stringify({ model: cleanModel, messages: messages2, stream });
|
|
581357
|
+
const reqBody = JSON.stringify({ model: cleanModel, messages: messages2, stream, ...extraFields || {} });
|
|
581228
581358
|
if (stream) {
|
|
581229
581359
|
res.writeHead(200, {
|
|
581230
581360
|
"Content-Type": "text/event-stream",
|
|
@@ -581292,12 +581422,27 @@ async function directChatBackend(opts) {
|
|
|
581292
581422
|
return content;
|
|
581293
581423
|
}
|
|
581294
581424
|
} else {
|
|
581425
|
+
const ef = extraFields || {};
|
|
581426
|
+
const ollamaOpts = {};
|
|
581427
|
+
if (typeof ef["temperature"] === "number") ollamaOpts["temperature"] = ef["temperature"];
|
|
581428
|
+
if (typeof ef["top_p"] === "number") ollamaOpts["top_p"] = ef["top_p"];
|
|
581429
|
+
if (typeof ef["max_tokens"] === "number") ollamaOpts["num_predict"] = ef["max_tokens"];
|
|
581430
|
+
if (typeof ef["seed"] === "number") ollamaOpts["seed"] = ef["seed"];
|
|
581431
|
+
if (typeof ef["frequency_penalty"] === "number") ollamaOpts["frequency_penalty"] = ef["frequency_penalty"];
|
|
581432
|
+
if (typeof ef["presence_penalty"] === "number") ollamaOpts["presence_penalty"] = ef["presence_penalty"];
|
|
581433
|
+
if (Array.isArray(ef["stop"]) || typeof ef["stop"] === "string") ollamaOpts["stop"] = ef["stop"];
|
|
581434
|
+
const hasTools = Array.isArray(ef["tools"]) && ef["tools"].length > 0;
|
|
581295
581435
|
const reqBody = JSON.stringify({
|
|
581296
581436
|
model: cleanModel,
|
|
581297
581437
|
messages: messages2,
|
|
581298
581438
|
stream,
|
|
581299
|
-
think:
|
|
581300
|
-
|
|
581439
|
+
// Don't force think:false when the caller is using tool calling —
|
|
581440
|
+
// thinking models often need their reasoning chain to choose a tool.
|
|
581441
|
+
...hasTools ? {} : { think: false },
|
|
581442
|
+
...hasTools ? { tools: ef["tools"] } : {},
|
|
581443
|
+
...ef["tool_choice"] !== void 0 ? { tool_choice: ef["tool_choice"] } : {},
|
|
581444
|
+
...ef["response_format"] !== void 0 ? { format: ef["response_format"] } : {},
|
|
581445
|
+
options: ollamaOpts
|
|
581301
581446
|
});
|
|
581302
581447
|
if (stream) {
|
|
581303
581448
|
res.writeHead(200, {
|
|
@@ -581353,7 +581498,20 @@ async function directChatBackend(opts) {
|
|
|
581353
581498
|
if (result.status >= 400) throw new Error(`Backend HTTP ${result.status}: ${result.body.slice(0, 200)}`);
|
|
581354
581499
|
const j = JSON.parse(result.body);
|
|
581355
581500
|
const content = j?.message?.content || "";
|
|
581356
|
-
|
|
581501
|
+
const rawToolCalls = j?.message?.tool_calls;
|
|
581502
|
+
const toolCalls = Array.isArray(rawToolCalls) ? rawToolCalls.map((tc, idx) => ({
|
|
581503
|
+
id: tc.id || `call_${Math.random().toString(36).slice(2, 10)}`,
|
|
581504
|
+
type: "function",
|
|
581505
|
+
function: {
|
|
581506
|
+
name: tc?.function?.name ?? tc?.name ?? "",
|
|
581507
|
+
arguments: typeof tc?.function?.arguments === "string" ? tc.function.arguments : JSON.stringify(tc?.function?.arguments ?? tc?.arguments ?? {})
|
|
581508
|
+
},
|
|
581509
|
+
index: idx
|
|
581510
|
+
})) : [];
|
|
581511
|
+
if (!content && toolCalls.length === 0) {
|
|
581512
|
+
throw new Error("Backend returned empty message (no content, no tool_calls)");
|
|
581513
|
+
}
|
|
581514
|
+
const finishReason = toolCalls.length > 0 ? "tool_calls" : "stop";
|
|
581357
581515
|
const promptTokens = j?.prompt_eval_count ?? 0;
|
|
581358
581516
|
const completionTokens = j?.eval_count ?? 0;
|
|
581359
581517
|
jsonResponse(res, 200, {
|
|
@@ -581363,8 +581521,12 @@ async function directChatBackend(opts) {
|
|
|
581363
581521
|
model: cleanModel,
|
|
581364
581522
|
choices: [{
|
|
581365
581523
|
index: 0,
|
|
581366
|
-
message: {
|
|
581367
|
-
|
|
581524
|
+
message: {
|
|
581525
|
+
role: "assistant",
|
|
581526
|
+
content,
|
|
581527
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
581528
|
+
},
|
|
581529
|
+
finish_reason: finishReason
|
|
581368
581530
|
}],
|
|
581369
581531
|
usage: {
|
|
581370
581532
|
prompt_tokens: promptTokens,
|
|
@@ -582008,10 +582170,13 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
582008
582170
|
}
|
|
582009
582171
|
return;
|
|
582010
582172
|
}
|
|
582173
|
+
const callerProvidedThink = "think" in routedBody;
|
|
582174
|
+
const callerProvidedTools = Array.isArray(routedBody["tools"]) && routedBody["tools"].length > 0;
|
|
582175
|
+
const finalThink = callerProvidedThink ? routedBody["think"] : callerProvidedTools ? void 0 : false;
|
|
582011
582176
|
const ollamaPayload = JSON.stringify({
|
|
582012
582177
|
...routedBody,
|
|
582013
582178
|
stream,
|
|
582014
|
-
think:
|
|
582179
|
+
...finalThink !== void 0 ? { think: finalThink } : {}
|
|
582015
582180
|
});
|
|
582016
582181
|
if (stream) {
|
|
582017
582182
|
res.writeHead(200, {
|
|
@@ -582059,7 +582224,17 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
582059
582224
|
const delta = {};
|
|
582060
582225
|
if (ollamaChunk.message.role) delta.role = ollamaChunk.message.role;
|
|
582061
582226
|
if (ollamaChunk.message.content) delta.content = ollamaChunk.message.content;
|
|
582062
|
-
if (ollamaChunk.message.tool_calls)
|
|
582227
|
+
if (ollamaChunk.message.tool_calls) {
|
|
582228
|
+
delta.tool_calls = ollamaChunk.message.tool_calls.map((tc, idx) => ({
|
|
582229
|
+
id: tc.id || `call_${randomBytes21(8).toString("hex")}`,
|
|
582230
|
+
type: "function",
|
|
582231
|
+
function: {
|
|
582232
|
+
name: tc?.function?.name ?? tc?.name ?? "",
|
|
582233
|
+
arguments: typeof tc?.function?.arguments === "string" ? tc.function.arguments : JSON.stringify(tc?.function?.arguments ?? tc?.arguments ?? {})
|
|
582234
|
+
},
|
|
582235
|
+
index: idx
|
|
582236
|
+
}));
|
|
582237
|
+
}
|
|
582063
582238
|
const sseEvent = {
|
|
582064
582239
|
id: chatId,
|
|
582065
582240
|
object: "chat.completion.chunk",
|
|
@@ -582135,7 +582310,15 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
582135
582310
|
content: ollamaResp.message?.content ?? ""
|
|
582136
582311
|
};
|
|
582137
582312
|
if (ollamaResp.message?.tool_calls && ollamaResp.message.tool_calls.length > 0) {
|
|
582138
|
-
responseMessage.tool_calls = ollamaResp.message.tool_calls
|
|
582313
|
+
responseMessage.tool_calls = ollamaResp.message.tool_calls.map((tc, idx) => ({
|
|
582314
|
+
id: tc.id || `call_${randomBytes21(8).toString("hex")}`,
|
|
582315
|
+
type: "function",
|
|
582316
|
+
function: {
|
|
582317
|
+
name: tc?.function?.name ?? tc?.name ?? "",
|
|
582318
|
+
arguments: typeof tc?.function?.arguments === "string" ? tc.function.arguments : JSON.stringify(tc?.function?.arguments ?? tc?.arguments ?? {})
|
|
582319
|
+
},
|
|
582320
|
+
index: idx
|
|
582321
|
+
}));
|
|
582139
582322
|
if (!ollamaResp.message.content) responseMessage.content = null;
|
|
582140
582323
|
}
|
|
582141
582324
|
const hasToolCalls = !!ollamaResp.message?.tool_calls?.length;
|
|
@@ -583584,6 +583767,103 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
583584
583767
|
return;
|
|
583585
583768
|
}
|
|
583586
583769
|
}
|
|
583770
|
+
if ((pathname === "/v3/api-docs" || pathname === "/swagger.json" || pathname === "/api-docs") && method === "GET") {
|
|
583771
|
+
jsonResponse(res, 200, getOpenApiSpec());
|
|
583772
|
+
return;
|
|
583773
|
+
}
|
|
583774
|
+
if (pathname === "/openapi.yaml" && method === "GET") {
|
|
583775
|
+
const spec = getOpenApiSpec();
|
|
583776
|
+
const yaml = jsonToYaml(spec);
|
|
583777
|
+
res.writeHead(200, {
|
|
583778
|
+
"Content-Type": "application/yaml; charset=utf-8",
|
|
583779
|
+
"Cache-Control": "public, max-age=60"
|
|
583780
|
+
});
|
|
583781
|
+
res.end(yaml);
|
|
583782
|
+
return;
|
|
583783
|
+
}
|
|
583784
|
+
if ((pathname === "/swagger-ui" || pathname === "/swagger-ui/" || pathname === "/swagger-ui/index.html") && method === "GET") {
|
|
583785
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
583786
|
+
res.end(getSwaggerUI());
|
|
583787
|
+
return;
|
|
583788
|
+
}
|
|
583789
|
+
if ((pathname === "/redoc" || pathname === "/redoc/") && method === "GET") {
|
|
583790
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
583791
|
+
res.end(getRedocHTML());
|
|
583792
|
+
return;
|
|
583793
|
+
}
|
|
583794
|
+
if ((pathname === "/asyncapi.json" || pathname === "/asyncapi") && method === "GET") {
|
|
583795
|
+
jsonResponse(res, 200, getAsyncApiSpec());
|
|
583796
|
+
return;
|
|
583797
|
+
}
|
|
583798
|
+
if (pathname === "/" && method === "GET" && !req2.headers.accept?.includes("text/html")) {
|
|
583799
|
+
const cfg = loadConfig();
|
|
583800
|
+
const baseUrl = `${req2.headers["x-forwarded-proto"] || (req2.socket && req2.socket.encrypted ? "https" : "http")}://${req2.headers.host || "localhost"}`;
|
|
583801
|
+
jsonResponse(res, 200, {
|
|
583802
|
+
name: "open-agents",
|
|
583803
|
+
version: API_VERSION,
|
|
583804
|
+
description: "Open Agents AI — local agentic stack with OpenAI-compatible inference, voice (TTS/ASR/voice-clone), per-project preferences, AIMS controls, and full WebSocket voicechat. All endpoints documented in /openapi.json + interactive at /api/docs.",
|
|
583805
|
+
documentation_url: `${baseUrl}/api/docs`,
|
|
583806
|
+
openapi_spec_url: `${baseUrl}/openapi.json`,
|
|
583807
|
+
asyncapi_spec_url: `${baseUrl}/asyncapi.json`,
|
|
583808
|
+
backend: { url: cfg.backendUrl, type: cfg.backendType, model: cfg.model },
|
|
583809
|
+
// _links shape mirrors GitHub's API root + JSON-Home flavor.
|
|
583810
|
+
// Each cluster has a one-line description so an agent doesn't need
|
|
583811
|
+
// to read the OpenAPI spec to know what's there.
|
|
583812
|
+
_links: {
|
|
583813
|
+
self: `${baseUrl}/`,
|
|
583814
|
+
health: { href: `${baseUrl}/health`, description: "Liveness + version + uptime" },
|
|
583815
|
+
openapi: { href: `${baseUrl}/openapi.json`, description: "OpenAPI 3.0 spec (machine-readable). Aliases: /openapi.yaml, /v3/api-docs, /swagger.json, /api-docs." },
|
|
583816
|
+
asyncapi: { href: `${baseUrl}/asyncapi.json`, description: "AsyncAPI 2.6 spec for the /v1/voicechat/ws WebSocket." },
|
|
583817
|
+
docs: { href: `${baseUrl}/api/docs`, description: "Interactive Swagger UI. Aliases: /docs, /swagger-ui." },
|
|
583818
|
+
redoc: { href: `${baseUrl}/redoc`, description: "ReDoc renderer of the same /openapi.json." },
|
|
583819
|
+
routes: { href: `${baseUrl}/v1/routes`, description: "Flat grep-friendly summary of every route (~5 KB)." },
|
|
583820
|
+
chat: {
|
|
583821
|
+
completions: { href: `${baseUrl}/v1/chat/completions`, description: "OpenAI-compatible chat completion. Native tool calling supported." },
|
|
583822
|
+
session: { href: `${baseUrl}/v1/chat`, description: "Stateful chat session with optional agent subprocess (set tools=true for full tool stack)." },
|
|
583823
|
+
sessions: { href: `${baseUrl}/v1/chat/sessions`, description: "List active chat sessions." }
|
|
583824
|
+
},
|
|
583825
|
+
voice: {
|
|
583826
|
+
state: { href: `${baseUrl}/v1/voice/state`, description: "Voice runtime status." },
|
|
583827
|
+
tts_models: { href: `${baseUrl}/v1/voice/models`, description: "List TTS voice models." },
|
|
583828
|
+
tts: { href: `${baseUrl}/v1/voice/tts`, description: "Synthesize text → audio bytes (also at /v1/audio/speech for OpenAI compat)." },
|
|
583829
|
+
asr_models: { href: `${baseUrl}/v1/voice/asr-models`, description: "List Whisper ASR models." },
|
|
583830
|
+
transcribe: { href: `${baseUrl}/v1/voice/transcribe`, description: "Transcribe audio → text (also at /v1/audio/transcriptions)." },
|
|
583831
|
+
transcribe_stream: { href: `${baseUrl}/v1/voice/transcribe/stream`, description: "Streaming ASR via SSE." },
|
|
583832
|
+
voicechat_ws: { href: `${baseUrl}/v1/voicechat/ws`, description: "Full-duplex voicechat WebSocket. See /asyncapi.json for the frame schemas." },
|
|
583833
|
+
clone_refs: { href: `${baseUrl}/v1/voice/clone-refs`, description: "Voice clone reference management. Upload via JSON+base64, raw multipart, or from-URL." },
|
|
583834
|
+
speak: { href: `${baseUrl}/v1/voice/speak`, description: "Synthesize text and broadcast to /v1/voicechat/ws clients." }
|
|
583835
|
+
},
|
|
583836
|
+
projects: {
|
|
583837
|
+
list: { href: `${baseUrl}/v1/projects`, description: "Workspace registry." },
|
|
583838
|
+
current: { href: `${baseUrl}/v1/projects/current`, description: "Active project." },
|
|
583839
|
+
switch: { href: `${baseUrl}/v1/projects/switch`, description: "Set the active project (POST)." },
|
|
583840
|
+
preferences: { href: `${baseUrl}/v1/projects/preferences`, description: "Per-project UI preferences (model, theme, current chat session, etc.)." }
|
|
583841
|
+
},
|
|
583842
|
+
inference: {
|
|
583843
|
+
models: { href: `${baseUrl}/v1/models`, description: "OpenAI-compatible model list." },
|
|
583844
|
+
embeddings: { href: `${baseUrl}/v1/embeddings`, description: "Generate embeddings." }
|
|
583845
|
+
},
|
|
583846
|
+
agentic: {
|
|
583847
|
+
run: { href: `${baseUrl}/v1/run`, description: "Submit autonomous task." },
|
|
583848
|
+
runs: { href: `${baseUrl}/v1/runs`, description: "List runs." },
|
|
583849
|
+
tools: { href: `${baseUrl}/v1/tools`, description: "Agentic tool registry." },
|
|
583850
|
+
mcps: { href: `${baseUrl}/v1/mcps`, description: "MCP server registry." }
|
|
583851
|
+
},
|
|
583852
|
+
memory: {
|
|
583853
|
+
root: { href: `${baseUrl}/v1/memory`, description: "Memory backends summary." },
|
|
583854
|
+
search: { href: `${baseUrl}/v1/memory/search`, description: "Search memory." },
|
|
583855
|
+
episodes: { href: `${baseUrl}/v1/memory/episodes`, description: "List episodes." }
|
|
583856
|
+
},
|
|
583857
|
+
observability: {
|
|
583858
|
+
usage: { href: `${baseUrl}/v1/usage`, description: "Token usage + rate limits." },
|
|
583859
|
+
audit: { href: `${baseUrl}/v1/audit`, description: "Audit log." },
|
|
583860
|
+
events: { href: `${baseUrl}/v1/events`, description: "SSE event bus." }
|
|
583861
|
+
},
|
|
583862
|
+
aims: { href: `${baseUrl}/v1/aims`, description: "ISO/IEC 42001:2023 AIMS controls (policies, roles, resources, impact assessments, …)." }
|
|
583863
|
+
}
|
|
583864
|
+
});
|
|
583865
|
+
return;
|
|
583866
|
+
}
|
|
583587
583867
|
if (pathname === "/" && method === "GET" && req2.headers.accept?.includes("text/html")) {
|
|
583588
583868
|
res.writeHead(200, {
|
|
583589
583869
|
"Content-Type": "text/html; charset=utf-8",
|
|
@@ -584601,19 +584881,42 @@ data: ${JSON.stringify(data)}
|
|
|
584601
584881
|
const session = getSession(sessionId, model, cwdPath);
|
|
584602
584882
|
addUserMessage(session, chatBody.message);
|
|
584603
584883
|
compactSession(session);
|
|
584604
|
-
const wantsTools = chatBody["tools"] !== false && chatBody["use_tools"] !== false;
|
|
584605
584884
|
const streamMode = chatBody.stream !== false;
|
|
584606
|
-
|
|
584885
|
+
const toolsField = chatBody["tools"];
|
|
584886
|
+
const isOpenAIToolsArray = Array.isArray(toolsField) && toolsField.length > 0 && toolsField.every(
|
|
584887
|
+
(t2) => t2 && typeof t2 === "object" && t2["type"] === "function" && typeof t2["function"]?.["name"] === "string"
|
|
584888
|
+
);
|
|
584889
|
+
const wantsAgent = !isOpenAIToolsArray && chatBody["tools"] !== false && chatBody["use_tools"] !== false;
|
|
584890
|
+
if (Array.isArray(chatBody.messages)) {
|
|
584891
|
+
const incomingSystem = chatBody.messages.find((m2) => m2?.role === "system" && typeof m2.content === "string");
|
|
584892
|
+
if (incomingSystem && session.messages.length > 0 && session.messages[0].role === "system") {
|
|
584893
|
+
session.messages[0] = { ...session.messages[0], content: incomingSystem.content };
|
|
584894
|
+
}
|
|
584895
|
+
}
|
|
584896
|
+
if (!wantsAgent) {
|
|
584607
584897
|
try {
|
|
584608
584898
|
const ans = await directChatBackend({
|
|
584609
584899
|
model,
|
|
584610
|
-
// Filter out tool_call/tool_result messages — the upstream
|
|
584611
|
-
// model only accepts standard system/user/assistant turns.
|
|
584612
584900
|
messages: session.messages.filter((m2) => m2.role === "system" || m2.role === "user" || m2.role === "assistant").map((m2) => ({ role: m2.role, content: m2.content })),
|
|
584613
584901
|
stream: streamMode,
|
|
584614
584902
|
res,
|
|
584615
584903
|
sessionId: session.id,
|
|
584616
|
-
ollamaUrl
|
|
584904
|
+
ollamaUrl,
|
|
584905
|
+
// Pass-through of OpenAI fields — the upstream model needs
|
|
584906
|
+
// them for native tool calling, deterministic outputs, etc.
|
|
584907
|
+
extraFields: {
|
|
584908
|
+
...isOpenAIToolsArray ? { tools: toolsField } : {},
|
|
584909
|
+
...chatBody["tool_choice"] !== void 0 ? { tool_choice: chatBody["tool_choice"] } : {},
|
|
584910
|
+
...chatBody["temperature"] !== void 0 ? { temperature: chatBody["temperature"] } : {},
|
|
584911
|
+
...chatBody["top_p"] !== void 0 ? { top_p: chatBody["top_p"] } : {},
|
|
584912
|
+
...chatBody["max_tokens"] !== void 0 ? { max_tokens: chatBody["max_tokens"] } : {},
|
|
584913
|
+
...chatBody["response_format"] !== void 0 ? { response_format: chatBody["response_format"] } : {},
|
|
584914
|
+
...chatBody["seed"] !== void 0 ? { seed: chatBody["seed"] } : {},
|
|
584915
|
+
...chatBody["frequency_penalty"] !== void 0 ? { frequency_penalty: chatBody["frequency_penalty"] } : {},
|
|
584916
|
+
...chatBody["presence_penalty"] !== void 0 ? { presence_penalty: chatBody["presence_penalty"] } : {},
|
|
584917
|
+
...chatBody["stop"] !== void 0 ? { stop: chatBody["stop"] } : {},
|
|
584918
|
+
...chatBody["parallel_tool_calls"] !== void 0 ? { parallel_tool_calls: chatBody["parallel_tool_calls"] } : {}
|
|
584919
|
+
}
|
|
584617
584920
|
});
|
|
584618
584921
|
if (ans !== null) {
|
|
584619
584922
|
addAssistantMessage(session, ans);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-agents-ai",
|
|
3
|
-
"version": "0.187.
|
|
3
|
+
"version": "0.187.456",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "open-agents-ai",
|
|
9
|
-
"version": "0.187.
|
|
9
|
+
"version": "0.187.456",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED