@vincemakes/kiso-core 0.42.1 → 0.42.2
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/loop.js +33 -46
- package/package.json +2 -2
package/dist/kernel/loop.js
CHANGED
|
@@ -112,6 +112,15 @@ export async function* loop(config) {
|
|
|
112
112
|
return full;
|
|
113
113
|
};
|
|
114
114
|
const aborted = () => signal?.aborted === true;
|
|
115
|
+
/** append → observe → yield, for a producer with NOTHING between the
|
|
116
|
+
* three (never the execution queue's ack, the stream's launch, or a
|
|
117
|
+
* producer without an observer). */
|
|
118
|
+
async function* emit(e) {
|
|
119
|
+
const full = log.append(e);
|
|
120
|
+
if (hooks.onEvent)
|
|
121
|
+
await hooks.onEvent(full, {}).catch(() => { });
|
|
122
|
+
yield full;
|
|
123
|
+
}
|
|
115
124
|
// Assemble: the incoming user message may be rewritten or vetoed.
|
|
116
125
|
// C group: the outcome is PERSISTED as a user_input_replaced event — the
|
|
117
126
|
// projection renders the final replacement AT THE INPUT'S POSITION (or
|
|
@@ -502,12 +511,8 @@ export async function* loop(config) {
|
|
|
502
511
|
// ── ADR-0055 (A1b): the compaction point, before every request ──
|
|
503
512
|
if (config.compact !== undefined) {
|
|
504
513
|
const added = await config.compact(log.all, messages, overflow === null ? "request" : "overflow");
|
|
505
|
-
for (const e of added)
|
|
506
|
-
|
|
507
|
-
if (hooks.onEvent)
|
|
508
|
-
await hooks.onEvent(full, {}).catch(() => { });
|
|
509
|
-
yield full;
|
|
510
|
-
}
|
|
514
|
+
for (const e of added)
|
|
515
|
+
yield* emit(e);
|
|
511
516
|
if (overflow !== null && added.length === 0) {
|
|
512
517
|
yield await terminal({ kind: "error", error: overflow });
|
|
513
518
|
return;
|
|
@@ -573,12 +578,8 @@ export async function* loop(config) {
|
|
|
573
578
|
yield* drainSettled();
|
|
574
579
|
if (launchError !== null)
|
|
575
580
|
throw launchError;
|
|
576
|
-
if (log.lastSeq > turnStart && !unsafeStartedInDraft())
|
|
577
|
-
|
|
578
|
-
if (hooks.onEvent)
|
|
579
|
-
await hooks.onEvent(marker, {}).catch(() => { });
|
|
580
|
-
yield marker;
|
|
581
|
-
}
|
|
581
|
+
if (log.lastSeq > turnStart && !unsafeStartedInDraft())
|
|
582
|
+
yield* emit({ type: "model_output_abandoned", voidFromSeq: turnStart, reason });
|
|
582
583
|
};
|
|
583
584
|
while (true) {
|
|
584
585
|
// Area 4: the backoff is abortable — a cancel landing during a
|
|
@@ -867,11 +868,8 @@ export async function* loop(config) {
|
|
|
867
868
|
return;
|
|
868
869
|
}
|
|
869
870
|
if (voided === null && heldStop !== null) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
await hooks.onEvent(full, {}).catch(() => { });
|
|
873
|
-
committed = true;
|
|
874
|
-
yield full;
|
|
871
|
+
committed = true; // a local flag; set before the emit, read only after it (the observer cannot throw)
|
|
872
|
+
yield* emit(heldStop);
|
|
875
873
|
}
|
|
876
874
|
settleTurn();
|
|
877
875
|
// A turn with no tool calls ends on its OWN stop reason (Phase B,
|
|
@@ -969,6 +967,20 @@ function terminalForStop(reason) {
|
|
|
969
967
|
};
|
|
970
968
|
}
|
|
971
969
|
}
|
|
970
|
+
/** The permission_decided event for an invocation — the fields in the
|
|
971
|
+
* order the log has always written them. The CALLER decides: approved or
|
|
972
|
+
* not, the reason, the speaker; this builds, never classifies. */
|
|
973
|
+
function decidedEvent(call, decisionId, approved, reason, decidedBy) {
|
|
974
|
+
return {
|
|
975
|
+
type: "permission_decided",
|
|
976
|
+
decisionId,
|
|
977
|
+
callId: call.callId,
|
|
978
|
+
invocationSeq: call.seq,
|
|
979
|
+
decision: approved ? "approved" : "denied",
|
|
980
|
+
...(reason !== undefined ? { reason } : {}),
|
|
981
|
+
...(decidedBy !== undefined ? { decidedBy } : {}),
|
|
982
|
+
};
|
|
983
|
+
}
|
|
972
984
|
/** The tool_result event for a call — the shared shape (executionId rides
|
|
973
985
|
* it as the durable correlation, round 5; invocationSeq = the framework
|
|
974
986
|
* identity, R-E 0.1.43). */
|
|
@@ -1101,17 +1113,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
|
|
|
1101
1113
|
// allow/deny are PERSISTED FACTS (decidedBy = a SPEAKING
|
|
1102
1114
|
// extension — never the chain head on behalf of a non-speaker)
|
|
1103
1115
|
// — never a human pause.
|
|
1104
|
-
push(
|
|
1105
|
-
type: "permission_decided",
|
|
1106
|
-
decisionId: nextDecisionId(),
|
|
1107
|
-
callId: call.callId,
|
|
1108
|
-
invocationSeq: call.seq,
|
|
1109
|
-
decision: chainVerdict.action === "allow" ? "approved" : "denied",
|
|
1110
|
-
...(chainVerdict.action === "deny" && chainVerdict.reason !== undefined
|
|
1111
|
-
? { reason: chainVerdict.reason }
|
|
1112
|
-
: {}),
|
|
1113
|
-
decidedBy: chainVerdict.decidedBy,
|
|
1114
|
-
});
|
|
1116
|
+
push(decidedEvent(call, nextDecisionId(), chainVerdict.action === "allow", chainVerdict.action === "deny" ? chainVerdict.reason : undefined, chainVerdict.decidedBy));
|
|
1115
1117
|
}
|
|
1116
1118
|
}
|
|
1117
1119
|
if (chainVerdict?.action === "deny") {
|
|
@@ -1197,14 +1199,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
|
|
|
1197
1199
|
// its honest aborted terminal.
|
|
1198
1200
|
const verdict = resolveApprovalVerdict?.(decisionId);
|
|
1199
1201
|
if (verdict !== undefined) {
|
|
1200
|
-
push(
|
|
1201
|
-
type: "permission_decided",
|
|
1202
|
-
decisionId,
|
|
1203
|
-
callId: call.callId,
|
|
1204
|
-
invocationSeq: call.seq,
|
|
1205
|
-
decision: verdict ? "approved" : "denied",
|
|
1206
|
-
...(verdict ? {} : { reason: "denied by user" }),
|
|
1207
|
-
});
|
|
1202
|
+
push(decidedEvent(call, decisionId, verdict, verdict ? undefined : "denied by user"));
|
|
1208
1203
|
}
|
|
1209
1204
|
}
|
|
1210
1205
|
throw err;
|
|
@@ -1213,16 +1208,8 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
|
|
|
1213
1208
|
// write-ahead BEFORE waking the resolver (Area 2): if it already
|
|
1214
1209
|
// landed in the log, this is the same decision, not a duplicate.
|
|
1215
1210
|
if (log.all.find((e) => e.type === "permission_decided" && e.decisionId === decisionId) === undefined) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
decisionId,
|
|
1219
|
-
callId: call.callId, // binds the decision to the invocation (B group)
|
|
1220
|
-
invocationSeq: call.seq,
|
|
1221
|
-
decision: finalDecision.action === "allow" ? "approved" : "denied",
|
|
1222
|
-
...(finalDecision.action === "deny" && finalDecision.reason !== undefined
|
|
1223
|
-
? { reason: finalDecision.reason }
|
|
1224
|
-
: {}),
|
|
1225
|
-
});
|
|
1211
|
+
// callId binds the decision to the invocation (B group)
|
|
1212
|
+
push(decidedEvent(call, decisionId, finalDecision.action === "allow", finalDecision.action === "deny" ? finalDecision.reason : undefined));
|
|
1226
1213
|
}
|
|
1227
1214
|
return finalDecision;
|
|
1228
1215
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-core",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.2",
|
|
4
4
|
"description": "kiso core \u2014 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.42.
|
|
36
|
+
"@vincemakes/kiso-evals": "0.42.2",
|
|
37
37
|
"@types/node": "^26.1.2",
|
|
38
38
|
"typescript": "^5.7.2",
|
|
39
39
|
"vitest": "^3.0.0"
|