open-agents-ai 0.187.578 → 0.187.580
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 +280 -75
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ function parseBackendType(value2) {
|
|
|
65
65
|
return VALID_BACKEND_TYPES.has(value2) ? value2 : void 0;
|
|
66
66
|
}
|
|
67
67
|
function loadConfigFile() {
|
|
68
|
-
const configPath2 = join(
|
|
68
|
+
const configPath2 = join(openAgentsConfigDir(), "config.json");
|
|
69
69
|
if (!existsSync(configPath2)) return {};
|
|
70
70
|
try {
|
|
71
71
|
const raw = readFileSync(configPath2, "utf8");
|
|
@@ -110,13 +110,16 @@ function mergeConfig(base3, overrides) {
|
|
|
110
110
|
return { ...base3, ...overrides };
|
|
111
111
|
}
|
|
112
112
|
function setConfigValue(key, value2) {
|
|
113
|
-
const dir =
|
|
113
|
+
const dir = openAgentsConfigDir();
|
|
114
114
|
mkdirSync(dir, { recursive: true });
|
|
115
115
|
const configPath2 = join(dir, "config.json");
|
|
116
116
|
const existing = loadConfigFile();
|
|
117
117
|
existing[key] = coerceConfigValue(key, value2);
|
|
118
118
|
writeFileSync(configPath2, JSON.stringify(existing, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
119
119
|
}
|
|
120
|
+
function openAgentsConfigDir() {
|
|
121
|
+
return join(process.env["OPEN_AGENTS_CONFIG_HOME"] ?? homedir(), ".open-agents");
|
|
122
|
+
}
|
|
120
123
|
function coerceConfigValue(key, value2) {
|
|
121
124
|
const intKeys = /* @__PURE__ */ new Set(["maxRetries", "timeoutMs"]);
|
|
122
125
|
const boolKeys = /* @__PURE__ */ new Set(["dryRun", "verbose"]);
|
|
@@ -569510,6 +569513,7 @@ var init_sponsor_wizard = __esm({
|
|
|
569510
569513
|
var voice_exports = {};
|
|
569511
569514
|
__export(voice_exports, {
|
|
569512
569515
|
VoiceEngine: () => VoiceEngine,
|
|
569516
|
+
applySupertonicExpressionTags: () => applySupertonicExpressionTags,
|
|
569513
569517
|
computeProsodyHint: () => computeProsodyHint,
|
|
569514
569518
|
describeTaskComplete: () => describeTaskComplete,
|
|
569515
569519
|
describeToolCall: () => describeToolCall,
|
|
@@ -569597,7 +569601,7 @@ function supertonicProfilesFile() {
|
|
|
569597
569601
|
return join106(voiceDir(), "supertonic3-profiles.json");
|
|
569598
569602
|
}
|
|
569599
569603
|
function isSupertonicExpression(value2) {
|
|
569600
|
-
return value2 === "none" || value2 === "laugh" || value2 === "breath" || value2 === "sigh";
|
|
569604
|
+
return value2 === "auto" || value2 === "none" || value2 === "laugh" || value2 === "breath" || value2 === "sigh";
|
|
569601
569605
|
}
|
|
569602
569606
|
function normalizeSupertonicSettings(value2) {
|
|
569603
569607
|
const v = value2 && typeof value2 === "object" ? value2 : {};
|
|
@@ -569622,9 +569626,122 @@ function clampFloat(value2, fallback, min, max) {
|
|
|
569622
569626
|
function clampInt(value2, fallback, min, max) {
|
|
569623
569627
|
return Math.round(clampFloat(value2, fallback, min, max));
|
|
569624
569628
|
}
|
|
569625
|
-
function
|
|
569626
|
-
|
|
569627
|
-
|
|
569629
|
+
function applySupertonicExpressionTags(text, expression, emotion) {
|
|
569630
|
+
const cleaned = text.trim();
|
|
569631
|
+
if (!cleaned || expression === "none") return cleaned;
|
|
569632
|
+
if (SUPERTONIC_EXPRESSION_TAG_RE.test(cleaned)) {
|
|
569633
|
+
return normalizeSupertonicTagSpacing(cleaned);
|
|
569634
|
+
}
|
|
569635
|
+
if (expression !== "auto") {
|
|
569636
|
+
return injectSupertonicTag(cleaned, expression);
|
|
569637
|
+
}
|
|
569638
|
+
const plan = inferSupertonicExpressionPlan(cleaned, emotion);
|
|
569639
|
+
if (!plan.primary) return cleaned;
|
|
569640
|
+
let expressive = injectSupertonicTag(cleaned, plan.primary);
|
|
569641
|
+
if (plan.boundaryBreath && !expressive.includes("<breath>")) {
|
|
569642
|
+
expressive = injectBreathAtSentenceBoundary(expressive);
|
|
569643
|
+
}
|
|
569644
|
+
if (plan.secondary && !expressive.includes(`<${plan.secondary}>`)) {
|
|
569645
|
+
expressive = injectSupertonicTag(expressive, plan.secondary);
|
|
569646
|
+
}
|
|
569647
|
+
return normalizeSupertonicTagSpacing(expressive);
|
|
569648
|
+
}
|
|
569649
|
+
function normalizeSupertonicTagSpacing(text) {
|
|
569650
|
+
return text.replace(/\s*(<(?:laugh|breath|sigh)>)\s*/gi, " $1 ").replace(/\s{2,}/g, " ").trim();
|
|
569651
|
+
}
|
|
569652
|
+
function inferSupertonicExpressionPlan(text, emotion) {
|
|
569653
|
+
const lower = text.toLowerCase();
|
|
569654
|
+
const hasFailure = /\b(error|failed|failure|failing|issue|exception|timeout|blocked|cannot|can't|could not|incomplete|crash|missing|denied|rejected|unreadable|stale|invalid)\b/.test(
|
|
569655
|
+
lower
|
|
569656
|
+
);
|
|
569657
|
+
const persistentFailure = hasFailure && /\b(again|repeated|persistent|consecutive|second|third|keeps|still|retry|attempt)\b/.test(
|
|
569658
|
+
lower
|
|
569659
|
+
);
|
|
569660
|
+
const hasSuccess = /\b(success|successful|successfully|complete|completed|done|clean|passed|green|fixed|resolved|ready|excellent|great|nice|all clean|zero errors)\b/.test(
|
|
569661
|
+
lower
|
|
569662
|
+
);
|
|
569663
|
+
const playful = /\b(playful|fun|delight|spark|nice|great|excellent|tiny victory|clean run)\b/.test(
|
|
569664
|
+
lower
|
|
569665
|
+
);
|
|
569666
|
+
const valence = emotion?.valence ?? 0;
|
|
569667
|
+
const arousal = emotion?.arousal ?? 0.3;
|
|
569668
|
+
const stressed = valence < -0.2 && arousal > 0.5;
|
|
569669
|
+
const subdued = valence < -0.2 && arousal <= 0.5;
|
|
569670
|
+
const excited = valence > 0.3 && arousal > 0.5;
|
|
569671
|
+
const multiSentence = /[.!?]\s+\S/.test(text);
|
|
569672
|
+
if (persistentFailure) {
|
|
569673
|
+
return { primary: "sigh", secondary: stressed ? "breath" : void 0 };
|
|
569674
|
+
}
|
|
569675
|
+
if (hasFailure) {
|
|
569676
|
+
return {
|
|
569677
|
+
primary: "sigh",
|
|
569678
|
+
secondary: stressed ? "breath" : void 0,
|
|
569679
|
+
boundaryBreath: multiSentence
|
|
569680
|
+
};
|
|
569681
|
+
}
|
|
569682
|
+
if (excited && (hasSuccess || playful)) {
|
|
569683
|
+
return { primary: "laugh" };
|
|
569684
|
+
}
|
|
569685
|
+
if (hasSuccess && playful) {
|
|
569686
|
+
return { primary: "laugh" };
|
|
569687
|
+
}
|
|
569688
|
+
if (stressed) {
|
|
569689
|
+
return { primary: "breath", boundaryBreath: multiSentence };
|
|
569690
|
+
}
|
|
569691
|
+
if (subdued && text.length > 80) {
|
|
569692
|
+
return { primary: "sigh" };
|
|
569693
|
+
}
|
|
569694
|
+
if (arousal > 0.75 && text.length > 90) {
|
|
569695
|
+
return { primary: "breath", boundaryBreath: multiSentence };
|
|
569696
|
+
}
|
|
569697
|
+
return { primary: null };
|
|
569698
|
+
}
|
|
569699
|
+
function injectBreathAtSentenceBoundary(text) {
|
|
569700
|
+
return text.replace(/([.!?])\s+(?=\S)/, `$1 <breath> `);
|
|
569701
|
+
}
|
|
569702
|
+
function injectSupertonicTag(text, tag) {
|
|
569703
|
+
if (tag === "laugh") {
|
|
569704
|
+
const opener = text.match(/^(nice|great|excellent|beautiful|perfect|lovely)\b[,!.]?\s*/i);
|
|
569705
|
+
if (opener) {
|
|
569706
|
+
return `${opener[0].trim()} <laugh> ${text.slice(opener[0].length).trim()}`;
|
|
569707
|
+
}
|
|
569708
|
+
const successIdx = text.search(
|
|
569709
|
+
/\b(successfully|passed|clean|all clean|zero errors|ready|resolved|green|complete|completed|done)\b/i
|
|
569710
|
+
);
|
|
569711
|
+
if (successIdx >= 0) {
|
|
569712
|
+
return insertTagAfterMatch(
|
|
569713
|
+
text,
|
|
569714
|
+
/\b(successfully|passed|clean|all clean|zero errors|ready|resolved|green|complete|completed|done)\b/i,
|
|
569715
|
+
tag
|
|
569716
|
+
);
|
|
569717
|
+
}
|
|
569718
|
+
return insertTagAfterOpeningClause(text, tag);
|
|
569719
|
+
}
|
|
569720
|
+
if (tag === "sigh") {
|
|
569721
|
+
const failure = /\b(failed again|keeps failing|failed|failure|failing|hit an issue|returned an error|could not finish|incomplete|timed out|timeout|blocked)\b/i;
|
|
569722
|
+
if (failure.test(text)) return insertTagBeforeMatch(text, failure, tag);
|
|
569723
|
+
return `<${tag}> ${text}`;
|
|
569724
|
+
}
|
|
569725
|
+
const pivot = /,\s*(pushing through|moving forward|being careful|addressing|retrying|checking|continuing)\b/i;
|
|
569726
|
+
if (pivot.test(text)) {
|
|
569727
|
+
return text.replace(pivot, (_match, phrase) => `, <${tag}> ${phrase}`);
|
|
569728
|
+
}
|
|
569729
|
+
return insertTagAfterOpeningClause(text, tag);
|
|
569730
|
+
}
|
|
569731
|
+
function insertTagAfterMatch(text, pattern, tag) {
|
|
569732
|
+
return text.replace(pattern, (match) => `${match} <${tag}>`);
|
|
569733
|
+
}
|
|
569734
|
+
function insertTagBeforeMatch(text, pattern, tag) {
|
|
569735
|
+
return text.replace(pattern, (match) => `<${tag}> ${match}`);
|
|
569736
|
+
}
|
|
569737
|
+
function insertTagAfterOpeningClause(text, tag) {
|
|
569738
|
+
const clause = text.match(/^(.{24,96}?[,:;.])\s+(.+)$/);
|
|
569739
|
+
if (clause) return `${clause[1]} <${tag}> ${clause[2]}`;
|
|
569740
|
+
const words = text.split(/\s+/);
|
|
569741
|
+
if (words.length > 6) {
|
|
569742
|
+
return `${words.slice(0, 5).join(" ")} <${tag}> ${words.slice(5).join(" ")}`;
|
|
569743
|
+
}
|
|
569744
|
+
return `<${tag}> ${text}`;
|
|
569628
569745
|
}
|
|
569629
569746
|
function writeDetectTorchScript(targetPath) {
|
|
569630
569747
|
if (existsSync89(targetPath)) return;
|
|
@@ -570292,7 +570409,7 @@ function formatBytes2(bytes) {
|
|
|
570292
570409
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
|
|
570293
570410
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
570294
570411
|
}
|
|
570295
|
-
var VOICE_MODELS, SUPERTONIC_LANGS, SUPERTONIC_VOICES, DEFAULT_SUPERTONIC_SETTINGS, SUPERTONIC_INFER_PY, VoiceEngine, RING_BUFFER_SIZE, narration;
|
|
570412
|
+
var VOICE_MODELS, SUPERTONIC_LANGS, SUPERTONIC_VOICES, DEFAULT_SUPERTONIC_SETTINGS, SUPERTONIC_EXPRESSION_TAG_RE, SUPERTONIC_INFER_PY, VoiceEngine, RING_BUFFER_SIZE, narration;
|
|
570296
570413
|
var init_voice = __esm({
|
|
570297
570414
|
"packages/cli/src/tui/voice.ts"() {
|
|
570298
570415
|
"use strict";
|
|
@@ -570433,8 +570550,9 @@ var init_voice = __esm({
|
|
|
570433
570550
|
lang: "en",
|
|
570434
570551
|
speed: 1.05,
|
|
570435
570552
|
totalStep: 8,
|
|
570436
|
-
expression: "
|
|
570553
|
+
expression: "auto"
|
|
570437
570554
|
};
|
|
570555
|
+
SUPERTONIC_EXPRESSION_TAG_RE = /<(?:laugh|breath|sigh)>/i;
|
|
570438
570556
|
SUPERTONIC_INFER_PY = String.raw`
|
|
570439
570557
|
import json, sys, traceback
|
|
570440
570558
|
|
|
@@ -570851,7 +570969,7 @@ except Exception as exc:
|
|
|
570851
570969
|
speak(text, emotion) {
|
|
570852
570970
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
570853
570971
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
570854
|
-
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor, 0.6);
|
|
570972
|
+
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor, 0.6, emotion);
|
|
570855
570973
|
}
|
|
570856
570974
|
/**
|
|
570857
570975
|
* Speak text at reduced volume with narrow stereo placement to indicate
|
|
@@ -570863,7 +570981,7 @@ except Exception as exc:
|
|
|
570863
570981
|
speakSubordinate(text, emotion) {
|
|
570864
570982
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
570865
570983
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
570866
|
-
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15);
|
|
570984
|
+
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15, emotion);
|
|
570867
570985
|
}
|
|
570868
570986
|
/** Wait until the speak queue is fully drained (all audio played). */
|
|
570869
570987
|
async waitUntilIdle() {
|
|
@@ -570874,11 +570992,20 @@ except Exception as exc:
|
|
|
570874
570992
|
await this.sleep(100);
|
|
570875
570993
|
}
|
|
570876
570994
|
}
|
|
570877
|
-
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
570995
|
+
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6, emotion) {
|
|
570878
570996
|
if (!this.enabled || !this.ready) return;
|
|
570879
570997
|
text = sanitizeForTTS(text);
|
|
570880
570998
|
if (!text.trim()) return;
|
|
570881
570999
|
const chunks = this.chunkText(text);
|
|
571000
|
+
const supertonicTagsPrepared = this.supertonicActive;
|
|
571001
|
+
if (supertonicTagsPrepared && chunks.length > 0) {
|
|
571002
|
+
const settings = this.getSupertonicSettings();
|
|
571003
|
+
chunks[0] = applySupertonicExpressionTags(
|
|
571004
|
+
chunks[0],
|
|
571005
|
+
settings.expression,
|
|
571006
|
+
emotion
|
|
571007
|
+
);
|
|
571008
|
+
}
|
|
570882
571009
|
if (this.speakQueue.length >= 30) {
|
|
570883
571010
|
return;
|
|
570884
571011
|
}
|
|
@@ -570888,7 +571015,9 @@ except Exception as exc:
|
|
|
570888
571015
|
volume,
|
|
570889
571016
|
pitchFactor,
|
|
570890
571017
|
speedFactor,
|
|
570891
|
-
stereoDelayMs
|
|
571018
|
+
stereoDelayMs,
|
|
571019
|
+
emotion,
|
|
571020
|
+
supertonicTagsPrepared
|
|
570892
571021
|
});
|
|
570893
571022
|
}
|
|
570894
571023
|
if (!this.speaking) {
|
|
@@ -571147,7 +571276,9 @@ except Exception as exc:
|
|
|
571147
571276
|
item.volume,
|
|
571148
571277
|
item.pitchFactor,
|
|
571149
571278
|
item.speedFactor,
|
|
571150
|
-
item.stereoDelayMs
|
|
571279
|
+
item.stereoDelayMs,
|
|
571280
|
+
item.emotion,
|
|
571281
|
+
item.supertonicTagsPrepared
|
|
571151
571282
|
);
|
|
571152
571283
|
}
|
|
571153
571284
|
} catch {
|
|
@@ -571175,7 +571306,7 @@ except Exception as exc:
|
|
|
571175
571306
|
// -------------------------------------------------------------------------
|
|
571176
571307
|
// Synthesis pipeline
|
|
571177
571308
|
// -------------------------------------------------------------------------
|
|
571178
|
-
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
571309
|
+
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6, emotion, supertonicTagsPrepared = false) {
|
|
571179
571310
|
if (this.luxttsActive) {
|
|
571180
571311
|
await this.synthesizeWithLuxtts(
|
|
571181
571312
|
text,
|
|
@@ -571192,7 +571323,9 @@ except Exception as exc:
|
|
|
571192
571323
|
volume,
|
|
571193
571324
|
pitchFactor,
|
|
571194
571325
|
speedFactor,
|
|
571195
|
-
stereoDelayMs
|
|
571326
|
+
stereoDelayMs,
|
|
571327
|
+
emotion,
|
|
571328
|
+
!supertonicTagsPrepared
|
|
571196
571329
|
);
|
|
571197
571330
|
return;
|
|
571198
571331
|
}
|
|
@@ -571704,13 +571837,11 @@ except Exception as exc:
|
|
|
571704
571837
|
child.stdin?.end(JSON.stringify(req2));
|
|
571705
571838
|
});
|
|
571706
571839
|
}
|
|
571707
|
-
async synthesizeSupertonicWav(text, speedFactor = 1) {
|
|
571840
|
+
async synthesizeSupertonicWav(text, speedFactor = 1, emotion, injectExpressionTags = true) {
|
|
571708
571841
|
await this.ensureSupertonic();
|
|
571709
571842
|
const settings = this.getSupertonicSettings();
|
|
571710
|
-
const
|
|
571711
|
-
|
|
571712
|
-
settings.expression
|
|
571713
|
-
);
|
|
571843
|
+
const baseText = sanitizeForTTS(text);
|
|
571844
|
+
const cleaned = injectExpressionTags ? applySupertonicExpressionTags(baseText, settings.expression, emotion) : baseText;
|
|
571714
571845
|
if (!cleaned) return null;
|
|
571715
571846
|
const wavPath = join106(
|
|
571716
571847
|
tmpdir20(),
|
|
@@ -571730,8 +571861,13 @@ except Exception as exc:
|
|
|
571730
571861
|
return null;
|
|
571731
571862
|
}
|
|
571732
571863
|
}
|
|
571733
|
-
async synthesizeWithSupertonic(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
571734
|
-
const wavPath = await this.synthesizeSupertonicWav(
|
|
571864
|
+
async synthesizeWithSupertonic(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6, emotion, injectExpressionTags = true) {
|
|
571865
|
+
const wavPath = await this.synthesizeSupertonicWav(
|
|
571866
|
+
text,
|
|
571867
|
+
speedFactor,
|
|
571868
|
+
emotion,
|
|
571869
|
+
injectExpressionTags
|
|
571870
|
+
);
|
|
571735
571871
|
if (!wavPath) return;
|
|
571736
571872
|
await this.postProcessAndPlayLuxtts(
|
|
571737
571873
|
wavPath,
|
|
@@ -579964,14 +580100,14 @@ async function handleSupertonicMenu(ctx3, save2) {
|
|
|
579964
580100
|
];
|
|
579965
580101
|
const speeds = ["0.9", "1.0", "1.05", "1.2", "1.35", "1.5"];
|
|
579966
580102
|
const steps = ["6", "8", "10", "12"];
|
|
579967
|
-
const expressions = ["none", "laugh", "breath", "sigh"];
|
|
580103
|
+
const expressions = ["auto", "none", "laugh", "breath", "sigh"];
|
|
579968
580104
|
while (true) {
|
|
579969
580105
|
const st = ctx3.voiceGetSupertonicSettings?.() ?? {
|
|
579970
580106
|
voiceName: "M4",
|
|
579971
580107
|
lang: "en",
|
|
579972
580108
|
speed: 1.05,
|
|
579973
580109
|
totalStep: 8,
|
|
579974
|
-
expression: "
|
|
580110
|
+
expression: "auto"
|
|
579975
580111
|
};
|
|
579976
580112
|
const profiles = ctx3.voiceListSupertonicProfiles?.() ?? [];
|
|
579977
580113
|
const items = [
|
|
@@ -594439,6 +594575,18 @@ async function runCommand(input, opts) {
|
|
|
594439
594575
|
const argsStr = rest.join(" ");
|
|
594440
594576
|
const release = await acquireLock2();
|
|
594441
594577
|
try {
|
|
594578
|
+
const quick2 = buildNonInteractiveSummary(cmdName, argsStr, opts?.config);
|
|
594579
|
+
if (quick2) {
|
|
594580
|
+
return {
|
|
594581
|
+
ok: true,
|
|
594582
|
+
command: cmdName,
|
|
594583
|
+
args: argsStr,
|
|
594584
|
+
kind: "handled",
|
|
594585
|
+
output: quick2,
|
|
594586
|
+
ansi: quick2,
|
|
594587
|
+
durationMs: Date.now() - start2
|
|
594588
|
+
};
|
|
594589
|
+
}
|
|
594442
594590
|
const buf = [];
|
|
594443
594591
|
setContentWriteHook({
|
|
594444
594592
|
begin: () => {
|
|
@@ -594489,6 +594637,43 @@ async function runCommand(input, opts) {
|
|
|
594489
594637
|
release();
|
|
594490
594638
|
}
|
|
594491
594639
|
}
|
|
594640
|
+
function buildNonInteractiveSummary(cmdName, _args, config) {
|
|
594641
|
+
const cfg = config ?? loadConfig();
|
|
594642
|
+
if (cmdName === "setup" || cmdName === "wizard") {
|
|
594643
|
+
return [
|
|
594644
|
+
"open-agents setup",
|
|
594645
|
+
"",
|
|
594646
|
+
"The setup wizard is an interactive terminal flow. In the GUI command bridge it is summarized instead of opening prompts, installing software, starting Ollama, or pulling models.",
|
|
594647
|
+
"",
|
|
594648
|
+
`Current backend: ${cfg.backendType ?? "ollama"}`,
|
|
594649
|
+
`Current endpoint: ${cfg.backendUrl ?? "http://127.0.0.1:11434"}`,
|
|
594650
|
+
`Current model: ${cfg.model ?? "qwen3.5:latest"}`,
|
|
594651
|
+
"",
|
|
594652
|
+
"Available non-interactive setup actions:",
|
|
594653
|
+
" /endpoint <url> Set or inspect the inference endpoint.",
|
|
594654
|
+
" /model <name> Set the active model directly.",
|
|
594655
|
+
" /models Show model-selection guidance.",
|
|
594656
|
+
" /config Inspect persisted configuration.",
|
|
594657
|
+
" /doctor Run diagnostics from the terminal if deeper repair is needed.",
|
|
594658
|
+
"",
|
|
594659
|
+
"Open a terminal and run `oa`, then use /setup for the full guided wizard."
|
|
594660
|
+
].join("\n");
|
|
594661
|
+
}
|
|
594662
|
+
if (cmdName === "models") {
|
|
594663
|
+
return [
|
|
594664
|
+
"open-agents models",
|
|
594665
|
+
"",
|
|
594666
|
+
"The model picker is interactive in the TUI. The GUI bridge does not probe remote model endpoints here, so it cannot hang on a stale backend.",
|
|
594667
|
+
"",
|
|
594668
|
+
`Active model: ${cfg.model ?? "qwen3.5:latest"}`,
|
|
594669
|
+
`Endpoint: ${cfg.backendUrl ?? "http://127.0.0.1:11434"}`,
|
|
594670
|
+
`Backend: ${cfg.backendType ?? "ollama"}`,
|
|
594671
|
+
"",
|
|
594672
|
+
"Use /model <name> to set a model directly, /endpoint to switch providers, or open the TUI for the searchable model picker."
|
|
594673
|
+
].join("\n");
|
|
594674
|
+
}
|
|
594675
|
+
return null;
|
|
594676
|
+
}
|
|
594492
594677
|
function acquireLock2() {
|
|
594493
594678
|
let release;
|
|
594494
594679
|
const next = new Promise((res) => {
|
|
@@ -607320,6 +607505,7 @@ async function refreshEndpointRegistry() {
|
|
|
607320
607505
|
type: config.backendType || "ollama",
|
|
607321
607506
|
authKey: config.apiKey
|
|
607322
607507
|
});
|
|
607508
|
+
if (process.env["OA_SKIP_SPONSOR_DISCOVERY"] === "1") return;
|
|
607323
607509
|
try {
|
|
607324
607510
|
const resp = await fetch("https://openagents.nexus/api/v1/sponsors", {
|
|
607325
607511
|
signal: AbortSignal.timeout(5e3)
|
|
@@ -607440,6 +607626,16 @@ function getBackendTimeoutMs(perRequestSeconds) {
|
|
|
607440
607626
|
}
|
|
607441
607627
|
return BACKEND_TIMEOUT_DEFAULT_MS;
|
|
607442
607628
|
}
|
|
607629
|
+
function getModelListTimeoutMs() {
|
|
607630
|
+
const envS = process.env["OA_MODEL_LIST_TIMEOUT_S"];
|
|
607631
|
+
if (envS) {
|
|
607632
|
+
const n2 = parseFloat(envS);
|
|
607633
|
+
if (Number.isFinite(n2) && n2 > 0) {
|
|
607634
|
+
return Math.min(Math.floor(n2 * 1e3), 3e4);
|
|
607635
|
+
}
|
|
607636
|
+
}
|
|
607637
|
+
return MODEL_LIST_TIMEOUT_DEFAULT_MS;
|
|
607638
|
+
}
|
|
607443
607639
|
function recordMetric(method, path11, status) {
|
|
607444
607640
|
const key = `${method}|${path11}|${status}`;
|
|
607445
607641
|
const existing = metrics.requests.get(key);
|
|
@@ -607879,10 +608075,12 @@ function ollamaRequest(ollamaUrl, path11, method, body, timeoutMs) {
|
|
|
607879
608075
|
}
|
|
607880
608076
|
};
|
|
607881
608077
|
const transport = isHttps ? https3 : http5;
|
|
608078
|
+
const _to = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
|
|
607882
608079
|
const proxyReq = transport.request(options2, (proxyRes) => {
|
|
607883
608080
|
const chunks = [];
|
|
607884
608081
|
proxyRes.on("data", (chunk) => chunks.push(chunk));
|
|
607885
608082
|
proxyRes.on("end", () => {
|
|
608083
|
+
clearTimeout(hardTimeout);
|
|
607886
608084
|
resolve43({
|
|
607887
608085
|
status: proxyRes.statusCode ?? 500,
|
|
607888
608086
|
headers: proxyRes.headers,
|
|
@@ -607890,11 +608088,17 @@ function ollamaRequest(ollamaUrl, path11, method, body, timeoutMs) {
|
|
|
607890
608088
|
});
|
|
607891
608089
|
});
|
|
607892
608090
|
});
|
|
607893
|
-
const
|
|
608091
|
+
const hardTimeout = setTimeout(() => {
|
|
608092
|
+
proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
|
|
608093
|
+
}, _to);
|
|
608094
|
+
hardTimeout.unref();
|
|
607894
608095
|
proxyReq.setTimeout(_to, () => {
|
|
607895
608096
|
proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
|
|
607896
608097
|
});
|
|
607897
|
-
proxyReq.on("error",
|
|
608098
|
+
proxyReq.on("error", (err) => {
|
|
608099
|
+
clearTimeout(hardTimeout);
|
|
608100
|
+
reject(err);
|
|
608101
|
+
});
|
|
607898
608102
|
if (body) proxyReq.write(body);
|
|
607899
608103
|
proxyReq.end();
|
|
607900
608104
|
});
|
|
@@ -608670,7 +608874,7 @@ async function fetchAggregatedOllamaTags() {
|
|
|
608670
608874
|
try {
|
|
608671
608875
|
const isOllama = ep.type === "ollama";
|
|
608672
608876
|
const path11 = isOllama ? "/api/tags" : "/v1/models";
|
|
608673
|
-
const result = await ollamaRequest(ep.url, path11, "GET");
|
|
608877
|
+
const result = await ollamaRequest(ep.url, path11, "GET", void 0, getModelListTimeoutMs());
|
|
608674
608878
|
if (result.status !== 200) return;
|
|
608675
608879
|
const body = JSON.parse(result.body);
|
|
608676
608880
|
if (isOllama) {
|
|
@@ -608727,6 +608931,10 @@ async function fetchAggregatedOllamaTags() {
|
|
|
608727
608931
|
return out.sort((a2, b) => a2.name.localeCompare(b.name));
|
|
608728
608932
|
}
|
|
608729
608933
|
async function handleApiTags(res) {
|
|
608934
|
+
if (process.env["OA_API_TEST_MODE"] === "1") {
|
|
608935
|
+
jsonResponse(res, 200, { models: [] });
|
|
608936
|
+
return;
|
|
608937
|
+
}
|
|
608730
608938
|
try {
|
|
608731
608939
|
const models = await fetchAggregatedOllamaTags();
|
|
608732
608940
|
jsonResponse(res, 200, { models });
|
|
@@ -611272,8 +611480,16 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
611272
611480
|
jsonResponse(res, 400, { error: "missing_text" });
|
|
611273
611481
|
return;
|
|
611274
611482
|
}
|
|
611483
|
+
const voiceStatus = getRuntimeStatus();
|
|
611484
|
+
if (!voiceStatus.voiceReady) {
|
|
611485
|
+
jsonResponse(res, 501, {
|
|
611486
|
+
error: "tts_not_ready",
|
|
611487
|
+
message: "Voice synthesis is not ready in the daemon. Warm the voice runtime with POST /v1/voice/start before requesting audio.",
|
|
611488
|
+
state: voiceStatus
|
|
611489
|
+
});
|
|
611490
|
+
return;
|
|
611491
|
+
}
|
|
611275
611492
|
try {
|
|
611276
|
-
await ensureRuntime();
|
|
611277
611493
|
const ve = getVoiceEngine();
|
|
611278
611494
|
let prevModel = null;
|
|
611279
611495
|
if (requestedModel && ve.modelId !== requestedModel) {
|
|
@@ -613510,6 +613726,7 @@ function startApiServer(options2 = {}) {
|
|
|
613510
613726
|
if (options2.host) host = options2.host;
|
|
613511
613727
|
if (options2.port) port = options2.port;
|
|
613512
613728
|
const verbose = options2.verbose ?? false;
|
|
613729
|
+
const apiTestMode = process.env["OA_API_TEST_MODE"] === "1";
|
|
613513
613730
|
const config = loadConfig();
|
|
613514
613731
|
const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
|
|
613515
613732
|
const cwd4 = process.cwd();
|
|
@@ -613529,31 +613746,37 @@ function startApiServer(options2 = {}) {
|
|
|
613529
613746
|
taskMgr.onEviction((taskId) => {
|
|
613530
613747
|
deleteAgentTaskSidecar(taskId);
|
|
613531
613748
|
});
|
|
613532
|
-
|
|
613533
|
-
|
|
613534
|
-
|
|
613749
|
+
if (!apiTestMode) {
|
|
613750
|
+
restoreAgentTasks(taskMgr).then((report2) => {
|
|
613751
|
+
if (report2.restored > 0) {
|
|
613752
|
+
log22(` task recovery: restored=${report2.restored} re-attached=${report2.reAttached} marked-failed=${report2.markedFailed}
|
|
613535
613753
|
`);
|
|
613536
|
-
|
|
613537
|
-
|
|
613538
|
-
|
|
613539
|
-
|
|
613540
|
-
|
|
613541
|
-
|
|
613542
|
-
|
|
613543
|
-
|
|
613544
|
-
|
|
613754
|
+
}
|
|
613755
|
+
}).catch(() => {
|
|
613756
|
+
});
|
|
613757
|
+
}
|
|
613758
|
+
if (!apiTestMode) {
|
|
613759
|
+
setTimeout(() => {
|
|
613760
|
+
try {
|
|
613761
|
+
purgeOldSidecars(24);
|
|
613762
|
+
} catch {
|
|
613763
|
+
}
|
|
613764
|
+
}, 5e3).unref();
|
|
613765
|
+
}
|
|
613545
613766
|
} catch {
|
|
613546
613767
|
}
|
|
613547
|
-
|
|
613548
|
-
|
|
613549
|
-
|
|
613550
|
-
|
|
613768
|
+
if (!apiTestMode) {
|
|
613769
|
+
try {
|
|
613770
|
+
const report2 = loadPersistedSessions();
|
|
613771
|
+
if (report2.restored > 0 || report2.staleInFlight > 0) {
|
|
613772
|
+
log22(` chat sessions: restored=${report2.restored} stale-in-flight=${report2.staleInFlight}
|
|
613551
613773
|
`);
|
|
613774
|
+
}
|
|
613775
|
+
} catch {
|
|
613552
613776
|
}
|
|
613553
|
-
} catch {
|
|
613554
613777
|
}
|
|
613555
613778
|
setTodoEventPublisher(null);
|
|
613556
|
-
try {
|
|
613779
|
+
if (!apiTestMode) try {
|
|
613557
613780
|
const dir = todoDir();
|
|
613558
613781
|
try {
|
|
613559
613782
|
mkdirSync69(dir, { recursive: true });
|
|
@@ -613630,7 +613853,7 @@ function startApiServer(options2 = {}) {
|
|
|
613630
613853
|
`);
|
|
613631
613854
|
}
|
|
613632
613855
|
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
613633
|
-
if (retentionDays > 0) {
|
|
613856
|
+
if (!apiTestMode && retentionDays > 0) {
|
|
613634
613857
|
try {
|
|
613635
613858
|
const jobsDir3 = join129(cwd4, ".oa", "jobs");
|
|
613636
613859
|
if (existsSync113(jobsDir3)) {
|
|
@@ -613681,9 +613904,12 @@ function startApiServer(options2 = {}) {
|
|
|
613681
613904
|
}
|
|
613682
613905
|
let _accessRejected = 0;
|
|
613683
613906
|
const handler = (req2, res) => {
|
|
613907
|
+
const requestId = req2.headers["x-request-id"] || randomUUID16();
|
|
613908
|
+
res.setHeader("X-Request-ID", requestId);
|
|
613909
|
+
res.setHeader("X-API-Version", API_VERSION);
|
|
613684
613910
|
const rawIp = req2.socket?.remoteAddress ?? "";
|
|
613685
613911
|
const hasBearer = typeof req2.headers["authorization"] === "string" && req2.headers["authorization"].startsWith("Bearer ");
|
|
613686
|
-
const anyKeyConfigured = Boolean(
|
|
613912
|
+
const anyKeyConfigured = hasBearer && Boolean(
|
|
613687
613913
|
process.env["OA_API_KEY"] || process.env["OA_API_KEYS"] || runtimeKeysExist()
|
|
613688
613914
|
);
|
|
613689
613915
|
if (!isAllowedIP(rawIp, runtimeAccessMode) && !(hasBearer && anyKeyConfigured)) {
|
|
@@ -613770,10 +613996,6 @@ function startApiServer(options2 = {}) {
|
|
|
613770
613996
|
handleEntitiesList(req2, res);
|
|
613771
613997
|
return;
|
|
613772
613998
|
}
|
|
613773
|
-
if (req2.method === "POST" && url.pathname === "/v1/memory/search") {
|
|
613774
|
-
handleMemorySearch2(req2, res);
|
|
613775
|
-
return;
|
|
613776
|
-
}
|
|
613777
613999
|
} catch {
|
|
613778
614000
|
}
|
|
613779
614001
|
handleRequest(req2, res, ollamaUrl, verbose).catch((err) => {
|
|
@@ -614024,6 +614246,10 @@ function startApiServer(options2 = {}) {
|
|
|
614024
614246
|
`);
|
|
614025
614247
|
log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
|
|
614026
614248
|
`);
|
|
614249
|
+
if (apiTestMode) {
|
|
614250
|
+
void refreshEndpointRegistry();
|
|
614251
|
+
return;
|
|
614252
|
+
}
|
|
614027
614253
|
try {
|
|
614028
614254
|
const { writeFileSync: writeFileSync67, mkdirSync: mkdirSync74, existsSync: _exists, readFileSync: _rfs } = require3("node:fs");
|
|
614029
614255
|
const { join: _join } = require3("node:path");
|
|
@@ -614451,28 +614677,6 @@ async function handleEntitiesList(req2, res) {
|
|
|
614451
614677
|
jsonResponse(res, 500, { error: "server_error", message: err instanceof Error ? err.message : String(err) });
|
|
614452
614678
|
}
|
|
614453
614679
|
}
|
|
614454
|
-
async function handleMemorySearch2(req2, res) {
|
|
614455
|
-
try {
|
|
614456
|
-
const body = await parseJsonBody(req2);
|
|
614457
|
-
if (!body || typeof body !== "object") {
|
|
614458
|
-
jsonResponse(res, 400, { error: "bad_request" });
|
|
614459
|
-
return;
|
|
614460
|
-
}
|
|
614461
|
-
const b = body;
|
|
614462
|
-
const query = String(b.query || "");
|
|
614463
|
-
const modality = b.modality ? String(b.modality) : void 0;
|
|
614464
|
-
const limit = b.limit ? Math.max(1, Math.min(200, parseInt(String(b.limit), 10))) : 20;
|
|
614465
|
-
const qEmb = Array.isArray(b.query_embedding) ? new Float32Array(b.query_embedding) : null;
|
|
614466
|
-
const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
|
|
614467
|
-
const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
|
|
614468
|
-
const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
614469
|
-
const epStore = new EpisodeStore3(join129(process.cwd(), ".oa", "memory.db"));
|
|
614470
|
-
const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
|
|
614471
|
-
jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
|
|
614472
|
-
} catch (err) {
|
|
614473
|
-
jsonResponse(res, 500, { error: "server_error", message: err instanceof Error ? err.message : String(err) });
|
|
614474
|
-
}
|
|
614475
|
-
}
|
|
614476
614680
|
async function apiServeCommand(opts, config) {
|
|
614477
614681
|
const server2 = startApiServer({
|
|
614478
614682
|
port: opts.port,
|
|
@@ -614533,7 +614737,7 @@ function setTimerEnabled(name10, enabled2) {
|
|
|
614533
614737
|
return false;
|
|
614534
614738
|
}
|
|
614535
614739
|
}
|
|
614536
|
-
var require3, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
|
|
614740
|
+
var require3, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, MODEL_LIST_TIMEOUT_DEFAULT_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
|
|
614537
614741
|
var init_serve = __esm({
|
|
614538
614742
|
"packages/cli/src/api/serve.ts"() {
|
|
614539
614743
|
"use strict";
|
|
@@ -614569,6 +614773,7 @@ var init_serve = __esm({
|
|
|
614569
614773
|
_lastEndpointDiagnostics = [];
|
|
614570
614774
|
BACKEND_TIMEOUT_DEFAULT_MS = 12e4;
|
|
614571
614775
|
BACKEND_TIMEOUT_MAX_MS = 36e5;
|
|
614776
|
+
MODEL_LIST_TIMEOUT_DEFAULT_MS = 1500;
|
|
614572
614777
|
metrics = {
|
|
614573
614778
|
requests: /* @__PURE__ */ new Map(),
|
|
614574
614779
|
totalTokensIn: 0,
|
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.580",
|
|
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.580",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "CC-BY-NC-4.0",
|
|
12
12
|
"dependencies": {
|
package/package.json
CHANGED