@vincemakes/kiso-core 0.1.33 → 0.1.34
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/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/kernel/loop.js +17 -5
- package/dist/kernel/project.js +15 -1
- package/dist/protocol/events.d.ts +31 -1
- package/dist/protocol/events.js +13 -7
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/kernel/loop.js
CHANGED
|
@@ -374,14 +374,17 @@ export async function* loop(config) {
|
|
|
374
374
|
lastStop = ev.reason;
|
|
375
375
|
stopCount += 1;
|
|
376
376
|
}
|
|
377
|
-
|
|
378
|
-
|
|
377
|
+
// R-E 0.1.43: the append precedes the launch — the call's
|
|
378
|
+
// framework seq is assigned here; invocationSeq must never
|
|
379
|
+
// be the adapter's stream-local hint (ADR-0002).
|
|
380
|
+
const full = log.append(ev);
|
|
381
|
+
if (full.type === "tool_call_end") {
|
|
382
|
+
pending.push(full);
|
|
379
383
|
// streaming execution: the call launches immediately — the decide
|
|
380
384
|
// and the ledgered run proceed in parallel with the
|
|
381
385
|
// model stream.
|
|
382
|
-
launch(
|
|
386
|
+
launch(full);
|
|
383
387
|
}
|
|
384
|
-
const full = log.append(ev);
|
|
385
388
|
if (hooks.onEvent)
|
|
386
389
|
await hooks.onEvent(full, {}).catch(() => { });
|
|
387
390
|
yield full;
|
|
@@ -578,11 +581,13 @@ function terminalForStop(reason) {
|
|
|
578
581
|
}
|
|
579
582
|
}
|
|
580
583
|
/** The tool_result event for a call — the shared shape (executionId rides
|
|
581
|
-
* it as the durable correlation, round 5
|
|
584
|
+
* it as the durable correlation, round 5; invocationSeq = the framework
|
|
585
|
+
* identity, R-E 0.1.43). */
|
|
582
586
|
function resultEvent(call, result, executionId) {
|
|
583
587
|
return {
|
|
584
588
|
type: "tool_result",
|
|
585
589
|
callId: call.callId,
|
|
590
|
+
invocationSeq: call.seq,
|
|
586
591
|
content: result.content,
|
|
587
592
|
isError: result.isError,
|
|
588
593
|
// P1-9: errorKind only exists on errors (the type now enforces it;
|
|
@@ -665,6 +670,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
|
|
|
665
670
|
type: "permission_decided",
|
|
666
671
|
decisionId: nextDecisionId(),
|
|
667
672
|
callId: call.callId,
|
|
673
|
+
invocationSeq: call.seq,
|
|
668
674
|
decision: chainVerdict.action === "allow" ? "approved" : "denied",
|
|
669
675
|
...(chainVerdict.action === "deny" && chainVerdict.reason !== undefined
|
|
670
676
|
? { reason: chainVerdict.reason }
|
|
@@ -733,6 +739,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
|
|
|
733
739
|
type: "permission_requested",
|
|
734
740
|
decisionId,
|
|
735
741
|
callId: call.callId,
|
|
742
|
+
invocationSeq: call.seq,
|
|
736
743
|
name: call.name,
|
|
737
744
|
input: call.input ?? {},
|
|
738
745
|
// W21: the ask verdict's speaker — the panel's why-asked line (a
|
|
@@ -759,6 +766,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
|
|
|
759
766
|
type: "permission_decided",
|
|
760
767
|
decisionId,
|
|
761
768
|
callId: call.callId,
|
|
769
|
+
invocationSeq: call.seq,
|
|
762
770
|
decision: verdict ? "approved" : "denied",
|
|
763
771
|
...(verdict ? {} : { reason: "denied by user" }),
|
|
764
772
|
});
|
|
@@ -774,6 +782,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
|
|
|
774
782
|
type: "permission_decided",
|
|
775
783
|
decisionId,
|
|
776
784
|
callId: call.callId, // binds the decision to the invocation (B group)
|
|
785
|
+
invocationSeq: call.seq,
|
|
777
786
|
decision: finalDecision.action === "allow" ? "approved" : "denied",
|
|
778
787
|
...(finalDecision.action === "deny" && finalDecision.reason !== undefined
|
|
779
788
|
? { reason: finalDecision.reason }
|
|
@@ -806,6 +815,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
|
|
|
806
815
|
push({
|
|
807
816
|
type: "tool_execution_started",
|
|
808
817
|
callId: call.callId,
|
|
818
|
+
invocationSeq: call.seq,
|
|
809
819
|
name: call.name,
|
|
810
820
|
input: call.input, // non-null: decideCall denied a null input before this ran
|
|
811
821
|
}, (id) => res(id ?? ""));
|
|
@@ -851,6 +861,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
|
|
|
851
861
|
type: "tool_execution_failed",
|
|
852
862
|
executionId,
|
|
853
863
|
callId: call.callId,
|
|
864
|
+
invocationSeq: call.seq,
|
|
854
865
|
error: result.content,
|
|
855
866
|
// P1-9: errorKind only exists on errors (the type now enforces it;
|
|
856
867
|
// the runtime guard keeps a JS tool's illegal combination out of
|
|
@@ -865,6 +876,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
|
|
|
865
876
|
type: "tool_execution_succeeded",
|
|
866
877
|
executionId,
|
|
867
878
|
callId: call.callId,
|
|
879
|
+
invocationSeq: call.seq,
|
|
868
880
|
result: { content: result.content, isError: false },
|
|
869
881
|
...(result.tags !== undefined ? { tags: result.tags } : {}),
|
|
870
882
|
});
|
package/dist/kernel/project.js
CHANGED
|
@@ -146,7 +146,17 @@ export function projectMessages(events) {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
// R-E 0.1.43 (Gap B): a model_output_abandoned marker voids the range
|
|
150
|
+
// (voidFromSeq, its seq] — the abandoned draft's events. The ranges are
|
|
151
|
+
// disjoint and in seq order; the skip below treats them exactly like the
|
|
152
|
+
// summary ranges (the marker itself renders nothing and skips itself).
|
|
153
|
+
const voidRanges = [];
|
|
154
|
+
for (const ev of events) {
|
|
155
|
+
if (ev.type === "model_output_abandoned")
|
|
156
|
+
voidRanges.push({ from: ev.voidFromSeq, to: ev.seq ?? -1 });
|
|
157
|
+
}
|
|
158
|
+
const isCovered = (seq) => summaryRanges.some((r) => seq > r.from && seq <= r.to) ||
|
|
159
|
+
voidRanges.some((r) => seq > r.from && seq <= r.to);
|
|
150
160
|
// Summaries render in range order as the pass crosses their boundaries.
|
|
151
161
|
let renderedSummaries = 0;
|
|
152
162
|
// 0.1.26 (ADR-0024 Amd, parallel execution): the tool results of ONE turn
|
|
@@ -459,6 +469,10 @@ export function projectMessages(events) {
|
|
|
459
469
|
case "permission_decided":
|
|
460
470
|
case "permission_expired":
|
|
461
471
|
case "uncertain_pending":
|
|
472
|
+
case "model_output_abandoned":
|
|
473
|
+
// R-E 0.1.43: renders nothing — the marker is always skipped by
|
|
474
|
+
// its own range; the case documents the intent (and no flush:
|
|
475
|
+
// it must never split a message).
|
|
462
476
|
break;
|
|
463
477
|
case "microcompacted":
|
|
464
478
|
// handled above (the replacement pass) — no open message.
|
|
@@ -134,6 +134,7 @@ export interface ToolResultEvent {
|
|
|
134
134
|
readonly seq: number;
|
|
135
135
|
readonly type: "tool_result";
|
|
136
136
|
readonly callId: string;
|
|
137
|
+
readonly invocationSeq?: number;
|
|
137
138
|
/** Full content — blocks preserved losslessly (D group). */
|
|
138
139
|
readonly content: string | readonly import("./messages.js").ContentBlock[];
|
|
139
140
|
readonly isError: boolean;
|
|
@@ -199,6 +200,7 @@ export interface ToolExecutionStarted {
|
|
|
199
200
|
readonly type: "tool_execution_started";
|
|
200
201
|
readonly executionId: string;
|
|
201
202
|
readonly callId: string;
|
|
203
|
+
readonly invocationSeq?: number;
|
|
202
204
|
readonly name: string;
|
|
203
205
|
readonly input: Readonly<Record<string, unknown>>;
|
|
204
206
|
}
|
|
@@ -208,6 +210,7 @@ export interface ToolExecutionSucceeded {
|
|
|
208
210
|
readonly type: "tool_execution_succeeded";
|
|
209
211
|
readonly executionId: string;
|
|
210
212
|
readonly callId: string;
|
|
213
|
+
readonly invocationSeq?: number;
|
|
211
214
|
readonly result: {
|
|
212
215
|
readonly content: string;
|
|
213
216
|
readonly isError: false;
|
|
@@ -227,6 +230,7 @@ export interface ToolExecutionFailed {
|
|
|
227
230
|
readonly type: "tool_execution_failed";
|
|
228
231
|
readonly executionId: string;
|
|
229
232
|
readonly callId: string;
|
|
233
|
+
readonly invocationSeq?: number;
|
|
230
234
|
readonly error: string;
|
|
231
235
|
readonly errorKind?: ToolErrorKind;
|
|
232
236
|
readonly safeToRetry: boolean;
|
|
@@ -243,6 +247,7 @@ export interface ToolExecutionResolved {
|
|
|
243
247
|
readonly type: "tool_execution_resolved";
|
|
244
248
|
readonly executionId: string;
|
|
245
249
|
readonly callId: string;
|
|
250
|
+
readonly invocationSeq?: number;
|
|
246
251
|
readonly resolution: "rerun" | "abandoned";
|
|
247
252
|
}
|
|
248
253
|
/**
|
|
@@ -256,6 +261,7 @@ export interface PermissionRequested {
|
|
|
256
261
|
readonly type: "permission_requested";
|
|
257
262
|
readonly decisionId: string;
|
|
258
263
|
readonly callId: string;
|
|
264
|
+
readonly invocationSeq?: number;
|
|
259
265
|
readonly name: string;
|
|
260
266
|
readonly input: Readonly<Record<string, unknown>>;
|
|
261
267
|
/** W21: the first non-abstain extension's name — the panel's why-asked
|
|
@@ -269,6 +275,7 @@ export interface PermissionDecided {
|
|
|
269
275
|
readonly decisionId: string;
|
|
270
276
|
/** The invocation this decision binds to (B group). */
|
|
271
277
|
readonly callId?: string;
|
|
278
|
+
readonly invocationSeq?: number;
|
|
272
279
|
readonly decision: "approved" | "denied";
|
|
273
280
|
readonly reason?: string;
|
|
274
281
|
/** E1: the deciding extension's name — present ONLY on policy decisions;
|
|
@@ -353,6 +360,22 @@ export interface SummarizedEvent {
|
|
|
353
360
|
/** The model's compression — replaces the covered range in the projection. */
|
|
354
361
|
readonly summary: string;
|
|
355
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* R-E 0.1.43 / ADR-0047 (Gap B) — a model output suffix WITHOUT a committed
|
|
365
|
+
* stop was abandoned on resume. `voidFromSeq` is the last committed-boundary
|
|
366
|
+
* event's seq (stop / user_input / terminal / compaction / summarized); the
|
|
367
|
+
* voided range is (voidFromSeq, this.seq]. The projection skips the range and
|
|
368
|
+
* the marker itself renders nothing — "a model output suffix without a
|
|
369
|
+
* committed stop is an incomplete draft and must never become committed
|
|
370
|
+
* provider history." Kernel-owned: the AdapterEvent whitelist excludes it, so
|
|
371
|
+
* adapter/extension forgery is invalid_request by construction.
|
|
372
|
+
*/
|
|
373
|
+
export interface ModelOutputAbandoned {
|
|
374
|
+
readonly seq: number;
|
|
375
|
+
readonly type: "model_output_abandoned";
|
|
376
|
+
readonly voidFromSeq: number;
|
|
377
|
+
readonly reason: string;
|
|
378
|
+
}
|
|
356
379
|
/** Extended-thinking content. Providers without it emit nothing here. */
|
|
357
380
|
export interface Thinking {
|
|
358
381
|
readonly seq: number;
|
|
@@ -440,10 +463,17 @@ export interface TerminalEvent {
|
|
|
440
463
|
readonly outcome: Terminal;
|
|
441
464
|
}
|
|
442
465
|
/**
|
|
466
|
+
* IDENTITY (the three-identity model, R-E 0.1.43 / ADR-0047): an invocation
|
|
467
|
+
* carries THREE ids — `callId` (provider correlation only, may repeat across
|
|
468
|
+
* runs), `invocationSeq` (the framework identity = the call's tool_call_end
|
|
469
|
+
* .seq; OPTIONAL — absent on old logs, present on everything written from
|
|
470
|
+
* 0.1.43), and `executionId` (a specific execution of that invocation, one
|
|
471
|
+
* per started event). Old logs keep the callId + seq-proximity fallback.
|
|
472
|
+
*
|
|
443
473
|
* The union. Consume it with a `switch (event.type)`; with
|
|
444
474
|
* `strictNullChecks` on, an unhandled variant is a compile error.
|
|
445
475
|
*/
|
|
446
|
-
export type Event = AssistantStart | AssistantEnd | TextStart | TextDelta | TextEnd | ToolCallStart | ToolCallInputDelta | ToolCallEnd | ToolResultEvent | Thinking | Usage | Stop | UserInputEvent | CompactedEvent | ToolExecutionStarted | ToolExecutionSucceeded | ToolExecutionFailed | ToolExecutionResolved | PermissionRequested | PermissionDecided | PermissionExpired | UncertainPending | UserInputReplaced | MicroCompactEvent | SummarizedEvent | TerminalEvent;
|
|
476
|
+
export type Event = AssistantStart | AssistantEnd | TextStart | TextDelta | TextEnd | ToolCallStart | ToolCallInputDelta | ToolCallEnd | ToolResultEvent | Thinking | Usage | Stop | UserInputEvent | CompactedEvent | ToolExecutionStarted | ToolExecutionSucceeded | ToolExecutionFailed | ToolExecutionResolved | PermissionRequested | PermissionDecided | PermissionExpired | UncertainPending | UserInputReplaced | MicroCompactEvent | SummarizedEvent | ModelOutputAbandoned | TerminalEvent;
|
|
447
477
|
/**
|
|
448
478
|
* Runtime type guard for the union. The store validates every JSONL record
|
|
449
479
|
* with it: valid JSON that is not a kiso event is corruption, not history.
|
package/dist/protocol/events.js
CHANGED
|
@@ -102,6 +102,9 @@ function isErrorKind(v) {
|
|
|
102
102
|
function isExecutionId(v) {
|
|
103
103
|
return v.executionId === undefined || typeof v.executionId === "string";
|
|
104
104
|
}
|
|
105
|
+
/** R-E 0.1.43: the optional framework invocation identity — absent on old
|
|
106
|
+
* logs, otherwise a non-negative safe integer (the tool_call_end.seq). */
|
|
107
|
+
const isInvocationSeq = (v) => v.invocationSeq === undefined || isNonNegativeInt(v.invocationSeq);
|
|
105
108
|
/** A StructuredError — the shape the `error` terminal carries. round 9: a
|
|
106
109
|
* status, when present, is a non-negative safe integer (no negatives,
|
|
107
110
|
* NaN, Infinity, or fractions). */
|
|
@@ -170,7 +173,7 @@ const EVENT_VALIDATORS = {
|
|
|
170
173
|
isErrorKind(v) &&
|
|
171
174
|
isExecutionId(v) &&
|
|
172
175
|
isSource(v) &&
|
|
173
|
-
isTags(v),
|
|
176
|
+
isTags(v) && isInvocationSeq(v),
|
|
174
177
|
thinking: (v) => typeof v.text === "string",
|
|
175
178
|
usage: isUsage,
|
|
176
179
|
stop: (v) => STOP_REASONS.has(v.reason),
|
|
@@ -186,32 +189,32 @@ const EVENT_VALIDATORS = {
|
|
|
186
189
|
tool_execution_started: (v) => typeof v.executionId === "string" &&
|
|
187
190
|
typeof v.callId === "string" &&
|
|
188
191
|
typeof v.name === "string" &&
|
|
189
|
-
isPlainObject(v.input),
|
|
192
|
+
isPlainObject(v.input) && isInvocationSeq(v),
|
|
190
193
|
tool_execution_succeeded: (v) => typeof v.executionId === "string" &&
|
|
191
194
|
typeof v.callId === "string" &&
|
|
192
195
|
isPlainObject(v.result) &&
|
|
193
196
|
typeof v.result.content === "string" &&
|
|
194
197
|
v.result.isError === false &&
|
|
195
|
-
isTags(v),
|
|
198
|
+
isTags(v) && isInvocationSeq(v),
|
|
196
199
|
tool_execution_failed: (v) => typeof v.executionId === "string" &&
|
|
197
200
|
typeof v.callId === "string" &&
|
|
198
201
|
typeof v.error === "string" &&
|
|
199
202
|
typeof v.safeToRetry === "boolean" &&
|
|
200
203
|
isErrorKind(v) &&
|
|
201
|
-
isTags(v),
|
|
204
|
+
isTags(v) && isInvocationSeq(v),
|
|
202
205
|
tool_execution_resolved: (v) => typeof v.executionId === "string" &&
|
|
203
206
|
typeof v.callId === "string" &&
|
|
204
|
-
(v.resolution === "rerun" || v.resolution === "abandoned"),
|
|
207
|
+
(v.resolution === "rerun" || v.resolution === "abandoned") && isInvocationSeq(v),
|
|
205
208
|
permission_requested: (v) => typeof v.decisionId === "string" &&
|
|
206
209
|
typeof v.callId === "string" &&
|
|
207
210
|
typeof v.name === "string" &&
|
|
208
211
|
isPlainObject(v.input) &&
|
|
209
|
-
(v.speaker === undefined || typeof v.speaker === "string"),
|
|
212
|
+
(v.speaker === undefined || typeof v.speaker === "string") && isInvocationSeq(v),
|
|
210
213
|
permission_decided: (v) => typeof v.decisionId === "string" &&
|
|
211
214
|
(v.decision === "approved" || v.decision === "denied") &&
|
|
212
215
|
(v.callId === undefined || typeof v.callId === "string") &&
|
|
213
216
|
(v.reason === undefined || typeof v.reason === "string") &&
|
|
214
|
-
(v.decidedBy === undefined || typeof v.decidedBy === "string"),
|
|
217
|
+
(v.decidedBy === undefined || typeof v.decidedBy === "string") && isInvocationSeq(v),
|
|
215
218
|
permission_expired: (v) => typeof v.decisionId === "string" && typeof v.reason === "string",
|
|
216
219
|
uncertain_pending: (v) => typeof v.executionId === "string" && typeof v.callId === "string" && typeof v.name === "string" && typeof v.error === "string",
|
|
217
220
|
microcompacted: (v) => isNonNegativeInt(v.beforeSeq),
|
|
@@ -221,6 +224,9 @@ const EVENT_VALIDATORS = {
|
|
|
221
224
|
typeof v.summary === "string" &&
|
|
222
225
|
v.summary.length > 0 &&
|
|
223
226
|
v.coversToSeq < v.seq,
|
|
227
|
+
// R-E 0.1.43: the void starts at a committed boundary BEFORE the marker —
|
|
228
|
+
// a marker that voids nothing (or itself) is corruption, not history.
|
|
229
|
+
model_output_abandoned: (v) => isNonNegativeInt(v.voidFromSeq) && typeof v.reason === "string" && v.voidFromSeq < v.seq,
|
|
224
230
|
user_input_replaced: (v) => isNonNegativeInt(v.replaces) && (v.content === null || isContent(v.content)) && isSource(v),
|
|
225
231
|
terminal: (v) => isTerminal(v.outcome),
|
|
226
232
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"openai"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@vincemakes/kiso-evals": "0.1.
|
|
36
|
+
"@vincemakes/kiso-evals": "0.1.35",
|
|
37
37
|
"@types/node": "^26.1.2",
|
|
38
38
|
"typescript": "^5.7.2",
|
|
39
39
|
"vitest": "^3.0.0"
|