opencode-interrupt-plugin 0.4.10 → 0.4.12
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 +46 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { VoiceOverlapDetector } from './audio/overlap.js';
|
|
|
8
8
|
import { detectTextInterruption } from './detector.js';
|
|
9
9
|
import { TTSStreamer } from './tts/index.js';
|
|
10
10
|
let activeSessionId = null;
|
|
11
|
+
let pendingInterrupt = null;
|
|
11
12
|
const TTS_COMMANDS = [
|
|
12
13
|
{ name: 'tts-on', description: 'Enable streaming TTS', template: 'TTS enabled.' },
|
|
13
14
|
{ name: 'tts-off', description: 'Disable streaming TTS', template: 'TTS disabled.' },
|
|
@@ -51,7 +52,8 @@ export const InterruptPlugin = (userConfig = {}) => {
|
|
|
51
52
|
}, () => ttsStreamer.getPartialContent());
|
|
52
53
|
overlapDetector.on('voice-overlap', (event) => {
|
|
53
54
|
if (!activeSessionId) {
|
|
54
|
-
|
|
55
|
+
pendingInterrupt = event;
|
|
56
|
+
debug(`[interrupt] Voice overlap event buffered (no active session)`);
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
57
59
|
debug(`[interrupt] Voice overlap detected (RMS: ${event.rmsLevel.toFixed(4)})`);
|
|
@@ -112,11 +114,12 @@ export const InterruptPlugin = (userConfig = {}) => {
|
|
|
112
114
|
if (!msg || !msg.role)
|
|
113
115
|
return;
|
|
114
116
|
if (msg.role === 'assistant') {
|
|
117
|
+
const state = getSessionState(sessionId);
|
|
115
118
|
const content = extractText(parts);
|
|
116
119
|
updateSessionState(sessionId, {
|
|
117
120
|
lastAssistantContent: content,
|
|
118
121
|
lastAssistantTimestamp: Date.now(),
|
|
119
|
-
wasInterrupted: false,
|
|
122
|
+
wasInterrupted: state.awaitingCorrection ? state.wasInterrupted : false,
|
|
120
123
|
});
|
|
121
124
|
return;
|
|
122
125
|
}
|
|
@@ -141,6 +144,17 @@ export const InterruptPlugin = (userConfig = {}) => {
|
|
|
141
144
|
if (!sessionId)
|
|
142
145
|
return;
|
|
143
146
|
activeSessionId = sessionId;
|
|
147
|
+
if (pendingInterrupt) {
|
|
148
|
+
updateSessionState(sessionId, {
|
|
149
|
+
wasInterrupted: true,
|
|
150
|
+
partialContentAtInterrupt: pendingInterrupt.partialTTSContent,
|
|
151
|
+
interruptTimestamp: pendingInterrupt.overlapTimestamp,
|
|
152
|
+
awaitingCorrection: true,
|
|
153
|
+
interruptSource: 'voice',
|
|
154
|
+
});
|
|
155
|
+
debug(`[interrupt] Applied buffered voice overlap to session ${sessionId}`);
|
|
156
|
+
pendingInterrupt = null;
|
|
157
|
+
}
|
|
144
158
|
const sessionState = getSessionState(sessionId);
|
|
145
159
|
const userMessage = extractUserMessage(input);
|
|
146
160
|
if (!userMessage)
|
|
@@ -202,10 +216,40 @@ export const InterruptPlugin = (userConfig = {}) => {
|
|
|
202
216
|
if (isTTSTool(toolName)) {
|
|
203
217
|
onTTSEnd();
|
|
204
218
|
}
|
|
219
|
+
if (config.tts && isWriteTool(toolName)) {
|
|
220
|
+
const text = extractToolOutput(output);
|
|
221
|
+
if (text) {
|
|
222
|
+
debug(`[interrupt] Tool "${toolName}" output captured (${text.length} chars) for TTS`);
|
|
223
|
+
ttsStreamer.onTextChunk({
|
|
224
|
+
messageID: `tool-${toolName}-${Date.now()}`,
|
|
225
|
+
type: 'text',
|
|
226
|
+
text,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
205
230
|
},
|
|
206
231
|
};
|
|
207
232
|
};
|
|
208
233
|
};
|
|
234
|
+
const WRITE_TOOL_NAMES = ['write', 'create', 'edit', 'overwrite', 'file.write', 'file.create', 'file.edit', 'file.overwrite', 'append'];
|
|
235
|
+
function isWriteTool(name) {
|
|
236
|
+
return WRITE_TOOL_NAMES.includes(name.toLowerCase());
|
|
237
|
+
}
|
|
238
|
+
function extractToolOutput(output) {
|
|
239
|
+
if (!output)
|
|
240
|
+
return '';
|
|
241
|
+
if (typeof output === 'string')
|
|
242
|
+
return output;
|
|
243
|
+
if (typeof output.result === 'string')
|
|
244
|
+
return output.result;
|
|
245
|
+
if (output.result?.content)
|
|
246
|
+
return output.result.content;
|
|
247
|
+
if (output.content)
|
|
248
|
+
return output.content;
|
|
249
|
+
if (output.text)
|
|
250
|
+
return output.text;
|
|
251
|
+
return '';
|
|
252
|
+
}
|
|
209
253
|
function extractUserMessage(input) {
|
|
210
254
|
try {
|
|
211
255
|
const messages = input.messages || [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-interrupt-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"description": "Streaming TTS + voice interruption for OpenCode. Speaks responses as they arrive and detects when you talk over it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|