@opencxh/domain 1.264.4 → 1.264.5
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.cjs +19 -19
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1200 -1183
- package/dist/platform/tool-verdict.d.ts +80 -0
- package/dist/platform/tool-verdict.test.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Agent } from '../entities/agent/types';
|
|
2
|
+
import { AssistantMode } from '../entities/ai-message/types';
|
|
3
|
+
/**
|
|
4
|
+
* May this tool be offered to the model this turn — and if it writes, may it run?
|
|
5
|
+
*
|
|
6
|
+
* **One function for the layers that used to be five files.** "Why could it not do that" was
|
|
7
|
+
* answered by `collectTools` (the profile filter), `buildToolRuntime` (the unattended filter),
|
|
8
|
+
* `resolveToolset` (procedure and mode narrowing), `gate.ts` (the suggest gate) and
|
|
9
|
+
* `mode.ts` — each with its own copy of "what counts as a write" and its own idea of the order.
|
|
10
|
+
* They had already drifted once: only the autonomous path could hold a write, only the
|
|
11
|
+
* interactive one could pin a tool.
|
|
12
|
+
*
|
|
13
|
+
* Pure and per-tool on purpose: every one of these rules is about a single tool, and a reader
|
|
14
|
+
* chasing a missing tool should be able to run this in their head.
|
|
15
|
+
*
|
|
16
|
+
* What stays outside: the **scope gate** at the receiving app
|
|
17
|
+
* (`platform-api/ai-tool/registerAiToolProvider`, which authorises `<kind>:<id>` against the
|
|
18
|
+
* acting identity). That belongs to the receiver, not to the caller, and it is the one layer a
|
|
19
|
+
* caller must not be able to answer for itself.
|
|
20
|
+
*/
|
|
21
|
+
export type ToolVerdict =
|
|
22
|
+
/** Not offered to the model at all. */
|
|
23
|
+
"hidden"
|
|
24
|
+
/** Offered, and it runs. */
|
|
25
|
+
| "free"
|
|
26
|
+
/** Offered, but a call is captured for approval instead of executed. */
|
|
27
|
+
| "held";
|
|
28
|
+
/** What a verdict is made of. The declared half of a tool plus where it came from. */
|
|
29
|
+
export interface ToolFacts {
|
|
30
|
+
name: string;
|
|
31
|
+
access?: "read" | "write";
|
|
32
|
+
effect?: "internal" | "outward";
|
|
33
|
+
surface?: "interactive";
|
|
34
|
+
produces?: "draft";
|
|
35
|
+
/** Runs on the acting user's own connection (a personal MCP server). */
|
|
36
|
+
personal?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ToolVerdictContext {
|
|
39
|
+
/**
|
|
40
|
+
* Tool names the profile switched on. **`undefined` means no filter** — the catalog asks that
|
|
41
|
+
* way, and it is the difference between "this profile enabled nothing" (an empty set, nothing
|
|
42
|
+
* passes) and "do not filter".
|
|
43
|
+
*/
|
|
44
|
+
allowed?: ReadonlySet<string>;
|
|
45
|
+
/** Whether the acting user's own connections take part. Default `"off"`. */
|
|
46
|
+
personalTools?: "off" | "allow";
|
|
47
|
+
/** A procedure's narrowing. Narrows only — a name not already allowed does not come back. */
|
|
48
|
+
narrow?: ReadonlySet<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Is a person watching this turn?
|
|
51
|
+
*
|
|
52
|
+
* `false` hides personal tools and anything delivering to a client surface: an unattended run
|
|
53
|
+
* has nobody to deliver to, and a tool reporting success for something that lands nowhere is
|
|
54
|
+
* worse than a missing tool.
|
|
55
|
+
*/
|
|
56
|
+
attended: boolean;
|
|
57
|
+
/** Interactive only: what the user said this turn is for. Narrows. */
|
|
58
|
+
mode?: AssistantMode;
|
|
59
|
+
/** A read lane: nothing that writes, whatever else it declares. */
|
|
60
|
+
readOnly?: boolean;
|
|
61
|
+
/** Is the approval gate on for this turn? Then writes are held instead of run. */
|
|
62
|
+
gate?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* The agent's mandate, when an agent runs this turn. It may call a tool a read that declares
|
|
65
|
+
* itself a write, and vice versa — an admin's explicit choice about this colleague.
|
|
66
|
+
*/
|
|
67
|
+
policy?: Agent["toolPolicy"];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Does this tool mutate anything? **The mandate decides, then the tool, then the safe default.**
|
|
71
|
+
*
|
|
72
|
+
* `policy` → `access` → "write"
|
|
73
|
+
*
|
|
74
|
+
* The agent's policy sits deliberately on top: that is an admin's explicit statement about what
|
|
75
|
+
* this colleague may do unsupervised, and it may be stricter than what the tool says about
|
|
76
|
+
* itself. Without `access`, "unknown = write" applies and a read tool would ask for needless
|
|
77
|
+
* approval — which is why every descriptor should declare it.
|
|
78
|
+
*/
|
|
79
|
+
export declare function isWriteTool(tool: ToolFacts, policy?: Agent["toolPolicy"]): boolean;
|
|
80
|
+
export declare function toolVerdict(tool: ToolFacts, ctx: ToolVerdictContext): ToolVerdict;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|