@ai-ecoverse/pi-audio 1.7.0 → 1.9.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/README.md +2 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +2 -2
- package/dist/openai-realtime/index.js +58 -0
- package/dist/openai-realtime/index.js.map +7 -0
- package/dist/openai-realtime/session.js +494 -0
- package/dist/openai-realtime/session.js.map +7 -0
- package/dist/openai-realtime/socket.js +56 -0
- package/dist/openai-realtime/socket.js.map +7 -0
- package/dist/queue.js +46 -0
- package/dist/queue.js.map +7 -0
- package/dist/spoken.js +197 -0
- package/dist/spoken.js.map +7 -0
- package/dist/turns.js +347 -0
- package/dist/turns.js.map +7 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/openai-realtime/index.d.ts +7 -0
- package/dist/types/openai-realtime/session.d.ts +15 -0
- package/dist/types/openai-realtime/socket.d.ts +25 -0
- package/dist/types/queue.d.ts +6 -0
- package/dist/types/spoken.d.ts +57 -0
- package/dist/types/turns.d.ts +107 -0
- package/dist/types/xai/index.d.ts +4 -0
- package/dist/xai/index.js +51 -0
- package/dist/xai/index.js.map +7 -0
- package/package.json +10 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/openai-realtime/session.ts"],
|
|
4
|
+
"sourcesContent": ["import type { JsonObject, Tool, ToolResultMessage, Usage } from '@earendil-works/pi-ai';\nimport type { AudioChunk, AudioFormat, TextSpan } from '../audio.ts';\nimport { blankUsage } from '../blank-usage.ts';\nimport { decodeAudioBase64, encodeAudioBase64 } from '../convert.ts';\nimport { VoiceRequestError } from '../errors.ts';\nimport type { Delivery, RealtimeModel } from '../models.ts';\nimport type {\n RealtimeContext,\n RealtimeEvent,\n RealtimeOptions,\n RealtimeSession,\n} from '../realtime.ts';\nimport { planTruncation, RealtimeLedger, realtimeSocket } from '../realtime.ts';\nimport {\n openVoiceSocket,\n type VoiceSocketConstructor,\n type VoiceWire,\n type VoiceWireTarget,\n} from './socket.ts';\n\nexport type VoiceWireFactory = (target: VoiceWireTarget) => VoiceWire;\n\nexport interface AdapterOptions {\n wire?: VoiceWireFactory;\n socket?: VoiceSocketConstructor;\n replace?: Record<string, string>;\n}\n\nexport interface VendorSessionOptions extends AdapterOptions {\n dialect: 'openai' | 'xai';\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined;\n return value as Record<string, unknown>;\n}\n\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction credential(options: RealtimeOptions | undefined): string {\n const token = options?.token?.value;\n if (typeof token === 'string' && token.length > 0) return token;\n const apiKey = options?.apiKey;\n if (typeof apiKey === 'string' && apiKey.length > 0) return apiKey;\n throw new VoiceRequestError('error', 'missing realtime credential');\n}\n\nfunction headersFor(\n options: RealtimeOptions | undefined,\n secret: string,\n bearer: boolean\n): Record<string, string> {\n const headers: Record<string, string> = {};\n if (bearer) headers.Authorization = `Bearer ${secret}`;\n const extra = options?.headers;\n if (extra === undefined) return headers;\n for (const [key, value] of Object.entries(extra)) {\n if (value === null) delete headers[key];\n else headers[key] = value;\n }\n return headers;\n}\n\nfunction sessionUrl(model: RealtimeModel<string>, resumeHandle: string | undefined): string {\n const params = new URLSearchParams({ model: model.id });\n if (resumeHandle !== undefined) params.set('conversation_id', resumeHandle);\n return `${model.baseUrl}?${params.toString()}`;\n}\n\nfunction functionTool(tool: Tool): JsonObject {\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters as unknown as JsonObject,\n };\n}\n\nfunction openaiSession(context: RealtimeContext, model: RealtimeModel<string>): JsonObject {\n return {\n type: 'realtime',\n instructions: context.instructions,\n tools: context.tools.map(functionTool),\n audio: {\n input: {\n format: { type: 'audio/pcm', rate: model.inputFormat.sampleRate },\n turn_detection: { type: 'server_vad' },\n },\n output: {\n format: { type: 'audio/pcm', rate: model.outputFormat.sampleRate },\n voice: context.voice,\n },\n },\n };\n}\n\nfunction xaiSession(\n context: RealtimeContext,\n model: RealtimeModel<string>,\n replace: Record<string, string> | undefined\n): JsonObject {\n const session: JsonObject = {\n voice: context.voice,\n instructions: context.instructions,\n turn_detection: { type: 'server_vad' },\n tools: context.tools.map(functionTool),\n resumption: { enabled: true },\n audio: {\n input: { format: { type: 'audio/pcm', rate: model.inputFormat.sampleRate } },\n output: { format: { type: 'audio/pcm', rate: model.outputFormat.sampleRate } },\n },\n };\n if (replace !== undefined) session.replace = replace;\n return session;\n}\n\nfunction userItem(value: string): JsonObject {\n return {\n type: 'conversation.item.create',\n item: {\n type: 'message',\n role: 'user',\n content: [{ type: 'input_text', text: value }],\n },\n };\n}\n\nfunction responseCreate(): JsonObject {\n return { type: 'response.create' };\n}\n\nfunction resultText(result: ToolResultMessage): string {\n const parts: string[] = [];\n for (const part of result.content) {\n if (part.type === 'text') parts.push(part.text);\n }\n return parts.join('\\n');\n}\n\nfunction toolOutput(callId: string, result: ToolResultMessage): JsonObject {\n return {\n type: 'conversation.item.create',\n item: { type: 'function_call_output', call_id: callId, output: resultText(result) },\n };\n}\n\nfunction forceMessage(value: string): JsonObject {\n return {\n type: 'conversation.item.create',\n item: {\n type: 'force_message',\n role: 'assistant',\n content: [{ type: 'output_text', text: value }],\n },\n };\n}\n\ninterface PendingAudio {\n chunks: AudioChunk[];\n cursor: number;\n}\n\nfunction spanFor(itemId: string, start: number, end: number): TextSpan {\n return { itemId, start, end };\n}\n\nfunction takeAudio(\n pending: PendingAudio,\n itemId: string,\n format: AudioFormat,\n end: number | undefined\n): RealtimeEvent[] {\n const chunks = pending.chunks;\n pending.chunks = [];\n if (chunks.length === 0) return [];\n const start = pending.cursor;\n if (end !== undefined) pending.cursor = end;\n const width = end === undefined ? 0 : end - start;\n const total = chunks.reduce((sum, chunk) => sum + chunk.data.length, 0);\n let used = 0;\n let cursor = start;\n return chunks.map((chunk, index) => {\n const event: RealtimeEvent = {\n type: 'output_audio',\n itemId,\n chunk: { data: chunk.data, format, timestamp: chunk.timestamp },\n };\n if (end === undefined || total === 0) return event;\n const last = index === chunks.length - 1;\n const next = last ? end : start + Math.round(((used + chunk.data.length) / total) * width);\n used += chunk.data.length;\n event.span = spanFor(itemId, cursor, next);\n cursor = next;\n return event;\n });\n}\n\nfunction argumentsOf(value: unknown): JsonObject {\n if (typeof value !== 'string') return {};\n try {\n const parsed: unknown = JSON.parse(value);\n const object = record(parsed);\n if (object === undefined) return {};\n return object as JsonObject;\n } catch {\n return {};\n }\n}\n\nfunction responseUsage(value: unknown): Usage {\n const usage = record(value);\n if (usage === undefined) return blankUsage();\n const input = typeof usage.input_tokens === 'number' ? usage.input_tokens : 0;\n const output = typeof usage.output_tokens === 'number' ? usage.output_tokens : 0;\n return {\n input,\n output,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: input + output,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n };\n}\n\nclass VendorSession implements RealtimeSession {\n readonly model: RealtimeModel<string>;\n readonly #dialect: 'openai' | 'xai';\n readonly #context: RealtimeContext;\n readonly #replace: Record<string, string> | undefined;\n readonly #wire: VoiceWire;\n readonly #ledger = new RealtimeLedger();\n readonly #format: AudioFormat;\n readonly #pending = new Map<string, PendingAudio>();\n readonly #inputText = new Map<string, string>();\n readonly #queue: RealtimeEvent[] = [];\n readonly #waiters: Array<(result: IteratorResult<RealtimeEvent>) => void> = [];\n #closed = false;\n #usage: Usage | undefined;\n #lastItem = '';\n\n constructor(\n model: RealtimeModel<string>,\n context: RealtimeContext,\n dialect: 'openai' | 'xai',\n replace: Record<string, string> | undefined,\n wire: VoiceWire\n ) {\n this.model = model;\n this.#context = context;\n this.#dialect = dialect;\n this.#replace = replace;\n this.#wire = wire;\n this.#format = model.outputFormat;\n }\n\n start(options: RealtimeOptions | undefined): void {\n this.#send(this.#sessionUpdate(this.#context));\n const signal = options?.signal;\n if (signal !== undefined) signal.addEventListener('abort', () => void this.close());\n void this.#read();\n }\n\n appendAudio(chunk: AudioChunk): void {\n this.#assertOpen();\n this.#ledger.addInput(chunk);\n this.#send({ type: 'input_audio_buffer.append', audio: encodeAudioBase64(chunk.data) });\n }\n\n sendText(textValue: string): void {\n this.#assertOpen();\n this.#ledger.addText();\n this.#send(userItem(textValue));\n this.#send(responseCreate());\n }\n\n inject(textValue: string, delivery: Delivery): void {\n this.#assertOpen();\n this.#ledger.submit(this.model.delivery, delivery, () => {\n this.#assertOpen();\n this.#ledger.addText();\n this.#sendInject(textValue, delivery);\n });\n }\n\n respond(callId: string, result: ToolResultMessage, delivery?: Delivery): void {\n this.#assertOpen();\n const send = (): void => {\n this.#send(toolOutput(callId, result));\n if (delivery !== 'silent') this.#send(responseCreate());\n };\n if (delivery === undefined) {\n send();\n return;\n }\n this.#ledger.submit(this.model.delivery, delivery, () => {\n this.#assertOpen();\n send();\n });\n }\n\n interrupt(heard?: { itemId: string; heardMs: number }): void {\n this.#assertOpen();\n this.#send({ type: 'response.cancel' });\n const plan = planTruncation(this.model.truncation, heard);\n if (plan.item !== undefined) {\n this.#send({\n type: 'conversation.item.truncate',\n item_id: plan.item.itemId,\n content_index: 0,\n audio_end_ms: plan.item.audioEndMs,\n });\n }\n this.#ledger.settle();\n }\n\n update(patch: Partial<Pick<RealtimeContext, 'instructions' | 'tools' | 'voice'>>): void {\n this.#assertOpen();\n if (patch.tools !== undefined && !this.model.liveToolUpdate) {\n throw new VoiceRequestError('error', 'live tool update is unsupported');\n }\n let instructions = this.#context.instructions;\n if (patch.instructions !== undefined) instructions = patch.instructions;\n let tools = this.#context.tools;\n if (patch.tools !== undefined) tools = patch.tools;\n let voice = this.#context.voice;\n if (patch.voice !== undefined) voice = patch.voice;\n const context: RealtimeContext = { instructions, tools, voice };\n if (patch.instructions !== undefined) this.#context.instructions = context.instructions;\n if (patch.tools !== undefined) this.#context.tools = context.tools;\n if (patch.voice !== undefined) this.#context.voice = context.voice;\n this.#send(this.#sessionUpdate(context));\n }\n\n async close(): Promise<{ usage: Usage }> {\n if (this.#usage !== undefined) return { usage: this.#usage };\n this.#ledger.settle();\n this.#closed = true;\n this.#wire.close();\n this.#end();\n this.#usage = this.#ledger.usage(this.model.audioCost);\n return { usage: this.#usage };\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<RealtimeEvent> {\n while (true) {\n const queued = this.#queue.shift();\n if (queued !== undefined) {\n yield queued;\n continue;\n }\n if (this.#closed) return;\n const next = await new Promise<IteratorResult<RealtimeEvent>>((resolve) => {\n this.#waiters.push(resolve);\n });\n if (next.done === true || next.value === undefined) return;\n yield next.value;\n }\n }\n\n #sessionUpdate(context: RealtimeContext): JsonObject {\n if (this.#dialect === 'openai') {\n return { type: 'session.update', session: openaiSession(context, this.model) };\n }\n return { type: 'session.update', session: xaiSession(context, this.model, this.#replace) };\n }\n\n #sendInject(textValue: string, delivery: Delivery): void {\n if (this.#dialect === 'xai' && delivery !== 'silent') {\n this.#send(forceMessage(textValue));\n return;\n }\n this.#send(userItem(textValue));\n if (delivery !== 'silent') this.#send(responseCreate());\n }\n\n #send(event: JsonObject): void {\n this.#wire.send(JSON.stringify(event));\n }\n\n #assertOpen(): void {\n if (this.#closed) throw new VoiceRequestError('error', 'session is closed');\n }\n\n #push(event: RealtimeEvent): void {\n if (this.#closed) return;\n this.#ledger.observe(event);\n const waiter = this.#waiters.shift();\n if (waiter !== undefined) waiter({ value: event, done: false });\n else this.#queue.push(event);\n }\n\n #end(): void {\n for (const waiter of this.#waiters) waiter({ value: undefined, done: true });\n this.#waiters.length = 0;\n }\n\n #pendingFor(itemId: string): PendingAudio {\n const existing = this.#pending.get(itemId);\n if (existing !== undefined) return existing;\n const created = { chunks: [], cursor: 0 };\n this.#pending.set(itemId, created);\n return created;\n }\n\n #audio(itemId: string, encoded: string): void {\n this.#lastItem = itemId;\n const pending = this.#pendingFor(itemId);\n pending.chunks.push({\n data: decodeAudioBase64(encoded),\n format: this.#format,\n timestamp: 0,\n });\n }\n\n #transcript(itemId: string, delta: string, final: boolean): void {\n const pending = this.#pendingFor(itemId);\n const end = pending.cursor + delta.length;\n const tagged = delta.length === 0 ? undefined : end;\n for (const event of takeAudio(pending, itemId, this.#format, tagged)) this.#push(event);\n this.#push({ type: 'output_transcript', itemId, text: delta, final });\n }\n\n #input(itemId: string, transcript: string, mode: 'append' | 'replace', final: boolean): void {\n const previous = this.#inputText.get(itemId) ?? '';\n const next = mode === 'append' ? `${previous}${transcript}` : transcript;\n this.#inputText.set(itemId, next);\n this.#push({ type: 'input_transcript', itemId, text: next, final });\n }\n\n #field(value: unknown, key: string): string {\n const object = record(value);\n if (object === undefined) return '';\n return text(object[key]);\n }\n\n #functionCall(event: Record<string, unknown>): void {\n this.#push({\n type: 'tool_call',\n blocking: this.model.toolCalls === 'blocking',\n call: {\n type: 'toolCall',\n id: text(event.call_id),\n name: text(event.name),\n arguments: argumentsOf(event.arguments),\n },\n });\n }\n\n #responseDone(event: Record<string, unknown>): void {\n const response = record(event.response);\n const output = response === undefined ? undefined : response.output;\n const first = Array.isArray(output) ? record(output[0]) : undefined;\n let itemId = this.#lastItem;\n if (first !== undefined && text(first.id).length > 0) itemId = text(first.id);\n const pending = this.#pendingFor(itemId);\n for (const audioEvent of takeAudio(pending, itemId, this.#format, undefined)) {\n this.#push(audioEvent);\n }\n const status = response === undefined ? '' : text(response.status);\n const usage = response === undefined ? undefined : response.usage;\n this.#push({\n type: 'response_done',\n itemId,\n interrupted: status === 'cancelled',\n usage: responseUsage(usage),\n });\n }\n\n #serverError(event: Record<string, unknown>): void {\n const detail = record(event.error);\n const code = detail === undefined ? '' : text(detail.code);\n const message = detail === undefined ? '' : text(detail.message);\n let fatal = false;\n if (code === 'max_duration') fatal = true;\n if (code === 'session_expired') fatal = true;\n this.#push({ type: 'error', error: message, fatal });\n }\n\n #apply(event: Record<string, unknown>): void {\n const type = text(event.type);\n if (type === 'session.created') {\n this.#push({ type: 'session_start', sessionId: this.#field(event.session, 'id') });\n return;\n }\n if (type === 'conversation.created') {\n this.#push({ type: 'resumption', handle: this.#field(event.conversation, 'id') });\n return;\n }\n if (type === 'input_audio_buffer.speech_started') {\n this.#push({ type: 'input_speech_start' });\n return;\n }\n if (type === 'conversation.item.input_audio_transcription.delta') {\n this.#input(text(event.item_id), text(event.delta), 'append', false);\n return;\n }\n if (type === 'conversation.item.input_audio_transcription.updated') {\n this.#input(text(event.item_id), text(event.transcript), 'replace', false);\n return;\n }\n if (type === 'conversation.item.input_audio_transcription.completed') {\n this.#input(text(event.item_id), text(event.transcript), 'replace', true);\n return;\n }\n if (type === 'response.output_audio.delta') {\n this.#audio(text(event.item_id), text(event.delta));\n return;\n }\n if (type === 'response.output_audio_transcript.delta') {\n this.#transcript(text(event.item_id), text(event.delta), false);\n return;\n }\n if (type === 'response.output_audio_transcript.done') {\n this.#transcript(text(event.item_id), text(event.transcript), true);\n return;\n }\n if (type === 'response.function_call_arguments.done') {\n this.#functionCall(event);\n return;\n }\n if (type === 'response.done') {\n this.#responseDone(event);\n return;\n }\n if (type === 'error') this.#serverError(event);\n }\n\n async #read(): Promise<void> {\n try {\n for await (const raw of this.#wire.incoming) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n this.#push({ type: 'error', error: 'invalid realtime event', fatal: false });\n continue;\n }\n const event = record(parsed);\n if (event === undefined || typeof event.type !== 'string') continue;\n this.#apply(event);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.#push({ type: 'error', error: message, fatal: true });\n } finally {\n this.#closed = true;\n this.#end();\n }\n }\n}\n\nexport async function connectVendorSession(\n model: RealtimeModel<string>,\n context: RealtimeContext,\n options: RealtimeOptions | undefined,\n vendor: VendorSessionOptions\n): Promise<RealtimeSession> {\n if (options?.signal?.aborted === true) {\n throw new VoiceRequestError('aborted', 'session aborted');\n }\n if (options?.transport === 'webrtc' && vendor.wire === undefined) {\n throw new VoiceRequestError('error', 'webrtc requires a data channel wire');\n }\n const secret = credential(options);\n const token = options?.token?.value;\n const ephemeral = typeof token === 'string' && token.length > 0;\n const protocols: string[] = [];\n if (vendor.dialect === 'openai') protocols.push(`openai-insecure-api-key.${secret}`, 'realtime');\n else if (ephemeral) protocols.push(`xai-client-secret.${secret}`);\n else protocols.push('realtime');\n const resumeHandle = vendor.dialect === 'xai' ? options?.resumeHandle : undefined;\n const socket = realtimeSocket(sessionUrl(model, resumeHandle), options, protocols);\n const target: VoiceWireTarget = {\n url: socket.url,\n protocols: socket.protocols,\n headers: headersFor(options, secret, vendor.dialect === 'openai' || !ephemeral),\n };\n const open =\n vendor.wire !== undefined\n ? vendor.wire\n : (wireTarget: VoiceWireTarget) => openVoiceSocket(wireTarget, vendor.socket);\n const session = new VendorSession(model, context, vendor.dialect, vendor.replace, open(target));\n session.start(options);\n return session;\n}\n\nexport function pcmFormat(sampleRate: number): AudioFormat {\n return { encoding: 'pcm16', sampleRate, channels: 1 };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
function openVoiceSocket(target, Socket = WebSocket) {
|
|
2
|
+
const socket = new Socket(target.url, {
|
|
3
|
+
protocols: target.protocols,
|
|
4
|
+
headers: target.headers
|
|
5
|
+
});
|
|
6
|
+
const queue = [];
|
|
7
|
+
const waiters = [];
|
|
8
|
+
let closed = false;
|
|
9
|
+
const push = (value) => {
|
|
10
|
+
if (closed) return;
|
|
11
|
+
const waiter = waiters.shift();
|
|
12
|
+
if (waiter !== void 0) waiter({ value, done: false });
|
|
13
|
+
else queue.push(value);
|
|
14
|
+
};
|
|
15
|
+
const end = () => {
|
|
16
|
+
if (closed) return;
|
|
17
|
+
closed = true;
|
|
18
|
+
for (const waiter of waiters) waiter({ value: void 0, done: true });
|
|
19
|
+
waiters.length = 0;
|
|
20
|
+
};
|
|
21
|
+
socket.addEventListener("message", (event) => {
|
|
22
|
+
push(typeof event.data === "string" ? event.data : String(event.data));
|
|
23
|
+
});
|
|
24
|
+
socket.addEventListener("close", end);
|
|
25
|
+
socket.addEventListener("error", end);
|
|
26
|
+
return {
|
|
27
|
+
send(data) {
|
|
28
|
+
socket.send(data);
|
|
29
|
+
},
|
|
30
|
+
close() {
|
|
31
|
+
socket.close();
|
|
32
|
+
end();
|
|
33
|
+
},
|
|
34
|
+
incoming: {
|
|
35
|
+
async *[Symbol.asyncIterator]() {
|
|
36
|
+
while (true) {
|
|
37
|
+
const queued = queue.shift();
|
|
38
|
+
if (queued !== void 0) {
|
|
39
|
+
yield queued;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (closed) return;
|
|
43
|
+
const next = await new Promise((resolve) => {
|
|
44
|
+
waiters.push(resolve);
|
|
45
|
+
});
|
|
46
|
+
if (next.done === true || next.value === void 0) return;
|
|
47
|
+
yield next.value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
openVoiceSocket
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=socket.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/openai-realtime/socket.ts"],
|
|
4
|
+
"sourcesContent": ["export interface VoiceWireTarget {\n url: string;\n protocols: string[];\n headers: Record<string, string>;\n}\n\nexport interface VoiceWire {\n send(data: string): void;\n close(): void;\n incoming: AsyncIterable<string>;\n}\n\nexport interface VoiceSocket {\n send(data: string): void;\n close(): void;\n addEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n addEventListener(type: 'close', listener: () => void): void;\n addEventListener(type: 'error', listener: () => void): void;\n}\n\nexport type VoiceSocketInit = {\n protocols: string[];\n headers: Record<string, string>;\n};\n\nexport type VoiceSocketConstructor = new (url: string, init: VoiceSocketInit) => VoiceSocket;\n\nexport function openVoiceSocket(\n target: VoiceWireTarget,\n Socket: VoiceSocketConstructor = WebSocket as unknown as VoiceSocketConstructor\n): VoiceWire {\n const socket = new Socket(target.url, {\n protocols: target.protocols,\n headers: target.headers,\n });\n const queue: string[] = [];\n const waiters: Array<(result: IteratorResult<string>) => void> = [];\n let closed = false;\n\n const push = (value: string): void => {\n if (closed) return;\n const waiter = waiters.shift();\n if (waiter !== undefined) waiter({ value, done: false });\n else queue.push(value);\n };\n\n const end = (): void => {\n if (closed) return;\n closed = true;\n for (const waiter of waiters) waiter({ value: undefined, done: true });\n waiters.length = 0;\n };\n\n socket.addEventListener('message', (event) => {\n push(typeof event.data === 'string' ? event.data : String(event.data));\n });\n socket.addEventListener('close', end);\n socket.addEventListener('error', end);\n\n return {\n send(data) {\n socket.send(data);\n },\n close() {\n socket.close();\n end();\n },\n incoming: {\n async *[Symbol.asyncIterator]() {\n while (true) {\n const queued = queue.shift();\n if (queued !== undefined) {\n yield queued;\n continue;\n }\n if (closed) return;\n const next = await new Promise<IteratorResult<string>>((resolve) => {\n waiters.push(resolve);\n });\n if (next.done === true || next.value === undefined) return;\n yield next.value;\n }\n },\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AA2BO,SAAS,gBACd,QACA,SAAiC,WACtB;AACX,QAAM,SAAS,IAAI,OAAO,OAAO,KAAK;AAAA,IACpC,WAAW,OAAO;AAAA,IAClB,SAAS,OAAO;AAAA,EAClB,CAAC;AACD,QAAM,QAAkB,CAAC;AACzB,QAAM,UAA2D,CAAC;AAClE,MAAI,SAAS;AAEb,QAAM,OAAO,CAAC,UAAwB;AACpC,QAAI,OAAQ;AACZ,UAAM,SAAS,QAAQ,MAAM;AAC7B,QAAI,WAAW,OAAW,QAAO,EAAE,OAAO,MAAM,MAAM,CAAC;AAAA,QAClD,OAAM,KAAK,KAAK;AAAA,EACvB;AAEA,QAAM,MAAM,MAAY;AACtB,QAAI,OAAQ;AACZ,aAAS;AACT,eAAW,UAAU,QAAS,QAAO,EAAE,OAAO,QAAW,MAAM,KAAK,CAAC;AACrE,YAAQ,SAAS;AAAA,EACnB;AAEA,SAAO,iBAAiB,WAAW,CAAC,UAAU;AAC5C,SAAK,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,EACvE,CAAC;AACD,SAAO,iBAAiB,SAAS,GAAG;AACpC,SAAO,iBAAiB,SAAS,GAAG;AAEpC,SAAO;AAAA,IACL,KAAK,MAAM;AACT,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,IACA,QAAQ;AACN,aAAO,MAAM;AACb,UAAI;AAAA,IACN;AAAA,IACA,UAAU;AAAA,MACR,QAAQ,OAAO,aAAa,IAAI;AAC9B,eAAO,MAAM;AACX,gBAAM,SAAS,MAAM,MAAM;AAC3B,cAAI,WAAW,QAAW;AACxB,kBAAM;AACN;AAAA,UACF;AACA,cAAI,OAAQ;AACZ,gBAAM,OAAO,MAAM,IAAI,QAAgC,CAAC,YAAY;AAClE,oBAAQ,KAAK,OAAO;AAAA,UACtB,CAAC;AACD,cAAI,KAAK,SAAS,QAAQ,KAAK,UAAU,OAAW;AACpD,gBAAM,KAAK;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function pushQueue() {
|
|
2
|
+
const values = [];
|
|
3
|
+
let ended = false;
|
|
4
|
+
let wake;
|
|
5
|
+
const notify = () => {
|
|
6
|
+
const current = wake;
|
|
7
|
+
wake = void 0;
|
|
8
|
+
current?.();
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
push(value) {
|
|
12
|
+
if (ended) return;
|
|
13
|
+
values.push(value);
|
|
14
|
+
notify();
|
|
15
|
+
},
|
|
16
|
+
end() {
|
|
17
|
+
ended = true;
|
|
18
|
+
notify();
|
|
19
|
+
},
|
|
20
|
+
iterable: {
|
|
21
|
+
async *[Symbol.asyncIterator]() {
|
|
22
|
+
let index = 0;
|
|
23
|
+
while (true) {
|
|
24
|
+
if (index < values.length) {
|
|
25
|
+
const value = values[index];
|
|
26
|
+
index += 1;
|
|
27
|
+
if (value !== void 0) yield value;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (ended) return;
|
|
31
|
+
await new Promise((resolve) => {
|
|
32
|
+
wake = () => {
|
|
33
|
+
wake = void 0;
|
|
34
|
+
resolve();
|
|
35
|
+
};
|
|
36
|
+
if (index < values.length || ended) wake();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
pushQueue
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/queue.ts"],
|
|
4
|
+
"sourcesContent": ["export interface PushQueue<T> {\n push(value: T): void;\n end(): void;\n readonly iterable: AsyncIterable<T>;\n}\n\nexport function pushQueue<T>(): PushQueue<T> {\n const values: T[] = [];\n let ended = false;\n let wake: (() => void) | undefined;\n const notify = () => {\n const current = wake;\n wake = undefined;\n current?.();\n };\n return {\n push(value) {\n if (ended) return;\n values.push(value);\n notify();\n },\n end() {\n ended = true;\n notify();\n },\n iterable: {\n async *[Symbol.asyncIterator]() {\n let index = 0;\n while (true) {\n if (index < values.length) {\n const value = values[index];\n index += 1;\n if (value !== undefined) yield value;\n continue;\n }\n if (ended) return;\n await new Promise<void>((resolve) => {\n wake = () => {\n wake = undefined;\n resolve();\n };\n if (index < values.length || ended) wake();\n });\n }\n },\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAMO,SAAS,YAA6B;AAC3C,QAAM,SAAc,CAAC;AACrB,MAAI,QAAQ;AACZ,MAAI;AACJ,QAAM,SAAS,MAAM;AACnB,UAAM,UAAU;AAChB,WAAO;AACP,cAAU;AAAA,EACZ;AACA,SAAO;AAAA,IACL,KAAK,OAAO;AACV,UAAI,MAAO;AACX,aAAO,KAAK,KAAK;AACjB,aAAO;AAAA,IACT;AAAA,IACA,MAAM;AACJ,cAAQ;AACR,aAAO;AAAA,IACT;AAAA,IACA,UAAU;AAAA,MACR,QAAQ,OAAO,aAAa,IAAI;AAC9B,YAAI,QAAQ;AACZ,eAAO,MAAM;AACX,cAAI,QAAQ,OAAO,QAAQ;AACzB,kBAAM,QAAQ,OAAO,KAAK;AAC1B,qBAAS;AACT,gBAAI,UAAU,OAAW,OAAM;AAC/B;AAAA,UACF;AACA,cAAI,MAAO;AACX,gBAAM,IAAI,QAAc,CAAC,YAAY;AACnC,mBAAO,MAAM;AACX,qBAAO;AACP,sBAAQ;AAAA,YACV;AACA,gBAAI,QAAQ,OAAO,UAAU,MAAO,MAAK;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/spoken.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { blankUsage } from "./blank-usage.js";
|
|
2
|
+
function createSpokenState() {
|
|
3
|
+
return { blocks: /* @__PURE__ */ new Map() };
|
|
4
|
+
}
|
|
5
|
+
function isCommentary(signature) {
|
|
6
|
+
if (!signature) return false;
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(signature);
|
|
9
|
+
return parsed?.phase === "commentary";
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function spokenPieces(event, state, options = {}) {
|
|
15
|
+
if (event.type === "tool_execution_start") return announceOf(event, options);
|
|
16
|
+
if (event.entry?.id !== void 0) state.entryId = String(event.entry.id);
|
|
17
|
+
if (event.type === "message_end") return messagePieces(event.entry?.model, state, options, true);
|
|
18
|
+
if (event.type === "message_start")
|
|
19
|
+
return messagePieces(assistantContent(event.message), state, options, true);
|
|
20
|
+
if (event.type === "message_update") return changePieces(event.changes ?? [], state, options);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
function announceOf(event, options) {
|
|
24
|
+
if (!options.announce || !event.toolName || !event.toolCallId) return [];
|
|
25
|
+
const text = options.announce({
|
|
26
|
+
type: "toolCall",
|
|
27
|
+
id: event.toolCallId,
|
|
28
|
+
name: event.toolName,
|
|
29
|
+
arguments: event.args ?? {}
|
|
30
|
+
});
|
|
31
|
+
if (!text) return [];
|
|
32
|
+
return [{ text, contentIndex: -1, start: 0, end: 0, kind: "announce" }];
|
|
33
|
+
}
|
|
34
|
+
function assistantContent(message) {
|
|
35
|
+
if (message?.role !== "assistant") return void 0;
|
|
36
|
+
return Array.isArray(message.content) ? message.content : void 0;
|
|
37
|
+
}
|
|
38
|
+
function messagePieces(model, state, options, close) {
|
|
39
|
+
const content = Array.isArray(model) ? blocksOf(model) : void 0;
|
|
40
|
+
if (!content) return [];
|
|
41
|
+
const pieces = [];
|
|
42
|
+
for (const [contentIndex, block] of content.entries()) {
|
|
43
|
+
const track = applyBlock(state, contentIndex, block);
|
|
44
|
+
const piece = takePiece(track, contentIndex, state, options, close);
|
|
45
|
+
if (piece) pieces.push(piece);
|
|
46
|
+
}
|
|
47
|
+
return pieces;
|
|
48
|
+
}
|
|
49
|
+
function blocksOf(model) {
|
|
50
|
+
const first = model[0];
|
|
51
|
+
if (!first) return void 0;
|
|
52
|
+
if ("role" in first) {
|
|
53
|
+
if (first.role !== "assistant" || !Array.isArray(first.content)) return void 0;
|
|
54
|
+
return first.content;
|
|
55
|
+
}
|
|
56
|
+
return model;
|
|
57
|
+
}
|
|
58
|
+
function changePieces(changes, state, options) {
|
|
59
|
+
const pieces = [];
|
|
60
|
+
for (const change of changes) pieces.push(...applyChange(change, state, options));
|
|
61
|
+
return pieces;
|
|
62
|
+
}
|
|
63
|
+
function applyChange(change, state, options) {
|
|
64
|
+
if (change.type === "message") {
|
|
65
|
+
return messagePieces(change.message ? [change.message] : void 0, state, options, false);
|
|
66
|
+
}
|
|
67
|
+
const contentIndex = change.contentIndex;
|
|
68
|
+
if (contentIndex === void 0) return [];
|
|
69
|
+
if (change.type === "thinking_start" || change.type === "thinking_delta") {
|
|
70
|
+
noteThinking(state, contentIndex, change);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
if (change.type === "toolcall_start" || change.type === "toolcall_delta") {
|
|
74
|
+
state.blocks.set(contentIndex, { kind: "tool", text: "", sent: 0, ended: true });
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
const track = textTrack(state, contentIndex);
|
|
78
|
+
if (change.type === "text_start" || change.type === "block") noteText(track, change.block);
|
|
79
|
+
if (change.type === "text_delta" && change.delta) track.text += change.delta;
|
|
80
|
+
const piece = change.type === "text_delta" && options.speakable ? customPiece(track, contentIndex, change.delta ?? "", state, options, "text_delta") : takePiece(track, contentIndex, state, options, false);
|
|
81
|
+
return piece ? [piece] : [];
|
|
82
|
+
}
|
|
83
|
+
function noteThinking(state, contentIndex, change) {
|
|
84
|
+
const existing = state.blocks.get(contentIndex);
|
|
85
|
+
const text = `${existing?.kind === "thinking" ? existing.text : ""}${change.delta ?? ""}`;
|
|
86
|
+
const started = change.block?.type === "thinking" ? change.block.thinking : text;
|
|
87
|
+
state.blocks.set(contentIndex, {
|
|
88
|
+
kind: "thinking",
|
|
89
|
+
text: change.type === "thinking_start" ? started : text,
|
|
90
|
+
sent: change.type === "thinking_start" ? started.length : text.length,
|
|
91
|
+
ended: true,
|
|
92
|
+
...change.block?.type === "thinking" && change.block.thinkingSignature ? { signature: change.block.thinkingSignature } : {}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function noteText(track, block) {
|
|
96
|
+
if (block?.type !== "text") return;
|
|
97
|
+
track.kind = "text";
|
|
98
|
+
track.text = block.text;
|
|
99
|
+
track.signature = block.textSignature;
|
|
100
|
+
}
|
|
101
|
+
function textTrack(state, contentIndex) {
|
|
102
|
+
const existing = state.blocks.get(contentIndex);
|
|
103
|
+
if (existing) return existing;
|
|
104
|
+
const created = { kind: "text", text: "", sent: 0, ended: false };
|
|
105
|
+
state.blocks.set(contentIndex, created);
|
|
106
|
+
return created;
|
|
107
|
+
}
|
|
108
|
+
function applyBlock(state, contentIndex, block) {
|
|
109
|
+
if (block.type === "thinking") {
|
|
110
|
+
const track2 = {
|
|
111
|
+
kind: "thinking",
|
|
112
|
+
text: block.thinking,
|
|
113
|
+
sent: block.thinking.length,
|
|
114
|
+
ended: true
|
|
115
|
+
};
|
|
116
|
+
state.blocks.set(contentIndex, track2);
|
|
117
|
+
return track2;
|
|
118
|
+
}
|
|
119
|
+
if (block.type === "toolCall") {
|
|
120
|
+
const track2 = { kind: "tool", text: "", sent: 0, ended: true };
|
|
121
|
+
state.blocks.set(contentIndex, track2);
|
|
122
|
+
return track2;
|
|
123
|
+
}
|
|
124
|
+
const existing = state.blocks.get(contentIndex);
|
|
125
|
+
const sent = existing?.kind === "text" ? existing.sent : 0;
|
|
126
|
+
let ended = false;
|
|
127
|
+
if (existing?.kind === "text") ended = existing.ended;
|
|
128
|
+
const track = {
|
|
129
|
+
kind: "text",
|
|
130
|
+
text: block.text,
|
|
131
|
+
sent,
|
|
132
|
+
ended,
|
|
133
|
+
...block.textSignature ? { signature: block.textSignature } : {}
|
|
134
|
+
};
|
|
135
|
+
state.blocks.set(contentIndex, track);
|
|
136
|
+
return track;
|
|
137
|
+
}
|
|
138
|
+
function takePiece(track, contentIndex, state, options, close) {
|
|
139
|
+
if (track.kind !== "text") return void 0;
|
|
140
|
+
if (options.speakable) {
|
|
141
|
+
if (!close || track.ended) return void 0;
|
|
142
|
+
track.ended = true;
|
|
143
|
+
return customPiece(track, contentIndex, track.text, state, options, "text_end");
|
|
144
|
+
}
|
|
145
|
+
if (isCommentary(track.signature)) {
|
|
146
|
+
track.sent = track.text.length;
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
149
|
+
if (track.sent >= track.text.length) return void 0;
|
|
150
|
+
const start = track.sent;
|
|
151
|
+
const text = track.text.slice(start);
|
|
152
|
+
track.sent = track.text.length;
|
|
153
|
+
if (!text) return void 0;
|
|
154
|
+
return { text, contentIndex, start, end: track.sent, kind: "answer", entryId: state.entryId };
|
|
155
|
+
}
|
|
156
|
+
function customPiece(track, contentIndex, delta, state, options, type) {
|
|
157
|
+
if (!options.speakable) return void 0;
|
|
158
|
+
const partial = partialFrom(state, options.model ?? "voice");
|
|
159
|
+
const event = type === "text_delta" ? { type: "text_delta", contentIndex, delta, partial } : { type: "text_end", contentIndex, content: track.text, partial };
|
|
160
|
+
const text = options.speakable(event);
|
|
161
|
+
const start = track.sent;
|
|
162
|
+
track.sent = track.text.length;
|
|
163
|
+
track.ended = type === "text_end";
|
|
164
|
+
if (!text) return void 0;
|
|
165
|
+
return { text, contentIndex, start, end: track.sent, kind: "answer", entryId: state.entryId };
|
|
166
|
+
}
|
|
167
|
+
function partialFrom(state, model) {
|
|
168
|
+
const max = Math.max(-1, ...state.blocks.keys());
|
|
169
|
+
const content = [];
|
|
170
|
+
for (let index = 0; index <= max; index += 1) content.push(partialBlock(state.blocks.get(index)));
|
|
171
|
+
return {
|
|
172
|
+
role: "assistant",
|
|
173
|
+
content,
|
|
174
|
+
api: "pi-audio",
|
|
175
|
+
provider: "pi-audio",
|
|
176
|
+
model,
|
|
177
|
+
usage: blankUsage(),
|
|
178
|
+
stopReason: "pending",
|
|
179
|
+
timestamp: 0
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function partialBlock(track) {
|
|
183
|
+
if (!track || track.kind === "thinking") return { type: "thinking", thinking: track?.text ?? "" };
|
|
184
|
+
if (track.kind === "tool")
|
|
185
|
+
return { type: "toolCall", id: "pending", name: "pending", arguments: {} };
|
|
186
|
+
return {
|
|
187
|
+
type: "text",
|
|
188
|
+
text: track.text,
|
|
189
|
+
...track.signature ? { textSignature: track.signature } : {}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
export {
|
|
193
|
+
createSpokenState,
|
|
194
|
+
isCommentary,
|
|
195
|
+
spokenPieces
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=spoken.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/spoken.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n AssistantMessage,\n AssistantMessageEvent,\n JsonObject,\n TextContent,\n ThinkingContent,\n ToolCall,\n} from '@earendil-works/pi-ai';\nimport { blankUsage } from './blank-usage.ts';\n\nexport interface VoiceMessageChange {\n type: string;\n contentIndex?: number;\n delta?: string;\n block?: TextContent | ThinkingContent | ToolCall;\n message?: AssistantMessage;\n}\n\nexport interface VoiceEntryRef {\n id: string | number;\n model?: readonly {\n role: string;\n content?: readonly (TextContent | ThinkingContent | ToolCall)[];\n }[];\n}\n\nexport interface VoiceAgentEvent {\n type: string;\n changes?: readonly VoiceMessageChange[];\n message?: { role: string; content?: unknown };\n entry?: VoiceEntryRef;\n toolName?: string;\n toolCallId?: string;\n args?: JsonObject;\n attempt?: number;\n at?: number;\n}\n\nexport interface SpokenPiece {\n text: string;\n contentIndex: number;\n start: number;\n end: number;\n kind: 'answer' | 'announce';\n entryId?: string;\n}\n\ninterface BlockTrack {\n kind: 'text' | 'thinking' | 'tool';\n text: string;\n sent: number;\n signature?: string;\n ended: boolean;\n}\n\nexport interface SpokenState {\n blocks: Map<number, BlockTrack>;\n entryId?: string;\n}\n\nexport interface SpokenOptions {\n speakable?(event: AssistantMessageEvent): string | undefined;\n announce?(call: ToolCall): string | undefined;\n model?: string;\n}\n\ntype Block = TextContent | ThinkingContent | ToolCall;\n\nexport function createSpokenState(): SpokenState {\n return { blocks: new Map() };\n}\n\nexport function isCommentary(signature: string | undefined): boolean {\n if (!signature) return false;\n try {\n const parsed = JSON.parse(signature) as { phase?: unknown } | null;\n return parsed?.phase === 'commentary';\n } catch {\n return false;\n }\n}\n\nexport function spokenPieces(\n event: VoiceAgentEvent,\n state: SpokenState,\n options: SpokenOptions = {}\n): SpokenPiece[] {\n if (event.type === 'tool_execution_start') return announceOf(event, options);\n if (event.entry?.id !== undefined) state.entryId = String(event.entry.id);\n if (event.type === 'message_end') return messagePieces(event.entry?.model, state, options, true);\n if (event.type === 'message_start')\n return messagePieces(assistantContent(event.message), state, options, true);\n if (event.type === 'message_update') return changePieces(event.changes ?? [], state, options);\n return [];\n}\n\nfunction announceOf(event: VoiceAgentEvent, options: SpokenOptions): SpokenPiece[] {\n if (!options.announce || !event.toolName || !event.toolCallId) return [];\n const text = options.announce({\n type: 'toolCall',\n id: event.toolCallId,\n name: event.toolName,\n arguments: event.args ?? {},\n });\n if (!text) return [];\n return [{ text, contentIndex: -1, start: 0, end: 0, kind: 'announce' }];\n}\n\nfunction assistantContent(message: VoiceAgentEvent['message']): readonly Block[] | undefined {\n if (message?.role !== 'assistant') return undefined;\n return Array.isArray(message.content) ? (message.content as readonly Block[]) : undefined;\n}\n\nfunction messagePieces(\n model: VoiceEntryRef['model'] | readonly Block[] | undefined,\n state: SpokenState,\n options: SpokenOptions,\n close: boolean\n): SpokenPiece[] {\n const content = Array.isArray(model) ? blocksOf(model) : undefined;\n if (!content) return [];\n const pieces: SpokenPiece[] = [];\n for (const [contentIndex, block] of content.entries()) {\n const track = applyBlock(state, contentIndex, block);\n const piece = takePiece(track, contentIndex, state, options, close);\n if (piece) pieces.push(piece);\n }\n return pieces;\n}\n\nfunction blocksOf(\n model: readonly Block[] | NonNullable<VoiceEntryRef['model']>\n): readonly Block[] | undefined {\n const first = model[0] as { role?: string; content?: unknown } | Block | undefined;\n if (!first) return undefined;\n if ('role' in first) {\n if (first.role !== 'assistant' || !Array.isArray(first.content)) return undefined;\n return first.content as readonly Block[];\n }\n return model as readonly Block[];\n}\n\nfunction changePieces(\n changes: readonly VoiceMessageChange[],\n state: SpokenState,\n options: SpokenOptions\n): SpokenPiece[] {\n const pieces: SpokenPiece[] = [];\n for (const change of changes) pieces.push(...applyChange(change, state, options));\n return pieces;\n}\n\nfunction applyChange(\n change: VoiceMessageChange,\n state: SpokenState,\n options: SpokenOptions\n): SpokenPiece[] {\n if (change.type === 'message') {\n return messagePieces(change.message ? [change.message] : undefined, state, options, false);\n }\n const contentIndex = change.contentIndex;\n if (contentIndex === undefined) return [];\n if (change.type === 'thinking_start' || change.type === 'thinking_delta') {\n noteThinking(state, contentIndex, change);\n return [];\n }\n if (change.type === 'toolcall_start' || change.type === 'toolcall_delta') {\n state.blocks.set(contentIndex, { kind: 'tool', text: '', sent: 0, ended: true });\n return [];\n }\n const track = textTrack(state, contentIndex);\n if (change.type === 'text_start' || change.type === 'block') noteText(track, change.block);\n if (change.type === 'text_delta' && change.delta) track.text += change.delta;\n const piece =\n change.type === 'text_delta' && options.speakable\n ? customPiece(track, contentIndex, change.delta ?? '', state, options, 'text_delta')\n : takePiece(track, contentIndex, state, options, false);\n return piece ? [piece] : [];\n}\n\nfunction noteThinking(state: SpokenState, contentIndex: number, change: VoiceMessageChange): void {\n const existing = state.blocks.get(contentIndex);\n const text = `${existing?.kind === 'thinking' ? existing.text : ''}${change.delta ?? ''}`;\n const started = change.block?.type === 'thinking' ? change.block.thinking : text;\n state.blocks.set(contentIndex, {\n kind: 'thinking',\n text: change.type === 'thinking_start' ? started : text,\n sent: change.type === 'thinking_start' ? started.length : text.length,\n ended: true,\n ...(change.block?.type === 'thinking' && change.block.thinkingSignature\n ? { signature: change.block.thinkingSignature }\n : {}),\n });\n}\n\nfunction noteText(track: BlockTrack, block: VoiceMessageChange['block']): void {\n if (block?.type !== 'text') return;\n track.kind = 'text';\n track.text = block.text;\n track.signature = block.textSignature;\n}\n\nfunction textTrack(state: SpokenState, contentIndex: number): BlockTrack {\n const existing = state.blocks.get(contentIndex);\n if (existing) return existing;\n const created: BlockTrack = { kind: 'text', text: '', sent: 0, ended: false };\n state.blocks.set(contentIndex, created);\n return created;\n}\n\nfunction applyBlock(state: SpokenState, contentIndex: number, block: Block): BlockTrack {\n if (block.type === 'thinking') {\n const track: BlockTrack = {\n kind: 'thinking',\n text: block.thinking,\n sent: block.thinking.length,\n ended: true,\n };\n state.blocks.set(contentIndex, track);\n return track;\n }\n if (block.type === 'toolCall') {\n const track: BlockTrack = { kind: 'tool', text: '', sent: 0, ended: true };\n state.blocks.set(contentIndex, track);\n return track;\n }\n const existing = state.blocks.get(contentIndex);\n const sent = existing?.kind === 'text' ? existing.sent : 0;\n let ended = false;\n if (existing?.kind === 'text') ended = existing.ended;\n const track: BlockTrack = {\n kind: 'text',\n text: block.text,\n sent,\n ended,\n ...(block.textSignature ? { signature: block.textSignature } : {}),\n };\n state.blocks.set(contentIndex, track);\n return track;\n}\n\nfunction takePiece(\n track: BlockTrack,\n contentIndex: number,\n state: SpokenState,\n options: SpokenOptions,\n close: boolean\n): SpokenPiece | undefined {\n if (track.kind !== 'text') return undefined;\n if (options.speakable) {\n if (!close || track.ended) return undefined;\n track.ended = true;\n return customPiece(track, contentIndex, track.text, state, options, 'text_end');\n }\n if (isCommentary(track.signature)) {\n track.sent = track.text.length;\n return undefined;\n }\n if (track.sent >= track.text.length) return undefined;\n const start = track.sent;\n const text = track.text.slice(start);\n track.sent = track.text.length;\n if (!text) return undefined;\n return { text, contentIndex, start, end: track.sent, kind: 'answer', entryId: state.entryId };\n}\n\nfunction customPiece(\n track: BlockTrack,\n contentIndex: number,\n delta: string,\n state: SpokenState,\n options: SpokenOptions,\n type: 'text_delta' | 'text_end'\n): SpokenPiece | undefined {\n if (!options.speakable) return undefined;\n const partial = partialFrom(state, options.model ?? 'voice');\n const event: AssistantMessageEvent =\n type === 'text_delta'\n ? { type: 'text_delta', contentIndex, delta, partial }\n : { type: 'text_end', contentIndex, content: track.text, partial };\n const text = options.speakable(event);\n const start = track.sent;\n track.sent = track.text.length;\n track.ended = type === 'text_end';\n if (!text) return undefined;\n return { text, contentIndex, start, end: track.sent, kind: 'answer', entryId: state.entryId };\n}\n\nfunction partialFrom(state: SpokenState, model: string): AssistantMessage {\n const max = Math.max(-1, ...state.blocks.keys());\n const content: Block[] = [];\n for (let index = 0; index <= max; index += 1) content.push(partialBlock(state.blocks.get(index)));\n return {\n role: 'assistant',\n content,\n api: 'pi-audio',\n provider: 'pi-audio',\n model,\n usage: blankUsage(),\n stopReason: 'pending',\n timestamp: 0,\n };\n}\n\nfunction partialBlock(track: BlockTrack | undefined): Block {\n if (!track || track.kind === 'thinking') return { type: 'thinking', thinking: track?.text ?? '' };\n if (track.kind === 'tool')\n return { type: 'toolCall', id: 'pending', name: 'pending', arguments: {} };\n return {\n type: 'text',\n text: track.text,\n ...(track.signature ? { textSignature: track.signature } : {}),\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["track"]
|
|
7
|
+
}
|