open-agents-ai 0.187.276 → 0.187.278
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 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -269758,6 +269758,10 @@ var init_agenticRunner = __esm({
|
|
|
269758
269758
|
// WO-KG-15
|
|
269759
269759
|
_retrievalContextCache = null;
|
|
269760
269760
|
// WO-KG-15: cache per-run
|
|
269761
|
+
// Observer world-model and cohort stats
|
|
269762
|
+
_observerMode = "both";
|
|
269763
|
+
_worldFacts = { files: /* @__PURE__ */ new Map(), lastTest: {}, lastLists: /* @__PURE__ */ new Map() };
|
|
269764
|
+
_argCohorts = /* @__PURE__ */ new Map();
|
|
269761
269765
|
// ── WO-NC-07: Error pattern learning → pre-action guidance injection ──
|
|
269762
269766
|
// Records error patterns (tool + error signature → learned guidance).
|
|
269763
269767
|
// When the same tool+context is about to be called again, injects the
|
|
@@ -269839,8 +269843,10 @@ var init_agenticRunner = __esm({
|
|
|
269839
269843
|
contextWindowSize: options2?.contextWindowSize ?? 0,
|
|
269840
269844
|
personality: options2?.personality ?? PERSONALITY_PRESETS.balanced,
|
|
269841
269845
|
personalityName: options2?.personalityName ?? "",
|
|
269842
|
-
finalVarResolver: options2?.finalVarResolver ?? void 0
|
|
269846
|
+
finalVarResolver: options2?.finalVarResolver ?? void 0,
|
|
269847
|
+
observerMode: options2?.observerMode ?? "both"
|
|
269843
269848
|
};
|
|
269849
|
+
this._observerMode = this.options.observerMode;
|
|
269844
269850
|
}
|
|
269845
269851
|
/** Update context window size (e.g. after querying Ollama /api/show) */
|
|
269846
269852
|
setContextWindowSize(size) {
|
|
@@ -270206,6 +270212,27 @@ ${body}`;
|
|
|
270206
270212
|
}
|
|
270207
270213
|
}
|
|
270208
270214
|
}
|
|
270215
|
+
/** Build a light fingerprint for arg cohort learning */
|
|
270216
|
+
buildArgCohortKey(tool, args) {
|
|
270217
|
+
const keys = Object.keys(args || {}).sort();
|
|
270218
|
+
const parts = [tool];
|
|
270219
|
+
for (const k of keys) {
|
|
270220
|
+
const v = args[k];
|
|
270221
|
+
if (typeof v === "string")
|
|
270222
|
+
parts.push(`${k}:${v.slice(0, 64)}`);
|
|
270223
|
+
else if (typeof v === "number" || typeof v === "boolean")
|
|
270224
|
+
parts.push(`${k}:${String(v)}`);
|
|
270225
|
+
else
|
|
270226
|
+
parts.push(`${k}:${JSON.stringify(v).slice(0, 64)}`);
|
|
270227
|
+
}
|
|
270228
|
+
let h = 2166136261;
|
|
270229
|
+
const s2 = parts.join("|");
|
|
270230
|
+
for (let i2 = 0; i2 < s2.length; i2++) {
|
|
270231
|
+
h ^= s2.charCodeAt(i2);
|
|
270232
|
+
h = Math.imul(h, 16777619);
|
|
270233
|
+
}
|
|
270234
|
+
return `${tool}#${(h >>> 0).toString(16)}`;
|
|
270235
|
+
}
|
|
270209
270236
|
/** Register a tool for the agent to use */
|
|
270210
270237
|
registerTool(tool) {
|
|
270211
270238
|
this.tools.set(tool.name, tool);
|
|
@@ -270540,6 +270567,9 @@ TASK: ${task}` : task;
|
|
|
270540
270567
|
this._hookDenyHintCount = 0;
|
|
270541
270568
|
this._selfConsistencyVotes = 0;
|
|
270542
270569
|
this._retrievalContextCache = null;
|
|
270570
|
+
this._observerMode = this.options.observerMode ?? "both";
|
|
270571
|
+
this._worldFacts = { files: /* @__PURE__ */ new Map(), lastTest: {}, lastLists: /* @__PURE__ */ new Map() };
|
|
270572
|
+
this._argCohorts.clear();
|
|
270543
270573
|
this._lastTodoWriteTurn = -1;
|
|
270544
270574
|
this._lastTodoReminderTurn = -1;
|
|
270545
270575
|
let pendingConstraintWarnings = [];
|
|
@@ -271114,6 +271144,14 @@ ${memoryLines.join("\n")}`
|
|
|
271114
271144
|
const executeSingle = async (tc) => {
|
|
271115
271145
|
if (this.aborted)
|
|
271116
271146
|
return null;
|
|
271147
|
+
const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
|
|
271148
|
+
const cohort = this._argCohorts.get(cohortKey);
|
|
271149
|
+
if (cohort && cohort.failure >= 3 && cohort.success === 0) {
|
|
271150
|
+
this.emit({ type: "observer_reaction", timestamp: (/* @__PURE__ */ new Date()).toISOString(), observer: { class: "arg_cohort_risk", shortText: `${tc.name} with similar args has failed ${cohort.failure}× recently`, confidence: 0.85 } });
|
|
271151
|
+
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
271152
|
+
this.pendingUserMessages.push(`[LITTLEMAN] ${tc.name} with similar arguments has failed ${cohort.failure}× recently. Try a different approach first: read relevant files, adjust arguments, or verify prerequisites.`);
|
|
271153
|
+
}
|
|
271154
|
+
}
|
|
271117
271155
|
if (this._errorPatterns.size > 0) {
|
|
271118
271156
|
for (const [sig, pattern] of this._errorPatterns) {
|
|
271119
271157
|
if (pattern.tool === tc.name && pattern.count >= 2 && !this._errorGuidanceInjected.has(sig)) {
|
|
@@ -271298,6 +271336,35 @@ ${memoryLines.join("\n")}`
|
|
|
271298
271336
|
}
|
|
271299
271337
|
}
|
|
271300
271338
|
}
|
|
271339
|
+
const updated = this._argCohorts.get(cohortKey) || { success: 0, failure: 0, lastOutcomeTurn: turn };
|
|
271340
|
+
if (result.success)
|
|
271341
|
+
updated.success++;
|
|
271342
|
+
else
|
|
271343
|
+
updated.failure++;
|
|
271344
|
+
updated.lastOutcomeTurn = turn;
|
|
271345
|
+
this._argCohorts.set(cohortKey, updated);
|
|
271346
|
+
try {
|
|
271347
|
+
if (tc.name === "file_read") {
|
|
271348
|
+
const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
|
|
271349
|
+
if (p2)
|
|
271350
|
+
this._worldFacts.files.set(p2, { exists: result.success, size: (result.output || "").length, hashSample: (result.output || "").slice(0, 32), lastSeenTurn: turn });
|
|
271351
|
+
} else if (tc.name === "list_directory") {
|
|
271352
|
+
const dir = String(tc.arguments?.["path"] ?? ".");
|
|
271353
|
+
this._worldFacts.lastLists.set(dir, { entriesCount: (result.output.match(/\n/g) || []).length + 1, lastSeenTurn: turn });
|
|
271354
|
+
} else if (tc.name === "shell") {
|
|
271355
|
+
const cmd = String(tc.arguments?.["command"] ?? "");
|
|
271356
|
+
if (/\b(npm|pnpm|yarn)\s+test\b|\bjest\b|\bvitest\b/i.test(cmd)) {
|
|
271357
|
+
const passed = /PASS|✓\s*all/i.test(result.output) && !/FAIL|✗/i.test(result.output);
|
|
271358
|
+
this._worldFacts.lastTest = { passed, summary: result.output.slice(0, 200), turn };
|
|
271359
|
+
}
|
|
271360
|
+
if (/^cd\s+/.test(cmd)) {
|
|
271361
|
+
const m2 = cmd.match(/^cd\s+([^&;\n]+)/);
|
|
271362
|
+
if (m2)
|
|
271363
|
+
this._worldFacts.lastCwd = m2[1];
|
|
271364
|
+
}
|
|
271365
|
+
}
|
|
271366
|
+
} catch {
|
|
271367
|
+
}
|
|
271301
271368
|
if (this._episodeStore) {
|
|
271302
271369
|
try {
|
|
271303
271370
|
const episodeContent = result.success ? `${tc.name}: ${(result.output ?? "").slice(0, 500)}` : `${tc.name} ERROR: ${(result.error ?? result.output ?? "").slice(0, 500)}`;
|
|
@@ -273086,6 +273153,9 @@ ${trimmedNew}`;
|
|
|
273086
273153
|
}
|
|
273087
273154
|
while (this._littlemanToolOutcomes.length > 20)
|
|
273088
273155
|
this._littlemanToolOutcomes.shift();
|
|
273156
|
+
const emitReaction = (cls, shortText, confidence, details2) => {
|
|
273157
|
+
this.emit({ type: "observer_reaction", timestamp: (/* @__PURE__ */ new Date()).toISOString(), observer: { class: cls, shortText, confidence, details: details2 } });
|
|
273158
|
+
};
|
|
273089
273159
|
const lastAssistant = [...recent].reverse().find((m2) => m2.role === "assistant" && typeof m2.content === "string");
|
|
273090
273160
|
if (lastAssistant && typeof lastAssistant.content === "string") {
|
|
273091
273161
|
const text = lastAssistant.content.toLowerCase();
|
|
@@ -273095,9 +273165,10 @@ ${trimmedNew}`;
|
|
|
273095
273165
|
const successes = recentOutcomes.filter((o2) => o2.succeeded);
|
|
273096
273166
|
if (successes.length >= 1) {
|
|
273097
273167
|
const successList = successes.map((o2) => `${o2.tool}: ${o2.preview.slice(0, 60)}`).join("; ");
|
|
273098
|
-
|
|
273099
|
-
|
|
273100
|
-
|
|
273168
|
+
emitReaction("false_failure", `Claimed failure, but recent tools succeeded (${successes.length})`, 0.9, successList);
|
|
273169
|
+
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
273170
|
+
this.pendingUserMessages.push(`[LITTLEMAN] Correction: recent tools DID succeed. Do not retry them. Successful results: ${successList}. Use them to advance the task.`);
|
|
273171
|
+
}
|
|
273101
273172
|
this.emit({
|
|
273102
273173
|
type: "status",
|
|
273103
273174
|
content: `Littleman: corrected false failure claim (${successes.length} tools succeeded)`,
|
|
@@ -273106,6 +273177,22 @@ Build on these results instead of retrying. What is your NEXT step toward the go
|
|
|
273106
273177
|
}
|
|
273107
273178
|
}
|
|
273108
273179
|
}
|
|
273180
|
+
if (lastAssistant && typeof lastAssistant.content === "string") {
|
|
273181
|
+
const text = lastAssistant.content.toLowerCase();
|
|
273182
|
+
const claimsSuccess = /(done|fixed|success|passed|complete)/i.test(text);
|
|
273183
|
+
if (claimsSuccess) {
|
|
273184
|
+
const recentOutcomes = this._littlemanToolOutcomes.slice(-4);
|
|
273185
|
+
const failures = recentOutcomes.filter((o2) => !o2.succeeded);
|
|
273186
|
+
const successes = recentOutcomes.filter((o2) => o2.succeeded);
|
|
273187
|
+
if (failures.length > 0 && successes.length === 0) {
|
|
273188
|
+
const failList = failures.map((o2) => `${o2.tool}: ${o2.preview.slice(0, 60)}`).join("; ");
|
|
273189
|
+
emitReaction("false_success", `Claimed success, but recent tools failed (${failures.length})`, 0.9, failList);
|
|
273190
|
+
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
273191
|
+
this.pendingUserMessages.push(`[LITTLEMAN] Your recent tools show errors (${failures.length}). Verify the last tool output and correct the issue before claiming success.`);
|
|
273192
|
+
}
|
|
273193
|
+
}
|
|
273194
|
+
}
|
|
273195
|
+
}
|
|
273109
273196
|
const lastToolCalls = recent.filter((m2) => m2.role === "assistant" && m2.tool_calls?.length).flatMap((m2) => m2.tool_calls ?? []);
|
|
273110
273197
|
for (const tc of lastToolCalls) {
|
|
273111
273198
|
const name10 = tc.function.name;
|
|
@@ -273117,8 +273204,10 @@ Build on these results instead of retrying. What is your NEXT step toward the go
|
|
|
273117
273204
|
const argsKey = name10 === "shell" ? String(args.command ?? "").slice(0, 60) : name10 === "web_fetch" ? String(args.url ?? "").slice(0, 80) : String(args.path ?? args.url ?? args.query ?? "").slice(0, 60);
|
|
273118
273205
|
const prior = this._littlemanToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.preview.includes(argsKey.slice(0, 30)) && o2.turn < turn);
|
|
273119
273206
|
if (prior) {
|
|
273120
|
-
|
|
273121
|
-
|
|
273207
|
+
emitReaction("redundant_action", `Already ran ${name10} successfully on turn ${prior.turn}`, 0.8, prior.preview);
|
|
273208
|
+
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
273209
|
+
this.pendingUserMessages.push(`[LITTLEMAN] You already ran ${name10} successfully on turn ${prior.turn} with similar arguments. Do NOT re-run it. Use the existing result and proceed.`);
|
|
273210
|
+
}
|
|
273122
273211
|
this.emit({
|
|
273123
273212
|
type: "status",
|
|
273124
273213
|
content: `Littleman: prevented redundant ${name10} call (succeeded on turn ${prior.turn})`,
|
|
@@ -273140,7 +273229,10 @@ Do NOT re-run it. Use the result you already have and proceed to the next step.`
|
|
|
273140
273229
|
}
|
|
273141
273230
|
}
|
|
273142
273231
|
if (consecutiveShortResults >= 3) {
|
|
273143
|
-
|
|
273232
|
+
emitReaction("idle_think", `Consecutive output without input: ${consecutiveShortResults}`, 0.7);
|
|
273233
|
+
if (this._observerMode === "skillcoach" || this._observerMode === "both") {
|
|
273234
|
+
this.pendingUserMessages.push(`[LITTLEMAN] You have sent ${consecutiveShortResults} consecutive outputs without reading any input. Alternate: receive input, then respond. Call your input tool now.`);
|
|
273235
|
+
}
|
|
273144
273236
|
this.emit({
|
|
273145
273237
|
type: "status",
|
|
273146
273238
|
content: `Littleman: blocked runaway output (${consecutiveShortResults} consecutive sends without receive)`,
|
|
@@ -294584,6 +294676,8 @@ var init_voice = __esm({
|
|
|
294584
294676
|
currentPlayback = null;
|
|
294585
294677
|
speakQueue = [];
|
|
294586
294678
|
speaking = false;
|
|
294679
|
+
drainPromise = null;
|
|
294680
|
+
drainResolve = null;
|
|
294587
294681
|
phonemizeFn = null;
|
|
294588
294682
|
/** True when current model uses MLX Audio backend */
|
|
294589
294683
|
mlxActive = false;
|
|
@@ -294900,6 +294994,15 @@ var init_voice = __esm({
|
|
|
294900
294994
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
294901
294995
|
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15);
|
|
294902
294996
|
}
|
|
294997
|
+
/** Wait until the speak queue is fully drained (all audio played). */
|
|
294998
|
+
async waitUntilIdle() {
|
|
294999
|
+
if (!this.speaking && this.speakQueue.length === 0) return;
|
|
295000
|
+
if (this.drainPromise) {
|
|
295001
|
+
await this.drainPromise;
|
|
295002
|
+
} else {
|
|
295003
|
+
await this.sleep(100);
|
|
295004
|
+
}
|
|
295005
|
+
}
|
|
294903
295006
|
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
294904
295007
|
if (!this.enabled || !this.ready) return;
|
|
294905
295008
|
text = sanitizeForTTS(text);
|
|
@@ -295098,6 +295201,11 @@ var init_voice = __esm({
|
|
|
295098
295201
|
*/
|
|
295099
295202
|
async drainQueue() {
|
|
295100
295203
|
this.speaking = true;
|
|
295204
|
+
if (!this.drainPromise) {
|
|
295205
|
+
this.drainPromise = new Promise((resolve40) => {
|
|
295206
|
+
this.drainResolve = resolve40;
|
|
295207
|
+
});
|
|
295208
|
+
}
|
|
295101
295209
|
let isFirst = true;
|
|
295102
295210
|
let prefetchedWav = null;
|
|
295103
295211
|
while (this.speakQueue.length > 0) {
|
|
@@ -295149,6 +295257,14 @@ var init_voice = __esm({
|
|
|
295149
295257
|
}
|
|
295150
295258
|
}
|
|
295151
295259
|
this.speaking = false;
|
|
295260
|
+
if (this.drainResolve) {
|
|
295261
|
+
try {
|
|
295262
|
+
this.drainResolve();
|
|
295263
|
+
} catch {
|
|
295264
|
+
}
|
|
295265
|
+
}
|
|
295266
|
+
this.drainResolve = null;
|
|
295267
|
+
this.drainPromise = null;
|
|
295152
295268
|
}
|
|
295153
295269
|
sleep(ms) {
|
|
295154
295270
|
return new Promise((resolve40) => setTimeout(resolve40, ms));
|
|
@@ -328126,13 +328242,12 @@ __export(voicechat_exports, {
|
|
|
328126
328242
|
VoiceChatSession: () => VoiceChatSession
|
|
328127
328243
|
});
|
|
328128
328244
|
import { EventEmitter as EventEmitter10 } from "node:events";
|
|
328129
|
-
var VAD_SILENCE_MS, MAX_SEGMENT_MS,
|
|
328245
|
+
var VAD_SILENCE_MS, MAX_SEGMENT_MS, MAX_CONTEXT_TURNS, SYSTEM_PROMPT2, VoiceChatSession;
|
|
328130
328246
|
var init_voicechat = __esm({
|
|
328131
328247
|
"packages/cli/src/tui/voicechat.ts"() {
|
|
328132
328248
|
"use strict";
|
|
328133
|
-
VAD_SILENCE_MS =
|
|
328249
|
+
VAD_SILENCE_MS = 2e3;
|
|
328134
328250
|
MAX_SEGMENT_MS = 6500;
|
|
328135
|
-
SUMMARY_INJECTION_INTERVAL = 4;
|
|
328136
328251
|
MAX_CONTEXT_TURNS = 20;
|
|
328137
328252
|
SYSTEM_PROMPT2 = `You are a voice assistant having a live spoken conversation. Keep responses extremely brief — 1-2 sentences max. You're speaking aloud, not writing. Be conversational, direct, and helpful. Don't use markdown, bullet points, or formatting — just natural speech. If you don't know something, say so briefly. Do not over-think — respond quickly and concisely.`;
|
|
328138
328253
|
VoiceChatSession = class extends EventEmitter10 {
|
|
@@ -328164,6 +328279,7 @@ var init_voicechat = __esm({
|
|
|
328164
328279
|
// Bound handlers for cleanup
|
|
328165
328280
|
_onTranscript = null;
|
|
328166
328281
|
_onError = null;
|
|
328282
|
+
_retryMicTimer = null;
|
|
328167
328283
|
constructor(opts) {
|
|
328168
328284
|
super();
|
|
328169
328285
|
this.voice = opts.voice;
|
|
@@ -328229,6 +328345,19 @@ var init_voicechat = __esm({
|
|
|
328229
328345
|
this._onError = (err) => {
|
|
328230
328346
|
const msg = err instanceof Error ? err.message : String(err);
|
|
328231
328347
|
this.onStatus(`ASR error (voicechat continues without mic): ${msg.slice(0, 80)}`);
|
|
328348
|
+
if (this.active && !this._retryMicTimer) {
|
|
328349
|
+
this._retryMicTimer = setTimeout(async () => {
|
|
328350
|
+
this._retryMicTimer = null;
|
|
328351
|
+
if (!this.active) return;
|
|
328352
|
+
try {
|
|
328353
|
+
await this.listen.stop().catch(() => {
|
|
328354
|
+
});
|
|
328355
|
+
await this.listen.start();
|
|
328356
|
+
this.onStatus("Mic auto-recovered — LISTENING");
|
|
328357
|
+
} catch {
|
|
328358
|
+
}
|
|
328359
|
+
}, 1e3);
|
|
328360
|
+
}
|
|
328232
328361
|
};
|
|
328233
328362
|
this.listen.on("transcript", this._onTranscript);
|
|
328234
328363
|
this.listen.on("error", this._onError);
|
|
@@ -328330,6 +328459,12 @@ var init_voicechat = __esm({
|
|
|
328330
328459
|
this.onUserSpeech(text);
|
|
328331
328460
|
this.context.push({ role: "user", content: text });
|
|
328332
328461
|
this.turnCount++;
|
|
328462
|
+
if (this.runner) {
|
|
328463
|
+
try {
|
|
328464
|
+
this.runner.injectUserMessage(`[VOICECHAT] ${text}`);
|
|
328465
|
+
} catch {
|
|
328466
|
+
}
|
|
328467
|
+
}
|
|
328333
328468
|
while (this.context.length > MAX_CONTEXT_TURNS + 1) {
|
|
328334
328469
|
this.context.splice(1, 1);
|
|
328335
328470
|
}
|
|
@@ -328351,11 +328486,18 @@ var init_voicechat = __esm({
|
|
|
328351
328486
|
this.setState("SPEAKING");
|
|
328352
328487
|
this.onAgentSpeech(response.trim());
|
|
328353
328488
|
this.voice.speak(response.trim());
|
|
328354
|
-
if (this.runner
|
|
328489
|
+
if (this.runner) {
|
|
328355
328490
|
this.injectSummary();
|
|
328356
328491
|
}
|
|
328357
|
-
|
|
328358
|
-
|
|
328492
|
+
if (typeof this.voice.waitUntilIdle === "function") {
|
|
328493
|
+
try {
|
|
328494
|
+
await this.voice.waitUntilIdle();
|
|
328495
|
+
} catch {
|
|
328496
|
+
}
|
|
328497
|
+
} else {
|
|
328498
|
+
const estimatedMs = Math.max(1500, response.length / 5 * (6e4 / 150));
|
|
328499
|
+
await new Promise((r2) => setTimeout(r2, estimatedMs));
|
|
328500
|
+
}
|
|
328359
328501
|
}
|
|
328360
328502
|
} catch (err) {
|
|
328361
328503
|
if (!this.active) return;
|
|
@@ -328478,13 +328620,19 @@ var init_voicechat = __esm({
|
|
|
328478
328620
|
// ---------------------------------------------------------------------------
|
|
328479
328621
|
injectSummary() {
|
|
328480
328622
|
if (!this.runner) return;
|
|
328481
|
-
const recentTurns = this.context.filter((t2) => t2.role !== "system").slice(-
|
|
328623
|
+
const recentTurns = this.context.filter((t2) => t2.role !== "system").slice(-8).map((t2) => `${t2.role === "user" ? "User" : "Assistant"}: ${t2.content}`).join("\n");
|
|
328482
328624
|
this.runner.injectUserMessage(
|
|
328483
|
-
`[VOICECHAT SUMMARY]
|
|
328625
|
+
`[VOICECHAT SUMMARY] Parallel voice liaison update (for awareness only). Continue your current task; do not respond to this directly.
|
|
328484
328626
|
|
|
328485
328627
|
${recentTurns}`
|
|
328486
328628
|
);
|
|
328487
328629
|
}
|
|
328630
|
+
/** Enqueue narration from main agent events into the voice channel */
|
|
328631
|
+
enqueueAgentNarration(text, subordinate = true) {
|
|
328632
|
+
if (!text || !this.active) return;
|
|
328633
|
+
if (subordinate) this.voice.speakSubordinate(text);
|
|
328634
|
+
else this.voice.speak(text);
|
|
328635
|
+
}
|
|
328488
328636
|
};
|
|
328489
328637
|
}
|
|
328490
328638
|
});
|
|
@@ -330064,6 +330212,17 @@ ${entry.fullContent}`
|
|
|
330064
330212
|
}
|
|
330065
330213
|
});
|
|
330066
330214
|
}
|
|
330215
|
+
if (voice?.enabled && voice.voiceMode === "voicechat" && _voiceChatSession?.isActive && event.toolName === "task_complete") {
|
|
330216
|
+
const emoStateFinal = emotionEngine?.getState();
|
|
330217
|
+
const emoCtxFinal = emoStateFinal ? { valence: emoStateFinal.valence, arousal: emoStateFinal.arousal, label: emoStateFinal.label, emoji: emoStateFinal.emoji } : void 0;
|
|
330218
|
+
const desc = describeTaskComplete(String(event.content ?? ""), true, vLevel);
|
|
330219
|
+
if (desc) {
|
|
330220
|
+
try {
|
|
330221
|
+
_voiceChatSession.enqueueAgentNarration(desc, false);
|
|
330222
|
+
} catch {
|
|
330223
|
+
}
|
|
330224
|
+
}
|
|
330225
|
+
}
|
|
330067
330226
|
break;
|
|
330068
330227
|
}
|
|
330069
330228
|
case "model_response":
|
|
@@ -330145,6 +330304,15 @@ ${entry.fullContent}`
|
|
|
330145
330304
|
voice.speak(chatText);
|
|
330146
330305
|
voice._spokenStreamText = true;
|
|
330147
330306
|
}
|
|
330307
|
+
} else if (voice?.enabled && voice.voiceMode === "voicechat" && (streamTextBuffer || event.content)) {
|
|
330308
|
+
const chatText = (streamTextBuffer || event.content || "").trim();
|
|
330309
|
+
streamTextBuffer = "";
|
|
330310
|
+
if (chatText.length > 10 && _voiceChatSession?.isActive) {
|
|
330311
|
+
try {
|
|
330312
|
+
_voiceChatSession.enqueueAgentNarration(chatText, false);
|
|
330313
|
+
} catch {
|
|
330314
|
+
}
|
|
330315
|
+
}
|
|
330148
330316
|
}
|
|
330149
330317
|
break;
|
|
330150
330318
|
}
|
|
@@ -331182,7 +331350,7 @@ ${opts.systemPromptAddition}` : `Working directory: ${repoRoot}`;
|
|
|
331182
331350
|
autoUpdateTimer.unref();
|
|
331183
331351
|
const voiceEngine = new VoiceEngine();
|
|
331184
331352
|
let voiceSession = null;
|
|
331185
|
-
let
|
|
331353
|
+
let _voiceChatSession2 = null;
|
|
331186
331354
|
let tunnelGateway = null;
|
|
331187
331355
|
let p2pGateway = null;
|
|
331188
331356
|
let peerMesh = null;
|
|
@@ -332871,7 +333039,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
332871
333039
|
},
|
|
332872
333040
|
// --- /voicechat: Voryn-style state machine voice conversation ---
|
|
332873
333041
|
async voiceChatStart() {
|
|
332874
|
-
if (
|
|
333042
|
+
if (_voiceChatSession2?.isActive) return;
|
|
332875
333043
|
if (!voiceEngine.enabled || !voiceEngine.ready) {
|
|
332876
333044
|
writeContent(() => renderInfo2("Auto-enabling voice for voice chat..."));
|
|
332877
333045
|
const voiceMsg = await voiceEngine.toggle();
|
|
@@ -332888,7 +333056,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
332888
333056
|
}
|
|
332889
333057
|
}
|
|
332890
333058
|
};
|
|
332891
|
-
|
|
333059
|
+
_voiceChatSession2 = new VoiceChatSession2({
|
|
332892
333060
|
voice: voiceEngine,
|
|
332893
333061
|
listen: listenEng,
|
|
332894
333062
|
backendUrl: currentConfig.backendUrl,
|
|
@@ -332913,16 +333081,16 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
332913
333081
|
writeContent(() => renderInfo2(`\x1B[38;5;243m[voicechat] ${state}\x1B[0m`));
|
|
332914
333082
|
}
|
|
332915
333083
|
});
|
|
332916
|
-
await
|
|
333084
|
+
await _voiceChatSession2.start();
|
|
332917
333085
|
},
|
|
332918
333086
|
async voiceChatStop() {
|
|
332919
|
-
if (
|
|
332920
|
-
await
|
|
332921
|
-
|
|
333087
|
+
if (_voiceChatSession2?.isActive) {
|
|
333088
|
+
await _voiceChatSession2.stop();
|
|
333089
|
+
_voiceChatSession2 = null;
|
|
332922
333090
|
}
|
|
332923
333091
|
},
|
|
332924
333092
|
isVoiceChatActive() {
|
|
332925
|
-
return
|
|
333093
|
+
return _voiceChatSession2?.isActive ?? false;
|
|
332926
333094
|
},
|
|
332927
333095
|
async exposeStart(kindOrUrl, authKey, transport, fullAccess, passthrough, loadbalance) {
|
|
332928
333096
|
const knownKinds = ["ollama", "vllm", "llvm", "passthrough"];
|
package/package.json
CHANGED