@a1hvdy/cc-openclaw 0.9.1 → 0.10.4

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.
Files changed (30) hide show
  1. package/dist/src/channels/telegram/completion-summary.js +20 -1
  2. package/dist/src/channels/telegram/completion-summary.js.map +1 -1
  3. package/dist/src/constants.d.ts +33 -2
  4. package/dist/src/constants.js +33 -2
  5. package/dist/src/constants.js.map +1 -1
  6. package/dist/src/lib/config.d.ts +3 -0
  7. package/dist/src/lib/config.js +46 -0
  8. package/dist/src/lib/config.js.map +1 -1
  9. package/dist/src/lib/trajectory.d.ts +1 -1
  10. package/dist/src/lib/trajectory.js.map +1 -1
  11. package/dist/src/openai-compat/non-streaming-handler.js +52 -3
  12. package/dist/src/openai-compat/non-streaming-handler.js.map +1 -1
  13. package/dist/src/openai-compat/openai-compat.js +64 -2
  14. package/dist/src/openai-compat/openai-compat.js.map +1 -1
  15. package/dist/src/openai-compat/skill-resolver.d.ts +15 -3
  16. package/dist/src/openai-compat/skill-resolver.js +30 -6
  17. package/dist/src/openai-compat/skill-resolver.js.map +1 -1
  18. package/dist/src/openai-compat/streaming-handler.js +107 -1
  19. package/dist/src/openai-compat/streaming-handler.js.map +1 -1
  20. package/dist/src/openai-compat/voice-recovery.d.ts +56 -0
  21. package/dist/src/openai-compat/voice-recovery.js +231 -0
  22. package/dist/src/openai-compat/voice-recovery.js.map +1 -0
  23. package/dist/src/session/session-manager.d.ts +51 -0
  24. package/dist/src/session/session-manager.js +165 -1
  25. package/dist/src/session/session-manager.js.map +1 -1
  26. package/dist/src/session-bootstrap/cwd-patch.d.ts.map +1 -1
  27. package/dist/tests/auto-recovery.test.js +4 -8
  28. package/dist/tests/auto-recovery.test.js.map +1 -1
  29. package/package.json +1 -1
  30. package/dist/src/lib/debug-tap.d.ts.map +0 -1
@@ -18,9 +18,15 @@
18
18
  * gets forwarded to Claude CLI via sessionConfig.tools (R3). Both fire,
19
19
  * neither blocks the other.
20
20
  *
21
- * Cache invalidates on workspace skills dir mtime change, so adding or
22
- * editing a SKILL.md is picked up on the next slash invocation without
23
- * a gateway restart.
21
+ * v0.9.2 (2026-05-11): SKILL.md **bodies** are re-read from disk on
22
+ * every slash invocation; only the directory listing (filename
23
+ * frontmatter `name:` mapping) is cached, keyed by directory mtime.
24
+ * Pre-v0.9.2 the body was also cached, which surfaced stale content
25
+ * when a user edited a SKILL.md file in place (the dir mtime stayed
26
+ * unchanged, so the cache wasn't refreshed). Analogous in spirit to
27
+ * the upstream OpenClaw 2026.5.7 "clear cached skills snapshots on
28
+ * /new" fix, but narrower. SKILL.md files are small (~few KB); a
29
+ * per-invocation read is ~1ms, well-bounded against rare slash usage.
24
30
  *
25
31
  * Override path with OPENCLAW_WORKSPACE_SKILLS_DIR env var.
26
32
  */
@@ -55,6 +61,9 @@ function parseFrontmatter(text) {
55
61
  }
56
62
  return { frontmatter: fm, body: text.slice(m[0].length) };
57
63
  }
64
+ /** Build the filename ↔ name index by scanning the workspace skills dir.
65
+ * Reads each SKILL.md only to extract its frontmatter `name:` field — does
66
+ * NOT cache the body. */
58
67
  function rebuildIndex() {
59
68
  const byName = new Map();
60
69
  let mtimeMs = 0;
@@ -79,11 +88,11 @@ function rebuildIndex() {
79
88
  catch {
80
89
  continue;
81
90
  }
82
- const { frontmatter, body } = parseFrontmatter(fullText);
91
+ const { frontmatter } = parseFrontmatter(fullText);
83
92
  const name = String(frontmatter.name || entry).toLowerCase().trim();
84
93
  if (!name)
85
94
  continue;
86
- byName.set(name, { skillDir, skillMd, body, fullText });
95
+ byName.set(name, { skillDir, skillMd });
87
96
  }
88
97
  return { mtimeMs, dir, byName };
89
98
  }
