gaoding-cli 1.0.0-alpha.10

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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/contracts/operations/agent.send/input.schema.json +354 -0
  4. package/contracts/operations/agent.send/output.schema.json +271 -0
  5. package/contracts/operations/auth.status/input.schema.json +7 -0
  6. package/contracts/operations/auth.status/output.schema.json +132 -0
  7. package/contracts/operations/dam.delete/input.schema.json +23 -0
  8. package/contracts/operations/dam.delete/output.schema.json +6 -0
  9. package/contracts/operations/dam.get/input.schema.json +16 -0
  10. package/contracts/operations/dam.get/output.schema.json +46 -0
  11. package/contracts/operations/dam.list/input.schema.json +44 -0
  12. package/contracts/operations/dam.list/output.schema.json +71 -0
  13. package/contracts/operations/dam.search/input.schema.json +46 -0
  14. package/contracts/operations/dam.search/output.schema.json +71 -0
  15. package/contracts/operations/dam.upload/input.schema.json +31 -0
  16. package/contracts/operations/dam.upload/output.schema.json +46 -0
  17. package/contracts/operations/editor.apply/input.schema.json +134 -0
  18. package/contracts/operations/editor.apply/output.schema.json +15 -0
  19. package/contracts/operations/editor.connect/input.schema.json +15 -0
  20. package/contracts/operations/editor.connect/output.schema.json +17 -0
  21. package/contracts/operations/editor.disconnect/input.schema.json +8 -0
  22. package/contracts/operations/editor.disconnect/output.schema.json +14 -0
  23. package/contracts/operations/editor.save/input.schema.json +8 -0
  24. package/contracts/operations/editor.save/output.schema.json +23 -0
  25. package/contracts/operations/editor.screenshot/input.schema.json +8 -0
  26. package/contracts/operations/editor.screenshot/output.schema.json +16 -0
  27. package/contracts/operations/editor.snapshot/input.schema.json +8 -0
  28. package/contracts/operations/editor.snapshot/output.schema.json +113 -0
  29. package/contracts/operations/model.get/input.schema.json +18 -0
  30. package/contracts/operations/model.get/output.schema.json +190 -0
  31. package/contracts/operations/model.list/input.schema.json +15 -0
  32. package/contracts/operations/model.list/output.schema.json +111 -0
  33. package/contracts/operations/org.current/input.schema.json +7 -0
  34. package/contracts/operations/org.current/output.schema.json +49 -0
  35. package/contracts/operations/org.list/input.schema.json +7 -0
  36. package/contracts/operations/org.list/output.schema.json +71 -0
  37. package/contracts/operations/tool.call/input.schema.json +35 -0
  38. package/contracts/operations/tool.call/output.schema.json +129 -0
  39. package/contracts/operations/tool.list/input.schema.json +7 -0
  40. package/contracts/operations/tool.list/output.schema.json +45 -0
  41. package/dist/bin/gd-cli.js +38 -0
  42. package/dist/bin/postinstall.js +42 -0
  43. package/dist/src/bootstrap/create-cli.js +55 -0
  44. package/dist/src/bootstrap/create-runtime.js +222 -0
  45. package/dist/src/bootstrap/validators.js +118 -0
  46. package/dist/src/cli/action-binding.js +63 -0
  47. package/dist/src/cli/agent-commands.js +39 -0
  48. package/dist/src/cli/auth-commands.js +47 -0
  49. package/dist/src/cli/dam-commands.js +207 -0
  50. package/dist/src/cli/editor-commands.js +73 -0
  51. package/dist/src/cli/errors.js +90 -0
  52. package/dist/src/cli/model-commands.js +47 -0
  53. package/dist/src/cli/org-commands.js +52 -0
  54. package/dist/src/cli/presenter.js +80 -0
  55. package/dist/src/cli/prompt.js +30 -0
  56. package/dist/src/cli/tool-commands.js +65 -0
  57. package/dist/src/cli/update-command.js +12 -0
  58. package/dist/src/contracts/schema.js +4 -0
  59. package/dist/src/features/agent/creative-agent-adapter.js +31 -0
  60. package/dist/src/features/agent/creative-protocol.js +324 -0
  61. package/dist/src/features/agent/creative-stream.js +127 -0
  62. package/dist/src/features/agent/use-cases.js +113 -0
  63. package/dist/src/features/auth/access-policy.js +101 -0
  64. package/dist/src/features/auth/credential-store.js +62 -0
  65. package/dist/src/features/auth/sso-service.js +179 -0
  66. package/dist/src/features/auth/state.js +129 -0
  67. package/dist/src/features/auth/use-cases.js +106 -0
  68. package/dist/src/features/dam/asset-projection.js +270 -0
  69. package/dist/src/features/dam/dam-api-adapter.js +206 -0
  70. package/dist/src/features/dam/object-storage.js +191 -0
  71. package/dist/src/features/dam/registered-uploader.js +224 -0
  72. package/dist/src/features/dam/storage-upload.js +141 -0
  73. package/dist/src/features/dam/transient-uploader.js +17 -0
  74. package/dist/src/features/dam/use-cases.js +151 -0
  75. package/dist/src/features/editor/bridge-client.js +96 -0
  76. package/dist/src/features/editor/bridge-process.js +222 -0
  77. package/dist/src/features/editor/bridge-server.js +311 -0
  78. package/dist/src/features/editor/protocol.js +1 -0
  79. package/dist/src/features/editor/session-state.js +78 -0
  80. package/dist/src/features/editor/session.js +193 -0
  81. package/dist/src/features/editor/use-cases.js +61 -0
  82. package/dist/src/features/org/org-service.js +76 -0
  83. package/dist/src/features/org/use-cases.js +140 -0
  84. package/dist/src/features/skill/bundled-skills.js +55 -0
  85. package/dist/src/features/skill/installer.js +265 -0
  86. package/dist/src/features/tool/catalog.js +79 -0
  87. package/dist/src/features/tool/dynamic-schema.js +96 -0
  88. package/dist/src/features/tool/mns-catalog-adapter.js +262 -0
  89. package/dist/src/features/tool/tool-api-adapter.js +200 -0
  90. package/dist/src/features/tool/use-cases.js +126 -0
  91. package/dist/src/features/update/update-service.js +194 -0
  92. package/dist/src/platform/json-input.js +64 -0
  93. package/dist/src/platform/local-json-file.js +59 -0
  94. package/dist/src/platform/open-browser.js +8 -0
  95. package/dist/src/platform/redact.js +80 -0
  96. package/dist/src/platform/safe-upload-file.js +146 -0
  97. package/dist/src/platform/signature.js +19 -0
  98. package/dist/src/platform/signed-http-transport.js +109 -0
  99. package/dist/src/platform/url-safety.js +100 -0
  100. package/package.json +56 -0
  101. package/skills/gd-cli/SKILL.md +15 -0
  102. package/skills/gd-cli/references/auth-org.md +9 -0
  103. package/skills/gd-cli/references/creation.md +38 -0
  104. package/skills/gd-cli/references/dam.md +20 -0
  105. package/skills/gd-cli/references/editor.md +12 -0
  106. package/skills/gd-cli/references/errors.md +10 -0
  107. package/skills/gd-cli/references/update.md +11 -0
