@haikit/server 0.2.0 → 0.3.1
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/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +41 -2
- package/dist/routes.js.map +1 -1
- package/dist/runtime.d.ts +0 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +26 -16
- package/dist/runtime.js.map +1 -1
- package/dist/store.d.ts +25 -3
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +75 -14
- package/dist/store.js.map +1 -1
- package/package.json +2 -2
- package/src/routes.ts +35 -2
- package/src/runtime.ts +33 -22
- package/src/store.ts +93 -13
package/dist/routes.d.ts.map
CHANGED
|
@@ -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;
|
|
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;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,SAAS,IACxB,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,OAAO,CAAC,CAiE1F"}
|
package/dist/routes.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isConversationBusy, isStaleLease } from "@haikit/core";
|
|
1
2
|
/**
|
|
2
3
|
* Node http handler for the two routes. Returns true if it handled the request.
|
|
3
4
|
*
|
|
@@ -14,11 +15,24 @@ export function nodeHandler(hai, basePath = "/hai") {
|
|
|
14
15
|
if (route !== "/chat" && route !== "/interact")
|
|
15
16
|
return false;
|
|
16
17
|
const body = await readJson(req);
|
|
17
|
-
|
|
18
|
+
// Before the SSE stream opens, because a rejected load has no stream to
|
|
19
|
+
// report into — and an uncaught throw here would take down the request.
|
|
20
|
+
let conversation;
|
|
21
|
+
try {
|
|
22
|
+
conversation = await hai.config.store.loadConversation(body.conversationId);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
if (!isConversationBusy(err))
|
|
26
|
+
throw err;
|
|
27
|
+
res.writeHead(409, { "content-type": "application/json" });
|
|
28
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
18
31
|
const emit = openSSE(res);
|
|
19
32
|
if (route === "/chat") {
|
|
20
33
|
emit({ type: "hello", conversationId: conversation.id, model: hai.config.model.id });
|
|
21
34
|
}
|
|
35
|
+
let superseded = false;
|
|
22
36
|
try {
|
|
23
37
|
if (route === "/chat") {
|
|
24
38
|
await hai.send(conversation, String(body.message ?? ""), emit);
|
|
@@ -28,9 +42,34 @@ export function nodeHandler(hai, basePath = "/hai") {
|
|
|
28
42
|
}
|
|
29
43
|
}
|
|
30
44
|
catch (err) {
|
|
45
|
+
if (isStaleLease(err))
|
|
46
|
+
superseded = true;
|
|
31
47
|
emit({ type: "error", message: err.message });
|
|
32
48
|
}
|
|
33
|
-
|
|
49
|
+
finally {
|
|
50
|
+
// The lease lives exactly as long as the request. Releasing it any
|
|
51
|
+
// earlier — when a turn parks, say — lets the client's next interaction
|
|
52
|
+
// arrive before this request has finished writing, and the two turns
|
|
53
|
+
// interleave on one conversation.
|
|
54
|
+
//
|
|
55
|
+
// Only the expiry is cleared. The token has to survive so the save below
|
|
56
|
+
// can still prove this request is the rightful holder.
|
|
57
|
+
conversation.leaseUntil = null;
|
|
58
|
+
try {
|
|
59
|
+
// A turn that already hit a fence knows its save would be rejected too;
|
|
60
|
+
// attempting it only repeats the same error to the client.
|
|
61
|
+
if (!superseded)
|
|
62
|
+
await hai.config.store.saveConversation(conversation);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
// Overtaken while we were slow: another turn already wrote newer state
|
|
66
|
+
// under a fresh token. Dropping this write is the correct outcome, but
|
|
67
|
+
// the client asked for something it is not getting, so say so.
|
|
68
|
+
if (!isStaleLease(err))
|
|
69
|
+
throw err;
|
|
70
|
+
emit({ type: "error", message: err.message });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
34
73
|
res.end();
|
|
35
74
|
return true;
|
|
36
75
|
};
|
package/dist/routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -7,8 +7,6 @@ export interface HaiConfig {
|
|
|
7
7
|
surfaces: AnySurfaceImpl[];
|
|
8
8
|
/** Guard against runaway tool loops. */
|
|
9
9
|
maxHops?: number;
|
|
10
|
-
/** Turn lease duration; a dead process releases after this. */
|
|
11
|
-
leaseMs?: number;
|
|
12
10
|
}
|
|
13
11
|
export declare class Hai {
|
|
14
12
|
readonly config: HaiConfig;
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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,EACjB,KAAK,YAAY,EACjB,KAAK,IAAI,EAGV,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,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,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,GAAG,CAAK;gBAEJ,MAAM,EAAE,SAAS;IAU7B,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;IA4BzE,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;YA8DF,OAAO;YAuEP,UAAU;YAsEV,WAAW;CAa1B"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { estTokens, makeCap, } from "@haikit/core";
|
|
2
|
-
const LEASE_MS = 120_000;
|
|
1
|
+
import { estTokens, isStaleLease, makeCap, } from "@haikit/core";
|
|
3
2
|
export class Hai {
|
|
4
3
|
config;
|
|
5
4
|
surfaces = new Map();
|
|
@@ -94,7 +93,9 @@ export class Hai {
|
|
|
94
93
|
// receive a tool_result, so close the pending one out honestly first.
|
|
95
94
|
if (conversation.status === "awaiting" && conversation.pending) {
|
|
96
95
|
const { toolUseId, handle, results, digest } = conversation.pending;
|
|
97
|
-
|
|
96
|
+
// Recorded on the conversation, not the payload, so it commits with the
|
|
97
|
+
// history that explains it — see Conversation.frozen.
|
|
98
|
+
conversation.frozen.push(handle);
|
|
98
99
|
emit({ type: "ui_state", handle, state: "frozen" });
|
|
99
100
|
conversation.messages.push({
|
|
100
101
|
role: "user",
|
|
@@ -114,11 +115,18 @@ export class Hai {
|
|
|
114
115
|
await this.runTurn(conversation, emit);
|
|
115
116
|
}
|
|
116
117
|
async interact(conversation, input, emit) {
|
|
118
|
+
// The payload row carries a conversation id, but that alone is not enough.
|
|
119
|
+
// A turn that rendered a surface and was then overtaken leaves a row behind:
|
|
120
|
+
// its conversation save is rejected, so the winning history never records
|
|
121
|
+
// the handle, yet the row and the browser that mounted it both still exist.
|
|
122
|
+
// Membership of the surviving `handles` is what makes those orphans inert.
|
|
123
|
+
if (!conversation.handles.includes(input.handle))
|
|
124
|
+
throw new Error("unknown handle");
|
|
125
|
+
if (conversation.frozen.includes(input.handle))
|
|
126
|
+
throw new Error("component is frozen");
|
|
117
127
|
const record = await this.config.store.getPayload(input.handle, conversation.id);
|
|
118
128
|
if (!record)
|
|
119
129
|
throw new Error("unknown handle");
|
|
120
|
-
if (record.state === "frozen")
|
|
121
|
-
throw new Error("component is frozen");
|
|
122
130
|
const impl = this.surfaces.get(record.component);
|
|
123
131
|
if (!impl)
|
|
124
132
|
throw new Error(`unknown component: ${record.component}`);
|
|
@@ -139,7 +147,7 @@ export class Hai {
|
|
|
139
147
|
if (spec.kind === "resolve") {
|
|
140
148
|
if (conversation.pending?.handle !== input.handle)
|
|
141
149
|
throw new Error("nothing awaiting this handle");
|
|
142
|
-
|
|
150
|
+
conversation.frozen.push(input.handle);
|
|
143
151
|
emit({ type: "ui_state", handle: input.handle, state: "frozen", selection: value });
|
|
144
152
|
emit({ type: "block_start", block: { kind: "interaction", id: this.nid("b"), handle: input.handle, label } });
|
|
145
153
|
conversation.messages.push({
|
|
@@ -166,7 +174,6 @@ export class Hai {
|
|
|
166
174
|
// ──────────────────────────────────────────────── the agent loop
|
|
167
175
|
async runTurn(conversation, emit) {
|
|
168
176
|
conversation.status = "streaming";
|
|
169
|
-
conversation.leaseUntil = Date.now() + (this.config.leaseMs ?? LEASE_MS);
|
|
170
177
|
emit({ type: "status", status: "streaming" });
|
|
171
178
|
const toolDefs = [...this.tools.values()].map((t) => ({
|
|
172
179
|
name: t.name,
|
|
@@ -216,7 +223,6 @@ export class Hai {
|
|
|
216
223
|
// Hold the resolved siblings too — the API is all-or-nothing per batch.
|
|
217
224
|
conversation.status = "awaiting";
|
|
218
225
|
conversation.pending = { ...parked, results };
|
|
219
|
-
conversation.leaseUntil = null;
|
|
220
226
|
emit({ type: "status", status: "awaiting" });
|
|
221
227
|
await this.emitContext(conversation, emit);
|
|
222
228
|
return;
|
|
@@ -224,7 +230,6 @@ export class Hai {
|
|
|
224
230
|
conversation.messages.push({ role: "user", content: results });
|
|
225
231
|
}
|
|
226
232
|
conversation.status = "idle";
|
|
227
|
-
conversation.leaseUntil = null;
|
|
228
233
|
emit({ type: "status", status: "idle" });
|
|
229
234
|
await this.emitContext(conversation, emit);
|
|
230
235
|
}
|
|
@@ -247,8 +252,7 @@ export class Hai {
|
|
|
247
252
|
version: impl.surface.version,
|
|
248
253
|
props: parsed,
|
|
249
254
|
mode: surfaceMode,
|
|
250
|
-
|
|
251
|
-
});
|
|
255
|
+
}, conversation.leaseToken);
|
|
252
256
|
conversation.handles.push(handle);
|
|
253
257
|
// The split, in two lines. Digest -> model. Payload -> browser.
|
|
254
258
|
const digest = impl.impl.digest(parsed, { handle });
|
|
@@ -276,16 +280,22 @@ export class Hai {
|
|
|
276
280
|
return { ret, mode };
|
|
277
281
|
}
|
|
278
282
|
catch (err) {
|
|
283
|
+
// A tool error is information for the model; a lost lease is not. Fencing
|
|
284
|
+
// exists so a superseded turn stops — converting StaleLease into "tool
|
|
285
|
+
// failed" would hand it back to the model and keep paying for hops whose
|
|
286
|
+
// output the fenced save is going to discard anyway.
|
|
287
|
+
if (isStaleLease(err))
|
|
288
|
+
throw err;
|
|
279
289
|
return { ret: { model: `${call.name} failed: ${err.message}` }, mode: null };
|
|
280
290
|
}
|
|
281
291
|
}
|
|
282
292
|
async emitContext(conversation, emit) {
|
|
293
|
+
// One batched read, not one per handle: this runs on every turn, and a
|
|
294
|
+
// conversation accumulates handles for as long as it lives.
|
|
295
|
+
const records = await this.config.store.getPayloads(conversation.handles, conversation.id);
|
|
283
296
|
let uiTokens = 0;
|
|
284
|
-
for (const
|
|
285
|
-
|
|
286
|
-
if (record)
|
|
287
|
-
uiTokens += estTokens(record.props);
|
|
288
|
-
}
|
|
297
|
+
for (const record of records)
|
|
298
|
+
uiTokens += estTokens(record.props);
|
|
289
299
|
emit({
|
|
290
300
|
type: "context",
|
|
291
301
|
messages: conversation.messages,
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type StoreAdapter } from "@haikit/core";
|
|
2
|
+
export interface MemoryStoreOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Turn lease TTL. A process that dies mid-turn strands the conversation for
|
|
5
|
+
* this long; too short and a slow turn is overtaken while still running.
|
|
6
|
+
*
|
|
7
|
+
* This is the single authority on lease duration — the runtime does not renew
|
|
8
|
+
* or override it. Being overtaken is safe rather than merely unlikely: the
|
|
9
|
+
* superseded turn's save is rejected by its fencing token.
|
|
10
|
+
*/
|
|
11
|
+
leaseMs?: number;
|
|
12
|
+
}
|
|
2
13
|
/**
|
|
3
|
-
* In-memory store. Implements the same interface a Postgres store would
|
|
14
|
+
* In-memory store. Implements the same interface a Postgres store would, and
|
|
15
|
+
* enforces the same rules — scoping, leasing and fencing are all checked here
|
|
16
|
+
* even though this store could get away without them. A reference
|
|
17
|
+
* implementation that only enforces what it happens to need is what let three
|
|
18
|
+
* of these bugs exist in the first place.
|
|
19
|
+
*
|
|
20
|
+
* Conversations are copied in and out rather than shared by reference. That is
|
|
21
|
+
* not an optimisation detail: a store that hands back a live object cannot
|
|
22
|
+
* detect a stale writer at all, because the caller's copy *is* the stored one.
|
|
23
|
+
* The copy is a JSON round trip specifically because that is what a `jsonb`
|
|
24
|
+
* column does — anything a real store would silently drop (undefined, a Date's
|
|
25
|
+
* type, a class instance) gets dropped here too, in development.
|
|
4
26
|
*
|
|
5
27
|
* Swapping this for a durable store is the single highest-value change for
|
|
6
28
|
* production: a parked `elicit` turn is durable state, and losing `pending`
|
|
7
29
|
* makes a conversation permanently unsendable.
|
|
8
30
|
*/
|
|
9
|
-
export declare function memoryStore(): StoreAdapter;
|
|
31
|
+
export declare function memoryStore(options?: MemoryStoreOptions): StoreAdapter;
|
|
10
32
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,YAAY,CA4F1E"}
|
package/dist/store.js
CHANGED
|
@@ -1,36 +1,93 @@
|
|
|
1
|
+
import { ConversationBusy, StaleLease, } from "@haikit/core";
|
|
2
|
+
const LEASE_MS = 120_000;
|
|
1
3
|
/**
|
|
2
|
-
* In-memory store. Implements the same interface a Postgres store would
|
|
4
|
+
* In-memory store. Implements the same interface a Postgres store would, and
|
|
5
|
+
* enforces the same rules — scoping, leasing and fencing are all checked here
|
|
6
|
+
* even though this store could get away without them. A reference
|
|
7
|
+
* implementation that only enforces what it happens to need is what let three
|
|
8
|
+
* of these bugs exist in the first place.
|
|
9
|
+
*
|
|
10
|
+
* Conversations are copied in and out rather than shared by reference. That is
|
|
11
|
+
* not an optimisation detail: a store that hands back a live object cannot
|
|
12
|
+
* detect a stale writer at all, because the caller's copy *is* the stored one.
|
|
13
|
+
* The copy is a JSON round trip specifically because that is what a `jsonb`
|
|
14
|
+
* column does — anything a real store would silently drop (undefined, a Date's
|
|
15
|
+
* type, a class instance) gets dropped here too, in development.
|
|
3
16
|
*
|
|
4
17
|
* Swapping this for a durable store is the single highest-value change for
|
|
5
18
|
* production: a parked `elicit` turn is durable state, and losing `pending`
|
|
6
19
|
* makes a conversation permanently unsendable.
|
|
7
20
|
*/
|
|
8
|
-
export function memoryStore() {
|
|
21
|
+
export function memoryStore(options = {}) {
|
|
22
|
+
const leaseMs = options.leaseMs ?? LEASE_MS;
|
|
23
|
+
// Zero or negative makes every lease expire the moment it is taken, so every
|
|
24
|
+
// load acquires and the one-turn-in-flight guarantee silently disappears.
|
|
25
|
+
// Infinity would strand a crashed turn's conversation forever. Refuse both
|
|
26
|
+
// here, loudly, rather than run with no mutual exclusion at all.
|
|
27
|
+
if (!Number.isFinite(leaseMs) || leaseMs <= 0) {
|
|
28
|
+
throw new RangeError(`leaseMs must be a positive, finite number of milliseconds (got ${leaseMs})`);
|
|
29
|
+
}
|
|
9
30
|
const conversations = new Map();
|
|
10
31
|
const payloads = new Map();
|
|
11
32
|
let convSeq = 0;
|
|
12
33
|
let handleSeq = 0;
|
|
34
|
+
const copy = (value) => JSON.parse(JSON.stringify(value));
|
|
35
|
+
const newToken = () => globalThis.crypto.randomUUID();
|
|
36
|
+
/** Every durable mutation presents the token it was issued. A holder that has
|
|
37
|
+
* been superseded must stop writing rather than run to completion and be
|
|
38
|
+
* discarded at the end.
|
|
39
|
+
*
|
|
40
|
+
* Atomic here only because nothing awaits between this check and the write
|
|
41
|
+
* that follows it: JavaScript cannot interleave another request into a
|
|
42
|
+
* synchronous run. Put an `await` between them and the compare-and-set the
|
|
43
|
+
* contract requires is silently gone. */
|
|
44
|
+
const fence = (conversationId, leaseToken) => {
|
|
45
|
+
const stored = conversations.get(conversationId);
|
|
46
|
+
// Mirrors the SQL shape in the contract: no matching row fails the
|
|
47
|
+
// compare-and-set exactly like a superseded token does. A null token needs
|
|
48
|
+
// no case of its own — a stored lease is never null, so it cannot match,
|
|
49
|
+
// just as `NULL = x` is never true. What must not happen is treating a
|
|
50
|
+
// missing token as "unfenced" and skipping this comparison.
|
|
51
|
+
if (!stored)
|
|
52
|
+
throw new StaleLease(conversationId, "does not exist — no lease was ever issued for it");
|
|
53
|
+
if (stored.leaseToken !== leaseToken)
|
|
54
|
+
throw new StaleLease(conversationId);
|
|
55
|
+
};
|
|
13
56
|
return {
|
|
14
57
|
async loadConversation(id) {
|
|
15
|
-
if (id && conversations.has(id))
|
|
16
|
-
|
|
58
|
+
if (id && conversations.has(id)) {
|
|
59
|
+
const stored = conversations.get(id);
|
|
60
|
+
if (stored.leaseUntil !== null && stored.leaseUntil > Date.now()) {
|
|
61
|
+
throw new ConversationBusy(stored.id);
|
|
62
|
+
}
|
|
63
|
+
// Reissuing the token is what fences out whoever held it before.
|
|
64
|
+
stored.leaseUntil = Date.now() + leaseMs;
|
|
65
|
+
stored.leaseToken = newToken();
|
|
66
|
+
return copy(stored);
|
|
67
|
+
}
|
|
17
68
|
const conversation = {
|
|
18
69
|
id: `conv_${++convSeq}`,
|
|
19
70
|
status: "idle",
|
|
20
71
|
messages: [],
|
|
21
72
|
handles: [],
|
|
73
|
+
frozen: [],
|
|
22
74
|
pending: null,
|
|
23
|
-
leaseUntil:
|
|
75
|
+
leaseUntil: Date.now() + leaseMs,
|
|
76
|
+
leaseToken: newToken(),
|
|
24
77
|
};
|
|
25
78
|
conversations.set(conversation.id, conversation);
|
|
26
|
-
return conversation;
|
|
79
|
+
return copy(conversation);
|
|
27
80
|
},
|
|
28
81
|
async saveConversation(conversation) {
|
|
29
|
-
|
|
82
|
+
// Same rule as every other fenced write. Not an upsert: a conversation
|
|
83
|
+
// this store never issued a lease for cannot be created by saving it.
|
|
84
|
+
fence(conversation.id, conversation.leaseToken);
|
|
85
|
+
conversations.set(conversation.id, copy(conversation));
|
|
30
86
|
},
|
|
31
|
-
async putPayload(record) {
|
|
87
|
+
async putPayload(record, leaseToken) {
|
|
88
|
+
fence(record.conversationId, leaseToken);
|
|
32
89
|
const handle = `ui_${String(++handleSeq).padStart(2, "0")}`;
|
|
33
|
-
payloads.set(handle, { ...record, handle, createdAt: Date.now() });
|
|
90
|
+
payloads.set(handle, copy({ ...record, handle, createdAt: Date.now() }));
|
|
34
91
|
return handle;
|
|
35
92
|
},
|
|
36
93
|
/** Scoped: a handle from another conversation must not resolve. */
|
|
@@ -38,12 +95,16 @@ export function memoryStore() {
|
|
|
38
95
|
const record = payloads.get(handle);
|
|
39
96
|
if (!record || record.conversationId !== conversationId)
|
|
40
97
|
return null;
|
|
41
|
-
return record;
|
|
98
|
+
return copy(record);
|
|
42
99
|
},
|
|
43
|
-
async
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
record
|
|
100
|
+
async getPayloads(handles, conversationId) {
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const handle of handles) {
|
|
103
|
+
const record = payloads.get(handle);
|
|
104
|
+
if (record && record.conversationId === conversationId)
|
|
105
|
+
out.push(copy(record));
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
47
108
|
},
|
|
48
109
|
};
|
|
49
110
|
}
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haikit/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "The haikit server runtime: agent loop, elicit state machine, derived query_ui, and the interaction security boundary.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"haikit",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"prepack": "npm --prefix ../.. run build"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@haikit/core": "0.
|
|
39
|
+
"@haikit/core": "0.3.1",
|
|
40
40
|
"@types/node": ">=22"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
package/src/routes.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { isConversationBusy, isStaleLease } from "@haikit/core";
|
|
2
3
|
import type { Emit, WireEvent } from "@haikit/core";
|
|
3
4
|
import type { Hai } from "./runtime.js";
|
|
4
5
|
|
|
@@ -18,13 +19,25 @@ export function nodeHandler(hai: Hai, basePath = "/hai") {
|
|
|
18
19
|
if (route !== "/chat" && route !== "/interact") return false;
|
|
19
20
|
|
|
20
21
|
const body = await readJson(req);
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
// Before the SSE stream opens, because a rejected load has no stream to
|
|
24
|
+
// report into — and an uncaught throw here would take down the request.
|
|
25
|
+
let conversation;
|
|
26
|
+
try {
|
|
27
|
+
conversation = await hai.config.store.loadConversation(body.conversationId);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (!isConversationBusy(err)) throw err;
|
|
30
|
+
res.writeHead(409, { "content-type": "application/json" });
|
|
31
|
+
res.end(JSON.stringify({ error: (err as Error).message }));
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
22
34
|
|
|
23
35
|
const emit = openSSE(res);
|
|
24
36
|
if (route === "/chat") {
|
|
25
37
|
emit({ type: "hello", conversationId: conversation.id, model: hai.config.model.id });
|
|
26
38
|
}
|
|
27
39
|
|
|
40
|
+
let superseded = false;
|
|
28
41
|
try {
|
|
29
42
|
if (route === "/chat") {
|
|
30
43
|
await hai.send(conversation, String(body.message ?? ""), emit);
|
|
@@ -36,10 +49,30 @@ export function nodeHandler(hai: Hai, basePath = "/hai") {
|
|
|
36
49
|
);
|
|
37
50
|
}
|
|
38
51
|
} catch (err) {
|
|
52
|
+
if (isStaleLease(err)) superseded = true;
|
|
39
53
|
emit({ type: "error", message: (err as Error).message });
|
|
54
|
+
} finally {
|
|
55
|
+
// The lease lives exactly as long as the request. Releasing it any
|
|
56
|
+
// earlier — when a turn parks, say — lets the client's next interaction
|
|
57
|
+
// arrive before this request has finished writing, and the two turns
|
|
58
|
+
// interleave on one conversation.
|
|
59
|
+
//
|
|
60
|
+
// Only the expiry is cleared. The token has to survive so the save below
|
|
61
|
+
// can still prove this request is the rightful holder.
|
|
62
|
+
conversation.leaseUntil = null;
|
|
63
|
+
try {
|
|
64
|
+
// A turn that already hit a fence knows its save would be rejected too;
|
|
65
|
+
// attempting it only repeats the same error to the client.
|
|
66
|
+
if (!superseded) await hai.config.store.saveConversation(conversation);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
// Overtaken while we were slow: another turn already wrote newer state
|
|
69
|
+
// under a fresh token. Dropping this write is the correct outcome, but
|
|
70
|
+
// the client asked for something it is not getting, so say so.
|
|
71
|
+
if (!isStaleLease(err)) throw err;
|
|
72
|
+
emit({ type: "error", message: (err as Error).message });
|
|
73
|
+
}
|
|
40
74
|
}
|
|
41
75
|
|
|
42
|
-
await hai.config.store.saveConversation(conversation);
|
|
43
76
|
res.end();
|
|
44
77
|
return true;
|
|
45
78
|
};
|
package/src/runtime.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
estTokens,
|
|
3
|
+
isStaleLease,
|
|
3
4
|
makeCap,
|
|
4
5
|
type AnySurfaceImpl,
|
|
5
6
|
type Conversation,
|
|
@@ -19,12 +20,8 @@ export interface HaiConfig {
|
|
|
19
20
|
surfaces: AnySurfaceImpl[];
|
|
20
21
|
/** Guard against runaway tool loops. */
|
|
21
22
|
maxHops?: number;
|
|
22
|
-
/** Turn lease duration; a dead process releases after this. */
|
|
23
|
-
leaseMs?: number;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
const LEASE_MS = 120_000;
|
|
27
|
-
|
|
28
25
|
export class Hai {
|
|
29
26
|
readonly config: HaiConfig;
|
|
30
27
|
private readonly surfaces = new Map<string, AnySurfaceImpl>();
|
|
@@ -134,7 +131,9 @@ export class Hai {
|
|
|
134
131
|
// receive a tool_result, so close the pending one out honestly first.
|
|
135
132
|
if (conversation.status === "awaiting" && conversation.pending) {
|
|
136
133
|
const { toolUseId, handle, results, digest } = conversation.pending;
|
|
137
|
-
|
|
134
|
+
// Recorded on the conversation, not the payload, so it commits with the
|
|
135
|
+
// history that explains it — see Conversation.frozen.
|
|
136
|
+
conversation.frozen.push(handle);
|
|
138
137
|
emit({ type: "ui_state", handle, state: "frozen" });
|
|
139
138
|
conversation.messages.push({
|
|
140
139
|
role: "user",
|
|
@@ -160,9 +159,17 @@ export class Hai {
|
|
|
160
159
|
input: { handle: string; action: string; value: unknown },
|
|
161
160
|
emit: Emit,
|
|
162
161
|
): Promise<void> {
|
|
162
|
+
// The payload row carries a conversation id, but that alone is not enough.
|
|
163
|
+
// A turn that rendered a surface and was then overtaken leaves a row behind:
|
|
164
|
+
// its conversation save is rejected, so the winning history never records
|
|
165
|
+
// the handle, yet the row and the browser that mounted it both still exist.
|
|
166
|
+
// Membership of the surviving `handles` is what makes those orphans inert.
|
|
167
|
+
if (!conversation.handles.includes(input.handle)) throw new Error("unknown handle");
|
|
168
|
+
|
|
169
|
+
if (conversation.frozen.includes(input.handle)) throw new Error("component is frozen");
|
|
170
|
+
|
|
163
171
|
const record = await this.config.store.getPayload(input.handle, conversation.id);
|
|
164
172
|
if (!record) throw new Error("unknown handle");
|
|
165
|
-
if (record.state === "frozen") throw new Error("component is frozen");
|
|
166
173
|
|
|
167
174
|
const impl = this.surfaces.get(record.component);
|
|
168
175
|
if (!impl) throw new Error(`unknown component: ${record.component}`);
|
|
@@ -184,7 +191,7 @@ export class Hai {
|
|
|
184
191
|
|
|
185
192
|
if (spec.kind === "resolve") {
|
|
186
193
|
if (conversation.pending?.handle !== input.handle) throw new Error("nothing awaiting this handle");
|
|
187
|
-
|
|
194
|
+
conversation.frozen.push(input.handle);
|
|
188
195
|
emit({ type: "ui_state", handle: input.handle, state: "frozen", selection: value });
|
|
189
196
|
emit({ type: "block_start", block: { kind: "interaction", id: this.nid("b"), handle: input.handle, label } });
|
|
190
197
|
|
|
@@ -215,7 +222,6 @@ export class Hai {
|
|
|
215
222
|
|
|
216
223
|
private async runTurn(conversation: Conversation, emit: Emit): Promise<void> {
|
|
217
224
|
conversation.status = "streaming";
|
|
218
|
-
conversation.leaseUntil = Date.now() + (this.config.leaseMs ?? LEASE_MS);
|
|
219
225
|
emit({ type: "status", status: "streaming" });
|
|
220
226
|
|
|
221
227
|
const toolDefs = [...this.tools.values()].map((t) => ({
|
|
@@ -272,7 +278,6 @@ export class Hai {
|
|
|
272
278
|
// Hold the resolved siblings too — the API is all-or-nothing per batch.
|
|
273
279
|
conversation.status = "awaiting";
|
|
274
280
|
conversation.pending = { ...parked, results };
|
|
275
|
-
conversation.leaseUntil = null;
|
|
276
281
|
emit({ type: "status", status: "awaiting" });
|
|
277
282
|
await this.emitContext(conversation, emit);
|
|
278
283
|
return;
|
|
@@ -282,7 +287,6 @@ export class Hai {
|
|
|
282
287
|
}
|
|
283
288
|
|
|
284
289
|
conversation.status = "idle";
|
|
285
|
-
conversation.leaseUntil = null;
|
|
286
290
|
emit({ type: "status", status: "idle" });
|
|
287
291
|
await this.emitContext(conversation, emit);
|
|
288
292
|
}
|
|
@@ -308,14 +312,16 @@ export class Hai {
|
|
|
308
312
|
// Validate before storing: props may originate outside this process.
|
|
309
313
|
const parsed = impl.surface.props.parse(props);
|
|
310
314
|
|
|
311
|
-
const handle = await this.config.store.putPayload(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
315
|
+
const handle = await this.config.store.putPayload(
|
|
316
|
+
{
|
|
317
|
+
conversationId: conversation.id,
|
|
318
|
+
component: impl.surface.name,
|
|
319
|
+
version: impl.surface.version,
|
|
320
|
+
props: parsed,
|
|
321
|
+
mode: surfaceMode,
|
|
322
|
+
},
|
|
323
|
+
conversation.leaseToken,
|
|
324
|
+
);
|
|
319
325
|
|
|
320
326
|
conversation.handles.push(handle);
|
|
321
327
|
|
|
@@ -346,16 +352,21 @@ export class Hai {
|
|
|
346
352
|
const ret = await tool.run(input, ctx);
|
|
347
353
|
return { ret, mode };
|
|
348
354
|
} catch (err) {
|
|
355
|
+
// A tool error is information for the model; a lost lease is not. Fencing
|
|
356
|
+
// exists so a superseded turn stops — converting StaleLease into "tool
|
|
357
|
+
// failed" would hand it back to the model and keep paying for hops whose
|
|
358
|
+
// output the fenced save is going to discard anyway.
|
|
359
|
+
if (isStaleLease(err)) throw err;
|
|
349
360
|
return { ret: { model: `${call.name} failed: ${(err as Error).message}` }, mode: null };
|
|
350
361
|
}
|
|
351
362
|
}
|
|
352
363
|
|
|
353
364
|
private async emitContext(conversation: Conversation, emit: Emit) {
|
|
365
|
+
// One batched read, not one per handle: this runs on every turn, and a
|
|
366
|
+
// conversation accumulates handles for as long as it lives.
|
|
367
|
+
const records = await this.config.store.getPayloads(conversation.handles, conversation.id);
|
|
354
368
|
let uiTokens = 0;
|
|
355
|
-
for (const
|
|
356
|
-
const record = await this.config.store.getPayload(handle, conversation.id);
|
|
357
|
-
if (record) uiTokens += estTokens(record.props);
|
|
358
|
-
}
|
|
369
|
+
for (const record of records) uiTokens += estTokens(record.props);
|
|
359
370
|
emit({
|
|
360
371
|
type: "context",
|
|
361
372
|
messages: conversation.messages,
|
package/src/store.ts
CHANGED
|
@@ -1,40 +1,116 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
ConversationBusy,
|
|
3
|
+
StaleLease,
|
|
4
|
+
type Conversation,
|
|
5
|
+
type PayloadRecord,
|
|
6
|
+
type StoreAdapter,
|
|
7
|
+
} from "@haikit/core";
|
|
8
|
+
|
|
9
|
+
const LEASE_MS = 120_000;
|
|
10
|
+
|
|
11
|
+
export interface MemoryStoreOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Turn lease TTL. A process that dies mid-turn strands the conversation for
|
|
14
|
+
* this long; too short and a slow turn is overtaken while still running.
|
|
15
|
+
*
|
|
16
|
+
* This is the single authority on lease duration — the runtime does not renew
|
|
17
|
+
* or override it. Being overtaken is safe rather than merely unlikely: the
|
|
18
|
+
* superseded turn's save is rejected by its fencing token.
|
|
19
|
+
*/
|
|
20
|
+
leaseMs?: number;
|
|
21
|
+
}
|
|
2
22
|
|
|
3
23
|
/**
|
|
4
|
-
* In-memory store. Implements the same interface a Postgres store would
|
|
24
|
+
* In-memory store. Implements the same interface a Postgres store would, and
|
|
25
|
+
* enforces the same rules — scoping, leasing and fencing are all checked here
|
|
26
|
+
* even though this store could get away without them. A reference
|
|
27
|
+
* implementation that only enforces what it happens to need is what let three
|
|
28
|
+
* of these bugs exist in the first place.
|
|
29
|
+
*
|
|
30
|
+
* Conversations are copied in and out rather than shared by reference. That is
|
|
31
|
+
* not an optimisation detail: a store that hands back a live object cannot
|
|
32
|
+
* detect a stale writer at all, because the caller's copy *is* the stored one.
|
|
33
|
+
* The copy is a JSON round trip specifically because that is what a `jsonb`
|
|
34
|
+
* column does — anything a real store would silently drop (undefined, a Date's
|
|
35
|
+
* type, a class instance) gets dropped here too, in development.
|
|
5
36
|
*
|
|
6
37
|
* Swapping this for a durable store is the single highest-value change for
|
|
7
38
|
* production: a parked `elicit` turn is durable state, and losing `pending`
|
|
8
39
|
* makes a conversation permanently unsendable.
|
|
9
40
|
*/
|
|
10
|
-
export function memoryStore(): StoreAdapter {
|
|
41
|
+
export function memoryStore(options: MemoryStoreOptions = {}): StoreAdapter {
|
|
42
|
+
const leaseMs = options.leaseMs ?? LEASE_MS;
|
|
43
|
+
// Zero or negative makes every lease expire the moment it is taken, so every
|
|
44
|
+
// load acquires and the one-turn-in-flight guarantee silently disappears.
|
|
45
|
+
// Infinity would strand a crashed turn's conversation forever. Refuse both
|
|
46
|
+
// here, loudly, rather than run with no mutual exclusion at all.
|
|
47
|
+
if (!Number.isFinite(leaseMs) || leaseMs <= 0) {
|
|
48
|
+
throw new RangeError(`leaseMs must be a positive, finite number of milliseconds (got ${leaseMs})`);
|
|
49
|
+
}
|
|
11
50
|
const conversations = new Map<string, Conversation>();
|
|
12
51
|
const payloads = new Map<string, PayloadRecord>();
|
|
13
52
|
let convSeq = 0;
|
|
14
53
|
let handleSeq = 0;
|
|
15
54
|
|
|
55
|
+
const copy = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;
|
|
56
|
+
const newToken = () => globalThis.crypto.randomUUID();
|
|
57
|
+
|
|
58
|
+
/** Every durable mutation presents the token it was issued. A holder that has
|
|
59
|
+
* been superseded must stop writing rather than run to completion and be
|
|
60
|
+
* discarded at the end.
|
|
61
|
+
*
|
|
62
|
+
* Atomic here only because nothing awaits between this check and the write
|
|
63
|
+
* that follows it: JavaScript cannot interleave another request into a
|
|
64
|
+
* synchronous run. Put an `await` between them and the compare-and-set the
|
|
65
|
+
* contract requires is silently gone. */
|
|
66
|
+
const fence = (conversationId: string, leaseToken: string | null) => {
|
|
67
|
+
const stored = conversations.get(conversationId);
|
|
68
|
+
// Mirrors the SQL shape in the contract: no matching row fails the
|
|
69
|
+
// compare-and-set exactly like a superseded token does. A null token needs
|
|
70
|
+
// no case of its own — a stored lease is never null, so it cannot match,
|
|
71
|
+
// just as `NULL = x` is never true. What must not happen is treating a
|
|
72
|
+
// missing token as "unfenced" and skipping this comparison.
|
|
73
|
+
if (!stored) throw new StaleLease(conversationId, "does not exist — no lease was ever issued for it");
|
|
74
|
+
if (stored.leaseToken !== leaseToken) throw new StaleLease(conversationId);
|
|
75
|
+
};
|
|
76
|
+
|
|
16
77
|
return {
|
|
17
78
|
async loadConversation(id) {
|
|
18
|
-
if (id && conversations.has(id))
|
|
79
|
+
if (id && conversations.has(id)) {
|
|
80
|
+
const stored = conversations.get(id)!;
|
|
81
|
+
if (stored.leaseUntil !== null && stored.leaseUntil > Date.now()) {
|
|
82
|
+
throw new ConversationBusy(stored.id);
|
|
83
|
+
}
|
|
84
|
+
// Reissuing the token is what fences out whoever held it before.
|
|
85
|
+
stored.leaseUntil = Date.now() + leaseMs;
|
|
86
|
+
stored.leaseToken = newToken();
|
|
87
|
+
return copy(stored);
|
|
88
|
+
}
|
|
19
89
|
const conversation: Conversation = {
|
|
20
90
|
id: `conv_${++convSeq}`,
|
|
21
91
|
status: "idle",
|
|
22
92
|
messages: [],
|
|
23
93
|
handles: [],
|
|
94
|
+
frozen: [],
|
|
24
95
|
pending: null,
|
|
25
|
-
leaseUntil:
|
|
96
|
+
leaseUntil: Date.now() + leaseMs,
|
|
97
|
+
leaseToken: newToken(),
|
|
26
98
|
};
|
|
27
99
|
conversations.set(conversation.id, conversation);
|
|
28
|
-
return conversation;
|
|
100
|
+
return copy(conversation);
|
|
29
101
|
},
|
|
30
102
|
|
|
31
103
|
async saveConversation(conversation) {
|
|
32
|
-
|
|
104
|
+
// Same rule as every other fenced write. Not an upsert: a conversation
|
|
105
|
+
// this store never issued a lease for cannot be created by saving it.
|
|
106
|
+
fence(conversation.id, conversation.leaseToken);
|
|
107
|
+
conversations.set(conversation.id, copy(conversation));
|
|
33
108
|
},
|
|
34
109
|
|
|
35
|
-
async putPayload(record) {
|
|
110
|
+
async putPayload(record, leaseToken) {
|
|
111
|
+
fence(record.conversationId, leaseToken);
|
|
36
112
|
const handle = `ui_${String(++handleSeq).padStart(2, "0")}`;
|
|
37
|
-
payloads.set(handle, { ...record, handle, createdAt: Date.now() });
|
|
113
|
+
payloads.set(handle, copy({ ...record, handle, createdAt: Date.now() }));
|
|
38
114
|
return handle;
|
|
39
115
|
},
|
|
40
116
|
|
|
@@ -42,12 +118,16 @@ export function memoryStore(): StoreAdapter {
|
|
|
42
118
|
async getPayload(handle, conversationId) {
|
|
43
119
|
const record = payloads.get(handle);
|
|
44
120
|
if (!record || record.conversationId !== conversationId) return null;
|
|
45
|
-
return record;
|
|
121
|
+
return copy(record);
|
|
46
122
|
},
|
|
47
123
|
|
|
48
|
-
async
|
|
49
|
-
const
|
|
50
|
-
|
|
124
|
+
async getPayloads(handles, conversationId) {
|
|
125
|
+
const out: PayloadRecord[] = [];
|
|
126
|
+
for (const handle of handles) {
|
|
127
|
+
const record = payloads.get(handle);
|
|
128
|
+
if (record && record.conversationId === conversationId) out.push(copy(record));
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
51
131
|
},
|
|
52
132
|
};
|
|
53
133
|
}
|