@vincemakes/kiso-core 0.1.32 → 0.1.33
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/kernel/project.js +97 -48
- package/package.json +1 -1
package/dist/kernel/project.js
CHANGED
|
@@ -85,6 +85,7 @@ export function projectMessages(events) {
|
|
|
85
85
|
assistantSource = undefined;
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
|
+
const callIds = blocks.filter((b) => b.type === "tool_use").map((b) => b.callId);
|
|
88
89
|
const reasoning = pendingReasoning;
|
|
89
90
|
pendingReasoning = null;
|
|
90
91
|
out.push({
|
|
@@ -95,6 +96,15 @@ export function projectMessages(events) {
|
|
|
95
96
|
});
|
|
96
97
|
blocks = [];
|
|
97
98
|
assistantSource = undefined;
|
|
99
|
+
// P1: the closed assistant's calls whose results are NOT already
|
|
100
|
+
// buffered are pending — their results land later (post-stop late
|
|
101
|
+
// results, the straddle's shape). The mid-execution inputs hold
|
|
102
|
+
// until those results flush.
|
|
103
|
+
// the guard keeps a still-pending pair holding when a call-less
|
|
104
|
+
// assistant closes mid-hold (the empty set would release the input)
|
|
105
|
+
const buffered = new Set(resultBuf.map((r) => r.callId));
|
|
106
|
+
if (callIds.length > 0)
|
|
107
|
+
pendingCalls = new Set(callIds.filter((c) => !buffered.has(c)));
|
|
98
108
|
};
|
|
99
109
|
// C group/round 6: vetoed/rewritten user inputs. Collect the replacement map
|
|
100
110
|
// first — the FINAL replacement for each input wins (later replacements
|
|
@@ -150,15 +160,32 @@ export function projectMessages(events) {
|
|
|
150
160
|
let resultBuf = [];
|
|
151
161
|
const callOrder = new Map();
|
|
152
162
|
let callOrderNext = 0;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
// P1 (0.1.42): the mid-execution input deferral. A user input arriving
|
|
164
|
+
// while the last closed assistant's tool_calls are UNANSWERED (the
|
|
165
|
+
// result lands later in the log — the boundary straddle's durable
|
|
166
|
+
// shape) must never separate the call from its result: the request
|
|
167
|
+
// [assistant, user, tool] is a real provider 400. Such inputs are
|
|
168
|
+
// HELD and released right after the results flush — the mid-execution
|
|
169
|
+
// input takes effect when the turn's execution completes.
|
|
170
|
+
let pendingCalls = new Set();
|
|
171
|
+
let heldUsers = [];
|
|
172
|
+
const flushResults = (force = false) => {
|
|
173
|
+
if (resultBuf.length > 0) {
|
|
174
|
+
resultBuf.sort((a, b) => (callOrder.get(a.callId) ?? 0) - (callOrder.get(b.callId) ?? 0));
|
|
175
|
+
for (const r of resultBuf)
|
|
176
|
+
out.push(r.message);
|
|
177
|
+
resultBuf = [];
|
|
178
|
+
callOrder.clear();
|
|
179
|
+
callOrderNext = 0;
|
|
180
|
+
}
|
|
181
|
+
// The held inputs release ONLY when the pair resolved (or the
|
|
182
|
+
// projection ends — force): a still-pending pair must keep holding,
|
|
183
|
+
// or the next user_input's leading flush would dump the inputs
|
|
184
|
+
// between the call and its late result (the 400 again).
|
|
185
|
+
if (force || pendingCalls.size === 0) {
|
|
186
|
+
out.push(...heldUsers);
|
|
187
|
+
heldUsers = [];
|
|
188
|
+
}
|
|
162
189
|
};
|
|
163
190
|
let explicitAssistant = false;
|
|
164
191
|
for (const ev of events) {
|
|
@@ -186,30 +213,41 @@ export function projectMessages(events) {
|
|
|
186
213
|
case "user_input": {
|
|
187
214
|
// 0.1.26: the previous turn closes here — the assistant
|
|
188
215
|
// first, then its results in call order (the turn boundary).
|
|
189
|
-
flushAssistant();
|
|
190
|
-
flushResults();
|
|
191
216
|
// round 6: the final replacement renders HERE, at the input's own
|
|
192
217
|
// position — the original is skipped, the replacement event
|
|
193
218
|
// itself produces nothing (a later replacement for the same
|
|
194
|
-
// input never becomes a second message)
|
|
219
|
+
// input never becomes a second message); a null content is a
|
|
220
|
+
// true veto (nothing renders at that position).
|
|
221
|
+
flushAssistant();
|
|
222
|
+
flushResults();
|
|
223
|
+
let content = ev.content;
|
|
224
|
+
let source = ev.source;
|
|
225
|
+
let veto = false;
|
|
195
226
|
if ("seq" in ev && typeof ev.seq === "number" && replaced.has(ev.seq)) {
|
|
196
227
|
const replacement = replaced.get(ev.seq);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
});
|
|
228
|
+
if (replacement.content === null) {
|
|
229
|
+
veto = true;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
content = replacement.content;
|
|
233
|
+
source = replacement.source ?? ev.source;
|
|
204
234
|
}
|
|
205
|
-
break;
|
|
206
235
|
}
|
|
207
|
-
|
|
208
|
-
|
|
236
|
+
if (veto)
|
|
237
|
+
break;
|
|
238
|
+
const message = {
|
|
209
239
|
role: "user",
|
|
210
|
-
content
|
|
211
|
-
...(
|
|
212
|
-
}
|
|
240
|
+
content,
|
|
241
|
+
...(source !== undefined ? { source } : {}),
|
|
242
|
+
};
|
|
243
|
+
// P1: the mid-execution deferral — an input arriving while
|
|
244
|
+
// the turn's calls are unanswered is HELD and released right
|
|
245
|
+
// after the results flush (the pairing invariant: the
|
|
246
|
+
// results must follow their calls before any user message).
|
|
247
|
+
if (pendingCalls.size > 0)
|
|
248
|
+
heldUsers.push(message);
|
|
249
|
+
else
|
|
250
|
+
out.push(message);
|
|
213
251
|
break;
|
|
214
252
|
}
|
|
215
253
|
case "user_input_replaced":
|
|
@@ -253,18 +291,16 @@ export function projectMessages(events) {
|
|
|
253
291
|
case "text_delta":
|
|
254
292
|
// 0.1.26: a text delta with BUFFERED RESULTS opens the NEXT
|
|
255
293
|
// turn's stream — the previous turn closes HERE: its
|
|
256
|
-
// assistant
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
flushAssistant();
|
|
267
|
-
flushResults();
|
|
294
|
+
// assistant (closed at the stop), then its buffered results
|
|
295
|
+
// in call order (the API requires each tool_calls message
|
|
296
|
+
// to be followed by its tool messages — a real 400 without
|
|
297
|
+
// the boundary). P1 (0.1.42): the flush keys on OPEN
|
|
298
|
+
// assistant content — an open block or text proves the
|
|
299
|
+
// model is still streaming THIS turn, and a same-turn
|
|
300
|
+
// buffered result must stay buffered (flushing it here
|
|
301
|
+
// split the turn's message — the fresh2 400).
|
|
302
|
+
if (blocks.length === 0 && text === null && resultBuf.length > 0)
|
|
303
|
+
flushResults();
|
|
268
304
|
text = (text ?? "") + ev.text;
|
|
269
305
|
break;
|
|
270
306
|
case "tool_call_start":
|
|
@@ -276,11 +312,14 @@ export function projectMessages(events) {
|
|
|
276
312
|
case "tool_call_end":
|
|
277
313
|
// 0.1.26: a tool_call_end with BUFFERED RESULTS opens the
|
|
278
314
|
// NEXT turn's stream (the model called again) — the
|
|
279
|
-
// previous turn
|
|
280
|
-
//
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
315
|
+
// previous turn's results close first; a same-turn call
|
|
316
|
+
// keeps the assistant open. P1 (0.1.42): open assistant
|
|
317
|
+
// content proves the same-turn call — the buffered results
|
|
318
|
+
// close at the stop, NEVER here (flushing a same-turn
|
|
319
|
+
// result at a later call_end split the turn's message —
|
|
320
|
+
// the fresh2 400).
|
|
321
|
+
if (blocks.length === 0 && text === null && resultBuf.length > 0)
|
|
322
|
+
flushResults();
|
|
284
323
|
pushText();
|
|
285
324
|
callOrder.set(ev.callId, callOrderNext++);
|
|
286
325
|
blocks.push({
|
|
@@ -315,6 +354,9 @@ export function projectMessages(events) {
|
|
|
315
354
|
}
|
|
316
355
|
// 0.1.26: BUFFERED — the results flush in call order at the
|
|
317
356
|
// turn boundary (flushResults), not in completion order.
|
|
357
|
+
// P1: a pending call's result resolves the pair — the held
|
|
358
|
+
// mid-execution inputs release with the flush.
|
|
359
|
+
pendingCalls.delete(ev.callId);
|
|
318
360
|
resultBuf.push({ callId: ev.callId, message });
|
|
319
361
|
break;
|
|
320
362
|
}
|
|
@@ -374,9 +416,11 @@ export function projectMessages(events) {
|
|
|
374
416
|
// the assistant message that follows carries it. 0.1.26: the
|
|
375
417
|
// assistant flush is guarded on the buffered results (a
|
|
376
418
|
// mid-turn reasoning must not split the current message).
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
419
|
+
// P1 (0.1.42): the flush keys on OPEN assistant content —
|
|
420
|
+
// a mid-turn reasoning with a same-turn result buffered
|
|
421
|
+
// must NOT split the message (the fresh2 400 family).
|
|
422
|
+
if (blocks.length === 0 && text === null && resultBuf.length > 0)
|
|
423
|
+
flushResults();
|
|
380
424
|
pendingReasoning = (pendingReasoning ?? "") + ev.text;
|
|
381
425
|
break;
|
|
382
426
|
case "summarized":
|
|
@@ -397,9 +441,14 @@ export function projectMessages(events) {
|
|
|
397
441
|
break;
|
|
398
442
|
case "stop":
|
|
399
443
|
// The turn boundary: the assistant closes at the provider's
|
|
400
|
-
// stop
|
|
401
|
-
// turn
|
|
444
|
+
// stop — and the turn's BUFFERED results close WITH it (P1
|
|
445
|
+
// 0.1.42). Parallel execution lands same-turn results
|
|
446
|
+
// mid-stream; flushing them here — the true boundary —
|
|
447
|
+
// projects [assistant, results…] in reading order, and the
|
|
448
|
+
// stream-open guards below only ever flush a CLOSED turn's
|
|
449
|
+
// late (post-stop) results.
|
|
402
450
|
flushAssistant();
|
|
451
|
+
flushResults();
|
|
403
452
|
break;
|
|
404
453
|
case "terminal":
|
|
405
454
|
case "tool_execution_started":
|
|
@@ -417,7 +466,7 @@ export function projectMessages(events) {
|
|
|
417
466
|
}
|
|
418
467
|
}
|
|
419
468
|
flushAssistant();
|
|
420
|
-
flushResults();
|
|
469
|
+
flushResults(true); // the log's end is the last resort: held inputs never drop
|
|
421
470
|
return out;
|
|
422
471
|
}
|
|
423
472
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "kiso (foundation) core — protocol, event log, loop, hooks, modes, permissions, compaction, delivery truth. The 2,000-line kernel at the bottom of the kiso framework.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|