@kuralle-syrinx/server-workers 4.4.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/kuralle-realtime-agent.d.ts +16 -0
  2. package/dist/kuralle-realtime-agent.d.ts.map +1 -0
  3. package/dist/kuralle-realtime-agent.js +156 -0
  4. package/dist/kuralle-realtime-agent.js.map +1 -0
  5. package/dist/live-realtime-session.d.ts +19 -0
  6. package/dist/live-realtime-session.d.ts.map +1 -0
  7. package/dist/live-realtime-session.js +65 -0
  8. package/dist/live-realtime-session.js.map +1 -0
  9. package/dist/live-session.d.ts +27 -0
  10. package/dist/live-session.d.ts.map +1 -0
  11. package/dist/live-session.js +93 -0
  12. package/dist/live-session.js.map +1 -0
  13. package/dist/worker-realtime.d.ts +13 -0
  14. package/dist/worker-realtime.d.ts.map +1 -0
  15. package/dist/worker-realtime.js +31 -0
  16. package/dist/worker-realtime.js.map +1 -0
  17. package/dist/worker.d.ts +32 -0
  18. package/dist/worker.d.ts.map +1 -0
  19. package/dist/worker.js +172 -0
  20. package/dist/worker.js.map +1 -0
  21. package/dist/workers-ai-smart-turn.d.ts +24 -0
  22. package/dist/workers-ai-smart-turn.d.ts.map +1 -0
  23. package/dist/workers-ai-smart-turn.js +36 -0
  24. package/dist/workers-ai-smart-turn.js.map +1 -0
  25. package/package.json +22 -15
  26. package/src/live-realtime-session.test.ts +88 -0
  27. package/src/live-session.test.ts +129 -0
  28. package/src/worker-runtime.test.ts +480 -0
  29. package/src/workers-ai-smart-turn.test.ts +67 -0
  30. package/.dev.vars.example +0 -17
  31. package/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite +0 -0
  32. package/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-shm +0 -0
  33. package/.wrangler/state/v3/cache/miniflare-CacheObject/metadata.sqlite-wal +0 -0
  34. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/642a4be3d8c37b7e8567dadb740c8b4480a517ece8a057e38786f06353895683.sqlite +0 -0
  35. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/642a4be3d8c37b7e8567dadb740c8b4480a517ece8a057e38786f06353895683.sqlite-shm +0 -0
  36. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/642a4be3d8c37b7e8567dadb740c8b4480a517ece8a057e38786f06353895683.sqlite-wal +0 -0
  37. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/metadata.sqlite +0 -0
  38. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/metadata.sqlite-shm +0 -0
  39. package/.wrangler/state/v3/r2/miniflare-R2BucketObject/metadata.sqlite-wal +0 -0
  40. package/wrangler.jsonc +0 -49
  41. package/wrangler.realtime-gemini.jsonc +0 -28
  42. package/wrangler.realtime.jsonc +0 -27
  43. package/wrangler.smartturn-spike.jsonc +0 -44
