@osovv/vv-opencode 1.5.0 → 1.6.0
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/CHANGELOG.md +9 -0
- package/README.md +39 -8
- package/dist/lib/agent-tool-catalog.d.ts +144 -0
- package/dist/lib/agent-tool-catalog.js +2551 -0
- package/dist/lib/agent-tool-catalog.js.map +1 -0
- package/dist/lib/agent-tool-contract.d.ts +200 -0
- package/dist/lib/agent-tool-contract.js +407 -0
- package/dist/lib/agent-tool-contract.js.map +1 -0
- package/dist/lib/workflow-contract.d.ts +12 -0
- package/dist/lib/workflow-contract.js +71 -18
- package/dist/lib/workflow-contract.js.map +1 -1
- package/dist/plugins/hashline-edit/index.js +102 -97
- package/dist/plugins/hashline-edit/index.js.map +1 -1
- package/dist/plugins/hashline-edit/normalize-edits.d.ts +2 -8
- package/dist/plugins/hashline-edit/normalize-edits.js +32 -17
- package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -1
- package/dist/plugins/hashline-edit/schemas.d.ts +246 -0
- package/dist/plugins/hashline-edit/schemas.js +659 -0
- package/dist/plugins/hashline-edit/schemas.js.map +1 -0
- package/dist/plugins/hashline-edit/str-replace-editor.d.ts +6 -17
- package/dist/plugins/hashline-edit/str-replace-editor.js +19 -21
- package/dist/plugins/hashline-edit/str-replace-editor.js.map +1 -1
- package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
- package/dist/plugins/hashline-edit/tool-description.js +20 -4
- package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
- package/dist/plugins/web-tools/fetch-service.d.ts +8 -5
- package/dist/plugins/web-tools/fetch-service.js +30 -45
- package/dist/plugins/web-tools/fetch-service.js.map +1 -1
- package/dist/plugins/web-tools/index.js +23 -5
- package/dist/plugins/web-tools/index.js.map +1 -1
- package/dist/plugins/web-tools/schemas.d.ts +469 -0
- package/dist/plugins/web-tools/schemas.js +523 -0
- package/dist/plugins/web-tools/schemas.js.map +1 -0
- package/dist/plugins/web-tools/search-service.d.ts +6 -3
- package/dist/plugins/web-tools/search-service.js +24 -29
- package/dist/plugins/web-tools/search-service.js.map +1 -1
- package/dist/plugins/workflow/authority.d.ts +6 -0
- package/dist/plugins/workflow/authority.js +45 -10
- package/dist/plugins/workflow/authority.js.map +1 -1
- package/dist/plugins/workflow/authorization.js +16 -8
- package/dist/plugins/workflow/authorization.js.map +1 -1
- package/dist/plugins/workflow/checkpoints.d.ts +41 -2
- package/dist/plugins/workflow/checkpoints.js +176 -47
- package/dist/plugins/workflow/checkpoints.js.map +1 -1
- package/dist/plugins/workflow/delegated.d.ts +15 -1
- package/dist/plugins/workflow/delegated.js +65 -35
- package/dist/plugins/workflow/delegated.js.map +1 -1
- package/dist/plugins/workflow/execution.d.ts +15 -30
- package/dist/plugins/workflow/execution.js +133 -33
- package/dist/plugins/workflow/execution.js.map +1 -1
- package/dist/plugins/workflow/index.js +177 -112
- package/dist/plugins/workflow/index.js.map +1 -1
- package/dist/plugins/workflow/input-validation.d.ts +48 -0
- package/dist/plugins/workflow/input-validation.js +536 -0
- package/dist/plugins/workflow/input-validation.js.map +1 -0
- package/dist/plugins/workflow/inspection.d.ts +60 -0
- package/dist/plugins/workflow/inspection.js +316 -0
- package/dist/plugins/workflow/inspection.js.map +1 -0
- package/dist/plugins/workflow/protocol.d.ts +2 -0
- package/dist/plugins/workflow/protocol.js +26 -4
- package/dist/plugins/workflow/protocol.js.map +1 -1
- package/dist/plugins/workflow/recovery.d.ts +2 -1
- package/dist/plugins/workflow/recovery.js +79 -12
- package/dist/plugins/workflow/recovery.js.map +1 -1
- package/dist/plugins/workflow/repair.d.ts +1 -1
- package/dist/plugins/workflow/repair.js +9 -10
- package/dist/plugins/workflow/repair.js.map +1 -1
- package/dist/plugins/workflow/results.d.ts +2566 -0
- package/dist/plugins/workflow/results.js +1111 -0
- package/dist/plugins/workflow/results.js.map +1 -0
- package/dist/plugins/workflow/schemas.d.ts +214 -24
- package/dist/plugins/workflow/schemas.js +350 -89
- package/dist/plugins/workflow/schemas.js.map +1 -1
- package/dist/plugins/workflow/state.d.ts +3 -2
- package/dist/plugins/workflow/state.js +15 -8
- package/dist/plugins/workflow/state.js.map +1 -1
- package/dist/plugins/workflow/system-instruction.md +17 -1
- package/dist/plugins/workflow/tooling.d.ts +2 -18
- package/dist/plugins/workflow/tooling.js +477 -460
- package/dist/plugins/workflow/tooling.js.map +1 -1
- package/dist/plugins/workflow/transactions.d.ts +13 -0
- package/dist/plugins/workflow/transactions.js +13 -3
- package/dist/plugins/workflow/transactions.js.map +1 -1
- package/package.json +6 -3
- package/schemas/vvoc/v3.json +1 -1
- package/templates/agents/vv-code-reviewer.md +13 -4
- package/templates/agents/vv-implementer.md +16 -9
- package/templates/agents/vv-spec-reviewer.md +13 -4
- package/templates/skills/vv-execute/SKILL.md +3 -3
- package/templates/skills/vv-execute/references/tool-contracts.md +1750 -0
- package/templates/skills/vv-review/SKILL.md +1 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
// FILE: src/lib/agent-tool-contract.ts
|
|
2
|
+
// VERSION: 1.1.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Provide reusable cross-plugin agent-tool contract primitives: registered raw argument maps, strict full-object runtime schemas with output inference, bounded diagnostics, fail-closed definition/pre-execute/direct-execute guards, SDK-compatible result-envelope helpers, and loaded contract identity.
|
|
5
|
+
// SCOPE: Generic owned-tool contract descriptors and host-boundary adapters only. No catalog aggregation, no workflow/plugin runtime imports, no permission or state-eligibility decisions. Uses the pinned SDK tool.schema Zod instance; zod imports are type-only. Result-envelope validation is producer/test-only and never wraps post-side-effect execution.
|
|
6
|
+
// DEPENDS: [@opencode-ai/plugin, zod (types), src/lib/package.ts]
|
|
7
|
+
// LINKS: [M-AGENT-TOOL-CONTRACT]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// AGENT_TOOL_CONTRACT_REVISION - Public tool-contract revision string for loaded identity.
|
|
14
|
+
// PACKAGE_NAME - Re-exported canonical package name from package.ts.
|
|
15
|
+
// PACKAGE_VERSION - Re-exported cached package version from package.ts.
|
|
16
|
+
// resolveToolContractReferencePath - Package-relative path to the tool-contracts reference document.
|
|
17
|
+
// MAX_CONTRACT_ISSUES - Maximum structural issues retained per diagnostic.
|
|
18
|
+
// MAX_ISSUE_PATH_CHARS - Maximum rendered issue path length.
|
|
19
|
+
// MAX_ISSUE_MESSAGE_CHARS - Maximum rendered issue message length.
|
|
20
|
+
// MAX_ISSUE_VALUE_CHARS - Maximum safe scalar preview length.
|
|
21
|
+
// ContractIssueCode - Stable machine-readable structural issue codes.
|
|
22
|
+
// ContractIssue - Bounded, tokenized structural issue with safe value/type summary.
|
|
23
|
+
// escapePathSegment - Escape one issue path segment for safe tokenized rendering.
|
|
24
|
+
// formatIssuePath - Render a Zod path tuple as a bounded, control-safe token path.
|
|
25
|
+
// summarizeReceivedValue - Safe bounded scalar/container value summary.
|
|
26
|
+
// toContractIssues - Convert a ZodError into bounded tokenized contract issues (preserves union branch paths).
|
|
27
|
+
// formatContractIssues - Render issues as a bounded single-line explanation.
|
|
28
|
+
// ContractInputError - Pre-execution structural rejection with code, category, and issues.
|
|
29
|
+
// ContractHostCompatibilityError - Fail-closed host-context rejection for unsupported definition publication.
|
|
30
|
+
// OperationExample - Named accept/reject operation example metadata for a contract.
|
|
31
|
+
// OwnedToolResult - Object branch of the pinned SDK ToolResult (assignable through tool execute).
|
|
32
|
+
// OwnedToolAttachment - Pinned SDK ToolAttachment shape.
|
|
33
|
+
// ownedToolResult - Build an SDK-compatible structured tool result envelope.
|
|
34
|
+
// ownedToolAttachmentSchema - Strict attachment envelope schema for producer/test validation.
|
|
35
|
+
// ownedToolResultSchema - Strict result envelope schema; metadata/document content remain opaque.
|
|
36
|
+
// validateOwnedToolResult - Producer/test-only result envelope validation (no post-side-effect wrapper).
|
|
37
|
+
// strictObject - Build a closed object schema on the SDK tool.schema instance.
|
|
38
|
+
// contractInputJsonSchema - Input-mode JSON Schema projection for a contract schema.
|
|
39
|
+
// OwnedToolArgs - Schema-inferred argument type for an owned-tool registered map.
|
|
40
|
+
// OwnedToolContract - Registered raw map plus strict runtime schema and typed parse helpers.
|
|
41
|
+
// defineOwnedToolContract - Define a closed owned-tool contract from a raw argument map.
|
|
42
|
+
// parseOwnedToolArgs - Direct-execute parse returning schema-inferred output (defaults applied).
|
|
43
|
+
// ToolDefinitionHookOutput - Narrow structural view of the SDK tool.definition hook output.
|
|
44
|
+
// createToolDefinitionAdapter - Owned-only fail-closed tool.definition adapter publishing strict jsonSchema while preserving parameters identity.
|
|
45
|
+
// createPreExecuteGuard - Owned-only tool.execute.before structural guard that never mutates raw args.
|
|
46
|
+
// END_MODULE_MAP
|
|
47
|
+
//
|
|
48
|
+
// START_CHANGE_SUMMARY
|
|
49
|
+
// LAST_CHANGE: [C-AGENT-TOOL-CONTRACTS - Correction cycle: fail-closed definition publication, Zod output inference end-to-end, SDK-compatible result envelope + producer validation schema, escaped diagnostic paths, and preserved nested union issue paths.]
|
|
50
|
+
// END_CHANGE_SUMMARY
|
|
51
|
+
import { tool } from "@opencode-ai/plugin";
|
|
52
|
+
import { join } from "node:path";
|
|
53
|
+
import { fileURLToPath } from "node:url";
|
|
54
|
+
import { PACKAGE_NAME, PACKAGE_VERSION } from "./package.js";
|
|
55
|
+
export { PACKAGE_NAME, PACKAGE_VERSION };
|
|
56
|
+
// START_BLOCK_CONTRACT_IDENTITY
|
|
57
|
+
/** Public tool-contract revision; independent of persistence and workflow contract versions. */
|
|
58
|
+
export const AGENT_TOOL_CONTRACT_REVISION = "1";
|
|
59
|
+
const TOOL_CONTRACT_REFERENCE_PACKAGE_PATH = "templates/skills/vv-execute/references/tool-contracts.md";
|
|
60
|
+
/**
|
|
61
|
+
* Resolve the package-relative path to the shipped tool-contracts reference document.
|
|
62
|
+
* Uses the loaded module location, not global installs or user config.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveToolContractReferencePath() {
|
|
65
|
+
const packageRoot = fileURLToPath(new URL("../../", import.meta.url));
|
|
66
|
+
return join(packageRoot, TOOL_CONTRACT_REFERENCE_PACKAGE_PATH);
|
|
67
|
+
}
|
|
68
|
+
// END_BLOCK_CONTRACT_IDENTITY
|
|
69
|
+
// START_BLOCK_ISSUES
|
|
70
|
+
/** Maximum number of structural issues retained in one diagnostic. */
|
|
71
|
+
export const MAX_CONTRACT_ISSUES = 8;
|
|
72
|
+
/** Maximum rendered path length in characters. */
|
|
73
|
+
export const MAX_ISSUE_PATH_CHARS = 120;
|
|
74
|
+
/** Maximum rendered message length in characters. */
|
|
75
|
+
export const MAX_ISSUE_MESSAGE_CHARS = 200;
|
|
76
|
+
/** Maximum safe scalar preview length in characters. */
|
|
77
|
+
export const MAX_ISSUE_VALUE_CHARS = 48;
|
|
78
|
+
function truncateChars(value, max) {
|
|
79
|
+
if (value.length <= max)
|
|
80
|
+
return value;
|
|
81
|
+
return `${value.slice(0, Math.max(0, max - 1))}…`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Escape one path segment so user-controlled keys cannot inject control characters
|
|
85
|
+
* or forge ambiguous dotted/bracketed paths.
|
|
86
|
+
*/
|
|
87
|
+
export function escapePathSegment(segment) {
|
|
88
|
+
let escaped = "";
|
|
89
|
+
for (const character of segment) {
|
|
90
|
+
const code = character.codePointAt(0) ?? 0;
|
|
91
|
+
if (code < 0x20 || code === 0x7f) {
|
|
92
|
+
escaped += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
93
|
+
}
|
|
94
|
+
else if (character === "\\" || character === "." || character === "[" || character === "]") {
|
|
95
|
+
escaped += `\\${character}`;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
escaped += character;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return escaped;
|
|
102
|
+
}
|
|
103
|
+
/** Render a Zod path tuple as a bounded dotted/bracketed token path with escaped segments. */
|
|
104
|
+
export function formatIssuePath(path) {
|
|
105
|
+
let rendered = "";
|
|
106
|
+
for (const segment of path) {
|
|
107
|
+
if (typeof segment === "number") {
|
|
108
|
+
rendered += `[${segment}]`;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const token = escapePathSegment(typeof segment === "symbol" ? segment.toString() : segment);
|
|
112
|
+
rendered = rendered ? `${rendered}.${token}` : token;
|
|
113
|
+
}
|
|
114
|
+
if (rendered.length >= MAX_ISSUE_PATH_CHARS) {
|
|
115
|
+
return truncateChars(rendered, MAX_ISSUE_PATH_CHARS);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return rendered || "(root)";
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Build a safe, bounded received-value summary.
|
|
122
|
+
* Scalars get a short preview; containers get a type name only — never a payload echo.
|
|
123
|
+
*/
|
|
124
|
+
export function summarizeReceivedValue(value) {
|
|
125
|
+
if (value === null)
|
|
126
|
+
return "null";
|
|
127
|
+
if (value === undefined)
|
|
128
|
+
return "undefined";
|
|
129
|
+
if (typeof value === "string") {
|
|
130
|
+
return truncateChars(JSON.stringify(value), MAX_ISSUE_VALUE_CHARS);
|
|
131
|
+
}
|
|
132
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
133
|
+
return truncateChars(String(value), MAX_ISSUE_VALUE_CHARS);
|
|
134
|
+
}
|
|
135
|
+
if (Array.isArray(value))
|
|
136
|
+
return "array";
|
|
137
|
+
if (typeof value === "object")
|
|
138
|
+
return "object";
|
|
139
|
+
return truncateChars(String(value), MAX_ISSUE_VALUE_CHARS);
|
|
140
|
+
}
|
|
141
|
+
function issueCodeOf(code) {
|
|
142
|
+
switch (code) {
|
|
143
|
+
case "unrecognized_keys":
|
|
144
|
+
case "invalid_value":
|
|
145
|
+
case "invalid_type":
|
|
146
|
+
case "invalid_format":
|
|
147
|
+
case "too_small":
|
|
148
|
+
case "too_big":
|
|
149
|
+
case "missing_value":
|
|
150
|
+
case "invalid_union":
|
|
151
|
+
case "custom":
|
|
152
|
+
return code;
|
|
153
|
+
default:
|
|
154
|
+
return "custom";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function pushConcreteIssue(issues, raw, basePath) {
|
|
158
|
+
if (issues.length >= MAX_CONTRACT_ISSUES)
|
|
159
|
+
return;
|
|
160
|
+
const code = issueCodeOf(raw.code);
|
|
161
|
+
if (raw.code === "unrecognized_keys" && Array.isArray(raw.keys)) {
|
|
162
|
+
for (const key of raw.keys) {
|
|
163
|
+
if (issues.length >= MAX_CONTRACT_ISSUES)
|
|
164
|
+
break;
|
|
165
|
+
issues.push({
|
|
166
|
+
code: "unrecognized_keys",
|
|
167
|
+
path: formatIssuePath([...basePath, String(key)]),
|
|
168
|
+
message: truncateChars(`unrecognized key ${JSON.stringify(truncateChars(String(key), MAX_ISSUE_VALUE_CHARS))}`, MAX_ISSUE_MESSAGE_CHARS),
|
|
169
|
+
expected: "a known property of this request object",
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const expected = Array.isArray(raw.values) && raw.values.length > 0
|
|
175
|
+
? truncateChars(raw.values.map((value) => summarizeReceivedValue(value)).join(" | "), MAX_ISSUE_MESSAGE_CHARS)
|
|
176
|
+
: raw.code === "invalid_type" && raw.expected !== undefined
|
|
177
|
+
? truncateChars(String(raw.expected), MAX_ISSUE_MESSAGE_CHARS)
|
|
178
|
+
: undefined;
|
|
179
|
+
const received = raw.code === "invalid_type" && raw.received !== undefined
|
|
180
|
+
? truncateChars(String(raw.received), MAX_ISSUE_VALUE_CHARS)
|
|
181
|
+
: undefined;
|
|
182
|
+
issues.push({
|
|
183
|
+
code,
|
|
184
|
+
path: formatIssuePath(basePath),
|
|
185
|
+
message: truncateChars(raw.message ?? "invalid value", MAX_ISSUE_MESSAGE_CHARS),
|
|
186
|
+
...(expected !== undefined ? { expected } : {}),
|
|
187
|
+
...(received !== undefined ? { received } : {}),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function pushIssueTree(issues, rawList, prefix) {
|
|
191
|
+
for (const raw of rawList) {
|
|
192
|
+
if (issues.length >= MAX_CONTRACT_ISSUES)
|
|
193
|
+
return;
|
|
194
|
+
const basePath = [...prefix, ...(raw.path ?? [])];
|
|
195
|
+
if (raw.code === "invalid_union" && Array.isArray(raw.errors) && raw.errors.length > 0) {
|
|
196
|
+
// Preserve nested union/discriminator branch paths (e.g. source.reference, source.kind).
|
|
197
|
+
for (const branch of raw.errors) {
|
|
198
|
+
pushIssueTree(issues, branch, basePath);
|
|
199
|
+
if (issues.length >= MAX_CONTRACT_ISSUES)
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
pushConcreteIssue(issues, raw, basePath);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Convert a ZodError into bounded tokenized contract issues.
|
|
209
|
+
* Unknown keys become precise leaf paths; union branch paths are preserved;
|
|
210
|
+
* values are summarized, not echoed wholesale.
|
|
211
|
+
*/
|
|
212
|
+
export function toContractIssues(error) {
|
|
213
|
+
const issues = [];
|
|
214
|
+
pushIssueTree(issues, error.issues, []);
|
|
215
|
+
return issues;
|
|
216
|
+
}
|
|
217
|
+
/** Render issues as one bounded single-line explanation suitable for host tool errors. */
|
|
218
|
+
export function formatContractIssues(issues) {
|
|
219
|
+
if (issues.length === 0)
|
|
220
|
+
return "INVALID_INPUT: structural validation failed";
|
|
221
|
+
const parts = issues.map((issue) => {
|
|
222
|
+
const path = issue.path || "(root)";
|
|
223
|
+
const expected = issue.expected ? `; expected ${issue.expected}` : "";
|
|
224
|
+
const received = issue.received ? `; received ${issue.received}` : "";
|
|
225
|
+
return truncateChars(`${path}: ${issue.message}${expected}${received}`, MAX_ISSUE_MESSAGE_CHARS);
|
|
226
|
+
});
|
|
227
|
+
return truncateChars(`INVALID_INPUT: ${parts.join(" | ")}`, MAX_ISSUE_MESSAGE_CHARS * (MAX_CONTRACT_ISSUES + 1));
|
|
228
|
+
}
|
|
229
|
+
/** Pre-execution structural rejection for owned tools. Not a permission or state decision. */
|
|
230
|
+
export class ContractInputError extends Error {
|
|
231
|
+
code = "INVALID_INPUT";
|
|
232
|
+
category = "input";
|
|
233
|
+
toolId;
|
|
234
|
+
issues;
|
|
235
|
+
constructor(toolId, issues) {
|
|
236
|
+
super(formatContractIssues(issues));
|
|
237
|
+
this.name = "ContractInputError";
|
|
238
|
+
this.toolId = toolId;
|
|
239
|
+
this.issues = issues;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Fail-closed host-context rejection when an owned tool cannot publish its contract
|
|
244
|
+
* through the host tool.definition seam. Never mutates the hook output before throwing.
|
|
245
|
+
*/
|
|
246
|
+
export class ContractHostCompatibilityError extends Error {
|
|
247
|
+
code = "HOST_CONTRACT_UNSUPPORTED";
|
|
248
|
+
category = "host_context";
|
|
249
|
+
toolId;
|
|
250
|
+
reason;
|
|
251
|
+
constructor(toolId, reason) {
|
|
252
|
+
super(truncateChars(`HOST_CONTRACT_UNSUPPORTED: tool=${escapePathSegment(toolId)}; ${reason}`, MAX_ISSUE_MESSAGE_CHARS));
|
|
253
|
+
this.name = "ContractHostCompatibilityError";
|
|
254
|
+
this.toolId = toolId;
|
|
255
|
+
this.reason = truncateChars(reason, MAX_ISSUE_MESSAGE_CHARS);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Build a structured tool result envelope compatible with the pinned SDK ToolResult.
|
|
260
|
+
* Empty output and empty metadata remain valid for consumers that need them.
|
|
261
|
+
*/
|
|
262
|
+
export function ownedToolResult(output, init) {
|
|
263
|
+
return {
|
|
264
|
+
...(init?.title !== undefined ? { title: init.title } : {}),
|
|
265
|
+
output,
|
|
266
|
+
...(init?.metadata !== undefined ? { metadata: init.metadata } : {}),
|
|
267
|
+
...(init?.attachments !== undefined ? { attachments: init.attachments } : {}),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/** Closed object schema on the SDK tool.schema instance (rejects unknown keys). */
|
|
271
|
+
export function strictObject(shape) {
|
|
272
|
+
return tool.schema.strictObject(shape);
|
|
273
|
+
}
|
|
274
|
+
/** Attachment envelope schema for producer/test validation of owned tool results. */
|
|
275
|
+
export const ownedToolAttachmentSchema = strictObject({
|
|
276
|
+
type: tool.schema.literal("file"),
|
|
277
|
+
mime: tool.schema.string(),
|
|
278
|
+
url: tool.schema.string(),
|
|
279
|
+
filename: tool.schema.string().optional(),
|
|
280
|
+
});
|
|
281
|
+
/**
|
|
282
|
+
* Strict result-envelope schema for producer/test checks.
|
|
283
|
+
* `metadata` and nested document/binary content are declared opaque extension regions
|
|
284
|
+
* (record/unknown or declared opaque fields), not re-validated payload shapes.
|
|
285
|
+
* This is never applied as a throw-after-side-effect execute wrapper.
|
|
286
|
+
*/
|
|
287
|
+
export const ownedToolResultSchema = strictObject({
|
|
288
|
+
title: tool.schema.string().optional(),
|
|
289
|
+
output: tool.schema.string(),
|
|
290
|
+
metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional(),
|
|
291
|
+
attachments: tool.schema.array(ownedToolAttachmentSchema).optional(),
|
|
292
|
+
});
|
|
293
|
+
/**
|
|
294
|
+
* Producer/test-only validation of a structured result envelope.
|
|
295
|
+
* Returns typed output on success; structural issues on failure.
|
|
296
|
+
* Do not call this after irreversible side effects as a gate that invites replay.
|
|
297
|
+
*/
|
|
298
|
+
export function validateOwnedToolResult(value) {
|
|
299
|
+
const result = ownedToolResultSchema.safeParse(value);
|
|
300
|
+
if (result.success) {
|
|
301
|
+
return { success: true, data: result.data };
|
|
302
|
+
}
|
|
303
|
+
return { success: false, issues: toContractIssues(result.error) };
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Project a contract schema to its input-mode JSON Schema.
|
|
307
|
+
* Consistent with the host registry projection (io: "input", $defs → definitions).
|
|
308
|
+
*/
|
|
309
|
+
export function contractInputJsonSchema(schema) {
|
|
310
|
+
const projected = tool.schema.toJSONSchema(schema, { io: "input" });
|
|
311
|
+
if (typeof projected !== "object" || projected === null || Array.isArray(projected)) {
|
|
312
|
+
throw new Error("contract schema produced a non-object JSON Schema");
|
|
313
|
+
}
|
|
314
|
+
const record = projected;
|
|
315
|
+
const { $defs, ...rest } = record;
|
|
316
|
+
if (typeof $defs === "object" && $defs !== null && !Array.isArray($defs)) {
|
|
317
|
+
return { ...rest, definitions: $defs };
|
|
318
|
+
}
|
|
319
|
+
return rest;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Define an owned-tool contract from the same raw argument map used for SDK registration.
|
|
323
|
+
* The runtime schema is a strict full-object validator over that map; nested closedness
|
|
324
|
+
* comes from composing nested shapes with strictObject. Unknown keys are never coerced or filtered.
|
|
325
|
+
*/
|
|
326
|
+
export function defineOwnedToolContract(init) {
|
|
327
|
+
const runtimeSchema = strictObject(init.registeredArgs);
|
|
328
|
+
const inputJsonSchema = contractInputJsonSchema(runtimeSchema);
|
|
329
|
+
const examples = init.examples ?? [];
|
|
330
|
+
return {
|
|
331
|
+
toolId: init.toolId,
|
|
332
|
+
description: init.description,
|
|
333
|
+
registeredArgs: init.registeredArgs,
|
|
334
|
+
runtimeSchema,
|
|
335
|
+
inputJsonSchema,
|
|
336
|
+
examples,
|
|
337
|
+
safeParse(raw) {
|
|
338
|
+
const result = runtimeSchema.safeParse(raw);
|
|
339
|
+
if (result.success) {
|
|
340
|
+
return { success: true, data: result.data };
|
|
341
|
+
}
|
|
342
|
+
return { success: false, issues: toContractIssues(result.error) };
|
|
343
|
+
},
|
|
344
|
+
parse(raw) {
|
|
345
|
+
const result = runtimeSchema.safeParse(raw);
|
|
346
|
+
if (result.success)
|
|
347
|
+
return result.data;
|
|
348
|
+
throw new ContractInputError(init.toolId, toContractIssues(result.error));
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Direct-execute validation: parse raw (host-forwarded) args through the contract schema,
|
|
354
|
+
* applying schema defaults/canonicalization for execute to consume.
|
|
355
|
+
* Returns the schema-inferred output type (defaults and enum literals preserved).
|
|
356
|
+
*/
|
|
357
|
+
export function parseOwnedToolArgs(contract, rawArgs) {
|
|
358
|
+
return contract.parse(rawArgs);
|
|
359
|
+
}
|
|
360
|
+
function isDefinitionHookOutput(value) {
|
|
361
|
+
return (typeof value === "object" && value !== null && "parameters" in value && "description" in value);
|
|
362
|
+
}
|
|
363
|
+
function hasJsonSchemaMember(value) {
|
|
364
|
+
return "jsonSchema" in value;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Owned-only tool.definition adapter (fail-closed).
|
|
368
|
+
* Publishes the strict input-mode jsonSchema through the host's observable jsonSchema member
|
|
369
|
+
* while preserving parameters identity (the host decoder is never replaced).
|
|
370
|
+
* For owned tool IDs, an unsupported host shape (malformed output or missing jsonSchema member)
|
|
371
|
+
* throws ContractHostCompatibilityError without mutating the output.
|
|
372
|
+
* Unowned tool IDs are left untouched.
|
|
373
|
+
*/
|
|
374
|
+
export function createToolDefinitionAdapter(contracts) {
|
|
375
|
+
const byId = new Map(contracts.map((contract) => [contract.toolId, contract]));
|
|
376
|
+
return async function toolDefinitionAdapter(input, output) {
|
|
377
|
+
const contract = byId.get(input.toolID);
|
|
378
|
+
if (!contract)
|
|
379
|
+
return;
|
|
380
|
+
if (!isDefinitionHookOutput(output)) {
|
|
381
|
+
throw new ContractHostCompatibilityError(contract.toolId, "malformed tool.definition output: missing required description/parameters members");
|
|
382
|
+
}
|
|
383
|
+
if (!hasJsonSchemaMember(output)) {
|
|
384
|
+
throw new ContractHostCompatibilityError(contract.toolId, "unsupported host tool.definition shape: missing jsonSchema member required for strict publication");
|
|
385
|
+
}
|
|
386
|
+
output.jsonSchema = contract.inputJsonSchema;
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Owned-only pre-execute structural guard for tool.execute.before.
|
|
391
|
+
* Inspects raw args and throws ContractInputError on structural failure.
|
|
392
|
+
* Never mutates output.args and never confers state/permission eligibility.
|
|
393
|
+
*/
|
|
394
|
+
export function createPreExecuteGuard(contracts) {
|
|
395
|
+
const byId = new Map(contracts.map((contract) => [contract.toolId, contract]));
|
|
396
|
+
return async function preExecuteGuard(input, output) {
|
|
397
|
+
const contract = byId.get(input.tool);
|
|
398
|
+
if (!contract)
|
|
399
|
+
return;
|
|
400
|
+
const result = contract.runtimeSchema.safeParse(output.args);
|
|
401
|
+
if (!result.success) {
|
|
402
|
+
throw new ContractInputError(contract.toolId, toContractIssues(result.error));
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
// END_BLOCK_HOST_ADAPTERS
|
|
407
|
+
//# sourceMappingURL=agent-tool-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-tool-contract.js","sourceRoot":"","sources":["../../src/lib/agent-tool-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,12 @@ export declare const WORKFLOW_CONTRACT_VERSION = 1;
|
|
|
2
2
|
export declare const WORKFLOW_ID_MAX_CHARS = 128;
|
|
3
3
|
export declare const WORKFLOW_TEXT_MAX_CHARS = 2000;
|
|
4
4
|
export declare const WORKFLOW_TEXT_MAX_ITEMS = 64;
|
|
5
|
+
/** Canonical work-item intent values accepted by work_item_open. */
|
|
6
|
+
export declare const WORK_ITEM_MODES: readonly ["implementation", "review_only", "delegated"];
|
|
7
|
+
/** Canonical independent reviewer roles accepted across workflow inputs. */
|
|
8
|
+
export declare const REVIEWER_ROLES: readonly ["spec", "code"];
|
|
9
|
+
/** Canonical delegatable lifecycle stages for advance authority. */
|
|
10
|
+
export declare const AUTHORITY_STAGES: readonly ["specification", "planning", "implementation", "verification"];
|
|
5
11
|
/** Normalized workspace-relative path, or the reason a declared path is malformed. */
|
|
6
12
|
export type DeclaredScopePathResult = {
|
|
7
13
|
ok: true;
|
|
@@ -225,6 +231,12 @@ export interface WorkflowMessageClaim {
|
|
|
225
231
|
export interface WorkflowContractProblem {
|
|
226
232
|
code: string;
|
|
227
233
|
message: string;
|
|
234
|
+
/**
|
|
235
|
+
* Tokenized field/index path of the offending value when it applies to one
|
|
236
|
+
* element (e.g. ["boundary", "files", 0]); absent when the problem applies to
|
|
237
|
+
* the whole value rather than a single indexed element.
|
|
238
|
+
*/
|
|
239
|
+
path?: readonly (string | number)[];
|
|
228
240
|
}
|
|
229
241
|
export type WorkflowContractValidation<T> = {
|
|
230
242
|
ok: true;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// FILE: src/lib/workflow-contract.ts
|
|
2
|
-
// VERSION: 1.
|
|
2
|
+
// VERSION: 1.1.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Dependency-free common execution contract for native-package, provided-plan, and conversation-scoped workflow runs: declared-path normalization, bounded task/checkpoint/boundary contracts, explicit reviewer sets, exact-reference DAG validation, lineage/revision records, and authority/stage provenance shapes.
|
|
5
|
-
// SCOPE: Pure path normalization, bounded identity/text validation, explicit reviewer-set normalization, execution boundary containment, task and checkpoint contract validation, exact reference and acyclic dependency checks, native definition adaptation into common contracts, and structural source/lineage/authority record types. No filesystem access, native XML parsing, SDK transport, task dispatch, or persistence.
|
|
4
|
+
// PURPOSE: Dependency-free common execution contract for native-package, provided-plan, and conversation-scoped workflow runs: canonical work-item/reviewer/authority enums, declared-path normalization, bounded task/checkpoint/boundary contracts, explicit reviewer sets, exact-reference DAG validation, lineage/revision records, and authority/stage provenance shapes.
|
|
5
|
+
// SCOPE: Pure path normalization, bounded identity/text validation, canonical enum constants shared by tool schemas and domain owners, explicit reviewer-set normalization, execution boundary containment (with boundary-reporting containment failures), task and checkpoint contract validation, exact reference and acyclic dependency checks, native definition adaptation into common contracts, and structural source/lineage/authority record types. No filesystem access, native XML parsing, SDK transport, task dispatch, or persistence.
|
|
6
6
|
// DEPENDS: [] (deliberately dependency-free so the native adapter and the generic runtime share one contract without a cycle)
|
|
7
|
-
// LINKS: [M-WORKFLOW-CONTRACT, M-SPEC-LINT, M-WORKFLOW-EXECUTION, M-WORKFLOW-AUTHORITY]
|
|
7
|
+
// LINKS: [M-WORKFLOW-CONTRACT, M-SPEC-LINT, M-WORKFLOW-EXECUTION, M-WORKFLOW-AUTHORITY, M-WORKFLOW-STATE, M-WORKFLOW-TOOLING]
|
|
8
8
|
// ROLE: RUNTIME
|
|
9
9
|
// MAP_MODE: EXPORTS
|
|
10
10
|
// END_MODULE_CONTRACT
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
// WORKFLOW_ID_MAX_CHARS - Maximum accepted workflow identity length.
|
|
15
15
|
// WORKFLOW_TEXT_MAX_CHARS - Maximum accepted bounded contract text length.
|
|
16
16
|
// WORKFLOW_TEXT_MAX_ITEMS - Maximum accepted list length inside one contract field.
|
|
17
|
+
// WORK_ITEM_MODES - Canonical work-item intent values accepted by work_item_open.
|
|
18
|
+
// REVIEWER_ROLES - Canonical independent reviewer roles accepted across workflow inputs.
|
|
19
|
+
// AUTHORITY_STAGES - Canonical delegatable lifecycle stages for advance authority.
|
|
17
20
|
// WorkflowReviewer - Canonical independent reviewer role.
|
|
18
21
|
// WorkflowObligationOrigin - Where a registered obligation came from (source, user, controller).
|
|
19
22
|
// DelegatedReviewer - Canonical delegated checkpoint reviewer roles (spec, code).
|
|
@@ -43,7 +46,7 @@
|
|
|
43
46
|
// WorkflowStageApproval - Recorded stage approval bound to an approved artifact hash.
|
|
44
47
|
// WorkflowReserveDebit - One consumed unit of the shared advance-recovery reserve.
|
|
45
48
|
// WorkflowMessageClaim - Session-wide claim that one root-user message already funded a grant.
|
|
46
|
-
// WorkflowContractProblem - One deterministic contract validation problem.
|
|
49
|
+
// WorkflowContractProblem - One deterministic contract validation problem, with an optional indexed path.
|
|
47
50
|
// WorkflowContractValidation - Validation result carrying a value or deterministic problems.
|
|
48
51
|
// isBoundedWorkflowId - Whether a value is a bounded explicit workflow identity.
|
|
49
52
|
// isPathInExecutionBoundary - Whether a normalized path is contained in an execution boundary.
|
|
@@ -56,13 +59,24 @@
|
|
|
56
59
|
// END_MODULE_MAP
|
|
57
60
|
//
|
|
58
61
|
// START_CHANGE_SUMMARY
|
|
59
|
-
// LAST_CHANGE: [C-
|
|
62
|
+
// LAST_CHANGE: [C-AGENT-TOOL-CONTRACTS T-002 - Added canonical work-item mode, reviewer role, and authority stage enum constants for schema/domain reuse, made OUT_OF_BOUNDARY containment failures report the offending scope together with the applicable declared boundary, and gave boundary problems precise indexed paths with bounded value previews.]
|
|
60
63
|
// END_CHANGE_SUMMARY
|
|
61
64
|
// START_BLOCK_CONTRACT_CONSTANTS
|
|
62
65
|
export const WORKFLOW_CONTRACT_VERSION = 1;
|
|
63
66
|
export const WORKFLOW_ID_MAX_CHARS = 128;
|
|
64
67
|
export const WORKFLOW_TEXT_MAX_CHARS = 2000;
|
|
65
68
|
export const WORKFLOW_TEXT_MAX_ITEMS = 64;
|
|
69
|
+
/** Canonical work-item intent values accepted by work_item_open. */
|
|
70
|
+
export const WORK_ITEM_MODES = ["implementation", "review_only", "delegated"];
|
|
71
|
+
/** Canonical independent reviewer roles accepted across workflow inputs. */
|
|
72
|
+
export const REVIEWER_ROLES = ["spec", "code"];
|
|
73
|
+
/** Canonical delegatable lifecycle stages for advance authority. */
|
|
74
|
+
export const AUTHORITY_STAGES = [
|
|
75
|
+
"specification",
|
|
76
|
+
"planning",
|
|
77
|
+
"implementation",
|
|
78
|
+
"verification",
|
|
79
|
+
];
|
|
66
80
|
/**
|
|
67
81
|
* Text-level canonical normalization for declared scope file paths. The linter
|
|
68
82
|
* and the runtime snapshot fingerprint share this representation so a plan that
|
|
@@ -201,32 +215,52 @@ export function normalizeReviewerSet(value) {
|
|
|
201
215
|
}
|
|
202
216
|
// END_BLOCK_REVIEWER_NORMALIZATION
|
|
203
217
|
// START_BLOCK_BOUNDARY_VALIDATION
|
|
204
|
-
|
|
218
|
+
/** Bounded preview of one offending value; never echoes an unbounded payload. */
|
|
219
|
+
const DIAGNOSTIC_PREVIEW_MAX_CHARS = 64;
|
|
220
|
+
function previewValue(value) {
|
|
221
|
+
const json = JSON.stringify(value);
|
|
222
|
+
const text = json === undefined ? String(value) : json;
|
|
223
|
+
return text.length <= DIAGNOSTIC_PREVIEW_MAX_CHARS
|
|
224
|
+
? text
|
|
225
|
+
: `${text.slice(0, DIAGNOSTIC_PREVIEW_MAX_CHARS - 1)}…`;
|
|
226
|
+
}
|
|
227
|
+
function normalizeUniquePaths(raw, field, normalize, problems, pathBase = []) {
|
|
205
228
|
if (raw === undefined || raw === null)
|
|
206
229
|
return [];
|
|
207
230
|
if (!Array.isArray(raw)) {
|
|
208
|
-
problems.push({
|
|
231
|
+
problems.push({
|
|
232
|
+
code: "INVALID_LIST",
|
|
233
|
+
message: `${field} must be an array`,
|
|
234
|
+
path: [...pathBase],
|
|
235
|
+
});
|
|
209
236
|
return [];
|
|
210
237
|
}
|
|
211
238
|
const seen = new Set();
|
|
212
239
|
const out = [];
|
|
213
|
-
for (
|
|
240
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
241
|
+
const entry = raw[index];
|
|
214
242
|
if (typeof entry !== "string") {
|
|
215
|
-
problems.push({
|
|
243
|
+
problems.push({
|
|
244
|
+
code: "INVALID_PATH",
|
|
245
|
+
message: `${field} entries must be strings`,
|
|
246
|
+
path: [...pathBase, index],
|
|
247
|
+
});
|
|
216
248
|
return [];
|
|
217
249
|
}
|
|
218
250
|
const normalized = normalize(entry);
|
|
219
251
|
if (!normalized.ok) {
|
|
220
252
|
problems.push({
|
|
221
253
|
code: "INVALID_PATH",
|
|
222
|
-
message: `${field} path ${
|
|
254
|
+
message: `${field} path ${previewValue(entry)} is malformed (${normalized.reason})`,
|
|
255
|
+
path: [...pathBase, index],
|
|
223
256
|
});
|
|
224
257
|
return [];
|
|
225
258
|
}
|
|
226
259
|
if (seen.has(normalized.path)) {
|
|
227
260
|
problems.push({
|
|
228
261
|
code: "DUPLICATE_PATH",
|
|
229
|
-
message: `${field} path ${
|
|
262
|
+
message: `${field} path ${previewValue(normalized.path)} is declared more than once`,
|
|
263
|
+
path: [...pathBase, index],
|
|
230
264
|
});
|
|
231
265
|
return [];
|
|
232
266
|
}
|
|
@@ -241,19 +275,29 @@ export function validateExecutionBoundary(raw) {
|
|
|
241
275
|
if (raw === null || typeof raw !== "object") {
|
|
242
276
|
return {
|
|
243
277
|
ok: false,
|
|
244
|
-
problems: [
|
|
278
|
+
problems: [
|
|
279
|
+
{
|
|
280
|
+
code: "INVALID_BOUNDARY",
|
|
281
|
+
message: "execution boundary must be an object",
|
|
282
|
+
path: ["boundary"],
|
|
283
|
+
},
|
|
284
|
+
],
|
|
245
285
|
};
|
|
246
286
|
}
|
|
247
287
|
const candidate = raw;
|
|
248
|
-
const files = normalizeUniquePaths(candidate.files, "boundary.files", normalizeDeclaredScopePath, problems);
|
|
249
|
-
const directories = normalizeUniquePaths(candidate.directories, "boundary.directories", normalizeDeclaredDirectoryPath, problems);
|
|
288
|
+
const files = normalizeUniquePaths(candidate.files, "boundary.files", normalizeDeclaredScopePath, problems, ["boundary", "files"]);
|
|
289
|
+
const directories = normalizeUniquePaths(candidate.directories, "boundary.directories", normalizeDeclaredDirectoryPath, problems, ["boundary", "directories"]);
|
|
250
290
|
if (problems.length > 0)
|
|
251
291
|
return { ok: false, problems };
|
|
252
292
|
if (files.length === 0 && directories.length === 0) {
|
|
253
293
|
return {
|
|
254
294
|
ok: false,
|
|
255
295
|
problems: [
|
|
256
|
-
{
|
|
296
|
+
{
|
|
297
|
+
code: "EMPTY_BOUNDARY",
|
|
298
|
+
message: "execution boundary declares no files or directories",
|
|
299
|
+
path: ["boundary"],
|
|
300
|
+
},
|
|
257
301
|
],
|
|
258
302
|
};
|
|
259
303
|
}
|
|
@@ -265,6 +309,15 @@ export function isPathInExecutionBoundary(path, boundary) {
|
|
|
265
309
|
return true;
|
|
266
310
|
return boundary.directories.some((directory) => path.startsWith(`${directory}/`));
|
|
267
311
|
}
|
|
312
|
+
/** Bounded one-line summary of a declared boundary for containment diagnostics. */
|
|
313
|
+
function describeExecutionBoundary(boundary) {
|
|
314
|
+
const summarize = (entries) => entries.length <= 8
|
|
315
|
+
? entries.join(", ")
|
|
316
|
+
: `${entries.slice(0, 8).join(", ")}, …(+${entries.length - 8})`;
|
|
317
|
+
const files = boundary.files.length > 0 ? summarize(boundary.files) : "(none)";
|
|
318
|
+
const directories = boundary.directories.length > 0 ? summarize(boundary.directories) : "(none)";
|
|
319
|
+
return `files: ${files}; directories: ${directories}`;
|
|
320
|
+
}
|
|
268
321
|
// END_BLOCK_BOUNDARY_VALIDATION
|
|
269
322
|
// START_BLOCK_TASK_VALIDATION
|
|
270
323
|
function normalizeBoundaryFiles(raw, field, problems, options) {
|
|
@@ -515,7 +568,7 @@ export function validateWorkflowContractGraph(graph) {
|
|
|
515
568
|
if (!isPathInExecutionBoundary(path, graph.boundary)) {
|
|
516
569
|
problems.push({
|
|
517
570
|
code: "OUT_OF_BOUNDARY",
|
|
518
|
-
message: `task ${task.taskId} writeScope ${JSON.stringify(path)} is outside the execution boundary`,
|
|
571
|
+
message: `task ${task.taskId} writeScope ${JSON.stringify(path)} is outside the execution boundary (declared ${describeExecutionBoundary(graph.boundary)})`,
|
|
519
572
|
});
|
|
520
573
|
}
|
|
521
574
|
}
|
|
@@ -537,7 +590,7 @@ export function validateWorkflowContractGraph(graph) {
|
|
|
537
590
|
if (!isPathInExecutionBoundary(path, graph.boundary)) {
|
|
538
591
|
problems.push({
|
|
539
592
|
code: "OUT_OF_BOUNDARY",
|
|
540
|
-
message: `checkpoint ${checkpoint.checkpointId} scope ${JSON.stringify(path)} is outside the execution boundary`,
|
|
593
|
+
message: `checkpoint ${checkpoint.checkpointId} scope ${JSON.stringify(path)} is outside the execution boundary (declared ${describeExecutionBoundary(graph.boundary)})`,
|
|
541
594
|
});
|
|
542
595
|
}
|
|
543
596
|
}
|