osborn 0.9.246 → 0.9.247
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/pipeline-direct-llm.js +19 -0
- package/dist/status-manager.d.ts +10 -0
- package/dist/status-manager.js +14 -0
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ import { llm, DEFAULT_API_CONNECT_OPTIONS } from '@livekit/agents';
|
|
|
12
12
|
import { ClaudeLLM } from './claude-llm.js';
|
|
13
13
|
import { askPipelineFastBrain } from './pipeline-fastbrain.js';
|
|
14
14
|
import { storeExists, openStore, recentRows } from './session-store.js';
|
|
15
|
+
import { statusManager } from './status-manager.js';
|
|
15
16
|
// ============================================================
|
|
16
17
|
// SESSION TAIL — compact recent-conversation block prepended to every user turn
|
|
17
18
|
// so the orchestrator never loses the thread across context compaction.
|
|
@@ -185,6 +186,22 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
185
186
|
// Actual mid-TTS interruption — keep the full [INTERRUPTED] template
|
|
186
187
|
console.log(`🔇 [pipeline] Enriching: interrupt (spoken=${interruptCtx.spokenText.length} chars, suppressed=${interruptCtx.suppressedText.length} chars)`);
|
|
187
188
|
this.#claudeLLM.interruptQuery().catch(() => { });
|
|
189
|
+
// An interrupt/cutoff SEVERS in-flight background Task sub-agents — the SDK's
|
|
190
|
+
// interrupt() kills run_in_background Task children and they never fire SubagentStop,
|
|
191
|
+
// so the agent gets NO signal they died and they can't be resumed. statusManager still
|
|
192
|
+
// lists them (start-tracked, never stopped) = the authoritative orphan set. Name them
|
|
193
|
+
// so the agent re-dispatches the necessary ones; mark them terminal so the tracker +
|
|
194
|
+
// Running panel don't leave them stuck "running" forever.
|
|
195
|
+
const orphanedSubagents = statusManager.getActiveDispatches();
|
|
196
|
+
const subagentReminder = orphanedSubagents.length
|
|
197
|
+
? `SUB-AGENTS SEVERED BY THE CUTOFF: your in-flight background sub-agents were killed by the interrupt and will NOT report back (no completion signal, cannot be resumed): ${orphanedSubagents.map(o => o.subagentType || 'agent').join(', ')}. Check which of these you still need and RE-DISPATCH them fresh — do not wait on them.`
|
|
198
|
+
: `SUB-AGENTS: if you had any background Task sub-agents in flight, an interrupt severs them silently (no completion signal, no resume) — check and re-dispatch any still needed rather than waiting on them.`;
|
|
199
|
+
for (const o of orphanedSubagents) {
|
|
200
|
+
try {
|
|
201
|
+
statusManager.upsertDispatch(o.id, { dispatchState: 'failed' });
|
|
202
|
+
}
|
|
203
|
+
catch { }
|
|
204
|
+
}
|
|
188
205
|
enrichedMessage = [
|
|
189
206
|
`[INTERRUPTED] The user interrupted your response mid-speech.`,
|
|
190
207
|
``,
|
|
@@ -206,6 +223,8 @@ export class PipelineDirectLLM extends llm.LLM {
|
|
|
206
223
|
`CONTEXT PRESERVATION (READ THIS):`,
|
|
207
224
|
`The user has NO memory of unheard content. If any of it bears on their current message — answers a question they just asked, sets up a follow-up they're now asking about, or shows a knowledge gap and fills in a detail they're reacting to — you MUST surface it. Briefly is fine if their message is off-topic or explores a direction they haven't asked about yet. But never assume they remember what they never heard.`,
|
|
208
225
|
``,
|
|
226
|
+
subagentReminder,
|
|
227
|
+
``,
|
|
209
228
|
`RESPOND with speech first, then act:`,
|
|
210
229
|
`- ALWAYS reply with at least one spoken sentence before doing any tool calls`,
|
|
211
230
|
`- If it's a quick side question, answer it then continue where you left off`,
|
package/dist/status-manager.d.ts
CHANGED
|
@@ -102,6 +102,16 @@ export declare class StatusManager {
|
|
|
102
102
|
* stale row from the dead process is reconciled away on the next poll.
|
|
103
103
|
*/
|
|
104
104
|
getActiveDispatchIds(): string[];
|
|
105
|
+
/**
|
|
106
|
+
* Non-terminal dispatches with their type — the set considered "in flight". Used on
|
|
107
|
+
* a voice interrupt to name the sub-agents that were just severed: an interrupt kills
|
|
108
|
+
* in-flight Task sub-agents (SDK regression) and they never fire SubagentStop, so they
|
|
109
|
+
* linger here as the authoritative orphan list until we mark them terminal.
|
|
110
|
+
*/
|
|
111
|
+
getActiveDispatches(): Array<{
|
|
112
|
+
id: string;
|
|
113
|
+
subagentType?: string;
|
|
114
|
+
}>;
|
|
105
115
|
/**
|
|
106
116
|
* Dispatcher v1 — create or update a dispatch entry keyed by tool_use_id.
|
|
107
117
|
* Creates a minimal TaskStatus shell if the id doesn't yet exist so callers
|
package/dist/status-manager.js
CHANGED
|
@@ -201,6 +201,20 @@ export class StatusManager {
|
|
|
201
201
|
t.dispatchState !== 'rejected')
|
|
202
202
|
.map(t => t.id);
|
|
203
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Non-terminal dispatches with their type — the set considered "in flight". Used on
|
|
206
|
+
* a voice interrupt to name the sub-agents that were just severed: an interrupt kills
|
|
207
|
+
* in-flight Task sub-agents (SDK regression) and they never fire SubagentStop, so they
|
|
208
|
+
* linger here as the authoritative orphan list until we mark them terminal.
|
|
209
|
+
*/
|
|
210
|
+
getActiveDispatches() {
|
|
211
|
+
return Array.from(this.tasks.values())
|
|
212
|
+
.filter(t => !!t.subagentType &&
|
|
213
|
+
t.dispatchState !== 'completed' &&
|
|
214
|
+
t.dispatchState !== 'failed' &&
|
|
215
|
+
t.dispatchState !== 'rejected')
|
|
216
|
+
.map(t => ({ id: t.id, subagentType: t.subagentType }));
|
|
217
|
+
}
|
|
204
218
|
/**
|
|
205
219
|
* Dispatcher v1 — create or update a dispatch entry keyed by tool_use_id.
|
|
206
220
|
* Creates a minimal TaskStatus shell if the id doesn't yet exist so callers
|