@xemahq/kernel-contracts 0.3.5 → 0.3.6
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/agent-composition/index.d.ts +1 -0
- package/dist/agent-composition/index.d.ts.map +1 -1
- package/dist/agent-composition/index.js +1 -0
- package/dist/agent-composition/index.js.map +1 -1
- package/dist/agent-composition/lib/composition.d.ts +3 -10
- package/dist/agent-composition/lib/composition.d.ts.map +1 -1
- package/dist/agent-composition/lib/composition.js.map +1 -1
- package/dist/agent-composition/lib/invocation-overlay.d.ts +17 -0
- package/dist/agent-composition/lib/invocation-overlay.d.ts.map +1 -0
- package/dist/agent-composition/lib/invocation-overlay.js +3 -0
- package/dist/agent-composition/lib/invocation-overlay.js.map +1 -0
- package/dist/agent-permission/index.d.ts +2 -0
- package/dist/agent-permission/index.d.ts.map +1 -0
- package/dist/agent-permission/index.js +18 -0
- package/dist/agent-permission/index.js.map +1 -0
- package/dist/agent-permission/lib/permission-map.d.ts +6 -0
- package/dist/agent-permission/lib/permission-map.d.ts.map +1 -0
- package/dist/agent-permission/lib/permission-map.js +27 -0
- package/dist/agent-permission/lib/permission-map.js.map +1 -0
- package/dist/agent-workspace/awp-spec.json +1 -1
- package/dist/agent-workspace/lib/agent-tool-defaults.d.ts +2 -5
- package/dist/agent-workspace/lib/agent-tool-defaults.d.ts.map +1 -1
- package/dist/agent-workspace/lib/agent-tool-defaults.js +5 -25
- package/dist/agent-workspace/lib/agent-tool-defaults.js.map +1 -1
- package/dist/reference-resolution/index.d.ts +2 -0
- package/dist/reference-resolution/index.d.ts.map +1 -0
- package/dist/reference-resolution/index.js +18 -0
- package/dist/reference-resolution/index.js.map +1 -0
- package/dist/reference-resolution/lib/reference-resolution.d.ts +40 -0
- package/dist/reference-resolution/lib/reference-resolution.d.ts.map +1 -0
- package/dist/reference-resolution/lib/reference-resolution.js +42 -0
- package/dist/reference-resolution/lib/reference-resolution.js.map +1 -0
- package/dist/workflow/lib/compiled-workspace-manifest.d.ts +1 -1
- package/dist/workflow/lib/compiled-workspace-manifest.d.ts.map +1 -1
- package/dist/workflow/lib/model-ref.d.ts +18 -8
- package/dist/workflow/lib/model-ref.d.ts.map +1 -1
- package/dist/workflow/lib/model-ref.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-composition/index.ts +1 -0
- package/src/agent-composition/lib/composition.ts +11 -57
- package/src/agent-composition/lib/invocation-overlay.ts +75 -0
- package/src/agent-permission/index.ts +12 -0
- package/src/agent-permission/lib/permission-map.ts +71 -0
- package/src/agent-workspace/lib/agent-tool-defaults.ts +20 -56
- package/src/reference-resolution/index.ts +10 -0
- package/src/reference-resolution/lib/reference-resolution.ts +175 -0
- package/src/workflow/lib/compiled-workspace-manifest.ts +1 -1
- package/src/workflow/lib/model-ref.ts +81 -28
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
// the agent section of `WorkspaceManifest` into this primitive.
|
|
14
14
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
15
|
|
|
16
|
-
import type { PermissionMap } from '../../agent-workspace';
|
|
17
16
|
import type { ToolSelectionEntry } from '../../mcp-tool';
|
|
18
|
-
import type {
|
|
17
|
+
import type { NodeOverlayFragment } from '../../workflow';
|
|
19
18
|
import type { SkillRef } from '../../skill';
|
|
20
19
|
import type { CapabilityLayer } from './capability-layer';
|
|
21
20
|
import type { CompositionWorkspace } from './composition-workspace';
|
|
@@ -100,7 +99,7 @@ export interface CompositionLimits {
|
|
|
100
99
|
* `skills` / `tools` / `modelOverride` attach AT this node — they extend or
|
|
101
100
|
* override what the referenced agent definition declares intrinsically.
|
|
102
101
|
*/
|
|
103
|
-
export interface CompositionNode {
|
|
102
|
+
export interface CompositionNode extends NodeOverlayFragment {
|
|
104
103
|
/** The agent definition this node runs. */
|
|
105
104
|
readonly agent: AgentRef;
|
|
106
105
|
/** Optional alias when the same agent appears more than once in the tree. */
|
|
@@ -109,42 +108,10 @@ export interface CompositionNode {
|
|
|
109
108
|
readonly skills: readonly SkillRef[];
|
|
110
109
|
/** Tools attached at this node. */
|
|
111
110
|
readonly tools: readonly ToolSelectionEntry[];
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* `temperature` and (for `StrategyModelRef`) the `modelClass` — so a
|
|
117
|
-
* node specializes BOTH which model and how it samples here, without a
|
|
118
|
-
* dedicated parallel field. The bundle renderer reads
|
|
119
|
-
* `modelOverride.temperature` to stamp the agent's sampling temperature.
|
|
120
|
-
*/
|
|
121
|
-
readonly modelOverride?: ModelRef;
|
|
122
|
-
/**
|
|
123
|
-
* Node-level instructions — a prompt fragment layered ONTO the referenced
|
|
124
|
-
* agent definition's intrinsic system prompt. This is the "instructions"
|
|
125
|
-
* lever that lets a handful of base agents (generic/coder/explorer/planner)
|
|
126
|
-
* be specialized per node without authoring a new agent definition.
|
|
127
|
-
*
|
|
128
|
-
* Composite ordering (resolver-enforced): `agentDefinition.systemPrompt`
|
|
129
|
-
* THEN these `instructions`. The platform `system-overlay.md` (AWP base +
|
|
130
|
-
* deliverable contract + authority) is injected LATER by the runtime — it
|
|
131
|
-
* is NOT part of this field. Absent/blank = the base prompt passes through
|
|
132
|
-
* unchanged (never an empty append).
|
|
133
|
-
*/
|
|
134
|
-
readonly instructions?: string;
|
|
135
|
-
/**
|
|
136
|
-
* Node-level permission override — a partial `PermissionMap` deep-merged
|
|
137
|
-
* (per top-level key) OVER the referenced agent definition's authored
|
|
138
|
-
* `permission` block, BEFORE the system tiers are applied by
|
|
139
|
-
* `resolveAgentPermissions`. This is what lets a generic base agent
|
|
140
|
-
* (e.g. `planner`) be specialized into a read-only, no-network reviewer
|
|
141
|
-
* at a node — e.g. `{ edit: 'deny', webfetch: 'deny', task: { '*':
|
|
142
|
-
* 'deny', 'kb-researcher': 'allow' } }` — without authoring a new agent
|
|
143
|
-
* definition. A present key fully replaces the base agent's value for
|
|
144
|
-
* that key; absent keys fall through to the base. Omitted = the base
|
|
145
|
-
* agent's permissions pass through unchanged.
|
|
146
|
-
*/
|
|
147
|
-
readonly permission?: PermissionMap;
|
|
111
|
+
// modelOverride / instructions / permission — the INVOCATION-overlay trio —
|
|
112
|
+
// are inherited from NodeOverlayFragment (single declaration site). They
|
|
113
|
+
// OVERRIDE the model, APPEND to the base prompt, and RESTRICT-merge the
|
|
114
|
+
// permission for this node only.
|
|
148
115
|
/** Sub-agents — themselves fully-armed composition nodes (recursive). */
|
|
149
116
|
readonly children: readonly CompositionNode[];
|
|
150
117
|
/**
|
|
@@ -192,7 +159,7 @@ export interface Composition {
|
|
|
192
159
|
* Distinct from `CompositionNode` (the AUTHORED form): a resolved node
|
|
193
160
|
* has its agent reference fully version-pinned, never `latest`.
|
|
194
161
|
*/
|
|
195
|
-
export interface ResolvedCompositionNode {
|
|
162
|
+
export interface ResolvedCompositionNode extends NodeOverlayFragment {
|
|
196
163
|
/** Fully version-pinned agent reference. */
|
|
197
164
|
readonly agent: Required<AgentRef>;
|
|
198
165
|
readonly alias?: string;
|
|
@@ -200,23 +167,10 @@ export interface ResolvedCompositionNode {
|
|
|
200
167
|
readonly skills: readonly SkillRef[];
|
|
201
168
|
/** Tool references attached at this node. */
|
|
202
169
|
readonly tools: readonly ToolSelectionEntry[];
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
* `CompositionNode.instructions`. The composer/runtime layers this onto
|
|
208
|
-
* the referenced agent definition's `systemPrompt` (base prompt first,
|
|
209
|
-
* then instructions). Absent = no node-level override.
|
|
210
|
-
*/
|
|
211
|
-
readonly instructions?: string;
|
|
212
|
-
/**
|
|
213
|
-
* Resolved node-level permission override, copied verbatim from the
|
|
214
|
-
* source `CompositionNode.permission`. The bundle renderer deep-merges
|
|
215
|
-
* it (per top-level key) over the referenced agent definition's authored
|
|
216
|
-
* permission before the system tiers run. Absent = no node-level
|
|
217
|
-
* permission override.
|
|
218
|
-
*/
|
|
219
|
-
readonly permission?: PermissionMap;
|
|
170
|
+
// modelOverride / instructions / permission — inherited verbatim from the
|
|
171
|
+
// source node via NodeOverlayFragment (single declaration site). The
|
|
172
|
+
// composer layers instructions onto the base systemPrompt and deep-merges
|
|
173
|
+
// permission over the agent's authored permission before the system tiers.
|
|
220
174
|
/** Resolved sub-agent nodes (recursive). */
|
|
221
175
|
readonly children: readonly ResolvedCompositionNode[];
|
|
222
176
|
/**
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Invocation Overlay ──
|
|
3
|
+
//
|
|
4
|
+
// The INVOCATION-axis overlay: per-call shaping of a resolved agent that is
|
|
5
|
+
// NEVER persisted into identity. ONE shared shape for both call sites —
|
|
6
|
+
// a workflow step's `with:` block AND a session/thread override — so the
|
|
7
|
+
// platform has a single overlay contract, not two divergent ones.
|
|
8
|
+
//
|
|
9
|
+
// Semantics (add-or-restrict ONLY — an overlay can extend context and NARROW
|
|
10
|
+
// capability, but NEVER widen beyond the agent's own + org/project policy):
|
|
11
|
+
// - modelOverride : OVERRIDE (inherited from NodeOverlayFragment)
|
|
12
|
+
// - instructions : APPEND (inherited; appended AFTER the resolved
|
|
13
|
+
// agent prompt — same field, same append
|
|
14
|
+
// semantics as a node; NO separate
|
|
15
|
+
// `instructionsAppend` name — one concept)
|
|
16
|
+
// - permission : RESTRICT (inherited; deep-merge, may only narrow)
|
|
17
|
+
// - tools : ADD/REMOVE (still policy-checked at resolve time)
|
|
18
|
+
// - skills : ADD-only (identity skills are the floor)
|
|
19
|
+
//
|
|
20
|
+
// Agent SELECTION (which agent runs) is deliberately NOT part of this overlay:
|
|
21
|
+
// in a workflow that is `agentSlug`/`agentRef`, and `compositionRef` selects a
|
|
22
|
+
// workspace SOURCE, not the agent (see plan audit A5). The overlay only SHAPES
|
|
23
|
+
// the already-selected agent.
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
|
|
26
|
+
import type { ToolSelectionEntry } from '../../mcp-tool';
|
|
27
|
+
import type { SkillRef } from '../../skill';
|
|
28
|
+
import type { NodeOverlayFragment } from '../../workflow';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Tools requested for this invocation. `add` requests extra tools, `remove`
|
|
32
|
+
* drops tools by ref. Both are still validated against the agent's resolved
|
|
33
|
+
* permission AND the step/session policy at resolve time — a request can
|
|
34
|
+
* never force-enable a tool the agent is not allowed to use (fail-fast).
|
|
35
|
+
*/
|
|
36
|
+
export interface InvocationToolOverlay {
|
|
37
|
+
readonly add?: readonly ToolSelectionEntry[];
|
|
38
|
+
/** Tool refs to drop for this invocation. */
|
|
39
|
+
readonly remove?: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Skills requested for this invocation. ADD-only: the resolved agent's own
|
|
44
|
+
* skills are the floor and cannot be removed by an overlay (they are
|
|
45
|
+
* governed, registered identity). Removal/disable is a separate, later
|
|
46
|
+
* governed capability — not part of the per-call overlay.
|
|
47
|
+
*/
|
|
48
|
+
export interface InvocationSkillOverlay {
|
|
49
|
+
readonly add?: readonly SkillRef[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The canonical per-call overlay. Extends {@link NodeOverlayFragment}
|
|
54
|
+
* (model / instructions / permission) with tools + skills. Both the
|
|
55
|
+
* workflow-step overlay and the session overlay ARE this shape.
|
|
56
|
+
*/
|
|
57
|
+
export interface InvocationOverlay extends NodeOverlayFragment {
|
|
58
|
+
readonly tools?: InvocationToolOverlay;
|
|
59
|
+
readonly skills?: InvocationSkillOverlay;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A workflow step's typed `with:` overlay. Structurally an
|
|
64
|
+
* {@link InvocationOverlay}; named for the call site. The agent action
|
|
65
|
+
* manifest validates it via its `spec.inputs` JSON Schema (the existing
|
|
66
|
+
* fail-fast validation lane — NOT a new validation system).
|
|
67
|
+
*/
|
|
68
|
+
export type AgentStepWithOverlay = InvocationOverlay;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A session/thread invocation overlay — the SAME shape as the workflow
|
|
72
|
+
* step overlay so sessions and workflows shape an agent identically
|
|
73
|
+
* (no second, looser session override surface).
|
|
74
|
+
*/
|
|
75
|
+
export type SessionInvocationOverlay = InvocationOverlay;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Agent Permission Contracts — Barrel Export ──
|
|
3
|
+
//
|
|
4
|
+
// Kernel (Layer-0) leaf: the pure permission TYPES (PermissionMap,
|
|
5
|
+
// PermissionRule, PermissionAction, PermissionKey, KNOWN_PERMISSION_KEYS).
|
|
6
|
+
// Zero deps. Imported by `workflow`, `agent-workspace`, and any consumer
|
|
7
|
+
// that needs the permission shape — breaks the prior workflow↔agent-workspace
|
|
8
|
+
// cycle. The resolve LOGIC + system tiers live in
|
|
9
|
+
// `agent-workspace/lib/agent-tool-defaults.ts`.
|
|
10
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
11
|
+
|
|
12
|
+
export * from './lib/permission-map';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Agent Permission types — single source of truth (Layer-0 leaf) ──
|
|
3
|
+
//
|
|
4
|
+
// The PURE permission TYPES, extracted to their own dependency-free subpath
|
|
5
|
+
// so BOTH `workflow` (model-ref / compiled-workspace-manifest) and
|
|
6
|
+
// `agent-workspace` (the resolve logic) can import them WITHOUT creating a
|
|
7
|
+
// `workflow ↔ agent-workspace` import cycle. The merge logic + system tiers
|
|
8
|
+
// (`resolveAgentPermissions`, `SYSTEM_*_PERMISSIONS`,
|
|
9
|
+
// `assertNoRequiredPermissionsDenied`) stay in
|
|
10
|
+
// `agent-workspace/lib/agent-tool-defaults.ts` and import these types.
|
|
11
|
+
//
|
|
12
|
+
// Mirrors OpenCode's unified `permission` surface (`packages/opencode/src/
|
|
13
|
+
// config/permission.ts`).
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Permission keys that take a `Rule` shape — either a scalar action or
|
|
18
|
+
* a per-target map (e.g. `bash: { '*': 'allow', 'rm -rf *': 'deny' }`,
|
|
19
|
+
* `task: { 'html-builder': 'allow' }`, `external_directory: { '/**':
|
|
20
|
+
* 'allow' }`). Mirrors OpenCode's `permission.ts` `InputObject`.
|
|
21
|
+
*/
|
|
22
|
+
const KNOWN_RULE_PERMISSION_KEYS = [
|
|
23
|
+
'read',
|
|
24
|
+
'edit',
|
|
25
|
+
'glob',
|
|
26
|
+
'grep',
|
|
27
|
+
'list',
|
|
28
|
+
'bash',
|
|
29
|
+
'task',
|
|
30
|
+
'external_directory',
|
|
31
|
+
'lsp',
|
|
32
|
+
'skill',
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Permission keys that take a scalar `Action` only (no per-target map).
|
|
37
|
+
* Mirrors OpenCode's `permission.ts` `InputObject`.
|
|
38
|
+
*/
|
|
39
|
+
const KNOWN_ACTION_PERMISSION_KEYS = [
|
|
40
|
+
'todowrite',
|
|
41
|
+
'question',
|
|
42
|
+
'webfetch',
|
|
43
|
+
'websearch',
|
|
44
|
+
'doom_loop',
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
export const KNOWN_PERMISSION_KEYS = [
|
|
48
|
+
...KNOWN_RULE_PERMISSION_KEYS,
|
|
49
|
+
...KNOWN_ACTION_PERMISSION_KEYS,
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
export type PermissionKey = (typeof KNOWN_PERMISSION_KEYS)[number];
|
|
53
|
+
|
|
54
|
+
export type PermissionAction = 'allow' | 'ask' | 'deny';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A permission entry is either a scalar action or a per-target map. The
|
|
58
|
+
* map form is supported only for the keys in `KNOWN_RULE_PERMISSION_KEYS`
|
|
59
|
+
* — the action-only keys reject map shapes at the OpenCode schema layer.
|
|
60
|
+
* Catch-all entries (MCP tool names, biome-emitted globs) live alongside
|
|
61
|
+
* the closed set; their shape is validated by OpenCode at config load.
|
|
62
|
+
*/
|
|
63
|
+
export type PermissionRule = PermissionAction | Readonly<Record<string, PermissionAction>>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Full permission map. Closed-set keys carry typed rules; the index
|
|
67
|
+
* signature accommodates MCP tool names and biome-emitted glob patterns
|
|
68
|
+
* (e.g. `xema_*`, `emit*`) that OpenCode resolves via its catch-all
|
|
69
|
+
* `Schema.Record(Schema.String, Rule)` in `permission.ts`.
|
|
70
|
+
*/
|
|
71
|
+
export type PermissionMap = Readonly<Record<string, PermissionRule>>;
|
|
@@ -29,62 +29,26 @@
|
|
|
29
29
|
// pipelines, and authoring previews all merge through this function.
|
|
30
30
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
* Permission keys that take a scalar `Action` only (no per-target map).
|
|
53
|
-
* Mirrors OpenCode's `permission.ts` `InputObject`.
|
|
54
|
-
*/
|
|
55
|
-
const KNOWN_ACTION_PERMISSION_KEYS = [
|
|
56
|
-
'todowrite',
|
|
57
|
-
'question',
|
|
58
|
-
'webfetch',
|
|
59
|
-
'websearch',
|
|
60
|
-
'doom_loop',
|
|
61
|
-
] as const;
|
|
62
|
-
|
|
63
|
-
export const KNOWN_PERMISSION_KEYS = [
|
|
64
|
-
...KNOWN_RULE_PERMISSION_KEYS,
|
|
65
|
-
...KNOWN_ACTION_PERMISSION_KEYS,
|
|
66
|
-
] as const;
|
|
67
|
-
|
|
68
|
-
export type PermissionKey = (typeof KNOWN_PERMISSION_KEYS)[number];
|
|
69
|
-
|
|
70
|
-
export type PermissionAction = 'allow' | 'ask' | 'deny';
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* A permission entry is either a scalar action or a per-target map. The
|
|
74
|
-
* map form is supported only for the keys in `KNOWN_RULE_PERMISSION_KEYS`
|
|
75
|
-
* — the action-only keys reject map shapes at the OpenCode schema layer.
|
|
76
|
-
* Catch-all entries (MCP tool names, biome-emitted globs) live alongside
|
|
77
|
-
* the closed set; their shape is validated by OpenCode at config load.
|
|
78
|
-
*/
|
|
79
|
-
export type PermissionRule = PermissionAction | Readonly<Record<string, PermissionAction>>;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Full permission map. Closed-set keys carry typed rules; the index
|
|
83
|
-
* signature accommodates MCP tool names and biome-emitted glob patterns
|
|
84
|
-
* (e.g. `xema_*`, `emit*`) that OpenCode resolves via its catch-all
|
|
85
|
-
* `Schema.Record(Schema.String, Rule)` in `permission.ts`.
|
|
86
|
-
*/
|
|
87
|
-
export type PermissionMap = Readonly<Record<string, PermissionRule>>;
|
|
32
|
+
// The pure permission TYPES now live in the dependency-free `agent-permission`
|
|
33
|
+
// leaf subpath (breaking the prior workflow↔agent-workspace cycle). Import the
|
|
34
|
+
// value (`KNOWN_PERMISSION_KEYS`) for the resolve logic below + the types, and
|
|
35
|
+
// re-export all of them so the `agent-workspace` barrel surface stays stable
|
|
36
|
+
// for every existing consumer.
|
|
37
|
+
import { KNOWN_PERMISSION_KEYS } from '../../agent-permission';
|
|
38
|
+
import type {
|
|
39
|
+
PermissionAction,
|
|
40
|
+
PermissionKey,
|
|
41
|
+
PermissionMap,
|
|
42
|
+
PermissionRule,
|
|
43
|
+
} from '../../agent-permission';
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
KNOWN_PERMISSION_KEYS,
|
|
47
|
+
type PermissionAction,
|
|
48
|
+
type PermissionKey,
|
|
49
|
+
type PermissionMap,
|
|
50
|
+
type PermissionRule,
|
|
51
|
+
} from '../../agent-permission';
|
|
88
52
|
|
|
89
53
|
/**
|
|
90
54
|
* Permissions every agent gets — manifests cannot deny them. Removing
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Reference Resolution Contracts — Barrel Export ──
|
|
3
|
+
//
|
|
4
|
+
// Kernel (Layer-0) leaf: the shared graceful-degradation decision (DBM.1) used
|
|
5
|
+
// by every resolver that walks a definition's declared references. Zero
|
|
6
|
+
// cross-subpath deps so agent-composition / skill / capability / workflow /
|
|
7
|
+
// action resolvers can all import it without a cycle.
|
|
8
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
9
|
+
|
|
10
|
+
export * from './lib/reference-resolution';
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// ── Reference Resolution — graceful-degradation decision (DBM.1) ──
|
|
3
|
+
//
|
|
4
|
+
// The ONE shared contract every resolver uses when it walks a definition's
|
|
5
|
+
// declared references (an Agent node's `agentRef`, a skill's sub-skill, an
|
|
6
|
+
// action's capability, a workflow's `uses:`) and asks "is this reference
|
|
7
|
+
// available right now, and what do I do if it isn't?".
|
|
8
|
+
//
|
|
9
|
+
// It exists because of DYNAMIC BIOME MODULARITY: a definition authored while
|
|
10
|
+
// biome X was installed keeps referencing X's contributions after X is
|
|
11
|
+
// uninstalled/disabled. Today every resolver hard-fails uniformly
|
|
12
|
+
// (AGENT_NOT_REGISTERED / MOUNT_SOURCE_NOT_FOUND aborts the whole run). The
|
|
13
|
+
// shared policy below lets a reference be declared `optional` so its absence
|
|
14
|
+
// degrades to a typed, observable skip instead of aborting — while the DEFAULT
|
|
15
|
+
// stays fail-fast/fail-closed (no silent fallback).
|
|
16
|
+
//
|
|
17
|
+
// Modeled on `ResolvedModelDecision` (the Model Matrix's traced outcome): a
|
|
18
|
+
// resolver returns one {@link ResolvedReferenceDecision} per reference, carrying
|
|
19
|
+
// the outcome + a human-readable `reason` for the Studio debugger. Distinct
|
|
20
|
+
// from model resolution on purpose — the Model Matrix always has a DEFAULT rule
|
|
21
|
+
// so it can never be "unavailable"; references genuinely can.
|
|
22
|
+
//
|
|
23
|
+
// Pure Layer-0 leaf: zero cross-subpath imports so EVERY resolver
|
|
24
|
+
// (agent-composition / skill / capability / workflow / action) can import it
|
|
25
|
+
// without creating a cycle.
|
|
26
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* How a resolver must treat a reference whose backing contribution is not
|
|
30
|
+
* currently available. Closed set; the DEFAULT is {@link Required}.
|
|
31
|
+
*
|
|
32
|
+
* This is the per-reference knob that makes biome add/remove non-breaking:
|
|
33
|
+
* authors mark the references they can live without as {@link Optional}; every
|
|
34
|
+
* other reference keeps the fail-fast contract.
|
|
35
|
+
*/
|
|
36
|
+
export enum MissingReferencePolicy {
|
|
37
|
+
/**
|
|
38
|
+
* Default. An unavailable reference is fatal — the resolver throws and the
|
|
39
|
+
* whole resolution/run fails fast. Never degrades silently.
|
|
40
|
+
*/
|
|
41
|
+
Required = 'required',
|
|
42
|
+
/**
|
|
43
|
+
* An unavailable reference is skipped with a typed warning
|
|
44
|
+
* ({@link ReferenceResolutionState.OptionalSkipped}) and resolution
|
|
45
|
+
* continues without it. The only sanctioned degradation path.
|
|
46
|
+
*/
|
|
47
|
+
Optional = 'optional',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The four — and only four — outcomes of resolving a single reference.
|
|
52
|
+
* Closed set; this is the "4-state ResolverDecision" of DBM.1.
|
|
53
|
+
*/
|
|
54
|
+
export enum ReferenceResolutionState {
|
|
55
|
+
/** Resolved to a live, available contribution. */
|
|
56
|
+
Present = 'present',
|
|
57
|
+
/**
|
|
58
|
+
* The reference is declared on the definition but its backing contribution
|
|
59
|
+
* is not currently available — typically because the owning biome was
|
|
60
|
+
* uninstalled or disabled. Fatal under {@link MissingReferencePolicy.Required};
|
|
61
|
+
* degrades to {@link OptionalSkipped} under {@link MissingReferencePolicy.Optional}.
|
|
62
|
+
*/
|
|
63
|
+
DeclaredButUnavailable = 'declared-but-unavailable',
|
|
64
|
+
/**
|
|
65
|
+
* An {@link MissingReferencePolicy.Optional} reference that was
|
|
66
|
+
* {@link DeclaredButUnavailable} and was therefore skipped; resolution
|
|
67
|
+
* continued without it. This is the graceful-degradation terminal state.
|
|
68
|
+
*/
|
|
69
|
+
OptionalSkipped = 'optional-skipped',
|
|
70
|
+
/**
|
|
71
|
+
* The reference resolves to a contribution the caller is NOT permitted to
|
|
72
|
+
* use (governance / scope / visibility denied it). Always fatal regardless
|
|
73
|
+
* of policy — fail-closed, never downgraded to a skip.
|
|
74
|
+
*/
|
|
75
|
+
Denied = 'denied',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The closed set of reference KINDS a definition can declare and a resolver
|
|
80
|
+
* can resolve. Adding a new resolvable reference type = a one-line enum
|
|
81
|
+
* extension here.
|
|
82
|
+
*/
|
|
83
|
+
export enum ReferenceKind {
|
|
84
|
+
/** An Agent node's `agentRef` (a child agent / sub-agent). */
|
|
85
|
+
Agent = 'agent',
|
|
86
|
+
/** A skill bundle slug (intrinsic, node-attached, or a sub-skill). */
|
|
87
|
+
Skill = 'skill',
|
|
88
|
+
/** An MCP tool selection entry (`<provider>:<tool>@<v>`). */
|
|
89
|
+
Tool = 'tool',
|
|
90
|
+
/** A capability ref (`document:pdf-to-markdown@1`) reached via the router. */
|
|
91
|
+
Capability = 'capability',
|
|
92
|
+
/** A workflow action ref. */
|
|
93
|
+
Action = 'action',
|
|
94
|
+
/** A sub-workflow `uses:` ref. */
|
|
95
|
+
Workflow = 'workflow',
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Declared-vs-enforced verification of a {@link ReferenceResolutionState.Present}
|
|
100
|
+
* reference — adopted from NemoClaw's verification model. Answers "the registry
|
|
101
|
+
* SAYS this exists, but is it actually reachable at the gateway/runtime?".
|
|
102
|
+
* Surfaced for diagnostics; it does NOT change fail-fast semantics (an
|
|
103
|
+
* unreachable-but-required reference still fails).
|
|
104
|
+
*/
|
|
105
|
+
export enum ReferenceVerification {
|
|
106
|
+
/** Declared in the registry AND confirmed reachable at the gateway/runtime. */
|
|
107
|
+
Verified = 'verified',
|
|
108
|
+
/** Declared in the registry but reachability at runtime is unconfirmed. */
|
|
109
|
+
RegistryOnly = 'registry-only',
|
|
110
|
+
/** Reachable at the gateway/runtime but with no registry declaration. */
|
|
111
|
+
GatewayOnly = 'gateway-only',
|
|
112
|
+
/** Neither declared nor reachable — pairs with {@link ReferenceResolutionState.DeclaredButUnavailable}. */
|
|
113
|
+
Unavailable = 'unavailable',
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Owner attribution for a reference — which biome contributes it (NemoClaw's
|
|
118
|
+
* owner-attribution shape). The key signal behind a
|
|
119
|
+
* {@link ReferenceResolutionState.DeclaredButUnavailable} outcome: it names the
|
|
120
|
+
* biome whose install/enable would make the reference {@link ReferenceResolutionState.Present}
|
|
121
|
+
* again, so the UI can say "install biome X to restore `media:transcribe@1`".
|
|
122
|
+
*
|
|
123
|
+
* Both fields optional — System/kernel-shipped references have no owning biome.
|
|
124
|
+
*/
|
|
125
|
+
export interface ReferenceOwner {
|
|
126
|
+
/** The contributing biome's id; absent for System/kernel-shipped references. */
|
|
127
|
+
readonly biomeId?: string;
|
|
128
|
+
/** The contributing biome's version at resolution time, when known. */
|
|
129
|
+
readonly biomeVersion?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The traced outcome of resolving ONE declared reference — the per-reference
|
|
134
|
+
* sibling of {@link ResolvedModelDecision}. A resolver emits one of these per
|
|
135
|
+
* reference it walks; the set is the audit trail the Studio debugger renders
|
|
136
|
+
* and the basis for any fail-fast throw.
|
|
137
|
+
*/
|
|
138
|
+
export interface ResolvedReferenceDecision {
|
|
139
|
+
/** What kind of reference this is. */
|
|
140
|
+
readonly kind: ReferenceKind;
|
|
141
|
+
/** The ref/slug exactly as authored on the definition. */
|
|
142
|
+
readonly ref: string;
|
|
143
|
+
/** The pinned version the definition requested, when it pinned one. */
|
|
144
|
+
readonly version?: string;
|
|
145
|
+
/** The policy that governed this reference (default {@link MissingReferencePolicy.Required}). */
|
|
146
|
+
readonly policy: MissingReferencePolicy;
|
|
147
|
+
/** The resolution outcome. */
|
|
148
|
+
readonly state: ReferenceResolutionState;
|
|
149
|
+
/** Declared-vs-enforced verification, when the resolver could determine it. */
|
|
150
|
+
readonly verification?: ReferenceVerification;
|
|
151
|
+
/** Which biome contributes the reference, for "install X to restore" UX. */
|
|
152
|
+
readonly owner?: ReferenceOwner;
|
|
153
|
+
/** Human-readable reason for the Studio debugger; mirrors `ResolvedModelDecision.reason`. */
|
|
154
|
+
readonly reason: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* `true` when the decision must abort resolution fail-fast — every
|
|
159
|
+
* {@link ReferenceResolutionState.Denied}, plus any
|
|
160
|
+
* {@link ReferenceResolutionState.DeclaredButUnavailable} that was NOT marked
|
|
161
|
+
* {@link MissingReferencePolicy.Optional}. The single predicate every resolver
|
|
162
|
+
* checks so the fail-fast rule is implemented in exactly one place (no
|
|
163
|
+
* per-resolver re-derivation, no silent divergence).
|
|
164
|
+
*/
|
|
165
|
+
export function isFatalReferenceDecision(
|
|
166
|
+
decision: ResolvedReferenceDecision,
|
|
167
|
+
): boolean {
|
|
168
|
+
if (decision.state === ReferenceResolutionState.Denied) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
if (decision.state === ReferenceResolutionState.DeclaredButUnavailable) {
|
|
172
|
+
return decision.policy !== MissingReferencePolicy.Optional;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* → workflow-contracts → workspace-manifest-dsl.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { PermissionMap } from '../../agent-
|
|
11
|
+
import type { PermissionMap } from '../../agent-permission';
|
|
12
12
|
import type { ToolSelectionEntry } from '../../mcp-tool';
|
|
13
13
|
|
|
14
14
|
import type { AgentRunRole } from './agent-role';
|