@yak-io/javascript 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,80 +1,152 @@
1
1
  # @yak-io/javascript
2
2
 
3
- Framework-agnostic core SDK for embedding the Yak chat widget. This package provides the low-level client and DOM rendering layer. Most developers should use a framework-specific package (`@yak-io/react`, `@yak-io/vue`, etc.) instead.
3
+ > 📚 **Full documentation:** https://docs.yak.io/docs/sdks/javascript
4
+ >
5
+ > 🤖 **For LLMs / AI agents:** https://docs.yak.io/llms.txt
4
6
 
5
- ## When to use this package directly
7
+ Framework-agnostic core SDK for [Yak](https://docs.yak.io) — an embeddable AI assistant (text chat **and** push-to-talk voice) for web apps. This package is the low-level runtime that every framework SDK (`@yak-io/react`, `@yak-io/vue`, …) is built on. It owns iframe messaging, the WebRTC voice session, DOM rendering of the trigger pill + chat panel, and an optional server handler.
6
8
 
7
- - You are building a vanilla JS / TypeScript app
8
- - You are building a new framework adapter
9
- - You need the server-side handler utilities (`./server` export) outside Next.js
10
-
11
- ## Installation
9
+ **Use this package directly when** you're on vanilla JS/TS, building a new framework adapter, or need the server handler (`@yak-io/javascript/server`) outside Next.js. On a supported framework, prefer that framework's package instead.
12
10
 
13
11
  ```bash
14
12
  pnpm add @yak-io/javascript
15
13
  ```
16
14
 
17
- ## Quickstart — Vanilla JS
15
+ ## Exports
16
+
17
+ | Export | Kind | Purpose |
18
+ | --- | --- | --- |
19
+ | `YakEmbed` | class | Drop-in widget: trigger pill + chat panel + voice, all wired. Start here. |
20
+ | `YakClient` | class | Headless chat-only iframe client (no DOM). Advanced. |
21
+ | `YakVoiceSession` | class | Headless WebRTC voice session. Advanced. |
22
+ | `enableYakLogging` / `disableYakLogging` / `isYakLoggingEnabled` | fn | Toggle verbose SDK logging. |
23
+ | `EMBED_PROTOCOL_VERSION` | const | Host ↔ iframe protocol version. |
24
+ | Types | — | `YakEmbedConfig`, `YakClientConfig`, `Theme`, `WidgetMode`, `VoiceState`, `VoiceMachine`, `ToolCallEvent`, `ChatConfig`, and more (see [Types](#types)). |
25
+ | `@yak-io/javascript/server` | subpath | `createYakHandler` + route/tool source types (see [Server](#server-side-handler)). |
26
+
27
+ ## Quickstart
18
28
 
19
29
  ```ts
20
30
  import { YakEmbed } from "@yak-io/javascript";
21
31
 
22
32
  const embed = new YakEmbed({
23
33
  appId: "your-app-id",
34
+ mode: "both", // "chat" | "voice" | "both" — default "chat"
35
+ trigger: true, // render the floating launcher pill
24
36
  theme: { position: "bottom-right", colorMode: "system" },
25
- trigger: { label: "Ask with AI" },
26
- getConfig: async () => ({
27
- routes: {
28
- routes: [
29
- { path: "/", title: "Home", description: "Landing page" },
30
- { path: "/docs", title: "Docs", description: "Documentation" },
31
- ],
32
- generated_at: new Date().toISOString(),
33
- },
34
- tools: {
35
- tools: [
36
- {
37
- name: "tasks.list",
38
- displayName: "List Tasks",
39
- description: "Return all tasks",
40
- inputSchema: { type: "object", properties: {} },
41
- },
42
- ],
43
- generated_at: new Date().toISOString(),
44
- },
45
- }),
46
- onToolCall: async (name, args) => {
47
- if (name === "tasks.list") {
48
- return { tasks: [] };
49
- }
50
- throw new Error(`Unknown tool: ${name}`);
37
+ // Routes + tools the assistant may use. Usually fetched from your server.
38
+ getConfig: async () => {
39
+ const res = await fetch("/api/yak");
40
+ return res.json(); // ChatConfig: { routes, tools? }
51
41
  },
52
- onRedirect: (path) => {
53
- window.location.assign(path);
42
+ // Execute a tool the assistant decides to call.
43
+ onToolCall: async (name, args) => {
44
+ const res = await fetch("/api/yak", {
45
+ method: "POST",
46
+ headers: { "Content-Type": "application/json" },
47
+ body: JSON.stringify({ name, args }),
48
+ });
49
+ const data = await res.json();
50
+ if (!data.ok) throw new Error(data.error);
51
+ return data.result;
54
52
  },
55
53
  });
56
54
 
57
- embed.mount();
55
+ embed.mount(); // inject into the DOM
56
+ ```
57
+
58
+ ## Programmatic control
59
+
60
+ Every method works whether or not the trigger pill is shown — pass `trigger: false` to drive a fully custom UI.
61
+
62
+ ```ts
63
+ // Chat
64
+ embed.open();
65
+ embed.close();
66
+ embed.toggle();
67
+ embed.openWithPrompt("How do I export my data?");
68
+
69
+ // Voice (requires mode "voice" or "both"; must be called from a user gesture)
70
+ await embed.voiceStart();
71
+ await embed.voiceStop();
72
+ await embed.voiceToggle();
73
+
74
+ // State
75
+ embed.getState(); // { isOpen, isReady, isLoading, isExpanded }
76
+ const stop = embed.onStateChange((s) => console.log(s.isLoading));
77
+ const stopVoice = embed.onVoiceStateChange((m) => console.log(m.state));
58
78
  ```
59
79
 
60
- ## Server-side utilities
80
+ `isLoading` is `isOpen && !isReady` — true from the moment the panel opens until the iframe handshakes ready. Drive a custom loading spinner off it instead of re-deriving the condition. For voice, the equivalent "still spinning up" check is `getVoiceState().state === "connecting"`.
61
81
 
62
- Use `@yak-io/javascript/server` to build framework-agnostic API handlers:
82
+ ## API reference
83
+
84
+ ### `new YakEmbed(config)`
85
+
86
+ **Config** (`YakEmbedConfig`):
87
+
88
+ | Option | Type | Default | Description |
89
+ | --- | --- | --- | --- |
90
+ | `appId` | `string` | — | Your Yak app ID (required). |
91
+ | `mode` | `"chat" \| "voice" \| "both"` | `"chat"` | Which surfaces the widget exposes. |
92
+ | `trigger` | `boolean \| TriggerButtonConfig` | `true` | Show the floating pill. `false` = headless. `TriggerButtonConfig` recolors it. |
93
+ | `theme` | `Theme` | — | Position, color mode, and colors. |
94
+ | `getConfig` | `ChatConfigProvider` | — | Async provider of `{ routes, tools? }`. Called on open and on each voice start. |
95
+ | `onToolCall` | `ToolCallHandler` | — | Executes a tool the assistant calls. |
96
+ | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | — | Handles GraphQL schema tool calls. |
97
+ | `onRESTSchemaCall` | `RESTSchemaHandler` | — | Handles REST/OpenAPI schema tool calls. |
98
+ | `onRedirect` | `(path: string) => void` | `window.location.assign` | Handle navigation requested by the assistant. |
99
+ | `onToolCallComplete` | `(event: ToolCallEvent) => void` | — | Fires after every tool call (use for cache invalidation). |
100
+ | `user` | `UserIdentity` | — | Signed end-user identity for server-side conversation persistence. See [end-user identity](https://docs.yak.io/docs/customization/end-user-identity). |
101
+ | `target` | `HTMLElement` | `document.body` | Where to mount the widget DOM. |
102
+ | `options.disableRestartButton` | `boolean` | `false` | Hide the restart-session button in the header. |
103
+
104
+ **Methods:** `mount()`, `destroy()`, `open()`, `close()`, `toggle()`, `openWithPrompt(prompt)`, `getState()`, `onStateChange(fn)`, `voiceStart()`, `voiceStop()`, `voiceToggle()`, `getVoiceState()`, `onVoiceStateChange(fn)`, `getClient()`, `getVoiceSession()`, `getMode()`.
105
+
106
+ ### `Theme`
107
+
108
+ ```ts
109
+ type Theme = {
110
+ position?: WidgetPosition; // default "bottom-left"
111
+ colorMode?: "light" | "dark" | "system";
112
+ displayMode?: "chatbox" | "drawer"; // floating panel vs full-height side drawer
113
+ fullscreen?: boolean;
114
+ light?: ThemeColors; // { background?, border?, messageBackground?, ... }
115
+ dark?: ThemeColors;
116
+ };
117
+ // WidgetPosition: top-left | top-center | top-right | left-center | right-center
118
+ // | bottom-left | bottom-center | bottom-right
119
+ ```
120
+
121
+ ### `VoiceState` / `VoiceMachine`
122
+
123
+ ```ts
124
+ type VoiceState = "idle" | "connecting" | "listening" | "thinking" | "speaking" | "error";
125
+ interface VoiceMachine { state: VoiceState; errorMessage?: string }
126
+ ```
127
+
128
+ ### `YakClient` / `YakVoiceSession`
129
+
130
+ Headless building blocks used internally by `YakEmbed`. Reach for them only when composing a bespoke integration — most apps should use `YakEmbed`.
131
+
132
+ ## Server-side handler
133
+
134
+ `@yak-io/javascript/server` builds a framework-agnostic `Request`/`Response` handler (Remix, Fastify, Hono, plain Node, …):
63
135
 
64
136
  ```ts
65
137
  import { createYakHandler } from "@yak-io/javascript/server";
66
138
 
67
- // Works with any Request/Response runtime (Remix, Fastify, etc.)
68
- const { GET, POST } = createYakHandler({
139
+ export const { GET, POST } = createYakHandler({
140
+ // GET returns the route + tool manifest the assistant sees.
69
141
  routes: [
70
142
  { path: "/", title: "Home" },
71
143
  { path: "/tasks", title: "Tasks" },
72
144
  ],
145
+ // POST executes a tool call.
73
146
  tools: {
74
147
  getTools: async () => [
75
148
  {
76
149
  name: "tasks.list",
77
- displayName: "List Tasks",
78
150
  description: "Return all tasks",
79
151
  inputSchema: { type: "object", properties: {} },
80
152
  },
@@ -87,61 +159,17 @@ const { GET, POST } = createYakHandler({
87
159
  });
88
160
  ```
89
161
 
90
- ## API Reference
91
-
92
- ### `YakEmbed`
93
-
94
- High-level class that handles DOM rendering (panel, iframe, trigger button) and client wiring.
162
+ `routes` and `tools` each accept a single source or an array of sources, so you can compose filesystem routes with adapters like [`@yak-io/trpc`](https://docs.yak.io/docs/tool-adapters/trpc) or [`@yak-io/prismic`](https://docs.yak.io/docs/cms/prismic).
95
163
 
96
- ```ts
97
- new YakEmbed(config: YakEmbedConfig)
98
- ```
99
-
100
- **Key methods:**
101
-
102
- | Method | Description |
103
- |--------|-------------|
104
- | `mount()` | Injects the widget into the DOM |
105
- | `destroy()` | Removes the widget from the DOM |
106
- | `open()` | Open the chat panel |
107
- | `close()` | Close the chat panel |
108
- | `toggle()` | Toggle open/close |
109
- | `openWithPrompt(prompt)` | Open and pre-fill a prompt |
110
- | `getState()` | Get current `{ isOpen, isReady }` state |
111
- | `onStateChange(fn)` | Subscribe to state changes, returns unsubscribe |
112
- | `getClient()` | Access the underlying `YakClient` |
113
-
114
- **Configuration (`YakEmbedConfig`):**
115
-
116
- | Option | Type | Description |
117
- |--------|------|-------------|
118
- | `appId` | `string` | Your Yak app ID |
119
- | `theme` | `Theme` | Position, color mode, and widget colors |
120
- | `trigger` | `boolean \| TriggerButtonConfig` | Show built-in trigger button |
121
- | `getConfig` | `ChatConfigProvider` | Async function returning routes + tools config |
122
- | `chatConfig` | `ChatConfig` | Static config (alternative to `getConfig`) |
123
- | `onToolCall` | `ToolCallHandler` | Handle tool calls from the assistant |
124
- | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | Handle GraphQL schema tool calls |
125
- | `onRESTSchemaCall` | `RESTSchemaHandler` | Handle REST/OpenAPI schema tool calls |
126
- | `onRedirect` | `(path: string) => void` | Handle navigation requests |
127
- | `onToolCallComplete` | `(event: ToolCallEvent) => void` | Called after each tool call |
128
- | `options.disableRestartButton` | `boolean` | Hide the restart session button |
129
-
130
- ### `YakClient`
131
-
132
- Low-level iframe communication client. Use `YakEmbed` for most cases.
133
-
134
- ### Logging utilities
164
+ ## Logging
135
165
 
136
166
  ```ts
137
167
  import { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/javascript";
138
168
 
139
- enableYakLogging(); // Turn on verbose SDK logging
140
- disableYakLogging(); // Turn off SDK logging
141
- isYakLoggingEnabled(); // Returns current state
169
+ enableYakLogging(); // verbose SDK logs
142
170
  ```
143
171
 
144
- In development, set `window.__YAK_INTERNAL_DEV__ = true` before mounting to connect to a locally running chat UI.
172
+ In development, set `window.__YAK_INTERNAL_DEV__ = true` before `mount()` to connect to a locally running chat UI.
145
173
 
146
174
  ## Types
147
175
 
@@ -149,6 +177,16 @@ All types are exported from the package root:
149
177
 
150
178
  ```ts
151
179
  import type {
180
+ YakEmbedConfig,
181
+ YakEmbedState,
182
+ YakClientConfig,
183
+ WidgetMode,
184
+ Theme,
185
+ ThemeColors,
186
+ WidgetPosition,
187
+ TriggerButtonConfig,
188
+ VoiceState,
189
+ VoiceMachine,
152
190
  ChatConfig,
153
191
  ChatConfigProvider,
154
192
  RouteManifest,
@@ -157,25 +195,12 @@ import type {
157
195
  ToolDefinition,
158
196
  ToolCallHandler,
159
197
  ToolCallEvent,
160
- ToolCallPayload,
161
- ToolCallResult,
162
198
  GraphQLSchemaHandler,
163
199
  RESTSchemaHandler,
164
- GraphQLRequest,
165
- RESTRequest,
166
200
  SchemaSource,
167
- GraphQLSchemaSource,
168
- OpenAPISchemaSource,
169
- Theme,
170
- ThemeColors,
171
- TriggerButtonConfig,
172
- WidgetPosition,
173
- YakClientConfig,
174
- YakEmbedConfig,
175
- YakEmbedState,
176
201
  } from "@yak-io/javascript";
177
202
  ```
178
203
 
179
204
  ## License
180
205
 
181
- Proprietary — see LICENSE file.
206
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/embed.d.ts CHANGED
@@ -2,6 +2,12 @@ import { YakClient, type YakClientConfig } from "./client.js";
2
2
  import type { ChatConfigProvider } from "./types/config.js";
3
3
  import { type VoiceMachine } from "./voice-machine.js";
4
4
  import { type VoiceStateListener, YakVoiceSession } from "./voice-session.js";
5
+ /**
6
+ * Which experiences the widget exposes:
7
+ * - `chat` — chat icon only (opens the chat iframe panel). The default.
8
+ * - `voice` — voice icon only (starts a WebRTC voice session).
9
+ * - `both` — both icons, sharing one trigger pill.
10
+ */
5
11
  export type WidgetMode = "chat" | "voice" | "both";
6
12
  export type TriggerButtonConfig = {
7
13
  /** Custom color overrides for light mode */
@@ -38,8 +44,17 @@ export type YakEmbedConfig = YakClientConfig & {
38
44
  getConfig?: ChatConfigProvider;
39
45
  };
40
46
  export type YakEmbedState = {
47
+ /** Whether the chat panel is open. */
41
48
  isOpen: boolean;
49
+ /** Whether the chat iframe has handshaked and can receive messages. */
42
50
  isReady: boolean;
51
+ /**
52
+ * Whether the chat is opening but not yet interactive — `isOpen && !isReady`.
53
+ * Stays true from the moment the panel opens until the iframe reports ready,
54
+ * so custom triggers can show a spinner without re-deriving it.
55
+ */
56
+ isLoading: boolean;
57
+ /** Whether the panel is expanded to (near) full-screen. */
43
58
  isExpanded: boolean;
44
59
  };
45
60
  export type YakEmbedStateListener = (state: YakEmbedState) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"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"}
package/dist/embed.js CHANGED
@@ -483,7 +483,12 @@ export class YakEmbed {
483
483
  }
484
484
  /** Get the current widget state. */
485
485
  getState() {
486
- return { isOpen: this.isOpen, isReady: this.isReady, isExpanded: this.isExpanded };
486
+ return {
487
+ isOpen: this.isOpen,
488
+ isReady: this.isReady,
489
+ isLoading: this.isOpen && !this.isReady,
490
+ isExpanded: this.isExpanded,
491
+ };
487
492
  }
488
493
  /** Subscribe to state changes. Returns an unsubscribe function. */
489
494
  onStateChange(listener) {
@@ -10,11 +10,24 @@
10
10
  * delegated to the injected `RealtimeMessageContext` so the function is
11
11
  * testable with a plain in-memory mock.
12
12
  */
13
+ /**
14
+ * Lifecycle of a voice session, in order:
15
+ * - `idle` — no session (the starting and stopped state).
16
+ * - `connecting` — establishing the WebRTC connection.
17
+ * - `listening` — connected and capturing the user's speech.
18
+ * - `thinking` — the model is processing / generating a response.
19
+ * - `speaking` — the assistant is playing audio back.
20
+ * - `error` — the session failed; see {@link VoiceMachine.errorMessage}.
21
+ */
13
22
  export type VoiceState = "idle" | "connecting" | "listening" | "thinking" | "speaking" | "error";
14
23
  export type VoiceEvent = {
15
24
  type: "start";
16
25
  } | {
17
26
  type: "connected";
27
+ }
28
+ /** An assistant-initiated turn was requested (e.g. the opening greeting). */
29
+ | {
30
+ type: "response_requested";
18
31
  } | {
19
32
  type: "speech_started";
20
33
  } | {
@@ -29,8 +42,11 @@ export type VoiceEvent = {
29
42
  type: "error";
30
43
  message: string;
31
44
  };
45
+ /** Snapshot of a voice session's state machine. */
32
46
  export interface VoiceMachine {
47
+ /** Current lifecycle state of the session. */
33
48
  state: VoiceState;
49
+ /** Human-readable failure reason — set only when `state === "error"`. */
34
50
  errorMessage?: string;
35
51
  }
36
52
  export declare const INITIAL_VOICE_MACHINE: VoiceMachine;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-machine.d.ts","sourceRoot":"","sources":["../src/voice-machine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjG,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,EAAE,YAAgC,CAAC;AAErE,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,CA4BnF;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACtD;AAmID,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAmCf"}
1
+ {"version":3,"file":"voice-machine.d.ts","sourceRoot":"","sources":["../src/voice-machine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjG,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE;AACvB,6EAA6E;GAC3E;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,KAAK,EAAE,UAAU,CAAC;IAClB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,EAAE,YAAgC,CAAC;AAErE,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,CAiCnF;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACtD;AAmID,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAmCf"}
@@ -17,6 +17,11 @@ export function voiceReducer(machine, event) {
17
17
  return machine.state === "idle" ? { state: "connecting" } : machine;
18
18
  case "connected":
19
19
  return machine.state === "connecting" ? { state: "listening" } : machine;
20
+ case "response_requested":
21
+ // The assistant is generating an unprompted turn (the opening greeting).
22
+ // Move to `thinking` so the subsequent `audio_delta` lands on `speaking`,
23
+ // matching a normal turn; no-op if we're not idling in `listening`.
24
+ return machine.state === "listening" ? { state: "thinking" } : machine;
20
25
  case "speech_started":
21
26
  if (machine.state === "idle" || machine.state === "error")
22
27
  return machine;
@@ -1 +1 @@
1
- {"version":3,"file":"voice-session.d.ts","sourceRoot":"","sources":["../src/voice-session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,KAAK,EAEV,oBAAoB,EAEpB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC;CACF;AAkBD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2DD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,eAAe,CAA6B;IACpD,6EAA6E;IAC7E,OAAO,CAAC,KAAK,CAAkC;IAC/C;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,EAAE,qBAAqB;IAKzC;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GAEpB;IAED,0DAA0D;IACnD,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIzD,QAAQ,IAAI,YAAY;IAI/B;;;;OAIG;IACI,YAAY,IAAI,MAAM;IAItB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAO9D;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+InC,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,2FAA2F;IACpF,OAAO,IAAI,IAAI;IAWtB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,mBAAmB;YAeb,aAAa;IAsC3B;;;;OAIG;YACW,WAAW;YAwBX,SAAS;IAuBvB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;YA4BhB,WAAW;IAmBzB,OAAO,CAAC,kBAAkB;YAWZ,gBAAgB;YA2BhB,QAAQ;YAuCR,QAAQ;IAMtB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,cAAc;CAevB"}
1
+ {"version":3,"file":"voice-session.d.ts","sourceRoot":"","sources":["../src/voice-session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,KAAK,EAEV,oBAAoB,EAEpB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC;CACF;AAkBD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,eAAe,CAA6B;IACpD,6EAA6E;IAC7E,OAAO,CAAC,KAAK,CAAkC;IAC/C;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,EAAE,qBAAqB;IAKzC;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GAEpB;IAED,0DAA0D;IACnD,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIzD,QAAQ,IAAI,YAAY;IAI/B;;;;OAIG;IACI,YAAY,IAAI,MAAM;IAItB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAO9D;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0JnC,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,2FAA2F;IACpF,OAAO,IAAI,IAAI;IAWtB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,mBAAmB;YAeb,aAAa;IAsC3B;;;;OAIG;YACW,WAAW;YAwBX,SAAS;IAuBvB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;YA4BhB,WAAW;IAmBzB,OAAO,CAAC,kBAAkB;YAWZ,gBAAgB;YA2BhB,QAAQ;YAuCR,QAAQ;IAMtB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,cAAc;CAevB"}
@@ -197,6 +197,17 @@ export class YakVoiceSession {
197
197
  dataChannel.onopen = () => {
198
198
  logger.debug("Voice: data channel opened");
199
199
  this.dispatch({ type: "connected" });
200
+ // Kick off an opening greeting so the assistant speaks first instead of
201
+ // waiting silently for the user. The minted session already carries the
202
+ // full instructions (persona, governance, language, "first turn" rule),
203
+ // so a bare `response.create` is enough — do NOT attach response-level
204
+ // instructions here, which would replace the session instructions.
205
+ // Skip it when the app's voice intro is "none" (`autoGreet === false`);
206
+ // a missing flag defaults to greeting for back-compat.
207
+ if (mint.autoGreet !== false) {
208
+ this.dispatch({ type: "response_requested" });
209
+ this.sendOverDataChannel({ type: "response.create" });
210
+ }
200
211
  };
201
212
  dataChannel.onclose = () => {
202
213
  logger.debug("Voice: data channel closed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yak-io/javascript",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Core JavaScript SDK for embedding yak chatbot",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -25,6 +25,7 @@
25
25
  "node": ">=18"
26
26
  },
27
27
  "files": [
28
+ "README.md",
28
29
  "dist",
29
30
  "LICENSE"
30
31
  ],
@@ -62,6 +63,7 @@
62
63
  "vitest": "^4.1.6",
63
64
  "@repo/typescript-config": "0.0.0"
64
65
  },
66
+ "homepage": "https://docs.yak.io/docs/sdks/javascript",
65
67
  "scripts": {
66
68
  "build": "tsc",
67
69
  "check-types": "tsc --noEmit",