@vincemakes/kiso-core 0.1.15 → 0.1.17
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 +18 -5
- package/dist/protocol/extension.d.ts +9 -1
- package/package.json +2 -2
package/dist/kernel/loop.js
CHANGED
|
@@ -592,6 +592,8 @@ async function* executeOne(call, registry, hooks, ctx, log, resolveApproval, res
|
|
|
592
592
|
let chainVerdict;
|
|
593
593
|
let deniedReason;
|
|
594
594
|
let deniedBy;
|
|
595
|
+
let firstSpeaker; // the first non-abstain verdict's extension
|
|
596
|
+
let anySpoke = false;
|
|
595
597
|
if (durable === undefined && approvalPolicies !== undefined && approvalPolicies.length > 0) {
|
|
596
598
|
for (const { extension, policy } of approvalPolicies) {
|
|
597
599
|
let v;
|
|
@@ -599,8 +601,12 @@ async function* executeOne(call, registry, hooks, ctx, log, resolveApproval, res
|
|
|
599
601
|
v = await raceAbort(Promise.resolve(policy.decide(payload, ctx)), signal);
|
|
600
602
|
}
|
|
601
603
|
catch {
|
|
602
|
-
v = { action: "ask" }; // 抛错 = 该扩展计为 ask
|
|
604
|
+
v = { action: "ask" }; // 抛错 = 该扩展计为 ask —— 发声,绝不静默
|
|
603
605
|
}
|
|
606
|
+
if (v.action === "abstain")
|
|
607
|
+
continue; // no opinion — not a verdict
|
|
608
|
+
anySpoke = true;
|
|
609
|
+
firstSpeaker ??= extension;
|
|
604
610
|
if (v.action === "deny") {
|
|
605
611
|
deniedBy ??= extension;
|
|
606
612
|
deniedReason ??= v.reason; // the FIRST denial's reason
|
|
@@ -612,19 +618,26 @@ async function* executeOne(call, registry, hooks, ctx, log, resolveApproval, res
|
|
|
612
618
|
if (deniedBy !== undefined) {
|
|
613
619
|
chainVerdict = { action: "deny", reason: deniedReason ?? "denied" };
|
|
614
620
|
}
|
|
621
|
+
else if (chainVerdict === undefined && anySpoke) {
|
|
622
|
+
chainVerdict = { action: "allow" }; // 全发声者皆 allow
|
|
623
|
+
}
|
|
615
624
|
else if (chainVerdict === undefined) {
|
|
616
|
-
|
|
625
|
+
// 全员 abstain (ADR-0042): NO policy speaks — the call falls to
|
|
626
|
+
// the ask flow below, never to a silent auto-approve. The human
|
|
627
|
+
// decides; absent a channel, awaitHumanApproval's honest denial.
|
|
628
|
+
chainVerdict = { action: "ask" };
|
|
617
629
|
}
|
|
618
630
|
if (chainVerdict.action !== "ask") {
|
|
619
|
-
// allow/deny are PERSISTED FACTS (decidedBy =
|
|
620
|
-
// never a
|
|
631
|
+
// allow/deny are PERSISTED FACTS (decidedBy = a SPEAKING
|
|
632
|
+
// extension — never the chain head on behalf of a non-speaker)
|
|
633
|
+
// — never a human pause.
|
|
621
634
|
yield log.append({
|
|
622
635
|
type: "permission_decided",
|
|
623
636
|
decisionId: `d-${log.lastSeq + 1}`,
|
|
624
637
|
callId: call.callId,
|
|
625
638
|
decision: chainVerdict.action === "allow" ? "approved" : "denied",
|
|
626
639
|
...(chainVerdict.action === "deny" ? { reason: chainVerdict.reason } : {}),
|
|
627
|
-
decidedBy: deniedBy ??
|
|
640
|
+
decidedBy: deniedBy ?? firstSpeaker,
|
|
628
641
|
});
|
|
629
642
|
}
|
|
630
643
|
}
|
|
@@ -16,7 +16,13 @@ export interface PolicyCall {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* A policy's verdict. `ask` defers to the existing human approval flow;
|
|
19
|
-
* `deny` carries the reason the model sees; `allow` auto-approves
|
|
19
|
+
* `deny` carries the reason the model sees; `allow` auto-approves;
|
|
20
|
+
* `abstain` is NO opinion — the policy does not speak (it neither allows,
|
|
21
|
+
* denies, nor asks), and the chain composes only over the SPEAKING
|
|
22
|
+
* verdicts. An all-abstain chain falls to the ask flow (the human
|
|
23
|
+
* decides; absent a channel, an honest denial) — abstaining is never a
|
|
24
|
+
* silent allow (ADR-0042: `allow` as "no opinion" auto-approved tools no
|
|
25
|
+
* policy meant to approve and misattributed decidedBy to a non-speaker).
|
|
20
26
|
*/
|
|
21
27
|
export type PolicyVerdict = {
|
|
22
28
|
readonly action: "allow";
|
|
@@ -25,6 +31,8 @@ export type PolicyVerdict = {
|
|
|
25
31
|
readonly reason: string;
|
|
26
32
|
} | {
|
|
27
33
|
readonly action: "ask";
|
|
34
|
+
} | {
|
|
35
|
+
readonly action: "abstain";
|
|
28
36
|
};
|
|
29
37
|
/** One approval policy — a pure decide function over a tool call. */
|
|
30
38
|
export interface ApprovalPolicy {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "kiso(基礎) 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.17",
|
|
37
37
|
"@types/node": "^26.1.2",
|
|
38
38
|
"typescript": "^5.7.2",
|
|
39
39
|
"vitest": "^3.0.0"
|