@@ -0,0 +1,16 @@
1
+ import type { VectorizeIndex } from "@cloudflare/workers-types";
2
+ import type { Reasoner } from "@kuralle-syrinx/core";
3
+ export interface KuralleRealtimeEnv {
4
+ readonly OPENAI_API_KEY?: string;
5
+ readonly OPENAI_MODEL?: string;
6
+ readonly VECTORIZE: VectorizeIndex;
7
+ }
8
+ export interface CreateRealtimeKuralleReasonerOptions {
9
+ readonly sessionId: string;
10
+ readonly userId?: string;
11
+ }
12
+ export declare function createRealtimeKuralleReasoner(env: KuralleRealtimeEnv, opts: CreateRealtimeKuralleReasonerOptions): Promise<Reasoner>;
13
+ export type KuralleCascadeEnv = KuralleRealtimeEnv;
14
+ export type CreateCascadeKuralleReasonerOptions = CreateRealtimeKuralleReasonerOptions;
15
+ export declare const createCascadeKuralleReasoner: typeof createRealtimeKuralleReasoner;
16
+ //# sourceMappingURL=kuralle-realtime-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kuralle-realtime-agent.d.ts","sourceRoot":"","sources":["../src/kuralle-realtime-agent.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAiHrD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;CACpC;AAED,MAAM,WAAW,oCAAoC;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA+CD,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,oCAAoC,GACzC,OAAO,CAAC,QAAQ,CAAC,CAMnB;AAED,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AACnD,MAAM,MAAM,mCAAmC,GAAG,oCAAoC,CAAC;AACvF,eAAO,MAAM,4BAA4B,sCAAgC,CAAC"}
@@ -0,0 +1,156 @@
1
+ // SPDX-License-Identifier: MIT
2
+ import { createOpenAI } from "@ai-sdk/openai";
3
+ import { defineAgent, defineFlow, defineTool, buildToolSet, createRuntime, MemoryStore, reply, } from "@kuralle-agents/core";
4
+ import { AiSdkEmbedder, VectorRetriever, } from "@kuralle-agents/rag";
5
+ import { defineSkill } from "@kuralle-agents/skills";
6
+ import { CloudflareVectorizeStore } from "@kuralle-agents/vectorize-store";
7
+ import { fromKuralleRuntime } from "@kuralle-syrinx/kuralle";
8
+ import { z } from "zod";
9
+ const DEFAULT_MODEL = "gpt-4.1-mini";
10
+ const INDEX_NAME = "kuralle-university-kb";
11
+ const SCHOLARSHIP_SKILL = defineSkill({
12
+ name: "scholarship-guidance",
13
+ description: "Guide students through scholarship eligibility and application steps",
14
+ body: `# Scholarship Guidance
15
+
16
+ 1. Ask whether the student is seeking merit-based aid, need-based aid, or both.
17
+ 2. For merit: cite the Dean's Merit Scholarship (GPA ≥ 3.5).
18
+ 3. For need: cite the Need-Based Grant (FAFSA required).
19
+ 4. Always mention the application deadline of February 15.`,
20
+ allowedTools: [],
21
+ });
22
+ let bookingCounter = 0;
23
+ const createBookingTool = defineTool({
24
+ name: "create_booking",
25
+ description: "Finalize the advisor appointment booking. Only call after the user has explicitly confirmed the details.",
26
+ input: z.object({}),
27
+ execute: async () => {
28
+ bookingCounter += 1;
29
+ return { bookingRef: `ADV-${bookingCounter}` };
30
+ },
31
+ });
32
+ const recordBookingDetails = defineTool({
33
+ name: "record_booking_details",
34
+ description: "Record the student's name, program, and preferred date once all three are known.",
35
+ input: z.object({ name: z.string(), program: z.string(), preferredDate: z.string() }),
36
+ execute: async (details) => details,
37
+ });
38
+ const requestTranscriptTool = defineTool({
39
+ name: "request_transcript",
40
+ description: "Submit an official transcript request for the given studentId.",
41
+ input: z.object({ studentId: z.string() }),
42
+ execute: async ({ studentId }) => ({ requestRef: `TR-${studentId}` }),
43
+ });
44
+ const replyBooked = reply({
45
+ id: "reply-booked",
46
+ grounding: { knowledge: { autoRetrieve: false } },
47
+ instructions: ({ state }) => `The advisor appointment is booked. Confirm it to the user and include this exact reference verbatim: ${String(state["bookingRef"] ?? "")}.`,
48
+ next: () => ({ end: "booked" }),
49
+ });
50
+ const confirmBooking = reply({
51
+ id: "confirm-booking",
52
+ grounding: { knowledge: { autoRetrieve: false } },
53
+ instructions: ({ state }) => `Summarize the advisor appointment — name: ${String(state["name"] ?? "")}, program: ${String(state["program"] ?? "")}, date: ${String(state["preferredDate"] ?? "")} — and ask the user to confirm. ONLY when the user clearly confirms, call create_booking to finalize. If they want changes, ask for the corrected detail.`,
54
+ tools: buildToolSet({ create_booking: createBookingTool }),
55
+ next: (turn) => {
56
+ const r = turn.toolResults.find((t) => t.name === "create_booking");
57
+ if (r?.result && typeof r.result === "object")
58
+ return { goto: replyBooked, data: r.result };
59
+ return "stay";
60
+ },
61
+ });
62
+ const collectBooking = reply({
63
+ id: "collect-booking",
64
+ grounding: { knowledge: { autoRetrieve: false } },
65
+ instructions: "Help the user book an advisor appointment. If you don't yet have all three of name, program, and preferred date, ask for the missing ones. Once you have all three, call record_booking_details.",
66
+ tools: buildToolSet({ record_booking_details: recordBookingDetails }),
67
+ next: (turn) => {
68
+ const r = turn.toolResults.find((t) => t.name === "record_booking_details");
69
+ if (r?.result && typeof r.result === "object")
70
+ return { goto: confirmBooking, data: r.result };
71
+ return "stay";
72
+ },
73
+ });
74
+ const bookingFlow = defineFlow({
75
+ name: "book-advisor-appointment",
76
+ description: "Book an appointment with an academic advisor",
77
+ start: collectBooking,
78
+ nodes: [collectBooking, confirmBooking, replyBooked],
79
+ });
80
+ const replyTranscript = reply({
81
+ id: "reply-transcript",
82
+ grounding: { knowledge: { autoRetrieve: false } },
83
+ instructions: ({ state }) => `Confirm the transcript request was submitted. Include this exact request reference verbatim: ${String(state["requestRef"] ?? "")}.`,
84
+ next: () => ({ end: "requested" }),
85
+ });
86
+ const collectTranscript = reply({
87
+ id: "collect-transcript",
88
+ grounding: { knowledge: { autoRetrieve: false } },
89
+ instructions: "Help the user request an official transcript. If you don't have their student ID, ask for it. Once you have it, call request_transcript with that studentId.",
90
+ tools: buildToolSet({ request_transcript: requestTranscriptTool }),
91
+ next: (turn) => {
92
+ const r = turn.toolResults.find((t) => t.name === "request_transcript");
93
+ if (r?.result && typeof r.result === "object")
94
+ return { goto: replyTranscript, data: r.result };
95
+ return "stay";
96
+ },
97
+ });
98
+ const transcriptFlow = defineFlow({
99
+ name: "request-transcript",
100
+ description: "Request an official academic transcript",
101
+ start: collectTranscript,
102
+ nodes: [collectTranscript, replyTranscript],
103
+ });
104
+ let runtimePromise;
105
+ function vectorStore(env) {
106
+ return new CloudflareVectorizeStore({ binding: env.VECTORIZE });
107
+ }
108
+ async function createUniversityRuntime(env) {
109
+ const apiKey = requireKey(env.OPENAI_API_KEY, "OPENAI_API_KEY");
110
+ const openai = createOpenAI({ apiKey });
111
+ const model = openai(env.OPENAI_MODEL?.trim() || DEFAULT_MODEL);
112
+ const embedder = new AiSdkEmbedder({ model: openai.embedding("text-embedding-3-small") });
113
+ const retriever = new VectorRetriever({
114
+ vectorStore: vectorStore(env),
115
+ embedder,
116
+ indexName: INDEX_NAME,
117
+ topK: 3,
118
+ });
119
+ const agent = defineAgent({
120
+ id: "university",
121
+ model,
122
+ instructions: "You are a friendly university support assistant. Answer admissions, program, tuition, and scholarship questions clearly and concisely for voice.",
123
+ knowledge: { autoRetrieve: true },
124
+ skills: [SCHOLARSHIP_SKILL],
125
+ flows: [bookingFlow, transcriptFlow],
126
+ tools: {
127
+ create_booking: createBookingTool,
128
+ request_transcript: requestTranscriptTool,
129
+ },
130
+ memory: { workingMemory: { autoLoad: [{ scope: "user", key: "USER" }] } },
131
+ });
132
+ return createRuntime({
133
+ agents: [agent],
134
+ defaultAgentId: "university",
135
+ sessionStore: new MemoryStore(),
136
+ knowledge: { retriever, embedder },
137
+ });
138
+ }
139
+ function getRuntime(env) {
140
+ return (runtimePromise ??= createUniversityRuntime(env));
141
+ }
142
+ export async function createRealtimeKuralleReasoner(env, opts) {
143
+ const runtime = await getRuntime(env);
144
+ return fromKuralleRuntime(runtime, {
145
+ sessionId: opts.sessionId,
146
+ userId: opts.userId ?? "voice",
147
+ });
148
+ }
149
+ export const createCascadeKuralleReasoner = createRealtimeKuralleReasoner;
150
+ function requireKey(value, name) {
151
+ const trimmed = value?.trim();
152
+ if (!trimmed)
153
+ throw new Error(`${name} is required to start a realtime voice session`);
154
+ return trimmed;
155
+ }
156
+ //# sourceMappingURL=kuralle-realtime-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kuralle-realtime-agent.js","sourceRoot":"","sources":["../src/kuralle-realtime-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Reasoner } from "@kuralle-syrinx/core";
2
+ import type { RealtimePipeline, VoicePipelineContext } from "@kuralle-syrinx/cf-agents";
3
+ import type { VectorizeIndex } from "@cloudflare/workers-types";
4
+ export type RealtimeFront = "openai" | "gemini";
5
+ export interface RealtimeSessionEnv {
6
+ readonly OPENAI_API_KEY?: string;
7
+ readonly OPENAI_MODEL?: string;
8
+ readonly GEMINI_API_KEY?: string;
9
+ readonly GEMINI_LIVE_MODEL?: string;
10
+ readonly REALTIME_FRONT?: string;
11
+ readonly VECTORIZE: VectorizeIndex;
12
+ }
13
+ export declare function resolveRealtimeFront(env: RealtimeSessionEnv): RealtimeFront;
14
+ export declare function hasRealtimeSessionCredentials(env: RealtimeSessionEnv): boolean;
15
+ /** Realtime pipeline descriptor consumed by `withVoice(Agent)`. */
16
+ export declare const realtimeVoicePipeline: RealtimePipeline<RealtimeSessionEnv>;
17
+ /** The back model: a kuralle Vectorize-backed Reasoner, keyed by the session id. */
18
+ export declare function createRealtimeReasoner(env: RealtimeSessionEnv, ctx: VoicePipelineContext): Promise<Reasoner>;
19
+ //# sourceMappingURL=live-realtime-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-realtime-session.d.ts","sourceRoot":"","sources":["../src/live-realtime-session.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAIxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;CACpC;AAiBD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,GAAG,aAAa,CAG3E;AAED,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAI9E;AAqBD,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,CAAC,kBAAkB,CAItE,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,QAAQ,CAAC,CAEnB"}
@@ -0,0 +1,65 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Bi-model voice pipeline for the Cloudflare Workers host: a gpt-realtime or Gemini
4
+ // Live front model with a kuralle Vectorize-backed Reasoner back model, consulted
5
+ // via the `ask_university` front-model delegate tool. This is the pipeline/brain
6
+ // layer — the host (worker-realtime.ts) composes it via `withVoice(Agent)`.
7
+ import { fromGeminiLive, fromOpenAIRealtime } from "@kuralle-syrinx/realtime";
8
+ import { createWorkersSocket } from "@kuralle-syrinx/ws/workers";
9
+ import { createRealtimeKuralleReasoner } from "./kuralle-realtime-agent.js";
10
+ const DEFAULT_GEMINI_LIVE_MODEL = "gemini-3.1-flash-live-preview";
11
+ const REALTIME_SYSTEM_INSTRUCTION = "You are a university student-relations voice assistant. Delegate factual questions to ask_university.";
12
+ const ASK_UNIVERSITY_TOOL = {
13
+ name: "ask_university",
14
+ description: "Answer university student-relations questions (enrollment, add/drop, advising).",
15
+ parameters: {
16
+ type: "object",
17
+ properties: { query: { type: "string" } },
18
+ required: ["query"],
19
+ },
20
+ };
21
+ export function resolveRealtimeFront(env) {
22
+ const front = env.REALTIME_FRONT?.trim().toLowerCase();
23
+ return front === "gemini" ? "gemini" : "openai";
24
+ }
25
+ export function hasRealtimeSessionCredentials(env) {
26
+ const front = resolveRealtimeFront(env);
27
+ if (front === "gemini")
28
+ return Boolean(env.GEMINI_API_KEY?.trim());
29
+ return Boolean(env.OPENAI_API_KEY?.trim());
30
+ }
31
+ function buildRealtimeFront(env) {
32
+ const front = resolveRealtimeFront(env);
33
+ if (front === "gemini") {
34
+ return fromGeminiLive({
35
+ apiKey: requireKey(env.GEMINI_API_KEY, "GEMINI_API_KEY"),
36
+ model: env.GEMINI_LIVE_MODEL?.trim() || DEFAULT_GEMINI_LIVE_MODEL,
37
+ systemInstruction: REALTIME_SYSTEM_INSTRUCTION,
38
+ tools: [ASK_UNIVERSITY_TOOL],
39
+ });
40
+ }
41
+ return fromOpenAIRealtime({
42
+ apiKey: requireKey(env.OPENAI_API_KEY, "OPENAI_API_KEY"),
43
+ socketFactory: createWorkersSocket,
44
+ turnDetection: { type: "server_vad", silence_duration_ms: 500 },
45
+ inputTranscription: true,
46
+ tools: [ASK_UNIVERSITY_TOOL],
47
+ });
48
+ }
49
+ /** Realtime pipeline descriptor consumed by `withVoice(Agent)`. */
50
+ export const realtimeVoicePipeline = {
51
+ kind: "realtime",
52
+ front: (env) => buildRealtimeFront(env),
53
+ delegateToolName: ASK_UNIVERSITY_TOOL.name,
54
+ };
55
+ /** The back model: a kuralle Vectorize-backed Reasoner, keyed by the session id. */
56
+ export function createRealtimeReasoner(env, ctx) {
57
+ return createRealtimeKuralleReasoner(env, { sessionId: ctx.sessionId });
58
+ }
59
+ function requireKey(value, name) {
60
+ const trimmed = value?.trim();
61
+ if (!trimmed)
62
+ throw new Error(`${name} is required to start a realtime voice session`);
63
+ return trimmed;
64
+ }
65
+ //# sourceMappingURL=live-realtime-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-realtime-session.js","sourceRoot":"","sources":["../src/live-realtime-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Reasoner } from "@kuralle-syrinx/core";
2
+ import type { CascadedPipeline, VoicePipelineContext } from "@kuralle-syrinx/cf-agents";
3
+ import type { VectorizeIndex } from "@cloudflare/workers-types";
4
+ import { WorkersAiSmartTurnPredictor, type Ai } from "./workers-ai-smart-turn.js";
5
+ /** Provider secrets + optional tuning, supplied as Workers env/secret bindings. */
6
+ export interface LiveSessionEnv {
7
+ readonly DEEPGRAM_API_KEY?: string;
8
+ readonly OPENAI_API_KEY?: string;
9
+ readonly OPENAI_MODEL?: string;
10
+ readonly VECTORIZE: VectorizeIndex;
11
+ /** Optional Cloudflare Workers AI binding for hosted Smart Turn. */
12
+ readonly AI?: Ai;
13
+ }
14
+ /** True when every provider secret needed for a live turn is present. */
15
+ export declare function hasLiveSessionCredentials(env: LiveSessionEnv): boolean;
16
+ /**
17
+ * Cascaded pipeline descriptor consumed by `withVoice(Agent)`. Deepgram Nova-3 STT
18
+ * (provider-endpointed, VAD events for barge-in) → kuralle Reasoner → Deepgram Aura
19
+ * TTS. `sttForceFinalizeTimeoutMs: 3500` keeps the engine's force-finalize tighter
20
+ * than the 7000ms default for the provider-endpointed cascade.
21
+ */
22
+ export declare const liveCascadedPipeline: CascadedPipeline<LiveSessionEnv>;
23
+ /** The brain: a kuralle Vectorize-backed Reasoner, keyed by the session id. */
24
+ export declare function createLiveReasoner(env: LiveSessionEnv, ctx: VoicePipelineContext): Promise<Reasoner>;
25
+ /** Factory: returns a hosted Smart Turn predictor when `env.AI` is present, otherwise undefined. */
26
+ export declare function createWorkersAiSmartTurnPredictor(env: LiveSessionEnv): WorkersAiSmartTurnPredictor | undefined;
27
+ //# sourceMappingURL=live-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-session.d.ts","sourceRoot":"","sources":["../src/live-session.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAIxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,2BAA2B,EAAE,KAAK,EAAE,EAAE,MAAM,4BAA4B,CAAC;AAElF,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;CAClB;AAMD,yEAAyE;AACzE,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAEtE;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,gBAAgB,CAAC,cAAc,CA0CjE,CAAC;AAEF,+EAA+E;AAC/E,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAI1G;AAED,oGAAoG;AACpG,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,cAAc,GAAG,2BAA2B,GAAG,SAAS,CAG9G"}
@@ -0,0 +1,93 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Cascaded voice pipeline for the Cloudflare Workers host: real Deepgram STT
4
+ // (nova-3) + kuralle (Vectorize RAG) Reasoner + Deepgram Aura TTS, all dialed
5
+ // over the Workers fetch-upgrade socket (createWorkersSocket) so no Node `ws`
6
+ // is pulled into the edge bundle. Default turn-taking is Deepgram endpointing
7
+ // (endpointingOwner: "provider_stt"); when `env.AI` is bound, hosted Workers AI
8
+ // Smart Turn owns EOS via the edge-safe PipecatEOSPlugin (`/eos` subpath, no ONNX).
9
+ //
10
+ // This is the pipeline/brain layer — the host (worker.ts) composes it via
11
+ // `withVoice(Agent)`; this module owns the plugin slots and the reasoner, not the
12
+ // connection lifecycle.
13
+ import { DeepgramSTTPlugin, DeepgramTTSPlugin } from "@kuralle-syrinx/deepgram";
14
+ import { PipecatEOSPlugin } from "@kuralle-syrinx/pipecat-smart-turn/eos";
15
+ import { createWorkersSocket } from "@kuralle-syrinx/ws/workers";
16
+ import { createRealtimeKuralleReasoner } from "./kuralle-realtime-agent.js";
17
+ import { WorkersAiSmartTurnPredictor } from "./workers-ai-smart-turn.js";
18
+ const DEFAULT_DEEPGRAM_TTS_MODEL = "aura-2-thalia-en";
19
+ const INPUT_SAMPLE_RATE_HZ = 16000;
20
+ const OUTPUT_SAMPLE_RATE_HZ = 16000;
21
+ /** True when every provider secret needed for a live turn is present. */
22
+ export function hasLiveSessionCredentials(env) {
23
+ return Boolean(env.DEEPGRAM_API_KEY?.trim() && env.OPENAI_API_KEY?.trim() && env.VECTORIZE);
24
+ }
25
+ /**
26
+ * Cascaded pipeline descriptor consumed by `withVoice(Agent)`. Deepgram Nova-3 STT
27
+ * (provider-endpointed, VAD events for barge-in) → kuralle Reasoner → Deepgram Aura
28
+ * TTS. `sttForceFinalizeTimeoutMs: 3500` keeps the engine's force-finalize tighter
29
+ * than the 7000ms default for the provider-endpointed cascade.
30
+ */
31
+ export const liveCascadedPipeline = {
32
+ kind: "cascaded",
33
+ stt: (env) => ({
34
+ plugin: new DeepgramSTTPlugin(createWorkersSocket),
35
+ config: {
36
+ api_key: requireKey(env.DEEPGRAM_API_KEY, "DEEPGRAM_API_KEY"),
37
+ sample_rate: INPUT_SAMPLE_RATE_HZ,
38
+ model: "nova-3",
39
+ language: "en-US",
40
+ // Silence (ms) before Deepgram finalizes a turn. 300ms is too aggressive with
41
+ // no semantic layer behind it: a natural mid-sentence pause ("my address is
42
+ // forty-two… Elm Street") finalizes early and the agent answers half an
43
+ // utterance. 500ms is the middle ground — it stops the worst cut-offs, and the
44
+ // ~200ms cost is negligible against the LLM-dominated v2v budget. The real fix
45
+ // for the edge is a semantic/dynamic endpointer (smart-turn has no Workers
46
+ // build yet); until then this is the sane default. Tune per deployment.
47
+ endpointing: 500,
48
+ // Gap-based backstop: on a noisy/continuous line where Deepgram never detects
49
+ // clean silence, `speech_final` can fail to fire and the turn wedges. UtteranceEnd
50
+ // completes it. Requires interim_results (on by default).
51
+ utterance_end_ms: 1000,
52
+ provider_finalize_timeout_ms: 2500,
53
+ finalize_timeout_fallback: true,
54
+ // No local VAD on the edge: Deepgram SpeechStarted is the barge-in
55
+ // speech-start signal (vad.speech_started producer).
56
+ vad_events: true,
57
+ },
58
+ }),
59
+ tts: (env) => ({
60
+ plugin: new DeepgramTTSPlugin(createWorkersSocket),
61
+ config: {
62
+ api_key: requireKey(env.DEEPGRAM_API_KEY, "DEEPGRAM_API_KEY"),
63
+ model: DEFAULT_DEEPGRAM_TTS_MODEL,
64
+ sample_rate: OUTPUT_SAMPLE_RATE_HZ,
65
+ },
66
+ }),
67
+ eos: (env) => {
68
+ const predictor = createWorkersAiSmartTurnPredictor(env);
69
+ return predictor ? { plugin: new PipecatEOSPlugin(predictor), config: {} } : undefined;
70
+ },
71
+ endpointingOwner: (env) => (env.AI ? "smart_turn" : "provider_stt"),
72
+ sttForceFinalizeTimeoutMs: 3500,
73
+ };
74
+ /** The brain: a kuralle Vectorize-backed Reasoner, keyed by the session id. */
75
+ export async function createLiveReasoner(env, ctx) {
76
+ requireKey(env.OPENAI_API_KEY, "OPENAI_API_KEY");
77
+ if (!env.VECTORIZE)
78
+ throw new Error("VECTORIZE binding is required to start a live voice session");
79
+ return createRealtimeKuralleReasoner(env, { sessionId: ctx.sessionId });
80
+ }
81
+ /** Factory: returns a hosted Smart Turn predictor when `env.AI` is present, otherwise undefined. */
82
+ export function createWorkersAiSmartTurnPredictor(env) {
83
+ if (!env.AI)
84
+ return undefined;
85
+ return new WorkersAiSmartTurnPredictor(env.AI);
86
+ }
87
+ function requireKey(value, name) {
88
+ const trimmed = value?.trim();
89
+ if (!trimmed)
90
+ throw new Error(`${name} is required to start a live voice session`);
91
+ return trimmed;
92
+ }
93
+ //# sourceMappingURL=live-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-session.js","sourceRoot":"","sources":["../src/live-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Agent } from "agents";
2
+ import { type RealtimeSessionEnv } from "./live-realtime-session.js";
3
+ export interface Env extends RealtimeSessionEnv {
4
+ readonly REALTIME_VOICE_CONVERSATIONS: DurableObjectNamespace;
5
+ }
6
+ declare const RealtimeVoiceConversation_base: typeof Agent<Env> & (new (...args: any[]) => import("@kuralle-syrinx/cf-agents").WithVoiceMembers);
7
+ export declare class RealtimeVoiceConversation extends RealtimeVoiceConversation_base {
8
+ }
9
+ declare const _default: {
10
+ fetch(request: Request, env: Env): Promise<Response>;
11
+ };
12
+ export default _default;
13
+ //# sourceMappingURL=worker-realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-realtime.d.ts","sourceRoot":"","sources":["../src/worker-realtime.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,GAAI,SAAQ,kBAAkB;IAC7C,QAAQ,CAAC,4BAA4B,EAAE,sBAAsB,CAAC;CAC/D;8CAK6D,OAAO,KAAK,CAAC,GAAG,CAAC;AAA/E,qBAAa,yBAA0B,SAAQ,8BAM7C;CAAG;;mBAGkB,OAAO,OAAO,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;;AAD5D,wBASE"}
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: MIT
2
+ //
3
+ // Cloudflare Workers realtime (bi-model) voice host, built on `withVoice(Agent)`
4
+ // (issue #10 / W1). Same host machinery as the cascaded worker — the only
5
+ // difference is the pipeline (realtime front + kuralle back) and the reasoner.
6
+ import { Agent } from "agents";
7
+ import { withVoice } from "@kuralle-syrinx/cf-agents";
8
+ import { createRealtimeReasoner, realtimeVoicePipeline, } from "./live-realtime-session.js";
9
+ const INPUT_SAMPLE_RATE_HZ = 16000;
10
+ const OUTPUT_SAMPLE_RATE_HZ = 16000;
11
+ export class RealtimeVoiceConversation extends withVoice((Agent), {
12
+ pipeline: realtimeVoicePipeline,
13
+ reasoner: (env, ctx) => createRealtimeReasoner(env, ctx),
14
+ inputSampleRateHz: INPUT_SAMPLE_RATE_HZ,
15
+ outputSampleRateHz: OUTPUT_SAMPLE_RATE_HZ,
16
+ resumeWindowMs: 15_000,
17
+ }) {
18
+ }
19
+ export default {
20
+ async fetch(request, env) {
21
+ const url = new URL(request.url);
22
+ if (url.pathname === "/health")
23
+ return new Response("ok");
24
+ if (url.pathname !== "/ws")
25
+ return new Response("not found", { status: 404 });
26
+ const sessionId = url.searchParams.get("sessionId") ?? crypto.randomUUID();
27
+ const id = env.REALTIME_VOICE_CONVERSATIONS.idFromName(sessionId);
28
+ return await env.REALTIME_VOICE_CONVERSATIONS.get(id).fetch(request);
29
+ },
30
+ };
31
+ //# sourceMappingURL=worker-realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-realtime.js","sourceRoot":"","sources":["../src/worker-realtime.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,iFAAiF;AACjF,0EAA0E;AAC1E,+EAA+E;AAE/E,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAEtB,MAAM,4BAA4B,CAAC;AAMpC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC,MAAM,OAAO,yBAA0B,SAAQ,SAAS,CAAyB,CAAA,KAAU,CAAA,EAAE;IAC3F,QAAQ,EAAE,qBAAqB;IAC/B,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC;IACxD,iBAAiB,EAAE,oBAAoB;IACvC,kBAAkB,EAAE,qBAAqB;IACzC,cAAc,EAAE,MAAM;CACvB,CAAC;CAAG;AAEL,eAAe;IACb,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAAQ;QACpC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;YAAE,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK;YAAE,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9E,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAC3E,MAAM,EAAE,GAAG,GAAG,CAAC,4BAA4B,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClE,OAAO,MAAM,GAAG,CAAC,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvE,CAAC;CACF,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Agent } from "agents";
2
+ import { type LiveSessionEnv } from "./live-session.js";
3
+ export interface Env extends LiveSessionEnv {
4
+ VOICE_CONVERSATIONS: DurableObjectNamespace;
5
+ TWILIO_VOICE_CONVERSATIONS: DurableObjectNamespace;
6
+ TELNYX_VOICE_CONVERSATIONS: DurableObjectNamespace;
7
+ /** Optional: when bound, full call audio is recorded to this bucket. */
8
+ RECORDINGS?: R2Bucket;
9
+ /** Optional: Cloudflare Workers AI binding for hosted Smart Turn endpointing. */
10
+ AI?: import("./workers-ai-smart-turn.js").Ai;
11
+ }
12
+ declare const VoiceConversation_base: typeof Agent<Env> & (new (...args: any[]) => import("@kuralle-syrinx/cf-agents").WithVoiceMembers);
13
+ /** Browser/edge cascaded host (Syrinx JSON+envelope protocol over /ws). */
14
+ export declare class VoiceConversation extends VoiceConversation_base {
15
+ }
16
+ declare const TwilioVoiceConversation_base: typeof Agent<Env> & (new (...args: any[]) => import("@kuralle-syrinx/cf-agents").WithVoiceMembers);
17
+ /** Telephony cascaded host (Twilio Media Streams μ-law 8 kHz over /twilio). Same pipeline/brain. */
18
+ export declare class TwilioVoiceConversation extends TwilioVoiceConversation_base {
19
+ }
20
+ declare const TelnyxVoiceConversation_base: typeof Agent<Env> & (new (...args: any[]) => import("@kuralle-syrinx/cf-agents").WithVoiceMembers);
21
+ /**
22
+ * Telephony cascaded host (Telnyx Media Streaming over /telnyx). Same pipeline/brain;
23
+ * idle timeout keeps the telephony re-engagement default. Live streaming_start →
24
+ * /telnyx is carrier-gated / unit-tested only.
25
+ */
26
+ export declare class TelnyxVoiceConversation extends TelnyxVoiceConversation_base {
27
+ }
28
+ declare const _default: {
29
+ fetch(request: Request, env: Env): Promise<Response>;
30
+ };
31
+ export default _default;
32
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAG/B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,GAAI,SAAQ,cAAc;IACzC,mBAAmB,EAAE,sBAAsB,CAAC;IAC5C,0BAA0B,EAAE,sBAAsB,CAAC;IACnD,0BAA0B,EAAE,sBAAsB,CAAC;IACnD,wEAAwE;IACxE,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,iFAAiF;IACjF,EAAE,CAAC,EAAE,OAAO,4BAA4B,EAAE,EAAE,CAAC;CAC9C;sCAMqD,OAAO,KAAK,CAAC,GAAG,CAAC;AADvE,2EAA2E;AAC3E,qBAAa,iBAAkB,SAAQ,sBAerC;CAAG;4CAGuD,OAAO,KAAK,CAAC,GAAG,CAAC;AAD7E,oGAAoG;AACpG,qBAAa,uBAAwB,SAAQ,4BAM3C;CAAG;4CAOuD,OAAO,KAAK,CAAC,GAAG,CAAC;AAL7E;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,4BAM3C;CAAG;;mBAGkB,OAAO,OAAO,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;;AAD5D,wBA4BE"}