@yak-io/svelte 0.3.0 β†’ 0.4.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,26 +1,37 @@
1
1
  # @yak-io/svelte
2
2
 
3
- Svelte integration for the Yak embeddable chat widget. Uses Svelte stores for reactive state.
3
+ > πŸ“š **Full documentation:** https://docs.yak.io/docs/sdks/svelte
4
+ >
5
+ > πŸ€– **For LLMs / AI agents:** https://docs.yak.io/llms.txt
4
6
 
5
- ## Installation
7
+ Svelte SDK for [Yak](https://docs.yak.io) β€” an embeddable AI assistant (text chat **and** push-to-talk voice) for web apps. `createYakProvider` returns a `YakApi` whose reactive state is exposed as Svelte `Readable` stores.
6
8
 
7
9
  ```bash
8
10
  pnpm add @yak-io/svelte
9
11
  ```
10
12
 
13
+ ## Exports
14
+
15
+ | Export | Kind | Purpose |
16
+ | --- | --- | --- |
17
+ | `createYakProvider(options)` | fn | Create a widget instance. Returns a `YakApi` with stores + `mount`/`destroy`. |
18
+ | `enableYakLogging` / `disableYakLogging` / `isYakLoggingEnabled` | fn | Toggle verbose SDK logging. |
19
+ | Types | β€” | `YakProviderOptions`, `YakApi`, `ToolCallEventHandler`, plus core types from `@yak-io/javascript`. |
20
+
11
21
  ## Quickstart
12
22
 
13
- ### 1. Initialize the provider (module scope)
23
+ ### 1. Create the provider (module scope)
14
24
 
15
25
  ```ts
16
26
  // src/yak.ts
17
- import { onMount, onDestroy } from "svelte";
27
+ import { goto } from "$app/navigation";
18
28
  import { createYakProvider } from "@yak-io/svelte";
19
29
 
20
30
  export const yak = createYakProvider({
21
31
  appId: import.meta.env.VITE_YAK_APP_ID,
32
+ mode: "both", // "chat" | "voice" | "both" β€” default "chat"
33
+ trigger: true, // show the floating launcher pill
22
34
  theme: { position: "bottom-right", colorMode: "system" },
23
- trigger: { label: "Ask with AI" },
24
35
  getConfig: async () => {
25
36
  const res = await fetch("/api/yak");
26
37
  return res.json();
@@ -35,19 +46,17 @@ export const yak = createYakProvider({
35
46
  if (!data.ok) throw new Error(data.error);
36
47
  return data.result;
37
48
  },
38
- onRedirect: (path) => {
39
- goto(path);
40
- },
49
+ onRedirect: (path) => goto(path),
41
50
  });
42
51
  ```
43
52
 
44
- ### 2. Mount and destroy in your root component
53
+ ### 2. Mount/destroy in your root component
45
54
 
46
55
  ```svelte
47
- <!-- App.svelte -->
56
+ <!-- +layout.svelte -->
48
57
  <script lang="ts">
49
58
  import { onMount, onDestroy } from "svelte";
50
- import { yak } from "./yak.ts";
59
+ import { yak } from "$lib/yak";
51
60
 
52
61
  onMount(() => yak.mount());
53
62
  onDestroy(() => yak.destroy());
@@ -56,69 +65,85 @@ export const yak = createYakProvider({
56
65
  <slot />
57
66
  ```
58
67
 
59
- ### 3. Use stores in components
68
+ ### 3. Use the stores
69
+
70
+ `isOpen`/`isReady` are `Readable` stores β€” read them with `$`:
71
+
72
+ ```svelte
73
+ <script lang="ts">
74
+ import { yak } from "$lib/yak";
75
+ const { isOpen, open, openWithPrompt } = yak;
76
+ </script>
77
+
78
+ <button on:click={open}>Open chat</button>
79
+ <button on:click={() => openWithPrompt("How do I get started?")}>Get help</button>
80
+ {#if $isOpen}<span>Chat is open</span>{/if}
81
+ ```
82
+
83
+ ## Voice
60
84
 
61
- `isOpen` and `isReady` are Svelte `Readable` stores β€” subscribe with `$`:
85
+ Set `mode: "voice"` or `mode: "both"`, then drive the session. `voiceStart()` must run from a user gesture (browser mic requirement).
62
86
 
63
87
  ```svelte
64
88
  <script lang="ts">
65
- import { yak } from "../yak.ts";
66
- const { isOpen, isReady, open, openWithPrompt } = yak;
89
+ import { yak } from "$lib/yak";
90
+ const { voiceToggle, voiceLoading, voiceMachine } = yak;
67
91
  </script>
68
92
 
69
- <button on:click={open}>Open Chat</button>
70
- {#if $isOpen}
71
- <p>Chat is open</p>
72
- {/if}
73
- {#if $isOpen && !$isReady}
74
- <p>Loading…</p>
75
- {/if}
93
+ <button on:click={voiceToggle} disabled={$voiceLoading}>
94
+ {$voiceMachine.state === "idle" ? "Start voice" : `Stop (${$voiceMachine.state})`}
95
+ </button>
76
96
  ```
77
97
 
78
- ### 4. Subscribe to tool events
98
+ ## Tool events
79
99
 
80
100
  ```ts
81
101
  yak.subscribeToToolEvents((event) => {
82
- if (event.ok && event.name.startsWith("tasks.")) {
83
- refreshTasks();
84
- }
102
+ // { name, args, ok, result?, error? }
103
+ if (event.ok && event.name.startsWith("tasks.")) refreshTasks();
85
104
  });
86
105
  ```
87
106
 
88
- ## API Reference
107
+ ## API reference
89
108
 
90
109
  ### `createYakProvider(options)`
91
110
 
92
- Creates a Yak widget instance. Returns a `YakApi` with Svelte stores for reactive state.
93
-
94
- You must call `yak.mount()` in `onMount()` and `yak.destroy()` in `onDestroy()`.
95
-
96
- **Options:**
97
-
98
- | Option | Type | Description |
99
- |--------|------|-------------|
100
- | `appId` | `string` | Your Yak app ID |
101
- | `getConfig` | `ChatConfigProvider` | Async function returning routes + tools. Called on first open. |
102
- | `onToolCall` | `ToolCallHandler` | Handle tool invocations from the assistant |
103
- | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | Handle GraphQL schema tool calls |
104
- | `onRESTSchemaCall` | `RESTSchemaHandler` | Handle REST/OpenAPI schema tool calls |
105
- | `theme` | `Theme` | Position, color mode, and custom colors |
106
- | `onRedirect` | `(path: string) => void` | Navigation handler (defaults to `window.location.assign`) |
107
- | `disableRestartButton` | `boolean` | Hide the restart session button |
108
- | `trigger` | `boolean \| TriggerButtonConfig` | Built-in trigger button |
111
+ Returns a `YakApi`. You must call `yak.mount()` in `onMount()` and `yak.destroy()` in `onDestroy()`.
112
+
113
+ | Option | Type | Default | Description |
114
+ | --- | --- | --- | --- |
115
+ | `appId` | `string` | β€” | Your Yak app ID (required). |
116
+ | `mode` | `"chat" \| "voice" \| "both"` | `"chat"` | Which surfaces the widget exposes. |
117
+ | `trigger` | `boolean \| TriggerButtonConfig` | `false` | Show the floating pill. **Set `true`** to display it; `TriggerButtonConfig` recolors it. |
118
+ | `getConfig` | `ChatConfigProvider` | β€” | Async provider of routes + tools. Called on open / voice start. |
119
+ | `onToolCall` | `ToolCallHandler` | β€” | Executes a tool the assistant calls. |
120
+ | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | β€” | Handles GraphQL schema tool calls. |
121
+ | `onRESTSchemaCall` | `RESTSchemaHandler` | β€” | Handles REST/OpenAPI schema tool calls. |
122
+ | `theme` | `Theme` | β€” | Position, color mode, and colors. |
123
+ | `onRedirect` | `(path: string) => void` | `window.location.assign` | Navigation handler. |
124
+ | `disableRestartButton` | `boolean` | `false` | Hide the restart-session button. |
109
125
 
110
126
  ### `YakApi`
111
127
 
112
128
  ```ts
113
129
  type YakApi = {
114
- isOpen: Readable<boolean>; // Svelte store
115
- isReady: Readable<boolean>; // Svelte store
130
+ // chat
131
+ isOpen: Readable<boolean>;
132
+ isReady: Readable<boolean>;
133
+ chatLoading: Readable<boolean>; // isOpen && !isReady
116
134
  open: () => void;
117
135
  close: () => void;
118
136
  openWithPrompt: (prompt: string) => void;
119
137
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
120
- mount: () => void; // Call in onMount()
121
- destroy: () => void; // Call in onDestroy()
138
+ // voice
139
+ voiceMachine: Readable<VoiceMachine>; // { state, errorMessage? }
140
+ voiceLoading: Readable<boolean>; // state === "connecting"
141
+ voiceStart: () => Promise<void>;
142
+ voiceStop: () => Promise<void>;
143
+ voiceToggle: () => Promise<void>;
144
+ // lifecycle
145
+ mount: () => void; // call in onMount()
146
+ destroy: () => void; // call in onDestroy()
122
147
  };
123
148
  ```
124
149
 
@@ -127,9 +152,7 @@ type YakApi = {
127
152
  ```ts
128
153
  import { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/svelte";
129
154
 
130
- enableYakLogging(); // Enable verbose SDK logs
131
- disableYakLogging(); // Disable SDK logs
132
- isYakLoggingEnabled(); // β†’ boolean
155
+ enableYakLogging(); // verbose SDK logs
133
156
  ```
134
157
 
135
158
  ## Types
@@ -143,11 +166,13 @@ import type {
143
166
  ToolCallHandler,
144
167
  ToolCallEvent,
145
168
  Theme,
146
- TriggerButtonConfig,
169
+ WidgetMode,
147
170
  WidgetPosition,
171
+ VoiceState,
172
+ VoiceMachine,
148
173
  } from "@yak-io/svelte";
149
174
  ```
150
175
 
151
176
  ## License
152
177
 
153
- Proprietary β€” see LICENSE file.
178
+ Proprietary β€” see [LICENSE](./LICENSE).
@@ -13,18 +13,35 @@ export type YakProviderOptions = {
13
13
  disableRestartButton?: boolean;
14
14
  trigger?: boolean | TriggerButtonConfig;
15
15
  };
16
+ /** Handle for controlling the Yak widget β€” chat + voice β€” from Svelte (stores). */
16
17
  export type YakApi = {
18
+ /** Whether the chat panel is currently open. */
17
19
  isOpen: Readable<boolean>;
20
+ /** Whether the chat iframe is ready to receive messages. */
18
21
  isReady: Readable<boolean>;
22
+ /** Whether the chat is opening but not yet interactive (`isOpen && !isReady`). */
23
+ chatLoading: Readable<boolean>;
24
+ /** Open the chat panel. */
19
25
  open: () => void;
26
+ /** Close the chat panel. */
20
27
  close: () => void;
28
+ /** Open the chat panel and send a specific prompt. */
21
29
  openWithPrompt: (prompt: string) => void;
30
+ /** Subscribe to tool-call completion events; returns an unsubscribe function. */
22
31
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
32
+ /** Current voice state-machine snapshot. `idle` when mode is `chat`. */
23
33
  voiceMachine: Readable<VoiceMachine>;
34
+ /** Whether the voice session is establishing its connection (`state === "connecting"`). */
35
+ voiceLoading: Readable<boolean>;
36
+ /** Start a voice session. Must be invoked from a user gesture. */
24
37
  voiceStart: () => Promise<void>;
38
+ /** Stop the current voice session. */
25
39
  voiceStop: () => Promise<void>;
40
+ /** Toggle voice: start if idle/error, stop if active. */
26
41
  voiceToggle: () => Promise<void>;
42
+ /** Mount the widget into the DOM. Call once (e.g. in `onMount`). */
27
43
  mount: () => void;
44
+ /** Tear down the widget and remove its listeners. */
28
45
  destroy: () => void;
29
46
  };
30
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAGzB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,QAAQ,EAAsB,MAAM,cAAc,CAAC;AAIjE,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAEnB,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAErE,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACrC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAiGrE"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAGzB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAW,KAAK,QAAQ,EAAsB,MAAM,cAAc,CAAC;AAI1E,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CACzC,CAAC;AAEF,mFAAmF;AACnF,MAAM,MAAM,MAAM,GAAG;IAEnB,gDAAgD;IAChD,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1B,4DAA4D;IAC5D,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,kFAAkF;IAClF,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,sDAAsD;IACtD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,iFAAiF;IACjF,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAErE,wEAAwE;IACxE,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACrC,2FAA2F;IAC3F,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,kEAAkE;IAClE,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,sCAAsC;IACtC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,yDAAyD;IACzD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,oEAAoE;IACpE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,qDAAqD;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAyGrE"}
package/dist/provider.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { INITIAL_VOICE_MACHINE, logger, YakEmbed, } from "@yak-io/javascript";
2
- import { readonly, writable } from "svelte/store";
2
+ import { derived, readonly, writable } from "svelte/store";
3
3
  // ── Provider factory ────────────────────────────────────────────────────────
4
4
  /**
5
5
  * Creates a yak widget instance (chat + voice) with Svelte stores.
@@ -86,9 +86,12 @@ export function createYakProvider(options) {
86
86
  logger.warn("Voice start failed", err);
87
87
  }
88
88
  };
89
+ const chatLoading = derived([isOpen, isReady], ([$isOpen, $isReady]) => $isOpen && !$isReady);
90
+ const voiceLoading = derived(voiceMachine, ($voiceMachine) => $voiceMachine.state === "connecting");
89
91
  return {
90
92
  isOpen: readonly(isOpen),
91
93
  isReady: readonly(isReady),
94
+ chatLoading,
92
95
  open: () => embed.open(),
93
96
  close: () => embed.close(),
94
97
  openWithPrompt: (prompt) => embed.openWithPrompt(prompt),
@@ -99,6 +102,7 @@ export function createYakProvider(options) {
99
102
  };
100
103
  },
101
104
  voiceMachine: readonly(voiceMachine),
105
+ voiceLoading,
102
106
  voiceStart,
103
107
  voiceStop: () => embed.voiceStop(),
104
108
  voiceToggle: () => embed.voiceToggle(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yak-io/svelte",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Svelte 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
  ],
@@ -41,7 +42,7 @@
41
42
  "./package.json": "./package.json"
42
43
  },
43
44
  "dependencies": {
44
- "@yak-io/javascript": "0.8.0"
45
+ "@yak-io/javascript": "0.9.0"
45
46
  },
46
47
  "peerDependencies": {
47
48
  "svelte": "^5.0.0"
@@ -52,6 +53,7 @@
52
53
  "typescript": "^5.3.0",
53
54
  "@repo/typescript-config": "0.0.0"
54
55
  },
56
+ "homepage": "https://docs.yak.io/docs/sdks/svelte",
55
57
  "scripts": {
56
58
  "build": "tsc",
57
59
  "check-types": "tsc --noEmit",