@yansirplus/cli 0.5.17
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/PUBLIC_API.md +22 -0
- package/README.md +34 -0
- package/dist/build/agent-authoring/config.d.ts +177 -0
- package/dist/build/agent-authoring/config.js +607 -0
- package/dist/build/agent-authoring/manifest-compiler.d.ts +159 -0
- package/dist/build/agent-authoring/manifest-compiler.js +737 -0
- package/dist/build/agent-authoring/shared.d.ts +10 -0
- package/dist/build/agent-authoring/shared.js +57 -0
- package/dist/build/agent-authoring/static-target.d.ts +59 -0
- package/dist/build/agent-authoring/static-target.js +1857 -0
- package/dist/build/agent-authoring.d.ts +9 -0
- package/dist/build/agent-authoring.js +5 -0
- package/dist/build/build-cli.d.ts +2 -0
- package/dist/build/build-cli.js +264 -0
- package/dist/check/algorithmic/architecture-checks.mjs +971 -0
- package/dist/check/algorithmic/client-boundary-checks.mjs +337 -0
- package/dist/check/algorithmic/convergence-smoke-checks.mjs +608 -0
- package/dist/check/algorithmic/distribution-checks.mjs +919 -0
- package/dist/check/algorithmic/owner-checks.mjs +647 -0
- package/dist/check/algorithmic/package-boundary-checks.mjs +985 -0
- package/dist/check/algorithmic/projection-boundary-checks.mjs +302 -0
- package/dist/check/algorithmic/repo-surface-checks.mjs +267 -0
- package/dist/check/algorithmic/runtime-structural-checks.mjs +264 -0
- package/dist/check/algorithmic/source-alias-checks.mjs +106 -0
- package/dist/check/algorithmic/static-target-checks.mjs +447 -0
- package/dist/check/algorithmic-checks.mjs +482 -0
- package/dist/check/check-coverage.mjs +231 -0
- package/dist/check/command-runner.mjs +22 -0
- package/dist/check/default-gate.mjs +51 -0
- package/dist/check/gate-selector.mjs +305 -0
- package/dist/check/manifest-rules.mjs +223 -0
- package/dist/check/package-graph.mjs +464 -0
- package/dist/generate/generate-agent-docs.mjs +435 -0
- package/dist/generate/generate-carrier-reference.mjs +514 -0
- package/dist/generate/generate-docs.mjs +345 -0
- package/dist/generate/generate-effect-skill-manifests.mjs +193 -0
- package/dist/generate/project-docs-site.mjs +190 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -0
- package/dist/lib/agent-docs-model.mjs +888 -0
- package/dist/lib/boundary-rules.mjs +63 -0
- package/dist/lib/capability-routes.mjs +354 -0
- package/dist/lib/projection-sink.mjs +113 -0
- package/dist/lib/public-api-model.mjs +306 -0
- package/dist/main.mjs +233 -0
- package/dist/runner.mjs +127 -0
- package/package.json +32 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
import { authoredValue } from "@yansirplus/core/authored-value";
|
|
2
|
+
import { WORKSPACE_TOPOLOGY, manifestScopeRefResult, workspaceBindingRef, workspaceProviderResourceId, } from "@yansirplus/core/runtime-protocol";
|
|
3
|
+
import { WORKSPACE_TOOL_DEFAULT_DECLARATIONS, } from "@yansirplus/runtime";
|
|
4
|
+
import { digestHex64, isNonEmptyString, isRecord } from "./shared.js";
|
|
5
|
+
import { workspaceManifestMacroOrigin } from "./manifest-compiler.js";
|
|
6
|
+
export const AGENTOS_CONFIG_PROFILE = {
|
|
7
|
+
WORKSPACE_V1: "workspace@1",
|
|
8
|
+
CHAT_V1: "chat@1",
|
|
9
|
+
};
|
|
10
|
+
export const AGENTOS_CONFIG_TARGET = {
|
|
11
|
+
CLOUDFLARE_DO_V1: "cloudflare-do@1",
|
|
12
|
+
};
|
|
13
|
+
export const AGENTOS_CONFIG_CLIENT = {
|
|
14
|
+
SVELTE_KIT_REMOTE_V1: "svelte-kit-remote@1",
|
|
15
|
+
BROWSER_DIRECT_V1: "browser-direct@1",
|
|
16
|
+
};
|
|
17
|
+
export const AGENTOS_CONFIG_LLM_ROUTE = {
|
|
18
|
+
OPENAI_CHAT_COMPATIBLE: "openai-chat-compatible",
|
|
19
|
+
};
|
|
20
|
+
const configAuthorOrigin = (factKey) => `author:agentos.config.jsonc#${factKey}`;
|
|
21
|
+
const workspaceMacroOrigin = (factKey) => `macro(${AGENTOS_CONFIG_PROFILE.WORKSPACE_V1})#${factKey}`;
|
|
22
|
+
const chatMacroOrigin = (factKey) => `macro(${AGENTOS_CONFIG_PROFILE.CHAT_V1})#${factKey}`;
|
|
23
|
+
const materialEnvPrefix = (kind) => kind === "endpoint"
|
|
24
|
+
? "AGENTOS_ENDPOINT"
|
|
25
|
+
: kind === "credential"
|
|
26
|
+
? "AGENTOS_CREDENTIAL"
|
|
27
|
+
: "AGENTOS_MODEL";
|
|
28
|
+
const materialEnvSuffix = (ref) => ref
|
|
29
|
+
.toUpperCase()
|
|
30
|
+
.replace(/[^A-Z0-9]+/g, "_")
|
|
31
|
+
.replace(/^_+|_+$/g, "") || "REF";
|
|
32
|
+
export const materialEnvNameForRef = (kind, ref) => `${materialEnvPrefix(kind)}_${materialEnvSuffix(ref)}`;
|
|
33
|
+
export const llmMaterialEnvBindingsForRefs = (refs) => refs.map(({ kind, ref }) => ({ kind, ref, envName: materialEnvNameForRef(kind, ref) }));
|
|
34
|
+
export const llmMaterialEnvNameCollisionIssues = (bindings) => {
|
|
35
|
+
const byEnv = new Map();
|
|
36
|
+
const issues = [];
|
|
37
|
+
for (const binding of bindings) {
|
|
38
|
+
const materialRef = `${binding.kind}:${binding.ref}`;
|
|
39
|
+
const existing = byEnv.get(binding.envName);
|
|
40
|
+
if (existing === undefined) {
|
|
41
|
+
byEnv.set(binding.envName, materialRef);
|
|
42
|
+
}
|
|
43
|
+
else if (existing !== materialRef) {
|
|
44
|
+
issues.push({
|
|
45
|
+
kind: "llm_material_env_name_collision",
|
|
46
|
+
path: "agentos.config.jsonc#/llm",
|
|
47
|
+
envName: binding.envName,
|
|
48
|
+
refs: [existing, materialRef],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return issues;
|
|
53
|
+
};
|
|
54
|
+
export const llmMaterialEnvBindings = (llm) => llmMaterialEnvBindingsForRefs([
|
|
55
|
+
{ kind: "endpoint", ref: llm.endpointRef },
|
|
56
|
+
{ kind: "credential", ref: llm.credentialRef },
|
|
57
|
+
{ kind: "model", ref: llm.modelRef },
|
|
58
|
+
]);
|
|
59
|
+
const configAllowedFields = new Set([
|
|
60
|
+
"$schema",
|
|
61
|
+
"profile",
|
|
62
|
+
"agent",
|
|
63
|
+
"deployment",
|
|
64
|
+
"target",
|
|
65
|
+
"client",
|
|
66
|
+
"llm",
|
|
67
|
+
"workspace",
|
|
68
|
+
]);
|
|
69
|
+
const deploymentAllowedFields = new Set(["id", "version"]);
|
|
70
|
+
const targetAllowedFields = new Set(["kind", "durableObject"]);
|
|
71
|
+
const durableObjectAllowedFields = new Set(["className", "binding"]);
|
|
72
|
+
const clientAllowedFields = new Set(["kind"]);
|
|
73
|
+
const llmAllowedFields = new Set(["route", "endpointRef", "credentialRef", "modelRef"]);
|
|
74
|
+
const workspaceAllowedFields = new Set(["binding", "root", "topology"]);
|
|
75
|
+
const topologyAllowedFields = new Set(["kind", "allocator"]);
|
|
76
|
+
const configRuntimeFactFields = new Set([
|
|
77
|
+
"continuation",
|
|
78
|
+
"continuationRef",
|
|
79
|
+
"inputRequestRef",
|
|
80
|
+
"snapshot",
|
|
81
|
+
"actualTriggerTime",
|
|
82
|
+
"resumePayload",
|
|
83
|
+
"resolvedMaterial",
|
|
84
|
+
"secret",
|
|
85
|
+
"credential",
|
|
86
|
+
"triggerTime",
|
|
87
|
+
]);
|
|
88
|
+
const issueInvalidConfigValue = (issues, path, field, reason) => {
|
|
89
|
+
issues.push({ kind: "invalid_config_value", path, field, reason });
|
|
90
|
+
};
|
|
91
|
+
const assertConfigAllowedFields = (issues, path, value, allowed) => {
|
|
92
|
+
for (const field of Object.keys(value)) {
|
|
93
|
+
if (!allowed.has(field))
|
|
94
|
+
issues.push({ kind: "unknown_field", path, field });
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const assertNoConfigRuntimeFacts = (issues, path, value) => {
|
|
98
|
+
const visit = (record, fieldPrefix) => {
|
|
99
|
+
for (const [field, child] of Object.entries(record)) {
|
|
100
|
+
const fieldPath = fieldPrefix.length === 0 ? field : `${fieldPrefix}.${field}`;
|
|
101
|
+
if (configRuntimeFactFields.has(field)) {
|
|
102
|
+
issues.push({ kind: "runtime_fact_forbidden", path, field: fieldPath });
|
|
103
|
+
}
|
|
104
|
+
if (typeof child === "function") {
|
|
105
|
+
issues.push({ kind: "function_in_config", path: `${path}.${fieldPath}` });
|
|
106
|
+
}
|
|
107
|
+
if (isRecord(child))
|
|
108
|
+
visit(child, fieldPath);
|
|
109
|
+
if (Array.isArray(child)) {
|
|
110
|
+
for (let index = 0; index < child.length; index += 1) {
|
|
111
|
+
const item = child[index];
|
|
112
|
+
if (isRecord(item))
|
|
113
|
+
visit(item, `${fieldPath}[${index}]`);
|
|
114
|
+
if (typeof item === "function") {
|
|
115
|
+
issues.push({ kind: "function_in_config", path: `${path}.${fieldPath}[${index}]` });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
visit(value, "");
|
|
122
|
+
};
|
|
123
|
+
const configStringField = (issues, path, field, value) => {
|
|
124
|
+
if (isNonEmptyString(value))
|
|
125
|
+
return value;
|
|
126
|
+
issueInvalidConfigValue(issues, path, field, "non_empty_string_required");
|
|
127
|
+
return null;
|
|
128
|
+
};
|
|
129
|
+
const configOptionalStringField = (issues, path, field, value) => {
|
|
130
|
+
if (value === undefined)
|
|
131
|
+
return undefined;
|
|
132
|
+
return configStringField(issues, path, field, value) ?? undefined;
|
|
133
|
+
};
|
|
134
|
+
const configRequiredRecord = (issues, path, field, value) => {
|
|
135
|
+
if (isRecord(value))
|
|
136
|
+
return value;
|
|
137
|
+
issueInvalidConfigValue(issues, path, field, "object_required");
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
const decodeDeploymentConfig = (issues, value) => {
|
|
141
|
+
const record = configRequiredRecord(issues, "agentos.config.jsonc", "/deployment", value);
|
|
142
|
+
if (record === null)
|
|
143
|
+
return null;
|
|
144
|
+
assertConfigAllowedFields(issues, "/deployment", record, deploymentAllowedFields);
|
|
145
|
+
const id = configStringField(issues, "/deployment", "/deployment/id", record.id);
|
|
146
|
+
const version = configOptionalStringField(issues, "/deployment", "/deployment/version", record.version);
|
|
147
|
+
return id === null ? null : { id, ...(version === undefined ? {} : { version }) };
|
|
148
|
+
};
|
|
149
|
+
const decodeTargetConfig = (issues, value) => {
|
|
150
|
+
const record = configRequiredRecord(issues, "agentos.config.jsonc", "/target", value);
|
|
151
|
+
if (record === null)
|
|
152
|
+
return null;
|
|
153
|
+
assertConfigAllowedFields(issues, "/target", record, targetAllowedFields);
|
|
154
|
+
if (record.kind !== AGENTOS_CONFIG_TARGET.CLOUDFLARE_DO_V1) {
|
|
155
|
+
issueInvalidConfigValue(issues, "/target", "/target/kind", "target_kind_invalid");
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const durableObject = configRequiredRecord(issues, "/target", "/target/durableObject", record.durableObject);
|
|
159
|
+
if (durableObject === null)
|
|
160
|
+
return null;
|
|
161
|
+
assertConfigAllowedFields(issues, "/target/durableObject", durableObject, durableObjectAllowedFields);
|
|
162
|
+
const className = configStringField(issues, "/target/durableObject", "/target/durableObject/className", durableObject.className);
|
|
163
|
+
const binding = configStringField(issues, "/target/durableObject", "/target/durableObject/binding", durableObject.binding);
|
|
164
|
+
return className === null || binding === null
|
|
165
|
+
? null
|
|
166
|
+
: {
|
|
167
|
+
kind: AGENTOS_CONFIG_TARGET.CLOUDFLARE_DO_V1,
|
|
168
|
+
durableObject: { className, binding },
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
const decodeClientConfig = (issues, value) => {
|
|
172
|
+
const record = configRequiredRecord(issues, "agentos.config.jsonc", "/client", value);
|
|
173
|
+
if (record === null)
|
|
174
|
+
return null;
|
|
175
|
+
assertConfigAllowedFields(issues, "/client", record, clientAllowedFields);
|
|
176
|
+
if (record.kind !== AGENTOS_CONFIG_CLIENT.SVELTE_KIT_REMOTE_V1 &&
|
|
177
|
+
record.kind !== AGENTOS_CONFIG_CLIENT.BROWSER_DIRECT_V1) {
|
|
178
|
+
issueInvalidConfigValue(issues, "/client", "/client/kind", "client_kind_invalid");
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return { kind: record.kind };
|
|
182
|
+
};
|
|
183
|
+
const decodeLlmConfig = (issues, value) => {
|
|
184
|
+
const record = configRequiredRecord(issues, "agentos.config.jsonc", "/llm", value);
|
|
185
|
+
if (record === null)
|
|
186
|
+
return null;
|
|
187
|
+
assertConfigAllowedFields(issues, "/llm", record, llmAllowedFields);
|
|
188
|
+
if (record.route !== AGENTOS_CONFIG_LLM_ROUTE.OPENAI_CHAT_COMPATIBLE) {
|
|
189
|
+
issueInvalidConfigValue(issues, "/llm", "/llm/route", "llm_route_invalid");
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
const endpointRef = configStringField(issues, "/llm", "/llm/endpointRef", record.endpointRef);
|
|
193
|
+
const credentialRef = configStringField(issues, "/llm", "/llm/credentialRef", record.credentialRef);
|
|
194
|
+
const modelRef = configStringField(issues, "/llm", "/llm/modelRef", record.modelRef);
|
|
195
|
+
return endpointRef === null || credentialRef === null || modelRef === null
|
|
196
|
+
? null
|
|
197
|
+
: {
|
|
198
|
+
route: AGENTOS_CONFIG_LLM_ROUTE.OPENAI_CHAT_COMPATIBLE,
|
|
199
|
+
endpointRef,
|
|
200
|
+
credentialRef,
|
|
201
|
+
modelRef,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
const decodeWorkspaceTopologyConfig = (issues, value) => {
|
|
205
|
+
const record = configRequiredRecord(issues, "/workspace", "/workspace/topology", value);
|
|
206
|
+
if (record === null)
|
|
207
|
+
return null;
|
|
208
|
+
assertConfigAllowedFields(issues, "/workspace/topology", record, topologyAllowedFields);
|
|
209
|
+
if (record.kind !== WORKSPACE_TOPOLOGY.PER_SCOPE) {
|
|
210
|
+
issueInvalidConfigValue(issues, "/workspace/topology", "/workspace/topology/kind", "workspace_topology_kind_invalid");
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const allocator = configStringField(issues, "/workspace/topology", "/workspace/topology/allocator", record.allocator);
|
|
214
|
+
return allocator === null ? null : { kind: WORKSPACE_TOPOLOGY.PER_SCOPE, allocator };
|
|
215
|
+
};
|
|
216
|
+
const decodeWorkspaceConfig = (issues, value) => {
|
|
217
|
+
const record = configRequiredRecord(issues, "agentos.config.jsonc", "/workspace", value);
|
|
218
|
+
if (record === null)
|
|
219
|
+
return null;
|
|
220
|
+
assertConfigAllowedFields(issues, "/workspace", record, workspaceAllowedFields);
|
|
221
|
+
const binding = configStringField(issues, "/workspace", "/workspace/binding", record.binding);
|
|
222
|
+
const root = configStringField(issues, "/workspace", "/workspace/root", record.root);
|
|
223
|
+
const topology = record.topology === undefined
|
|
224
|
+
? undefined
|
|
225
|
+
: decodeWorkspaceTopologyConfig(issues, record.topology);
|
|
226
|
+
return binding === null || root === null || topology === null
|
|
227
|
+
? null
|
|
228
|
+
: { binding, root, ...(topology === undefined ? {} : { topology }) };
|
|
229
|
+
};
|
|
230
|
+
export const decodeAgentOsConfig = (value) => {
|
|
231
|
+
const issues = [];
|
|
232
|
+
if (!isRecord(value))
|
|
233
|
+
return { ok: false, issues: [{ kind: "config_not_object", path: "agentos.config.jsonc" }] };
|
|
234
|
+
assertConfigAllowedFields(issues, "agentos.config.jsonc", value, configAllowedFields);
|
|
235
|
+
assertNoConfigRuntimeFacts(issues, "agentos.config.jsonc", value);
|
|
236
|
+
const schema = configOptionalStringField(issues, "agentos.config.jsonc", "/$schema", value.$schema);
|
|
237
|
+
if (value.profile !== AGENTOS_CONFIG_PROFILE.WORKSPACE_V1 &&
|
|
238
|
+
value.profile !== AGENTOS_CONFIG_PROFILE.CHAT_V1) {
|
|
239
|
+
issueInvalidConfigValue(issues, "agentos.config.jsonc", "/profile", "profile_invalid");
|
|
240
|
+
}
|
|
241
|
+
const agent = configStringField(issues, "agentos.config.jsonc", "/agent", value.agent);
|
|
242
|
+
const deployment = decodeDeploymentConfig(issues, value.deployment);
|
|
243
|
+
const target = decodeTargetConfig(issues, value.target);
|
|
244
|
+
const client = decodeClientConfig(issues, value.client);
|
|
245
|
+
const llm = decodeLlmConfig(issues, value.llm);
|
|
246
|
+
const workspace = value.profile === AGENTOS_CONFIG_PROFILE.WORKSPACE_V1
|
|
247
|
+
? decodeWorkspaceConfig(issues, value.workspace)
|
|
248
|
+
: null;
|
|
249
|
+
if (value.profile === AGENTOS_CONFIG_PROFILE.CHAT_V1 &&
|
|
250
|
+
Object.prototype.hasOwnProperty.call(value, "workspace")) {
|
|
251
|
+
issueInvalidConfigValue(issues, "agentos.config.jsonc", "/workspace", "workspace_forbidden_for_chat_profile");
|
|
252
|
+
}
|
|
253
|
+
if (issues.length > 0 ||
|
|
254
|
+
agent === null ||
|
|
255
|
+
deployment === null ||
|
|
256
|
+
target === null ||
|
|
257
|
+
client === null ||
|
|
258
|
+
llm === null ||
|
|
259
|
+
(value.profile === AGENTOS_CONFIG_PROFILE.WORKSPACE_V1 && workspace === null)) {
|
|
260
|
+
return { ok: false, issues };
|
|
261
|
+
}
|
|
262
|
+
const base = {
|
|
263
|
+
...(schema === undefined ? {} : { $schema: schema }),
|
|
264
|
+
agent,
|
|
265
|
+
deployment,
|
|
266
|
+
target,
|
|
267
|
+
client,
|
|
268
|
+
llm,
|
|
269
|
+
};
|
|
270
|
+
if (value.profile === AGENTOS_CONFIG_PROFILE.CHAT_V1) {
|
|
271
|
+
return {
|
|
272
|
+
ok: true,
|
|
273
|
+
value: {
|
|
274
|
+
...base,
|
|
275
|
+
profile: AGENTOS_CONFIG_PROFILE.CHAT_V1,
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
ok: true,
|
|
281
|
+
value: {
|
|
282
|
+
...base,
|
|
283
|
+
profile: AGENTOS_CONFIG_PROFILE.WORKSPACE_V1,
|
|
284
|
+
workspace: workspace,
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
const defaultWorkspaceTopology = () => ({
|
|
289
|
+
kind: WORKSPACE_TOPOLOGY.PER_SCOPE,
|
|
290
|
+
allocator: "workspace-per-scope-v1",
|
|
291
|
+
});
|
|
292
|
+
const workspaceMaterialRef = (providerResourceId) => ({
|
|
293
|
+
kind: "external_resource",
|
|
294
|
+
provider: "agent-os",
|
|
295
|
+
resourceKind: "workspace-env",
|
|
296
|
+
ref: providerResourceId,
|
|
297
|
+
});
|
|
298
|
+
const workspaceDefaultToolFactKey = (toolId, field) => `/tools/${toolId}/${field}`;
|
|
299
|
+
const workspaceExecutionDomainFactKey = "/executionDomains/workspace/bindingRef";
|
|
300
|
+
const workspaceMaterialFactKey = "/materials/workspace";
|
|
301
|
+
const defaultWorkspaceToolEntry = (tool, control) => ({
|
|
302
|
+
bindingRef: tool.name,
|
|
303
|
+
executionDomain: tool.executionDomain,
|
|
304
|
+
interaction: control?.kind === "override" && control.interaction !== undefined
|
|
305
|
+
? control.interaction.value
|
|
306
|
+
: tool.interaction,
|
|
307
|
+
materialRefs: tool.materialRefs,
|
|
308
|
+
effects: tool.effects,
|
|
309
|
+
receiptPolicy: tool.receiptPolicy,
|
|
310
|
+
});
|
|
311
|
+
const addDefaultWorkspaceToolProvenance = (provenance, tool, control) => {
|
|
312
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "bindingRef")] = workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "bindingRef"));
|
|
313
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "executionDomain")] =
|
|
314
|
+
workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "executionDomain"));
|
|
315
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "interaction")] =
|
|
316
|
+
control?.kind === "override" && control.interaction !== undefined
|
|
317
|
+
? control.interaction.origin
|
|
318
|
+
: workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "interaction"));
|
|
319
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "materialRefs")] = workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "materialRefs"));
|
|
320
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "effects")] = workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "effects"));
|
|
321
|
+
provenance[workspaceDefaultToolFactKey(tool.name, "receiptPolicy")] =
|
|
322
|
+
workspaceManifestMacroOrigin(workspaceDefaultToolFactKey(tool.name, "receiptPolicy"));
|
|
323
|
+
};
|
|
324
|
+
const applyWorkspaceDefaultTools = (compiled) => {
|
|
325
|
+
const issues = [];
|
|
326
|
+
const tools = { ...compiled.manifest.tools };
|
|
327
|
+
const executionDomains = {
|
|
328
|
+
...compiled.manifest.executionDomains,
|
|
329
|
+
};
|
|
330
|
+
const provenance = {
|
|
331
|
+
...compiled.provenance,
|
|
332
|
+
};
|
|
333
|
+
const exclusions = {};
|
|
334
|
+
if (executionDomains.workspace === undefined) {
|
|
335
|
+
executionDomains.workspace = { bindingRef: "workspace" };
|
|
336
|
+
provenance[workspaceExecutionDomainFactKey] = workspaceManifestMacroOrigin(workspaceExecutionDomainFactKey);
|
|
337
|
+
}
|
|
338
|
+
for (const defaultTool of WORKSPACE_TOOL_DEFAULT_DECLARATIONS) {
|
|
339
|
+
const control = compiled.workspaceToolControls[defaultTool.name];
|
|
340
|
+
const existing = compiled.manifest.tools?.[defaultTool.name];
|
|
341
|
+
if (control?.kind === "disabled") {
|
|
342
|
+
exclusions[`/tools/${defaultTool.name}`] = control.origin;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (existing !== undefined) {
|
|
346
|
+
issues.push({
|
|
347
|
+
kind: "workspace_default_tool_shadowed",
|
|
348
|
+
path: compiled.toolFilePaths[defaultTool.name] ?? `agent/tools/${defaultTool.name}.ts`,
|
|
349
|
+
toolId: defaultTool.name,
|
|
350
|
+
});
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
tools[defaultTool.name] = defaultWorkspaceToolEntry(defaultTool, control);
|
|
354
|
+
addDefaultWorkspaceToolProvenance(provenance, defaultTool, control);
|
|
355
|
+
}
|
|
356
|
+
const manifestWithoutTools = { ...compiled.manifest };
|
|
357
|
+
delete manifestWithoutTools.tools;
|
|
358
|
+
delete manifestWithoutTools.executionDomains;
|
|
359
|
+
const sortedTools = Object.fromEntries(Object.entries(tools).sort(([left], [right]) => left.localeCompare(right)));
|
|
360
|
+
const sortedExecutionDomains = Object.fromEntries(Object.entries(executionDomains).sort(([left], [right]) => left.localeCompare(right)));
|
|
361
|
+
return {
|
|
362
|
+
manifest: authoredValue({
|
|
363
|
+
...manifestWithoutTools,
|
|
364
|
+
...(Object.keys(sortedTools).length === 0 ? {} : { tools: sortedTools }),
|
|
365
|
+
...(Object.keys(sortedExecutionDomains).length === 0
|
|
366
|
+
? {}
|
|
367
|
+
: { executionDomains: sortedExecutionDomains }),
|
|
368
|
+
}),
|
|
369
|
+
provenance,
|
|
370
|
+
exclusions,
|
|
371
|
+
issues,
|
|
372
|
+
};
|
|
373
|
+
};
|
|
374
|
+
const addWorkspaceMaterial = (manifest, provenance, providerResourceId) => {
|
|
375
|
+
if (manifest.materials?.workspace !== undefined) {
|
|
376
|
+
return { manifest, provenance };
|
|
377
|
+
}
|
|
378
|
+
const materials = {
|
|
379
|
+
...manifest.materials,
|
|
380
|
+
workspace: workspaceMaterialRef(providerResourceId),
|
|
381
|
+
};
|
|
382
|
+
const sortedMaterials = Object.fromEntries(Object.entries(materials).sort(([left], [right]) => left.localeCompare(right)));
|
|
383
|
+
return {
|
|
384
|
+
manifest: authoredValue({
|
|
385
|
+
...manifest,
|
|
386
|
+
materials: sortedMaterials,
|
|
387
|
+
}),
|
|
388
|
+
provenance: {
|
|
389
|
+
...provenance,
|
|
390
|
+
[workspaceMaterialFactKey]: workspaceManifestMacroOrigin(workspaceMaterialFactKey),
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
const validateManifestToolReferences = (manifest) => {
|
|
395
|
+
const issues = [];
|
|
396
|
+
for (const [toolId, tool] of Object.entries(manifest.tools ?? {}).sort(([left], [right]) => left.localeCompare(right))) {
|
|
397
|
+
for (const materialRef of tool.materialRefs ?? []) {
|
|
398
|
+
if (manifest.materials?.[materialRef] === undefined) {
|
|
399
|
+
issues.push({ kind: "tool_material_ref_unresolved", toolId, materialRef });
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (tool.executionDomain !== undefined &&
|
|
403
|
+
manifest.executionDomains?.[tool.executionDomain] === undefined) {
|
|
404
|
+
issues.push({
|
|
405
|
+
kind: "tool_execution_domain_ref_unresolved",
|
|
406
|
+
toolId,
|
|
407
|
+
executionDomain: tool.executionDomain,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (tool.interaction !== undefined && manifest.interactions?.[tool.interaction] === undefined) {
|
|
411
|
+
issues.push({
|
|
412
|
+
kind: "tool_interaction_ref_unresolved",
|
|
413
|
+
toolId,
|
|
414
|
+
interaction: tool.interaction,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return issues;
|
|
419
|
+
};
|
|
420
|
+
const cloudflareSandboxIdPrefix = (deploymentNamespace, workspaceBindingRef, scopeRef) => `${deploymentNamespace}-${workspaceBindingRef}-${scopeRef.kind}-${scopeRef.scopeId}`
|
|
421
|
+
.toLowerCase()
|
|
422
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
423
|
+
.replace(/-+/g, "-")
|
|
424
|
+
.replace(/^-|-$/g, "");
|
|
425
|
+
const cloudflareWorkspaceSandboxId = (input) => {
|
|
426
|
+
const digest = digestHex64(input.providerResourceId);
|
|
427
|
+
const suffix = `-${digest}`;
|
|
428
|
+
const rawPrefix = cloudflareSandboxIdPrefix(input.deploymentNamespace, input.workspaceBindingRef, input.scopeRef);
|
|
429
|
+
const prefix = rawPrefix.length === 0 ? "agentos-sandbox" : rawPrefix;
|
|
430
|
+
const prefixBudget = 63 - suffix.length;
|
|
431
|
+
const shortenedPrefix = prefix.slice(0, prefixBudget).replace(/-+$/g, "") || "agentos-sandbox";
|
|
432
|
+
return `${shortenedPrefix}${suffix}`;
|
|
433
|
+
};
|
|
434
|
+
export const normalizeAgentOsConfig = (config, compiled) => {
|
|
435
|
+
const decoded = decodeAgentOsConfig(config);
|
|
436
|
+
if (!decoded.ok)
|
|
437
|
+
return decoded;
|
|
438
|
+
const value = decoded.value;
|
|
439
|
+
const llmEnvIssues = llmMaterialEnvNameCollisionIssues(llmMaterialEnvBindings(value.llm));
|
|
440
|
+
if (llmEnvIssues.length > 0) {
|
|
441
|
+
return { ok: false, issues: llmEnvIssues };
|
|
442
|
+
}
|
|
443
|
+
const profileManifest = value.profile === AGENTOS_CONFIG_PROFILE.WORKSPACE_V1
|
|
444
|
+
? applyWorkspaceDefaultTools(compiled)
|
|
445
|
+
: {
|
|
446
|
+
manifest: compiled.manifest,
|
|
447
|
+
provenance: compiled.provenance,
|
|
448
|
+
exclusions: {},
|
|
449
|
+
issues: [],
|
|
450
|
+
};
|
|
451
|
+
if (profileManifest.issues.length > 0) {
|
|
452
|
+
return { ok: false, issues: profileManifest.issues };
|
|
453
|
+
}
|
|
454
|
+
const scopeRef = manifestScopeRefResult(profileManifest.manifest);
|
|
455
|
+
if (!scopeRef.ok) {
|
|
456
|
+
return {
|
|
457
|
+
ok: false,
|
|
458
|
+
issues: [
|
|
459
|
+
{
|
|
460
|
+
kind: "workspace_scope_not_manifest_owned",
|
|
461
|
+
path: "agent/agent.json#/scope",
|
|
462
|
+
reason: scopeRef.reason,
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
if (value.profile === AGENTOS_CONFIG_PROFILE.CHAT_V1) {
|
|
468
|
+
const referenceIssues = validateManifestToolReferences(profileManifest.manifest);
|
|
469
|
+
if (referenceIssues.length > 0) {
|
|
470
|
+
return { ok: false, issues: referenceIssues };
|
|
471
|
+
}
|
|
472
|
+
const origins = {
|
|
473
|
+
"/profile": configAuthorOrigin("/profile"),
|
|
474
|
+
"/agent": configAuthorOrigin("/agent"),
|
|
475
|
+
"/deployment/id": configAuthorOrigin("/deployment/id"),
|
|
476
|
+
...(value.deployment.version === undefined
|
|
477
|
+
? {}
|
|
478
|
+
: { "/deployment/version": configAuthorOrigin("/deployment/version") }),
|
|
479
|
+
"/target/kind": configAuthorOrigin("/target/kind"),
|
|
480
|
+
"/target/durableObject/className": configAuthorOrigin("/target/durableObject/className"),
|
|
481
|
+
"/target/durableObject/binding": configAuthorOrigin("/target/durableObject/binding"),
|
|
482
|
+
"/client/kind": configAuthorOrigin("/client/kind"),
|
|
483
|
+
"/llm/route": configAuthorOrigin("/llm/route"),
|
|
484
|
+
"/llm/endpointRef": configAuthorOrigin("/llm/endpointRef"),
|
|
485
|
+
"/llm/credentialRef": configAuthorOrigin("/llm/credentialRef"),
|
|
486
|
+
"/llm/modelRef": configAuthorOrigin("/llm/modelRef"),
|
|
487
|
+
"/deployment/backend": `derived:/target/kind`,
|
|
488
|
+
"/deployment/adapter": `derived:/target/kind`,
|
|
489
|
+
"/deployment/codec": chatMacroOrigin("/deployment/codec"),
|
|
490
|
+
"/deployment/providerStrategy": `derived:/llm/route`,
|
|
491
|
+
};
|
|
492
|
+
return {
|
|
493
|
+
ok: true,
|
|
494
|
+
value: {
|
|
495
|
+
profile: AGENTOS_CONFIG_PROFILE.CHAT_V1,
|
|
496
|
+
config: value,
|
|
497
|
+
deployment: {
|
|
498
|
+
deploymentId: value.deployment.id,
|
|
499
|
+
manifest: profileManifest.manifest,
|
|
500
|
+
backend: "cloudflare-do",
|
|
501
|
+
adapter: AGENTOS_CONFIG_TARGET.CLOUDFLARE_DO_V1,
|
|
502
|
+
codec: "agentos-json@1",
|
|
503
|
+
providerStrategy: value.llm.route,
|
|
504
|
+
},
|
|
505
|
+
...(value.deployment.version === undefined
|
|
506
|
+
? {}
|
|
507
|
+
: { deploymentVersion: value.deployment.version }),
|
|
508
|
+
authoredToolNames: Object.keys(compiled.toolFilePaths).sort(),
|
|
509
|
+
target: value.target,
|
|
510
|
+
client: value.client,
|
|
511
|
+
llm: value.llm,
|
|
512
|
+
origins,
|
|
513
|
+
provenance: {
|
|
514
|
+
manifest: profileManifest.provenance,
|
|
515
|
+
deployment: origins,
|
|
516
|
+
exclusions: profileManifest.exclusions,
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
const topology = value.workspace.topology ?? defaultWorkspaceTopology();
|
|
522
|
+
const bindingRef = workspaceBindingRef(value.workspace.binding);
|
|
523
|
+
const providerResourceId = workspaceProviderResourceId({
|
|
524
|
+
deploymentNamespace: value.deployment.id,
|
|
525
|
+
workspaceBindingRef: bindingRef,
|
|
526
|
+
topology,
|
|
527
|
+
scopeRef: scopeRef.value,
|
|
528
|
+
});
|
|
529
|
+
const cloudflareSandboxId = cloudflareWorkspaceSandboxId({
|
|
530
|
+
deploymentNamespace: value.deployment.id,
|
|
531
|
+
workspaceBindingRef: bindingRef,
|
|
532
|
+
scopeRef: scopeRef.value,
|
|
533
|
+
providerResourceId,
|
|
534
|
+
});
|
|
535
|
+
const manifestWithWorkspaceMaterial = addWorkspaceMaterial(profileManifest.manifest, profileManifest.provenance, providerResourceId);
|
|
536
|
+
const referenceIssues = validateManifestToolReferences(manifestWithWorkspaceMaterial.manifest);
|
|
537
|
+
if (referenceIssues.length > 0) {
|
|
538
|
+
return { ok: false, issues: referenceIssues };
|
|
539
|
+
}
|
|
540
|
+
const origins = {
|
|
541
|
+
"/profile": configAuthorOrigin("/profile"),
|
|
542
|
+
"/agent": configAuthorOrigin("/agent"),
|
|
543
|
+
"/deployment/id": configAuthorOrigin("/deployment/id"),
|
|
544
|
+
...(value.deployment.version === undefined
|
|
545
|
+
? {}
|
|
546
|
+
: { "/deployment/version": configAuthorOrigin("/deployment/version") }),
|
|
547
|
+
"/target/kind": configAuthorOrigin("/target/kind"),
|
|
548
|
+
"/target/durableObject/className": configAuthorOrigin("/target/durableObject/className"),
|
|
549
|
+
"/target/durableObject/binding": configAuthorOrigin("/target/durableObject/binding"),
|
|
550
|
+
"/client/kind": configAuthorOrigin("/client/kind"),
|
|
551
|
+
"/llm/route": configAuthorOrigin("/llm/route"),
|
|
552
|
+
"/llm/endpointRef": configAuthorOrigin("/llm/endpointRef"),
|
|
553
|
+
"/llm/credentialRef": configAuthorOrigin("/llm/credentialRef"),
|
|
554
|
+
"/llm/modelRef": configAuthorOrigin("/llm/modelRef"),
|
|
555
|
+
"/workspace/binding": configAuthorOrigin("/workspace/binding"),
|
|
556
|
+
"/workspace/bindingRef": `derived:/workspace/binding`,
|
|
557
|
+
"/workspace/root": configAuthorOrigin("/workspace/root"),
|
|
558
|
+
"/workspace/topology/kind": value.workspace.topology === undefined
|
|
559
|
+
? workspaceMacroOrigin("/workspace/topology/kind")
|
|
560
|
+
: configAuthorOrigin("/workspace/topology/kind"),
|
|
561
|
+
"/workspace/topology/allocator": value.workspace.topology === undefined
|
|
562
|
+
? workspaceMacroOrigin("/workspace/topology/allocator")
|
|
563
|
+
: configAuthorOrigin("/workspace/topology/allocator"),
|
|
564
|
+
"/deployment/backend": `derived:/target/kind`,
|
|
565
|
+
"/deployment/adapter": `derived:/target/kind`,
|
|
566
|
+
"/deployment/codec": workspaceMacroOrigin("/deployment/codec"),
|
|
567
|
+
"/deployment/providerStrategy": `derived:/llm/route`,
|
|
568
|
+
"/workspace/providerResourceId": `derived:/deployment/id+/workspace/binding+/workspace/topology+/agent/scope`,
|
|
569
|
+
"/workspace/cloudflareSandboxId": `derived:/workspace/providerResourceId`,
|
|
570
|
+
};
|
|
571
|
+
return {
|
|
572
|
+
ok: true,
|
|
573
|
+
value: {
|
|
574
|
+
profile: AGENTOS_CONFIG_PROFILE.WORKSPACE_V1,
|
|
575
|
+
config: value,
|
|
576
|
+
deployment: {
|
|
577
|
+
deploymentId: value.deployment.id,
|
|
578
|
+
manifest: manifestWithWorkspaceMaterial.manifest,
|
|
579
|
+
backend: "cloudflare-do",
|
|
580
|
+
adapter: AGENTOS_CONFIG_TARGET.CLOUDFLARE_DO_V1,
|
|
581
|
+
codec: "agentos-json@1",
|
|
582
|
+
providerStrategy: value.llm.route,
|
|
583
|
+
},
|
|
584
|
+
...(value.deployment.version === undefined
|
|
585
|
+
? {}
|
|
586
|
+
: { deploymentVersion: value.deployment.version }),
|
|
587
|
+
authoredToolNames: Object.keys(compiled.toolFilePaths).sort(),
|
|
588
|
+
target: value.target,
|
|
589
|
+
client: value.client,
|
|
590
|
+
llm: value.llm,
|
|
591
|
+
workspace: {
|
|
592
|
+
binding: value.workspace.binding,
|
|
593
|
+
bindingRef,
|
|
594
|
+
root: value.workspace.root,
|
|
595
|
+
topology,
|
|
596
|
+
providerResourceId,
|
|
597
|
+
cloudflareSandboxId,
|
|
598
|
+
},
|
|
599
|
+
origins,
|
|
600
|
+
provenance: {
|
|
601
|
+
manifest: manifestWithWorkspaceMaterial.provenance,
|
|
602
|
+
deployment: origins,
|
|
603
|
+
exclusions: profileManifest.exclusions,
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
};
|
|
607
|
+
};
|