@haikit/server 0.12.0 → 0.14.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
@@ -12,6 +12,13 @@ const handle = nodeHandler(hai, "/hai");
12
12
 
13
13
  Two routes: `POST /hai/chat` and `POST /hai/interact`, both streaming SSE.
14
14
 
15
+ **A conversation id is a bearer token: put the routes behind your own auth.**
16
+ `nodeHandler` does no authentication. Anyone with a conversation's id can send
17
+ to it, click in it, read its notices, and wake it, so it is only as private
18
+ as its id. `pgStore` and `memoryStore` mint unguessable ids. Before handing a
19
+ request to `nodeHandler`, check that the signed-in user owns that
20
+ conversation, as you would for any record.
21
+
15
22
  **`/hai/interact` accepts `{handle, action, value}` and nothing else.** What an
16
23
  action *means* is resolved server-side from the surface's declared contract. If
17
24
  the client could name a tool, a prompt injection inside any tool result would
@@ -113,6 +120,102 @@ tools it was given, and the browser can only send `{handle, action, value}`,
113
120
  so put every check with consequences, such as who may book what, inside the
114
121
  tool or action handler, where it runs as code.
115
122
 
123
+ **The server can tell a conversation something later, with a notice.** A
124
+ webhook confirming a booking, a job finishing: `hai.notify` sends the browser
125
+ the notice's payload now, and the model its `model` text in the next user
126
+ message the conversation records. Declare it once, beside your surfaces:
127
+
128
+ ```ts
129
+ // shared/notices.ts — imported by both halves
130
+ export const holdConfirmed = defineNotice({
131
+ name: "hold_confirmed",
132
+ version: 1,
133
+ payload: z.object({ flightId: z.string(), reference: z.string() }),
134
+ });
135
+
136
+ // server
137
+ const holdConfirmedServer = holdConfirmed.implement({
138
+ // required, like a digest: what the model hears, or null for nothing
139
+ model: (p) => `The airline confirmed the hold on ${p.flightId}, reference ${p.reference}.`,
140
+ });
141
+ const hai = createHai({ model, store, tools, surfaces, system, notices: [holdConfirmedServer] });
142
+
143
+ // anywhere, whenever: a webhook, a queue, an action handler's follow-up
144
+ await hai.notify(conversationId, holdConfirmedServer, { flightId: "AC832", reference: "QX7P2L" }, { handle: "ui_01" });
145
+ ```
146
+
147
+ The payload is typed from the contract, and checked against its schema before
148
+ it is stored. A notice that isn't listed in `notices`, a payload that fails its
149
+ schema, or a `handle` with no surface stored in the conversation is refused.
150
+ Pass a handle from the conversation's saved history, such as an action
151
+ handler's `ctx.handle`. The check is against the stored surfaces, not that
152
+ history, so a surface left behind by an overtaken turn may also pass, until a
153
+ sweep such as `@haikit/postgres`'s `sweepOrphans` removes it. That is no
154
+ promise, just harmless: the handle only says where the browser shows the
155
+ notice, the model never sees it, and a notice can't change anything.
156
+
157
+ `notify` takes no lease, so it works while a turn is streaming, while one is
158
+ parked on a question, and with nobody connected. It never touches the history
159
+ itself: the next request that records a user message takes every unread notice
160
+ in. A typed message carries them ahead of what the user typed, and an answer to
161
+ a question carries them after its tool results. Taking them in commits with
162
+ that request's history, so a turn whose save is lost leaves them unread for
163
+ the next one. A notice never starts a turn.
164
+
165
+ With any notices listed, `hello` tells the browser to open a fourth route,
166
+ `GET /hai/events?conversationId=…`. It streams the conversation's notices,
167
+ each with its sequence number as its SSE `id`, so a browser that reconnects
168
+ with `Last-Event-ID` picks up where it left off. It takes no lease, writes
169
+ nothing, and accepts nothing from the browser but which conversation and where
170
+ to resume. The `model` text never goes out on it. The browser sees that only
171
+ once a turn has taken it in, as part of the history the `context` event shows
172
+ the inspector, the same as a digest. It reads the store every two
173
+ seconds, and a store with `watch` wakes it the moment a notice lands. The
174
+ two-second read stays even then, so a lost wake-up only delays a notice.
175
+
176
+ **A `wake` notice starts a turn of its own.** Declare one with `kind: "wake"`,
177
+ and its `model` function must return text, since the turn is the model's
178
+ answer to it:
179
+
180
+ ```ts
181
+ export const fareDropped = defineNotice({ name: "fare_dropped", version: 1, kind: "wake", payload: FareDrop });
182
+ const fareDroppedServer = fareDropped.implement({
183
+ model: (p) => `The fare on ${p.flightId} dropped from $${p.was} to $${p.now}.`,
184
+ });
185
+ ```
186
+
187
+ It is sent the same way, with `hai.notify`. The turn runs where a browser is
188
+ watching: the events route, holding the conversation's stream, takes the
189
+ lease and streams the turn down that stream. The user message it records
190
+ carries every unread notice, then
191
+ `[The user has not said anything. The notifications above arrived on their own.]`.
192
+ If the conversation is busy, the route tries again, backing off from 250 ms to
193
+ 5 s, until it is free or the browser leaves. No turn starts in these cases,
194
+ and the notice rides the user's next message, as a passive one does:
195
+
196
+ - nobody is watching (a browser that connects later starts it);
197
+ - a question is waiting for an answer;
198
+ - the conversation hasn't begun, or is out of date;
199
+ - it's past `maxWakes`, by default one wake turn a minute per conversation.
200
+
201
+ ```ts
202
+ createHai({ /* … */, notices: [fareDroppedServer], maxWakes: { count: 1, perMs: 60_000 } });
203
+ ```
204
+
205
+ Several wake notices waiting at once start one turn. One held back by
206
+ `maxWakes` never wakes later. Every events stream this process has open for
207
+ the conversation hears the turn, so a second tab shows the reply too; a tab
208
+ connected to another server instance does not.
209
+
210
+ A wake turn whose model call fails before any tool has run is undone: the
211
+ history is left as it was and its notices can wake again, though the attempt
212
+ still counts against `maxWakes`. Once a tool has run, a failure keeps what
213
+ happened, the call and its result, and closes the turn. The notice never
214
+ wakes again, so no tool runs twice. When a turn ends, the stream sends
215
+ `released` once the conversation is saved and free, and the client waits for
216
+ that before it sends anything. `hai.wake(conversationId, emit)` is what the
217
+ route calls, if you serve the events stream yourself.
218
+
116
219
  **A conversation closes once any of its surfaces passes its `staleAfterMs`.**
