@haikit/client 0.20.4 → 0.21.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
@@ -126,8 +126,8 @@ mountChat({
126
126
  If something on the network holds the stream back, as HTTPS-inspecting
127
127
  corporate proxies (Netskope, Zscaler) do, the chat polls instead. The server
128
128
  greets every stream with a comment the moment it opens. A stream that brings
129
- no bytes at all within `eventsFallbackMs` (default 8 s, a `createChat`
130
- option) is dropped for short polls, whose responses end and so get through.
129
+ no bytes at all within `eventsFallbackMs` (default 8 s, an option of
130
+ `createChat` and `mountChat`) is dropped for short polls, whose responses end and so get through.
131
131
  Notices, signals and wake turns all arrive by polling, a little later than
132
132
  they would stream. Each poll asks the server to hold for `pollHoldMs`
133
133
  (default 15 s, the server's maximum) when nothing is new; set it lower
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haikit/client",
3
- "version": "0.20.4",
3
+ "version": "0.21.0",
4
4
  "description": "The haikit browser runtime: streams tool payloads into interactive UI surfaces. Plain ESM, no build step, no dependencies.",
5
5
  "keywords": [
6
6
  "haikit",
package/src/app.d.ts CHANGED
@@ -7,7 +7,7 @@ export interface MountChatOptions {
7
7
  notices?: NoticeRegistry;
8
8
  /** Handlers for the signals the server sends, by signal name. */
9
9
  signals?: SignalRegistry;
10
- /** Base path the server's two routes are mounted at. Default `/hai`. */
10
+ /** Where the server's routes are: `nodeHandler`'s base path. Default `/hai`. */
11
11
  endpoint?: string;
12
12
  title?: string;
13
13
  subtitle?: string;
@@ -27,6 +27,10 @@ export interface MountChatOptions {
27
27
  * dark setting, or a `data-hai-theme` already in the page's markup.
28
28
  */
29
29
  theme?: "light" | "dark";
30
+ /** Passed to `createChat`: how long the events stream may be silent before the chat polls. Default 8000 ms. */
31
+ eventsFallbackMs?: number;
32
+ /** Passed to `createChat`: how long each poll asks the server to hold. Default 15000 ms. */
33
+ pollHoldMs?: number;
30
34
  }
31
35
 
32
36
  /**
package/src/app.js CHANGED
@@ -95,6 +95,8 @@ function dropFavicon() {
95
95
  * placeholder?: string,
96
96
  * emptyText?: string,
97
97
  * theme?: "light" | "dark",
98
+ * eventsFallbackMs?: number,
99
+ * pollHoldMs?: number,
98
100
  * }} options
99
101
  */
100
102
  export function mountChat({
@@ -110,8 +112,11 @@ export function mountChat({
110
112
  placeholder = "message…",
111
113
  emptyText = "",
112
114
  theme,
115
+ eventsFallbackMs,
116
+ pollHoldMs,
113
117
  }) {
114
- const chat = createChat({ endpoint, registry, notices, signals });
118
+ // undefined leaves createChat's defaults
119
+ const chat = createChat({ endpoint, registry, notices, signals, eventsFallbackMs, pollHoldMs });
115
120
  const id = `hai-${++shells}`;
116
121
 
117
122
  // Unset, the page follows the system. A pin goes on the root, where hai.css
@@ -250,6 +255,10 @@ export function mountChat({
250
255
  shell.append(top, main);
251
256
  root.replaceChildren(shell);
252
257
 
258
+ // A start that fails, such as the network being down, is reported, not
259
+ // left unhandled: the first message starts the conversation anyway.
260
+ const start = () => chat.start().catch((err) => console.error("[haikit] the conversation couldn't start:", err));
261
+
253
262
  // ── composer ───────────────────────────────────────────────────────
254
263
  // The input grows with what is typed, up to the height hai.css allows.
255
264
  const fit = () => {
@@ -270,12 +279,21 @@ export function mountChat({
270
279
  // A message queued behind a long turn can still be turned away later, if
271
280
  // the conversation goes out of date before its turn comes. Give the text
272
281
  // back then, unless something new has been typed since.
273
- sending.then((sent) => {
274
- if (!sent && !input.value) {
282
+ const giveBack = () => {
283
+ if (!input.value) {
275
284
  input.value = text;
276
285
  fit();
277
286
  }
278
- });
287
+ };
288
+ sending.then(
289
+ (sent) => sent || giveBack(),
290
+ // the request itself failed, such as the network being down: the text
291
+ // goes back, and the error is reported rather than left unhandled
292
+ (err) => {
293
+ console.error("[haikit] the message wasn't sent:", err);
294
+ giveBack();
295
+ },
296
+ );
279
297
  };
280
298
 
281
299
  // ── empty state ────────────────────────────────────────────────────
@@ -342,7 +360,7 @@ export function mountChat({
342
360
 
343
361
  // A new conversation starts at once, so the server's init tool — if it
344
362
  // has one — runs before anything is typed.
345
- if (event.type === "reset") chat.start();
363
+ if (event.type === "reset") start();
346
364
 
347
365
  render();
348
366
 
@@ -378,7 +396,7 @@ export function mountChat({
378
396
  render();
379
397
  // a server without an init tool sends nothing until the first message
380
398
  if (inspectorBody) renderInspector(inspectorBody, chat.state.context);
381
- chat.start();
399
+ start();
382
400
  return chat;
383
401
  }
384
402