salmon-loop 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/authorization/non-interactive.js +7 -21
- package/dist/cli/commands/chat.js +1 -1
- package/dist/cli/commands/parallel.js +46 -41
- package/dist/cli/commands/run/assistant-message.js +3 -0
- package/dist/cli/commands/run/handler.js +2 -1
- package/dist/cli/commands/serve.js +123 -154
- package/dist/cli/headless/json-protocol.js +1 -1
- package/dist/cli/headless/stream-json-protocol.js +3 -2
- package/dist/cli/slash/runtime.js +5 -1
- package/dist/cli/ui/components/CommandSuggestionList.js +1 -1
- package/dist/core/adapters/fs/node-fs.js +1 -0
- package/dist/core/benchmark/patch-artifact.js +1 -1
- package/dist/core/context/service.js +36 -10
- package/dist/core/extensions/index.js +2 -35
- package/dist/core/extensions/redact.js +9 -3
- package/dist/core/extensions/schemas.js +2 -51
- package/dist/core/facades/cli-authorization-non-interactive.js +1 -1
- package/dist/core/facades/cli-serve.js +0 -1
- package/dist/core/grizzco/dsl/strategies.js +1 -3
- package/dist/core/grizzco/engine/outcome/loop-result-mapper.js +12 -7
- package/dist/core/grizzco/engine/transaction/attempt-failure.js +23 -23
- package/dist/core/grizzco/engine/transaction/report-mapper.js +3 -0
- package/dist/core/grizzco/engine/transaction/transaction-runner.js +14 -0
- package/dist/core/grizzco/flows/AutopilotFlow.js +1 -0
- package/dist/core/grizzco/flows/SalmonLoopFlow.js +1 -0
- package/dist/core/grizzco/steps/apply.js +0 -7
- package/dist/core/grizzco/steps/autopilot.js +108 -6
- package/dist/core/grizzco/steps/preflight.js +10 -0
- package/dist/core/grizzco/steps/tool-runtime.js +1 -0
- package/dist/core/interaction/events/bus.js +14 -0
- package/dist/core/interaction/orchestration/facade.js +10 -0
- package/dist/core/mcp/bridge/index.js +4 -0
- package/dist/core/mcp/bridge/prompt-command-provider.js +261 -0
- package/dist/core/mcp/bridge/resource-context-provider.js +259 -0
- package/dist/core/mcp/bridge/tool-bridge.js +303 -0
- package/dist/core/mcp/cache/resource-cache.js +41 -0
- package/dist/core/mcp/catalog/discovery.js +51 -0
- package/dist/core/mcp/catalog/notification-router.js +28 -0
- package/dist/core/mcp/catalog/prompt-catalog.js +4 -0
- package/dist/core/mcp/catalog/resource-catalog.js +7 -0
- package/dist/core/mcp/catalog/tool-catalog.js +4 -0
- package/dist/core/mcp/client/connection-manager.js +239 -0
- package/dist/core/mcp/client/lifecycle.js +13 -0
- package/dist/core/mcp/client/transport-factory.js +168 -0
- package/dist/core/mcp/config/index.js +32 -0
- package/dist/core/mcp/config/schema-v2.js +129 -0
- package/dist/core/mcp/host/elicitation-provider.js +209 -0
- package/dist/core/mcp/host/roots-provider.js +70 -0
- package/dist/core/mcp/host/sampling-provider.js +170 -0
- package/dist/core/mcp/index.js +4 -0
- package/dist/core/mcp/observability/events.js +19 -0
- package/dist/core/mcp/policy/approval-policy.js +2 -0
- package/dist/core/mcp/policy/classifier.js +172 -0
- package/dist/core/mcp/policy/grants.js +356 -0
- package/dist/core/mcp/policy/uri-policy.js +60 -0
- package/dist/core/mcp/schema/json-schema-to-zod.js +511 -0
- package/dist/core/mcp/types.js +2 -0
- package/dist/core/protocols/a2a/agent-card.js +36 -11
- package/dist/core/protocols/a2a/sdk/executor.js +105 -36
- package/dist/core/protocols/a2a/sdk/server.js +1311 -3
- package/dist/core/protocols/acp/acp-checkpoint-probe.js +113 -0
- package/dist/core/protocols/acp/acp-session-persistence.js +336 -0
- package/dist/core/protocols/acp/acp-types.js +17 -0
- package/dist/core/protocols/acp/formal-agent.js +271 -603
- package/dist/core/protocols/acp/handlers.js +3 -0
- package/dist/core/protocols/acp/permission-provider.js +11 -39
- package/dist/core/protocols/acp/stdio-server.js +20 -1
- package/dist/core/protocols/acp/tool-kind-mapping.js +62 -0
- package/dist/core/protocols/shared/flow-mode-mapping.js +0 -8
- package/dist/core/public-capabilities/flow-mode-metadata.js +0 -6
- package/dist/core/public-capabilities/projections.js +1 -0
- package/dist/core/runtime/agent-server-runtime.js +2 -3
- package/dist/core/runtime/spawn-command.js +8 -2
- package/dist/core/runtime/spawn-interactive.js +26 -0
- package/dist/core/session/manager.js +65 -35
- package/dist/core/tools/builtin/index.js +6 -1
- package/dist/core/tools/builtin/proposal.js +0 -7
- package/dist/core/tools/builtin/workspace.js +76 -0
- package/dist/core/tools/dispatcher.js +1 -0
- package/dist/core/tools/loader.js +92 -46
- package/dist/core/verification/runner.js +60 -31
- package/dist/core/workspace/capabilities.js +80 -0
- package/dist/locales/en.js +17 -3
- package/package.json +4 -2
- package/dist/core/protocols/a2a/mapper.js +0 -14
- package/dist/core/protocols/a2a/sdk/auth-middleware.js +0 -31
- package/dist/core/protocols/a2a/task-projection.js +0 -45
- package/dist/core/protocols/acp/checkpoint-meta.js +0 -2
- package/dist/core/tools/mcp/client.js +0 -309
- package/dist/core/tools/mcp/loader.js +0 -110
- package/dist/core/tools/mcp/schema.js +0 -54
- package/dist/core/tools/mcp/streamable-http.js +0 -101
- package/dist/core/tools/mcp/types.js +0 -26
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export function jsonSchemaToZod(jsonSchema) {
|
|
4
|
+
return jsonSchemaToZodWithContext(jsonSchema, jsonSchema);
|
|
5
|
+
}
|
|
6
|
+
function jsonSchemaToZodWithContext(jsonSchema, rootSchema) {
|
|
7
|
+
if (jsonSchema === true) {
|
|
8
|
+
return z.any();
|
|
9
|
+
}
|
|
10
|
+
if (jsonSchema === false) {
|
|
11
|
+
return z.never();
|
|
12
|
+
}
|
|
13
|
+
if (!jsonSchema || typeof jsonSchema !== 'object') {
|
|
14
|
+
return z.any();
|
|
15
|
+
}
|
|
16
|
+
const schema = jsonSchema;
|
|
17
|
+
if (typeof schema.$ref === 'string') {
|
|
18
|
+
const { $ref: _ref, ...siblings } = schema;
|
|
19
|
+
return z.lazy(() => {
|
|
20
|
+
const referencedSchema = resolveLocalRef(rootSchema, schema.$ref);
|
|
21
|
+
if (!referencedSchema) {
|
|
22
|
+
return z.never();
|
|
23
|
+
}
|
|
24
|
+
return finalizeSchema(combineWithSiblingKeywords(jsonSchemaToZodWithContext(referencedSchema, rootSchema), siblings, rootSchema), schema, rootSchema);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
28
|
+
const { oneOf, ...siblings } = schema;
|
|
29
|
+
return finalizeSchema(combineWithSiblingKeywords(oneOfToZod(oneOf, rootSchema), siblings, rootSchema), schema, rootSchema);
|
|
30
|
+
}
|
|
31
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
32
|
+
const { anyOf, ...siblings } = schema;
|
|
33
|
+
return finalizeSchema(combineWithSiblingKeywords(unionToZod(anyOf, rootSchema), siblings, rootSchema), schema, rootSchema);
|
|
34
|
+
}
|
|
35
|
+
if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
36
|
+
const { allOf, ...siblings } = schema;
|
|
37
|
+
const hasSiblings = hasValidationKeywords(siblings);
|
|
38
|
+
const schemasToMerge = hasSiblings ? [...allOf, siblings] : allOf;
|
|
39
|
+
const parts = schemasToMerge.map((part) => jsonSchemaToZodWithContext(part, rootSchema));
|
|
40
|
+
return finalizeSchema(parts.reduce((acc, part) => acc.and(part)), schema, rootSchema);
|
|
41
|
+
}
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(schema, 'const')) {
|
|
43
|
+
const { const: _const, ...siblings } = schema;
|
|
44
|
+
return finalizeSchema(combineWithSiblingKeywords(z.literal(schema.const), siblings, rootSchema), schema, rootSchema);
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
47
|
+
const literals = schema.enum.map((value) => z.literal(value));
|
|
48
|
+
const { enum: _enum, ...siblings } = schema;
|
|
49
|
+
return finalizeSchema(combineWithSiblingKeywords(unionLiterals(literals), siblings, rootSchema), schema, rootSchema);
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(schema.type)) {
|
|
52
|
+
const nullable = schema.type.includes('null');
|
|
53
|
+
const nonNullTypes = schema.type.filter((type) => type !== 'null');
|
|
54
|
+
if (nonNullTypes.length === 0 && nullable) {
|
|
55
|
+
return finalizeSchema(z.null(), schema, rootSchema);
|
|
56
|
+
}
|
|
57
|
+
const typed = unionToZod(nonNullTypes.map((type) => ({ ...schema, type })), rootSchema);
|
|
58
|
+
return finalizeSchema(nullable ? typed.nullable() : typed, schema, rootSchema);
|
|
59
|
+
}
|
|
60
|
+
if (!schema.type) {
|
|
61
|
+
const implicitSchema = buildImplicitTypeScopedSchema(schema, rootSchema);
|
|
62
|
+
if (implicitSchema) {
|
|
63
|
+
return implicitSchema;
|
|
64
|
+
}
|
|
65
|
+
return finalizeSchema(z.any(), schema, rootSchema);
|
|
66
|
+
}
|
|
67
|
+
switch (schema.type) {
|
|
68
|
+
case 'string':
|
|
69
|
+
return finalizeSchema(applyStringConstraints(z.string(), schema), schema, rootSchema);
|
|
70
|
+
case 'number':
|
|
71
|
+
return finalizeSchema(applyNumberConstraints(z.number(), schema), schema, rootSchema);
|
|
72
|
+
case 'integer':
|
|
73
|
+
return finalizeSchema(applyNumberConstraints(z.number().int(), schema), schema, rootSchema);
|
|
74
|
+
case 'boolean':
|
|
75
|
+
return finalizeSchema(z.boolean(), schema, rootSchema);
|
|
76
|
+
case 'array':
|
|
77
|
+
return finalizeSchema(applyArrayConstraints(arraySchemaToZod(schema, rootSchema), schema, rootSchema), schema, rootSchema);
|
|
78
|
+
case 'object':
|
|
79
|
+
case undefined:
|
|
80
|
+
return objectSchemaToZod(schema, rootSchema);
|
|
81
|
+
case 'null':
|
|
82
|
+
return finalizeSchema(z.null(), schema, rootSchema);
|
|
83
|
+
default:
|
|
84
|
+
return finalizeSchema(z.any(), schema, rootSchema);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function objectSchemaToZod(schema, rootSchema) {
|
|
88
|
+
const shape = {};
|
|
89
|
+
const properties = schema.properties || {};
|
|
90
|
+
const required = schema.required || [];
|
|
91
|
+
const undeclaredRequired = required.filter((key) => !Object.prototype.hasOwnProperty.call(properties, key));
|
|
92
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
93
|
+
let fieldSchema = jsonSchemaToZodWithContext(prop, rootSchema);
|
|
94
|
+
if (!required.includes(key)) {
|
|
95
|
+
fieldSchema = fieldSchema.optional();
|
|
96
|
+
}
|
|
97
|
+
shape[key] = fieldSchema;
|
|
98
|
+
}
|
|
99
|
+
const objectSchema = z.object(shape).passthrough();
|
|
100
|
+
return finalizeSchema(applyRequiredProperties(applyObjectConstraints(objectSchema, schema, rootSchema), undeclaredRequired), schema, rootSchema);
|
|
101
|
+
}
|
|
102
|
+
function applyStringConstraints(schema, jsonSchema) {
|
|
103
|
+
let constrained = schema;
|
|
104
|
+
if (typeof jsonSchema.minLength === 'number') {
|
|
105
|
+
constrained = constrained.min(jsonSchema.minLength);
|
|
106
|
+
}
|
|
107
|
+
if (typeof jsonSchema.maxLength === 'number') {
|
|
108
|
+
constrained = constrained.max(jsonSchema.maxLength);
|
|
109
|
+
}
|
|
110
|
+
if (typeof jsonSchema.pattern === 'string') {
|
|
111
|
+
constrained = constrained.regex(new RegExp(jsonSchema.pattern));
|
|
112
|
+
}
|
|
113
|
+
return constrained;
|
|
114
|
+
}
|
|
115
|
+
function applyNumberConstraints(schema, jsonSchema) {
|
|
116
|
+
let constrained = schema;
|
|
117
|
+
if (typeof jsonSchema.minimum === 'number') {
|
|
118
|
+
constrained = constrained.min(jsonSchema.minimum);
|
|
119
|
+
}
|
|
120
|
+
if (typeof jsonSchema.maximum === 'number') {
|
|
121
|
+
constrained = constrained.max(jsonSchema.maximum);
|
|
122
|
+
}
|
|
123
|
+
if (typeof jsonSchema.exclusiveMinimum === 'number') {
|
|
124
|
+
constrained = constrained.gt(jsonSchema.exclusiveMinimum);
|
|
125
|
+
}
|
|
126
|
+
if (typeof jsonSchema.exclusiveMaximum === 'number') {
|
|
127
|
+
constrained = constrained.lt(jsonSchema.exclusiveMaximum);
|
|
128
|
+
}
|
|
129
|
+
if (typeof jsonSchema.multipleOf === 'number' && jsonSchema.multipleOf > 0) {
|
|
130
|
+
constrained = constrained.refine((value) => isMultipleOf(value, jsonSchema.multipleOf), `Expected a multiple of ${jsonSchema.multipleOf}`);
|
|
131
|
+
}
|
|
132
|
+
return constrained;
|
|
133
|
+
}
|
|
134
|
+
function arraySchemaToZod(schema, rootSchema) {
|
|
135
|
+
if (Array.isArray(schema.prefixItems) && schema.prefixItems.length > 0) {
|
|
136
|
+
const prefixSchemas = schema.prefixItems.map((itemSchema) => jsonSchemaToZodWithContext(itemSchema, rootSchema));
|
|
137
|
+
const tailSchema = schema.items !== undefined ? jsonSchemaToZodWithContext(schema.items, rootSchema) : undefined;
|
|
138
|
+
return z.array(z.any()).superRefine((items, ctx) => {
|
|
139
|
+
items.forEach((item, index) => {
|
|
140
|
+
if (index < prefixSchemas.length) {
|
|
141
|
+
const result = prefixSchemas[index]?.safeParse(item);
|
|
142
|
+
if (!result?.success) {
|
|
143
|
+
for (const issue of result?.error.issues ?? []) {
|
|
144
|
+
ctx.addIssue({
|
|
145
|
+
...issue,
|
|
146
|
+
path: [index, ...issue.path],
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (!tailSchema)
|
|
153
|
+
return;
|
|
154
|
+
const result = tailSchema.safeParse(item);
|
|
155
|
+
if (!result.success) {
|
|
156
|
+
for (const issue of result.error.issues) {
|
|
157
|
+
ctx.addIssue({
|
|
158
|
+
...issue,
|
|
159
|
+
path: [index, ...issue.path],
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const itemSchema = schema.items !== undefined ? jsonSchemaToZodWithContext(schema.items, rootSchema) : z.any();
|
|
167
|
+
return z.array(itemSchema);
|
|
168
|
+
}
|
|
169
|
+
function buildImplicitTypeScopedSchema(schema, rootSchema) {
|
|
170
|
+
const scopedSchemas = [];
|
|
171
|
+
if (hasObjectKeywords(schema)) {
|
|
172
|
+
scopedSchemas.push({
|
|
173
|
+
matches: isPlainObject,
|
|
174
|
+
schema: objectSchemaToZod({ ...schema, type: 'object' }, rootSchema),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (hasArrayKeywords(schema)) {
|
|
178
|
+
const arraySchema = { ...schema, type: 'array' };
|
|
179
|
+
scopedSchemas.push({
|
|
180
|
+
matches: Array.isArray,
|
|
181
|
+
schema: finalizeSchema(applyArrayConstraints(arraySchemaToZod(arraySchema, rootSchema), arraySchema, rootSchema), arraySchema, rootSchema),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (hasStringKeywords(schema)) {
|
|
185
|
+
const stringSchema = { ...schema, type: 'string' };
|
|
186
|
+
scopedSchemas.push({
|
|
187
|
+
matches: (value) => typeof value === 'string',
|
|
188
|
+
schema: finalizeSchema(applyStringConstraints(z.string(), stringSchema), stringSchema, rootSchema),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (hasNumberKeywords(schema)) {
|
|
192
|
+
const numberSchema = { ...schema, type: 'number' };
|
|
193
|
+
scopedSchemas.push({
|
|
194
|
+
matches: (value) => typeof value === 'number' && Number.isFinite(value),
|
|
195
|
+
schema: finalizeSchema(applyNumberConstraints(z.number(), numberSchema), numberSchema, rootSchema),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (scopedSchemas.length === 0) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
return finalizeSchema(z.any().superRefine((value, ctx) => {
|
|
202
|
+
for (const scopedSchema of scopedSchemas) {
|
|
203
|
+
if (!scopedSchema.matches(value))
|
|
204
|
+
continue;
|
|
205
|
+
const result = scopedSchema.schema.safeParse(value);
|
|
206
|
+
if (!result.success) {
|
|
207
|
+
for (const issue of result.error.issues) {
|
|
208
|
+
ctx.addIssue({ ...issue });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}), schema, rootSchema);
|
|
213
|
+
}
|
|
214
|
+
function applyArrayConstraints(schema, jsonSchema, rootSchema) {
|
|
215
|
+
let constrained = schema;
|
|
216
|
+
if (typeof jsonSchema.minItems === 'number') {
|
|
217
|
+
constrained = constrained.min(jsonSchema.minItems);
|
|
218
|
+
}
|
|
219
|
+
if (typeof jsonSchema.maxItems === 'number') {
|
|
220
|
+
constrained = constrained.max(jsonSchema.maxItems);
|
|
221
|
+
}
|
|
222
|
+
if (jsonSchema.uniqueItems === true) {
|
|
223
|
+
constrained = constrained.refine((items) => hasUniqueItems(items), 'Expected array items to be unique');
|
|
224
|
+
}
|
|
225
|
+
if (jsonSchema.contains !== undefined) {
|
|
226
|
+
const containsSchema = jsonSchemaToZodWithContext(jsonSchema.contains, rootSchema);
|
|
227
|
+
constrained = constrained.refine((items) => {
|
|
228
|
+
const matchCount = items.filter((item) => containsSchema.safeParse(item).success).length;
|
|
229
|
+
const minContains = typeof jsonSchema.minContains === 'number' ? jsonSchema.minContains : 1;
|
|
230
|
+
const maxContains = typeof jsonSchema.maxContains === 'number'
|
|
231
|
+
? jsonSchema.maxContains
|
|
232
|
+
: Number.POSITIVE_INFINITY;
|
|
233
|
+
return matchCount >= minContains && matchCount <= maxContains;
|
|
234
|
+
}, 'Contains validation failed');
|
|
235
|
+
}
|
|
236
|
+
return constrained;
|
|
237
|
+
}
|
|
238
|
+
function applyObjectConstraints(schema, jsonSchema, rootSchema) {
|
|
239
|
+
let constrained = schema;
|
|
240
|
+
const knownProperties = new Set(Object.keys(jsonSchema.properties ?? {}));
|
|
241
|
+
if (typeof jsonSchema.minProperties === 'number') {
|
|
242
|
+
constrained = constrained.refine((value) => Object.keys(value).length >= jsonSchema.minProperties, `Expected at least ${jsonSchema.minProperties} properties`);
|
|
243
|
+
}
|
|
244
|
+
if (typeof jsonSchema.maxProperties === 'number') {
|
|
245
|
+
constrained = constrained.refine((value) => Object.keys(value).length <= jsonSchema.maxProperties, `Expected at most ${jsonSchema.maxProperties} properties`);
|
|
246
|
+
}
|
|
247
|
+
if (jsonSchema.propertyNames) {
|
|
248
|
+
const propertyNameSchema = propertyNamesToZod(jsonSchema.propertyNames, rootSchema);
|
|
249
|
+
constrained = constrained.refine((value) => Object.keys(value).every((key) => propertyNameSchema.safeParse(key).success), 'Property name validation failed');
|
|
250
|
+
}
|
|
251
|
+
const patternSchemas = jsonSchema.patternProperties && typeof jsonSchema.patternProperties === 'object'
|
|
252
|
+
? Object.entries(jsonSchema.patternProperties).map(([pattern, valueSchema]) => ({
|
|
253
|
+
pattern: new RegExp(pattern),
|
|
254
|
+
schema: jsonSchemaToZodWithContext(valueSchema, rootSchema),
|
|
255
|
+
}))
|
|
256
|
+
: [];
|
|
257
|
+
const additionalPropertySchema = jsonSchema.additionalProperties && typeof jsonSchema.additionalProperties === 'object'
|
|
258
|
+
? jsonSchemaToZodWithContext(jsonSchema.additionalProperties, rootSchema)
|
|
259
|
+
: undefined;
|
|
260
|
+
if (patternSchemas.length > 0 ||
|
|
261
|
+
jsonSchema.additionalProperties === false ||
|
|
262
|
+
additionalPropertySchema) {
|
|
263
|
+
constrained = constrained.superRefine((value, ctx) => {
|
|
264
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
265
|
+
const matchingPatterns = patternSchemas.filter(({ pattern }) => pattern.test(key));
|
|
266
|
+
for (const { schema: patternSchema } of matchingPatterns) {
|
|
267
|
+
const result = patternSchema.safeParse(entryValue);
|
|
268
|
+
if (!result.success) {
|
|
269
|
+
for (const issue of result.error.issues) {
|
|
270
|
+
ctx.addIssue({
|
|
271
|
+
...issue,
|
|
272
|
+
path: [key, ...issue.path],
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (knownProperties.has(key) || matchingPatterns.length > 0) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (jsonSchema.additionalProperties === false) {
|
|
281
|
+
ctx.addIssue({
|
|
282
|
+
code: 'custom',
|
|
283
|
+
path: [key],
|
|
284
|
+
message: 'Additional properties are not allowed',
|
|
285
|
+
});
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (!additionalPropertySchema) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const result = additionalPropertySchema.safeParse(entryValue);
|
|
292
|
+
if (!result.success) {
|
|
293
|
+
for (const issue of result.error.issues) {
|
|
294
|
+
ctx.addIssue({
|
|
295
|
+
...issue,
|
|
296
|
+
path: [key, ...issue.path],
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if (jsonSchema.dependentRequired && typeof jsonSchema.dependentRequired === 'object') {
|
|
304
|
+
constrained = constrained.refine((value) => {
|
|
305
|
+
const record = value;
|
|
306
|
+
return Object.entries(jsonSchema.dependentRequired ?? {}).every(([key, dependencies]) => {
|
|
307
|
+
if (!(key in record))
|
|
308
|
+
return true;
|
|
309
|
+
return dependencies.every((dependency) => dependency in record);
|
|
310
|
+
});
|
|
311
|
+
}, 'Dependent required validation failed');
|
|
312
|
+
}
|
|
313
|
+
if (jsonSchema.dependentSchemas && typeof jsonSchema.dependentSchemas === 'object') {
|
|
314
|
+
const dependentSchemas = Object.entries(jsonSchema.dependentSchemas).map(([key, dependency]) => ({
|
|
315
|
+
key,
|
|
316
|
+
schema: jsonSchemaToZodWithContext(dependency, rootSchema),
|
|
317
|
+
}));
|
|
318
|
+
constrained = constrained.refine((value) => {
|
|
319
|
+
const record = value;
|
|
320
|
+
return dependentSchemas.every(({ key, schema }) => {
|
|
321
|
+
if (!(key in record))
|
|
322
|
+
return true;
|
|
323
|
+
return schema.safeParse(record).success;
|
|
324
|
+
});
|
|
325
|
+
}, 'Dependent schema validation failed');
|
|
326
|
+
}
|
|
327
|
+
return constrained;
|
|
328
|
+
}
|
|
329
|
+
function applyRequiredProperties(schema, required) {
|
|
330
|
+
if (required.length === 0) {
|
|
331
|
+
return schema;
|
|
332
|
+
}
|
|
333
|
+
return schema.superRefine((value, ctx) => {
|
|
334
|
+
const record = value;
|
|
335
|
+
for (const key of required) {
|
|
336
|
+
if (key in record)
|
|
337
|
+
continue;
|
|
338
|
+
ctx.addIssue({
|
|
339
|
+
code: 'custom',
|
|
340
|
+
path: [key],
|
|
341
|
+
message: 'Required',
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function unionToZod(schemas, rootSchema) {
|
|
347
|
+
if (schemas.length === 0)
|
|
348
|
+
return z.any();
|
|
349
|
+
if (schemas.length === 1)
|
|
350
|
+
return jsonSchemaToZodWithContext(schemas[0], rootSchema);
|
|
351
|
+
const [first, second, ...rest] = schemas.map((part) => jsonSchemaToZodWithContext(part, rootSchema));
|
|
352
|
+
return z.union([first, second, ...rest]);
|
|
353
|
+
}
|
|
354
|
+
function oneOfToZod(schemas, rootSchema) {
|
|
355
|
+
if (schemas.length === 0)
|
|
356
|
+
return z.any();
|
|
357
|
+
if (schemas.length === 1)
|
|
358
|
+
return jsonSchemaToZodWithContext(schemas[0], rootSchema);
|
|
359
|
+
const parts = schemas.map((part) => jsonSchemaToZodWithContext(part, rootSchema));
|
|
360
|
+
return z.any().transform((value, ctx) => {
|
|
361
|
+
const matches = parts
|
|
362
|
+
.map((part) => part.safeParse(value))
|
|
363
|
+
.filter((result) => result.success)
|
|
364
|
+
.map((result) => result.data);
|
|
365
|
+
if (matches.length !== 1) {
|
|
366
|
+
ctx.addIssue({
|
|
367
|
+
code: 'custom',
|
|
368
|
+
message: 'Expected exactly one oneOf schema to match',
|
|
369
|
+
});
|
|
370
|
+
return z.NEVER;
|
|
371
|
+
}
|
|
372
|
+
return matches[0];
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
function unionLiterals(literals) {
|
|
376
|
+
if (literals.length === 1)
|
|
377
|
+
return literals[0];
|
|
378
|
+
const [first, second, ...rest] = literals;
|
|
379
|
+
return z.union([first, second, ...rest]);
|
|
380
|
+
}
|
|
381
|
+
function combineWithSiblingKeywords(baseSchema, siblings, rootSchema) {
|
|
382
|
+
if (!hasValidationKeywords(siblings)) {
|
|
383
|
+
return baseSchema;
|
|
384
|
+
}
|
|
385
|
+
return jsonSchemaToZodWithContext(siblings, rootSchema).and(baseSchema);
|
|
386
|
+
}
|
|
387
|
+
function finalizeSchema(baseSchema, jsonSchema, rootSchema) {
|
|
388
|
+
return applyConditionalKeywords(baseSchema, jsonSchema, rootSchema).describe(jsonSchema.description || '');
|
|
389
|
+
}
|
|
390
|
+
function applyConditionalKeywords(schema, jsonSchema, rootSchema) {
|
|
391
|
+
let constrained = schema;
|
|
392
|
+
if (jsonSchema.not !== undefined) {
|
|
393
|
+
const notSchema = jsonSchemaToZodWithContext(jsonSchema.not, rootSchema);
|
|
394
|
+
constrained = constrained.refine((value) => !notSchema.safeParse(value).success, 'Negated schema validation failed');
|
|
395
|
+
}
|
|
396
|
+
if (jsonSchema.if !== undefined) {
|
|
397
|
+
const ifSchema = jsonSchemaToZodWithContext(jsonSchema.if, rootSchema);
|
|
398
|
+
const thenSchema = jsonSchema.then !== undefined
|
|
399
|
+
? jsonSchemaToZodWithContext(jsonSchema.then, rootSchema)
|
|
400
|
+
: z.any();
|
|
401
|
+
const elseSchema = jsonSchema.else !== undefined
|
|
402
|
+
? jsonSchemaToZodWithContext(jsonSchema.else, rootSchema)
|
|
403
|
+
: z.any();
|
|
404
|
+
constrained = constrained.refine((value) => {
|
|
405
|
+
const branchSchema = ifSchema.safeParse(value).success ? thenSchema : elseSchema;
|
|
406
|
+
return branchSchema.safeParse(value).success;
|
|
407
|
+
}, 'Conditional schema validation failed');
|
|
408
|
+
}
|
|
409
|
+
return constrained;
|
|
410
|
+
}
|
|
411
|
+
function hasValidationKeywords(schema) {
|
|
412
|
+
return Object.keys(schema).some((key) => !['description', '$defs', '$ref'].includes(key) &&
|
|
413
|
+
schema[key] !== undefined);
|
|
414
|
+
}
|
|
415
|
+
function hasObjectKeywords(schema) {
|
|
416
|
+
return (schema.properties !== undefined ||
|
|
417
|
+
schema.patternProperties !== undefined ||
|
|
418
|
+
schema.required !== undefined ||
|
|
419
|
+
schema.dependentRequired !== undefined ||
|
|
420
|
+
schema.dependentSchemas !== undefined ||
|
|
421
|
+
schema.minProperties !== undefined ||
|
|
422
|
+
schema.maxProperties !== undefined ||
|
|
423
|
+
schema.additionalProperties !== undefined ||
|
|
424
|
+
schema.propertyNames !== undefined);
|
|
425
|
+
}
|
|
426
|
+
function hasArrayKeywords(schema) {
|
|
427
|
+
return (schema.prefixItems !== undefined ||
|
|
428
|
+
schema.items !== undefined ||
|
|
429
|
+
schema.contains !== undefined ||
|
|
430
|
+
schema.minItems !== undefined ||
|
|
431
|
+
schema.maxItems !== undefined ||
|
|
432
|
+
schema.minContains !== undefined ||
|
|
433
|
+
schema.maxContains !== undefined ||
|
|
434
|
+
schema.uniqueItems !== undefined);
|
|
435
|
+
}
|
|
436
|
+
function hasStringKeywords(schema) {
|
|
437
|
+
return (schema.minLength !== undefined || schema.maxLength !== undefined || schema.pattern !== undefined);
|
|
438
|
+
}
|
|
439
|
+
function hasNumberKeywords(schema) {
|
|
440
|
+
return (schema.minimum !== undefined ||
|
|
441
|
+
schema.maximum !== undefined ||
|
|
442
|
+
schema.exclusiveMinimum !== undefined ||
|
|
443
|
+
schema.exclusiveMaximum !== undefined ||
|
|
444
|
+
schema.multipleOf !== undefined);
|
|
445
|
+
}
|
|
446
|
+
function resolveLocalRef(rootSchema, ref) {
|
|
447
|
+
if (ref === '#')
|
|
448
|
+
return rootSchema;
|
|
449
|
+
if (!rootSchema || typeof rootSchema !== 'object')
|
|
450
|
+
return undefined;
|
|
451
|
+
if (ref.startsWith('#/')) {
|
|
452
|
+
let current = rootSchema;
|
|
453
|
+
for (const token of ref
|
|
454
|
+
.slice(2)
|
|
455
|
+
.split('/')
|
|
456
|
+
.map((part) => part.replace(/~1/g, '/').replace(/~0/g, '~'))) {
|
|
457
|
+
if (!current || typeof current !== 'object')
|
|
458
|
+
return undefined;
|
|
459
|
+
current = current[token];
|
|
460
|
+
}
|
|
461
|
+
return current;
|
|
462
|
+
}
|
|
463
|
+
if (ref.startsWith('#')) {
|
|
464
|
+
const anchor = decodeURIComponent(ref.slice(1));
|
|
465
|
+
if (!anchor)
|
|
466
|
+
return undefined;
|
|
467
|
+
return findAnchor(rootSchema, anchor);
|
|
468
|
+
}
|
|
469
|
+
return undefined;
|
|
470
|
+
}
|
|
471
|
+
function findAnchor(schema, anchor) {
|
|
472
|
+
if (!schema || typeof schema !== 'object') {
|
|
473
|
+
return undefined;
|
|
474
|
+
}
|
|
475
|
+
const schemaObject = schema;
|
|
476
|
+
if (schemaObject.$anchor === anchor) {
|
|
477
|
+
return schema;
|
|
478
|
+
}
|
|
479
|
+
for (const value of Object.values(schemaObject)) {
|
|
480
|
+
if (Array.isArray(value)) {
|
|
481
|
+
for (const item of value) {
|
|
482
|
+
const found = findAnchor(item, anchor);
|
|
483
|
+
if (found !== undefined)
|
|
484
|
+
return found;
|
|
485
|
+
}
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const found = findAnchor(value, anchor);
|
|
489
|
+
if (found !== undefined)
|
|
490
|
+
return found;
|
|
491
|
+
}
|
|
492
|
+
return undefined;
|
|
493
|
+
}
|
|
494
|
+
function propertyNamesToZod(jsonSchema, rootSchema) {
|
|
495
|
+
if (jsonSchema && typeof jsonSchema === 'object' && !Array.isArray(jsonSchema)) {
|
|
496
|
+
const schema = jsonSchema;
|
|
497
|
+
return jsonSchemaToZodWithContext(schema.type === undefined ? { type: 'string', ...schema } : schema, rootSchema);
|
|
498
|
+
}
|
|
499
|
+
return jsonSchemaToZodWithContext(jsonSchema, rootSchema);
|
|
500
|
+
}
|
|
501
|
+
function isPlainObject(value) {
|
|
502
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
503
|
+
}
|
|
504
|
+
function isMultipleOf(value, divisor) {
|
|
505
|
+
const quotient = value / divisor;
|
|
506
|
+
return Math.abs(quotient - Math.round(quotient)) < 1e-9;
|
|
507
|
+
}
|
|
508
|
+
function hasUniqueItems(items) {
|
|
509
|
+
return items.every((item, index) => items.findIndex((candidate) => isDeepStrictEqual(candidate, item)) === index);
|
|
510
|
+
}
|
|
511
|
+
//# sourceMappingURL=json-schema-to-zod.js.map
|
|
@@ -1,32 +1,57 @@
|
|
|
1
1
|
import { PACKAGE_VERSION } from '../../version.js';
|
|
2
2
|
export function buildA2AAgentCard(input) {
|
|
3
3
|
const capabilities = input.capabilities ?? [];
|
|
4
|
+
const protocolVersion = input.protocolVersion ?? '1.0';
|
|
5
|
+
const agentCapabilities = {
|
|
6
|
+
extensions: input.capabilityOptions?.extensions,
|
|
7
|
+
pushNotifications: input.capabilityOptions?.pushNotifications ?? false,
|
|
8
|
+
streaming: input.capabilityOptions?.streaming ?? true,
|
|
9
|
+
...(input.capabilityOptions?.extendedAgentCard === true ? { extendedAgentCard: true } : {}),
|
|
10
|
+
};
|
|
4
11
|
const securitySchemes = input.security.length > 0
|
|
5
12
|
? Object.fromEntries(input.security.map((scheme, index) => [
|
|
6
13
|
scheme.name ?? `${scheme.type}-${index}`,
|
|
7
|
-
|
|
14
|
+
toSecuritySchemeValue(scheme),
|
|
8
15
|
]))
|
|
9
16
|
: undefined;
|
|
17
|
+
const securityRequirements = input.security.length > 0
|
|
18
|
+
? input.security.map((scheme, index) => ({ [scheme.name ?? `${scheme.type}-${index}`]: [] }))
|
|
19
|
+
: undefined;
|
|
10
20
|
return {
|
|
11
21
|
name: input.name,
|
|
12
|
-
url: input.url,
|
|
13
22
|
description: input.description ?? 'Salmon Loop agent',
|
|
14
23
|
version: input.version ?? PACKAGE_VERSION,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
documentationUrl: input.documentationUrl,
|
|
25
|
+
provider: input.provider,
|
|
26
|
+
supportedInterfaces: [
|
|
27
|
+
{
|
|
28
|
+
url: input.url,
|
|
29
|
+
protocolBinding: 'JSONRPC',
|
|
30
|
+
protocolVersion,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
defaultInputModes: input.defaultInputModes ?? ['text/plain'],
|
|
34
|
+
defaultOutputModes: input.defaultOutputModes ?? ['text/plain'],
|
|
35
|
+
capabilities: agentCapabilities,
|
|
23
36
|
skills: capabilities.map((capability) => ({
|
|
24
37
|
id: capability.id,
|
|
25
38
|
name: capability.title,
|
|
26
39
|
description: capability.description ?? capability.title,
|
|
27
|
-
tags: [],
|
|
40
|
+
tags: capability.tags ?? [],
|
|
41
|
+
examples: capability.examples,
|
|
42
|
+
inputModes: capability.inputModes,
|
|
43
|
+
outputModes: capability.outputModes,
|
|
44
|
+
securityRequirements: capability.security,
|
|
28
45
|
})),
|
|
29
46
|
securitySchemes,
|
|
47
|
+
securityRequirements,
|
|
30
48
|
};
|
|
31
49
|
}
|
|
50
|
+
function toSecuritySchemeValue(scheme) {
|
|
51
|
+
if (scheme.type === 'apiKey') {
|
|
52
|
+
return { ...scheme };
|
|
53
|
+
}
|
|
54
|
+
const { name: _name, ...standardScheme } = scheme;
|
|
55
|
+
return standardScheme;
|
|
56
|
+
}
|
|
32
57
|
//# sourceMappingURL=agent-card.js.map
|