117
220
  From then on both routes answer with an `expired` event and the model is not
118
221
  called, so a picker left open over a weekend cannot resolve against last week's
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Hai, DEFAULT_SCOPE, type HaiConfig } from "./runtime.js";
1
+ export { Hai, DEFAULT_SCOPE, type HaiConfig, type WakeOutcome } from "./runtime.js";
2
2
  export { memoryStore } from "./store.js";
3
3
  export { nodeHandler } from "./routes.js";
4
4
  import { Hai, type HaiConfig } from "./runtime.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACnD,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,QAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACnD,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,QAAoB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,aAAa,EAAkB,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAkB,MAAM,cAAc,CAAC;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAiB,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,aAAa,EAAoC,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAkB,MAAM,cAAc,CAAC;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAiB,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC"}
package/dist/routes.d.ts CHANGED
@@ -1,13 +1,17 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import type { Hai } from "./runtime.js";
3
3
  /**
4
- * Node http handler for the three routes. Returns true if it handled the
5
- * request.
4
+ * Node http handler for the three routes, and a fourth when the app sends
5
+ * notices. Returns true if it handled the request.
6
6
  *
7
- * All three stream SSE: chat and interact because both can resume the agent
8
- * loop, start because the init tool it runs can render surfaces. Note what the
9
- * interact route accepts: {handle, action, value} and nothing else. The client
10
- * cannot name a tool, a handler, or an action target.
7
+ * The three POST routes stream SSE: chat and interact because both can resume
8
+ * the agent loop, start because the init tool it runs can render surfaces.
9
+ * Note what the interact route accepts: {handle, action, value} and nothing
10
+ * else. The client cannot name a tool, a handler, or an action target.
11
+ *
12
+ * `GET /events` streams a conversation's notices, and the turns `wake`
13
+ * notices start. It accepts nothing from the browser beyond which
14
+ * conversation, and where to resume.
11
15
  */
