ai-capability-framework 1.0.0-rc.1

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 (115) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/CONTRIBUTING.md +56 -0
  3. package/LICENSE +21 -0
  4. package/README.md +198 -0
  5. package/SECURITY.md +29 -0
  6. package/conformance/invalid/duplicate/capabilities/conformance.duplicate.one.yaml +55 -0
  7. package/conformance/invalid/duplicate/capabilities/conformance.duplicate.two.yaml +55 -0
  8. package/conformance/invalid/eval-results/conformance.results.failing.json +15 -0
  9. package/conformance/invalid/missing-reference/capabilities/conformance.missing_reference.prepare.yaml +58 -0
  10. package/conformance/invalid/schema/capabilities/conformance.invalid.missing_required.yaml +3 -0
  11. package/conformance/valid/capabilities/conformance.note.get.yaml +82 -0
  12. package/conformance/valid/decisions/conformance.note.get.denied_missing_permission.json +13 -0
  13. package/conformance/valid/entities/Note.yaml +18 -0
  14. package/conformance/valid/eval-results/conformance.results.passing.json +19 -0
  15. package/conformance/valid/evals/conformance.note.get.valid.yaml +33 -0
  16. package/conformance/valid/openai/context.no_permissions.json +6 -0
  17. package/dist/adapter-common.d.ts +62 -0
  18. package/dist/adapter-common.d.ts.map +1 -0
  19. package/dist/adapter-common.js +453 -0
  20. package/dist/ai-sdk.d.ts +5 -0
  21. package/dist/ai-sdk.d.ts.map +1 -0
  22. package/dist/ai-sdk.js +71 -0
  23. package/dist/anthropic-claude.d.ts +5 -0
  24. package/dist/anthropic-claude.d.ts.map +1 -0
  25. package/dist/anthropic-claude.js +62 -0
  26. package/dist/cli.d.ts +11 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +360 -0
  29. package/dist/decision.d.ts +6 -0
  30. package/dist/decision.d.ts.map +1 -0
  31. package/dist/decision.js +237 -0
  32. package/dist/eval-runner.d.ts +6 -0
  33. package/dist/eval-runner.d.ts.map +1 -0
  34. package/dist/eval-runner.js +372 -0
  35. package/dist/gemini.d.ts +5 -0
  36. package/dist/gemini.d.ts.map +1 -0
  37. package/dist/gemini.js +64 -0
  38. package/dist/generated/manifest-types.d.ts +208 -0
  39. package/dist/generated/manifest-types.d.ts.map +1 -0
  40. package/dist/generated/manifest-types.js +1 -0
  41. package/dist/index.d.ts +15 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +13 -0
  44. package/dist/langchain.d.ts +5 -0
  45. package/dist/langchain.d.ts.map +1 -0
  46. package/dist/langchain.js +65 -0
  47. package/dist/loader.d.ts +4 -0
  48. package/dist/loader.d.ts.map +1 -0
  49. package/dist/loader.js +94 -0
  50. package/dist/mcp.d.ts +5 -0
  51. package/dist/mcp.d.ts.map +1 -0
  52. package/dist/mcp.js +82 -0
  53. package/dist/openai-responses.d.ts +6 -0
  54. package/dist/openai-responses.d.ts.map +1 -0
  55. package/dist/openai-responses.js +65 -0
  56. package/dist/registry.d.ts +6 -0
  57. package/dist/registry.d.ts.map +1 -0
  58. package/dist/registry.js +134 -0
  59. package/dist/semantic-kernel.d.ts +5 -0
  60. package/dist/semantic-kernel.d.ts.map +1 -0
  61. package/dist/semantic-kernel.js +79 -0
  62. package/dist/types.d.ts +400 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +1 -0
  65. package/dist/validator.d.ts +3 -0
  66. package/dist/validator.d.ts.map +1 -0
  67. package/dist/validator.js +105 -0
  68. package/docs/adapter-roadmap.md +179 -0
  69. package/docs/adapters.md +112 -0
  70. package/docs/api.md +115 -0
  71. package/docs/capability-manifests.md +47 -0
  72. package/docs/control-plane.md +59 -0
  73. package/docs/eval-runner.md +80 -0
  74. package/docs/evals.md +34 -0
  75. package/docs/getting-started.md +51 -0
  76. package/docs/host-responsibilities.md +23 -0
  77. package/docs/interoperability.md +32 -0
  78. package/docs/migration-0.1-to-1.0.md +22 -0
  79. package/docs/openai-responses.md +103 -0
  80. package/docs/release.md +75 -0
  81. package/docs/spec.md +194 -0
  82. package/examples/eval-results/public.results.passing.json +128 -0
  83. package/examples/scheduling/capabilities/scheduling.availability.get.yaml +91 -0
  84. package/examples/scheduling/capabilities/scheduling.invite.prepare.yaml +114 -0
  85. package/examples/scheduling/capabilities/scheduling.invite.send.yaml +97 -0
  86. package/examples/scheduling/decisions/scheduling.availability.get.select.json +14 -0
  87. package/examples/scheduling/decisions/scheduling.invite.prepare.allowed.json +20 -0
  88. package/examples/scheduling/decisions/scheduling.invite.send.allowed.json +22 -0
  89. package/examples/scheduling/decisions/scheduling.invite.send.denied_missing_approval.json +18 -0
  90. package/examples/scheduling/entities/AvailabilitySlot.yaml +26 -0
  91. package/examples/scheduling/entities/MeetingInvite.yaml +25 -0
  92. package/examples/scheduling/eval-results/scheduling.results.passing.json +59 -0
  93. package/examples/scheduling/evals/scheduling.availability.get.valid.yaml +38 -0
  94. package/examples/scheduling/evals/scheduling.invite.prepare.valid.yaml +44 -0
  95. package/examples/scheduling/evals/scheduling.invite.send.requires_approval.yaml +43 -0
  96. package/examples/scheduling/openai/context.scheduler.json +6 -0
  97. package/examples/support/capabilities/support.refund.commit_case.yaml +98 -0
  98. package/examples/support/capabilities/support.refund.prepare_case.yaml +116 -0
  99. package/examples/support/capabilities/support.ticket.get.yaml +85 -0
  100. package/examples/support/decisions/support.refund.commit_case.allowed.json +22 -0
  101. package/examples/support/decisions/support.refund.commit_case.denied_missing_approval.json +18 -0
  102. package/examples/support/decisions/support.refund.prepare_case.approval_required.json +19 -0
  103. package/examples/support/decisions/support.ticket.get.select.json +0 -0
  104. package/examples/support/entities/Order.yaml +23 -0
  105. package/examples/support/entities/Ticket.yaml +25 -0
  106. package/examples/support/eval-results/support.results.passing.json +68 -0
  107. package/examples/support/evals/support.refund.commit_case.requires_approval.yaml +42 -0
  108. package/examples/support/evals/support.refund.prepare_case.approval_required.yaml +45 -0
  109. package/examples/support/evals/support.refund.prepare_case.valid.yaml +43 -0
  110. package/examples/support/openai/context.support_agent.json +9 -0
  111. package/package.json +74 -0
  112. package/schemas/capability-manifest.schema.json +250 -0
  113. package/schemas/entity-manifest.schema.json +97 -0
  114. package/schemas/eval-case.schema.json +134 -0
  115. package/schemas/eval-result.schema.json +77 -0
