@llmrtc/llmrtc-core 1.0.0
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/LICENSE +201 -0
- package/README.md +25 -0
- package/dist/hooks.d.ts +345 -0
- package/dist/hooks.js +52 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/logging-hooks.d.ts +120 -0
- package/dist/logging-hooks.js +280 -0
- package/dist/logging-hooks.js.map +1 -0
- package/dist/metrics.d.ts +243 -0
- package/dist/metrics.js +241 -0
- package/dist/metrics.js.map +1 -0
- package/dist/orchestrator.d.ts +73 -0
- package/dist/orchestrator.js +450 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/playbook-engine.d.ts +140 -0
- package/dist/playbook-engine.js +390 -0
- package/dist/playbook-engine.js.map +1 -0
- package/dist/playbook-orchestrator.d.ts +193 -0
- package/dist/playbook-orchestrator.js +687 -0
- package/dist/playbook-orchestrator.js.map +1 -0
- package/dist/playbook.d.ts +220 -0
- package/dist/playbook.js +92 -0
- package/dist/playbook.js.map +1 -0
- package/dist/protocol.d.ts +327 -0
- package/dist/protocol.js +149 -0
- package/dist/protocol.js.map +1 -0
- package/dist/tool-executor.d.ts +64 -0
- package/dist/tool-executor.js +240 -0
- package/dist/tool-executor.js.map +1 -0
- package/dist/tools.d.ts +183 -0
- package/dist/tools.js +157 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { createTimingInfo, callHookSafe } from './hooks.js';
|
|
2
|
+
import { MetricNames, NoopMetrics } from './metrics.js';
|
|
3
|
+
// Sentence boundary regex: matches .!? followed by space or end of string
|
|
4
|
+
// Handles common abbreviations by requiring whitespace after punctuation
|
|
5
|
+
const SENTENCE_BOUNDARY = /[.!?]+(?:\s+|$)/;
|
|
6
|
+
export class ConversationOrchestrator {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
Object.defineProperty(this, "config", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: config
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "providers", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "history", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: []
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "systemPrompt", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(this, "historyLimit", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "logger", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: void 0
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(this, "streamingTTS", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: void 0
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "sessionId", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: void 0
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(this, "hooks", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: true,
|
|
59
|
+
writable: true,
|
|
60
|
+
value: void 0
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(this, "metrics", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: void 0
|
|
67
|
+
});
|
|
68
|
+
Object.defineProperty(this, "sentenceChunker", {
|
|
69
|
+
enumerable: true,
|
|
70
|
+
configurable: true,
|
|
71
|
+
writable: true,
|
|
72
|
+
value: void 0
|
|
73
|
+
});
|
|
74
|
+
this.providers = config.providers;
|
|
75
|
+
this.systemPrompt = config.systemPrompt;
|
|
76
|
+
this.historyLimit = config.historyLimit ?? 8;
|
|
77
|
+
this.logger = config.logger ?? console;
|
|
78
|
+
this.streamingTTS = config.streamingTTS ?? true;
|
|
79
|
+
this.sessionId = config.sessionId;
|
|
80
|
+
this.hooks = config.hooks ?? {};
|
|
81
|
+
this.metrics = config.metrics ?? new NoopMetrics();
|
|
82
|
+
this.sentenceChunker = config.sentenceChunker;
|
|
83
|
+
}
|
|
84
|
+
async init() {
|
|
85
|
+
await Promise.all([
|
|
86
|
+
this.providers.llm.init?.(),
|
|
87
|
+
this.providers.stt.init?.(),
|
|
88
|
+
this.providers.tts.init?.(),
|
|
89
|
+
this.providers.vision?.init?.()
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run a single voice+vision turn: audio -> STT -> LLM (+optional vision) -> TTS.
|
|
94
|
+
*/
|
|
95
|
+
async runTurn(audio, attachments = []) {
|
|
96
|
+
const transcript = await this.providers.stt.transcribe(audio);
|
|
97
|
+
this.logger.debug?.('[orchestrator] transcript', transcript.text);
|
|
98
|
+
const userMessage = {
|
|
99
|
+
role: 'user',
|
|
100
|
+
content: transcript.text,
|
|
101
|
+
attachments: attachments.length ? attachments : undefined
|
|
102
|
+
};
|
|
103
|
+
if (this.systemPrompt && !this.history.length) {
|
|
104
|
+
this.history.push({ role: 'system', content: this.systemPrompt });
|
|
105
|
+
}
|
|
106
|
+
this.pushHistory(userMessage);
|
|
107
|
+
const llmRequest = {
|
|
108
|
+
messages: this.history.slice(-this.historyLimit),
|
|
109
|
+
config: {
|
|
110
|
+
systemPrompt: this.systemPrompt,
|
|
111
|
+
historyLimit: this.historyLimit,
|
|
112
|
+
temperature: this.config.temperature,
|
|
113
|
+
topP: this.config.topP,
|
|
114
|
+
maxTokens: this.config.maxTokens
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const llm = await this.providers.llm.complete(llmRequest);
|
|
118
|
+
this.logger.debug?.('[orchestrator] llm response', llm.fullText);
|
|
119
|
+
const assistantMessage = { role: 'assistant', content: llm.fullText };
|
|
120
|
+
this.pushHistory(assistantMessage);
|
|
121
|
+
const tts = await this.providers.tts.speak(llm.fullText);
|
|
122
|
+
return { transcript, llm, tts };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Streaming version: yields LLM chunks as they arrive.
|
|
126
|
+
*
|
|
127
|
+
* With streaming TTS enabled (when provider supports speakStream):
|
|
128
|
+
* - Detects sentence boundaries during LLM streaming
|
|
129
|
+
* - Starts TTS generation as soon as each sentence is complete
|
|
130
|
+
* - Yields TTSChunk events with PCM audio data
|
|
131
|
+
* - User hears audio while LLM is still generating
|
|
132
|
+
*
|
|
133
|
+
* Hooks and metrics are called throughout the turn lifecycle.
|
|
134
|
+
*/
|
|
135
|
+
async *runTurnStream(audio, attachments = []) {
|
|
136
|
+
// Generate turn context
|
|
137
|
+
const turnStartTime = Date.now();
|
|
138
|
+
const ctx = {
|
|
139
|
+
turnId: globalThis.crypto.randomUUID(),
|
|
140
|
+
sessionId: this.sessionId,
|
|
141
|
+
startTime: turnStartTime
|
|
142
|
+
};
|
|
143
|
+
// Call onTurnStart hook
|
|
144
|
+
await callHookSafe(this.hooks.onTurnStart, ctx, audio);
|
|
145
|
+
// -------------------------------------------------------------------------
|
|
146
|
+
// STT Phase
|
|
147
|
+
// -------------------------------------------------------------------------
|
|
148
|
+
const sttStartTime = Date.now();
|
|
149
|
+
await callHookSafe(this.hooks.onSTTStart, ctx, audio);
|
|
150
|
+
let transcript;
|
|
151
|
+
try {
|
|
152
|
+
transcript = await this.providers.stt.transcribe(audio);
|
|
153
|
+
const sttTiming = createTimingInfo(sttStartTime, Date.now());
|
|
154
|
+
this.metrics.timing(MetricNames.STT_DURATION, sttTiming.durationMs, {
|
|
155
|
+
provider: this.providers.stt.name
|
|
156
|
+
});
|
|
157
|
+
await callHookSafe(this.hooks.onSTTEnd, ctx, transcript, sttTiming);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
161
|
+
await callHookSafe(this.hooks.onSTTError, ctx, err);
|
|
162
|
+
this.metrics.increment(MetricNames.ERRORS, 1, { component: 'stt' });
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
this.pushHistory({ role: 'user', content: transcript.text, attachments: attachments.length ? attachments : undefined });
|
|
166
|
+
yield transcript;
|
|
167
|
+
const llmRequest = {
|
|
168
|
+
messages: this.history.slice(-this.historyLimit),
|
|
169
|
+
config: {
|
|
170
|
+
systemPrompt: this.systemPrompt,
|
|
171
|
+
historyLimit: this.historyLimit,
|
|
172
|
+
temperature: this.config.temperature,
|
|
173
|
+
topP: this.config.topP,
|
|
174
|
+
maxTokens: this.config.maxTokens
|
|
175
|
+
},
|
|
176
|
+
stream: true
|
|
177
|
+
};
|
|
178
|
+
// -------------------------------------------------------------------------
|
|
179
|
+
// LLM Phase
|
|
180
|
+
// -------------------------------------------------------------------------
|
|
181
|
+
const llmStartTime = Date.now();
|
|
182
|
+
await callHookSafe(this.hooks.onLLMStart, ctx, llmRequest);
|
|
183
|
+
let llmFirstChunkTime;
|
|
184
|
+
// Non-streaming LLM fallback
|
|
185
|
+
if (!this.providers.llm.stream) {
|
|
186
|
+
try {
|
|
187
|
+
const llm = await this.providers.llm.complete(llmRequest);
|
|
188
|
+
const llmTiming = createTimingInfo(llmStartTime, Date.now());
|
|
189
|
+
this.metrics.timing(MetricNames.LLM_DURATION, llmTiming.durationMs, {
|
|
190
|
+
provider: this.providers.llm.name
|
|
191
|
+
});
|
|
192
|
+
await callHookSafe(this.hooks.onLLMEnd, ctx, llm, llmTiming);
|
|
193
|
+
this.pushHistory({ role: 'assistant', content: llm.fullText });
|
|
194
|
+
yield llm;
|
|
195
|
+
yield* this.generateTTSWithHooks(ctx, llm.fullText);
|
|
196
|
+
// Turn complete
|
|
197
|
+
const turnTiming = createTimingInfo(turnStartTime, Date.now());
|
|
198
|
+
this.metrics.timing(MetricNames.TURN_DURATION, turnTiming.durationMs);
|
|
199
|
+
await callHookSafe(this.hooks.onTurnEnd, ctx, turnTiming);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
204
|
+
await callHookSafe(this.hooks.onLLMError, ctx, err);
|
|
205
|
+
this.metrics.increment(MetricNames.ERRORS, 1, { component: 'llm' });
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Check if we can do streaming TTS (requires config enabled AND provider support)
|
|
210
|
+
const canStreamTTS = this.streamingTTS && !!this.providers.tts.speakStream;
|
|
211
|
+
let assembled = '';
|
|
212
|
+
let pendingText = '';
|
|
213
|
+
let ttsStarted = false;
|
|
214
|
+
let chunkIndex = 0;
|
|
215
|
+
const ttsStartTime = Date.now();
|
|
216
|
+
try {
|
|
217
|
+
for await (const chunk of this.providers.llm.stream(llmRequest)) {
|
|
218
|
+
// Track time to first token
|
|
219
|
+
if (chunkIndex === 0 && chunk.content) {
|
|
220
|
+
llmFirstChunkTime = Date.now();
|
|
221
|
+
this.metrics.timing(MetricNames.LLM_TTFT, llmFirstChunkTime - llmStartTime, {
|
|
222
|
+
provider: this.providers.llm.name
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (chunk.content) {
|
|
226
|
+
assembled += chunk.content;
|
|
227
|
+
pendingText += chunk.content;
|
|
228
|
+
}
|
|
229
|
+
// Call LLM chunk hook
|
|
230
|
+
await callHookSafe(this.hooks.onLLMChunk, ctx, chunk, chunkIndex);
|
|
231
|
+
chunkIndex++;
|
|
232
|
+
yield chunk;
|
|
233
|
+
// Only do sentence-boundary TTS if provider supports streaming
|
|
234
|
+
if (canStreamTTS && pendingText) {
|
|
235
|
+
// Check for complete sentences using custom chunker or default
|
|
236
|
+
const sentences = this.splitIntoSentences(pendingText);
|
|
237
|
+
if (sentences.length > 1) {
|
|
238
|
+
// We have at least one complete sentence
|
|
239
|
+
const completeSentences = sentences.slice(0, -1);
|
|
240
|
+
pendingText = sentences[sentences.length - 1];
|
|
241
|
+
for (const completeSentence of completeSentences) {
|
|
242
|
+
if (completeSentence.trim()) {
|
|
243
|
+
// Signal TTS start on first sentence
|
|
244
|
+
if (!ttsStarted) {
|
|
245
|
+
ttsStarted = true;
|
|
246
|
+
await callHookSafe(this.hooks.onTTSStart, ctx, completeSentence.trim());
|
|
247
|
+
yield { type: 'tts-start' };
|
|
248
|
+
}
|
|
249
|
+
// Stream TTS for this sentence
|
|
250
|
+
yield* this.streamTTSChunksWithHooks(ctx, completeSentence.trim());
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// LLM complete
|
|
257
|
+
const llmEndTime = Date.now();
|
|
258
|
+
const llmTiming = createTimingInfo(llmStartTime, llmEndTime);
|
|
259
|
+
this.metrics.timing(MetricNames.LLM_DURATION, llmTiming.durationMs, {
|
|
260
|
+
provider: this.providers.llm.name
|
|
261
|
+
});
|
|
262
|
+
const llmResult = { fullText: assembled };
|
|
263
|
+
await callHookSafe(this.hooks.onLLMEnd, ctx, llmResult, llmTiming);
|
|
264
|
+
this.pushHistory({ role: 'assistant', content: assembled });
|
|
265
|
+
yield llmResult;
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
269
|
+
await callHookSafe(this.hooks.onLLMError, ctx, err);
|
|
270
|
+
this.metrics.increment(MetricNames.ERRORS, 1, { component: 'llm' });
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
// -------------------------------------------------------------------------
|
|
274
|
+
// TTS Phase (remaining text)
|
|
275
|
+
// -------------------------------------------------------------------------
|
|
276
|
+
try {
|
|
277
|
+
// Handle remaining text after LLM completes
|
|
278
|
+
if (canStreamTTS) {
|
|
279
|
+
const remainingText = pendingText.trim();
|
|
280
|
+
if (remainingText) {
|
|
281
|
+
if (!ttsStarted) {
|
|
282
|
+
ttsStarted = true;
|
|
283
|
+
await callHookSafe(this.hooks.onTTSStart, ctx, remainingText);
|
|
284
|
+
yield { type: 'tts-start' };
|
|
285
|
+
}
|
|
286
|
+
yield* this.streamTTSChunksWithHooks(ctx, remainingText);
|
|
287
|
+
}
|
|
288
|
+
// Signal TTS complete
|
|
289
|
+
if (ttsStarted) {
|
|
290
|
+
const ttsTiming = createTimingInfo(ttsStartTime, Date.now());
|
|
291
|
+
this.metrics.timing(MetricNames.TTS_DURATION, ttsTiming.durationMs, {
|
|
292
|
+
provider: this.providers.tts.name
|
|
293
|
+
});
|
|
294
|
+
await callHookSafe(this.hooks.onTTSEnd, ctx, ttsTiming);
|
|
295
|
+
yield { type: 'tts-complete' };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Fallback to non-streaming TTS
|
|
300
|
+
yield* this.generateTTSWithHooks(ctx, assembled);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
305
|
+
await callHookSafe(this.hooks.onTTSError, ctx, err);
|
|
306
|
+
this.metrics.increment(MetricNames.ERRORS, 1, { component: 'tts' });
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
// Turn complete
|
|
310
|
+
const turnTiming = createTimingInfo(turnStartTime, Date.now());
|
|
311
|
+
this.metrics.timing(MetricNames.TURN_DURATION, turnTiming.durationMs);
|
|
312
|
+
await callHookSafe(this.hooks.onTurnEnd, ctx, turnTiming);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Split text into sentences using custom chunker or default regex
|
|
316
|
+
*/
|
|
317
|
+
splitIntoSentences(text) {
|
|
318
|
+
if (this.sentenceChunker) {
|
|
319
|
+
return this.sentenceChunker(text);
|
|
320
|
+
}
|
|
321
|
+
// Default: split on sentence boundaries, keep last part as incomplete
|
|
322
|
+
const parts = text.split(SENTENCE_BOUNDARY);
|
|
323
|
+
// The split removes the delimiter, so we need to reconstruct
|
|
324
|
+
const matches = text.match(new RegExp(SENTENCE_BOUNDARY.source, 'g')) || [];
|
|
325
|
+
const result = [];
|
|
326
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
327
|
+
result.push(parts[i] + (matches[i] || ''));
|
|
328
|
+
}
|
|
329
|
+
// Last part is incomplete (no boundary yet)
|
|
330
|
+
if (parts.length > 0) {
|
|
331
|
+
result.push(parts[parts.length - 1]);
|
|
332
|
+
}
|
|
333
|
+
return result;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Stream TTS chunks for a sentence using PCM format with hooks.
|
|
337
|
+
* Yields TTSChunk events as audio data arrives.
|
|
338
|
+
*/
|
|
339
|
+
async *streamTTSChunksWithHooks(ctx, text) {
|
|
340
|
+
if (!this.providers.tts.speakStream)
|
|
341
|
+
return;
|
|
342
|
+
let chunkIndex = 0;
|
|
343
|
+
try {
|
|
344
|
+
for await (const audioChunk of this.providers.tts.speakStream(text, { format: 'pcm' })) {
|
|
345
|
+
const ttsChunk = {
|
|
346
|
+
type: 'tts-chunk',
|
|
347
|
+
audio: audioChunk,
|
|
348
|
+
format: 'pcm',
|
|
349
|
+
sampleRate: 24000, // OpenAI/ElevenLabs PCM is 24kHz
|
|
350
|
+
sentence: text
|
|
351
|
+
};
|
|
352
|
+
await callHookSafe(this.hooks.onTTSChunk, ctx, ttsChunk, chunkIndex);
|
|
353
|
+
chunkIndex++;
|
|
354
|
+
yield ttsChunk;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
this.logger.error?.('[orchestrator] TTS stream error:', err);
|
|
359
|
+
// Fallback: try non-streaming TTS
|
|
360
|
+
try {
|
|
361
|
+
const tts = await this.providers.tts.speak(text, { format: 'pcm' });
|
|
362
|
+
const ttsChunk = {
|
|
363
|
+
type: 'tts-chunk',
|
|
364
|
+
audio: tts.audio,
|
|
365
|
+
format: 'pcm',
|
|
366
|
+
sampleRate: 24000,
|
|
367
|
+
sentence: text
|
|
368
|
+
};
|
|
369
|
+
await callHookSafe(this.hooks.onTTSChunk, ctx, ttsChunk, chunkIndex);
|
|
370
|
+
yield ttsChunk;
|
|
371
|
+
}
|
|
372
|
+
catch (fallbackErr) {
|
|
373
|
+
this.logger.error?.('[orchestrator] TTS fallback also failed:', fallbackErr);
|
|
374
|
+
throw fallbackErr;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Non-streaming TTS with hooks: generates complete audio and yields as single TTSResult.
|
|
380
|
+
*/
|
|
381
|
+
async *generateTTSWithHooks(ctx, text) {
|
|
382
|
+
const ttsStartTime = Date.now();
|
|
383
|
+
await callHookSafe(this.hooks.onTTSStart, ctx, text);
|
|
384
|
+
yield { type: 'tts-start' };
|
|
385
|
+
const tts = await this.providers.tts.speak(text);
|
|
386
|
+
yield tts;
|
|
387
|
+
const ttsTiming = createTimingInfo(ttsStartTime, Date.now());
|
|
388
|
+
this.metrics.timing(MetricNames.TTS_DURATION, ttsTiming.durationMs, {
|
|
389
|
+
provider: this.providers.tts.name
|
|
390
|
+
});
|
|
391
|
+
await callHookSafe(this.hooks.onTTSEnd, ctx, ttsTiming);
|
|
392
|
+
yield { type: 'tts-complete' };
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* @deprecated Use streamTTSChunksWithHooks instead
|
|
396
|
+
* Stream TTS chunks for a sentence using PCM format.
|
|
397
|
+
*/
|
|
398
|
+
async *streamTTSChunks(text) {
|
|
399
|
+
if (!this.providers.tts.speakStream)
|
|
400
|
+
return;
|
|
401
|
+
try {
|
|
402
|
+
for await (const audioChunk of this.providers.tts.speakStream(text, { format: 'pcm' })) {
|
|
403
|
+
yield {
|
|
404
|
+
type: 'tts-chunk',
|
|
405
|
+
audio: audioChunk,
|
|
406
|
+
format: 'pcm',
|
|
407
|
+
sampleRate: 24000, // OpenAI/ElevenLabs PCM is 24kHz
|
|
408
|
+
sentence: text
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
this.logger.error?.('[orchestrator] TTS stream error:', err);
|
|
414
|
+
// Fallback: try non-streaming TTS
|
|
415
|
+
try {
|
|
416
|
+
const tts = await this.providers.tts.speak(text, { format: 'pcm' });
|
|
417
|
+
yield {
|
|
418
|
+
type: 'tts-chunk',
|
|
419
|
+
audio: tts.audio,
|
|
420
|
+
format: 'pcm',
|
|
421
|
+
sampleRate: 24000,
|
|
422
|
+
sentence: text
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
catch (fallbackErr) {
|
|
426
|
+
this.logger.error?.('[orchestrator] TTS fallback also failed:', fallbackErr);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* @deprecated Use generateTTSWithHooks instead
|
|
432
|
+
* Non-streaming TTS: generates complete audio and yields as single TTSResult.
|
|
433
|
+
*/
|
|
434
|
+
async *generateTTS(text) {
|
|
435
|
+
yield { type: 'tts-start' };
|
|
436
|
+
const tts = await this.providers.tts.speak(text);
|
|
437
|
+
yield tts;
|
|
438
|
+
yield { type: 'tts-complete' };
|
|
439
|
+
}
|
|
440
|
+
pushHistory(message) {
|
|
441
|
+
this.history.push(message);
|
|
442
|
+
if (this.history.length > this.historyLimit + 2) {
|
|
443
|
+
// keep system prompt if present
|
|
444
|
+
const start = this.history[0]?.role === 'system' ? 1 : 0;
|
|
445
|
+
const overflow = this.history.length - (this.historyLimit + 2);
|
|
446
|
+
this.history.splice(start, overflow);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,gBAAgB,EAEhB,YAAY,EACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAkB,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExE,0EAA0E;AAC1E,yEAAyE;AACzE,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAc5C,MAAM,OAAO,wBAAwB;IAYnC,YAA6B,MAAmC;QAApD;;;;mBAAiB,MAAM;WAA6B;QAX/C;;;;;WAAiC;QACjC;;;;mBAAqB,EAAE;WAAC;QACxB;;;;;WAAsB;QACtB;;;;;WAAqB;QACrB;;;;;WAAO;QACP;;;;;WAAsB;QACtB;;;;;WAAmB;QACnB;;;;;WAAyB;QACzB;;;;;WAAwB;QACxB;;;;;WAA6C;QAG5D,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;QAChD,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,WAAW,EAAE,CAAC;QACnD,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,cAAkC,EAAE;QAK/D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,2BAA2B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAElE,MAAM,WAAW,GAAY;YAC3B,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,UAAU,CAAC,IAAI;YACxB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;SAC1D,CAAC;QAEF,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC9C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAE9B,MAAM,UAAU,GAAe;YAC7B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;YAChD,MAAM,EAAE;gBACN,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACpC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;gBACtB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;aACjC;SACF,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEjE,MAAM,gBAAgB,GAAY,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC/E,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAEnC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEzD,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAClC,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,CAAC,aAAa,CAAC,KAAa,EAAE,cAAkC,EAAE;QAKtE,wBAAwB;QACxB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACjC,MAAM,GAAG,GAAgB;YACvB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE;YACtC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,aAAa;SACzB,CAAC;QAEF,wBAAwB;QACxB,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAEvD,4EAA4E;QAC5E,YAAY;QACZ,4EAA4E;QAC5E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAEtD,IAAI,UAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxD,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,UAAU,EAAE;gBAClE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;aAClC,CAAC,CAAC;YACH,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACpD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACxH,MAAM,UAAU,CAAC;QAEjB,MAAM,UAAU,GAAe;YAC7B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;YAChD,MAAM,EAAE;gBACN,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACpC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;gBACtB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;aACjC;YACD,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,4EAA4E;QAC5E,YAAY;QACZ,4EAA4E;QAC5E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,iBAAqC,CAAC;QAE1C,6BAA6B;QAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBAC1D,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,UAAU,EAAE;oBAClE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;iBAClC,CAAC,CAAC;gBACH,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;gBAE7D,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC/D,MAAM,GAAG,CAAC;gBACV,KAAK,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAEpD,gBAAgB;gBAChB,MAAM,UAAU,GAAG,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC/D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;gBACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;gBAC1D,OAAO;YACT,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBACpD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpE,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,kFAAkF;QAClF,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAE3E,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEhC,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChE,4BAA4B;gBAC5B,IAAI,UAAU,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBACtC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,YAAY,EAAE;wBAC1E,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;qBAClC,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC;oBAC3B,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC;gBAC/B,CAAC;gBAED,sBAAsB;gBACtB,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;gBAClE,UAAU,EAAE,CAAC;gBACb,MAAM,KAAK,CAAC;gBAEZ,+DAA+D;gBAC/D,IAAI,YAAY,IAAI,WAAW,EAAE,CAAC;oBAChC,+DAA+D;oBAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;oBACvD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACzB,yCAAyC;wBACzC,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;wBACjD,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBAE9C,KAAK,MAAM,gBAAgB,IAAI,iBAAiB,EAAE,CAAC;4BACjD,IAAI,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC;gCAC5B,qCAAqC;gCACrC,IAAI,CAAC,UAAU,EAAE,CAAC;oCAChB,UAAU,GAAG,IAAI,CAAC;oCAClB,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;oCACxE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAc,CAAC;gCAC1C,CAAC;gCAED,+BAA+B;gCAC/B,KAAK,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;4BACrE,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,eAAe;YACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,UAAU,EAAE;gBAClE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;aAClC,CAAC,CAAC;YAEH,MAAM,SAAS,GAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;YACrD,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YACnE,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5D,MAAM,SAAS,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACpD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,MAAM,KAAK,CAAC;QACd,CAAC;QAED,4EAA4E;QAC5E,6BAA6B;QAC7B,4EAA4E;QAC5E,IAAI,CAAC;YACH,4CAA4C;YAC5C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;gBACzC,IAAI,aAAa,EAAE,CAAC;oBAClB,IAAI,CAAC,UAAU,EAAE,CAAC;wBAChB,UAAU,GAAG,IAAI,CAAC;wBAClB,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;wBAC9D,MAAM,EAAE,IAAI,EAAE,WAAW,EAAc,CAAC;oBAC1C,CAAC;oBACD,KAAK,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;gBAC3D,CAAC;gBAED,sBAAsB;gBACtB,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;oBAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,UAAU,EAAE;wBAClE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;qBAClC,CAAC,CAAC;oBACH,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;oBACxD,MAAM,EAAE,IAAI,EAAE,cAAc,EAAiB,CAAC;gBAChD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,gCAAgC;gBAChC,KAAK,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACpD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,MAAM,KAAK,CAAC;QACd,CAAC;QAED,gBAAgB;QAChB,MAAM,UAAU,GAAG,gBAAgB,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QACtE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,IAAY;QACrC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QACD,sEAAsE;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC5C,6DAA6D;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,4CAA4C;QAC5C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,CAAC,wBAAwB,CACrC,GAAgB,EAChB,IAAY;QAEZ,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW;YAAE,OAAO;QAE5C,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBACvF,MAAM,QAAQ,GAAa;oBACzB,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,UAAU;oBACjB,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE,KAAK,EAAE,iCAAiC;oBACpD,QAAQ,EAAE,IAAI;iBACf,CAAC;gBACF,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACrE,UAAU,EAAE,CAAC;gBACb,MAAM,QAAQ,CAAC;YACjB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YAC7D,kCAAkC;YAClC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpE,MAAM,QAAQ,GAAa;oBACzB,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE,KAAK;oBACjB,QAAQ,EAAE,IAAI;iBACf,CAAC;gBACF,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACrE,MAAM,QAAQ,CAAC;YACjB,CAAC;YAAC,OAAO,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,0CAA0C,EAAE,WAAW,CAAC,CAAC;gBAC7E,MAAM,WAAW,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,CAAC,oBAAoB,CACjC,GAAgB,EAChB,IAAY;QAEZ,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACrD,MAAM,EAAE,IAAI,EAAE,WAAW,EAAc,CAAC;QAExC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,GAAG,CAAC;QAEV,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,UAAU,EAAE;YAClE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;SAClC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,EAAE,IAAI,EAAE,cAAc,EAAiB,CAAC;IAChD,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,CAAC,eAAe,CAAC,IAAY;QACzC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW;YAAE,OAAO;QAE5C,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;gBACvF,MAAM;oBACJ,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,UAAU;oBACjB,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE,KAAK,EAAE,iCAAiC;oBACpD,QAAQ,EAAE,IAAI;iBACf,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YAC7D,kCAAkC;YAClC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpE,MAAM;oBACJ,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE,KAAK;oBACjB,QAAQ,EAAE,IAAI;iBACf,CAAC;YACJ,CAAC;YAAC,OAAO,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,0CAA0C,EAAE,WAAW,CAAC,CAAC;YAC/E,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,CAAC,WAAW,CAAC,IAAY;QACrC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAc,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,GAAG,CAAC;QACV,MAAM,EAAE,IAAI,EAAE,cAAc,EAAiB,CAAC;IAChD,CAAC;IAEO,WAAW,CAAC,OAAgB;QAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;YAChD,gCAAgC;YAChC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;YAC/D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playbook Engine
|
|
3
|
+
*
|
|
4
|
+
* Evaluates transition rules and manages stage transitions in a playbook.
|
|
5
|
+
*/
|
|
6
|
+
import type { Playbook, PlaybookState, Stage, Transition, TransitionEvaluationResult } from './playbook.js';
|
|
7
|
+
/**
|
|
8
|
+
* Options for the playbook engine
|
|
9
|
+
*/
|
|
10
|
+
export interface PlaybookEngineOptions {
|
|
11
|
+
/** Enable debug logging */
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
/** Custom logger */
|
|
14
|
+
logger?: {
|
|
15
|
+
debug: (msg: string, ...args: unknown[]) => void;
|
|
16
|
+
info: (msg: string, ...args: unknown[]) => void;
|
|
17
|
+
warn: (msg: string, ...args: unknown[]) => void;
|
|
18
|
+
error: (msg: string, ...args: unknown[]) => void;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Event emitted during playbook execution
|
|
23
|
+
*/
|
|
24
|
+
export type PlaybookEvent = {
|
|
25
|
+
type: 'stage_enter';
|
|
26
|
+
stage: Stage;
|
|
27
|
+
previousStage?: Stage;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'stage_exit';
|
|
30
|
+
stage: Stage;
|
|
31
|
+
nextStage: Stage;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'transition';
|
|
34
|
+
transition: Transition;
|
|
35
|
+
from: Stage;
|
|
36
|
+
to: Stage;
|
|
37
|
+
} | {
|
|
38
|
+
type: 'turn_complete';
|
|
39
|
+
stage: Stage;
|
|
40
|
+
turnCount: number;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'playbook_complete';
|
|
43
|
+
finalStage: Stage;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Listener for playbook events
|
|
47
|
+
*/
|
|
48
|
+
export type PlaybookEventListener = (event: PlaybookEvent) => void | Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Playbook Engine - Evaluates transitions and manages playbook state
|
|
51
|
+
*/
|
|
52
|
+
export declare class PlaybookEngine {
|
|
53
|
+
private readonly playbook;
|
|
54
|
+
private state;
|
|
55
|
+
private readonly options;
|
|
56
|
+
private readonly listeners;
|
|
57
|
+
private sessionMetadata;
|
|
58
|
+
constructor(playbook: Playbook, options?: PlaybookEngineOptions);
|
|
59
|
+
/**
|
|
60
|
+
* Get current playbook state
|
|
61
|
+
*/
|
|
62
|
+
getState(): Readonly<PlaybookState>;
|
|
63
|
+
/**
|
|
64
|
+
* Get current stage
|
|
65
|
+
*/
|
|
66
|
+
getCurrentStage(): Stage;
|
|
67
|
+
/**
|
|
68
|
+
* Get the playbook
|
|
69
|
+
*/
|
|
70
|
+
getPlaybook(): Playbook;
|
|
71
|
+
/**
|
|
72
|
+
* Set session metadata
|
|
73
|
+
*/
|
|
74
|
+
setSessionMetadata(metadata: Record<string, unknown>): void;
|
|
75
|
+
/**
|
|
76
|
+
* Update conversation context
|
|
77
|
+
*/
|
|
78
|
+
updateContext(updates: Record<string, unknown>): void;
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to playbook events
|
|
81
|
+
*/
|
|
82
|
+
on(listener: PlaybookEventListener): () => void;
|
|
83
|
+
/**
|
|
84
|
+
* Emit an event to all listeners
|
|
85
|
+
*/
|
|
86
|
+
private emit;
|
|
87
|
+
/**
|
|
88
|
+
* Log a debug message
|
|
89
|
+
*/
|
|
90
|
+
private log;
|
|
91
|
+
/**
|
|
92
|
+
* Build transition context for evaluation
|
|
93
|
+
*/
|
|
94
|
+
private buildTransitionContext;
|
|
95
|
+
/**
|
|
96
|
+
* Evaluate a single transition condition
|
|
97
|
+
*/
|
|
98
|
+
private evaluateCondition;
|
|
99
|
+
/**
|
|
100
|
+
* Evaluate all applicable transitions and return the highest priority match
|
|
101
|
+
*/
|
|
102
|
+
evaluateTransitions(lastAssistantMessage?: string, lastToolCalls?: Array<{
|
|
103
|
+
name: string;
|
|
104
|
+
arguments: Record<string, unknown>;
|
|
105
|
+
}>): Promise<TransitionEvaluationResult>;
|
|
106
|
+
/**
|
|
107
|
+
* Check if a specific transition should be triggered (e.g., from playbook_transition tool)
|
|
108
|
+
*/
|
|
109
|
+
evaluateExplicitTransition(targetStage: string, reason: string, data?: Record<string, unknown>): Promise<TransitionEvaluationResult>;
|
|
110
|
+
/**
|
|
111
|
+
* Execute a stage transition
|
|
112
|
+
*/
|
|
113
|
+
executeTransition(transition: Transition, overrideData?: Record<string, unknown>): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Increment turn count and emit event
|
|
116
|
+
*/
|
|
117
|
+
completeTurn(): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Mark playbook as complete
|
|
120
|
+
*/
|
|
121
|
+
complete(): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Get the effective system prompt for current stage
|
|
124
|
+
* (combines global prompt with stage-specific prompt)
|
|
125
|
+
*/
|
|
126
|
+
getEffectiveSystemPrompt(): string;
|
|
127
|
+
/**
|
|
128
|
+
* Get all tools available in current stage
|
|
129
|
+
* (combines global tools with stage-specific tools)
|
|
130
|
+
*/
|
|
131
|
+
getAvailableTools(): import('./tools.js').ToolDefinition[];
|
|
132
|
+
/**
|
|
133
|
+
* Get effective LLM config for current stage
|
|
134
|
+
*/
|
|
135
|
+
getEffectiveLLMConfig(): import('./playbook.js').StageLLMConfig;
|
|
136
|
+
/**
|
|
137
|
+
* Reset engine to initial state
|
|
138
|
+
*/
|
|
139
|
+
reset(): void;
|
|
140
|
+
}
|