@haikit/client 0.4.0 → 0.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.
- package/package.json +1 -1
- package/src/app.d.ts +3 -1
- package/src/app.js +19 -4
- package/src/index.d.ts +7 -0
- package/src/index.js +13 -0
package/package.json
CHANGED
package/src/app.d.ts
CHANGED
|
@@ -17,7 +17,9 @@ export interface MountChatOptions {
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Builds the shell, wires the composer, renders the transcript and mounts your
|
|
20
|
-
* surfaces. The ten-line path to a running app.
|
|
20
|
+
* surfaces. The ten-line path to a running app. It starts the conversation as
|
|
21
|
+
* soon as it opens, and again after `reset()`, so a server with an init tool
|
|
22
|
+
* runs it before the user types.
|
|
21
23
|
*
|
|
22
24
|
* It is a convenience, not the API — everything it does is built on `createChat`
|
|
23
25
|
* and `renderTranscript`. Dropping to those when this shell stops fitting is the
|
package/src/app.js
CHANGED
|
@@ -96,7 +96,7 @@ export function mountChat({
|
|
|
96
96
|
});
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
function
|
|
99
|
+
function emptyState() {
|
|
100
100
|
const empty = h("div", "hai-empty");
|
|
101
101
|
if (emptyText) empty.append(h("p", null, emptyText));
|
|
102
102
|
if (suggestions.length) {
|
|
@@ -108,13 +108,27 @@ export function mountChat({
|
|
|
108
108
|
}
|
|
109
109
|
empty.append(row);
|
|
110
110
|
}
|
|
111
|
-
|
|
111
|
+
return empty;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
const renderEmpty = () => transcript.replaceChildren(emptyState());
|
|
115
|
+
|
|
114
116
|
// ── wiring ─────────────────────────────────────────────────────────
|
|
115
|
-
chat.subscribe((state) => {
|
|
117
|
+
chat.subscribe((state, event) => {
|
|
118
|
+
// A new conversation starts at once, so the server's init tool — if it
|
|
119
|
+
// has one — runs before anything is typed.
|
|
120
|
+
if (event.type === "reset") chat.start();
|
|
121
|
+
|
|
116
122
|
if (state.blocks.length === 0) renderEmpty();
|
|
117
|
-
else
|
|
123
|
+
else {
|
|
124
|
+
renderTranscript(transcript, chat);
|
|
125
|
+
// what the conversation opened with (an init tool's row, a welcome
|
|
126
|
+
// surface) doesn't replace the suggestions; the user engaging does —
|
|
127
|
+
// a first message, or an answer to something init showed
|
|
128
|
+
if (!state.blocks.some((b) => b.kind === "user" || b.kind === "interaction")) {
|
|
129
|
+
transcript.append(emptyState());
|
|
130
|
+
}
|
|
131
|
+
}
|
|
118
132
|
|
|
119
133
|
modelEl.textContent = state.model;
|
|
120
134
|
input.disabled = state.expired !== null;
|
|
@@ -141,6 +155,7 @@ export function mountChat({
|
|
|
141
155
|
};
|
|
142
156
|
|
|
143
157
|
renderEmpty();
|
|
158
|
+
chat.start();
|
|
144
159
|
return chat;
|
|
145
160
|
}
|
|
146
161
|
|
package/src/index.d.ts
CHANGED
|
@@ -111,6 +111,13 @@ export interface Chat {
|
|
|
111
111
|
* cleared its input can then put the text back.
|
|
112
112
|
*/
|
|
113
113
|
send(text: string): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Start the conversation before the user types, so a server with an init
|
|
116
|
+
* tool runs it now and anything it shows is already there. Does nothing once
|
|
117
|
+
* this chat has a conversation, and a server without an init tool creates
|
|
118
|
+
* nothing. `mountChat` calls it when it opens and after `reset()`.
|
|
119
|
+
*/
|
|
120
|
+
start(): Promise<boolean>;
|
|
114
121
|
interact(handle: string, action: string, value: unknown): Promise<void>;
|
|
115
122
|
/** Mounts the surface for `handle` into `element`. Null if props have not arrived. */
|
|
116
123
|
mount(handle: string, element: HTMLElement): SurfaceInstance | null;
|
package/src/index.js
CHANGED
|
@@ -332,6 +332,18 @@ export function createChat({ endpoint = "/hai", registry }) {
|
|
|
332
332
|
return enqueue("/chat", { message: text });
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Start the conversation before the user types, so a server with an init
|
|
337
|
+
* tool runs it now and whatever it shows is there first. Does nothing once
|
|
338
|
+
* this chat has a conversation. A server without an init tool answers with
|
|
339
|
+
* an empty stream and creates nothing; the first message starts the
|
|
340
|
+
* conversation, as it always has. Resolves like send().
|
|
341
|
+
*/
|
|
342
|
+
async function start() {
|
|
343
|
+
if (state.conversationId || closed()) return false;
|
|
344
|
+
return enqueue("/start", {});
|
|
345
|
+
}
|
|
346
|
+
|
|
335
347
|
// A click carries nothing the user authored, and stacking them is worse than
|
|
336
348
|
// dropping them: a double-click on a picker row would resolve it and then
|
|
337
349
|
// queue a second resolution into "component is frozen". The deadline is
|
|
@@ -365,6 +377,7 @@ export function createChat({ endpoint = "/hai", registry }) {
|
|
|
365
377
|
|
|
366
378
|
return {
|
|
367
379
|
state,
|
|
380
|
+
start,
|
|
368
381
|
send,
|
|
369
382
|
interact,
|
|
370
383
|
mount,
|