@yansirplus/cli 0.5.17 → 0.5.19
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/README.md +12 -6
- package/agent-catalog/agentOS/SKILL.md +22 -0
- package/agent-catalog/agentOS/references/agent/decision-graph.json +530 -0
- package/agent-catalog/agentOS/references/agent/errors.json +497 -0
- package/agent-catalog/agentOS/references/agent/invariant-matrix.json +337 -0
- package/agent-catalog/agentOS/references/agent/primitives.json +989 -0
- package/agent-catalog/agentOS/references/agent/recipes.json +109 -0
- package/agent-catalog/agentOS/references/agent/start-here.md +25 -0
- package/agent-catalog/agentOS/references/package-map.md +73 -0
- package/agent-catalog/agentOS/references/provenance.json +251 -0
- package/agent-catalog/agentOS/references/public-api/cli.md +20 -0
- package/agent-catalog/agentOS/references/public-api/client.md +90 -0
- package/agent-catalog/agentOS/references/public-api/core.md +1907 -0
- package/agent-catalog/agentOS/references/public-api/runtime.md +843 -0
- package/dist/build/agent-authoring/config.d.ts +20 -5
- package/dist/build/agent-authoring/config.js +132 -32
- package/dist/build/agent-authoring/manifest-compiler.d.ts +131 -2
- package/dist/build/agent-authoring/manifest-compiler.js +630 -8
- package/dist/build/agent-authoring/shared.d.ts +2 -0
- package/dist/build/agent-authoring/shared.js +2 -0
- package/dist/build/agent-authoring/static-target.d.ts +6 -3
- package/dist/build/agent-authoring/static-target.js +1900 -281
- package/dist/build/agent-authoring.d.ts +3 -3
- package/dist/build/agent-authoring.js +1 -1
- package/dist/build/build-cli.d.ts +1 -1
- package/dist/build/build-cli.js +1629 -26
- package/dist/check/algorithmic/client-boundary-checks.mjs +3 -34
- package/dist/check/algorithmic/convergence-smoke-checks.mjs +652 -6
- package/dist/check/algorithmic/distribution-checks.mjs +8 -7
- package/dist/check/algorithmic/package-boundary-checks.mjs +3 -2
- package/dist/check/algorithmic/repo-surface-checks.mjs +55 -1
- package/dist/check/algorithmic/static-target-checks.mjs +83 -5
- package/dist/check/algorithmic-checks.mjs +10 -17
- package/dist/check/default-gate.mjs +3 -3
- package/dist/check/effect-scan-gate.mjs +121 -0
- package/dist/check/package-graph.mjs +2 -32
- package/dist/consumer-overlay.mjs +1281 -0
- package/dist/lib/public-api-model.mjs +19 -0
- package/dist/lib/repo-source-files.mjs +26 -0
- package/dist/lib/ts-module-loader.mjs +44 -0
- package/dist/lib/workspace-manifest.mjs +77 -0
- package/dist/main.mjs +171 -21
- package/dist/release-status.mjs +515 -0
- package/package.json +8 -4
- package/dist/check/check-coverage.mjs +0 -231
- package/dist/generate/generate-agent-docs.mjs +0 -435
- package/dist/generate/generate-carrier-reference.mjs +0 -514
- package/dist/generate/generate-docs.mjs +0 -345
- package/dist/generate/generate-effect-skill-manifests.mjs +0 -193
- package/dist/generate/project-docs-site.mjs +0 -190
- package/dist/lib/boundary-rules.mjs +0 -63
- package/dist/lib/capability-routes.mjs +0 -354
- package/dist/lib/projection-sink.mjs +0 -113
|
@@ -4,10 +4,24 @@ import { isAuthorityRef } from "@yansirplus/core/effect-claim";
|
|
|
4
4
|
import { isMaterialRef } from "@yansirplus/core/material-ref";
|
|
5
5
|
import { BUILTIN_HANDLER_KINDS } from "@yansirplus/core/runtime-protocol";
|
|
6
6
|
import { WORKSPACE_TOOL_DEFAULT_DECLARATIONS, } from "@yansirplus/runtime";
|
|
7
|
-
import {
|
|
7
|
+
import { cronMinuteExpression } from "@yansirplus/runtime/schedule";
|
|
8
|
+
import { AUTHORING_DEFAULTS_VERSION, digestText, findFunctionPath, GENERATED_LOAD_SKILL_TOOL_NAME, GENERATED_READ_SKILL_FILE_TOOL_NAME, hasFunction, isNonEmptyString, isRecord, isWorkspaceToolName, } from "./shared.js";
|
|
9
|
+
const SKILL_DESCRIPTION_MAX_BYTES = 240;
|
|
10
|
+
const SKILL_BODY_MAX_BYTES = 131_072;
|
|
11
|
+
const SKILL_SUPPORT_FILE_MAX_BYTES = 65_536;
|
|
12
|
+
const SKILL_SUPPORT_FILES_MAX_COUNT = 64;
|
|
13
|
+
const SKILL_SUPPORT_PACKAGE_MAX_BYTES = 262_144;
|
|
14
|
+
const skillNamePattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
15
|
+
const channelNamePattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
16
|
+
const workflowNamePattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
17
|
+
const scheduleSlugPattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
18
|
+
const instructionFragmentIdPattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
19
|
+
const dynamicResolverIdPattern = /^[a-z][a-z0-9_-]{0,63}$/u;
|
|
20
|
+
const textEncoder = new TextEncoder();
|
|
21
|
+
const textDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
8
22
|
const defaultOrigin = (factKey) => `default:${AUTHORING_DEFAULTS_VERSION}#${factKey}`;
|
|
9
23
|
export const workspaceManifestMacroOrigin = (factKey) => `macro(workspace@1)#${factKey}`;
|
|
10
|
-
const authoredPath = (path) =>
|
|
24
|
+
const authoredPath = (path) => path.startsWith("workflows/") ? path : `agent/${path}`;
|
|
11
25
|
const authorOrigin = (path, pointer) => `author:${authoredPath(path)}#${pointer}`;
|
|
12
26
|
const pathOrigin = (path) => `path:${authoredPath(path)}`;
|
|
13
27
|
const isManifestMapId = (value) => value.length > 0 && !value.includes("/") && value !== "." && value !== "..";
|
|
@@ -28,6 +42,60 @@ const parseStringField = (state, path, field, value) => {
|
|
|
28
42
|
}
|
|
29
43
|
return value;
|
|
30
44
|
};
|
|
45
|
+
const utf8ByteLength = (value) => textEncoder.encode(value).length;
|
|
46
|
+
const isSkillName = (value) => skillNamePattern.test(value);
|
|
47
|
+
const isChannelName = (value) => channelNamePattern.test(value);
|
|
48
|
+
const isWorkflowName = (value) => workflowNamePattern.test(value);
|
|
49
|
+
const isScheduleSlug = (value) => scheduleSlugPattern.test(value);
|
|
50
|
+
const isInstructionFragmentId = (value) => instructionFragmentIdPattern.test(value);
|
|
51
|
+
const isDynamicResolverId = (value) => dynamicResolverIdPattern.test(value);
|
|
52
|
+
const decodeUtf8Bytes = (state, path, field, bytes) => {
|
|
53
|
+
try {
|
|
54
|
+
return textDecoder.decode(bytes);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
invalidAuthoredValue(state, path, field, "utf8_required");
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const assertNoNulText = (state, path, field, text) => {
|
|
62
|
+
if (!text.includes("\0"))
|
|
63
|
+
return true;
|
|
64
|
+
invalidAuthoredValue(state, path, field, "nul_byte_forbidden");
|
|
65
|
+
return false;
|
|
66
|
+
};
|
|
67
|
+
const assertRegularAuthoredSource = (state, path, sourceKind) => {
|
|
68
|
+
const kind = sourceKind ?? "regular";
|
|
69
|
+
if (kind === "regular")
|
|
70
|
+
return true;
|
|
71
|
+
state.issues.push({
|
|
72
|
+
kind: "unsupported_path",
|
|
73
|
+
path,
|
|
74
|
+
reason: kind === "symlink" ? "symlink_forbidden" : "regular_file_required",
|
|
75
|
+
});
|
|
76
|
+
return false;
|
|
77
|
+
};
|
|
78
|
+
const parseSkillFrontmatterStringField = (state, path, field, value) => {
|
|
79
|
+
const parsed = parseStringField(state, path, field, value);
|
|
80
|
+
if (parsed === null)
|
|
81
|
+
return null;
|
|
82
|
+
const trimmed = parsed.trim();
|
|
83
|
+
if (trimmed.length === 0) {
|
|
84
|
+
invalidAuthoredValue(state, path, field, "non_empty_string_required");
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return trimmed;
|
|
88
|
+
};
|
|
89
|
+
const parseSkillDescriptionField = (state, path, value) => {
|
|
90
|
+
const description = parseSkillFrontmatterStringField(state, path, "/frontmatter/description", value);
|
|
91
|
+
if (description === null)
|
|
92
|
+
return null;
|
|
93
|
+
if (utf8ByteLength(description) > SKILL_DESCRIPTION_MAX_BYTES) {
|
|
94
|
+
invalidAuthoredValue(state, path, "/frontmatter/description", "skill_description_too_large");
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return description;
|
|
98
|
+
};
|
|
31
99
|
const parseOptionalStringField = (state, path, field, value) => {
|
|
32
100
|
if (value === undefined)
|
|
33
101
|
return undefined;
|
|
@@ -133,7 +201,25 @@ const parseOutputSchema = (state, path, value) => {
|
|
|
133
201
|
fingerprint: value.fingerprint,
|
|
134
202
|
};
|
|
135
203
|
};
|
|
136
|
-
const
|
|
204
|
+
const agentGrammarRoots = new Set([
|
|
205
|
+
"agent.json",
|
|
206
|
+
"channels",
|
|
207
|
+
"domains",
|
|
208
|
+
"instructions",
|
|
209
|
+
"instructions.md",
|
|
210
|
+
"interactions",
|
|
211
|
+
"materials",
|
|
212
|
+
"skills",
|
|
213
|
+
"schedules",
|
|
214
|
+
"tools",
|
|
215
|
+
]);
|
|
216
|
+
const stripAgentPrefix = (path) => {
|
|
217
|
+
if (!path.startsWith("agent/"))
|
|
218
|
+
return path;
|
|
219
|
+
const rest = path.slice("agent/".length);
|
|
220
|
+
const root = rest.split("/")[0] ?? "";
|
|
221
|
+
return agentGrammarRoots.has(root) ? rest : path;
|
|
222
|
+
};
|
|
137
223
|
const normalizePath = (path) => {
|
|
138
224
|
if (path.length === 0 || path.startsWith("/") || path.includes("\\"))
|
|
139
225
|
return null;
|
|
@@ -233,6 +319,12 @@ const toolAllowedFields = new Set([
|
|
|
233
319
|
"effects",
|
|
234
320
|
"receiptPolicy",
|
|
235
321
|
]);
|
|
322
|
+
const dynamicResolverAllowedFields = new Set(["outputs", "id", "name"]);
|
|
323
|
+
const dynamicOutputSlots = [
|
|
324
|
+
"tools",
|
|
325
|
+
"skills",
|
|
326
|
+
"instructions",
|
|
327
|
+
];
|
|
236
328
|
const domainAllowedFields = new Set(["bindingRef"]);
|
|
237
329
|
const interactionAllowedFields = new Set(["bindingRef"]);
|
|
238
330
|
const agentAllowedFields = new Set([
|
|
@@ -241,6 +333,7 @@ const agentAllowedFields = new Set([
|
|
|
241
333
|
"scope",
|
|
242
334
|
"effectAuthorityRef",
|
|
243
335
|
"handlers",
|
|
336
|
+
"capabilities",
|
|
244
337
|
"llmRoutes",
|
|
245
338
|
"tools",
|
|
246
339
|
"materials",
|
|
@@ -380,6 +473,9 @@ const recordAgentJson = (state, path, value) => {
|
|
|
380
473
|
invalidAuthoredValue(state, path, "/effectAuthorityRef", "authority_ref_invalid");
|
|
381
474
|
}
|
|
382
475
|
const handlers = value.handlers === undefined ? undefined : parseHandlers(state, path, value.handlers);
|
|
476
|
+
const capabilities = value.capabilities === undefined
|
|
477
|
+
? undefined
|
|
478
|
+
: parseRecordMap(state, path, "/capabilities", value.capabilities, (_capability, child) => parseBindingRefObject(state, path, "/capabilities", child));
|
|
383
479
|
const llmRoutes = value.llmRoutes === undefined
|
|
384
480
|
? undefined
|
|
385
481
|
: parseRecordMap(state, path, "/llmRoutes", value.llmRoutes, (_route, child) => parseBindingRefObject(state, path, "/llmRoutes", child));
|
|
@@ -421,6 +517,11 @@ const recordAgentJson = (state, path, value) => {
|
|
|
421
517
|
}
|
|
422
518
|
if (handlers !== undefined && handlers !== null)
|
|
423
519
|
putAuthored(state, "/handlers", handlers, authorOrigin(path, "/handlers"));
|
|
520
|
+
if (capabilities !== undefined && capabilities !== null) {
|
|
521
|
+
for (const [capabilityId, ref] of Object.entries(capabilities)) {
|
|
522
|
+
putAuthored(state, `/capabilities/${capabilityId}/bindingRef`, ref.bindingRef, authorOrigin(path, `/capabilities/${capabilityId}/bindingRef`));
|
|
523
|
+
}
|
|
524
|
+
}
|
|
424
525
|
if (llmRoutes !== undefined && llmRoutes !== null) {
|
|
425
526
|
for (const [route, ref] of Object.entries(llmRoutes)) {
|
|
426
527
|
putAuthored(state, `/llmRoutes/${route}/bindingRef`, ref.bindingRef, authorOrigin(path, `/llmRoutes/${route}/bindingRef`));
|
|
@@ -503,7 +604,236 @@ const recordJsonFile = (state, path, value) => {
|
|
|
503
604
|
state.issues.push({ kind: "unsupported_path", path, reason: "json_path_not_in_grammar" });
|
|
504
605
|
}
|
|
505
606
|
};
|
|
506
|
-
const
|
|
607
|
+
const skillIdentityForPath = (path) => {
|
|
608
|
+
const parts = path.split("/");
|
|
609
|
+
if (parts[0] !== "skills")
|
|
610
|
+
return null;
|
|
611
|
+
if (parts.length === 2 && parts[1]?.endsWith(".md")) {
|
|
612
|
+
const name = parts[1].slice(0, -".md".length);
|
|
613
|
+
return isSkillName(name) ? name : null;
|
|
614
|
+
}
|
|
615
|
+
if (parts.length === 3 && parts[2] === "SKILL.md") {
|
|
616
|
+
const name = parts[1] ?? "";
|
|
617
|
+
return isSkillName(name) ? name : null;
|
|
618
|
+
}
|
|
619
|
+
return null;
|
|
620
|
+
};
|
|
621
|
+
const isPackagedSkillPath = (skill) => skill.path === `agent/skills/${skill.name}/SKILL.md`;
|
|
622
|
+
const skillSupportPathForPath = (path) => {
|
|
623
|
+
const parts = path.split("/");
|
|
624
|
+
if (parts[0] !== "skills" || parts.length < 4)
|
|
625
|
+
return null;
|
|
626
|
+
const skillName = parts[1] ?? "";
|
|
627
|
+
if (!isSkillName(skillName))
|
|
628
|
+
return null;
|
|
629
|
+
const root = parts[2];
|
|
630
|
+
if (root !== "references" && root !== "scripts")
|
|
631
|
+
return null;
|
|
632
|
+
return {
|
|
633
|
+
skillName,
|
|
634
|
+
packagePath: [root, ...parts.slice(3)].join("/"),
|
|
635
|
+
};
|
|
636
|
+
};
|
|
637
|
+
const instructionFragmentIdForPath = (path) => {
|
|
638
|
+
const parts = path.split("/");
|
|
639
|
+
if (parts.length !== 2 || parts[0] !== "instructions" || !parts[1]?.endsWith(".md")) {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
const fragmentId = parts[1].slice(0, -".md".length);
|
|
643
|
+
return isInstructionFragmentId(fragmentId) ? fragmentId : null;
|
|
644
|
+
};
|
|
645
|
+
const dynamicResolverIdentityForPath = (path) => {
|
|
646
|
+
const parts = path.split("/");
|
|
647
|
+
if (parts.length !== 2 || !parts[1]?.endsWith(".dynamic.ts"))
|
|
648
|
+
return null;
|
|
649
|
+
const slot = parts[0];
|
|
650
|
+
if (slot !== "tools" && slot !== "skills" && slot !== "instructions")
|
|
651
|
+
return null;
|
|
652
|
+
const resolverId = parts[1].slice(0, -".dynamic.ts".length);
|
|
653
|
+
if (!isDynamicResolverId(resolverId))
|
|
654
|
+
return null;
|
|
655
|
+
return { slot, resolverId };
|
|
656
|
+
};
|
|
657
|
+
const stripYamlQuotes = (value) => {
|
|
658
|
+
if (((value.startsWith('"') && value.endsWith('"')) ||
|
|
659
|
+
(value.startsWith("'") && value.endsWith("'"))) &&
|
|
660
|
+
value.length >= 2) {
|
|
661
|
+
return value.slice(1, -1);
|
|
662
|
+
}
|
|
663
|
+
return value;
|
|
664
|
+
};
|
|
665
|
+
const parseSkillFrontmatter = (state, path, text) => {
|
|
666
|
+
const normalized = text.replace(/\r\n?/gu, "\n");
|
|
667
|
+
const lines = normalized.split("\n");
|
|
668
|
+
if (lines[0]?.trim() !== "---") {
|
|
669
|
+
invalidAuthoredValue(state, path, "/frontmatter", "frontmatter_required");
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
|
|
673
|
+
if (end < 0) {
|
|
674
|
+
invalidAuthoredValue(state, path, "/frontmatter", "frontmatter_not_closed");
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
const issueCount = state.issues.length;
|
|
678
|
+
const fields = {};
|
|
679
|
+
for (let index = 1; index < end; index += 1) {
|
|
680
|
+
const line = lines[index]?.trim() ?? "";
|
|
681
|
+
if (line.length === 0)
|
|
682
|
+
continue;
|
|
683
|
+
const match = /^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/u.exec(line);
|
|
684
|
+
if (match === null) {
|
|
685
|
+
invalidAuthoredValue(state, path, `/frontmatter/${index}`, "frontmatter_line_invalid");
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
const [, key, rawValue] = match;
|
|
689
|
+
if (Object.prototype.hasOwnProperty.call(fields, key)) {
|
|
690
|
+
invalidAuthoredValue(state, path, `/frontmatter/${key}`, "frontmatter_field_duplicate");
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
fields[key] = stripYamlQuotes(rawValue.trim());
|
|
694
|
+
}
|
|
695
|
+
assertAllowedFields(state, path, fields, new Set(["name", "description"]));
|
|
696
|
+
const name = parseSkillFrontmatterStringField(state, path, "/frontmatter/name", fields.name);
|
|
697
|
+
const description = parseSkillDescriptionField(state, path, fields.description);
|
|
698
|
+
if (name === null || description === null || state.issues.length > issueCount)
|
|
699
|
+
return null;
|
|
700
|
+
return {
|
|
701
|
+
name,
|
|
702
|
+
description,
|
|
703
|
+
body: lines
|
|
704
|
+
.slice(end + 1)
|
|
705
|
+
.join("\n")
|
|
706
|
+
.replace(/^\n/u, "")
|
|
707
|
+
.replace(/\s+$/u, ""),
|
|
708
|
+
};
|
|
709
|
+
};
|
|
710
|
+
const recordInstructionFragmentFile = (state, path, fragmentId, text, sourceKind) => {
|
|
711
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
712
|
+
return;
|
|
713
|
+
if (text.trim().length === 0) {
|
|
714
|
+
invalidAuthoredValue(state, path, "/body", "instruction_fragment_empty");
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
if (!assertNoNulText(state, path, "/body", text))
|
|
718
|
+
return;
|
|
719
|
+
const existing = state.instructionFragments.get(fragmentId);
|
|
720
|
+
if (existing !== undefined) {
|
|
721
|
+
state.issues.push({
|
|
722
|
+
kind: "duplicate_instruction_fragment",
|
|
723
|
+
fragmentId,
|
|
724
|
+
path,
|
|
725
|
+
existingPath: existing.path,
|
|
726
|
+
});
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
state.instructionFragments.set(fragmentId, {
|
|
730
|
+
fragmentId,
|
|
731
|
+
path: authoredPath(path),
|
|
732
|
+
digest: digestText(text),
|
|
733
|
+
text,
|
|
734
|
+
origin: pathOrigin(path),
|
|
735
|
+
});
|
|
736
|
+
};
|
|
737
|
+
const recordSkillFile = (state, path, expectedName, text, sourceKind) => {
|
|
738
|
+
if (!isSkillName(expectedName)) {
|
|
739
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "skill_name_invalid" });
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
743
|
+
return;
|
|
744
|
+
const parsed = parseSkillFrontmatter(state, path, text);
|
|
745
|
+
if (parsed === null)
|
|
746
|
+
return;
|
|
747
|
+
if (!isSkillName(parsed.name)) {
|
|
748
|
+
invalidAuthoredValue(state, path, "/frontmatter/name", "skill_name_invalid");
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (parsed.name !== expectedName) {
|
|
752
|
+
state.issues.push({
|
|
753
|
+
kind: "skill_identity_mismatch",
|
|
754
|
+
path,
|
|
755
|
+
expectedName,
|
|
756
|
+
actualName: parsed.name,
|
|
757
|
+
});
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (utf8ByteLength(parsed.body) > SKILL_BODY_MAX_BYTES) {
|
|
761
|
+
invalidAuthoredValue(state, path, "/body", "skill_body_too_large");
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (!assertNoNulText(state, path, "/body", parsed.body))
|
|
765
|
+
return;
|
|
766
|
+
const existing = state.skills.get(expectedName);
|
|
767
|
+
if (existing !== undefined) {
|
|
768
|
+
state.issues.push({
|
|
769
|
+
kind: "duplicate_skill",
|
|
770
|
+
name: expectedName,
|
|
771
|
+
path,
|
|
772
|
+
existingPath: existing.path,
|
|
773
|
+
});
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
state.skills.set(expectedName, {
|
|
777
|
+
name: expectedName,
|
|
778
|
+
description: parsed.description,
|
|
779
|
+
path: authoredPath(path),
|
|
780
|
+
digest: digestText(parsed.body),
|
|
781
|
+
text: parsed.body,
|
|
782
|
+
files: [],
|
|
783
|
+
});
|
|
784
|
+
};
|
|
785
|
+
const recordSkillSupportFile = (state, path, supportPath, bytes, sourceKind) => {
|
|
786
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
787
|
+
return;
|
|
788
|
+
if (bytes.byteLength > SKILL_SUPPORT_FILE_MAX_BYTES) {
|
|
789
|
+
invalidAuthoredValue(state, path, "/bytes", "skill_file_too_large");
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const files = state.skillSupportFiles.get(supportPath.skillName) ?? [];
|
|
793
|
+
if (files.length >= SKILL_SUPPORT_FILES_MAX_COUNT) {
|
|
794
|
+
invalidAuthoredValue(state, path, "/bytes", "skill_package_too_many_files");
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
const currentBytes = state.skillSupportByteTotals.get(supportPath.skillName) ?? 0;
|
|
798
|
+
if (currentBytes + bytes.byteLength > SKILL_SUPPORT_PACKAGE_MAX_BYTES) {
|
|
799
|
+
invalidAuthoredValue(state, path, "/bytes", "skill_package_too_large");
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const text = decodeUtf8Bytes(state, path, "/bytes", bytes);
|
|
803
|
+
if (text === null || !assertNoNulText(state, path, "/bytes", text))
|
|
804
|
+
return;
|
|
805
|
+
files.push({
|
|
806
|
+
path: supportPath.packagePath,
|
|
807
|
+
digest: digestText(text),
|
|
808
|
+
bytes: bytes.byteLength,
|
|
809
|
+
text,
|
|
810
|
+
});
|
|
811
|
+
state.skillSupportFiles.set(supportPath.skillName, files);
|
|
812
|
+
state.skillSupportByteTotals.set(supportPath.skillName, currentBytes + bytes.byteLength);
|
|
813
|
+
};
|
|
814
|
+
const recordMarkdownFile = (state, path, text, sourceKind) => {
|
|
815
|
+
const skillName = skillIdentityForPath(path);
|
|
816
|
+
if (path.startsWith("skills/")) {
|
|
817
|
+
if (skillName === null) {
|
|
818
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "skill_path_not_in_grammar" });
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
recordSkillFile(state, path, skillName, text, sourceKind);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (path.startsWith("instructions/")) {
|
|
825
|
+
const fragmentId = instructionFragmentIdForPath(path);
|
|
826
|
+
if (fragmentId === null) {
|
|
827
|
+
state.issues.push({
|
|
828
|
+
kind: "unsupported_path",
|
|
829
|
+
path,
|
|
830
|
+
reason: "instruction_fragment_path_not_in_grammar",
|
|
831
|
+
});
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
recordInstructionFragmentFile(state, path, fragmentId, text, sourceKind);
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
507
837
|
if (path !== "instructions.md") {
|
|
508
838
|
state.issues.push({ kind: "unsupported_path", path, reason: "markdown_path_not_in_grammar" });
|
|
509
839
|
return;
|
|
@@ -516,20 +846,225 @@ const recordMarkdownFile = (state, path, text) => {
|
|
|
516
846
|
};
|
|
517
847
|
putAuthored(state, "/instructions", instructions, pathOrigin(path));
|
|
518
848
|
};
|
|
849
|
+
const recordTextFile = (state, path, bytes, sourceKind) => {
|
|
850
|
+
const supportPath = skillSupportPathForPath(path);
|
|
851
|
+
if (supportPath === null) {
|
|
852
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "text_path_not_in_grammar" });
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
recordSkillSupportFile(state, path, supportPath, bytes, sourceKind);
|
|
856
|
+
};
|
|
519
857
|
const recordToolFile = (state, path, declaration) => {
|
|
520
858
|
const parts = path.split("/");
|
|
521
859
|
if (parts.length !== 2 || parts[0] !== "tools" || !parts[1]?.endsWith(".ts")) {
|
|
522
860
|
state.issues.push({ kind: "unsupported_path", path, reason: "tool_path_not_in_grammar" });
|
|
523
861
|
return;
|
|
524
862
|
}
|
|
863
|
+
if (parts[1].endsWith(".dynamic.ts")) {
|
|
864
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "dynamic_path_not_in_grammar" });
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
525
867
|
const toolId = parts[1].slice(0, -".ts".length);
|
|
526
868
|
if (toolId.length === 0) {
|
|
527
869
|
state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
|
|
528
870
|
return;
|
|
529
871
|
}
|
|
872
|
+
if (toolId === GENERATED_LOAD_SKILL_TOOL_NAME || toolId === GENERATED_READ_SKILL_FILE_TOOL_NAME) {
|
|
873
|
+
state.issues.push({ kind: "reserved_tool_name", path, toolId });
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
530
876
|
state.toolFilePaths.set(toolId, path);
|
|
531
877
|
recordToolFacts(state, toolId, path, declaration ?? {}, (field) => authorOrigin(path, field));
|
|
532
878
|
};
|
|
879
|
+
const parseDynamicOutputs = (state, path, slot, value) => {
|
|
880
|
+
if (!isRecord(value)) {
|
|
881
|
+
invalidAuthoredValue(state, path, "/outputs", "object_required");
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
for (const outputSlot of Object.keys(value)) {
|
|
885
|
+
if (!dynamicOutputSlots.includes(outputSlot)) {
|
|
886
|
+
state.issues.push({ kind: "unknown_field", path, field: `/outputs/${outputSlot}` });
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
if (outputSlot !== slot) {
|
|
890
|
+
state.issues.push({
|
|
891
|
+
kind: "dynamic_resolver_cross_slot_output",
|
|
892
|
+
path,
|
|
893
|
+
slot,
|
|
894
|
+
outputSlot: outputSlot,
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (!Object.prototype.hasOwnProperty.call(value, slot)) {
|
|
899
|
+
invalidAuthoredValue(state, path, `/outputs/${slot}`, "dynamic_resolver_output_required");
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
return parseStringArrayField(state, path, `/outputs/${slot}`, value[slot]);
|
|
903
|
+
};
|
|
904
|
+
const recordDynamicResolverFile = (state, path, declaration, sourceKind) => {
|
|
905
|
+
const identity = dynamicResolverIdentityForPath(path);
|
|
906
|
+
if (identity === null) {
|
|
907
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "dynamic_path_not_in_grammar" });
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
911
|
+
return;
|
|
912
|
+
if (!isRecord(declaration)) {
|
|
913
|
+
invalidAuthoredValue(state, path, "/", "dynamic_resolver_declaration_object_required");
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const localIssueCount = state.issues.length;
|
|
917
|
+
assertNoPathIdentityFields(state, path, declaration);
|
|
918
|
+
assertAllowedFields(state, path, declaration, dynamicResolverAllowedFields);
|
|
919
|
+
assertNoRuntimeFactFields(state, path, declaration);
|
|
920
|
+
const outputs = parseDynamicOutputs(state, path, identity.slot, declaration.outputs);
|
|
921
|
+
if (outputs === null || state.issues.length > localIssueCount)
|
|
922
|
+
return;
|
|
923
|
+
const key = `${identity.slot}/${identity.resolverId}`;
|
|
924
|
+
const existing = state.dynamicResolvers.get(key);
|
|
925
|
+
if (existing !== undefined) {
|
|
926
|
+
state.issues.push({
|
|
927
|
+
kind: "duplicate_dynamic_resolver",
|
|
928
|
+
slot: identity.slot,
|
|
929
|
+
resolverId: identity.resolverId,
|
|
930
|
+
path,
|
|
931
|
+
existingPath: existing.path,
|
|
932
|
+
});
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
state.dynamicResolvers.set(key, {
|
|
936
|
+
resolverId: identity.resolverId,
|
|
937
|
+
slot: identity.slot,
|
|
938
|
+
path: authoredPath(path),
|
|
939
|
+
outputs,
|
|
940
|
+
origin: pathOrigin(path),
|
|
941
|
+
});
|
|
942
|
+
};
|
|
943
|
+
const recordChannelFile = (state, path, sourceKind) => {
|
|
944
|
+
const parts = path.split("/");
|
|
945
|
+
if (parts.length !== 2 || parts[0] !== "channels" || !parts[1]?.endsWith(".ts")) {
|
|
946
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "channel_path_not_in_grammar" });
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const name = parts[1].slice(0, -".ts".length);
|
|
950
|
+
if (name.length === 0) {
|
|
951
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
if (!isChannelName(name)) {
|
|
955
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "channel_name_invalid" });
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
959
|
+
return;
|
|
960
|
+
state.channels.set(name, {
|
|
961
|
+
name,
|
|
962
|
+
path: authoredPath(path),
|
|
963
|
+
origin: pathOrigin(path),
|
|
964
|
+
});
|
|
965
|
+
};
|
|
966
|
+
const recordWorkflowFile = (state, path, sourceKind) => {
|
|
967
|
+
const parts = path.split("/");
|
|
968
|
+
if (parts.length !== 2 || parts[0] !== "workflows" || !parts[1]?.endsWith(".ts")) {
|
|
969
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "workflow_path_not_in_grammar" });
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const name = parts[1].slice(0, -".ts".length);
|
|
973
|
+
if (name.length === 0) {
|
|
974
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (!isWorkflowName(name)) {
|
|
978
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "workflow_name_invalid" });
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
982
|
+
return;
|
|
983
|
+
state.workflows.set(name, {
|
|
984
|
+
name,
|
|
985
|
+
path: authoredPath(path),
|
|
986
|
+
origin: pathOrigin(path),
|
|
987
|
+
});
|
|
988
|
+
};
|
|
989
|
+
const scheduleAllowedFields = new Set(["cron", "handler", "id", "name", "kind"]);
|
|
990
|
+
const scheduleIdFromPath = (state, path) => {
|
|
991
|
+
const parts = path.split("/");
|
|
992
|
+
if (parts.length < 2 || parts[0] !== "schedules" || !parts[parts.length - 1]?.endsWith(".ts")) {
|
|
993
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "schedule_path_not_in_grammar" });
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
const slugs = [...parts.slice(1, -1), parts[parts.length - 1].slice(0, -".ts".length)];
|
|
997
|
+
if (slugs.some((slug) => slug.length === 0)) {
|
|
998
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "empty_path_identity" });
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
if (slugs.includes("subagents")) {
|
|
1002
|
+
state.issues.push({
|
|
1003
|
+
kind: "unsupported_path",
|
|
1004
|
+
path,
|
|
1005
|
+
reason: "subagent_schedule_directory_forbidden",
|
|
1006
|
+
});
|
|
1007
|
+
return null;
|
|
1008
|
+
}
|
|
1009
|
+
const invalid = slugs.find((slug) => !isScheduleSlug(slug));
|
|
1010
|
+
if (invalid !== undefined) {
|
|
1011
|
+
state.issues.push({ kind: "unsupported_path", path, reason: "schedule_slug_invalid" });
|
|
1012
|
+
return null;
|
|
1013
|
+
}
|
|
1014
|
+
return slugs.join("/");
|
|
1015
|
+
};
|
|
1016
|
+
const recordScheduleFile = (state, path, declaration, sourceKind) => {
|
|
1017
|
+
const scheduleId = scheduleIdFromPath(state, path);
|
|
1018
|
+
if (scheduleId === null)
|
|
1019
|
+
return;
|
|
1020
|
+
if (!assertRegularAuthoredSource(state, path, sourceKind))
|
|
1021
|
+
return;
|
|
1022
|
+
if (!isRecord(declaration)) {
|
|
1023
|
+
invalidAuthoredValue(state, path, "/", "schedule_declaration_object_required");
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
const declarationRecord = declaration;
|
|
1027
|
+
const localIssueCount = state.issues.length;
|
|
1028
|
+
assertNoPathIdentityFields(state, path, declarationRecord);
|
|
1029
|
+
if (Object.prototype.hasOwnProperty.call(declarationRecord, "kind")) {
|
|
1030
|
+
state.issues.push({ kind: "identity_field_forbidden", path, field: "kind" });
|
|
1031
|
+
}
|
|
1032
|
+
assertAllowedFields(state, path, declarationRecord, scheduleAllowedFields);
|
|
1033
|
+
assertNoRuntimeFactFields(state, path, declarationRecord);
|
|
1034
|
+
if (state.issues.length > localIssueCount)
|
|
1035
|
+
return;
|
|
1036
|
+
if (typeof declaration.cron !== "string") {
|
|
1037
|
+
invalidAuthoredValue(state, path, "/cron", "cron_string_required");
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
if (typeof declaration.handler !== "function") {
|
|
1041
|
+
invalidAuthoredValue(state, path, "/handler", "schedule_handler_function_required");
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
let cron;
|
|
1045
|
+
try {
|
|
1046
|
+
cron = cronMinuteExpression(declaration.cron);
|
|
1047
|
+
}
|
|
1048
|
+
catch {
|
|
1049
|
+
invalidAuthoredValue(state, path, "/cron", "cron_minute_expression_invalid");
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
if (state.schedules.has(scheduleId)) {
|
|
1053
|
+
const existing = state.schedules.get(scheduleId);
|
|
1054
|
+
state.issues.push({
|
|
1055
|
+
kind: "duplicate_path",
|
|
1056
|
+
path: authoredPath(path),
|
|
1057
|
+
existingPath: existing?.path ?? authoredPath(path),
|
|
1058
|
+
});
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
state.schedules.set(scheduleId, {
|
|
1062
|
+
scheduleId,
|
|
1063
|
+
cron,
|
|
1064
|
+
path: authoredPath(path),
|
|
1065
|
+
origin: pathOrigin(path),
|
|
1066
|
+
});
|
|
1067
|
+
};
|
|
533
1068
|
const applyDefaults = (state) => {
|
|
534
1069
|
putDefault(state, "/agentId", "agent");
|
|
535
1070
|
const agentId = state.facts.get("/agentId")?.value;
|
|
@@ -629,6 +1164,10 @@ const buildManifest = (state) => {
|
|
|
629
1164
|
const bindingRef = factValue(state, `/llmRoutes/${id}/bindingRef`);
|
|
630
1165
|
return bindingRef === undefined ? null : { bindingRef };
|
|
631
1166
|
});
|
|
1167
|
+
const capabilities = collectRecord(state, "/capabilities/", (id) => {
|
|
1168
|
+
const bindingRef = factValue(state, `/capabilities/${id}/bindingRef`);
|
|
1169
|
+
return bindingRef === undefined ? null : { bindingRef };
|
|
1170
|
+
});
|
|
632
1171
|
const tools = collectRecord(state, "/tools/", (id) => collectTool(state, id));
|
|
633
1172
|
const materials = collectRecord(state, "/materials/", (id) => factValue(state, `/materials/${id}`) ?? null);
|
|
634
1173
|
const executionDomains = collectRecord(state, "/executionDomains/", (id) => {
|
|
@@ -649,6 +1188,7 @@ const buildManifest = (state) => {
|
|
|
649
1188
|
handlers: factValue(state, "/handlers") ?? [],
|
|
650
1189
|
...(version === undefined ? {} : { version }),
|
|
651
1190
|
...(instructions === undefined ? {} : { instructions }),
|
|
1191
|
+
...(capabilities === undefined ? {} : { capabilities }),
|
|
652
1192
|
...(llmRoutes === undefined ? {} : { llmRoutes }),
|
|
653
1193
|
...(tools === undefined ? {} : { tools }),
|
|
654
1194
|
...(materials === undefined ? {} : { materials }),
|
|
@@ -678,10 +1218,61 @@ const buildToolFilePaths = (state) => {
|
|
|
678
1218
|
}
|
|
679
1219
|
return paths;
|
|
680
1220
|
};
|
|
1221
|
+
const buildChannels = (state) => [...state.channels.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
1222
|
+
const buildWorkflows = (state) => [...state.workflows.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
1223
|
+
const buildSchedules = (state) => [...state.schedules.values()].sort((left, right) => left.scheduleId.localeCompare(right.scheduleId));
|
|
1224
|
+
const buildInstructionFragments = (state) => [...state.instructionFragments.values()].sort((left, right) => left.fragmentId.localeCompare(right.fragmentId));
|
|
1225
|
+
const buildDynamicResolvers = (state) => [...state.dynamicResolvers.values()].sort((left, right) => left.slot.localeCompare(right.slot) || left.resolverId.localeCompare(right.resolverId));
|
|
1226
|
+
const validateSkillSupportFiles = (state) => {
|
|
1227
|
+
for (const [skillName, files] of state.skillSupportFiles.entries()) {
|
|
1228
|
+
const skill = state.skills.get(skillName);
|
|
1229
|
+
if (skill !== undefined && isPackagedSkillPath(skill))
|
|
1230
|
+
continue;
|
|
1231
|
+
for (const file of files) {
|
|
1232
|
+
state.issues.push({
|
|
1233
|
+
kind: "unsupported_path",
|
|
1234
|
+
path: `skills/${skillName}/${file.path}`,
|
|
1235
|
+
reason: "skill_support_requires_packaged_skill",
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
const dynamicResolverTargets = (state, slot) => {
|
|
1241
|
+
switch (slot) {
|
|
1242
|
+
case "tools":
|
|
1243
|
+
return state.toolIds;
|
|
1244
|
+
case "skills":
|
|
1245
|
+
return new Set(state.skills.keys());
|
|
1246
|
+
case "instructions":
|
|
1247
|
+
return new Set(state.instructionFragments.keys());
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
const validateDynamicResolvers = (state) => {
|
|
1251
|
+
for (const resolver of state.dynamicResolvers.values()) {
|
|
1252
|
+
const targetIds = dynamicResolverTargets(state, resolver.slot);
|
|
1253
|
+
for (const targetId of resolver.outputs) {
|
|
1254
|
+
if (targetIds.has(targetId))
|
|
1255
|
+
continue;
|
|
1256
|
+
state.issues.push({
|
|
1257
|
+
kind: "dynamic_resolver_unknown_target",
|
|
1258
|
+
path: resolver.path,
|
|
1259
|
+
slot: resolver.slot,
|
|
1260
|
+
targetId,
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
1265
|
+
const buildSkills = (state) => [...state.skills.values()]
|
|
1266
|
+
.map((skill) => ({
|
|
1267
|
+
...skill,
|
|
1268
|
+
files: [...(state.skillSupportFiles.get(skill.name) ?? [])].sort((left, right) => left.path.localeCompare(right.path)),
|
|
1269
|
+
}))
|
|
1270
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
681
1271
|
/**
|
|
682
|
-
* Compile
|
|
683
|
-
*
|
|
684
|
-
* material are rejected before they can become manifest
|
|
1272
|
+
* Compile authored `agent/` and `workflows/` roots into one normalized
|
|
1273
|
+
* manifest plus authoring facts. This is the app-author entrypoint; runtime
|
|
1274
|
+
* facts and provider material are rejected before they can become manifest
|
|
1275
|
+
* truth.
|
|
685
1276
|
*
|
|
686
1277
|
* @agentosPrimitive primitive.agent-authoring.compileAgentTree
|
|
687
1278
|
* @agentosInvariant invariant.docs.agent-projection
|
|
@@ -695,6 +1286,14 @@ export const compileAgentTree = (tree) => {
|
|
|
695
1286
|
pathKeys: new Map(),
|
|
696
1287
|
toolIds: new Set(),
|
|
697
1288
|
toolFilePaths: new Map(),
|
|
1289
|
+
channels: new Map(),
|
|
1290
|
+
workflows: new Map(),
|
|
1291
|
+
schedules: new Map(),
|
|
1292
|
+
skills: new Map(),
|
|
1293
|
+
skillSupportFiles: new Map(),
|
|
1294
|
+
skillSupportByteTotals: new Map(),
|
|
1295
|
+
instructionFragments: new Map(),
|
|
1296
|
+
dynamicResolvers: new Map(),
|
|
698
1297
|
workspaceToolControls: new Map(),
|
|
699
1298
|
};
|
|
700
1299
|
for (const file of tree.files) {
|
|
@@ -703,7 +1302,10 @@ export const compileAgentTree = (tree) => {
|
|
|
703
1302
|
continue;
|
|
704
1303
|
switch (file.kind) {
|
|
705
1304
|
case "markdown":
|
|
706
|
-
recordMarkdownFile(state, path, file.text);
|
|
1305
|
+
recordMarkdownFile(state, path, file.text, file.sourceKind);
|
|
1306
|
+
break;
|
|
1307
|
+
case "text":
|
|
1308
|
+
recordTextFile(state, path, file.bytes, file.sourceKind);
|
|
707
1309
|
break;
|
|
708
1310
|
case "json":
|
|
709
1311
|
recordJsonFile(state, path, file.value);
|
|
@@ -711,8 +1313,22 @@ export const compileAgentTree = (tree) => {
|
|
|
711
1313
|
case "tool":
|
|
712
1314
|
recordToolFile(state, path, file.declaration);
|
|
713
1315
|
break;
|
|
1316
|
+
case "dynamic":
|
|
1317
|
+
recordDynamicResolverFile(state, path, file.declaration, file.sourceKind);
|
|
1318
|
+
break;
|
|
1319
|
+
case "channel":
|
|
1320
|
+
recordChannelFile(state, path, file.sourceKind);
|
|
1321
|
+
break;
|
|
1322
|
+
case "workflow":
|
|
1323
|
+
recordWorkflowFile(state, path, file.sourceKind);
|
|
1324
|
+
break;
|
|
1325
|
+
case "schedule":
|
|
1326
|
+
recordScheduleFile(state, path, file.declaration, file.sourceKind);
|
|
1327
|
+
break;
|
|
714
1328
|
}
|
|
715
1329
|
}
|
|
1330
|
+
validateSkillSupportFiles(state);
|
|
1331
|
+
validateDynamicResolvers(state);
|
|
716
1332
|
applyDefaults(state);
|
|
717
1333
|
enforceL0(state);
|
|
718
1334
|
if (state.issues.length > 0)
|
|
@@ -732,6 +1348,12 @@ export const compileAgentTree = (tree) => {
|
|
|
732
1348
|
provenance: buildProvenance(state),
|
|
733
1349
|
workspaceToolControls: buildWorkspaceToolControls(state),
|
|
734
1350
|
toolFilePaths: buildToolFilePaths(state),
|
|
1351
|
+
channels: buildChannels(state),
|
|
1352
|
+
workflows: buildWorkflows(state),
|
|
1353
|
+
schedules: buildSchedules(state),
|
|
1354
|
+
skills: buildSkills(state),
|
|
1355
|
+
instructionFragments: buildInstructionFragments(state),
|
|
1356
|
+
dynamicResolvers: buildDynamicResolvers(state),
|
|
735
1357
|
},
|
|
736
1358
|
};
|
|
737
1359
|
};
|