12
16
  export declare function nodeHandler(hai: Hai, basePath?: string): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
13
17
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,SAAS,IACxB,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,OAAO,CAAC,CA4E1F"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,SAAS,IACxB,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,OAAO,CAAC,CAuF1F"}
package/dist/routes.js CHANGED
@@ -1,19 +1,29 @@
1
1
  import { isConversationBusy, isStaleLease } from "@haikit/core";
2
2
  /**
3
- * Node http handler for the three routes. Returns true if it handled the
4
- * request.
3
+ * Node http handler for the three routes, and a fourth when the app sends
4
+ * notices. Returns true if it handled the request.
5
5
  *
6
- * All three stream SSE: chat and interact because both can resume the agent
7
- * loop, start because the init tool it runs can render surfaces. Note what the
8
- * interact route accepts: {handle, action, value} and nothing else. The client
9
- * cannot name a tool, a handler, or an action target.
6
+ * The three POST routes stream SSE: chat and interact because both can resume
7
+ * the agent loop, start because the init tool it runs can render surfaces.
8
+ * Note what the interact route accepts: {handle, action, value} and nothing
9
+ * else. The client cannot name a tool, a handler, or an action target.
10
+ *
11
+ * `GET /events` streams a conversation's notices, and the turns `wake`
12
+ * notices start. It accepts nothing from the browser beyond which
13
+ * conversation, and where to resume.
10
14
  */