@@ -0,0 +1,33 @@
1
+ schema_version: "1.0"
2
+ id: conformance.note.get.valid
3
+ name: Read a conformance note
4
+ capability_under_test: conformance.note.get
5
+ tags:
6
+ - conformance
7
+ - tool_selection
8
+ input:
9
+ user_message: Read conformance note NOTE-1001.
10
+ context:
11
+ request_context:
12
+ environment: test
13
+ user:
14
+ id: user_example_conformance
15
+ roles:
16
+ - reader
17
+ permissions:
18
+ - note.read
19
+ tenant_id: tenant_example
20
+ autonomy_tier: A1
21
+ expected:
22
+ selected_capabilities:
23
+ includes:
24
+ - conformance.note.get
25
+ tool_calls:
26
+ - capability_id: conformance.note.get
27
+ args_match:
28
+ note_id: NOTE-1001
29
+ no_commit: true
30
+ scorers:
31
+ - type: tool_selection_includes
32
+ - type: tool_input_json_subset
33
+ - type: no_unapproved_commit
@@ -0,0 +1,6 @@
1
+ {
2
+ "autonomyTier": "A1",
3
+ "permissions": [],
4
+ "tenantId": "tenant_example",
5
+ "userId": "user_example_conformance"
6
+ }
@@ -0,0 +1,62 @@
1
+ import type { AdapterExcludedCapability, AdapterToolBinding, AicfDiagnostic, CapabilityManifest, DecisionRequest, JsonObject, LoadedCapabilityManifest, ManifestRegistry, ParseAdapterToolCallResult } from "./types.js";
2
+ export declare const strictToolSchemaUnsupportedKeywords: string[];
3
+ export interface BuildAdapterToolsetOptions<TTool, TBinding extends AdapterToolBinding = AdapterToolBinding> {
4
+ adapterName: string;
5
+ buildTool(input: {
6
+ loadedCapability: LoadedCapabilityManifest;
7
+ normalizedInputSchema: JsonObject;
8
+ restricted: boolean;
9
+ toolName: string;
10
+ }): TTool;
11
+ context: DecisionRequest["context"];
12
+ defaultNamePrefix: string;
13
+ includeRestricted?: boolean;
14
+ maxToolNameLength?: number;
15
+ namePrefix?: string;
16
+ toBinding?(binding: AdapterToolBinding, input: {
17
+ loadedCapability: LoadedCapabilityManifest;
18
+ normalizedInputSchema: JsonObject;
19
+ restricted: boolean;
20
+ toolName: string;
21
+ }): TBinding;
22
+ registry: ManifestRegistry;
23
+ unsupportedSchemaKeywords?: string[];
24
+ }
25
+ export interface BuiltAdapterToolset<TTool, TBinding extends AdapterToolBinding = AdapterToolBinding> {
26
+ bindings: TBinding[];
27
+ diagnostics: AicfDiagnostic[];
28
+ excluded: AdapterExcludedCapability[];
29
+ tools: TTool[];
30
+ }
31
+ export declare function buildAdapterToolset<TTool, TBinding extends AdapterToolBinding = AdapterToolBinding>(options: BuildAdapterToolsetOptions<TTool, TBinding>): BuiltAdapterToolset<TTool, TBinding>;
32
+ export declare function selectContextForCapability(capability: CapabilityManifest, context: DecisionRequest["context"]): DecisionRequest["context"];
33
+ export declare function isRestrictedCapability(capability: CapabilityManifest): boolean;
34
+ export declare function adapterToolDescription(capability: CapabilityManifest): string;
35
+ export declare function toAdapterToolName(capabilityId: string, options: {
36
+ maxLength?: number;
37
+ namePrefix: string;
38
+ }): string;
39
+ export declare function normalizeInputSchemaForStrictTool(loadedCapability: LoadedCapabilityManifest, options?: {
40
+ unsupportedSchemaKeywords?: string[];
41
+ }): {
42
+ diagnostics: AicfDiagnostic[];
43
+ ok: false;
44
+ } | {
45
+ diagnostics: AicfDiagnostic[];
46
+ ok: true;
47
+ schema: JsonObject;
48
+ };
49
+ export declare function parseAdapterToolCall(input: {
50
+ argumentsPath: string;
51
+ bindings: AdapterToolBinding[];
52
+ callId?: string;
53
+ id?: string;
54
+ rawArguments: unknown;
55
+ rawArgumentsAreJsonString?: boolean;
56
+ toolName: string;
57
+ toolNamePath: string;
58
+ }): ParseAdapterToolCallResult;
59
+ export declare function validateAdapterContext(context: DecisionRequest["context"], adapterName: string): string | null;
60
+ export declare function toJsonObject(value: unknown): JsonObject;
61
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
62
+ //# sourceMappingURL=adapter-common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-common.d.ts","sourceRoot":"","sources":["../src/adapter-common.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,453 @@
1
+ import { createHash } from "node:crypto";
2
+ import Ajv2020 from "ajv/dist/2020.js";
3
+ import { decideCapability } from "./decision.js";
4
+ const hashLength = 8;
5
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
6
+ const autonomyRank = {
7
+ A0: 0,
8
+ A1: 1,
9
+ A2: 2,
10
+ A3: 3,
11
+ A4: 4,
12
+ A5: 5
13
+ };
14
+ export const strictToolSchemaUnsupportedKeywords = [
15
+ "$ref",
16
+ "allOf",
17
+ "anyOf",
18
+ "dependencies",
19
+ "dependentRequired",
20
+ "dependentSchemas",
21
+ "if",
22
+ "not",
23
+ "oneOf",
24
+ "patternProperties",
25
+ "prefixItems",
26
+ "then",
27
+ "unevaluatedProperties"
28
+ ];
29
+ export function buildAdapterToolset(options) {
30
+ const contextError = validateAdapterContext(options.context, options.adapterName);
31
+ if (contextError) {
32
+ return {
33
+ bindings: [],
34
+ diagnostics: [{
35
+ code: "invalid_context",
36
+ message: contextError,
37
+ path: "options.context"
38
+ }],
39
+ excluded: [],
40
+ tools: []
41
+ };
42
+ }
43
+ const diagnostics = [];
44
+ const excluded = [];
45
+ const bindings = [];
46
+ const tools = [];
47
+ const toolNameOwners = new Map();
48
+ for (const loadedCapability of options.registry.capabilities) {
49
+ const capability = loadedCapability.manifest;
50
+ const restricted = isRestrictedCapability(capability);
51
+ if (restricted && !options.includeRestricted) {
52
+ const capabilityDiagnostics = [{
53
+ code: "capability_excluded",
54
+ details: {
55
+ restricted: true
56
+ },
57
+ id: capability.id,
58
+ kind: "capability",
59
+ message: `Capability "${capability.id}" is restricted and was not exported to ${options.adapterName} tools.`,
60
+ path: loadedCapability.path
61
+ }];
62
+ diagnostics.push(...capabilityDiagnostics);
63
+ excluded.push({
64
+ capabilityId: capability.id,
65
+ diagnostics: capabilityDiagnostics,
66
+ path: loadedCapability.path,
67
+ reason: "restricted"
68
+ });
69
+ continue;
70
+ }
71
+ const selectDecision = decideCapability(options.registry, {
72
+ capabilityId: capability.id,
73
+ context: selectContextForCapability(capability, options.context),
74
+ operation: "select"
75
+ });
76
+ if (selectDecision.status !== "allowed") {
77
+ const capabilityDiagnostics = decisionDiagnostics(loadedCapability, selectDecision.reasons, options.adapterName);
78
+ diagnostics.push(...capabilityDiagnostics);
79
+ excluded.push({
80
+ capabilityId: capability.id,
81
+ diagnostics: capabilityDiagnostics,
82
+ path: loadedCapability.path,
83
+ reason: "decision_denied"
84
+ });
85
+ continue;
86
+ }
87
+ const normalizedSchema = normalizeInputSchemaForStrictTool(loadedCapability, {
88
+ unsupportedSchemaKeywords: options.unsupportedSchemaKeywords
89
+ });
90
+ if (!normalizedSchema.ok) {
91
+ diagnostics.push(...normalizedSchema.diagnostics);
92
+ excluded.push({
93
+ capabilityId: capability.id,
94
+ diagnostics: normalizedSchema.diagnostics,
95
+ path: loadedCapability.path,
96
+ reason: "unsupported_schema"
97
+ });
98
+ continue;
99
+ }
100
+ const toolName = toAdapterToolName(capability.id, {
101
+ maxLength: options.maxToolNameLength,
102
+ namePrefix: options.namePrefix ?? options.defaultNamePrefix
103
+ });
104
+ const existingOwner = toolNameOwners.get(toolName);
105
+ if (existingOwner && existingOwner !== capability.id) {
106
+ const collisionDiagnostics = [{
107
+ code: "tool_name_collision",
108
+ details: {
109
+ existingCapabilityId: existingOwner,
110
+ toolName
111
+ },
112
+ id: capability.id,
113
+ kind: "capability",
114
+ message: `${options.adapterName} tool name "${toolName}" collides with capability "${existingOwner}".`,
115
+ path: loadedCapability.path
116
+ }];
117
+ diagnostics.push(...collisionDiagnostics);
118
+ excluded.push({
119
+ capabilityId: capability.id,
120
+ diagnostics: collisionDiagnostics,
121
+ path: loadedCapability.path,
122
+ reason: "tool_name_collision"
123
+ });
124
+ continue;
125
+ }
126
+ toolNameOwners.set(toolName, capability.id);
127
+ const binding = baseBinding(loadedCapability, {
128
+ normalizedInputSchema: normalizedSchema.schema,
129
+ restricted,
130
+ toolName
131
+ });
132
+ const input = {
133
+ loadedCapability,
134
+ normalizedInputSchema: normalizedSchema.schema,
135
+ restricted,
136
+ toolName
137
+ };
138
+ tools.push(options.buildTool(input));
139
+ bindings.push(options.toBinding ? options.toBinding(binding, input) : binding);
140
+ }
141
+ return {
142
+ bindings,
143
+ diagnostics,
144
+ excluded,
145
+ tools
146
+ };
147
+ }
148
+ export function selectContextForCapability(capability, context) {
149
+ if (autonomyRank[context.autonomyTier] <= autonomyRank[capability.autonomy_tier]) {
150
+ return context;
151
+ }
152
+ return {
153
+ ...context,
154
+ autonomyTier: capability.autonomy_tier
155
+ };
156
+ }
157
+ export function isRestrictedCapability(capability) {
158
+ return capability.lifecycle.commit
159
+ || capability.capability_type === "write_commit"
160
+ || capability.capability_type === "external_message_send"
161
+ || capability.capability_type === "workflow_start"
162
+ || capability.side_effects.charges_money
163
+ || capability.side_effects.refunds_money
164
+ || capability.side_effects.changes_permissions
165
+ || capability.side_effects.triggers_external_workflow
166
+ || capability.side_effects.irreversible
167
+ || capability.side_effects.sends_external_messages;
168
+ }
169
+ export function adapterToolDescription(capability) {
170
+ const lifecycle = Object.entries(capability.lifecycle)
171
+ .filter(([, enabled]) => enabled)
172
+ .map(([name]) => name)
173
+ .join(", ") || "none";
174
+ const whenToUse = (capability.when_to_use ?? []).join(" ");
175
+ const whenNotToUse = (capability.when_not_to_use ?? []).join(" ");
176
+ return [
177
+ capability.model_description.trim(),
178
+ `Capability ID: ${capability.id}.`,
179
+ `Type: ${capability.capability_type}. Risk: ${capability.risk_tier}. Autonomy: ${capability.autonomy_tier}. Lifecycle: ${lifecycle}.`,
180
+ whenToUse ? `Use when: ${whenToUse}` : "",
181
+ whenNotToUse ? `Do not use when: ${whenNotToUse}` : ""
182
+ ].filter(Boolean).join(" ");
183
+ }
184
+ export function toAdapterToolName(capabilityId, options) {
185
+ const maxLength = options.maxLength ?? 64;
186
+ const sanitizedPrefix = sanitizeToolNamePart(options.namePrefix);
187
+ const sanitizedId = sanitizeToolNamePart(capabilityId);
188
+ const baseName = `${sanitizedPrefix}${sanitizedId}`;
189
+ if (baseName.length <= maxLength) {
190
+ return baseName;
191
+ }
192
+ const hash = createHash("sha256").update(capabilityId).digest("hex").slice(0, hashLength);
193
+ const prefixLength = maxLength - hash.length - 1;
194
+ return `${baseName.slice(0, prefixLength)}_${hash}`;
195
+ }
196
+ export function normalizeInputSchemaForStrictTool(loadedCapability, options = {}) {
197
+ const schema = loadedCapability.manifest.input_schema;
198
+ if (!isRecord(schema)) {
199
+ return unsupportedSchema(loadedCapability, "/", "Input schema must be a JSON object.");
200
+ }
201
+ const normalized = normalizeSchemaObject(loadedCapability, schema, "/", false, options);
202
+ if (!normalized.ok) {
203
+ return normalized;
204
+ }
205
+ const types = schemaTypes(normalized.schema.type);
206
+ if (!types.includes("object")) {
207
+ return unsupportedSchema(loadedCapability, "/", "Tool parameters must be an object schema.");
208
+ }
209
+ return normalized;
210
+ }
211
+ export function parseAdapterToolCall(input) {
212
+ const binding = input.bindings.find((candidate) => candidate.toolName === input.toolName);
213
+ if (!binding) {
214
+ return {
215
+ diagnostics: [{
216
+ code: "invalid_tool_call",
217
+ details: {
218
+ toolName: input.toolName
219
+ },
220
+ message: `Unknown tool name "${input.toolName}".`,
221
+ path: input.toolNamePath
222
+ }],
223
+ valid: false
224
+ };
225
+ }
226
+ let args = input.rawArguments;
227
+ if (input.rawArgumentsAreJsonString) {
228
+ if (typeof input.rawArguments !== "string") {
229
+ return invalidToolCall(binding, input.argumentsPath, "Tool call arguments must be a JSON string.");
230
+ }
231
+ try {
232
+ args = JSON.parse(input.rawArguments);
233
+ }
234
+ catch (error) {
235
+ return {
236
+ diagnostics: [{
237
+ code: "invalid_tool_call",
238
+ details: error instanceof Error ? error.message : undefined,
239
+ id: binding.capabilityId,
240
+ message: `Tool call arguments for "${input.toolName}" are not valid JSON.`,
241
+ path: input.argumentsPath
242
+ }],
243
+ valid: false
244
+ };
245
+ }
246
+ }
247
+ if (!isRecord(args)) {
248
+ return invalidToolCall(binding, input.argumentsPath, `Tool call arguments for "${input.toolName}" must be a JSON object.`);
249
+ }
250
+ const validate = ajv.compile(binding.inputSchema);
251
+ const valid = validate(args);
252
+ if (!valid) {
253
+ return {
254
+ diagnostics: (validate.errors ?? []).map((error) => ({
255
+ code: "schema",
256
+ details: error,
257
+ id: binding.capabilityId,
258
+ message: `${error.instancePath || "/"}: ${error.message ?? "schema validation failed"}`,
259
+ path: input.argumentsPath
260
+ })),
261
+ valid: false
262
+ };
263
+ }
264
+ return {
265
+ diagnostics: [],
266
+ parsed: {
267
+ args,
268
+ callId: input.callId,
269
+ capabilityId: binding.capabilityId,
270
+ id: input.id,
271
+ toolName: binding.toolName
272
+ },
273
+ valid: true
274
+ };
275
+ }
276
+ export function validateAdapterContext(context, adapterName) {
277
+ if (!isRecord(context)) {
278
+ return `${adapterName} tool export requires a context object.`;
279
+ }
280
+ if (!Array.isArray(context.permissions) || context.permissions.some((permission) => typeof permission !== "string")) {
281
+ return `${adapterName} tool export context.permissions must be an array of strings.`;
282
+ }
283
+ if (!["A0", "A1", "A2", "A3", "A4", "A5"].includes(context.autonomyTier)) {
284
+ return `${adapterName} tool export context.autonomyTier must be A0, A1, A2, A3, A4, or A5.`;
285
+ }
286
+ if (context.userId !== undefined && typeof context.userId !== "string") {
287
+ return `${adapterName} tool export context.userId must be a string when present.`;
288
+ }
289
+ if (context.tenantId !== undefined && typeof context.tenantId !== "string") {
290
+ return `${adapterName} tool export context.tenantId must be a string when present.`;
291
+ }
292
+ return null;
293
+ }
294
+ export function toJsonObject(value) {
295
+ return JSON.parse(JSON.stringify(value));
296
+ }
297
+ export function isRecord(value) {
298
+ return typeof value === "object" && value !== null && !Array.isArray(value);
299
+ }
300
+ function baseBinding(loadedCapability, input) {
301
+ const capability = loadedCapability.manifest;
302
+ return {
303
+ autonomyTier: capability.autonomy_tier,
304
+ capabilityId: capability.id,
305
+ capabilityType: capability.capability_type,
306
+ inputSchema: toJsonObject(capability.input_schema),
307
+ normalizedInputSchema: input.normalizedInputSchema,
308
+ path: loadedCapability.path,
309
+ restricted: input.restricted,
310
+ riskTier: capability.risk_tier,
311
+ toolName: input.toolName
312
+ };
313
+ }
314
+ function decisionDiagnostics(loadedCapability, reasons, adapterName) {
315
+ if (reasons.length === 0) {
316
+ return [{
317
+ code: "capability_excluded",
318
+ id: loadedCapability.manifest.id,
319
+ kind: "capability",
320
+ message: `Capability "${loadedCapability.manifest.id}" was not selectable and was not exported to ${adapterName} tools.`,
321
+ path: loadedCapability.path
322
+ }];
323
+ }
324
+ return reasons.map((reason) => ({
325
+ code: "capability_excluded",
326
+ details: reason,
327
+ id: loadedCapability.manifest.id,
328
+ kind: "capability",
329
+ message: `Capability "${loadedCapability.manifest.id}" was not exported: ${reason.message}`,
330
+ path: loadedCapability.path
331
+ }));
332
+ }
333
+ function normalizeSchemaObject(loadedCapability, schema, pointer, optional, options) {
334
+ const unsupportedKeywords = options.unsupportedSchemaKeywords ?? strictToolSchemaUnsupportedKeywords;
335
+ for (const keyword of unsupportedKeywords) {
336
+ if (keyword in schema) {
337
+ return unsupportedSchema(loadedCapability, pointer, `Input schema uses unsupported keyword "${keyword}" for strict tool export.`);
338
+ }
339
+ }
340
+ const normalized = toJsonObject(schema);
341
+ const types = schemaTypes(schema.type);
342
+ if (types.includes("object")) {
343
+ const properties = schema.properties;
344
+ const required = schema.required;
345
+ if (properties !== undefined && !isRecord(properties)) {
346
+ return unsupportedSchema(loadedCapability, `${pointer}/properties`, "Schema properties must be an object.");
347
+ }
348
+ if (required !== undefined && !isStringArray(required)) {
349
+ return unsupportedSchema(loadedCapability, `${pointer}/required`, "Schema required fields must be a string array.");
350
+ }
351
+ const propertySchemas = properties ?? {};
352
+ const requiredFields = new Set(required ?? []);
353
+ const normalizedProperties = {};
354
+ for (const [propertyName, propertySchema] of Object.entries(propertySchemas)) {
355
+ if (!isRecord(propertySchema)) {
356
+ return unsupportedSchema(loadedCapability, `${pointer}/properties/${propertyName}`, `Property "${propertyName}" must be a schema object.`);
357
+ }
358
+ const propertyResult = normalizeSchemaObject(loadedCapability, propertySchema, `${pointer}/properties/${propertyName}`, !requiredFields.has(propertyName), options);
359
+ if (!propertyResult.ok) {
360
+ return propertyResult;
361
+ }
362
+ normalizedProperties[propertyName] = propertyResult.schema;
363
+ }
364
+ normalized.properties = normalizedProperties;
365
+ normalized.required = Object.keys(normalizedProperties);
366
+ normalized.additionalProperties = false;
367
+ }
368
+ if (types.includes("array")) {
369
+ const items = schema.items;
370
+ if (items !== undefined) {
371
+ if (!isRecord(items)) {
372
+ return unsupportedSchema(loadedCapability, `${pointer}/items`, "Array items must be a single schema object.");
373
+ }
374
+ const itemResult = normalizeSchemaObject(loadedCapability, items, `${pointer}/items`, false, options);
375
+ if (!itemResult.ok) {
376
+ return itemResult;
377
+ }
378
+ normalized.items = itemResult.schema;
379
+ }
380
+ }
381
+ if (optional) {
382
+ const nullable = makeNullable(normalized);
383
+ if (!nullable.ok) {
384
+ return unsupportedSchema(loadedCapability, pointer, "Optional schema could not be represented as nullable for strict tool export.");
385
+ }
386
+ }
387
+ return {
388
+ diagnostics: [],
389
+ ok: true,
390
+ schema: normalized
391
+ };
392
+ }
393
+ function makeNullable(schema) {
394
+ const type = schema.type;
395
+ if (typeof type === "string") {
396
+ schema.type = type === "null" ? "null" : [type, "null"];
397
+ }
398
+ else if (Array.isArray(type) && type.every((entry) => typeof entry === "string")) {
399
+ if (!type.includes("null")) {
400
+ schema.type = [...type, "null"];
401
+ }
402
+ }
403
+ else if (!("enum" in schema)) {
404
+ return { ok: false };
405
+ }
406
+ const enumValue = schema.enum;
407
+ if (Array.isArray(enumValue) && !enumValue.includes(null)) {
408
+ schema.enum = [...enumValue, null];
409
+ }
410
+ return { ok: true };
411
+ }
412
+ function unsupportedSchema(loadedCapability, pointer, message) {
413
+ return {
414
+ diagnostics: [{
415
+ code: "unsupported",
416
+ details: {
417
+ pointer
418
+ },
419
+ id: loadedCapability.manifest.id,
420
+ kind: "capability",
421
+ message,
422
+ path: loadedCapability.path
423
+ }],
424
+ ok: false
425
+ };
426
+ }
427
+ function invalidToolCall(binding, path, message) {
428
+ return {
429
+ diagnostics: [{
430
+ code: "invalid_tool_call",
431
+ id: binding.capabilityId,
432
+ message,
433
+ path
434
+ }],
435
+ valid: false
436
+ };
437
+ }
438
+ function sanitizeToolNamePart(value) {
439
+ const sanitized = value.replace(/[^A-Za-z0-9_-]/g, "_");
440
+ return sanitized.length > 0 ? sanitized : "_";
441
+ }
442
+ function schemaTypes(value) {
443
+ if (typeof value === "string") {
444
+ return [value];
445
+ }
446
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
447
+ return value;
448
+ }
449
+ return [];
450
+ }
451
+ function isStringArray(value) {
452
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
453
+ }
@@ -0,0 +1,5 @@
1
+ import type { AiSdkToolCall, AiSdkToolNameOptions, AiSdkToolset, BuildAiSdkToolsOptions, ManifestRegistry, ParseAiSdkToolCallResult } from "./types.js";
2
+ export declare function buildAiSdkTools(registry: ManifestRegistry, options: BuildAiSdkToolsOptions): AiSdkToolset;
3
+ export declare function parseAiSdkToolCall(toolset: AiSdkToolset, call: AiSdkToolCall): ParseAiSdkToolCallResult;
4
+ export declare function toAiSdkToolName(capabilityId: string, options?: AiSdkToolNameOptions): string;
5
+ //# sourceMappingURL=ai-sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-sdk.d.ts","sourceRoot":"","sources":["../src/ai-sdk.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAKpB,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,sBAAsB,GAC9B,YAAY,CA8Bd;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,aAAa,GAClB,wBAAwB,CAqB1B;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,oBAAyB,GACjC,MAAM,CAKR"}
package/dist/ai-sdk.js ADDED
@@ -0,0 +1,71 @@
1
+ import { adapterToolDescription, buildAdapterToolset, isRecord, parseAdapterToolCall, toAdapterToolName } from "./adapter-common.js";
2
+ const defaultNamePrefix = "aicf_";
3
+ const maxToolNameLength = 64;
4
+ export function buildAiSdkTools(registry, options) {
5
+ const built = buildAdapterToolset({
6
+ adapterName: "Vercel AI SDK",
7
+ buildTool: ({ loadedCapability, normalizedInputSchema }) => ({
8
+ description: adapterToolDescription(loadedCapability.manifest),
9
+ inputSchema: normalizedInputSchema,
10
+ strict: true
11
+ }),
12
+ context: options.context,
13
+ defaultNamePrefix,
14
+ includeRestricted: options.includeRestricted,
15
+ maxToolNameLength,
16
+ namePrefix: options.namePrefix,
17
+ registry
18
+ });
19
+ const tools = {};
20
+ for (const [index, binding] of built.bindings.entries()) {
21
+ const tool = built.tools[index];
22
+ if (tool) {
23
+ tools[binding.toolName] = tool;
24
+ }
25
+ }
26
+ return {
27
+ bindings: built.bindings,
28
+ diagnostics: built.diagnostics,
29
+ excluded: built.excluded,
30
+ tools
31
+ };
32
+ }
33
+ export function parseAiSdkToolCall(toolset, call) {
34
+ const shapeError = validateAiSdkToolCall(call);
35
+ if (shapeError) {
36
+ return {
37
+ diagnostics: [{
38
+ code: "invalid_tool_call",
39
+ message: shapeError,
40
+ path: "toolCall"
41
+ }],
42
+ valid: false
43
+ };
44
+ }
45
+ return parseAdapterToolCall({
46
+ argumentsPath: call.input !== undefined ? "toolCall.input" : "toolCall.args",
47
+ bindings: toolset.bindings,
48
+ callId: call.toolCallId,
49
+ rawArguments: call.input ?? call.args,
50
+ toolName: call.toolName,
51
+ toolNamePath: "toolCall.toolName"
52
+ });
53
+ }
54
+ export function toAiSdkToolName(capabilityId, options = {}) {
55
+ return toAdapterToolName(capabilityId, {
56
+ maxLength: maxToolNameLength,
57
+ namePrefix: options.namePrefix ?? defaultNamePrefix
58
+ });
59
+ }
60
+ function validateAiSdkToolCall(call) {
61
+ if (!isRecord(call)) {
62
+ return "AI SDK tool call must be an object.";
63
+ }
64
+ if (typeof call.toolName !== "string" || call.toolName.length === 0) {
65
+ return "AI SDK tool call toolName is required.";
66
+ }
67
+ if (!isRecord(call.input ?? call.args)) {
68
+ return "AI SDK tool call input or args must be a JSON object.";
69
+ }
70
+ return null;
71
+ }
@@ -0,0 +1,5 @@
1
+ import type { AnthropicClaudeToolNameOptions, AnthropicClaudeToolset, AnthropicClaudeToolUse, BuildAnthropicClaudeToolsOptions, ManifestRegistry, ParseAnthropicClaudeToolUseResult } from "./types.js";
2
+ export declare function buildAnthropicClaudeTools(registry: ManifestRegistry, options: BuildAnthropicClaudeToolsOptions): AnthropicClaudeToolset;
3
+ export declare function parseAnthropicClaudeToolUse(toolset: AnthropicClaudeToolset, toolUse: AnthropicClaudeToolUse): ParseAnthropicClaudeToolUseResult;
4
+ export declare function toAnthropicClaudeToolName(capabilityId: string, options?: AnthropicClaudeToolNameOptions): string;
5
+ //# sourceMappingURL=anthropic-claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-claude.d.ts","sourceRoot":"","sources":["../src/anthropic-claude.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,8BAA8B,EAC9B,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,gBAAgB,EAChB,iCAAiC,EAClC,MAAM,YAAY,CAAC;AAKpB,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,gCAAgC,GACxC,sBAAsB,CAgBxB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,GAC9B,iCAAiC,CAqBnC;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,8BAAmC,GAC3C,MAAM,CAKR"}