open-agents-ai 0.184.71 → 0.184.73
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 +193 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -560,6 +560,10 @@ var init_normalizeUrl = __esm({
|
|
|
560
560
|
"use strict";
|
|
561
561
|
PROVIDERS = [
|
|
562
562
|
// --- Cloud providers (specific domains) ---
|
|
563
|
+
{
|
|
564
|
+
match: (u) => /api\.anthropic\.com/i.test(u),
|
|
565
|
+
info: { id: "anthropic", label: "Anthropic (Claude)", local: false, authRequired: true, keyPrefix: "sk-ant-", modelsPath: "/v1/models" }
|
|
566
|
+
},
|
|
563
567
|
{
|
|
564
568
|
match: (u) => /api\.openai\.com/i.test(u),
|
|
565
569
|
info: { id: "openai", label: "OpenAI", local: false, authRequired: true, keyPrefix: "sk-", modelsPath: "/v1/models" }
|
|
@@ -28487,11 +28491,14 @@ ${transcript}`
|
|
|
28487
28491
|
/** Multi-key pool — round-robin rotation per request for load distribution */
|
|
28488
28492
|
_keyPool = [];
|
|
28489
28493
|
_keyIndex = 0;
|
|
28494
|
+
/** Whether this backend targets Anthropic's Messages API */
|
|
28495
|
+
_isAnthropic = false;
|
|
28490
28496
|
constructor(baseUrl, model, apiKey, thinking) {
|
|
28491
28497
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
28492
28498
|
this.model = model;
|
|
28493
28499
|
this.apiKey = apiKey ?? "";
|
|
28494
28500
|
this.thinking = thinking ?? true;
|
|
28501
|
+
this._isAnthropic = /api\.anthropic\.com/i.test(baseUrl);
|
|
28495
28502
|
}
|
|
28496
28503
|
/** Set multiple API keys for round-robin rotation per request */
|
|
28497
28504
|
setKeyPool(keys) {
|
|
@@ -28502,7 +28509,7 @@ ${transcript}`
|
|
|
28502
28509
|
setAbortSignal(signal) {
|
|
28503
28510
|
this._abortSignal = signal;
|
|
28504
28511
|
}
|
|
28505
|
-
/** Build auth headers —
|
|
28512
|
+
/** Build auth headers — adapts to provider (Bearer for most, x-api-key for Anthropic).
|
|
28506
28513
|
* When a key pool is set, round-robins through keys per request. */
|
|
28507
28514
|
authHeaders() {
|
|
28508
28515
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -28512,11 +28519,19 @@ ${transcript}`
|
|
|
28512
28519
|
this._keyIndex++;
|
|
28513
28520
|
}
|
|
28514
28521
|
if (key) {
|
|
28515
|
-
|
|
28522
|
+
if (this._isAnthropic) {
|
|
28523
|
+
headers["x-api-key"] = key;
|
|
28524
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
28525
|
+
} else {
|
|
28526
|
+
headers["Authorization"] = `Bearer ${key}`;
|
|
28527
|
+
}
|
|
28516
28528
|
}
|
|
28517
28529
|
return headers;
|
|
28518
28530
|
}
|
|
28519
28531
|
async chatCompletion(request) {
|
|
28532
|
+
if (this._isAnthropic) {
|
|
28533
|
+
return this._anthropicChatCompletion(request);
|
|
28534
|
+
}
|
|
28520
28535
|
const body = {
|
|
28521
28536
|
model: this.model,
|
|
28522
28537
|
messages: request.messages,
|
|
@@ -28574,6 +28589,106 @@ ${transcript}`
|
|
|
28574
28589
|
} : void 0
|
|
28575
28590
|
};
|
|
28576
28591
|
}
|
|
28592
|
+
/** Anthropic Messages API translation — converts our standard format to/from Anthropic's. */
|
|
28593
|
+
async _anthropicChatCompletion(request) {
|
|
28594
|
+
const systemMsgs = request.messages.filter((m) => m.role === "system");
|
|
28595
|
+
const nonSystemMsgs = request.messages.filter((m) => m.role !== "system");
|
|
28596
|
+
const systemText = systemMsgs.map((m) => typeof m.content === "string" ? m.content : "").join("\n\n");
|
|
28597
|
+
const anthropicMessages = [];
|
|
28598
|
+
for (const msg of nonSystemMsgs) {
|
|
28599
|
+
if (msg.role === "tool") {
|
|
28600
|
+
anthropicMessages.push({
|
|
28601
|
+
role: "user",
|
|
28602
|
+
content: [{
|
|
28603
|
+
type: "tool_result",
|
|
28604
|
+
tool_use_id: msg.tool_call_id ?? "",
|
|
28605
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
28606
|
+
}]
|
|
28607
|
+
});
|
|
28608
|
+
} else if (msg.role === "assistant" && msg.tool_calls?.length > 0) {
|
|
28609
|
+
const blocks = [];
|
|
28610
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
28611
|
+
blocks.push({ type: "text", text: msg.content });
|
|
28612
|
+
}
|
|
28613
|
+
for (const tc of msg.tool_calls) {
|
|
28614
|
+
blocks.push({
|
|
28615
|
+
type: "tool_use",
|
|
28616
|
+
id: tc.id,
|
|
28617
|
+
name: tc.function?.name ?? tc.name,
|
|
28618
|
+
input: typeof tc.function?.arguments === "string" ? (() => {
|
|
28619
|
+
try {
|
|
28620
|
+
return JSON.parse(tc.function.arguments);
|
|
28621
|
+
} catch {
|
|
28622
|
+
return {};
|
|
28623
|
+
}
|
|
28624
|
+
})() : tc.function?.arguments ?? {}
|
|
28625
|
+
});
|
|
28626
|
+
}
|
|
28627
|
+
anthropicMessages.push({ role: "assistant", content: blocks });
|
|
28628
|
+
} else {
|
|
28629
|
+
anthropicMessages.push({
|
|
28630
|
+
role: msg.role === "user" ? "user" : "assistant",
|
|
28631
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content ?? "")
|
|
28632
|
+
});
|
|
28633
|
+
}
|
|
28634
|
+
}
|
|
28635
|
+
const anthropicTools = (request.tools ?? []).filter((t) => t.type === "function" && t.function).map((t) => ({
|
|
28636
|
+
name: t.function.name,
|
|
28637
|
+
description: t.function.description,
|
|
28638
|
+
input_schema: t.function.parameters
|
|
28639
|
+
}));
|
|
28640
|
+
const body = {
|
|
28641
|
+
model: this.model,
|
|
28642
|
+
messages: anthropicMessages,
|
|
28643
|
+
max_tokens: request.maxTokens ?? 8192,
|
|
28644
|
+
temperature: request.temperature
|
|
28645
|
+
};
|
|
28646
|
+
if (systemText)
|
|
28647
|
+
body.system = systemText;
|
|
28648
|
+
if (anthropicTools.length > 0)
|
|
28649
|
+
body.tools = anthropicTools;
|
|
28650
|
+
const fetchOpts = {
|
|
28651
|
+
method: "POST",
|
|
28652
|
+
headers: this.authHeaders(),
|
|
28653
|
+
body: JSON.stringify(body)
|
|
28654
|
+
};
|
|
28655
|
+
if (this._abortSignal)
|
|
28656
|
+
fetchOpts.signal = this._abortSignal;
|
|
28657
|
+
const resp = await fetch(`${this.baseUrl}/v1/messages`, fetchOpts);
|
|
28658
|
+
if (!resp.ok) {
|
|
28659
|
+
const text = await resp.text().catch(() => "");
|
|
28660
|
+
throw new Error(`Anthropic HTTP ${resp.status}: ${text.slice(0, 300)}`);
|
|
28661
|
+
}
|
|
28662
|
+
const data = await resp.json();
|
|
28663
|
+
const contentBlocks = data.content ?? [];
|
|
28664
|
+
const usage = data.usage;
|
|
28665
|
+
let textContent = "";
|
|
28666
|
+
const toolCalls = [];
|
|
28667
|
+
for (const block of contentBlocks) {
|
|
28668
|
+
if (block.type === "text") {
|
|
28669
|
+
textContent += block.text ?? "";
|
|
28670
|
+
} else if (block.type === "tool_use") {
|
|
28671
|
+
toolCalls.push({
|
|
28672
|
+
id: block.id || crypto.randomUUID(),
|
|
28673
|
+
name: block.name,
|
|
28674
|
+
arguments: block.input ?? {}
|
|
28675
|
+
});
|
|
28676
|
+
}
|
|
28677
|
+
}
|
|
28678
|
+
return {
|
|
28679
|
+
choices: [{
|
|
28680
|
+
message: {
|
|
28681
|
+
content: textContent || null,
|
|
28682
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
28683
|
+
}
|
|
28684
|
+
}],
|
|
28685
|
+
usage: usage ? {
|
|
28686
|
+
totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
|
|
28687
|
+
promptTokens: usage.input_tokens,
|
|
28688
|
+
completionTokens: usage.output_tokens
|
|
28689
|
+
} : void 0
|
|
28690
|
+
};
|
|
28691
|
+
}
|
|
28577
28692
|
/**
|
|
28578
28693
|
* SSE streaming variant — yields StreamChunks as tokens arrive.
|
|
28579
28694
|
* Uses `stream: true` and the current thinking setting.
|
|
@@ -38613,9 +38728,15 @@ async function fetchOllamaModels(baseUrl) {
|
|
|
38613
38728
|
async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
38614
38729
|
const normalized = normalizeBaseUrl(baseUrl);
|
|
38615
38730
|
const url = `${normalized}/v1/models`;
|
|
38731
|
+
const isAnthropic = /api\.anthropic\.com/i.test(baseUrl);
|
|
38616
38732
|
const headers = {};
|
|
38617
38733
|
if (apiKey) {
|
|
38618
|
-
|
|
38734
|
+
if (isAnthropic) {
|
|
38735
|
+
headers["x-api-key"] = apiKey;
|
|
38736
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
38737
|
+
} else {
|
|
38738
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
38739
|
+
}
|
|
38619
38740
|
}
|
|
38620
38741
|
const resp = await fetch(url, {
|
|
38621
38742
|
headers,
|
|
@@ -46047,17 +46168,31 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46047
46168
|
const isMac = process.platform === "darwin";
|
|
46048
46169
|
try {
|
|
46049
46170
|
const { spawnSync } = await import("node:child_process");
|
|
46171
|
+
if (process.stdout.isTTY) {
|
|
46172
|
+
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l");
|
|
46173
|
+
}
|
|
46050
46174
|
if (isMac) {
|
|
46051
46175
|
renderInfo(" macOS ARM detected \u2014 installing build deps via Homebrew...");
|
|
46052
46176
|
const brewCheck = spawnSync("which", ["brew"], { stdio: "pipe", timeout: 5e3 });
|
|
46053
46177
|
if (brewCheck.status === 0) {
|
|
46054
|
-
spawnSync("brew", ["install", "llvm", "gcc", "openblas", "libsndfile"], {
|
|
46055
|
-
stdio: "
|
|
46178
|
+
const brewResult = spawnSync("brew", ["install", "llvm", "gcc", "openblas", "libsndfile"], {
|
|
46179
|
+
stdio: "pipe",
|
|
46056
46180
|
timeout: 3e5
|
|
46057
46181
|
});
|
|
46182
|
+
if (brewResult.stdout)
|
|
46183
|
+
process.stdout.write(brewResult.stdout);
|
|
46184
|
+
if (brewResult.stderr)
|
|
46185
|
+
process.stderr.write(brewResult.stderr);
|
|
46058
46186
|
const llvmPrefix = spawnSync("brew", ["--prefix", "llvm"], { stdio: "pipe", timeout: 5e3 });
|
|
46059
46187
|
if (llvmPrefix.stdout) {
|
|
46060
|
-
|
|
46188
|
+
const prefix = llvmPrefix.stdout.toString().trim();
|
|
46189
|
+
process.env.LLVM_CONFIG = `${prefix}/bin/llvm-config`;
|
|
46190
|
+
const openblas = spawnSync("brew", ["--prefix", "openblas"], { stdio: "pipe", timeout: 5e3 });
|
|
46191
|
+
if (openblas.stdout) {
|
|
46192
|
+
const obPrefix = openblas.stdout.toString().trim();
|
|
46193
|
+
process.env.LDFLAGS = `${process.env.LDFLAGS ?? ""} -L${obPrefix}/lib`.trim();
|
|
46194
|
+
process.env.CPPFLAGS = `${process.env.CPPFLAGS ?? ""} -I${obPrefix}/include`.trim();
|
|
46195
|
+
}
|
|
46061
46196
|
}
|
|
46062
46197
|
} else {
|
|
46063
46198
|
renderWarning(" Homebrew not found. Install it: https://brew.sh");
|
|
@@ -46068,7 +46203,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46068
46203
|
const sudoCheck = spawnSync("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
|
|
46069
46204
|
if (sudoCheck.status === 0) {
|
|
46070
46205
|
renderInfo(" Installing system build dependencies (this may take a minute)...");
|
|
46071
|
-
spawnSync("sudo", [
|
|
46206
|
+
const aptResult = spawnSync("sudo", [
|
|
46072
46207
|
"apt-get",
|
|
46073
46208
|
"install",
|
|
46074
46209
|
"-y",
|
|
@@ -46079,11 +46214,18 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46079
46214
|
"gfortran",
|
|
46080
46215
|
"libopenblas-dev",
|
|
46081
46216
|
"libsndfile1-dev"
|
|
46082
|
-
], { stdio: "
|
|
46217
|
+
], { stdio: "pipe", timeout: 12e4 });
|
|
46218
|
+
if (aptResult.stdout)
|
|
46219
|
+
process.stdout.write(aptResult.stdout);
|
|
46220
|
+
if (aptResult.stderr)
|
|
46221
|
+
process.stderr.write(aptResult.stderr);
|
|
46083
46222
|
} else {
|
|
46084
46223
|
renderWarning(" sudo not available \u2014 skipping system build deps. librosa/lhotse may fail to compile.");
|
|
46085
46224
|
}
|
|
46086
46225
|
}
|
|
46226
|
+
if (process.stdout.isTTY) {
|
|
46227
|
+
process.stdout.write("\x1B[?1002h\x1B[?1006h");
|
|
46228
|
+
}
|
|
46087
46229
|
} catch (err) {
|
|
46088
46230
|
renderWarning(` Could not install system build deps: ${err instanceof Error ? err.message : String(err)}`);
|
|
46089
46231
|
}
|
|
@@ -46119,8 +46261,10 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46119
46261
|
// Non-fatal (not hard-imported by LuxTTS):
|
|
46120
46262
|
{ cmd: `${pipCmd} -m pip install --quiet piper-phonemize --find-links https://k2-fsa.github.io/icefall/piper_phonemize.html`, fatal: false, label: "piper-phonemize (optional)" },
|
|
46121
46263
|
{ cmd: `${pipCmd} -m pip install --quiet jieba pypinyin cn2an`, fatal: true, label: "Chinese text processing" },
|
|
46122
|
-
// LuxTTS itself:
|
|
46123
|
-
|
|
46264
|
+
// LuxTTS itself: use --no-deps on ARM because we installed deps individually above.
|
|
46265
|
+
// Without --no-deps, pip tries to resolve zipvoice's full dependency tree which
|
|
46266
|
+
// includes piper-phonemize — and that has no macOS ARM wheel, causing fatal failure.
|
|
46267
|
+
{ cmd: `${pipCmd} -m pip install --quiet --no-deps -e ${JSON.stringify(repoDir)}`, fatal: true, label: "LuxTTS (editable install)" }
|
|
46124
46268
|
] : [
|
|
46125
46269
|
// x86_64: all-in-one (fast, all wheels available)
|
|
46126
46270
|
{
|
|
@@ -50202,7 +50346,12 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
50202
50346
|
const healthUrl = `${normalizedUrl}${provider.modelsPath}`;
|
|
50203
50347
|
const headers = {};
|
|
50204
50348
|
if (apiKey) {
|
|
50205
|
-
|
|
50349
|
+
if (provider.id === "anthropic") {
|
|
50350
|
+
headers["x-api-key"] = apiKey;
|
|
50351
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
50352
|
+
} else {
|
|
50353
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
50354
|
+
}
|
|
50206
50355
|
}
|
|
50207
50356
|
const resp = await fetch(healthUrl, {
|
|
50208
50357
|
headers,
|
|
@@ -65099,6 +65248,7 @@ async function startInteractive(config, repoPath) {
|
|
|
65099
65248
|
initOaDirectory(repoRoot);
|
|
65100
65249
|
const savedSettings = resolveSettings(repoRoot);
|
|
65101
65250
|
if (process.stdout.isTTY) {
|
|
65251
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
65102
65252
|
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?1049h\x1B[48;5;233m\x1B[2J\x1B[3J\x1B[H\x1B[?25l");
|
|
65103
65253
|
const restoreScreen = () => {
|
|
65104
65254
|
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?25h\x1B[?1049l");
|
|
@@ -69957,9 +70107,40 @@ async function main() {
|
|
|
69957
70107
|
}
|
|
69958
70108
|
var scriptPath = process.argv[1] ?? "";
|
|
69959
70109
|
var isMain = scriptPath.endsWith("index.js") || scriptPath.endsWith("index.ts") || scriptPath.endsWith("open-agents-bin") || scriptPath.includes("open-agents") || scriptPath.includes("/oa");
|
|
70110
|
+
function crashLog(label, err) {
|
|
70111
|
+
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
70112
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
70113
|
+
const logLine = `[${timestamp}] ${label}: ${msg}
|
|
70114
|
+
`;
|
|
70115
|
+
try {
|
|
70116
|
+
const { appendFileSync: appendFileSync5, mkdirSync: mkdirSync30 } = __require("node:fs");
|
|
70117
|
+
const { join: join76 } = __require("node:path");
|
|
70118
|
+
const { homedir: homedir20 } = __require("node:os");
|
|
70119
|
+
const logDir = join76(homedir20(), ".open-agents");
|
|
70120
|
+
mkdirSync30(logDir, { recursive: true });
|
|
70121
|
+
appendFileSync5(join76(logDir, "crash.log"), logLine);
|
|
70122
|
+
} catch {
|
|
70123
|
+
}
|
|
70124
|
+
try {
|
|
70125
|
+
process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?25h\x1B[?1049l\x1B[0m\n");
|
|
70126
|
+
process.stderr.write(`\x1B[31m\u2716 ${label}:\x1B[0m ${msg}
|
|
70127
|
+
`);
|
|
70128
|
+
process.stderr.write(`\x1B[2m Crash log: ~/.open-agents/crash.log\x1B[0m
|
|
70129
|
+
`);
|
|
70130
|
+
} catch {
|
|
70131
|
+
}
|
|
70132
|
+
}
|
|
70133
|
+
process.on("uncaughtException", (err) => {
|
|
70134
|
+
crashLog("Uncaught exception", err);
|
|
70135
|
+
process.exit(1);
|
|
70136
|
+
});
|
|
70137
|
+
process.on("unhandledRejection", (reason) => {
|
|
70138
|
+
crashLog("Unhandled rejection", reason);
|
|
70139
|
+
process.exit(1);
|
|
70140
|
+
});
|
|
69960
70141
|
if (isMain && !process.env.__OPEN_AGENTS_NO_AUTO_RUN) {
|
|
69961
70142
|
await main().catch((err) => {
|
|
69962
|
-
|
|
70143
|
+
crashLog("Fatal error", err);
|
|
69963
70144
|
process.exit(1);
|
|
69964
70145
|
});
|
|
69965
70146
|
}
|
package/package.json
CHANGED