@@ -105,7 +114,22 @@ export function resolveSkillForSlash(name) {
105
114
  if (!cache || dirMtime > cache.mtimeMs || cache.dir !== currentDir) {
106
115
  cache = rebuildIndex();
107
116
  }
108
- return cache.byName.get(normalized) || null;
117
+ const ref = cache.byName.get(normalized);
118
+ if (!ref)
119
+ return null;
120
+ // v0.9.2: read the SKILL.md body fresh from disk so in-place edits to
121
+ // an existing SKILL.md (no add/remove, dir mtime unchanged) surface
122
+ // immediately. Pre-v0.9.2 the cache stored a stale body until process
123
+ // restart or skill add/remove.
124
+ let fullText;
125
+ try {
126
+ fullText = fs.readFileSync(ref.skillMd, 'utf8');
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ const { body } = parseFrontmatter(fullText);
132
+ return { skillDir: ref.skillDir, skillMd: ref.skillMd, body, fullText };
109
133
  }
110
134
  export function maybeInlineSkill(userText) {
111
135
  if (typeof userText !== 'string')
@@ -1 +1 @@
1
- {"version":3,"file":"skill-resolver.js","sourceRoot":"","sources":["../../../src/openai-compat/skill-resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skill-resolver.js","sourceRoot":"","sources":["../../../src/openai-compat/skill-resolver.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,25 @@ import { formatCompletionChunk } from './response-formatter.js';
41
41
  import { isToolStreamMode } from './mode-flags.js';
42
42
  import { emit as emitTrajectory } from '../lib/trajectory.js';
43
43
  import { formatError, ERROR_CODES } from '../lib/error-formatter.js';
44
+ import { getTtsAutoMode } from '../lib/config.js';
45
+ import { applyVoiceRecovery, detectVoiceIntent, hasTtsMarkers, _logVoiceDebug } from './voice-recovery.js';
46
+ /** Coerce a userMessage (string | UserMessageBlock[]) to a flat string
47
+ * for voice-intent detection. Tool-result blocks aren't user prompts. */
48
+ function userMessageToText(msg) {
49
+ if (typeof msg === 'string')
50
+ return msg;
51
+ if (!Array.isArray(msg))
52
+ return '';
53
+ return msg
54
+ .map((b) => {
55
+ if (b && typeof b === 'object' && 'type' in b && b.type === 'text' && typeof b.text === 'string') {
56
+ return b.text;
57
+ }
58
+ return '';
59
+ })
60
+ .filter(Boolean)
61
+ .join('\n');
62
+ }
44
63
  export async function handleStreaming(manager, sessionName, model,
45
64
  // Phase 2 R4 wire-up: accepts native content-block arrays in tool-stream mode.
46
65
  userMessage, completionId, res, hasTools) {
@@ -89,6 +108,25 @@ userMessage, completionId, res, hasTools) {
89
108
  // text chunks directly for low latency.
90
109
  let bufferedText = '';
91
110
  let toolCallsEmitted = 0;
111
+ // v0.10.3: Voice-recovery for streaming path. When user explicitly asks
112
+ // for a voice note AND TTS is configured non-off, switch the no-tools
113
+ // path from "stream chunks immediately" to "buffer chunks then recover
114
+ // + emit at end". The trade-off: ~2s perceived latency vs guaranteed
115
+ // [[tts:text]]...[[/tts:text]] markers reaching OpenClaw's TTS
116
+ // pipeline. Acceptable for voice prompts which are usually short.
117
+ const ttsAuto = getTtsAutoMode();
118
+ const userText = userMessageToText(userMessage);
119
+ const voiceIntent = ttsAuto !== 'off' && detectVoiceIntent(userText);
120
+ _logVoiceDebug('streaming.entry', {
121
+ sessionName,
122
+ userTextPreview: userText.slice(0, 200),
123
+ userTextLen: userText.length,
124
+ ttsAuto,
125
+ voiceIntent,
126
+ useToolStream,
127
+ hasTools,
128
+ });
129
+ let chunkLogCount = 0;
92
130
  // v0.7.2 streaming-path backstop: track whether *any* visible content
93
131
  // (text chunk OR tool_calls SSE chunk) was ever streamed. If the model
94
132
  // uses only CLI built-in tools (Bash/Read/Write) without producing text,
@@ -102,6 +140,33 @@ userMessage, completionId, res, hasTools) {
102
140
  await manager.sendMessage(sessionName, userMessage, {
103
141
  onChunk: (chunk) => {
104
142
  if (useToolStream || !hasTools) {
143
+ // v0.10.3: when voice intent is detected, BUFFER instead of stream.
144
+ // Recovery runs at stream end before final-chunk emission.
145
+ if (voiceIntent && !useToolStream) {
146
+ bufferedText += chunk;
147
+ if (chunk.length > 0)
148
+ streamedAnything = true;
149
+ if (chunkLogCount < 3) {
150
+ _logVoiceDebug('streaming.chunk.buffered', {
151
+ sessionName,
152
+ chunkLen: chunk.length,
153
+ bufferedTextLen: bufferedText.length,
154
+ chunkIdx: chunkLogCount,
155
+ });
156
+ chunkLogCount += 1;
157
+ }
158
+ return;
159
+ }
160
+ if (chunkLogCount < 3) {
161
+ _logVoiceDebug('streaming.chunk.streamed', {
162
+ sessionName,
163
+ chunkLen: chunk.length,
164
+ voiceIntent,
165
+ useToolStream,
166
+ chunkIdx: chunkLogCount,
167
+ });
168
+ chunkLogCount += 1;
169
+ }
105
170
  // Stream text deltas immediately. Tool-stream mode interleaves
106
171
  // text and tool_calls chunks naturally — Claude CLI emits text
107
172
  // between tool_use blocks, OpenClaw client handles that fine.
@@ -211,7 +276,48 @@ userMessage, completionId, res, hasTools) {
211
276
  writeSSE(JSON.stringify(formatCompletionChunk(completionId, model, { content: 'Done.' }, null)));
212
277
  streamedAnything = true;
213
278
  }
214
- if (useToolStream) {
279
+ // v0.10.3: voice-recovery emission. When voice intent was detected AND
280
+ // chunks were buffered (not streamed), apply recovery to bufferedText
281
+ // (translate <tool_calls> XML for voice tools, or auto-wrap if no
282
+ // [[tts:text]] markers present), then emit the recovered text as a
283
+ // single content chunk before the final chunk. Sets a flag so the
284
+ // other finalization branches don't double-emit.
285
+ let voiceRecoveryEmitted = false;
286
+ _logVoiceDebug('streaming.finalize', {
287
+ sessionName,
288
+ voiceIntent,
289
+ useToolStream,
290
+ hasTools,
291
+ bufferedTextLen: bufferedText.length,
292
+ bufferedTextHasMarkersBefore: hasTtsMarkers(bufferedText),
293
+ streamedAnything,
294
+ toolCallsEmitted,
295
+ });
296
+ if (voiceIntent && !useToolStream && bufferedText) {
297
+ const recovery = applyVoiceRecovery(userText, bufferedText);
298
+ const finalText = recovery.text;
299
+ _logVoiceDebug('streaming.recovery', {
300
+ sessionName,
301
+ recovered: recovery.recovered,
302
+ via: recovery.via,
303
+ finalLen: finalText.length,
304
+ finalSnippet: finalText.slice(0, 300),
305
+ finalHasMarkers: hasTtsMarkers(finalText),
306
+ });
307
+ if (recovery.recovered) {
308
+ emitTrajectory('tool_use', { name: '_voice_recovery', inputKeys: [recovery.via] }, sessionName);
309
+ }
310
+ writeSSE(JSON.stringify(formatCompletionChunk(completionId, model, { content: finalText }, null)));
311
+ const finalChunk = formatCompletionChunk(completionId, model, {}, 'stop');
312
+ if (usage)
313
+ finalChunk.usage = usage;
314
+ writeSSE(JSON.stringify(finalChunk));
315
+ voiceRecoveryEmitted = true;
316
+ }
317
+ if (voiceRecoveryEmitted) {
318
+ // Already finalized via voice-recovery path. Skip the standard branches.
319
+ }
320
+ else if (useToolStream) {
215
321
  // R1+R2: tool-stream mode — text + tool_calls already streamed inline.
216
322
  // Just emit the final chunk with the right finish_reason.
217
323
  const finishReason = toolCallsEmitted > 0 ? 'tool_calls' : 'stop';
@@ -1 +1 @@
1
- {"version":3,"file":"streaming-handler.js","sourceRoot":"","sources":["../../../src/openai-compat/streaming-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"streaming-handler.js","sourceRoot":"","sources":["../../../src/openai-compat/streaming-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAKH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE3G;0EAC0E;AAC1E,SAAS,iBAAiB,CAAC,GAAgC;IACzD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,GAAG;SACP,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzH,OAAQ,CAAsB,CAAC,IAAI,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;SACD,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA2B,EAC3B,WAAmB,EACnB,KAAa;AACb,+EAA+E;AAC/E,WAAwC,EACxC,YAAoB,EACpB,GAAwB,EACxB,QAAiB;IAEjB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,UAAU;QAC3B,UAAU,EAAE,YAAY;QACxB,mBAAmB,EAAE,IAAI;KAC1B,CAAC,CAAC;IAEH,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACnB,kBAAkB,GAAG,IAAI,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;QAChC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC;gBACP,kBAAkB,GAAG,IAAI,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAElG,0BAA0B;IAC1B,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,kBAAkB,GAAG,IAAI,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC,EAAE,MAAM,CAAC,CAAC;IAEX,0EAA0E;IAC1E,sEAAsE;IACtE,qEAAqE;IACrE,+DAA+D;IAC/D,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,aAAa,GAAG,gBAAgB,EAAE,IAAI,QAAQ,CAAC;IAErD,0EAA0E;IAC1E,wEAAwE;IACxE,wCAAwC;IACxC,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAEzB,wEAAwE;IACxE,sEAAsE;IACtE,uEAAuE;IACvE,qEAAqE;IACrE,+DAA+D;IAC/D,kEAAkE;IAClE,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACrE,cAAc,CAAC,iBAAiB,EAAE;QAChC,WAAW;QACX,eAAe,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QACvC,WAAW,EAAE,QAAQ,CAAC,MAAM;QAC5B,OAAO;QACP,WAAW;QACX,aAAa;QACb,QAAQ;KACT,CAAC,CAAC;IACH,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,sEAAsE;IACtE,uEAAuE;IACvE,yEAAyE;IACzE,0EAA0E;IAC1E,iEAAiE;IACjE,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAE7B,IAAI,CAAC;QACH,YAAY,CAAC,UAAU,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE;YAClD,OAAO,EAAE,CAAC,KAAa,EAAE,EAAE;gBACzB,IAAI,aAAa,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAC/B,oEAAoE;oBACpE,2DAA2D;oBAC3D,IAAI,WAAW,IAAI,CAAC,aAAa,EAAE,CAAC;wBAClC,YAAY,IAAI,KAAK,CAAC;wBACtB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;4BAAE,gBAAgB,GAAG,IAAI,CAAC;wBAC9C,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;4BACtB,cAAc,CAAC,0BAA0B,EAAE;gCACzC,WAAW;gCACX,QAAQ,EAAE,KAAK,CAAC,MAAM;gCACtB,eAAe,EAAE,YAAY,CAAC,MAAM;gCACpC,QAAQ,EAAE,aAAa;6BACxB,CAAC,CAAC;4BACH,aAAa,IAAI,CAAC,CAAC;wBACrB,CAAC;wBACD,OAAO;oBACT,CAAC;oBACD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;wBACtB,cAAc,CAAC,0BAA0B,EAAE;4BACzC,WAAW;4BACX,QAAQ,EAAE,KAAK,CAAC,MAAM;4BACtB,WAAW;4BACX,aAAa;4BACb,QAAQ,EAAE,aAAa;yBACxB,CAAC,CAAC;wBACH,aAAa,IAAI,CAAC,CAAC;oBACrB,CAAC;oBACD,+DAA+D;oBAC/D,+DAA+D;oBAC/D,8DAA8D;oBAC9D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;wBAAE,gBAAgB,GAAG,IAAI,CAAC;oBAC9C,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;gBACjG,CAAC;qBAAM,CAAC;oBACN,yEAAyE;oBACzE,YAAY,IAAI,KAAK,CAAC;gBACxB,CAAC;YACH,CAAC;YACD,OAAO,EAAE,CAAC,KAA+F,EAAE,EAAE;gBAC3G,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACjC,2DAA2D;oBAC3D,cAAc,CAAC,aAAa,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC;oBAC/C,OAAO;gBACT,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;oBAClD,YAAY,CAAC,SAAS,EAAE,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAChG,6DAA6D;oBAC7D,mEAAmE;oBACnE,cAAc,CACZ,UAAU,EACV;wBACE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI;wBACrB,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;qBACjE,EACD,WAAW,CACZ,CAAC;oBACF,IAAI,aAAa,EAAE,CAAC;wBAClB,+DAA+D;wBAC/D,4DAA4D;wBAC5D,mCAAmC;wBACnC,0CAA0C;wBAC1C,MAAM,SAAS,GACb,KAAK,CAAC,IAAI,CAAC,EAAE;4BACb,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;wBAC/E,MAAM,GAAG,GAAG,gBAAgB,CAAC;wBAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpF,MAAM,UAAU,GAAG;4BACjB,EAAE,EAAE,YAAY;4BAChB,MAAM,EAAE,uBAAgC;4BACxC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;4BACtC,KAAK;4BACL,OAAO,EAAE;gCACP;oCACE,KAAK,EAAE,CAAC;oCACR,KAAK,EAAE;wCACL,UAAU,EAAE;4CACV;gDACE,KAAK,EAAE,GAAG;gDACV,EAAE,EAAE,SAAS;gDACb,IAAI,EAAE,UAAmB;gDACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;6CACnD;yCACF;qCACF;oCACD,aAAa,EAAE,IAAI;iCACpB;6BACF;yBACF,CAAC;wBACF,MAAM,SAAS,GAAG;4BAChB,EAAE,EAAE,YAAY;4BAChB,MAAM,EAAE,uBAAgC;4BACxC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;4BACtC,KAAK;4BACL,OAAO,EAAE;gCACP;oCACE,KAAK,EAAE,CAAC;oCACR,KAAK,EAAE;wCACL,UAAU,EAAE;4CACV;gDACE,KAAK,EAAE,GAAG;gDACV,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;6CAClC;yCACF;qCACF;oCACD,aAAa,EAAE,IAAI;iCACpB;6BACF;yBACF,CAAC;wBACF,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;wBACrC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;wBACpC,gBAAgB,IAAI,CAAC,CAAC;wBACtB,gBAAgB,GAAG,IAAI,CAAC;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE9B,kCAAkC;QAClC,IAAI,KAA6F,CAAC;QAClG,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YAC9C,KAAK,GAAG;gBACN,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;gBACpC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;gBACzC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS;aAC7D,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;QAED,sEAAsE;QACtE,wEAAwE;QACxE,kEAAkE;QAClE,qEAAqE;QACrE,4DAA4D;QAC5D,MAAM,gBAAgB,GAAG,CAAC,gBAAgB,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,gBAAgB,KAAK,CAAC,CAAC;QAClG,IAAI,gBAAgB,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YACjG,gBAAgB,GAAG,IAAI,CAAC;QAC1B,CAAC;QAED,uEAAuE;QACvE,sEAAsE;QACtE,kEAAkE;QAClE,mEAAmE;QACnE,kEAAkE;QAClE,iDAAiD;QACjD,IAAI,oBAAoB,GAAG,KAAK,CAAC;QACjC,cAAc,CAAC,oBAAoB,EAAE;YACnC,WAAW;YACX,WAAW;YACX,aAAa;YACb,QAAQ;YACR,eAAe,EAAE,YAAY,CAAC,MAAM;YACpC,4BAA4B,EAAE,aAAa,CAAC,YAAY,CAAC;YACzD,gBAAgB;YAChB,gBAAgB;SACjB,CAAC,CAAC;QACH,IAAI,WAAW,IAAI,CAAC,aAAa,IAAI,YAAY,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC;YAChC,cAAc,CAAC,oBAAoB,EAAE;gBACnC,WAAW;gBACX,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,QAAQ,EAAE,SAAS,CAAC,MAAM;gBAC1B,YAAY,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBACrC,eAAe,EAAE,aAAa,CAAC,SAAS,CAAC;aAC1C,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACvB,cAAc,CACZ,UAAU,EACV,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EACtD,WAAW,CACZ,CAAC;YACJ,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YACnG,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YAC1E,IAAI,KAAK;gBAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YACrC,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;QAED,IAAI,oBAAoB,EAAE,CAAC;YACzB,yEAAyE;QAC3E,CAAC;aAAM,IAAI,aAAa,EAAE,CAAC;YACzB,uEAAuE;YACvE,0DAA0D;YAC1D,MAAM,YAAY,GAAG,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;YAClE,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC;YAChF,IAAI,KAAK;gBAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAAC;YAEpD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,2BAA2B;gBAC3B,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC9G,CAAC;gBACD,wBAAwB;gBACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACjD,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC/B,QAAQ,CACN,IAAI,CAAC,SAAS,CAAC;wBACb,EAAE,EAAE,YAAY;wBAChB,MAAM,EAAE,uBAAgC;wBACxC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;wBACtC,KAAK;wBACL,OAAO,EAAE;4BACP;gCACE,KAAK,EAAE,CAAC;gCACR,KAAK,EAAE;oCACL,UAAU,EAAE;wCACV;4CACE,KAAK,EAAE,CAAC;4CACR,EAAE,EAAE,EAAE,CAAC,EAAE;4CACT,IAAI,EAAE,UAAmB;4CACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE;yCACvE;qCACF;iCACF;gCACD,aAAa,EAAE,IAAI;6BACpB;yBACF;qBACF,CAAC,CACH,CAAC;gBACJ,CAAC;gBACD,4CAA4C;gBAC5C,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,YAAY,CAAC,CAAC;gBAChF,IAAI,KAAK;oBAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;gBACpC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,gDAAgD;gBAChD,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;gBACtG,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;gBAC1E,IAAI,KAAK;oBAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;gBACpC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,6BAA6B;YAC7B,MAAM,UAAU,GAAG,qBAAqB,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YAC1E,IAAI,KAAK;gBAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QACvC,yEAAyE;QACzE,WAAW,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACrH,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/F,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC;YAAS,CAAC;QACT,aAAa,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * voice-recovery — server-side bridge that ensures voice delivery via
3
+ * `[[tts:text]]...[[/tts:text]]` markers even when Savvy doesn't emit them.
4
+ *
5
+ * v0.10.3 turns cc-openclaw from a passive text proxy into an active
6
+ * voice-aware bridge for three failure modes:
7
+ *
8
+ * 1. Savvy emits `<tool_calls>` XML for a native OpenClaw voice tool
9
+ * (e.g. `message.voice`) that cc-openclaw can't execute. The XML
10
+ * lands as raw text in the SSE stream. → `translateVoiceToolCalls`
11
+ * rewrites it as `[[tts:text]]` markers.
12
+ *
13
+ * 2. User explicitly asks for voice but Savvy produces markerless text
14
+ * (the dominant failure observed in the 2026-05-11 evening test).
15
+ * → `autoWrapMissingMarkers` wraps the first sentence/paragraph
16
+ * in markers so OpenClaw's `maybeApplyTtsToPayload` triggers.
17
+ *
18
+ * 3. Hint-loss between turns. → `detectVoiceIntent` gates recovery so
19
+ * it only fires on explicit voice requests, never on accidental
20
+ * voice-keyword matches in non-voice prompts.
21
+ *
22
+ * All functions are PURE — no side effects, no IO, no logging. Tests
23
+ * exercise them directly via `tests/voice-recovery.test.ts`.
24
+ */
25
+ /** Default max chars inside the spoken block. Matches the TTS_RULE budget. */
26
+ export declare const DEFAULT_MAX_SPOKEN_CHARS = 500;
27
+ /** v0.10.4 — env-gated debug logger for triangulating voice-recovery
28
+ * failure mode on Telegram vs. direct-probe paths. Single-line JSON for
29
+ * grep-ability via `pm2 logs openclaw-gateway | grep _voice_debug`.
30
+ * Disabled unless `CC_OPENCLAW_VOICE_DEBUG=1`. Safe to leave in code
31
+ * permanently — the gate is a single string equality check. */
32
+ export declare function _logVoiceDebug(label: string, fields: Record<string, unknown>): void;
33
+ /** Detect whether the user's prompt explicitly requests a voice note. */
34
+ export declare function detectVoiceIntent(userPrompt: string): boolean;
35
+ /** Check whether the reply text already contains a complete `[[tts:text]]`
36
+ * block (open + close pair). */
37
+ export declare function hasTtsMarkers(text: string): boolean;
38
+ /** If `text` contains a `<tool_calls>` XML block targeting a voice-delivery
39
+ * tool, extract the spoken-text argument. Returns the spoken text or null. */
40
+ export declare function extractTtsToolCallText(text: string): string | null;
41
+ /** Rewrite `text`: if a voice-tool XML block is present, remove it and
42
+ * insert a `[[tts:text]]<spoken>[[/tts:text]]` block in its place. Idempotent
43
+ * when no voice-tool XML is present. */
44
+ export declare function translateVoiceToolCalls(text: string): string;
45
+ /** If `text` is missing voice markers, find a reasonable spoken summary
46
+ * (first paragraph up to `maxSpokenChars`) and wrap it. Returns text with
47
+ * the marker block prepended; the original first paragraph is left in place
48
+ * as text expansion. Idempotent when markers already present. */
49
+ export declare function autoWrapMissingMarkers(text: string, maxSpokenChars?: number): string;
50
+ /** Convenience helper: run the full recovery pipeline on a reply when the
51
+ * user has expressed voice intent. Returns the (possibly rewritten) text. */
52
+ export declare function applyVoiceRecovery(userPrompt: string, replyText: string, maxSpokenChars?: number): {
53
+ text: string;
54
+ recovered: boolean;
55
+ via: 'none' | 'tool-translate' | 'auto-wrap';
56
+ };
@@ -0,0 +1,231 @@
1
+ /**
2
+ * voice-recovery — server-side bridge that ensures voice delivery via
3
+ * `[[tts:text]]...[[/tts:text]]` markers even when Savvy doesn't emit them.
4
+ *
5
+ * v0.10.3 turns cc-openclaw from a passive text proxy into an active
6
+ * voice-aware bridge for three failure modes:
7
+ *
8
+ * 1. Savvy emits `<tool_calls>` XML for a native OpenClaw voice tool
9
+ * (e.g. `message.voice`) that cc-openclaw can't execute. The XML
10
+ * lands as raw text in the SSE stream. → `translateVoiceToolCalls`
11
+ * rewrites it as `[[tts:text]]` markers.
12
+ *
13
+ * 2. User explicitly asks for voice but Savvy produces markerless text
14
+ * (the dominant failure observed in the 2026-05-11 evening test).
15
+ * → `autoWrapMissingMarkers` wraps the first sentence/paragraph
16
+ * in markers so OpenClaw's `maybeApplyTtsToPayload` triggers.
17
+ *
18
+ * 3. Hint-loss between turns. → `detectVoiceIntent` gates recovery so
19
+ * it only fires on explicit voice requests, never on accidental
20
+ * voice-keyword matches in non-voice prompts.
21
+ *
22
+ * All functions are PURE — no side effects, no IO, no logging. Tests
23
+ * exercise them directly via `tests/voice-recovery.test.ts`.
24
+ */
25
+ // ── Constants ─────────────────────────────────────────────────────────────
26
+ /** Word-boundary regex for explicit voice-delivery intent in user prompts.
27
+ * Kept TIGHT to avoid false positives: "voice" alone is too broad (could be
28
+ * asking about TTS config); "send a voice note" / "speak" / "in voice" are
29
+ * the intended triggers. */
30
+ const VOICE_INTENT_REGEX = /\b(voice\s*notes?|voice\s*messages?|send\s+(?:me\s+)?(?:a\s+)?voice|in\s+voice|speak\s+(?:it|the|me|to|aloud)|say\s+(?:it|the|me).*aloud|tell\s+me\s+(?:out\s+loud|aloud)|read\s+(?:it|the|this)\s+aloud)\b/i;
31
+ /** Markers OpenClaw's `maybeApplyTtsToPayload` looks for. */
32
+ const TTS_OPEN = '[[tts:text]]';
33
+ const TTS_CLOSE = '[[/tts:text]]';
34
+ /** Default max chars inside the spoken block. Matches the TTS_RULE budget. */
35
+ export const DEFAULT_MAX_SPOKEN_CHARS = 500;
36
+ // ── Diagnostic logging (v0.10.4) ──────────────────────────────────────────
37
+ /** v0.10.4 — env-gated debug logger for triangulating voice-recovery
38
+ * failure mode on Telegram vs. direct-probe paths. Single-line JSON for
39
+ * grep-ability via `pm2 logs openclaw-gateway | grep _voice_debug`.
40
+ * Disabled unless `CC_OPENCLAW_VOICE_DEBUG=1`. Safe to leave in code
41
+ * permanently — the gate is a single string equality check. */
42
+ export function _logVoiceDebug(label, fields) {
43
+ if (process.env.CC_OPENCLAW_VOICE_DEBUG !== '1')
44
+ return;
45
+ try {
46
+ const payload = { _voice_debug: label, ...fields, ts: new Date().toISOString() };
47
+ // eslint-disable-next-line no-console
48
+ console.error(JSON.stringify(payload));
49
+ }
50
+ catch {
51
+ // Logging must never throw into the request path
52
+ }
53
+ }
54
+ // ── Public API ────────────────────────────────────────────────────────────
55
+ /** Detect whether the user's prompt explicitly requests a voice note. */
56
+ export function detectVoiceIntent(userPrompt) {
57
+ if (!userPrompt)
58
+ return false;
59
+ return VOICE_INTENT_REGEX.test(userPrompt);
60
+ }
61
+ /** Check whether the reply text already contains a complete `[[tts:text]]`
62
+ * block (open + close pair). */
63
+ export function hasTtsMarkers(text) {
64
+ if (!text)
65
+ return false;
66
+ const openIdx = text.indexOf(TTS_OPEN);
67
+ if (openIdx === -1)
68
+ return false;
69
+ const closeIdx = text.indexOf(TTS_CLOSE, openIdx + TTS_OPEN.length);
70
+ return closeIdx !== -1;
71
+ }
72
+ /** Pattern matching `<tool_calls>` or `<tool_use>` or `<function_calls>` XML
73
+ * blocks whose `name` attribute looks like a voice/TTS delivery tool.
74
+ * Matches names: `voice`, `speak`, `tts`, `sendVoice`, `send_voice`,
75
+ * `message.voice`, `message_voice`, `messageVoice`, and `message.send` if
76
+ * it carries an `audioAsVoice` or `as_voice` argument. Permissive on
77
+ * purpose — Phase H of the ship plan analyzes the actual tool name from
78
+ * a sysprompt dump and may narrow this in v0.10.4. */
79
+ const VOICE_TOOL_NAME_REGEX = /(?:voice|speak|tts|send[\s_-]?voice|message[.\s_-]?voice|message[.\s_-]?send.*?(?:audioAsVoice|as[\s_-]?voice))/i;
80
+ /** Loose regex catching the common Anthropic-style tool-call XML envelopes. */
81
+ const TOOL_CALL_XML_BLOCK_REGEX = /<(tool_calls?|tool_use|function_calls?)\b[^>]*>([\s\S]*?)<\/\1>/gi;
82
+ /** Inside a tool-call XML block (or the full <tag name="..."> opening),
83
+ * find the `name` attribute or `<name>` field or JSON-style `"name":"..."`. */
84
+ const TOOL_NAME_REGEX = /name\s*=\s*"([^"]+)"|<name>\s*([^<]+?)\s*<\/name>|"name"\s*:\s*"([^"]+)"/i;
85
+ /** Inside a tool-call XML block, extract the spoken text argument. Tries
86
+ * several common shapes: `<text>X</text>`, `<input>X</input>`,
87
+ * `<content>X</content>`, `"text":"X"`, `"input":"X"`, `"content":"X"`.
88
+ * Returns the first non-empty match, trimmed. */
89
+ function extractSpokenText(xmlBody) {
90
+ const xmlTagPatterns = [/<text>([\s\S]*?)<\/text>/i, /<input>([\s\S]*?)<\/input>/i, /<content>([\s\S]*?)<\/content>/i, /<speech>([\s\S]*?)<\/speech>/i];
91
+ for (const re of xmlTagPatterns) {
92
+ const m = xmlBody.match(re);
93
+ if (m && m[1]) {
94
+ const trimmed = m[1].trim();
95
+ if (trimmed)
96
+ return trimmed;
97
+ }
98
+ }
99
+ const jsonPatterns = [/"text"\s*:\s*"((?:[^"\\]|\\.)*)"/i, /"input"\s*:\s*"((?:[^"\\]|\\.)*)"/i, /"content"\s*:\s*"((?:[^"\\]|\\.)*)"/i, /"speech"\s*:\s*"((?:[^"\\]|\\.)*)"/i];
100
+ for (const re of jsonPatterns) {
101
+ const m = xmlBody.match(re);
102
+ if (m && m[1]) {
103
+ const decoded = m[1].replace(/\\n/g, '\n').replace(/\\"/g, '"').replace(/\\\\/g, '\\').trim();
104
+ if (decoded)
105
+ return decoded;
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ /** If `text` contains a `<tool_calls>` XML block targeting a voice-delivery
111
+ * tool, extract the spoken-text argument. Returns the spoken text or null. */
112
+ export function extractTtsToolCallText(text) {
113
+ if (!text)
114
+ return null;
115
+ TOOL_CALL_XML_BLOCK_REGEX.lastIndex = 0;
116
+ let match;
117
+ while ((match = TOOL_CALL_XML_BLOCK_REGEX.exec(text)) !== null) {
118
+ const body = match[2] ?? '';
119
+ // Search the FULL match (including opening tag) so `name="..."` attributes
120
+ // on the outer <tool_use name="speak"> tag are caught. Also handles
121
+ // JSON-style `"name":"..."` payloads inside the body.
122
+ const nameMatch = match[0].match(TOOL_NAME_REGEX);
123
+ const toolName = (nameMatch?.[1] ?? nameMatch?.[2] ?? nameMatch?.[3] ?? '').trim();
124
+ if (toolName && VOICE_TOOL_NAME_REGEX.test(toolName)) {
125
+ const spoken = extractSpokenText(body);
126
+ if (spoken)
127
+ return spoken;
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ /** Rewrite `text`: if a voice-tool XML block is present, remove it and
133
+ * insert a `[[tts:text]]<spoken>[[/tts:text]]` block in its place. Idempotent
134
+ * when no voice-tool XML is present. */
135
+ export function translateVoiceToolCalls(text) {
136
+ if (!text)
137
+ return text;
138
+ TOOL_CALL_XML_BLOCK_REGEX.lastIndex = 0;
139
+ // Walk the matches, build a replacement.
140
+ let result = '';
141
+ let lastEnd = 0;
142
+ let match;
143
+ TOOL_CALL_XML_BLOCK_REGEX.lastIndex = 0;
144
+ while ((match = TOOL_CALL_XML_BLOCK_REGEX.exec(text)) !== null) {
145
+ const body = match[2] ?? '';
146
+ // Search the FULL match (including opening tag) so `name="..."` attributes
147
+ // on the outer <tool_use name="speak"> tag are caught. Also handles
148
+ // JSON-style `"name":"..."` payloads inside the body.
149
+ const nameMatch = match[0].match(TOOL_NAME_REGEX);
150
+ const toolName = (nameMatch?.[1] ?? nameMatch?.[2] ?? nameMatch?.[3] ?? '').trim();
151
+ if (toolName && VOICE_TOOL_NAME_REGEX.test(toolName)) {
152
+ const spoken = extractSpokenText(body);
153
+ if (spoken) {
154
+ result += text.slice(lastEnd, match.index);
155
+ result += `${TTS_OPEN}${spoken}${TTS_CLOSE}`;
156
+ lastEnd = match.index + match[0].length;
157
+ }
158
+ }
159
+ }
160
+ result += text.slice(lastEnd);
161
+ return result;
162
+ }
163
+ /** Truncate at a sentence boundary if possible, otherwise hard-cut.
164
+ * Used to keep the spoken portion within the voice-budget. */
165
+ function truncateAtSentence(text, maxChars) {
166
+ if (text.length <= maxChars)
167
+ return text;
168
+ const slice = text.slice(0, maxChars);
169
+ // Try last sentence-ending punctuation
170
+ const lastSentence = Math.max(slice.lastIndexOf('. '), slice.lastIndexOf('! '), slice.lastIndexOf('? '));
171
+ if (lastSentence > maxChars * 0.5)
172
+ return slice.slice(0, lastSentence + 1);
173
+ // Otherwise hard-cut at last space
174
+ const lastSpace = slice.lastIndexOf(' ');
175
+ if (lastSpace > maxChars * 0.5)
176
+ return slice.slice(0, lastSpace) + '…';
177
+ return slice + '…';
178
+ }
179
+ /** If `text` is missing voice markers, find a reasonable spoken summary
180
+ * (first paragraph up to `maxSpokenChars`) and wrap it. Returns text with
181
+ * the marker block prepended; the original first paragraph is left in place
182
+ * as text expansion. Idempotent when markers already present. */
183
+ export function autoWrapMissingMarkers(text, maxSpokenChars = DEFAULT_MAX_SPOKEN_CHARS) {
184
+ if (!text)
185
+ return text;
186
+ if (hasTtsMarkers(text))
187
+ return text;
188
+ const trimmed = text.trim();
189
+ if (!trimmed)
190
+ return text;
191
+ // Pick the first paragraph (up to the first blank line). The ★ Insight
192
+ // block typically appears below — leave it alone.
193
+ const firstBlankLine = trimmed.search(/\n\s*\n/);
194
+ const firstPara = firstBlankLine === -1 ? trimmed : trimmed.slice(0, firstBlankLine).trim();
195
+ // Strip leading boilerplate Savvy sometimes adds ("Let me send the voice note now.")
196
+ const filtered = firstPara
197
+ .replace(/^(?:i (?:have|got) what i need\.?\s*)?let me send (?:the\s+)?voice (?:note|message)(?:\s+now)?\.?\s*/i, '')
198
+ .replace(/^(?:here(?:'s|\s+is)|on\s+it|sending\s+(?:a\s+)?voice(?:\s+note)?)[:.]?\s*/i, '')
199
+ .trim();
200
+ // Fall back to the original first paragraph if filtering removed everything
201
+ const spokenRaw = filtered || firstPara;
202
+ const spoken = truncateAtSentence(spokenRaw, maxSpokenChars);
203
+ if (!spoken)
204
+ return text;
205
+ // Prepend the marker block; keep the rest of the original text as text expansion.
206
+ // Use \n\n separator so the marker block is visually distinct.
207
+ return `${TTS_OPEN}${spoken}${TTS_CLOSE}\n\n${text}`;
208
+ }
209
+ /** Convenience helper: run the full recovery pipeline on a reply when the
210
+ * user has expressed voice intent. Returns the (possibly rewritten) text. */
211
+ export function applyVoiceRecovery(userPrompt, replyText, maxSpokenChars = DEFAULT_MAX_SPOKEN_CHARS) {
212
+ if (!detectVoiceIntent(userPrompt)) {
213
+ return { text: replyText, recovered: false, via: 'none' };
214
+ }
215
+ // First try translating any tool-call XML
216
+ const translated = translateVoiceToolCalls(replyText);
217
+ if (translated !== replyText && hasTtsMarkers(translated)) {
218
+ return { text: translated, recovered: true, via: 'tool-translate' };
219
+ }
220
+ // If markers already present, nothing to do
221
+ if (hasTtsMarkers(translated)) {
222
+ return { text: translated, recovered: false, via: 'none' };
223
+ }
224
+ // Auto-wrap the first paragraph
225
+ const wrapped = autoWrapMissingMarkers(translated, maxSpokenChars);
226
+ if (wrapped !== translated && hasTtsMarkers(wrapped)) {
227
+ return { text: wrapped, recovered: true, via: 'auto-wrap' };
228
+ }
229
+ return { text: translated, recovered: false, via: 'none' };
230
+ }
231
+ //# sourceMappingURL=voice-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-recovery.js","sourceRoot":"","sources":["../../../src/openai-compat/voice-recovery.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,8 @@ export declare class SessionManager {
28
28
  private sessions;
29
29
  private _pendingSessions;
30
30
  private cleanupTimer;
31
+ private stalledWatchTimer;
32
+ private _recentSpawns;
31
33
  private pluginConfig;
32
34
  private persistedSessions;
33
35
  private _debouncedSave;
@@ -207,5 +209,54 @@ export declare class SessionManager {
207
209
  }): UltrareviewResult;
208
210
  ultrareviewStatus(id: string): UltrareviewResult | undefined;
209
211
  private _cleanupIdleSessions;
212
+ /**
213
+ * v0.10.0 — runtime stalled-session watchdog.
214
+ *
215
+ * Fires every STALLED_WATCH_INTERVAL_MS. For each session that is
216
+ * currently `isBusy === true` (mid-turn) AND whose underlying
217
+ * PersistentClaudeSession has not received any subprocess event for
218
+ * STALLED_SESSION_KILL_MS, the watchdog:
219
+ *
220
+ * 1. Logs the stall
221
+ * 2. Emits a `session_stalled_killed` trajectory event
222
+ * 3. Calls session.stop() (SIGTERM, then SIGKILL after STOP_SIGKILL_DELAY_MS)
223
+ * 4. Removes the entry from the in-memory `sessions` Map
224
+ *
225
+ * The in-flight `sendMessage()` promise will reject with the existing
226
+ * `TURN_TIMEOUT_MS` error or a session-stop error. The outer agent-runner
227
+ * then fast-fails to the cross-engine fallback (`openai-codex/gpt-5.4`)
228
+ * rather than waiting the full provider envelope (900s).
229
+ *
230
+ * Threshold is overridable via `CC_OPENCLAW_STALLED_KILL_MS` env var.
231
+ *
232
+ * Mirrors `gateway-pm2-wrapper.sh:53-60` boot-time orphan reaper.
233
+ */
234
+ private _watchStalledSessions;
235
+ /**
236
+ * Resolve the stalled-session kill threshold. Env var
237
+ * `CC_OPENCLAW_STALLED_KILL_MS` overrides STALLED_SESSION_KILL_MS at
238
+ * runtime so the value can be tuned without rebuild.
239
+ */
240
+ private _stalledThresholdMs;
241
+ /**
242
+ * v0.10.1 — record a fresh subprocess spawn for the runaway-loop
243
+ * watchdog. Trims entries older than RUNAWAY_LOOP_WINDOW_MS so the
244
+ * array length is bounded.
245
+ */
246
+ private _recordSpawn;
247
+ /**
248
+ * v0.10.1 — true when the spawn rate over RUNAWAY_LOOP_WINDOW_MS
249
+ * exceeds the configured threshold (env-overridable). Called by
250
+ * `_doStartSession` BEFORE recording the new spawn — i.e. the check
251
+ * fires when the (N+1)-th spawn attempt would push the count over.
252
+ */
253
+ private _isRunawayLoop;
254
+ /**
255
+ * v0.10.1 — resolve the runaway-loop spawn threshold. Env var
256
+ * `CC_OPENCLAW_LOOP_MAX_SUBPROCS` overrides RUNAWAY_LOOP_MAX_SUBPROCS
257
+ * for runtime tuning without rebuild. Clamped to [2, 20] to prevent
258
+ * accidental disable (0/1) or unbounded raise.
259
+ */
260
+ private _runawayThreshold;
210
261
  }
211
262
  export {};