@@ -0,0 +1,265 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { cp, lstat, mkdir, mkdtemp, readFile, readlink, rename, rm, symlink, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
+ export class SkillSyncError extends Error {
6
+ results;
7
+ constructor(message, results) {
8
+ super(message);
9
+ this.results = results;
10
+ this.name = "SkillSyncError";
11
+ }
12
+ }
13
+ export async function syncBundledSkills(skills, options = {}) {
14
+ const homeDirectory = options.homeDirectory ?? homedir();
15
+ const platform = options.platform ?? process.platform;
16
+ const results = [];
17
+ for (const skill of skills) {
18
+ assertDescriptor(skill, results);
19
+ const targets = await skillTargets(skill.skill, homeDirectory, options.env ?? {});
20
+ const targetResults = [];
21
+ try {
22
+ const canonical = targets[0];
23
+ let current = await inspectTarget(canonical, skill, canonical.path, platform);
24
+ if (current.status === "conflict" || current.status === "broken") {
25
+ targetResults.push(current);
26
+ throw new Error(current.reason ?? "canonical Skill conflict");
27
+ }
28
+ if (current.status === "missing" || current.status === "outdated") {
29
+ await replaceManagedDirectory(skill, canonical.path, current.status === "outdated");
30
+ current = installed(canonical, "canonical", true);
31
+ }
32
+ targetResults.push(current);
33
+ for (const target of targets.slice(1)) {
34
+ current = await inspectTarget(target, skill, canonical.path, platform);
35
+ if (current.status === "conflict" || current.status === "broken") {
36
+ targetResults.push(current);
37
+ throw new Error(current.reason ?? "Agent host Skill conflict");
38
+ }
39
+ if (current.status === "missing") {
40
+ current = await createLinkOrCopy(skill, target, canonical.path, {
41
+ platform,
42
+ createLink: options.createLink ?? symlink
43
+ });
44
+ }
45
+ else if (current.status === "outdated") {
46
+ await replaceManagedDirectory(skill, target.path, true);
47
+ current = installed(target, "copy", true);
48
+ }
49
+ targetResults.push(current);
50
+ }
51
+ results.push(syncResult(skill, targetResults));
52
+ }
53
+ catch (error) {
54
+ const active = targets[targetResults.length];
55
+ if (active && !targetResults.some((target) => target.host === active.host)) {
56
+ targetResults.push({
57
+ host: active.host,
58
+ path: active.path,
59
+ status: "conflict",
60
+ changed: false,
61
+ reason: message(error)
62
+ });
63
+ }
64
+ results.push(syncResult(skill, targetResults));
65
+ throw new SkillSyncError(`Agent Skill ${skill.skill} 同步失败${active ? ` (${active.path})` : ""}: ${message(error)}`, results);
66
+ }
67
+ }
68
+ return results;
69
+ }
70
+ export async function verifyBundledSkills(skills, options = {}) {
71
+ const homeDirectory = options.homeDirectory ?? homedir();
72
+ const platform = options.platform ?? process.platform;
73
+ const results = [];
74
+ for (const skill of skills) {
75
+ assertDescriptor(skill, results);
76
+ const targets = await skillTargets(skill.skill, homeDirectory, options.env ?? {});
77
+ const canonical = targets[0];
78
+ const inspected = await Promise.all(targets.map((target) => inspectTarget(target, skill, canonical.path, platform)));
79
+ results.push(syncResult(skill, inspected));
80
+ }
81
+ const invalid = results.flatMap((result) => result.targets)
82
+ .find((target) => target.status !== "installed");
83
+ if (invalid) {
84
+ throw new SkillSyncError(`Agent Skill 验收失败 (${invalid.path}): ${invalid.reason ?? invalid.status}`, results);
85
+ }
86
+ return results;
87
+ }
88
+ async function skillTargets(skill, homeDirectory, env) {
89
+ const roots = [
90
+ { host: "claude-code", root: env.CLAUDE_HOME ?? join(homeDirectory, ".claude") },
91
+ { host: "codex", root: env.CODEX_HOME ?? join(homeDirectory, ".codex") },
92
+ { host: "cursor", root: env.CURSOR_HOME ?? join(homeDirectory, ".cursor") },
93
+ { host: "opencode", root: env.OPENCODE_HOME ?? join(homeDirectory, ".config", "opencode") },
94
+ { host: "openclaw", root: env.OPENCLAW_HOME ?? join(homeDirectory, ".openclaw") },
95
+ { host: "workbuddy", root: join(homeDirectory, ".workbuddy") }
96
+ ];
97
+ const detected = await Promise.all(roots.map(async (target) => ({
98
+ ...target,
99
+ detected: Boolean(await lstatMaybe(target.root))
100
+ })));
101
+ return [
102
+ { host: "canonical", path: join(homeDirectory, ".agents", "skills", skill) },
103
+ ...detected
104
+ .filter((target) => target.detected)
105
+ .map((target) => ({ host: target.host, path: join(target.root, "skills", skill) }))
106
+ ];
107
+ }
108
+ async function inspectTarget(target, skill, canonical, platform) {
109
+ const stat = await lstatMaybe(target.path);
110
+ if (!stat)
111
+ return targetResult(target, "missing");
112
+ if (target.host === "canonical") {
113
+ if (stat.isSymbolicLink()) {
114
+ return targetResult(target, "conflict", undefined, "canonical 不能是链接");
115
+ }
116
+ if (!stat.isDirectory()) {
117
+ return targetResult(target, "conflict", undefined, "canonical 路径不是目录");
118
+ }
119
+ const marker = await readMarker(target.path);
120
+ if (!marker || marker.skill !== skill.skill) {
121
+ return targetResult(target, "conflict", undefined, "canonical 缺少合法 marker");
122
+ }
123
+ return targetResult(target, marker.version === skill.version ? "installed" : "outdated", "canonical");
124
+ }
125
+ if (stat.isSymbolicLink()) {
126
+ let resolved;
127
+ try {
128
+ resolved = resolve(dirname(target.path), await readlink(target.path));
129
+ }
130
+ catch (error) {
131
+ return targetResult(target, "conflict", linkMode(platform), message(error));
132
+ }
133
+ if (!samePath(resolved, canonical, platform)) {
134
+ return targetResult(target, "conflict", linkMode(platform), "链接未指向 canonical Skill");
135
+ }
136
+ if (!await lstatMaybe(canonical)) {
137
+ return targetResult(target, "broken", linkMode(platform), "canonical Skill 不存在");
138
+ }
139
+ return targetResult(target, "installed", linkMode(platform));
140
+ }
141
+ if (!stat.isDirectory()) {
142
+ return targetResult(target, "conflict", undefined, "宿主路径不是目录或链接");
143
+ }
144
+ const marker = await readMarker(target.path);
145
+ if (!marker || marker.skill !== skill.skill) {
146
+ return targetResult(target, "conflict", undefined, "宿主目录缺少合法 marker");
147
+ }
148
+ return targetResult(target, marker.version === skill.version ? "installed" : "outdated", "copy");
149
+ }
150
+ async function createLinkOrCopy(skill, target, canonical, options) {
151
+ await mkdir(dirname(target.path), { recursive: true });
152
+ try {
153
+ if (options.platform === "win32") {
154
+ await options.createLink(canonical, target.path, "junction");
155
+ return installed(target, "junction", true);
156
+ }
157
+ await options.createLink(relative(dirname(target.path), canonical), target.path);
158
+ return installed(target, "symlink", true);
159
+ }
160
+ catch (error) {
161
+ if (await lstatMaybe(target.path))
162
+ throw error;
163
+ await replaceManagedDirectory(skill, target.path, false);
164
+ return installed(target, "copy", true);
165
+ }
166
+ }
167
+ async function replaceManagedDirectory(skill, destination, replace) {
168
+ const parent = dirname(destination);
169
+ await mkdir(parent, { recursive: true });
170
+ const stagingRoot = await mkdtemp(join(parent, ".gd-cli-stage-"));
171
+ const staged = join(stagingRoot, skill.skill);
172
+ let backup;
173
+ try {
174
+ await cp(skill.sourceDirectory, staged, { recursive: true });
175
+ await writeFile(join(staged, ".gd-cli.json"), `${JSON.stringify({ skill: skill.skill, version: skill.version })}\n`);
176
+ if (replace) {
177
+ backup = join(parent, `.gd-cli-backup-${randomUUID()}`);
178
+ await rename(destination, backup);
179
+ }
180
+ try {
181
+ await rename(staged, destination);
182
+ }
183
+ catch (error) {
184
+ if (backup)
185
+ await rename(backup, destination);
186
+ throw error;
187
+ }
188
+ if (backup)
189
+ await rm(backup, { recursive: true, force: false });
190
+ }
191
+ finally {
192
+ await rm(stagingRoot, { recursive: true, force: true });
193
+ }
194
+ }
195
+ async function readMarker(directory) {
196
+ try {
197
+ const parsed = JSON.parse(await readFile(join(directory, ".gd-cli.json"), "utf8"));
198
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
199
+ return undefined;
200
+ const marker = parsed;
201
+ if (Object.keys(marker).sort().join(",") !== "skill,version")
202
+ return undefined;
203
+ if (typeof marker.skill !== "string" || !marker.skill.trim())
204
+ return undefined;
205
+ if (typeof marker.version !== "string" || !marker.version.trim())
206
+ return undefined;
207
+ return { skill: marker.skill, version: marker.version };
208
+ }
209
+ catch (error) {
210
+ const code = error.code;
211
+ if (code === "ENOENT" || error instanceof SyntaxError)
212
+ return undefined;
213
+ throw error;
214
+ }
215
+ }
216
+ async function lstatMaybe(path) {
217
+ try {
218
+ return await lstat(path);
219
+ }
220
+ catch (error) {
221
+ const code = error.code;
222
+ if (code === "ENOENT" || code === "ENOTDIR")
223
+ return undefined;
224
+ throw error;
225
+ }
226
+ }
227
+ function assertDescriptor(skill, results) {
228
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(skill.skill) || !skill.version.trim()) {
229
+ throw new SkillSyncError(`Agent Skill descriptor 无效: ${skill.skill}`, results);
230
+ }
231
+ }
232
+ function installed(target, mode, changed) {
233
+ return { host: target.host, path: target.path, status: "installed", mode, changed };
234
+ }
235
+ function targetResult(target, status, mode, reason) {
236
+ return {
237
+ host: target.host,
238
+ path: target.path,
239
+ status,
240
+ ...(mode ? { mode } : {}),
241
+ changed: false,
242
+ ...(reason ? { reason } : {})
243
+ };
244
+ }
245
+ function syncResult(skill, targets) {
246
+ return {
247
+ skill: skill.skill,
248
+ version: skill.version,
249
+ changed: targets.some((target) => target.changed),
250
+ targets
251
+ };
252
+ }
253
+ function linkMode(platform) {
254
+ return platform === "win32" ? "junction" : "symlink";
255
+ }
256
+ function samePath(left, right, platform) {
257
+ const normalizedLeft = resolve(left);
258
+ const normalizedRight = resolve(right);
259
+ return platform === "win32"
260
+ ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase()
261
+ : normalizedLeft === normalizedRight;
262
+ }
263
+ function message(error) {
264
+ return error instanceof Error ? error.message : String(error);
265
+ }
@@ -0,0 +1,79 @@
1
+ export class ToolInputError extends Error {
2
+ constructor() {
3
+ super("Tool 输入不可用。");
4
+ this.name = "ToolInputError";
5
+ }
6
+ }
7
+ const tools = [
8
+ {
9
+ name: "image.generate",
10
+ title: "图片生成与编辑",
11
+ description: "使用已发布的图片模型,根据文本和可选参考图片生成或编辑图片。"
12
+ },
13
+ {
14
+ name: "video.generate",
15
+ title: "视频生成",
16
+ description: "使用已发布的视频模型,根据文本及可选图片、视频或音频生成视频。"
17
+ },
18
+ {
19
+ name: "text.generate",
20
+ title: "文本生成",
21
+ description: "使用已发布的文本模型,根据文本和可选图片生成文本。"
22
+ }
23
+ ];
24
+ function toolIndex(tool) {
25
+ return tools.findIndex((candidate) => candidate.name === tool);
26
+ }
27
+ function compareModels(left, right) {
28
+ return toolIndex(left.tool) - toolIndex(right.tool)
29
+ || left.sceneSort - right.sceneSort
30
+ || left.modelSort - right.modelSort
31
+ || (left.model < right.model ? -1 : left.model > right.model ? 1 : 0);
32
+ }
33
+ function summary(model) {
34
+ return {
35
+ tool: model.tool,
36
+ model: model.model,
37
+ title: model.title,
38
+ ...(model.description === undefined ? {} : { description: model.description }),
39
+ ...(model.cost === undefined ? {} : { cost: model.cost }),
40
+ ...(model.estimatedTime === undefined ? {} : { estimatedTime: model.estimatedTime })
41
+ };
42
+ }
43
+ export function projectToolList(catalog) {
44
+ return {
45
+ tools: tools.filter((tool) => catalog.models.some((model) => model.tool === tool.name))
46
+ };
47
+ }
48
+ export function projectModelList(catalog, tool) {
49
+ if (tool !== undefined && !catalog.models.some((model) => model.tool === tool)) {
50
+ throw new ToolInputError();
51
+ }
52
+ return {
53
+ models: catalog.models
54
+ .filter((model) => tool === undefined || model.tool === tool)
55
+ .toSorted(compareModels)
56
+ .map(summary)
57
+ };
58
+ }
59
+ export function projectModelDetail(catalog, model) {
60
+ const found = catalog.models.find((candidate) => candidate.model === model);
61
+ if (found === undefined)
62
+ throw new ToolInputError();
63
+ return {
64
+ ...summary(found),
65
+ ...(found.usageDescription === undefined
66
+ ? {}
67
+ : { usageDescription: found.usageDescription }),
68
+ ...(found.outputMediaTypes === undefined
69
+ ? {}
70
+ : { outputMediaTypes: found.outputMediaTypes }),
71
+ parameters: found.parameters
72
+ };
73
+ }
74
+ export function findToolModel(catalog, tool, model) {
75
+ const found = catalog.models.find((candidate) => candidate.tool === tool && candidate.model === model);
76
+ if (found === undefined)
77
+ throw new ToolInputError();
78
+ return found;
79
+ }
@@ -0,0 +1,96 @@
1
+ import { Ajv2020 } from "ajv/dist/2020.js";
2
+ import addFormatsImport, {} from "ajv-formats";
3
+ import { ToolInputError } from "./catalog.js";
4
+ function parameterSchema(parameter) {
5
+ const common = {
6
+ ...(parameter.description === undefined ? {} : { description: parameter.description }),
7
+ ...(parameter.default === undefined ? {} : { default: parameter.default })
8
+ };
9
+ if (parameter.type === "uri")
10
+ return { type: "string", format: "uri", ...common };
11
+ if (parameter.type === "uri[]") {
12
+ return { type: "array", items: { type: "string", format: "uri" }, ...common };
13
+ }
14
+ return {
15
+ type: "string",
16
+ ...(parameter.options === undefined
17
+ ? {}
18
+ : { enum: parameter.options.map((option) => option.value) }),
19
+ ...common
20
+ };
21
+ }
22
+ function sameShape(left, right) {
23
+ return left.type === right.type
24
+ && left.format === right.format
25
+ && left.items?.format === right.items?.format;
26
+ }
27
+ function mergeSchema(current, next) {
28
+ if (!sameShape(current, next)) {
29
+ const variants = current.anyOf ?? [current];
30
+ return variants.some((variant) => sameShape(variant, next))
31
+ ? current
32
+ : { anyOf: [...variants, next] };
33
+ }
34
+ if (current.enum === undefined || next.enum === undefined) {
35
+ if (current.enum === undefined)
36
+ return current;
37
+ const { enum: ignored, ...unrestricted } = current;
38
+ void ignored;
39
+ return unrestricted;
40
+ }
41
+ return {
42
+ ...current,
43
+ enum: [...new Set([...current.enum, ...next.enum])]
44
+ };
45
+ }
46
+ export function buildToolArgumentsSchema(catalog, tool) {
47
+ const models = catalog.models.filter((model) => model.tool === tool);
48
+ if (models.length === 0)
49
+ throw new ToolInputError();
50
+ const properties = {
51
+ model: {
52
+ type: "string",
53
+ description: "要调用的模型机器标识;取值来自 model list。"
54
+ }
55
+ };
56
+ for (const model of models) {
57
+ for (const parameter of model.parameters) {
58
+ const next = parameterSchema(parameter);
59
+ const current = properties[parameter.name];
60
+ properties[parameter.name] = current === undefined ? next : mergeSchema(current, next);
61
+ }
62
+ }
63
+ return {
64
+ type: "object",
65
+ properties,
66
+ required: ["model"],
67
+ additionalProperties: false
68
+ };
69
+ }
70
+ const ajv = new Ajv2020({ allErrors: true, strict: true });
71
+ const addFormats = addFormatsImport;
72
+ addFormats(ajv);
73
+ function validator(model) {
74
+ const properties = {
75
+ model: { type: "string" }
76
+ };
77
+ for (const parameter of model.parameters) {
78
+ properties[parameter.name] = parameterSchema(parameter);
79
+ }
80
+ return ajv.compile({
81
+ type: "object",
82
+ properties,
83
+ required: [
84
+ "model",
85
+ ...model.parameters.filter((parameter) => parameter.required).map((parameter) => parameter.name)
86
+ ],
87
+ additionalProperties: false
88
+ });
89
+ }
90
+ export function assertModelArguments(model, value) {
91
+ if (typeof value !== "object" || value === null
92
+ || value.model !== model.model
93
+ || !validator(model)(value)) {
94
+ throw new ToolInputError();
95
+ }
96
+ }