patchwork-os 1.1.0-beta.4.canary.476 → 1.1.0-beta.4.canary.477
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.
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prospective gate evaluation — "what could this worker do here?"
|
|
3
|
+
*
|
|
4
|
+
* The gate answers one question at a time, retrospectively: a tool call arrives
|
|
5
|
+
* and `decideWorkerAction` allows, gates or forbids it. That is the right shape
|
|
6
|
+
* for enforcement and the wrong shape for showing somebody the boundary, which
|
|
7
|
+
* has to be answerable *before* anything is attempted.
|
|
8
|
+
*
|
|
9
|
+
* This module asks the same question ahead of time, for a set of candidate
|
|
10
|
+
* actions, and buckets the answers into the three columns an operator reads:
|
|
11
|
+
* **may do now / needs approval / not permitted**.
|
|
12
|
+
*
|
|
13
|
+
* ## It must reuse the gate, not re-implement it
|
|
14
|
+
*
|
|
15
|
+
* The single property that makes this worth building: `previewActions` calls
|
|
16
|
+
* `decideWorkerAction` — the exact function enforcement uses. It contains no
|
|
17
|
+
* policy of its own, no parallel thresholds and no second copy of the
|
|
18
|
+
* reversibility rules.
|
|
19
|
+
*
|
|
20
|
+
* A preview with its own logic would be worse than no preview. It would drift,
|
|
21
|
+
* and the failure is silent and in the dangerous direction: a screen that says
|
|
22
|
+
* "not permitted" while the gate would in fact allow the action tells an
|
|
23
|
+
* operator they are protected when they are not. Trust in the boundary screen
|
|
24
|
+
* IS the product claim, so the screen has to be a view of the gate rather than
|
|
25
|
+
* a description of it.
|
|
26
|
+
*
|
|
27
|
+
* This is cheap precisely because `decideWorkerAction` is pure over
|
|
28
|
+
* `(worker, toolName, params, store, opts)` — no I/O, no side effects, so
|
|
29
|
+
* evaluating a hypothetical costs the same as evaluating a real call.
|
|
30
|
+
*
|
|
31
|
+
* ## What it deliberately does not do
|
|
32
|
+
*
|
|
33
|
+
* No side effects, and no approval-queue interaction: previewing an action must
|
|
34
|
+
* never enqueue one, or opening a screen would spam a human with requests
|
|
35
|
+
* nobody made. It also does not persist a decision record — a hypothetical is
|
|
36
|
+
* not a decision, and writing one would pollute the audit trail with things
|
|
37
|
+
* that never happened.
|
|
38
|
+
*/
|
|
39
|
+
import type { ForbidRule } from "./forbidPolicy.js";
|
|
40
|
+
import type { WorkerManifest } from "./worker.js";
|
|
41
|
+
import type { WorkerLevelStore } from "./workerLevelStore.js";
|
|
42
|
+
/** An action to ask about. `label` is what a person should see. */
|
|
43
|
+
export interface CandidateAction {
|
|
44
|
+
toolName: string;
|
|
45
|
+
params?: Record<string, unknown>;
|
|
46
|
+
/** Human phrasing, e.g. "Publish the release to npm". Defaults to toolName. */
|
|
47
|
+
label?: string;
|
|
48
|
+
}
|
|
49
|
+
/** One evaluated candidate. */
|
|
50
|
+
export interface PreviewedAction {
|
|
51
|
+
label: string;
|
|
52
|
+
toolName: string;
|
|
53
|
+
/** `${domain}:${reversibility}:${blastTier}` — the trust unit. */
|
|
54
|
+
classKey: string;
|
|
55
|
+
/** Why it landed in this column, in the gate's own words. */
|
|
56
|
+
reason: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ActionBoundary {
|
|
59
|
+
/** Flows without asking anyone. */
|
|
60
|
+
mayDoNow: PreviewedAction[];
|
|
61
|
+
/** A named person must say yes first. */
|
|
62
|
+
needsApproval: PreviewedAction[];
|
|
63
|
+
/** Refused outright — no approval unlocks these. */
|
|
64
|
+
notPermitted: PreviewedAction[];
|
|
65
|
+
}
|
|
66
|
+
export interface PreviewOpts {
|
|
67
|
+
forbidRules?: readonly ForbidRule[];
|
|
68
|
+
/** Situational risk, folded in exactly as the live gate folds it in. */
|
|
69
|
+
contextRisk?: import("./contextRisk.js").ContextRisk;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Bucket candidate actions into the three columns.
|
|
73
|
+
*
|
|
74
|
+
* Order within each column is the order the candidates were supplied, so a
|
|
75
|
+
* caller controls presentation without this module knowing anything about
|
|
76
|
+
* presentation.
|
|
77
|
+
*/
|
|
78
|
+
export declare function previewActions(worker: WorkerManifest, candidates: readonly CandidateAction[], store: WorkerLevelStore, opts?: PreviewOpts): ActionBoundary;
|
|
79
|
+
/** Total candidates evaluated — for a "N actions considered" caption. */
|
|
80
|
+
export declare function boundarySize(b: ActionBoundary): number;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prospective gate evaluation — "what could this worker do here?"
|
|
3
|
+
*
|
|
4
|
+
* The gate answers one question at a time, retrospectively: a tool call arrives
|
|
5
|
+
* and `decideWorkerAction` allows, gates or forbids it. That is the right shape
|
|
6
|
+
* for enforcement and the wrong shape for showing somebody the boundary, which
|
|
7
|
+
* has to be answerable *before* anything is attempted.
|
|
8
|
+
*
|
|
9
|
+
* This module asks the same question ahead of time, for a set of candidate
|
|
10
|
+
* actions, and buckets the answers into the three columns an operator reads:
|
|
11
|
+
* **may do now / needs approval / not permitted**.
|
|
12
|
+
*
|
|
13
|
+
* ## It must reuse the gate, not re-implement it
|
|
14
|
+
*
|
|
15
|
+
* The single property that makes this worth building: `previewActions` calls
|
|
16
|
+
* `decideWorkerAction` — the exact function enforcement uses. It contains no
|
|
17
|
+
* policy of its own, no parallel thresholds and no second copy of the
|
|
18
|
+
* reversibility rules.
|
|
19
|
+
*
|
|
20
|
+
* A preview with its own logic would be worse than no preview. It would drift,
|
|
21
|
+
* and the failure is silent and in the dangerous direction: a screen that says
|
|
22
|
+
* "not permitted" while the gate would in fact allow the action tells an
|
|
23
|
+
* operator they are protected when they are not. Trust in the boundary screen
|
|
24
|
+
* IS the product claim, so the screen has to be a view of the gate rather than
|
|
25
|
+
* a description of it.
|
|
26
|
+
*
|
|
27
|
+
* This is cheap precisely because `decideWorkerAction` is pure over
|
|
28
|
+
* `(worker, toolName, params, store, opts)` — no I/O, no side effects, so
|
|
29
|
+
* evaluating a hypothetical costs the same as evaluating a real call.
|
|
30
|
+
*
|
|
31
|
+
* ## What it deliberately does not do
|
|
32
|
+
*
|
|
33
|
+
* No side effects, and no approval-queue interaction: previewing an action must
|
|
34
|
+
* never enqueue one, or opening a screen would spam a human with requests
|
|
35
|
+
* nobody made. It also does not persist a decision record — a hypothetical is
|
|
36
|
+
* not a decision, and writing one would pollute the audit trail with things
|
|
37
|
+
* that never happened.
|
|
38
|
+
*/
|
|
39
|
+
import { decideWorkerAction, gateOutcomeFor } from "./workerGate.js";
|
|
40
|
+
/**
|
|
41
|
+
* Bucket candidate actions into the three columns.
|
|
42
|
+
*
|
|
43
|
+
* Order within each column is the order the candidates were supplied, so a
|
|
44
|
+
* caller controls presentation without this module knowing anything about
|
|
45
|
+
* presentation.
|
|
46
|
+
*/
|
|
47
|
+
export function previewActions(worker, candidates, store, opts = {}) {
|
|
48
|
+
const boundary = {
|
|
49
|
+
mayDoNow: [],
|
|
50
|
+
needsApproval: [],
|
|
51
|
+
notPermitted: [],
|
|
52
|
+
};
|
|
53
|
+
for (const c of candidates) {
|
|
54
|
+
const decision = decideWorkerAction(worker, c.toolName, c.params, store, {
|
|
55
|
+
...(opts.contextRisk ? { contextRisk: opts.contextRisk } : {}),
|
|
56
|
+
...(opts.forbidRules ? { forbidRules: opts.forbidRules } : {}),
|
|
57
|
+
});
|
|
58
|
+
const entry = {
|
|
59
|
+
label: c.label ?? c.toolName,
|
|
60
|
+
toolName: c.toolName,
|
|
61
|
+
classKey: decision.classKey,
|
|
62
|
+
reason: decision.reason,
|
|
63
|
+
};
|
|
64
|
+
// Route through the SAME mapping the enforcement path uses, so a column
|
|
65
|
+
// can never disagree with what would actually happen.
|
|
66
|
+
switch (gateOutcomeFor(decision.action)) {
|
|
67
|
+
case "flow":
|
|
68
|
+
boundary.mayDoNow.push(entry);
|
|
69
|
+
break;
|
|
70
|
+
case "queue":
|
|
71
|
+
boundary.needsApproval.push(entry);
|
|
72
|
+
break;
|
|
73
|
+
default:
|
|
74
|
+
// `refuse` — forbidden, or an action this build does not understand.
|
|
75
|
+
// Both belong in the column that says nobody can wave it through.
|
|
76
|
+
boundary.notPermitted.push(entry);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return boundary;
|
|
81
|
+
}
|
|
82
|
+
/** Total candidates evaluated — for a "N actions considered" caption. */
|
|
83
|
+
export function boundarySize(b) {
|
|
84
|
+
return b.mayDoNow.length + b.needsApproval.length + b.notPermitted.length;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=previewActions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewActions.js","sourceRoot":"","sources":["../../src/workers/previewActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAoCrE;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAsB,EACtB,UAAsC,EACtC,KAAuB,EACvB,OAAoB,EAAE;IAEtB,MAAM,QAAQ,GAAmB;QAC/B,QAAQ,EAAE,EAAE;QACZ,aAAa,EAAE,EAAE;QACjB,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE;YACvE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;QAEH,MAAM,KAAK,GAAoB;YAC7B,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ;YAC5B,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;SACxB,CAAC;QAEF,wEAAwE;QACxE,sDAAsD;QACtD,QAAQ,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,KAAK,MAAM;gBACT,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC9B,MAAM;YACR,KAAK,OAAO;gBACV,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnC,MAAM;YACR;gBACE,qEAAqE;gBACrE,kEAAkE;gBAClE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClC,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,CAAiB;IAC5C,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC;AAC5E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "1.1.0-beta.4.canary.
|
|
3
|
+
"version": "1.1.0-beta.4.canary.477",
|
|
4
4
|
"description": "Your personal AI runtime, local-first. Patchwork OS gives any AI model a consistent set of tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all on your machine, all under your policy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|