11
15
  export function nodeHandler(hai, basePath = "/hai") {
12
16
  return async function handle(req, res) {
13
17
  const url = new URL(req.url ?? "/", "http://localhost");
14
- if (req.method !== "POST" || !url.pathname.startsWith(basePath))
18
+ if (!url.pathname.startsWith(basePath))
15
19
  return false;
16
20
  const route = url.pathname.slice(basePath.length);
21
+ if (req.method === "GET" && route === "/events" && hai.sendsNotices) {
22
+ await streamNotices(hai, req, res, url);
23
+ return true;
24
+ }
25
+ if (req.method !== "POST")
26
+ return false;
17
27
  if (route !== "/chat" && route !== "/interact" && route !== "/start")
18
28
  return false;
19
29
  const body = await readJson(req);
@@ -40,7 +50,12 @@ export function nodeHandler(hai, basePath = "/hai") {
40
50
  }
41
51
  const emit = openSSE(res);
42
52
  if (route === "/chat" || route === "/start") {
43
- emit({ type: "hello", conversationId: conversation.id, model: hai.config.model.id });
53
+ emit({
54
+ type: "hello",
55
+ conversationId: conversation.id,
56
+ model: hai.config.model.id,
57
+ ...(hai.sendsNotices ? { events: true } : {}),
58
+ });
44
59
  }
45
60
  let superseded = false;
46
61
  try {
@@ -87,6 +102,287 @@ export function nodeHandler(hai, basePath = "/hai") {
87
102
  return true;
88
103
  };
89
104
  }
105
+ /**
106
+ * The longest a notice waits to be read. A store's `watch` makes it sooner;
107
+ * this is what still finds a notice whose wake-up was lost.
108
+ */
109
+ const POLL_MS = 2_000;
110
+ /** Proxies drop a stream that says nothing for long; a comment keeps it open. */
111
+ const HEARTBEAT_MS = 25_000;
112
+ /** Notices read from the store at a time, so a long backlog goes out page by page. */
113
+ const PAGE = 100;
114
+ /**
115
+ * Stream a conversation's notices: every one after where the browser has got
116
+ * to (`Last-Event-ID` on a reconnect, else `?after=`), then each as it lands.
117
+ * Takes no lease and writes nothing. Each notice goes out as its payload; its
118
+ * model text is not in it: that reaches the browser only as part of the
119
+ * history, in the `context` event, once a turn has taken it in.
120
+ *
121
+ * Bounded both ways. The store is read a page at a time, so a conversation
122
+ * with years of notices is never held in memory at once, and nothing more is
123
+ * written while the socket is still taking what was, so a reader that is slow
124
+ * cannot make the server buffer every notice for it.
125
+ */
126
+ async function streamNotices(hai, req, res, url) {
127
+ const { store } = hai.config;
128
+ const conversationId = url.searchParams.get("conversationId") ?? "";
129
+ const resume = Number(req.headers["last-event-id"] ?? url.searchParams.get("after") ?? 0);
130
+ let after = Number.isSafeInteger(resume) && resume > 0 ? resume : 0;
131
+ const first = await store.getNotices(conversationId, after, PAGE);
132
+ if (first === null) {
133
+ res.writeHead(404, { "content-type": "application/json" });
134
+ res.end(JSON.stringify({ error: "unknown conversation" }));
135
+ return;
136
+ }
137
+ res.writeHead(200, {
138
+ "content-type": "text/event-stream",
139
+ "cache-control": "no-cache",
140
+ connection: "keep-alive",
141
+ });
142
+ // Sent now, not with the first frame: with nothing to catch up on, that is a
143
+ // heartbeat away, and the browser's request would hang open until then.
144
+ res.flushHeaders();
145
+ const aborter = new AbortController();
146
+ const { signal } = aborter;
147
+ res.on("close", () => aborter.abort());
148
+ // Resolves once the socket has taken what is queued, or the browser has gone.
149
+ const write = async (chunk) => {
150
+ if (res.write(chunk))
151
+ return;
152
+ await new Promise((resolve) => {
153
+ const done = () => {
154
+ res.off("drain", done);
155
+ signal.removeEventListener("abort", done);
156
+ resolve();
157
+ };
158
+ res.on("drain", done);
159
+ signal.addEventListener("abort", done);
160
+ });
161
+ };
162
+ // A wake turn's events go out as they come, one frame each, and a stream
163
+ // the browser has left takes no more.
164
+ const emit = (event) => {
165
+ if (!signal.aborted && !res.writableEnded)
166
+ res.write(`data: ${JSON.stringify(event)}\n\n`);
167
+ };
168
+ // Every stream this process has open for the conversation hears a wake
169
+ // turn, not only the one whose attempt won the lease: another tab shows the
170
+ // reply too, and holds its requests until the turn lets go.
171
+ const watchers = watchersOf(hai, conversationId);
172
+ watchers.streams.add(emit);
173
+ // Joining while a wake turn runs: what it has shown so far, starting with
174
+ // its `streaming` status, so the browser holds requests until it lets go,
175
+ // and the reply's later text has a block to land in.
176
+ if (watchers.live)
177
+ for (const event of watchers.shown)
178
+ emit(event);
179
+ // Wake turns run beside the notice loop, so a notice never waits behind a
180
+ // turn, nor behind the retries while another request holds the
181
+ // conversation. One attempt at a time; a wake notice that lands meanwhile
182
+ // asks for another once it is done.
183
+ let waking = null;
184
+ let again = false;
185
+ const wake = () => {
186
+ if (!hai.wakes || signal.aborted)
187
+ return;
188
+ if (waking) {
189
+ again = true;
190
+ return;
191
+ }
192
+ waking = (async () => {
193
+ do {
194
+ again = false;
195
+ let wait = WAKE_RETRY_MS;
196
+ while (!signal.aborted && (await hai.wake(conversationId, watchers.broadcast)) === "busy") {
197
+ await pause(wait, signal);
198
+ wait = Math.min(wait * 2, WAKE_RETRY_MAX_MS);
199
+ }
200
+ } while (again && !signal.aborted);
201
+ })()
202
+ .catch((err) => emit({ type: "error", message: err.message }))
203
+ .finally(() => {
204
+ waking = null;
205
+ // a notice that asked between the loop's last look and now
206
+ if (again)
207
+ wake();
208
+ });
209
+ };
210
+ // Everything after `after`, a page at a time, until a page comes back short.
211
+ // A conversation deleted since the stream opened ends it: there is nothing
212
+ // more to wait for, and the browser's reconnect is then refused.
213
+ const catchUp = async (page = null) => {
214
+ let woken = false;
215
+ for (;;) {
216
+ const records = page ?? (await store.getNotices(conversationId, after, PAGE));
217
+ if (records === null)
218
+ return aborter.abort();
219
+ for (const n of records) {
220
+ if (signal.aborted)
221
+ return;
222
+ if (n.seq <= after)
223
+ continue;
224
+ const event = {
225
+ type: "notice",
226
+ seq: n.seq,
227
+ name: n.name,
228
+ version: n.version,
229
+ payload: n.payload,
230
+ ...(n.handle === undefined ? {} : { handle: n.handle }),
231
+ };
232
+ await write(`id: ${n.seq}\ndata: ${JSON.stringify(event)}\n\n`);
233
+ after = n.seq;
234
+ woken ||= n.kind === "wake";
235
+ }
236
+ if (records.length < PAGE || signal.aborted)
237
+ break;
238
+ page = null;
239
+ }
240
+ if (woken)
241
+ wake();
242
+ };
243
+ // a heartbeat is only for a stream gone quiet, never one already backed up
244
+ const heartbeat = setInterval(() => res.writableNeedDrain || res.write(": ping\n\n"), HEARTBEAT_MS);
245
+ const wakes = wakeups(store.watch?.(conversationId, signal), signal)[Symbol.asyncIterator]();
246
+ try {
247
+ await catchUp(first);
248
+ // A wake notice may be waiting from before this browser connected: one
249
+ // that arrived while nobody watched, or while the conversation was busy.
250
+ wake();
251
+ // Watching starts before the next read, so a notice that landed after the
252
+ // backlog was read is either in that read or wakes the loop.
253
+ let next = wakes.next();
254
+ await catchUp();
255
+ while (!signal.aborted) {
256
+ if ((await next).done)
257
+ break;
258
+ next = wakes.next();
259
+ await catchUp();
260
+ }
261
+ }
262
+ finally {
263
+ clearInterval(heartbeat);
264
+ aborter.abort();
265
+ watchers.streams.delete(emit);
266
+ if (!watchers.streams.size)
267
+ forgetWatchers(hai, conversationId, watchers);
268
+ await wakes.return?.();
269
+ res.end();
270
+ }
271
+ }
272
+ /** Fold a wake turn's frame into what it has shown so far. */
273
+ function remember(shown, event) {
274
+ const block = (id) => shown.find((e) => e.type === "block_start" && e.block.id === id)?.block;
275
+ if (event.type === "block_start")
276
+ shown.push({ ...event, block: { ...event.block } });
277
+ else if (event.type === "text_delta") {
278
+ const b = block(event.id);
279
+ if (b && "text" in b)
280
+ b.text += event.text;
281
+ }
282
+ else if (event.type === "block_update") {
283
+ const b = block(event.id);
284
+ if (b)
285
+ Object.assign(b, { status: event.status, ms: event.ms, result: event.result });
286
+ }
287
+ else if (event.type === "progress") {
288
+ const { type, toolId, ...fields } = event;
289
+ const b = block(toolId);
290
+ if (b?.kind === "tool")
291
+ b.progress = { ...b.progress, ...fields };
292
+ }
293
+ else
294
+ shown.push(event);
295
+ }
296
+ const watching = new WeakMap();
297
+ function watchersOf(hai, conversationId) {
298
+ let byConversation = watching.get(hai);
299
+ if (!byConversation)
300
+ watching.set(hai, (byConversation = new Map()));
301
+ const map = byConversation;
302
+ let watchers = byConversation.get(conversationId);
303
+ if (!watchers) {
304
+ const fresh = {
305
+ streams: new Set(),
306
+ live: false,
307
+ shown: [],
308
+ // A wake turn's frames, to every stream. `live` from its first
309
+ // `streaming` until `released`, with what it has shown kept meanwhile,
310
+ // for a stream that joins part way.
311
+ broadcast: (event) => {
312
+ if (event.type === "status" && event.status === "streaming" && !fresh.live) {
313
+ fresh.live = true;
314
+ fresh.shown = [];
315
+ }
316
+ if (fresh.live)
317
+ remember(fresh.shown, event);
318
+ if (event.type === "released") {
319
+ fresh.live = false;
320
+ fresh.shown = [];
321
+ }
322
+ for (const send of fresh.streams)
323
+ send(event);
324
+ // the turn outlived every stream that watched it: nothing left to keep
325
+ if (!fresh.live && !fresh.streams.size && map.get(conversationId) === fresh)
326
+ map.delete(conversationId);
327
+ },
328
+ };
329
+ byConversation.set(conversationId, (watchers = fresh));
330
+ }
331
+ return watchers;
332
+ }
333
+ function forgetWatchers(hai, conversationId, watchers) {
334
+ // a wake turn still running keeps its entry, so a stream that joins later still hears it
335
+ if (!watchers.live && watching.get(hai)?.get(conversationId) === watchers)
336
+ watching.get(hai).delete(conversationId);
337
+ }
338
+ /** The first wait before trying a wake turn again on a busy conversation, and the longest. */
339
+ const WAKE_RETRY_MS = 250;
340
+ const WAKE_RETRY_MAX_MS = 5_000;
341
+ /** Wait `ms`, or until `signal` aborts. */
342
+ const pause = (ms, signal) => new Promise((resolve) => {
343
+ const done = () => {
344
+ clearTimeout(timer);
345
+ signal.removeEventListener("abort", done);
346
+ resolve();
347
+ };
348
+ const timer = setTimeout(done, ms);
349
+ signal.addEventListener("abort", done);
350
+ });
351
+ /**
352
+ * When the events route reads next: every POLL_MS, and sooner whenever the
353
+ * store's `watch` says a notice may have landed. `watch` alone is not enough.
354
+ * A wake-up can be lost, and a LISTEN connection can drop, and either would
355
+ * leave the stream open on heartbeats with a notice it never reads. A `watch`
356
+ * that ends or fails leaves the reads every POLL_MS to carry on.
357
+ */
358
+ async function* wakeups(watch, signal) {
359
+ const steps = watch?.[Symbol.asyncIterator]();
360
+ // started now, so the watch is listening before the caller's next read
361
+ let step = steps?.next().then((r) => !r.done, () => false) ?? null;
362
+ try {
363
+ while (!signal.aborted) {
364
+ let timer;
365
+ let onAbort;
366
+ const tick = new Promise((resolve) => {
367
+ onAbort = () => resolve("tick");
368
+ timer = setTimeout(onAbort, POLL_MS);
369
+ signal.addEventListener("abort", onAbort);
370
+ });
371
+ const woke = await Promise.race(step ? [tick, step] : [tick]);
372
+ clearTimeout(timer);
373
+ signal.removeEventListener("abort", onAbort);
374
+ if (signal.aborted)
375
+ return;
376
+ // the watch stepped: listen for the next; it ended or failed: stop listening
377
+ if (woke !== "tick")
378
+ step = woke ? steps.next().then((r) => !r.done, () => false) : null;
379
+ yield;
380
+ }
381
+ }
382
+ finally {
383
+ await steps?.return?.();
384
+ }
385
+ }
90
386
  function openSSE(res) {
91
387
  res.writeHead(200, {
92
388
  "content-type": "text/event-stream",
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
package/dist/runtime.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type AnySurfaceImpl, type Conversation, type Emit, type ModelAdapter, type StoreAdapter, type Tool } from "@haikit/core";
1
+ import { type AnyNoticeImpl, type AnySurfaceImpl, type Conversation, type Emit, type ModelAdapter, type Notify, type StoreAdapter, type Tool } from "@haikit/core";
2
2
  export interface HaiConfig {
3
3
  model: ModelAdapter;
4
4
  store: StoreAdapter;
@@ -33,7 +33,30 @@ export interface HaiConfig {
33
33
  * model gets "already ran" back instead of running it again.
34
34
  */
35
35
  init?: Tool;
36
+ /**
37
+ * The notices this app sends with `hai.notify`. A notice not listed here is
38
+ * refused, as an unregistered surface is. With any listed, the browser opens
39
+ * the events stream (`GET {base}/events`) to receive them.
40
+ */
41
+ notices?: AnyNoticeImpl[];
42
+ /**
43
+ * How many turns `wake` notices may start in a conversation, per window.
44
+ * Default one a minute. A wake turn is a model call nobody asked for, and a
45
+ * tool inside one could send another wake notice: past the limit, a wake
46
+ * notice is left to ride the user's next message, like a passive one. The
47
+ * browser still shows it at once.
48
+ */
49
+ maxWakes?: {
50
+ count: number;
51
+ perMs: number;
52
+ };
36
53
  }
54
+ /**
55
+ * What `hai.wake` did: started a turn; started one that failed, and put the
56
+ * conversation back as it was; found the conversation busy; was held back by
57
+ * `maxWakes`; or had nothing to do.
58
+ */
59
+ export type WakeOutcome = "woke" | "failed" | "busy" | "limited" | "idle";
37
60
  /**
38
61
  * Appended to every app's system prompt unless `scope` says otherwise. Generic
39
62
  * on purpose: the app's own `system` says what it is for, and this keeps the
@@ -44,10 +67,47 @@ export declare class Hai {
44
67
  readonly config: HaiConfig;
45
68
  private readonly surfaces;
46
69
  private readonly tools;
70
+ private readonly notices;
71
+ private readonly maxWakes;
47
72
  /** What the model gets as its system prompt: the app's, then the scope. */
48
73
  readonly system: string;
49
74
  private seq;
50
75
  constructor(config: HaiConfig);
76
+ /** Whether this app sends notices, so the browser should open the events stream. */
77
+ get sendsNotices(): boolean;
78
+ /** Whether any of its notices are `wake` notices, which the events route starts turns for. */
79
+ get wakes(): boolean;
80
+ /**
81
+ * Send a notice to a conversation: its payload to the browser now, over the
82
+ * events stream, and its model text to the model in the next user message
83
+ * the conversation records.
84
+ *
85
+ * Takes no lease, so it works while a turn is streaming, while one is
86
+ * parked, and with nobody connected. It never runs a turn itself: a passive
87
+ * notice waits for the user, and a `wake` notice's turn is started later, by
88
+ * the events route, where a browser is watching (see `wake`).
89
+ */
90
+ readonly notify: Notify;
91
+ /**
92
+ * Start a turn for the `wake` notices this conversation hasn't taken in, if
93
+ * it can take one now. The events route calls this, and streams the turn
94
+ * to the browser that is watching; nothing else starts one.
95
+ *
96
+ * It takes the lease like any request, and releases it before it resolves.
97
+ * No turn starts while a question waits (a user message there would follow
98
+ * an unanswered tool_use), before the conversation has begun (it would skip
99
+ * init), once it is out of date, or past `maxWakes`; the notices then ride
100
+ * the user's next message, as passive ones do.
101
+ */
102
+ wake(conversationId: string, emit: Emit): Promise<WakeOutcome>;
103
+ private wakeTurn;
104
+ /**
105
+ * The notices this conversation's history hasn't taken in yet: their model
106
+ * text as blocks for the user message this request is about to record, and
107
+ * the number to set `noticedThrough` to when it does. Set it only where the
108
+ * message is pushed, so a request refused before then takes nothing in.
109
+ */
110
+ private unreadNotices;
51
111
  private nid;
52
112
  private buildQueryUiTool;
53
113
  send(conversation: Conversation, text: string, emit: Emit): Promise<void>;
@@ -59,9 +119,10 @@ export declare class Hai {
59
119
  */
60
120
  start(conversation: Conversation, emit: Emit): Promise<void>;
61
121
  /**
62
- * Run the init tool as the conversation's first tool call, after `text` —
63
- * the user's first message, or STARTED when it runs before one. Returns
64
- * true when it parked the conversation on an elicit surface.
122
+ * Run the init tool as the conversation's first tool call, after `message` —
123
+ * the user's first message, or STARTED when it runs before one, with any
124
+ * unread notices, which take the conversation's notices through `through`.
125
+ * Returns true when it parked the conversation on an elicit surface.
65
126
  *
66
127
  * Nothing reaches the history until the tool has succeeded — not even the
67
128
  * user's message — so a refused start leaves the conversation exactly as
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,YAAY,EAEjB,KAAK,YAAY,EACjB,KAAK,IAAI,EAIV,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AASD;;;;GAIG;AACH,eAAO,MAAM,aAAa,ufAQ+B,CAAC;AAuB1D,qBAAa,GAAG;IACd,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,GAAG,CAAK;gBAEJ,MAAM,EAAE,SAAS;IAsB7B,OAAO,CAAC,GAAG;IAMX,OAAO,CAAC,gBAAgB;IAkFlB,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC/E;;;;;OAKG;IACG,KAAK,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlE;;;;;;;;OAQG;YACW,OAAO;IA+Df,QAAQ,CACZ,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EACzD,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,IAAI,CAAC;IA2GhB;;;;;;;;;;;;;;;;OAgBG;YACW,eAAe;YA4Cf,OAAO;YA0EP,UAAU;YA6NV,WAAW;CAa1B"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAGlB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,YAAY,EACjB,KAAK,MAAM,EAEX,KAAK,YAAY,EACjB,KAAK,IAAI,EAIV,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAS1E;;;;GAIG;AACH,eAAO,MAAM,aAAa,ufAQ+B,CAAC;AA0B1D,qBAAa,GAAG;IACd,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,GAAG,CAAK;gBAEJ,MAAM,EAAE,SAAS;IAoC7B,oFAAoF;IACpF,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,8FAA8F;IAC9F,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAgCrB;IAEF;;;;;;;;;;OAUG;IACG,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC;YA0CtD,QAAQ;IAkFtB;;;;;OAKG;YACW,aAAa;IAgB3B,OAAO,CAAC,GAAG;IAMX,OAAO,CAAC,gBAAgB;IAkFlB,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C/E;;;;;OAKG;IACG,KAAK,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE;;;;;;;;;OASG;YACW,OAAO;IAqEf,QAAQ,CACZ,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EACzD,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,IAAI,CAAC;IAmHhB;;;;;;;;;;;;;;;;OAgBG;YACW,eAAe;YA4Cf,OAAO;YA0EP,UAAU;YA6NV,WAAW;CAa1B"}