@moureau/pipeflow 0.0.1
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 +833 -0
- package/dist/cjs/agents/agent.js +2 -0
- package/dist/cjs/agents/agent.js.map +7 -0
- package/dist/cjs/agents/index.js +2 -0
- package/dist/cjs/agents/index.js.map +7 -0
- package/dist/cjs/agents/tools/index.js +2 -0
- package/dist/cjs/agents/tools/index.js.map +7 -0
- package/dist/cjs/agents/tools/tools.js +2 -0
- package/dist/cjs/agents/tools/tools.js.map +7 -0
- package/dist/cjs/conversations/conversation/conversation.js +2 -0
- package/dist/cjs/conversations/conversation/conversation.js.map +7 -0
- package/dist/cjs/conversations/conversation/index.js +2 -0
- package/dist/cjs/conversations/conversation/index.js.map +7 -0
- package/dist/cjs/conversations/conversations.js +2 -0
- package/dist/cjs/conversations/conversations.js.map +7 -0
- package/dist/cjs/conversations/index.js +2 -0
- package/dist/cjs/conversations/index.js.map +7 -0
- package/dist/cjs/conversations/orchestration/orchestrator/index.js +2 -0
- package/dist/cjs/conversations/orchestration/orchestrator/index.js.map +7 -0
- package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js +3 -0
- package/dist/cjs/conversations/orchestration/orchestrator/orchestrator.js.map +7 -0
- package/dist/cjs/conversations/transcription/index.js +2 -0
- package/dist/cjs/conversations/transcription/index.js.map +7 -0
- package/dist/cjs/conversations/transcription/transcription.js +2 -0
- package/dist/cjs/conversations/transcription/transcription.js.map +7 -0
- package/dist/cjs/conversations/types.js +2 -0
- package/dist/cjs/conversations/types.js.map +7 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/persistence/adapters/index.js +2 -0
- package/dist/cjs/persistence/adapters/index.js.map +7 -0
- package/dist/cjs/persistence/adapters/memory/index.js +2 -0
- package/dist/cjs/persistence/adapters/memory/index.js.map +7 -0
- package/dist/cjs/persistence/adapters/memory/memory.js +2 -0
- package/dist/cjs/persistence/adapters/memory/memory.js.map +7 -0
- package/dist/cjs/persistence/adapters/sqlite/index.js +2 -0
- package/dist/cjs/persistence/adapters/sqlite/index.js.map +7 -0
- package/dist/cjs/persistence/adapters/sqlite/sqlite.js +58 -0
- package/dist/cjs/persistence/adapters/sqlite/sqlite.js.map +7 -0
- package/dist/cjs/persistence/index.js +2 -0
- package/dist/cjs/persistence/index.js.map +7 -0
- package/dist/cjs/persistence/persistence.js +2 -0
- package/dist/cjs/persistence/persistence.js.map +7 -0
- package/dist/cjs/providers/index.js +2 -0
- package/dist/cjs/providers/index.js.map +7 -0
- package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js +2 -0
- package/dist/cjs/providers/llm/adapters/deepseek/deepseek.js.map +7 -0
- package/dist/cjs/providers/llm/adapters/deepseek/index.js +2 -0
- package/dist/cjs/providers/llm/adapters/deepseek/index.js.map +7 -0
- package/dist/cjs/providers/llm/adapters/index.js +2 -0
- package/dist/cjs/providers/llm/adapters/index.js.map +7 -0
- package/dist/cjs/providers/llm/index.js +2 -0
- package/dist/cjs/providers/llm/index.js.map +7 -0
- package/dist/cjs/providers/llm/types.js +2 -0
- package/dist/cjs/providers/llm/types.js.map +7 -0
- package/dist/cjs/providers/shared.js +2 -0
- package/dist/cjs/providers/shared.js.map +7 -0
- package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js +2 -0
- package/dist/cjs/providers/stt/adapters/deepgram/deepgram.js.map +7 -0
- package/dist/cjs/providers/stt/adapters/deepgram/index.js +2 -0
- package/dist/cjs/providers/stt/adapters/deepgram/index.js.map +7 -0
- package/dist/cjs/providers/stt/adapters/index.js +2 -0
- package/dist/cjs/providers/stt/adapters/index.js.map +7 -0
- package/dist/cjs/providers/stt/index.js +2 -0
- package/dist/cjs/providers/stt/index.js.map +7 -0
- package/dist/cjs/providers/stt/types.js +2 -0
- package/dist/cjs/providers/stt/types.js.map +7 -0
- package/dist/cjs/providers/tts/adapters/index.js +2 -0
- package/dist/cjs/providers/tts/adapters/index.js.map +7 -0
- package/dist/cjs/providers/tts/adapters/kokoro/index.js +2 -0
- package/dist/cjs/providers/tts/adapters/kokoro/index.js.map +7 -0
- package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js +2 -0
- package/dist/cjs/providers/tts/adapters/kokoro/kokoro.js.map +7 -0
- package/dist/cjs/providers/tts/index.js +2 -0
- package/dist/cjs/providers/tts/index.js.map +7 -0
- package/dist/cjs/providers/tts/types.js +2 -0
- package/dist/cjs/providers/tts/types.js.map +7 -0
- package/dist/cjs/transport/adapters/index.js +2 -0
- package/dist/cjs/transport/adapters/index.js.map +7 -0
- package/dist/cjs/transport/adapters/memory/index.js +2 -0
- package/dist/cjs/transport/adapters/memory/index.js.map +7 -0
- package/dist/cjs/transport/adapters/memory/memory.js +2 -0
- package/dist/cjs/transport/adapters/memory/memory.js.map +7 -0
- package/dist/cjs/transport/index.js +2 -0
- package/dist/cjs/transport/index.js.map +7 -0
- package/dist/cjs/transport/types.js +2 -0
- package/dist/cjs/transport/types.js.map +7 -0
- package/dist/esm/agents/agent.js +2 -0
- package/dist/esm/agents/agent.js.map +7 -0
- package/dist/esm/agents/index.js +2 -0
- package/dist/esm/agents/index.js.map +7 -0
- package/dist/esm/agents/tools/index.js +2 -0
- package/dist/esm/agents/tools/index.js.map +7 -0
- package/dist/esm/agents/tools/tools.js +2 -0
- package/dist/esm/agents/tools/tools.js.map +7 -0
- package/dist/esm/conversations/conversation/conversation.js +2 -0
- package/dist/esm/conversations/conversation/conversation.js.map +7 -0
- package/dist/esm/conversations/conversation/index.js +2 -0
- package/dist/esm/conversations/conversation/index.js.map +7 -0
- package/dist/esm/conversations/conversations.js +2 -0
- package/dist/esm/conversations/conversations.js.map +7 -0
- package/dist/esm/conversations/index.js +2 -0
- package/dist/esm/conversations/index.js.map +7 -0
- package/dist/esm/conversations/orchestration/orchestrator/index.js +2 -0
- package/dist/esm/conversations/orchestration/orchestrator/index.js.map +7 -0
- package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js +3 -0
- package/dist/esm/conversations/orchestration/orchestrator/orchestrator.js.map +7 -0
- package/dist/esm/conversations/transcription/index.js +2 -0
- package/dist/esm/conversations/transcription/index.js.map +7 -0
- package/dist/esm/conversations/transcription/transcription.js +2 -0
- package/dist/esm/conversations/transcription/transcription.js.map +7 -0
- package/dist/esm/conversations/types.js +2 -0
- package/dist/esm/conversations/types.js.map +7 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/persistence/adapters/index.js +2 -0
- package/dist/esm/persistence/adapters/index.js.map +7 -0
- package/dist/esm/persistence/adapters/memory/index.js +2 -0
- package/dist/esm/persistence/adapters/memory/index.js.map +7 -0
- package/dist/esm/persistence/adapters/memory/memory.js +2 -0
- package/dist/esm/persistence/adapters/memory/memory.js.map +7 -0
- package/dist/esm/persistence/adapters/sqlite/index.js +2 -0
- package/dist/esm/persistence/adapters/sqlite/index.js.map +7 -0
- package/dist/esm/persistence/adapters/sqlite/sqlite.js +58 -0
- package/dist/esm/persistence/adapters/sqlite/sqlite.js.map +7 -0
- package/dist/esm/persistence/index.js +2 -0
- package/dist/esm/persistence/index.js.map +7 -0
- package/dist/esm/persistence/persistence.js +1 -0
- package/dist/esm/persistence/persistence.js.map +7 -0
- package/dist/esm/providers/index.js +2 -0
- package/dist/esm/providers/index.js.map +7 -0
- package/dist/esm/providers/llm/adapters/deepseek/deepseek.js +2 -0
- package/dist/esm/providers/llm/adapters/deepseek/deepseek.js.map +7 -0
- package/dist/esm/providers/llm/adapters/deepseek/index.js +2 -0
- package/dist/esm/providers/llm/adapters/deepseek/index.js.map +7 -0
- package/dist/esm/providers/llm/adapters/index.js +2 -0
- package/dist/esm/providers/llm/adapters/index.js.map +7 -0
- package/dist/esm/providers/llm/index.js +2 -0
- package/dist/esm/providers/llm/index.js.map +7 -0
- package/dist/esm/providers/llm/types.js +1 -0
- package/dist/esm/providers/llm/types.js.map +7 -0
- package/dist/esm/providers/shared.js +1 -0
- package/dist/esm/providers/shared.js.map +7 -0
- package/dist/esm/providers/stt/adapters/deepgram/deepgram.js +2 -0
- package/dist/esm/providers/stt/adapters/deepgram/deepgram.js.map +7 -0
- package/dist/esm/providers/stt/adapters/deepgram/index.js +2 -0
- package/dist/esm/providers/stt/adapters/deepgram/index.js.map +7 -0
- package/dist/esm/providers/stt/adapters/index.js +2 -0
- package/dist/esm/providers/stt/adapters/index.js.map +7 -0
- package/dist/esm/providers/stt/index.js +2 -0
- package/dist/esm/providers/stt/index.js.map +7 -0
- package/dist/esm/providers/stt/types.js +1 -0
- package/dist/esm/providers/stt/types.js.map +7 -0
- package/dist/esm/providers/tts/adapters/index.js +2 -0
- package/dist/esm/providers/tts/adapters/index.js.map +7 -0
- package/dist/esm/providers/tts/adapters/kokoro/index.js +2 -0
- package/dist/esm/providers/tts/adapters/kokoro/index.js.map +7 -0
- package/dist/esm/providers/tts/adapters/kokoro/kokoro.js +2 -0
- package/dist/esm/providers/tts/adapters/kokoro/kokoro.js.map +7 -0
- package/dist/esm/providers/tts/index.js +2 -0
- package/dist/esm/providers/tts/index.js.map +7 -0
- package/dist/esm/providers/tts/types.js +1 -0
- package/dist/esm/providers/tts/types.js.map +7 -0
- package/dist/esm/transport/adapters/index.js +2 -0
- package/dist/esm/transport/adapters/index.js.map +7 -0
- package/dist/esm/transport/adapters/memory/index.js +2 -0
- package/dist/esm/transport/adapters/memory/index.js.map +7 -0
- package/dist/esm/transport/adapters/memory/memory.js +2 -0
- package/dist/esm/transport/adapters/memory/memory.js.map +7 -0
- package/dist/esm/transport/index.js +2 -0
- package/dist/esm/transport/index.js.map +7 -0
- package/dist/esm/transport/types.js +1 -0
- package/dist/esm/transport/types.js.map +7 -0
- package/dist/types/agents/agent.d.ts +60 -0
- package/dist/types/agents/index.d.ts +4 -0
- package/dist/types/agents/tools/index.d.ts +2 -0
- package/dist/types/agents/tools/tools.d.ts +22 -0
- package/dist/types/conversations/conversation/conversation.d.ts +138 -0
- package/dist/types/conversations/conversation/index.d.ts +2 -0
- package/dist/types/conversations/conversations.d.ts +23 -0
- package/dist/types/conversations/index.d.ts +10 -0
- package/dist/types/conversations/orchestration/orchestrator/index.d.ts +2 -0
- package/dist/types/conversations/orchestration/orchestrator/orchestrator.d.ts +98 -0
- package/dist/types/conversations/transcription/index.d.ts +2 -0
- package/dist/types/conversations/transcription/transcription.d.ts +59 -0
- package/dist/types/conversations/types.d.ts +63 -0
- package/dist/types/index.d.ts +45 -0
- package/dist/types/persistence/adapters/index.d.ts +2 -0
- package/dist/types/persistence/adapters/memory/index.d.ts +1 -0
- package/dist/types/persistence/adapters/memory/memory.d.ts +27 -0
- package/dist/types/persistence/adapters/sqlite/index.d.ts +2 -0
- package/dist/types/persistence/adapters/sqlite/sqlite.d.ts +31 -0
- package/dist/types/persistence/index.d.ts +2 -0
- package/dist/types/persistence/persistence.d.ts +38 -0
- package/dist/types/providers/index.d.ts +6 -0
- package/dist/types/providers/llm/adapters/deepseek/deepseek.d.ts +24 -0
- package/dist/types/providers/llm/adapters/deepseek/index.d.ts +2 -0
- package/dist/types/providers/llm/adapters/index.d.ts +1 -0
- package/dist/types/providers/llm/index.d.ts +10 -0
- package/dist/types/providers/llm/types.d.ts +55 -0
- package/dist/types/providers/shared.d.ts +8 -0
- package/dist/types/providers/stt/adapters/deepgram/deepgram.d.ts +57 -0
- package/dist/types/providers/stt/adapters/deepgram/index.d.ts +2 -0
- package/dist/types/providers/stt/adapters/index.d.ts +1 -0
- package/dist/types/providers/stt/index.d.ts +2 -0
- package/dist/types/providers/stt/types.d.ts +30 -0
- package/dist/types/providers/tts/adapters/index.d.ts +1 -0
- package/dist/types/providers/tts/adapters/kokoro/index.d.ts +2 -0
- package/dist/types/providers/tts/adapters/kokoro/kokoro.d.ts +34 -0
- package/dist/types/providers/tts/index.d.ts +2 -0
- package/dist/types/providers/tts/types.d.ts +16 -0
- package/dist/types/transport/adapters/index.d.ts +1 -0
- package/dist/types/transport/adapters/memory/index.d.ts +1 -0
- package/dist/types/transport/adapters/memory/memory.d.ts +20 -0
- package/dist/types/transport/index.d.ts +2 -0
- package/dist/types/transport/types.d.ts +49 -0
- package/package.json +82 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/conversations/conversation/conversation.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Agent } from \"../../agents/agent\";\nimport type { Persistence } from \"../../persistence/persistence\";\nimport type {\n AudioChunk,\n ConversationId,\n ConversationState,\n ConversationStatus,\n Generation,\n Participant,\n ParticipantInput,\n Turn,\n UserId,\n} from \"../types\";\nimport { createConversationState } from \"../types\";\nimport {\n Transcription,\n type TranscriptEntry,\n type TranscriptEntryInput,\n} from \"../transcription/transcription\";\nimport type { ToolCall, ToolCallResult } from \"../types\";\n\nexport interface ConversationOptions {\n id: ConversationId;\n agents?: Agent[];\n persistence?: Persistence;\n}\n\nexport interface ConversationEvents {\n start: { conversationId: ConversationId };\n stop: { conversationId: ConversationId };\n participant: { conversationId: ConversationId; participant: Participant };\n /** Raw audio fed in via `listen()`. Consumed by the orchestrator. */\n \"audio-in\": { conversationId: ConversationId; userId: UserId; audio: AudioChunk };\n /** Generated audio to be played by the application. */\n audio: { conversationId: ConversationId; audio: AudioChunk };\n turn: { conversationId: ConversationId; turn: Turn };\n transcript: { conversationId: ConversationId; entry: TranscriptEntry };\n generation: { conversationId: ConversationId; generation: Generation };\n /** Live STT partials, for captions and fast UX. Not persisted. */\n \"partial-transcript\": {\n conversationId: ConversationId;\n userId: UserId;\n text: string;\n };\n /** The model requested a tool call. Resolve it with `resolveToolCall()`. */\n \"tool-call\": { conversationId: ConversationId; call: ToolCall };\n /** A pending tool call was resolved by the application. */\n \"tool-call-result\": { conversationId: ConversationId; result: ToolCallResult };\n interrupt: { conversationId: ConversationId };\n /** A provider failure (STT, LLM, or TTS). */\n error: { conversationId: ConversationId; error: Error };\n state: { conversationId: ConversationId; state: ConversationState };\n}\n\n/**\n * The public realtime conversation API.\n *\n * A `Conversation` is a runtime handle to a persistent conversation:\n * lifecycle (`start`/`stop`), participants, audio intake (`listen`), and\n * events. The orchestrator (added later) subscribes to `audio-in` and\n * pushes generated audio, turns, transcripts, and tool calls back through\n * the `push*`/`requestToolCall` methods.\n */\nexport class Conversation {\n readonly id: ConversationId;\n readonly agents: readonly Agent[];\n readonly transcription: Transcription;\n readonly state: ConversationState;\n private readonly persistence: Persistence | undefined;\n private readonly listeners = new Map<\n keyof ConversationEvents,\n Set<(payload: never) => void>\n >();\n private readonly pendingToolCallsById = new Map<string, ToolCall>();\n private nextAudioSequence = 0;\n\n constructor(options: ConversationOptions) {\n this.id = options.id;\n this.agents = options.agents ?? [];\n this.persistence = options.persistence;\n this.transcription = new Transcription(this.id);\n this.state = createConversationState();\n }\n\n get status(): ConversationStatus {\n return this.state.status;\n }\n\n get participants(): Participant[] {\n return [...this.state.participants.values()];\n }\n\n start(): void {\n if (this.state.status === \"stopped\") {\n throw new Error(`Conversation \"${this.id}\" has already been stopped`);\n }\n if (this.state.status === \"started\") return;\n this.state.status = \"started\";\n this.emit(\"start\", { conversationId: this.id });\n this.emitState();\n }\n\n async stop(): Promise<void> {\n if (this.state.status === \"stopped\") return;\n this.state.status = \"stopped\";\n this.pendingToolCallsById.clear();\n const cancelled = this.cancelCurrentGeneration();\n if (cancelled) {\n await this.persistence?.appendGeneration(this.id, cancelled);\n }\n await this.persistence?.finalizeConversation(this.id, Date.now());\n this.emit(\"stop\", { conversationId: this.id });\n this.emitState();\n }\n\n async participate(\n input: ParticipantInput | ParticipantInput[],\n ): Promise<Participant[]> {\n if (this.state.status === \"stopped\") {\n throw new Error(`Conversation \"${this.id}\" has already been stopped`);\n }\n\n const inputs = Array.isArray(input) ? input : [input];\n\n // Validate the whole batch before mutating any state.\n const seen = new Set<UserId>();\n for (const item of inputs) {\n if (seen.has(item.userId)) {\n throw new Error(`Duplicate participant \"${item.userId}\" in batch`);\n }\n seen.add(item.userId);\n if (this.state.participants.has(item.userId)) {\n throw new Error(`Participant \"${item.userId}\" already exists`);\n }\n }\n\n const added: Participant[] = [];\n for (const item of inputs) {\n const participant: Participant = {\n userId: item.userId,\n aliases: [...(item.aliases ?? [])],\n joinedAt: Date.now(),\n };\n this.state.participants.set(participant.userId, participant);\n await this.persistence?.addParticipant(this.id, participant);\n added.push(participant);\n this.emit(\"participant\", { conversationId: this.id, participant });\n }\n this.emitState();\n return added;\n }\n\n /**\n * Send an audio packet. Intentionally synchronous: it means \"send this\n * packet\", not \"wait for this utterance to finish\".\n */\n listen(input: { userId: UserId; audio: Uint8Array }): void {\n if (this.state.status !== \"started\") {\n throw new Error(`Conversation \"${this.id}\" is not started`);\n }\n if (!this.state.participants.has(input.userId)) {\n throw new Error(`Unknown participant \"${input.userId}\"`);\n }\n const chunk: AudioChunk = {\n data: input.audio,\n timestamp: Date.now(),\n sequence: this.nextAudioSequence++,\n };\n this.emit(\"audio-in\", { conversationId: this.id, userId: input.userId, audio: chunk });\n }\n\n /** Interrupt the current agent output (stop TTS, cancel the generation). */\n interrupt(): void {\n const cancelled = this.cancelCurrentGeneration();\n // Persist asynchronously: interruption must stay synchronous for the\n // realtime path.\n if (cancelled) {\n void this.persistence?.appendGeneration(this.id, cancelled).catch(() => {});\n }\n this.emit(\"interrupt\", { conversationId: this.id });\n this.emitState();\n }\n\n on<K extends keyof ConversationEvents>(\n event: K,\n listener: (payload: ConversationEvents[K]) => void,\n ): () => void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(listener as (payload: never) => void);\n return () => {\n set!.delete(listener as (payload: never) => void);\n };\n }\n\n /**\n * Emit an event. Primarily used by the orchestrator to push output\n * (audio, turns, transcripts) into the conversation.\n */\n emit<K extends keyof ConversationEvents>(\n event: K,\n payload: ConversationEvents[K],\n ): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const listener of [...set]) {\n listener(payload as never);\n }\n }\n\n // -------------------------------------------------------------------------\n // Orchestrator-facing output\n // -------------------------------------------------------------------------\n\n /** Push a chunk of generated audio to the application. */\n pushAudio(audio: AudioChunk): void {\n this.emit(\"audio\", { conversationId: this.id, audio });\n }\n\n /** Push a completed participant turn into the conversation. */\n async pushTurn(turn: Turn): Promise<void> {\n this.state.currentTurn = turn;\n this.emit(\"turn\", { conversationId: this.id, turn });\n await this.persistence?.appendTurn(this.id, turn);\n this.emitState();\n }\n\n /** Append a transcript entry and notify listeners. */\n async pushTranscript(\n input: Omit<TranscriptEntryInput, \"conversationId\">,\n ): Promise<TranscriptEntry> {\n const entry = this.transcription.append({ ...input });\n this.state.transcriptCount++;\n this.emit(\"transcript\", { conversationId: this.id, entry });\n await this.persistence?.appendTranscript(this.id, entry);\n this.emitState();\n return entry;\n }\n\n /** Push an agent generation into the conversation. */\n async pushGeneration(generation: Generation): Promise<void> {\n this.state.currentGeneration = generation;\n this.emit(\"generation\", { conversationId: this.id, generation });\n await this.persistence?.appendGeneration(this.id, generation);\n this.emitState();\n }\n\n // -------------------------------------------------------------------------\n // Orchestrator-facing tool calls\n // -------------------------------------------------------------------------\n\n /** Tool calls requested by the model that are awaiting resolution. */\n get pendingToolCalls(): ToolCall[] {\n return [...this.pendingToolCallsById.values()];\n }\n\n /**\n * Track and emit a tool call requested by the model. The application\n * listens for `tool-call` events, executes the tool in its own backend,\n * and reports back through `resolveToolCall()`.\n */\n requestToolCall(call: ToolCall): void {\n this.pendingToolCallsById.set(call.id, call);\n this.emit(\"tool-call\", { conversationId: this.id, call });\n this.emitState();\n }\n\n /** Resolve a pending tool call with a result or an error. */\n resolveToolCall(result: ToolCallResult): void {\n if (!this.pendingToolCallsById.has(result.id)) {\n throw new Error(`No pending tool call \"${result.id}\"`);\n }\n this.pendingToolCallsById.delete(result.id);\n this.emit(\"tool-call-result\", { conversationId: this.id, result });\n this.emitState();\n }\n\n /** Mark the current generation as completed, recording its final text. */\n async completeGeneration(text?: string): Promise<void> {\n const generation = this.state.currentGeneration;\n if (generation && generation.status === \"streaming\") {\n if (text !== undefined) generation.text = text;\n generation.status = \"completed\";\n generation.endedAt = Date.now();\n await this.persistence?.appendGeneration(this.id, generation);\n this.emitState();\n }\n }\n\n /** The live in-memory transcript. */\n transcript(): TranscriptEntry[] {\n return this.transcription.list();\n }\n\n private cancelCurrentGeneration(): Generation | null {\n const generation = this.state.currentGeneration;\n if (generation && generation.status === \"streaming\") {\n generation.status = \"cancelled\";\n generation.endedAt = Date.now();\n }\n this.state.currentGeneration = null;\n return generation ?? null;\n }\n\n private emitState(): void {\n this.emit(\"state\", { conversationId: this.id, state: this.state });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createConversationState", "Transcription", "Conversation", "__name", "options", "cancelled", "input", "inputs", "seen", "item", "added", "participant", "chunk", "event", "listener", "set", "payload", "audio", "turn", "entry", "generation", "call", "result", "text"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/conversations/conversation/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { Conversation } from \"./conversation\";\nexport type {\n ConversationEvents,\n ConversationOptions,\n} from \"./conversation\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,gBAAAA,MAAoB",
|
|
6
|
+
"names": ["Conversation"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var o=Object.defineProperty;var n=(r,e)=>o(r,"name",{value:e,configurable:!0});import{Conversation as s}from"./conversation/conversation.js";class p{constructor(e){this.persistence=e}persistence;static{n(this,"Conversations")}async create(e={}){const t=await this.persistence.createConversation({agentNames:(e.agents??[]).map(i=>i.name)});return new s({id:t.id,agents:e.agents,persistence:this.persistence})}async transcript(e){return await this.requireConversation(e),this.persistence.listTranscript(e)}async get(e){const t=await this.persistence.getConversation(e);return t?new s({id:t.id,persistence:this.persistence}):null}async requireConversation(e){if(!await this.persistence.getConversation(e))throw new Error(`Conversation "${e}" not found`)}}export{p as Conversations};
|
|
2
|
+
//# sourceMappingURL=conversations.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/conversations/conversations.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Agent } from \"../agents/agent\";\nimport type { Persistence } from \"../persistence/persistence\";\nimport type { ConversationId } from \"./types\";\nimport type { TranscriptEntry } from \"./transcription/transcription\";\nimport { Conversation } from \"./conversation/conversation\";\n\nexport interface CreateConversationOptions {\n agents?: Agent[];\n}\n\n/**\n * The conversations API surface of a Pipeflow instance: create persistent\n * conversations and retrieve their transcripts.\n */\nexport class Conversations {\n constructor(private readonly persistence: Persistence) {}\n\n /** Create a persistent conversation. Realtime execution is separate. */\n async create(options: CreateConversationOptions = {}): Promise<Conversation> {\n const record = await this.persistence.createConversation({\n agentNames: (options.agents ?? []).map((agent) => agent.name),\n });\n return new Conversation({\n id: record.id,\n agents: options.agents,\n persistence: this.persistence,\n });\n }\n\n /** Retrieve the persisted transcript of a conversation. */\n async transcript(id: ConversationId): Promise<TranscriptEntry[]> {\n await this.requireConversation(id);\n return this.persistence.listTranscript(id);\n }\n\n /** Rehydrate a runtime handle for an existing conversation. */\n async get(id: ConversationId): Promise<Conversation | null> {\n const record = await this.persistence.getConversation(id);\n if (!record) return null;\n return new Conversation({ id: record.id, persistence: this.persistence });\n }\n\n private async requireConversation(id: ConversationId): Promise<void> {\n const record = await this.persistence.getConversation(id);\n if (!record) {\n throw new Error(`Conversation \"${id}\" not found`);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "+EAIA,OAAS,gBAAAA,MAAoB,8BAUtB,MAAMC,CAAc,CACzB,YAA6BC,EAA0B,CAA1B,iBAAAA,CAA2B,CAA3B,YAf/B,MAc2B,CAAAC,EAAA,sBAIzB,MAAM,OAAOC,EAAqC,CAAC,EAA0B,CAC3E,MAAMC,EAAS,MAAM,KAAK,YAAY,mBAAmB,CACvD,YAAaD,EAAQ,QAAU,CAAC,GAAG,IAAKE,GAAUA,EAAM,IAAI,CAC9D,CAAC,EACD,OAAO,IAAIN,EAAa,CACtB,GAAIK,EAAO,GACX,OAAQD,EAAQ,OAChB,YAAa,KAAK,WACpB,CAAC,CACH,CAGA,MAAM,WAAWG,EAAgD,CAC/D,aAAM,KAAK,oBAAoBA,CAAE,EAC1B,KAAK,YAAY,eAAeA,CAAE,CAC3C,CAGA,MAAM,IAAIA,EAAkD,CAC1D,MAAMF,EAAS,MAAM,KAAK,YAAY,gBAAgBE,CAAE,EACxD,OAAKF,EACE,IAAIL,EAAa,CAAE,GAAIK,EAAO,GAAI,YAAa,KAAK,WAAY,CAAC,EADpD,IAEtB,CAEA,MAAc,oBAAoBE,EAAmC,CAEnE,GAAI,CADW,MAAM,KAAK,YAAY,gBAAgBA,CAAE,EAEtD,MAAM,IAAI,MAAM,iBAAiBA,CAAE,aAAa,CAEpD,CACF",
|
|
6
|
+
"names": ["Conversation", "Conversations", "persistence", "__name", "options", "record", "agent", "id"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createConversationState as o}from"./types.js";import{Conversation as e}from"./conversation/index.js";import{Conversations as i}from"./conversations.js";import{Orchestrator as p}from"./orchestration/orchestrator/index.js";import{Transcription as x,TranscriptEntry as C}from"./transcription/index.js";export{e as Conversation,i as Conversations,p as Orchestrator,C as TranscriptEntry,x as Transcription,o as createConversationState};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/conversations/index.ts"],
|
|
4
|
+
"sourcesContent": ["export type {\n AudioChunk,\n ConversationId,\n ConversationState,\n ConversationStatus,\n Generation,\n GenerationStatus,\n Participant,\n ParticipantInput,\n ToolCall,\n ToolCallResult,\n Turn,\n TurnId,\n UserId,\n} from \"./types\";\nexport { createConversationState } from \"./types\";\nexport { Conversation } from \"./conversation/index\";\nexport type {\n ConversationEvents,\n ConversationOptions,\n} from \"./conversation/index\";\nexport { Conversations } from \"./conversations\";\nexport type { CreateConversationOptions } from \"./conversations\";\nexport { Orchestrator } from \"./orchestration/orchestrator/index\";\nexport type { OrchestratorOptions } from \"./orchestration/orchestrator/index\";\nexport { Transcription, TranscriptEntry } from \"./transcription/index\";\nexport type {\n TranscriptEntryInput,\n TranscriptSpeakerKind,\n} from \"./transcription/index\";\n"],
|
|
5
|
+
"mappings": "AAeA,OAAS,2BAAAA,MAA+B,UACxC,OAAS,gBAAAC,MAAoB,uBAK7B,OAAS,iBAAAC,MAAqB,kBAE9B,OAAS,gBAAAC,MAAoB,qCAE7B,OAAS,iBAAAC,EAAe,mBAAAC,MAAuB",
|
|
6
|
+
"names": ["createConversationState", "Conversation", "Conversations", "Orchestrator", "Transcription", "TranscriptEntry"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/conversations/orchestration/orchestrator/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { Orchestrator } from \"./orchestrator\";\nexport type { OrchestratorOptions } from \"./orchestrator\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,gBAAAA,MAAoB",
|
|
6
|
+
"names": ["Orchestrator"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var m=Object.defineProperty;var d=(u,t)=>m(u,"name",{value:t,configurable:!0});class f{static{d(this,"Orchestrator")}conversation;agent;llm;stt;tts;persistence;toolTimeoutMs;maxToolIterations;temperature;maxTokens;started=!1;generating=!1;epoch=0;unsubscribers=[];sttSessions=new Map;history=[];toolWaiters=new Map;generationChain=Promise.resolve();speechChain=Promise.resolve();speechBuffer="";pendingTurns=0;pendingGenerations=0;audioSequence=0;turnSequence=0;constructor(t){const e=t.llm??t.agent?.llm;if(!t.stt)throw new Error("Orchestrator requires an STT provider");if(t.agent&&!e)throw new Error("Orchestrator requires an LLM when an agent is attached: pass one explicitly or configure the agent with one");if(t.agent&&!t.tts)throw new Error("Orchestrator requires a TTS provider when an agent is attached");this.conversation=t.conversation,this.agent=t.agent,this.llm=e,this.stt=t.stt,this.tts=t.tts,this.persistence=t.persistence,this.toolTimeoutMs=t.toolTimeoutMs??3e4,this.maxToolIterations=t.maxToolIterations??10,this.temperature=t.temperature,this.maxTokens=t.maxTokens}async start(){if(!this.started){if(this.started=!0,this.persistence){const[t,e]=await Promise.all([this.persistence.listTurns(this.conversation.id),this.persistence.listGenerations(this.conversation.id)]),r=[...t.map(s=>({at:s.startedAt,kind:"turn",turn:s})),...e.filter(s=>s.status==="completed").map(s=>({at:s.startedAt,kind:"generation",text:s.text}))].sort((s,i)=>s.at-i.at);for(const s of r)s.kind==="turn"?this.history.push({role:"user",content:`${s.turn.participantName}: ${s.turn.text}`}):this.history.push({role:"assistant",content:s.text})}this.unsubscribers.push(this.conversation.on("stop",()=>{this.stop()}),this.conversation.on("audio-in",t=>this.onAudioIn(t)),this.conversation.on("interrupt",()=>this.onInterrupt()),this.conversation.on("tool-call-result",t=>this.onToolCallResult(t.result)))}}async stop(){if(!this.started)return;this.started=!1,this.epoch++,this.llm?.stop(),this.tts?.stop(),this.cancelToolWaiters("conversation stopped"),this.speechBuffer="";for(const e of this.unsubscribers)e();this.unsubscribers.length=0;const t=[...this.sttSessions.values()];this.sttSessions.clear();for(const{session:e}of t)await e.end().catch(()=>{})}async whenIdle(){for(;;){for(;this.pendingTurns>0||this.pendingGenerations>0||this.generating;)await Bun.sleep(1);if(await Promise.resolve(),this.pendingTurns===0&&this.pendingGenerations===0&&!this.generating)return}}onAudioIn(t){let e=this.sttSessions.get(t.userId);if(!e){const r=this.stt.start({});r.on("partial",s=>this.onPartial(t.userId,s)),r.on("final",s=>this.onFinal(t.userId,s)),r.on("error",s=>this.onProviderError(s)),e={session:r,turnStartedAt:null},this.sttSessions.set(t.userId,e)}e.turnStartedAt===null&&(e.turnStartedAt=Date.now()),e.session.write(t.audio.data),this.pendingGenerations>0&&this.conversation.interrupt()}onPartial(t,e){const r=e.trim();r&&this.conversation.emit("partial-transcript",{conversationId:this.conversation.id,userId:t,text:r})}onFinal(t,e){const r=e.trim();if(!r)return;const s=this.conversation.state.participants.get(t);if(!s)return;const i=this.sttSessions.get(t),n=i?.turnStartedAt??Date.now();i&&(i.turnStartedAt=null);const o={id:crypto.randomUUID(),conversationId:this.conversation.id,participantId:t,participantName:s.aliases[0]??t,text:r,sequence:this.turnSequence++,startedAt:n,endedAt:Date.now()};this.pendingTurns++,this.processTurn(o)}async processTurn(t){try{await this.conversation.pushTurn(t),await this.conversation.pushTranscript({speaker:t.participantName,speakerKind:"participant",text:t.text}),this.history.push({role:"user",content:`${t.participantName}: ${t.text}`}),this.agent&&this.queueGeneration()}finally{this.pendingTurns--}}onInterrupt(){this.epoch++,this.llm?.stop(),this.tts?.stop(),this.cancelToolWaiters("interrupted"),this.speechBuffer=""}onToolCallResult(t){const e=this.toolWaiters.get(t.id);e&&(this.toolWaiters.delete(t.id),e(t))}onProviderError(t){this.conversation.emit("error",{conversationId:this.conversation.id,error:t})}queueGeneration(){this.pendingGenerations++;const t=this.epoch;this.generationChain=this.generationChain.then(async()=>{if(this.epoch!==t){this.pendingGenerations--;return}try{await this.generate()}finally{this.pendingGenerations--}})}async generate(){const{agent:t,llm:e,tts:r}=this;if(!(!t||!e||!r)){this.generating=!0;try{await this.runGeneration(this.epoch,t,e,r)}finally{this.generating=!1}}}async runGeneration(t,e,r,s){await this.conversation.pushGeneration({id:crypto.randomUUID(),conversationId:this.conversation.id,agentName:e.name,text:"",status:"streaming",startedAt:Date.now()});const i=e.tools.map(a=>({name:a.name,description:a.description,parameters:a.parameters??{type:"object",properties:{}}})),n=[];e.context&&n.push({role:"system",content:e.context}),n.push(...this.history);let o="";try{for(let a=0;a<this.maxToolIterations;a++){if(this.epoch!==t)return;const l=[];let p=!1;for await(const h of r.stream({messages:n,tools:i,temperature:this.temperature,maxTokens:this.maxTokens})){if(this.epoch!==t)return;switch(h.type){case"delta":o+=h.content,this.feedDelta(h.content);break;case"tool_call":l.push({id:h.id,name:h.name,arguments:h.arguments});break;case"error":throw h.error;case"done":p=!0}}if(this.epoch!==t)return;if(l.length>0){this.flushSpeech(),n.push({role:"assistant",content:o,toolCalls:l});const h=await this.resolveToolCalls(l,t);if(this.epoch!==t)return;for(const c of h)n.push({role:"tool",toolCallId:c.id,name:c.name,content:JSON.stringify(c.error!==void 0?{error:c.error}:c.result)});continue}if(p)break}if(this.epoch!==t||(this.flushSpeech(),await this.speechChain,this.epoch!==t))return;await this.conversation.completeGeneration(o),await this.conversation.pushTranscript({speaker:e.name,speakerKind:"agent",text:o}),this.history.push({role:"assistant",content:o})}catch(a){if(this.epoch!==t)return;this.conversation.emit("error",{conversationId:this.conversation.id,error:a instanceof Error?a:new Error(String(a))}),await this.conversation.completeGeneration(o),o&&(await this.conversation.pushTranscript({speaker:e.name,speakerKind:"agent",text:o}),this.history.push({role:"assistant",content:o}))}}async resolveToolCalls(t,e){const r=t.map(i=>this.waitForToolResult(i.id,e));for(const i of t){let n;try{n=JSON.parse(i.arguments)}catch{n=i.arguments}this.conversation.requestToolCall({id:i.id,name:i.name,arguments:n})}return(await Promise.all(r)).map((i,n)=>{const o=t[n];return{id:i.id,name:o.name,result:"result"in i?i.result:void 0,error:"error"in i?i.error:void 0}})}waitForToolResult(t,e){return new Promise(r=>{const s=setTimeout(()=>{this.toolWaiters.delete(t),r({id:t,error:`Tool call "${t}" timed out`})},this.toolTimeoutMs);this.toolWaiters.set(t,i=>{clearTimeout(s),r(i)})})}cancelToolWaiters(t){for(const[e,r]of[...this.toolWaiters])this.toolWaiters.delete(e),r({id:e,error:t})}feedDelta(t){for(this.speechBuffer+=t;;){let e=-1;for(let s=0;s<this.speechBuffer.length;s++){const i=this.speechBuffer[s];if(i==="."||i==="!"||i==="?"||i===`
|
|
2
|
+
`){e=s;break}}if(e<0)break;const r=this.speechBuffer.slice(0,e+1).trim();this.speechBuffer=this.speechBuffer.slice(e+1),r&&this.speak(r)}}flushSpeech(){const t=this.speechBuffer.trim();this.speechBuffer="",t&&this.speak(t)}speak(t){const e=this.tts;if(!e)return;const r=this.epoch;this.speechChain=this.speechChain.then(async()=>{if(!(!this.started||this.epoch!==r))try{for await(const s of e.stream({text:t})){if(!this.started||this.epoch!==r)break;this.conversation.pushAudio({data:s,timestamp:Date.now(),sequence:this.audioSequence++})}}catch(s){if(this.epoch!==r)return;this.conversation.emit("error",{conversationId:this.conversation.id,error:s instanceof Error?s:new Error(String(s))})}})}}export{f as Orchestrator};
|
|
3
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/conversations/orchestration/orchestrator/orchestrator.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Agent } from \"../../../agents/agent\";\nimport type { Conversation } from \"../../conversation/conversation\";\nimport type { Persistence } from \"../../../persistence/persistence\";\nimport type {\n LLM,\n LLMMessage,\n LLMToolCall,\n LLMToolDefinition,\n} from \"../../../providers/llm/types\";\nimport type { STT, STTSession } from \"../../../providers/stt/types\";\nimport type { TTS } from \"../../../providers/tts/types\";\nimport type { AudioChunk, ToolCallResult, Turn, UserId } from \"../../types\";\n\nexport interface OrchestratorOptions {\n conversation: Conversation;\n /**\n * The agent driving the realtime loop. Omit it for transcription-only\n * mode (audio in, turns and transcripts out \u2014 no LLM or TTS required).\n */\n agent?: Agent;\n /** Defaults to the agent's LLM. */\n llm?: LLM;\n stt: STT;\n /** Required when an agent is attached. */\n tts?: TTS;\n /** Used to rehydrate conversation history on start. */\n persistence?: Persistence;\n /** How long to wait for the application to resolve a tool call. */\n toolTimeoutMs?: number;\n /** Safety bound on tool-call round trips per generation. */\n maxToolIterations?: number;\n temperature?: number;\n maxTokens?: number;\n}\n\ninterface SttSessionEntry {\n session: STTSession;\n turnStartedAt: number | null;\n}\n\ninterface ResolvedToolCall {\n id: string;\n name: string;\n result?: unknown;\n error?: string;\n}\n\n/**\n * The realtime conversation state machine.\n *\n * Wires the conversation to the providers:\n *\n * ```text\n * audio-in \u2500\u2500\u25BA STT \u2500\u2500\u25BA turn \u2500\u2500\u25BA LLM \u2500\u2500\u25BA TTS \u2500\u2500\u25BA audio-out\n * \u2502\n * \u2514\u2500\u25BA tool-call \u2500\u2500\u25BA app resolves \u2500\u2500\u25BA resume\n * ```\n *\n * Deltas stream to TTS immediately (so the agent can narrate while a tool\n * runs), tool calls pause the generation until the application resolves\n * them, and interruptions cancel the current generation \u2014 discarding any\n * stale tool results or audio via a generation epoch.\n */\nexport class Orchestrator {\n private readonly conversation: Conversation;\n private readonly agent: Agent | undefined;\n private readonly llm: LLM | undefined;\n private readonly stt: STT;\n private readonly tts: TTS | undefined;\n private readonly persistence: Persistence | undefined;\n private readonly toolTimeoutMs: number;\n private readonly maxToolIterations: number;\n private readonly temperature: number | undefined;\n private readonly maxTokens: number | undefined;\n\n private started = false;\n private generating = false;\n private epoch = 0;\n private readonly unsubscribers: (() => void)[] = [];\n private readonly sttSessions = new Map<UserId, SttSessionEntry>();\n private readonly history: LLMMessage[] = [];\n private readonly toolWaiters = new Map<string, (result: ToolCallResult) => void>();\n private generationChain: Promise<void> = Promise.resolve();\n private speechChain: Promise<void> = Promise.resolve();\n private speechBuffer = \"\";\n private pendingTurns = 0;\n private pendingGenerations = 0;\n private audioSequence = 0;\n private turnSequence = 0;\n\n constructor(options: OrchestratorOptions) {\n const llm = options.llm ?? options.agent?.llm;\n if (!options.stt) {\n throw new Error(\"Orchestrator requires an STT provider\");\n }\n if (options.agent && !llm) {\n throw new Error(\n \"Orchestrator requires an LLM when an agent is attached: \" +\n \"pass one explicitly or configure the agent with one\",\n );\n }\n if (options.agent && !options.tts) {\n throw new Error(\"Orchestrator requires a TTS provider when an agent is attached\");\n }\n this.conversation = options.conversation;\n this.agent = options.agent;\n this.llm = llm;\n this.stt = options.stt;\n this.tts = options.tts;\n this.persistence = options.persistence;\n this.toolTimeoutMs = options.toolTimeoutMs ?? 30_000;\n this.maxToolIterations = options.maxToolIterations ?? 10;\n this.temperature = options.temperature;\n this.maxTokens = options.maxTokens;\n }\n\n /**\n * Attach to the conversation: rehydrate history from persistence and\n * subscribe to conversation events.\n */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n if (this.persistence) {\n const [turns, generations] = await Promise.all([\n this.persistence.listTurns(this.conversation.id),\n this.persistence.listGenerations(this.conversation.id),\n ]);\n const entries: Array<\n | { at: number; kind: \"turn\"; turn: Turn }\n | { at: number; kind: \"generation\"; text: string }\n > = [\n ...turns.map((turn) => ({ at: turn.startedAt, kind: \"turn\" as const, turn })),\n ...generations\n .filter((generation) => generation.status === \"completed\")\n .map((generation) => ({\n at: generation.startedAt,\n kind: \"generation\" as const,\n text: generation.text,\n })),\n ].sort((a, b) => a.at - b.at);\n\n for (const entry of entries) {\n if (entry.kind === \"turn\") {\n this.history.push({\n role: \"user\",\n content: `${entry.turn.participantName}: ${entry.turn.text}`,\n });\n } else {\n this.history.push({ role: \"assistant\", content: entry.text });\n }\n }\n }\n\n this.unsubscribers.push(\n this.conversation.on(\"stop\", () => void this.stop()),\n this.conversation.on(\"audio-in\", (payload) => this.onAudioIn(payload)),\n this.conversation.on(\"interrupt\", () => this.onInterrupt()),\n this.conversation.on(\"tool-call-result\", (payload) =>\n this.onToolCallResult(payload.result),\n ),\n );\n }\n\n async stop(): Promise<void> {\n if (!this.started) return;\n this.started = false;\n this.epoch++;\n this.llm?.stop();\n this.tts?.stop();\n this.cancelToolWaiters(\"conversation stopped\");\n this.speechBuffer = \"\";\n for (const unsubscribe of this.unsubscribers) unsubscribe();\n this.unsubscribers.length = 0;\n const sessions = [...this.sttSessions.values()];\n this.sttSessions.clear();\n for (const { session } of sessions) {\n await session.end().catch(() => {});\n }\n }\n\n /**\n * Resolve once every queued and in-flight turn and generation has\n * finished processing. Useful for tests and graceful shutdown.\n */\n async whenIdle(): Promise<void> {\n for (;;) {\n while (\n this.pendingTurns > 0 ||\n this.pendingGenerations > 0 ||\n this.generating\n ) {\n await Bun.sleep(1);\n }\n // Give work scheduled in the same microtask turn a chance to register.\n await Promise.resolve();\n if (\n this.pendingTurns === 0 &&\n this.pendingGenerations === 0 &&\n !this.generating\n ) {\n return;\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Conversation event handlers\n // -------------------------------------------------------------------------\n\n private onAudioIn(payload: { userId: UserId; audio: AudioChunk }): void {\n let entry = this.sttSessions.get(payload.userId);\n if (!entry) {\n const session = this.stt.start({});\n session.on(\"partial\", (text) => this.onPartial(payload.userId, text));\n session.on(\"final\", (text) => this.onFinal(payload.userId, text));\n session.on(\"error\", (error) => this.onProviderError(error));\n entry = { session, turnStartedAt: null };\n this.sttSessions.set(payload.userId, entry);\n }\n\n if (entry.turnStartedAt === null) {\n entry.turnStartedAt = Date.now();\n }\n entry.session.write(payload.audio.data);\n\n // Barge-in: a participant speaks while the agent is responding (or about\n // to). The interrupting audio is already queued to STT above.\n if (this.pendingGenerations > 0) {\n this.conversation.interrupt();\n }\n }\n\n private onPartial(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.conversation.emit(\"partial-transcript\", {\n conversationId: this.conversation.id,\n userId,\n text: trimmed,\n });\n }\n\n private onFinal(userId: UserId, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n const participant = this.conversation.state.participants.get(userId);\n if (!participant) return;\n\n const entry = this.sttSessions.get(userId);\n const startedAt = entry?.turnStartedAt ?? Date.now();\n if (entry) entry.turnStartedAt = null;\n\n const turn: Turn = {\n id: crypto.randomUUID(),\n conversationId: this.conversation.id,\n participantId: userId,\n participantName: participant.aliases[0] ?? userId,\n text: trimmed,\n sequence: this.turnSequence++,\n startedAt,\n endedAt: Date.now(),\n };\n\n // Track synchronously so `whenIdle()` can observe in-flight work.\n this.pendingTurns++;\n void this.processTurn(turn);\n }\n\n private async processTurn(turn: Turn): Promise<void> {\n try {\n await this.conversation.pushTurn(turn);\n await this.conversation.pushTranscript({\n speaker: turn.participantName,\n speakerKind: \"participant\",\n text: turn.text,\n });\n this.history.push({\n role: \"user\",\n content: `${turn.participantName}: ${turn.text}`,\n });\n if (this.agent) {\n this.queueGeneration();\n }\n } finally {\n this.pendingTurns--;\n }\n }\n\n private onInterrupt(): void {\n this.epoch++;\n this.llm?.stop();\n this.tts?.stop();\n this.cancelToolWaiters(\"interrupted\");\n this.speechBuffer = \"\";\n }\n\n private onToolCallResult(result: ToolCallResult): void {\n const resolve = this.toolWaiters.get(result.id);\n if (!resolve) return; // stale, timed out, or already resolved\n this.toolWaiters.delete(result.id);\n resolve(result);\n }\n\n private onProviderError(error: Error): void {\n this.conversation.emit(\"error\", { conversationId: this.conversation.id, error });\n }\n\n // -------------------------------------------------------------------------\n // Generation\n // -------------------------------------------------------------------------\n\n private queueGeneration(): void {\n this.pendingGenerations++;\n const epoch = this.epoch;\n this.generationChain = this.generationChain.then(async () => {\n if (this.epoch !== epoch) {\n // Superseded by an interruption while queued.\n this.pendingGenerations--;\n return;\n }\n try {\n await this.generate();\n } finally {\n this.pendingGenerations--;\n }\n });\n }\n\n private async generate(): Promise<void> {\n const { agent, llm, tts } = this;\n if (!agent || !llm || !tts) return;\n this.generating = true;\n try {\n await this.runGeneration(this.epoch, agent, llm, tts);\n } finally {\n this.generating = false;\n }\n }\n\n private async runGeneration(\n epoch: number,\n agent: Agent,\n llm: LLM,\n tts: TTS,\n ): Promise<void> {\n await this.conversation.pushGeneration({\n id: crypto.randomUUID(),\n conversationId: this.conversation.id,\n agentName: agent.name,\n text: \"\",\n status: \"streaming\",\n startedAt: Date.now(),\n });\n\n const definitions: LLMToolDefinition[] = agent.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters ?? { type: \"object\", properties: {} },\n }));\n\n const messages: LLMMessage[] = [];\n if (agent.context) {\n messages.push({ role: \"system\", content: agent.context });\n }\n messages.push(...this.history);\n\n let text = \"\";\n\n try {\n for (let iteration = 0; iteration < this.maxToolIterations; iteration++) {\n if (this.epoch !== epoch) return;\n\n const toolCalls: LLMToolCall[] = [];\n let done = false;\n\n for await (const event of llm.stream({\n messages,\n tools: definitions,\n temperature: this.temperature,\n maxTokens: this.maxTokens,\n })) {\n if (this.epoch !== epoch) return;\n switch (event.type) {\n case \"delta\":\n text += event.content;\n this.feedDelta(event.content);\n break;\n case \"tool_call\":\n toolCalls.push({ id: event.id, name: event.name, arguments: event.arguments });\n break;\n case \"error\":\n throw event.error;\n case \"done\":\n done = true;\n }\n }\n\n if (this.epoch !== epoch) return;\n\n if (toolCalls.length > 0) {\n // Pause the response: let the narration finish, hand the calls to\n // the application, and resume once they are resolved.\n this.flushSpeech();\n messages.push({ role: \"assistant\", content: text, toolCalls });\n const results = await this.resolveToolCalls(toolCalls, epoch);\n if (this.epoch !== epoch) return;\n for (const result of results) {\n messages.push({\n role: \"tool\",\n toolCallId: result.id,\n name: result.name,\n content: JSON.stringify(\n result.error !== undefined ? { error: result.error } : result.result,\n ),\n });\n }\n continue;\n }\n\n if (done) break;\n }\n\n if (this.epoch !== epoch) return;\n\n this.flushSpeech();\n await this.speechChain;\n\n if (this.epoch !== epoch) return;\n\n await this.conversation.completeGeneration(text);\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text,\n });\n this.history.push({ role: \"assistant\", content: text });\n } catch (error) {\n if (this.epoch !== epoch) return; // interrupted \u2014 discard everything\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n // Finalize whatever was generated so the conversation state stays\n // consistent even though the provider failed.\n await this.conversation.completeGeneration(text);\n if (text) {\n await this.conversation.pushTranscript({\n speaker: agent.name,\n speakerKind: \"agent\",\n text,\n });\n this.history.push({ role: \"assistant\", content: text });\n }\n }\n }\n\n private async resolveToolCalls(\n calls: LLMToolCall[],\n epoch: number,\n ): Promise<ResolvedToolCall[]> {\n const resolutions = calls.map((call) => this.waitForToolResult(call.id, epoch));\n for (const call of calls) {\n let args: unknown;\n try {\n args = JSON.parse(call.arguments);\n } catch {\n args = call.arguments;\n }\n this.conversation.requestToolCall({\n id: call.id,\n name: call.name,\n arguments: args,\n });\n }\n\n const results = await Promise.all(resolutions);\n return results.map((result, index) => {\n const call = calls[index]!;\n return {\n id: result.id,\n name: call.name,\n result: \"result\" in result ? result.result : undefined,\n error: \"error\" in result ? result.error : undefined,\n };\n });\n }\n\n private waitForToolResult(id: string, _epoch: number): Promise<ToolCallResult> {\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.toolWaiters.delete(id);\n resolve({ id, error: `Tool call \"${id}\" timed out` });\n }, this.toolTimeoutMs);\n this.toolWaiters.set(id, (result) => {\n clearTimeout(timeout);\n resolve(result);\n });\n });\n }\n\n private cancelToolWaiters(reason: string): void {\n for (const [id, resolve] of [...this.toolWaiters]) {\n this.toolWaiters.delete(id);\n resolve({ id, error: reason });\n }\n }\n\n // -------------------------------------------------------------------------\n // Speech (LLM deltas \u2192 sentence buffering \u2192 TTS \u2192 audio-out)\n // -------------------------------------------------------------------------\n\n private feedDelta(delta: string): void {\n this.speechBuffer += delta;\n // Flush every complete sentence so multi-sentence deltas (and deltas\n // that span several sentences) are spoken as separate TTS requests.\n for (;;) {\n let boundary = -1;\n for (let i = 0; i < this.speechBuffer.length; i++) {\n const ch = this.speechBuffer[i];\n if (ch === \".\" || ch === \"!\" || ch === \"?\" || ch === \"\\n\") {\n boundary = i;\n break;\n }\n }\n if (boundary < 0) break;\n const sentence = this.speechBuffer.slice(0, boundary + 1).trim();\n this.speechBuffer = this.speechBuffer.slice(boundary + 1);\n if (sentence) this.speak(sentence);\n }\n }\n\n private flushSpeech(): void {\n const rest = this.speechBuffer.trim();\n this.speechBuffer = \"\";\n if (rest) this.speak(rest);\n }\n\n /** Synthesize a sentence and push the audio chunks out to the app. */\n private speak(sentence: string): void {\n const tts = this.tts;\n if (!tts) return;\n const epoch = this.epoch;\n this.speechChain = this.speechChain.then(async () => {\n if (!this.started || this.epoch !== epoch) return;\n try {\n for await (const chunk of tts.stream({ text: sentence })) {\n if (!this.started || this.epoch !== epoch) break;\n this.conversation.pushAudio({\n data: chunk,\n timestamp: Date.now(),\n sequence: this.audioSequence++,\n });\n }\n } catch (error) {\n if (this.epoch !== epoch) return; // interrupted\n this.conversation.emit(\"error\", {\n conversationId: this.conversation.id,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Orchestrator", "__name", "options", "llm", "turns", "generations", "entries", "turn", "generation", "a", "b", "entry", "payload", "unsubscribe", "sessions", "session", "text", "error", "userId", "trimmed", "participant", "startedAt", "result", "resolve", "epoch", "agent", "tts", "definitions", "tool", "messages", "iteration", "toolCalls", "done", "event", "results", "calls", "resolutions", "call", "args", "index", "id", "_epoch", "timeout", "reason", "delta", "boundary", "i", "ch", "sentence", "rest", "chunk"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/conversations/transcription/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { Transcription, TranscriptEntry } from \"./transcription\";\nexport type {\n TranscriptEntryInput,\n TranscriptSpeakerKind,\n} from \"./transcription\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,iBAAAA,EAAe,mBAAAC,MAAuB",
|
|
6
|
+
"names": ["Transcription", "TranscriptEntry"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var a=Object.defineProperty;var r=(i,e)=>a(i,"name",{value:e,configurable:!0});class s{static{r(this,"TranscriptEntry")}id;conversationId;speaker;speakerKind;text;timestamp;sequence;constructor(e){this.id=e.id??crypto.randomUUID(),this.conversationId=e.conversationId,this.speaker=e.speaker,this.speakerKind=e.speakerKind,this.text=e.text,this.timestamp=e.timestamp??Date.now(),this.sequence=e.sequence??0}static fromPlain(e){return new s({...e})}toString(){return`${this.speaker}: ${this.text}`}}class p{static{r(this,"Transcription")}conversationId;entries=[];ids=new Set;nextSequence=0;constructor(e){this.conversationId=e}get length(){return this.entries.length}get isEmpty(){return this.entries.length===0}appendSpeech(e,n,t=Date.now()){return this.append({speaker:e,speakerKind:"participant",text:n,timestamp:t})}appendGeneration(e,n,t=Date.now()){return this.append({speaker:e,speakerKind:"agent",text:n,timestamp:t})}append(e){const n=new s({...e,conversationId:this.conversationId,sequence:e.sequence??this.nextSequence});if(this.ids.has(n.id))throw new Error(`Transcript entry "${n.id}" already exists`);return this.ids.add(n.id),this.entries.push(n),this.nextSequence=n.sequence+1,n}list(){return[...this.entries]}get(e){return this.entries.find(n=>n.id===e)??null}getBySequence(e){return this.entries.find(n=>n.sequence===e)??null}last(){return this.entries.at(-1)??null}clear(){this.entries.length=0,this.ids.clear(),this.nextSequence=0}}export{s as TranscriptEntry,p as Transcription};
|
|
2
|
+
//# sourceMappingURL=transcription.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/conversations/transcription/transcription.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ConversationId } from \"../types\";\n\nexport type TranscriptSpeakerKind = \"participant\" | \"agent\";\n\nexport interface TranscriptEntryInput {\n conversationId: ConversationId;\n speaker: string;\n speakerKind: TranscriptSpeakerKind;\n text: string;\n timestamp?: number;\n sequence?: number;\n id?: string;\n}\n\n/**\n * A single line of a conversation transcript.\n *\n * `toString()` renders the entry as `speaker: text` so transcript arrays can\n * be joined directly into a readable dump.\n */\nexport class TranscriptEntry {\n readonly id: string;\n readonly conversationId: ConversationId;\n readonly speaker: string;\n readonly speakerKind: TranscriptSpeakerKind;\n readonly text: string;\n readonly timestamp: number;\n readonly sequence: number;\n\n constructor(input: TranscriptEntryInput) {\n this.id = input.id ?? crypto.randomUUID();\n this.conversationId = input.conversationId;\n this.speaker = input.speaker;\n this.speakerKind = input.speakerKind;\n this.text = input.text;\n this.timestamp = input.timestamp ?? Date.now();\n this.sequence = input.sequence ?? 0;\n }\n\n /** Rebuild an entry from plain (e.g. persisted) data. */\n static fromPlain(plain: TranscriptEntry): TranscriptEntry {\n return new TranscriptEntry({ ...plain });\n }\n\n toString(): string {\n return `${this.speaker}: ${this.text}`;\n }\n}\n\n/**\n * In-memory transcript state for a single conversation.\n *\n * Entries are appended in order and assigned monotonically increasing\n * sequence numbers. The orchestrator appends entries as speech is finalized\n * and generations complete; persistence mirrors these entries.\n */\nexport class Transcription {\n private readonly conversationId: ConversationId;\n private readonly entries: TranscriptEntry[] = [];\n private readonly ids = new Set<string>();\n private nextSequence = 0;\n\n constructor(conversationId: ConversationId) {\n this.conversationId = conversationId;\n }\n\n get length(): number {\n return this.entries.length;\n }\n\n get isEmpty(): boolean {\n return this.entries.length === 0;\n }\n\n /** Append a participant speech entry. */\n appendSpeech(speaker: string, text: string, timestamp = Date.now()): TranscriptEntry {\n return this.append({ speaker, speakerKind: \"participant\", text, timestamp });\n }\n\n /** Append an agent generation entry. */\n appendGeneration(agentName: string, text: string, timestamp = Date.now()): TranscriptEntry {\n return this.append({ speaker: agentName, speakerKind: \"agent\", text, timestamp });\n }\n\n append(\n input: Omit<TranscriptEntryInput, \"conversationId\" | \"sequence\" | \"id\"> & {\n id?: string;\n sequence?: number;\n },\n ): TranscriptEntry {\n const entry = new TranscriptEntry({\n ...input,\n conversationId: this.conversationId,\n sequence: input.sequence ?? this.nextSequence,\n });\n if (this.ids.has(entry.id)) {\n throw new Error(`Transcript entry \"${entry.id}\" already exists`);\n }\n this.ids.add(entry.id);\n this.entries.push(entry);\n this.nextSequence = entry.sequence + 1;\n return entry;\n }\n\n list(): TranscriptEntry[] {\n return [...this.entries];\n }\n\n get(id: string): TranscriptEntry | null {\n return this.entries.find((entry) => entry.id === id) ?? null;\n }\n\n getBySequence(sequence: number): TranscriptEntry | null {\n return this.entries.find((entry) => entry.sequence === sequence) ?? null;\n }\n\n last(): TranscriptEntry | null {\n return this.entries.at(-1) ?? null;\n }\n\n clear(): void {\n this.entries.length = 0;\n this.ids.clear();\n this.nextSequence = 0;\n }\n}\n"],
|
|
5
|
+
"mappings": "+EAoBO,MAAMA,CAAgB,CApB7B,MAoB6B,CAAAC,EAAA,wBAClB,GACA,eACA,QACA,YACA,KACA,UACA,SAET,YAAYC,EAA6B,CACvC,KAAK,GAAKA,EAAM,IAAM,OAAO,WAAW,EACxC,KAAK,eAAiBA,EAAM,eAC5B,KAAK,QAAUA,EAAM,QACrB,KAAK,YAAcA,EAAM,YACzB,KAAK,KAAOA,EAAM,KAClB,KAAK,UAAYA,EAAM,WAAa,KAAK,IAAI,EAC7C,KAAK,SAAWA,EAAM,UAAY,CACpC,CAGA,OAAO,UAAUC,EAAyC,CACxD,OAAO,IAAIH,EAAgB,CAAE,GAAGG,CAAM,CAAC,CACzC,CAEA,UAAmB,CACjB,MAAO,GAAG,KAAK,OAAO,KAAK,KAAK,IAAI,EACtC,CACF,CASO,MAAMC,CAAc,CAxD3B,MAwD2B,CAAAH,EAAA,sBACR,eACA,QAA6B,CAAC,EAC9B,IAAM,IAAI,IACnB,aAAe,EAEvB,YAAYI,EAAgC,CAC1C,KAAK,eAAiBA,CACxB,CAEA,IAAI,QAAiB,CACnB,OAAO,KAAK,QAAQ,MACtB,CAEA,IAAI,SAAmB,CACrB,OAAO,KAAK,QAAQ,SAAW,CACjC,CAGA,aAAaC,EAAiBC,EAAcC,EAAY,KAAK,IAAI,EAAoB,CACnF,OAAO,KAAK,OAAO,CAAE,QAAAF,EAAS,YAAa,cAAe,KAAAC,EAAM,UAAAC,CAAU,CAAC,CAC7E,CAGA,iBAAiBC,EAAmBF,EAAcC,EAAY,KAAK,IAAI,EAAoB,CACzF,OAAO,KAAK,OAAO,CAAE,QAASC,EAAW,YAAa,QAAS,KAAAF,EAAM,UAAAC,CAAU,CAAC,CAClF,CAEA,OACEN,EAIiB,CACjB,MAAMQ,EAAQ,IAAIV,EAAgB,CAChC,GAAGE,EACH,eAAgB,KAAK,eACrB,SAAUA,EAAM,UAAY,KAAK,YACnC,CAAC,EACD,GAAI,KAAK,IAAI,IAAIQ,EAAM,EAAE,EACvB,MAAM,IAAI,MAAM,qBAAqBA,EAAM,EAAE,kBAAkB,EAEjE,YAAK,IAAI,IAAIA,EAAM,EAAE,EACrB,KAAK,QAAQ,KAAKA,CAAK,EACvB,KAAK,aAAeA,EAAM,SAAW,EAC9BA,CACT,CAEA,MAA0B,CACxB,MAAO,CAAC,GAAG,KAAK,OAAO,CACzB,CAEA,IAAIC,EAAoC,CACtC,OAAO,KAAK,QAAQ,KAAMD,GAAUA,EAAM,KAAOC,CAAE,GAAK,IAC1D,CAEA,cAAcC,EAA0C,CACtD,OAAO,KAAK,QAAQ,KAAMF,GAAUA,EAAM,WAAaE,CAAQ,GAAK,IACtE,CAEA,MAA+B,CAC7B,OAAO,KAAK,QAAQ,GAAG,EAAE,GAAK,IAChC,CAEA,OAAc,CACZ,KAAK,QAAQ,OAAS,EACtB,KAAK,IAAI,MAAM,EACf,KAAK,aAAe,CACtB,CACF",
|
|
6
|
+
"names": ["TranscriptEntry", "__name", "input", "plain", "Transcription", "conversationId", "speaker", "text", "timestamp", "agentName", "entry", "id", "sequence"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r=Object.defineProperty;var e=(t,n)=>r(t,"name",{value:n,configurable:!0});function i(t="created"){return{status:t,participants:new Map,floor:null,currentTurn:null,currentGeneration:null,transcriptCount:0}}e(i,"createConversationState");export{i as createConversationState};
|
|
2
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/conversations/types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Core domain types shared across Pipeflow modules.\n */\n\n// ---------------------------------------------------------------------------\n// Identities\n// ---------------------------------------------------------------------------\n\nexport type ConversationId = string;\nexport type UserId = string;\nexport type TurnId = string;\n\n// ---------------------------------------------------------------------------\n// Participants\n// ---------------------------------------------------------------------------\n\nexport interface ParticipantInput {\n userId: UserId;\n aliases?: string[];\n}\n\nexport interface Participant {\n userId: UserId;\n aliases: string[];\n joinedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Turns & generations\n// ---------------------------------------------------------------------------\n\nexport interface Turn {\n id: TurnId;\n conversationId: ConversationId;\n participantId: UserId;\n participantName: string;\n text: string;\n sequence: number;\n startedAt: number;\n endedAt: number;\n}\n\nexport type GenerationStatus = \"streaming\" | \"completed\" | \"cancelled\";\n\nexport interface Generation {\n id: string;\n conversationId: ConversationId;\n agentName: string;\n text: string;\n status: GenerationStatus;\n startedAt: number;\n endedAt?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Tool calls\n// ---------------------------------------------------------------------------\n\nexport interface ToolCall {\n id: string;\n name: string;\n /** Parsed arguments, or the raw JSON string if parsing failed. */\n arguments: unknown;\n}\n\nexport type ToolCallResult =\n | { id: string; result: unknown }\n | { id: string; error: string };\n\n// ---------------------------------------------------------------------------\n// Audio\n// ---------------------------------------------------------------------------\n\nexport interface AudioChunk {\n data: Uint8Array;\n timestamp: number;\n sequence: number;\n}\n\n// ---------------------------------------------------------------------------\n// Conversation state\n// ---------------------------------------------------------------------------\n\nexport type ConversationStatus = \"created\" | \"started\" | \"stopped\";\n\nexport interface ConversationState {\n status: ConversationStatus;\n participants: Map<UserId, Participant>;\n floor: UserId | null;\n currentTurn: Turn | null;\n currentGeneration: Generation | null;\n transcriptCount: number;\n}\n\nexport function createConversationState(\n status: ConversationStatus = \"created\",\n): ConversationState {\n return {\n status,\n participants: new Map(),\n floor: null,\n currentTurn: null,\n currentGeneration: null,\n transcriptCount: 0,\n };\n}\n"],
|
|
5
|
+
"mappings": "+EA8FO,SAASA,EACdC,EAA6B,UACV,CACnB,MAAO,CACL,OAAAA,EACA,aAAc,IAAI,IAClB,MAAO,KACP,YAAa,KACb,kBAAmB,KACnB,gBAAiB,CACnB,CACF,CAXgBC,EAAAF,EAAA",
|
|
6
|
+
"names": ["createConversationState", "status", "__name"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var n=Object.defineProperty;var r=(e,t)=>n(e,"name",{value:t,configurable:!0});import{Agent as o}from"./agents/agent.js";import{Conversations as i}from"./conversations/conversations.js";import{MemoryPersistence as p}from"./persistence/adapters/memory/memory.js";class c{static{r(this,"Pipeflow")}llm;stt;tts;conversations;constructor(t={}){this.llm=t.llm,this.stt=t.stt,this.tts=t.tts;const s=t.persistence??new p;this.conversations=new i(s)}agent(t){return new o({...t,llm:t.llm??this.llm})}}import{Tool as d,Tool as v}from"./agents/tools/tools.js";import{Conversation as C,Conversations as x,Orchestrator as g,Transcription as L,TranscriptEntry as O}from"./conversations/index.js";export{o as Agent,C as Conversation,x as Conversations,g as Orchestrator,c as Pipeflow,v as PipeflowTool,d as Tool,O as TranscriptEntry,L as Transcription};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import { Agent, type AgentOptions } from \"./agents/agent\";\nimport { Conversations } from \"./conversations/conversations\";\nimport { MemoryPersistence } from \"./persistence/adapters/memory/memory\";\nimport type { Persistence } from \"./persistence/persistence\";\nimport type { LLM } from \"./providers/llm/types\";\nimport type { STT } from \"./providers/stt/types\";\nimport type { TTS } from \"./providers/tts/types\";\n\nexport interface PipeflowOptions {\n llm?: LLM;\n stt?: STT;\n tts?: TTS;\n persistence?: Persistence;\n}\n\n/**\n * The Pipeflow entry point.\n *\n * ```ts\n * const pipeflow = new Pipeflow({ llm });\n * const agent = pipeflow.agent({ name: \"Jarvis\", context: \"...\" });\n * const conversation = await pipeflow.conversations.create({ agents: [agent] });\n * ```\n */\nexport class Pipeflow {\n readonly llm: LLM | undefined;\n readonly stt: STT | undefined;\n readonly tts: TTS | undefined;\n readonly conversations: Conversations;\n\n constructor(options: PipeflowOptions = {}) {\n this.llm = options.llm;\n this.stt = options.stt;\n this.tts = options.tts;\n const persistence = options.persistence ?? new MemoryPersistence();\n this.conversations = new Conversations(persistence);\n }\n\n /**\n * Create an agent. Agents inherit the Pipeflow instance's LLM provider so\n * `agent.run()` works out of the box.\n */\n agent(options: Omit<AgentOptions, \"llm\"> & { llm?: LLM }): Agent {\n return new Agent({ ...options, llm: options.llm ?? this.llm });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Core public API\n// ---------------------------------------------------------------------------\n\nexport { Agent };\nexport type {\n AgentOptions,\n AgentRunRequest,\n AgentRunResult,\n ExecutedToolCall,\n} from \"./agents/agent\";\nexport { Tool, Tool as PipeflowTool } from \"./agents/tools/tools\";\nexport type { ToolOptions } from \"./agents/tools/tools\";\n\nexport {\n Conversation,\n Conversations,\n Orchestrator,\n Transcription,\n TranscriptEntry,\n} from \"./conversations/index\";\nexport type {\n AudioChunk,\n ConversationEvents,\n ConversationId,\n ConversationOptions,\n ConversationState,\n ConversationStatus,\n CreateConversationOptions,\n Generation,\n GenerationStatus,\n OrchestratorOptions,\n Participant,\n ParticipantInput,\n ToolCall,\n ToolCallResult,\n TranscriptEntryInput,\n TranscriptSpeakerKind,\n Turn,\n TurnId,\n UserId,\n} from \"./conversations/index\";\n\n// ---------------------------------------------------------------------------\n// Configuration interfaces.\n//\n// Provider and persistence *implementations* are intentionally not exported\n// from the main entry \u2014 they are replaceable implementation detail. Import\n// them from their module subpaths when needed:\n//\n// import { DeepSeekLLM } from \"pipeflow/providers\";\n// import { SQLitePersistence } from \"pipeflow/persistence\";\n// import { MemoryTransport } from \"pipeflow/transport\";\n// ---------------------------------------------------------------------------\n\nexport type { LLM, LLMMessage } from \"./providers/llm/types\";\nexport type { STT } from \"./providers/stt/types\";\nexport type { TTS } from \"./providers/tts/types\";\nexport type { Persistence } from \"./persistence/persistence\";\n"],
|
|
5
|
+
"mappings": "+EAAA,OAAS,SAAAA,MAAgC,iBACzC,OAAS,iBAAAC,MAAqB,gCAC9B,OAAS,qBAAAC,MAAyB,uCAsB3B,MAAMC,CAAS,CAxBtB,MAwBsB,CAAAC,EAAA,iBACX,IACA,IACA,IACA,cAET,YAAYC,EAA2B,CAAC,EAAG,CACzC,KAAK,IAAMA,EAAQ,IACnB,KAAK,IAAMA,EAAQ,IACnB,KAAK,IAAMA,EAAQ,IACnB,MAAMC,EAAcD,EAAQ,aAAe,IAAIH,EAC/C,KAAK,cAAgB,IAAID,EAAcK,CAAW,CACpD,CAMA,MAAMD,EAA2D,CAC/D,OAAO,IAAIL,EAAM,CAAE,GAAGK,EAAS,IAAKA,EAAQ,KAAO,KAAK,GAAI,CAAC,CAC/D,CACF,CAaA,OAAS,QAAAE,EAAc,QAARA,MAA4B,uBAG3C,OACE,gBAAAC,EACA,iBAAAP,EACA,gBAAAQ,EACA,iBAAAC,EACA,mBAAAC,MACK",
|
|
6
|
+
"names": ["Agent", "Conversations", "MemoryPersistence", "Pipeflow", "__name", "options", "persistence", "Tool", "Conversation", "Orchestrator", "Transcription", "TranscriptEntry"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/persistence/adapters/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { MemoryPersistence } from \"./memory/memory\";\nexport { SQLitePersistence } from \"./sqlite/sqlite\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,qBAAAA,MAAyB,kBAClC,OAAS,qBAAAC,MAAyB",
|
|
6
|
+
"names": ["MemoryPersistence", "SQLitePersistence"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var c=Object.defineProperty;var o=(s,e)=>c(s,"name",{value:e,configurable:!0});class p{static{o(this,"MemoryPersistence")}conversations=new Map;participants=new Map;transcript=new Map;turns=new Map;generations=new Map;async createConversation(e={}){const n={id:e.id??crypto.randomUUID(),agentNames:[...e.agentNames??[]],createdAt:e.createdAt??Date.now(),endedAt:null};return this.conversations.set(n.id,n),i(n)}async getConversation(e){const n=this.conversations.get(e);return n?i(n):null}async listConversations(){return[...this.conversations.values()].sort((e,n)=>e.createdAt-n.createdAt).map(i)}async finalizeConversation(e,n=Date.now()){const t=this.conversations.get(e);return t?(t.endedAt=n,i(t)):null}async deleteConversation(e){const n=this.conversations.delete(e);return this.participants.delete(e),this.transcript.delete(e),this.turns.delete(e),this.generations.delete(e),n}async addParticipant(e,n){let t=this.participants.get(e);t||(t=new Map,this.participants.set(e,t)),t.set(n.userId,{...n,aliases:[...n.aliases]})}async listParticipants(e){const n=this.participants.get(e);return n?[...n.values()].map(t=>({...t,aliases:[...t.aliases]})):[]}async appendTranscript(e,n){const t=this.transcript.get(e)??[],r=t.findIndex(a=>a.id===n.id);r===-1?t.push(n):t[r]=n,this.transcript.set(e,t)}async listTranscript(e){return[...this.transcript.get(e)??[]]}async appendTurn(e,n){const t=this.turns.get(e)??[];t.push({...n}),this.turns.set(e,t)}async listTurns(e){return[...this.turns.get(e)??[]].map(n=>({...n}))}async appendGeneration(e,n){const t=this.generations.get(e)??[],r=t.findIndex(a=>a.id===n.id);r===-1?t.push({...n}):t[r]={...n},this.generations.set(e,t)}async listGenerations(e){return[...this.generations.get(e)??[]].map(n=>({...n}))}}function i(s){return{...s,agentNames:[...s.agentNames]}}o(i,"copyConversation");export{p as MemoryPersistence};
|
|
2
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/persistence/adapters/memory/memory.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n ConversationId,\n Generation,\n Participant,\n Turn,\n UserId,\n} from \"../../../conversations/types\";\nimport type { TranscriptEntry } from \"../../../conversations/transcription/transcription\";\nimport type {\n ConversationRecord,\n NewConversation,\n Persistence,\n} from \"../../persistence\";\n\n/**\n * In-memory persistence adapter. Useful for tests and development: data is\n * lost when the process exits.\n */\nexport class MemoryPersistence implements Persistence {\n private readonly conversations = new Map<ConversationId, ConversationRecord>();\n private readonly participants = new Map<ConversationId, Map<UserId, Participant>>();\n private readonly transcript = new Map<ConversationId, TranscriptEntry[]>();\n private readonly turns = new Map<ConversationId, Turn[]>();\n private readonly generations = new Map<ConversationId, Generation[]>();\n\n async createConversation(input: NewConversation = {}): Promise<ConversationRecord> {\n const record: ConversationRecord = {\n id: input.id ?? crypto.randomUUID(),\n agentNames: [...(input.agentNames ?? [])],\n createdAt: input.createdAt ?? Date.now(),\n endedAt: null,\n };\n this.conversations.set(record.id, record);\n return copyConversation(record);\n }\n\n async getConversation(id: ConversationId): Promise<ConversationRecord | null> {\n const record = this.conversations.get(id);\n return record ? copyConversation(record) : null;\n }\n\n async listConversations(): Promise<ConversationRecord[]> {\n return [...this.conversations.values()]\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(copyConversation);\n }\n\n async finalizeConversation(\n id: ConversationId,\n endedAt = Date.now(),\n ): Promise<ConversationRecord | null> {\n const record = this.conversations.get(id);\n if (!record) return null;\n record.endedAt = endedAt;\n return copyConversation(record);\n }\n\n async deleteConversation(id: ConversationId): Promise<boolean> {\n const existed = this.conversations.delete(id);\n this.participants.delete(id);\n this.transcript.delete(id);\n this.turns.delete(id);\n this.generations.delete(id);\n return existed;\n }\n\n async addParticipant(\n conversationId: ConversationId,\n participant: Participant,\n ): Promise<void> {\n let map = this.participants.get(conversationId);\n if (!map) {\n map = new Map();\n this.participants.set(conversationId, map);\n }\n map.set(participant.userId, { ...participant, aliases: [...participant.aliases] });\n }\n\n async listParticipants(conversationId: ConversationId): Promise<Participant[]> {\n const map = this.participants.get(conversationId);\n if (!map) return [];\n return [...map.values()].map((p) => ({ ...p, aliases: [...p.aliases] }));\n }\n\n async appendTranscript(\n conversationId: ConversationId,\n entry: TranscriptEntry,\n ): Promise<void> {\n const list = this.transcript.get(conversationId) ?? [];\n const index = list.findIndex((e) => e.id === entry.id);\n if (index === -1) list.push(entry);\n else list[index] = entry;\n this.transcript.set(conversationId, list);\n }\n\n async listTranscript(conversationId: ConversationId): Promise<TranscriptEntry[]> {\n return [...(this.transcript.get(conversationId) ?? [])];\n }\n\n async appendTurn(conversationId: ConversationId, turn: Turn): Promise<void> {\n const list = this.turns.get(conversationId) ?? [];\n list.push({ ...turn });\n this.turns.set(conversationId, list);\n }\n\n async listTurns(conversationId: ConversationId): Promise<Turn[]> {\n return [...(this.turns.get(conversationId) ?? [])].map((turn) => ({ ...turn }));\n }\n\n async appendGeneration(\n conversationId: ConversationId,\n generation: Generation,\n ): Promise<void> {\n const list = this.generations.get(conversationId) ?? [];\n const index = list.findIndex((g) => g.id === generation.id);\n if (index === -1) list.push({ ...generation });\n else list[index] = { ...generation };\n this.generations.set(conversationId, list);\n }\n\n async listGenerations(conversationId: ConversationId): Promise<Generation[]> {\n return [...(this.generations.get(conversationId) ?? [])].map((generation) => ({\n ...generation,\n }));\n }\n}\n\nfunction copyConversation(record: ConversationRecord): ConversationRecord {\n return { ...record, agentNames: [...record.agentNames] };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MemoryPersistence", "__name", "input", "record", "copyConversation", "id", "a", "b", "endedAt", "existed", "conversationId", "participant", "map", "p", "entry", "list", "index", "e", "turn", "generation", "g"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/persistence/adapters/sqlite/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { SQLitePersistence } from \"./sqlite\";\nexport type { SQLitePersistenceOptions } from \"./sqlite\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,qBAAAA,MAAyB",
|
|
6
|
+
"names": ["SQLitePersistence"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var r=Object.defineProperty;var s=(i,t)=>r(i,"name",{value:t,configurable:!0});import{Database as o}from"bun:sqlite";import{TranscriptEntry as d}from"../../../conversations/transcription/transcription.js";class u{static{s(this,"SQLitePersistence")}db;constructor(t={}){this.db=new o(t.filename??":memory:"),this.db.exec(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
agent_names TEXT NOT NULL,
|
|
5
|
+
created_at INTEGER NOT NULL,
|
|
6
|
+
ended_at INTEGER
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS participants (
|
|
10
|
+
conversation_id TEXT NOT NULL,
|
|
11
|
+
user_id TEXT NOT NULL,
|
|
12
|
+
aliases TEXT NOT NULL,
|
|
13
|
+
joined_at INTEGER NOT NULL,
|
|
14
|
+
PRIMARY KEY (conversation_id, user_id)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS transcript (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
conversation_id TEXT NOT NULL,
|
|
20
|
+
speaker TEXT NOT NULL,
|
|
21
|
+
speaker_kind TEXT NOT NULL,
|
|
22
|
+
text TEXT NOT NULL,
|
|
23
|
+
timestamp INTEGER NOT NULL,
|
|
24
|
+
sequence INTEGER NOT NULL
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE TABLE IF NOT EXISTS turns (
|
|
28
|
+
id TEXT PRIMARY KEY,
|
|
29
|
+
conversation_id TEXT NOT NULL,
|
|
30
|
+
participant_id TEXT NOT NULL,
|
|
31
|
+
participant_name TEXT NOT NULL,
|
|
32
|
+
text TEXT NOT NULL,
|
|
33
|
+
started_at INTEGER NOT NULL,
|
|
34
|
+
ended_at INTEGER NOT NULL,
|
|
35
|
+
sequence INTEGER NOT NULL
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE IF NOT EXISTS generations (
|
|
39
|
+
id TEXT PRIMARY KEY,
|
|
40
|
+
conversation_id TEXT NOT NULL,
|
|
41
|
+
agent_name TEXT NOT NULL,
|
|
42
|
+
text TEXT NOT NULL,
|
|
43
|
+
status TEXT NOT NULL,
|
|
44
|
+
started_at INTEGER NOT NULL,
|
|
45
|
+
ended_at INTEGER
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_participants_conversation ON participants (conversation_id);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_transcript_conversation ON transcript (conversation_id);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_turns_conversation ON turns (conversation_id);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_generations_conversation ON generations (conversation_id);
|
|
52
|
+
`)}close(){this.db.close()}async createConversation(t={}){const e={id:t.id??crypto.randomUUID(),agentNames:t.agentNames??[],createdAt:t.createdAt??Date.now(),endedAt:null};return this.db.query(`INSERT OR REPLACE INTO conversations (id, agent_names, created_at, ended_at)
|
|
53
|
+
VALUES (?, ?, ?, ?)`).run(e.id,JSON.stringify(e.agentNames),e.createdAt,null),{...e}}async getConversation(t){const e=this.db.query("SELECT * FROM conversations WHERE id = ?").get(t);return e?a(e):null}async listConversations(){return this.db.query("SELECT * FROM conversations ORDER BY created_at ASC").all().map(a)}async finalizeConversation(t,e=Date.now()){return this.db.query("UPDATE conversations SET ended_at = ? WHERE id = ?").run(e,t).changes===0?null:this.getConversation(t)}async deleteConversation(t){return this.db.query("SELECT id FROM conversations WHERE id = ?").get(t)?(this.db.query("DELETE FROM participants WHERE conversation_id = ?").run(t),this.db.query("DELETE FROM transcript WHERE conversation_id = ?").run(t),this.db.query("DELETE FROM turns WHERE conversation_id = ?").run(t),this.db.query("DELETE FROM generations WHERE conversation_id = ?").run(t),this.db.query("DELETE FROM conversations WHERE id = ?").run(t),!0):!1}async addParticipant(t,e){this.db.query(`INSERT OR REPLACE INTO participants (conversation_id, user_id, aliases, joined_at)
|
|
54
|
+
VALUES (?, ?, ?, ?)`).run(t,e.userId,JSON.stringify(e.aliases),e.joinedAt)}async listParticipants(t){return this.db.query("SELECT * FROM participants WHERE conversation_id = ? ORDER BY joined_at ASC").all(t).map(n=>({userId:n.user_id,aliases:JSON.parse(n.aliases),joinedAt:n.joined_at}))}async appendTranscript(t,e){this.db.query(`INSERT OR REPLACE INTO transcript (id, conversation_id, speaker, speaker_kind, text, timestamp, sequence)
|
|
55
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(e.id,t,e.speaker,e.speakerKind,e.text,e.timestamp,e.sequence)}async listTranscript(t){return this.db.query("SELECT * FROM transcript WHERE conversation_id = ? ORDER BY sequence ASC").all(t).map(n=>d.fromPlain({id:n.id,conversationId:n.conversation_id,speaker:n.speaker,speakerKind:n.speaker_kind,text:n.text,timestamp:n.timestamp,sequence:n.sequence}))}async appendTurn(t,e){this.db.query(`INSERT OR REPLACE INTO turns (id, conversation_id, participant_id, participant_name, text, started_at, ended_at, sequence)
|
|
56
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(e.id,t,e.participantId,e.participantName,e.text,e.startedAt,e.endedAt,e.sequence)}async listTurns(t){return this.db.query("SELECT * FROM turns WHERE conversation_id = ? ORDER BY sequence ASC").all(t).map(n=>({id:n.id,conversationId:n.conversation_id,participantId:n.participant_id,participantName:n.participant_name,text:n.text,startedAt:n.started_at,endedAt:n.ended_at,sequence:n.sequence}))}async appendGeneration(t,e){this.db.query(`INSERT OR REPLACE INTO generations (id, conversation_id, agent_name, text, status, started_at, ended_at)
|
|
57
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(e.id,t,e.agentName,e.text,e.status,e.startedAt,e.endedAt??null)}async listGenerations(t){return this.db.query("SELECT * FROM generations WHERE conversation_id = ? ORDER BY started_at ASC").all(t).map(n=>({id:n.id,conversationId:n.conversation_id,agentName:n.agent_name,text:n.text,status:n.status,startedAt:n.started_at,endedAt:n.ended_at??void 0}))}}function a(i){return{id:i.id,agentNames:JSON.parse(i.agent_names),createdAt:i.created_at,endedAt:i.ended_at}}s(a,"rowToConversation");export{u as SQLitePersistence};
|
|
58
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/persistence/adapters/sqlite/sqlite.ts"],
|
|
4
|
+
"sourcesContent": ["import { Database } from \"bun:sqlite\";\nimport type {\n ConversationId,\n Generation,\n Participant,\n Turn,\n UserId,\n} from \"../../../conversations/types\";\nimport { TranscriptEntry } from \"../../../conversations/transcription/transcription\";\nimport type {\n ConversationRecord,\n NewConversation,\n Persistence,\n} from \"../../persistence\";\n\nexport interface SQLitePersistenceOptions {\n /** Database filename. Defaults to an in-memory database. */\n filename?: string;\n}\n\ninterface ConversationRow {\n id: string;\n agent_names: string;\n created_at: number;\n ended_at: number | null;\n}\n\ninterface ParticipantRow {\n conversation_id: string;\n user_id: string;\n aliases: string;\n joined_at: number;\n}\n\ninterface TranscriptRow {\n id: string;\n conversation_id: string;\n speaker: string;\n speaker_kind: string;\n text: string;\n timestamp: number;\n sequence: number;\n}\n\ninterface TurnRow {\n id: string;\n conversation_id: string;\n participant_id: string;\n participant_name: string;\n text: string;\n started_at: number;\n ended_at: number;\n sequence: number;\n}\n\ninterface GenerationRow {\n id: string;\n conversation_id: string;\n agent_name: string;\n text: string;\n status: string;\n started_at: number;\n ended_at: number | null;\n}\n\n/**\n * SQLite-backed persistence adapter (via bun:sqlite).\n *\n * A lightweight persistent backend for local applications and early\n * deployments.\n */\nexport class SQLitePersistence implements Persistence {\n private readonly db: Database;\n\n constructor(options: SQLitePersistenceOptions = {}) {\n this.db = new Database(options.filename ?? \":memory:\");\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS conversations (\n id TEXT PRIMARY KEY,\n agent_names TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n ended_at INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS participants (\n conversation_id TEXT NOT NULL,\n user_id TEXT NOT NULL,\n aliases TEXT NOT NULL,\n joined_at INTEGER NOT NULL,\n PRIMARY KEY (conversation_id, user_id)\n );\n\n CREATE TABLE IF NOT EXISTS transcript (\n id TEXT PRIMARY KEY,\n conversation_id TEXT NOT NULL,\n speaker TEXT NOT NULL,\n speaker_kind TEXT NOT NULL,\n text TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n sequence INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS turns (\n id TEXT PRIMARY KEY,\n conversation_id TEXT NOT NULL,\n participant_id TEXT NOT NULL,\n participant_name TEXT NOT NULL,\n text TEXT NOT NULL,\n started_at INTEGER NOT NULL,\n ended_at INTEGER NOT NULL,\n sequence INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS generations (\n id TEXT PRIMARY KEY,\n conversation_id TEXT NOT NULL,\n agent_name TEXT NOT NULL,\n text TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at INTEGER NOT NULL,\n ended_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_participants_conversation ON participants (conversation_id);\n CREATE INDEX IF NOT EXISTS idx_transcript_conversation ON transcript (conversation_id);\n CREATE INDEX IF NOT EXISTS idx_turns_conversation ON turns (conversation_id);\n CREATE INDEX IF NOT EXISTS idx_generations_conversation ON generations (conversation_id);\n `);\n }\n\n close(): void {\n this.db.close();\n }\n\n async createConversation(input: NewConversation = {}): Promise<ConversationRecord> {\n const record: ConversationRecord = {\n id: input.id ?? crypto.randomUUID(),\n agentNames: input.agentNames ?? [],\n createdAt: input.createdAt ?? Date.now(),\n endedAt: null,\n };\n this.db\n .query(\n `INSERT OR REPLACE INTO conversations (id, agent_names, created_at, ended_at)\n VALUES (?, ?, ?, ?)`,\n )\n .run(record.id, JSON.stringify(record.agentNames), record.createdAt, null);\n return { ...record };\n }\n\n async getConversation(id: ConversationId): Promise<ConversationRecord | null> {\n const row = this.db\n .query<ConversationRow, [string]>(`SELECT * FROM conversations WHERE id = ?`)\n .get(id);\n return row ? rowToConversation(row) : null;\n }\n\n async listConversations(): Promise<ConversationRecord[]> {\n const rows = this.db\n .query<ConversationRow, []>(`SELECT * FROM conversations ORDER BY created_at ASC`)\n .all();\n return rows.map(rowToConversation);\n }\n\n async finalizeConversation(\n id: ConversationId,\n endedAt = Date.now(),\n ): Promise<ConversationRecord | null> {\n const result = this.db\n .query<unknown, [number, string]>(`UPDATE conversations SET ended_at = ? WHERE id = ?`)\n .run(endedAt, id);\n if (result.changes === 0) return null;\n return this.getConversation(id);\n }\n\n async deleteConversation(id: ConversationId): Promise<boolean> {\n const conversation = this.db\n .query<ConversationRow, [string]>(`SELECT id FROM conversations WHERE id = ?`)\n .get(id);\n if (!conversation) return false;\n this.db.query(`DELETE FROM participants WHERE conversation_id = ?`).run(id);\n this.db.query(`DELETE FROM transcript WHERE conversation_id = ?`).run(id);\n this.db.query(`DELETE FROM turns WHERE conversation_id = ?`).run(id);\n this.db.query(`DELETE FROM generations WHERE conversation_id = ?`).run(id);\n this.db.query(`DELETE FROM conversations WHERE id = ?`).run(id);\n return true;\n }\n\n async addParticipant(\n conversationId: ConversationId,\n participant: Participant,\n ): Promise<void> {\n this.db\n .query(\n `INSERT OR REPLACE INTO participants (conversation_id, user_id, aliases, joined_at)\n VALUES (?, ?, ?, ?)`,\n )\n .run(\n conversationId,\n participant.userId,\n JSON.stringify(participant.aliases),\n participant.joinedAt,\n );\n }\n\n async listParticipants(conversationId: ConversationId): Promise<Participant[]> {\n const rows = this.db\n .query<ParticipantRow, [string]>(\n `SELECT * FROM participants WHERE conversation_id = ? ORDER BY joined_at ASC`,\n )\n .all(conversationId);\n return rows.map((row) => ({\n userId: row.user_id,\n aliases: JSON.parse(row.aliases) as string[],\n joinedAt: row.joined_at,\n }));\n }\n\n async appendTranscript(\n conversationId: ConversationId,\n entry: TranscriptEntry,\n ): Promise<void> {\n this.db\n .query(\n `INSERT OR REPLACE INTO transcript (id, conversation_id, speaker, speaker_kind, text, timestamp, sequence)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n entry.id,\n conversationId,\n entry.speaker,\n entry.speakerKind,\n entry.text,\n entry.timestamp,\n entry.sequence,\n );\n }\n\n async listTranscript(conversationId: ConversationId): Promise<TranscriptEntry[]> {\n const rows = this.db\n .query<TranscriptRow, [string]>(\n `SELECT * FROM transcript WHERE conversation_id = ? ORDER BY sequence ASC`,\n )\n .all(conversationId);\n return rows.map((row) =>\n TranscriptEntry.fromPlain({\n id: row.id,\n conversationId: row.conversation_id,\n speaker: row.speaker,\n speakerKind: row.speaker_kind as TranscriptEntry[\"speakerKind\"],\n text: row.text,\n timestamp: row.timestamp,\n sequence: row.sequence,\n }),\n );\n }\n\n async appendTurn(conversationId: ConversationId, turn: Turn): Promise<void> {\n this.db\n .query(\n `INSERT OR REPLACE INTO turns (id, conversation_id, participant_id, participant_name, text, started_at, ended_at, sequence)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n turn.id,\n conversationId,\n turn.participantId,\n turn.participantName,\n turn.text,\n turn.startedAt,\n turn.endedAt,\n turn.sequence,\n );\n }\n\n async listTurns(conversationId: ConversationId): Promise<Turn[]> {\n const rows = this.db\n .query<TurnRow, [string]>(\n `SELECT * FROM turns WHERE conversation_id = ? ORDER BY sequence ASC`,\n )\n .all(conversationId);\n return rows.map((row) => ({\n id: row.id,\n conversationId: row.conversation_id,\n participantId: row.participant_id,\n participantName: row.participant_name,\n text: row.text,\n startedAt: row.started_at,\n endedAt: row.ended_at,\n sequence: row.sequence,\n }));\n }\n\n async appendGeneration(\n conversationId: ConversationId,\n generation: Generation,\n ): Promise<void> {\n this.db\n .query(\n `INSERT OR REPLACE INTO generations (id, conversation_id, agent_name, text, status, started_at, ended_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n generation.id,\n conversationId,\n generation.agentName,\n generation.text,\n generation.status,\n generation.startedAt,\n generation.endedAt ?? null,\n );\n }\n\n async listGenerations(conversationId: ConversationId): Promise<Generation[]> {\n const rows = this.db\n .query<GenerationRow, [string]>(\n `SELECT * FROM generations WHERE conversation_id = ? ORDER BY started_at ASC`,\n )\n .all(conversationId);\n return rows.map((row) => ({\n id: row.id,\n conversationId: row.conversation_id,\n agentName: row.agent_name,\n text: row.text,\n status: row.status as Generation[\"status\"],\n startedAt: row.started_at,\n endedAt: row.ended_at ?? undefined,\n }));\n }\n}\n\nfunction rowToConversation(row: ConversationRow): ConversationRecord {\n return {\n id: row.id,\n agentNames: JSON.parse(row.agent_names) as string[],\n createdAt: row.created_at,\n endedAt: row.ended_at,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Database", "TranscriptEntry", "SQLitePersistence", "__name", "options", "input", "record", "id", "row", "rowToConversation", "endedAt", "conversationId", "participant", "entry", "turn", "generation"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/persistence/index.ts"],
|
|
4
|
+
"sourcesContent": ["export type {\n ConversationRecord,\n NewConversation,\n Persistence,\n} from \"./persistence\";\nexport { MemoryPersistence, SQLitePersistence } from \"./adapters/index\";\n"],
|
|
5
|
+
"mappings": "AAKA,OAAS,qBAAAA,EAAmB,qBAAAC,MAAyB",
|
|
6
|
+
"names": ["MemoryPersistence", "SQLitePersistence"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{complete as t,streamText as T,DeepSeekLLM as L}from"./llm/index.js";import{DeepgramSTT as p}from"./stt/index.js";import{KokoroTTS as s}from"./tts/index.js";export{L as DeepSeekLLM,p as DeepgramSTT,s as KokoroTTS,t as complete,T as streamText};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/providers/index.ts"],
|
|
4
|
+
"sourcesContent": ["export type { LLM, LLMEvent, LLMMessage, LLMRole, LLMToolCall, LLMToolDefinition, LLMRequest } from \"./llm/index\";\nexport type { STT, STTOptions, STTSession } from \"./stt/index\";\nexport type { TTS, TTSRequest } from \"./tts/index\";\n\nexport { complete, streamText, DeepSeekLLM } from \"./llm/index\";\nexport { DeepgramSTT } from \"./stt/index\";\nexport { KokoroTTS } from \"./tts/index\";\n"],
|
|
5
|
+
"mappings": "AAIA,OAAS,YAAAA,EAAU,cAAAC,EAAY,eAAAC,MAAmB,cAClD,OAAS,eAAAC,MAAmB,cAC5B,OAAS,aAAAC,MAAiB",
|
|
6
|
+
"names": ["complete", "streamText", "DeepSeekLLM", "DeepgramSTT", "KokoroTTS"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var f=Object.defineProperty;var d=(p,e)=>f(p,"name",{value:e,configurable:!0});class u{static{d(this,"DeepSeekLLM")}apiKey;model;baseUrl;fetchImpl;abort=null;constructor(e){if(!e.apiKey)throw new Error("DeepSeekLLM requires an apiKey");this.apiKey=e.apiKey,this.model=e.model??"deepseek-chat",this.baseUrl=(e.baseUrl??"https://api.deepseek.com").replace(/\/+$/,""),this.fetchImpl=e.fetch??fetch}stop(){this.abort?.abort()}async*stream(e){this.abort?.abort();const i=new AbortController;this.abort=i;try{const n=await this.fetchImpl(`${this.baseUrl}/chat/completions`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({model:this.model,messages:e.messages,tools:e.tools?.map(a=>({type:"function",function:a})),stream:!0,temperature:e.temperature,max_tokens:e.maxTokens}),signal:i.signal});if(!n.ok){const a=await n.text();throw new Error(`DeepSeek request failed (${n.status}): ${a}`)}if(!n.body)throw new Error("DeepSeek returned an empty body");const r=new Map;for await(const a of m(n.body,i.signal)){const s=a.choices?.[0];if(!s)continue;const l=s.delta;l?.content&&(yield{type:"delta",content:l.content});for(const t of l?.tool_calls??[]){const c=t.index??0,o=r.get(c)??{id:"",name:"",arguments:""};t.id&&(o.id=t.id),t.function?.name&&(o.name+=t.function.name),t.function?.arguments&&(o.arguments+=t.function.arguments),r.set(c,o)}if(s.finish_reason==="tool_calls"){for(const t of r.values())yield{type:"tool_call",id:t.id,name:t.name,arguments:t.arguments};break}if(s.finish_reason==="stop")break}yield{type:"done"}}finally{this.abort===i&&(this.abort=null)}}}async function*m(p,e){const i=p.getReader(),n=new TextDecoder;let r="";for(;;){if(e.aborted)throw new DOMException("The operation was aborted.","AbortError");const{done:a,value:s}=await i.read();if(a)break;r+=n.decode(s,{stream:!0});const l=r.split(/\r?\n\r?\n/);r=l.pop()??"";for(const t of l)for(const c of t.split(/\r?\n/)){if(!c.startsWith("data:"))continue;const o=c.slice(5).trim();if(o==="[DONE]")return;try{yield JSON.parse(o)}catch{}}}}d(m,"parseSSE");export{u as DeepSeekLLM};
|
|
2
|
+
//# sourceMappingURL=deepseek.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/providers/llm/adapters/deepseek/deepseek.ts"],
|
|
4
|
+
"sourcesContent": ["import type { LLM, LLMEvent, LLMRequest } from \"../../types\";\nimport type { FetchLike } from \"../../../shared\";\n\nexport interface DeepSeekOptions {\n apiKey: string;\n /** Defaults to `deepseek-chat`. */\n model?: string;\n /** Defaults to `https://api.deepseek.com`. */\n baseUrl?: string;\n /** Injectable fetch implementation, mainly for tests. */\n fetch?: FetchLike;\n}\n\ninterface DeepSeekDeltaToolCall {\n index?: number;\n id?: string;\n function?: { name?: string; arguments?: string };\n}\n\ninterface DeepSeekChunk {\n choices?: Array<{\n delta?: { content?: string | null; tool_calls?: DeepSeekDeltaToolCall[] };\n finish_reason?: string | null;\n }>;\n}\n\n/**\n * DeepSeek LLM adapter (OpenAI-compatible chat completions over SSE).\n */\nexport class DeepSeekLLM implements LLM {\n private readonly apiKey: string;\n private readonly model: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: FetchLike;\n private abort: AbortController | null = null;\n\n constructor(options: DeepSeekOptions) {\n if (!options.apiKey) {\n throw new Error(\"DeepSeekLLM requires an apiKey\");\n }\n this.apiKey = options.apiKey;\n this.model = options.model ?? \"deepseek-chat\";\n this.baseUrl = (options.baseUrl ?? \"https://api.deepseek.com\").replace(/\\/+$/, \"\");\n this.fetchImpl = options.fetch ?? fetch;\n }\n\n stop(): void {\n this.abort?.abort();\n }\n\n async *stream(request: LLMRequest): AsyncGenerator<LLMEvent> {\n // Only one generation at a time per adapter instance.\n this.abort?.abort();\n const controller = new AbortController();\n this.abort = controller;\n\n try {\n const response = await this.fetchImpl(`${this.baseUrl}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.model,\n messages: request.messages,\n tools: request.tools?.map((tool) => ({ type: \"function\", function: tool })),\n stream: true,\n temperature: request.temperature,\n max_tokens: request.maxTokens,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`DeepSeek request failed (${response.status}): ${body}`);\n }\n if (!response.body) {\n throw new Error(\"DeepSeek returned an empty body\");\n }\n\n // Tool calls arrive fragmented across chunks and are reassembled by\n // index before being emitted once the stream signals `tool_calls`.\n const toolCalls = new Map<number, { id: string; name: string; arguments: string }>();\n\n for await (const chunk of parseSSE(response.body, controller.signal)) {\n const choice = chunk.choices?.[0];\n if (!choice) continue;\n\n const delta = choice.delta;\n if (delta?.content) {\n yield { type: \"delta\", content: delta.content };\n }\n\n for (const tc of delta?.tool_calls ?? []) {\n const index = tc.index ?? 0;\n const accumulated = toolCalls.get(index) ?? { id: \"\", name: \"\", arguments: \"\" };\n if (tc.id) accumulated.id = tc.id;\n if (tc.function?.name) accumulated.name += tc.function.name;\n if (tc.function?.arguments) accumulated.arguments += tc.function.arguments;\n toolCalls.set(index, accumulated);\n }\n\n if (choice.finish_reason === \"tool_calls\") {\n for (const call of toolCalls.values()) {\n yield {\n type: \"tool_call\",\n id: call.id,\n name: call.name,\n arguments: call.arguments,\n };\n }\n break;\n }\n if (choice.finish_reason === \"stop\") {\n break;\n }\n }\n\n yield { type: \"done\" };\n } finally {\n if (this.abort === controller) {\n this.abort = null;\n }\n }\n }\n}\n\n/**\n * Parse an SSE byte stream into JSON events. Supports both LF and CRLF\n * framing, ignores comments and malformed frames, and stops at `[DONE]`.\n * Aborts with an `AbortError` once the signal fires.\n */\nasync function* parseSSE(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n): AsyncGenerator<DeepSeekChunk> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n if (signal.aborted) {\n throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const frames = buffer.split(/\\r?\\n\\r?\\n/);\n buffer = frames.pop() ?? \"\";\n for (const frame of frames) {\n for (const line of frame.split(/\\r?\\n/)) {\n if (!line.startsWith(\"data:\")) continue;\n const data = line.slice(5).trim();\n if (data === \"[DONE]\") return;\n try {\n yield JSON.parse(data) as DeepSeekChunk;\n } catch {\n // Ignore malformed frames.\n }\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["DeepSeekLLM", "__name", "options", "request", "controller", "response", "tool", "body", "toolCalls", "chunk", "parseSSE", "choice", "delta", "tc", "index", "accumulated", "call", "signal", "reader", "decoder", "buffer", "done", "value", "frames", "frame", "line", "data"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/providers/llm/adapters/deepseek/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { DeepSeekLLM } from \"./deepseek\";\nexport type { DeepSeekOptions } from \"./deepseek\";\n"],
|
|
5
|
+
"mappings": "AAAA,OAAS,eAAAA,MAAmB",
|
|
6
|
+
"names": ["DeepSeekLLM"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var n=Object.defineProperty;var L=(t,o)=>n(t,"name",{value:o,configurable:!0});async function*s(t,o){for await(const e of t.stream(o))if(e.type==="delta")yield e.content;else if(e.type==="error")throw e.error}L(s,"streamText");async function i(t,o){let e="";for await(const r of s(t,o))e+=r;return e}L(i,"complete");import{DeepSeekLLM as f}from"./adapters/index.js";export{f as DeepSeekLLM,i as complete,s as streamText};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/providers/llm/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { LLM, LLMRequest } from \"./types\";\n\nexport type {\n LLM,\n LLMEvent,\n LLMMessage,\n LLMRole,\n LLMToolCall,\n LLMToolDefinition,\n LLMRequest,\n} from \"./types\";\n\n/**\n * Stream only the text deltas of an LLM generation, rethrowing any\n * streamed error.\n */\nexport async function* streamText(\n llm: LLM,\n request: LLMRequest,\n): AsyncGenerator<string> {\n for await (const event of llm.stream(request)) {\n if (event.type === \"delta\") {\n yield event.content;\n } else if (event.type === \"error\") {\n throw event.error;\n }\n }\n}\n\n/** Collect an entire LLM generation into a single string. */\nexport async function complete(llm: LLM, request: LLMRequest): Promise<string> {\n let text = \"\";\n for await (const chunk of streamText(llm, request)) {\n text += chunk;\n }\n return text;\n}\n\nexport { DeepSeekLLM } from \"./adapters/index\";\n"],
|
|
5
|
+
"mappings": "+EAgBA,eAAuBA,EACrBC,EACAC,EACwB,CACxB,gBAAiBC,KAASF,EAAI,OAAOC,CAAO,EAC1C,GAAIC,EAAM,OAAS,QACjB,MAAMA,EAAM,gBACHA,EAAM,OAAS,QACxB,MAAMA,EAAM,KAGlB,CAXuBC,EAAAJ,EAAA,cAcvB,eAAsBK,EAASJ,EAAUC,EAAsC,CAC7E,IAAII,EAAO,GACX,gBAAiBC,KAASP,EAAWC,EAAKC,CAAO,EAC/CI,GAAQC,EAEV,OAAOD,CACT,CANsBF,EAAAC,EAAA,YAQtB,OAAS,eAAAG,MAAmB",
|
|
6
|
+
"names": ["streamText", "llm", "request", "event", "__name", "complete", "text", "chunk", "DeepSeekLLM"]
|
|
7
|
+
}
|