@kindgi/capabilities 0.0.0-bootstrap.0 → 0.1.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.
@@ -0,0 +1,250 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://kindgi.com/schemas/v1/capability.schema.json",
4
+ "$comment": "schema-version: 1.1.0",
5
+ "title": "Capability declaration",
6
+ "description": "An agent's model requirements as declarative constraints. The model router matches capabilities against registered providers, respecting per-tenant policy. `defineCapability` validates a declaration against this schema; a declaration that no registered provider satisfies fails at routing time with `capability-unsatisfiable`.",
7
+ "type": "object",
8
+ "required": ["needs"],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "kind": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "default": "llm-inference",
15
+ "examples": ["llm-inference", "embedding", "gpu-compute", "sandbox-exec", "browser-session"],
16
+ "description": "Resource kind this capability requests. Open string: `examples` lists the well-known kinds, and adapters can declare their own. Absent means `llm-inference`. The router only considers providers whose `capabilityKind` equals it (a provider that declares none counts as `llm-inference`). Added in schema-version 1.1.0."
17
+ },
18
+ "needs": {
19
+ "type": "array",
20
+ "minItems": 1,
21
+ "items": {
22
+ "$ref": "#/$defs/Requirement"
23
+ }
24
+ },
25
+ "prefer": {
26
+ "type": "array",
27
+ "items": {
28
+ "$ref": "#/$defs/Preference"
29
+ },
30
+ "description": "Soft preferences: the router picks the highest-scoring model that also satisfies all 'needs'."
31
+ },
32
+ "budget": {
33
+ "$ref": "#/$defs/Budget",
34
+ "description": "Per-invocation budget. Declarative: carried with the declaration but not enforced by the runtime (per-turn spend is capped by the agent's `budget.maxCostUsd`)."
35
+ }
36
+ },
37
+ "$defs": {
38
+ "Requirement": {
39
+ "oneOf": [
40
+ {
41
+ "$ref": "#/$defs/FeatureRequirement"
42
+ },
43
+ {
44
+ "$ref": "#/$defs/ContextRequirement"
45
+ },
46
+ {
47
+ "$ref": "#/$defs/CostRequirement"
48
+ },
49
+ {
50
+ "$ref": "#/$defs/RegionRequirement"
51
+ },
52
+ {
53
+ "$ref": "#/$defs/LatencyRequirement"
54
+ },
55
+ {
56
+ "$ref": "#/$defs/ProviderRequirement"
57
+ },
58
+ {
59
+ "$ref": "#/$defs/ModelRequirement"
60
+ }
61
+ ]
62
+ },
63
+ "FeatureRequirement": {
64
+ "type": "object",
65
+ "required": ["feature"],
66
+ "additionalProperties": false,
67
+ "properties": {
68
+ "feature": {
69
+ "type": "string",
70
+ "enum": [
71
+ "structured-output",
72
+ "vision",
73
+ "audio-input",
74
+ "audio-output",
75
+ "tool-use",
76
+ "parallel-tool-use",
77
+ "thinking",
78
+ "long-context",
79
+ "code-execution",
80
+ "web-search",
81
+ "file-search",
82
+ "streaming",
83
+ "batch"
84
+ ]
85
+ }
86
+ }
87
+ },
88
+ "ContextRequirement": {
89
+ "type": "object",
90
+ "required": ["contextWindow"],
91
+ "additionalProperties": false,
92
+ "properties": {
93
+ "contextWindow": {
94
+ "type": "object",
95
+ "required": ["op", "value"],
96
+ "additionalProperties": false,
97
+ "properties": {
98
+ "op": {
99
+ "type": "string",
100
+ "enum": [">=", ">", "=", "<=", "<"]
101
+ },
102
+ "value": {
103
+ "type": "integer",
104
+ "minimum": 1
105
+ }
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "CostRequirement": {
111
+ "type": "object",
112
+ "required": ["costPerCall"],
113
+ "additionalProperties": false,
114
+ "properties": {
115
+ "costPerCall": {
116
+ "type": "object",
117
+ "required": ["op", "usd"],
118
+ "additionalProperties": false,
119
+ "properties": {
120
+ "op": {
121
+ "type": "string",
122
+ "enum": [">=", ">", "=", "<=", "<"]
123
+ },
124
+ "usd": {
125
+ "type": "number",
126
+ "minimum": 0
127
+ }
128
+ }
129
+ }
130
+ }
131
+ },
132
+ "RegionRequirement": {
133
+ "type": "object",
134
+ "required": ["region"],
135
+ "additionalProperties": false,
136
+ "properties": {
137
+ "region": {
138
+ "type": "string",
139
+ "description": "Geographic region constraint (e.g. 'eu-only', 'us-only', 'us-gov'). Enforced by the router against each provider's declared region; a tenant policy's `regionAllow` can constrain it further."
140
+ }
141
+ }
142
+ },
143
+ "LatencyRequirement": {
144
+ "type": "object",
145
+ "required": ["p95LatencyMs"],
146
+ "additionalProperties": false,
147
+ "properties": {
148
+ "p95LatencyMs": {
149
+ "type": "object",
150
+ "required": ["op", "value"],
151
+ "additionalProperties": false,
152
+ "properties": {
153
+ "op": {
154
+ "type": "string",
155
+ "enum": ["<=", "<"]
156
+ },
157
+ "value": {
158
+ "type": "integer",
159
+ "minimum": 0
160
+ }
161
+ }
162
+ }
163
+ }
164
+ },
165
+ "ProviderRequirement": {
166
+ "type": "object",
167
+ "required": ["providers"],
168
+ "additionalProperties": false,
169
+ "description": "Hard constraint on allowed providers (allowlist) or disallowed providers (denylist). Tenant policy can narrow the set further.",
170
+ "properties": {
171
+ "providers": {
172
+ "type": "object",
173
+ "additionalProperties": false,
174
+ "properties": {
175
+ "allow": {
176
+ "type": "array",
177
+ "items": {
178
+ "type": "string"
179
+ }
180
+ },
181
+ "deny": {
182
+ "type": "array",
183
+ "items": {
184
+ "type": "string"
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ },
191
+ "ModelRequirement": {
192
+ "type": "object",
193
+ "required": ["models"],
194
+ "additionalProperties": false,
195
+ "description": "Hard constraint on allowed models (allowlist) or disallowed models (denylist), matched against each provider's model names (`ModelInfo.name`). Can be combined with a providers requirement. Tenant policy can narrow the set further. Added in schema-version 1.1.0.",
196
+ "properties": {
197
+ "models": {
198
+ "type": "object",
199
+ "additionalProperties": false,
200
+ "properties": {
201
+ "allow": {
202
+ "type": "array",
203
+ "items": {
204
+ "type": "string"
205
+ }
206
+ },
207
+ "deny": {
208
+ "type": "array",
209
+ "items": {
210
+ "type": "string"
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+ },
217
+ "Preference": {
218
+ "type": "object",
219
+ "required": ["feature", "weight"],
220
+ "additionalProperties": false,
221
+ "properties": {
222
+ "feature": {
223
+ "type": "string",
224
+ "description": "A capability feature or a soft attribute (e.g. 'lower-cost', 'lower-latency', 'higher-accuracy')."
225
+ },
226
+ "weight": {
227
+ "type": "number"
228
+ }
229
+ }
230
+ },
231
+ "Budget": {
232
+ "type": "object",
233
+ "additionalProperties": false,
234
+ "properties": {
235
+ "maxCostUsd": {
236
+ "type": "number",
237
+ "minimum": 0
238
+ },
239
+ "maxTokens": {
240
+ "type": "integer",
241
+ "minimum": 0
242
+ },
243
+ "maxDurationMs": {
244
+ "type": "integer",
245
+ "minimum": 0
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
@@ -0,0 +1,13 @@
1
+ import type { Result } from '@kindgi/types';
2
+ import type { InvalidCapabilityError } from './errors.js';
3
+ import type { Capability } from './types.js';
4
+ /**
5
+ * Validate a capability declaration against `@kindgi/specs/capability.schema.json`
6
+ * and return a typed `Capability` on success. Called by pack authors at
7
+ * agent construction — a rejection here surfaces at pack init, well
8
+ * before any user request touches the flow.
9
+ */
10
+ export declare function defineCapability(spec: Capability): Result<Capability, InvalidCapabilityError>;
11
+ /** The `$id` of the JSON Schema this loader validates against. */
12
+ export declare const CAPABILITY_SCHEMA_URI = "https://kindgi.com/schemas/v1/capability.schema.json";
13
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB7C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAkB7F;AAED,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,yDAAuB,CAAC"}
package/dist/define.js ADDED
@@ -0,0 +1,45 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ import { createSpecRegistry } from '@kindgi/schema';
4
+ import capabilitySchema from './capability.schema.json' with { type: 'json' };
5
+ const CAPABILITY_SCHEMA_ID = 'https://kindgi.com/schemas/v1/capability.schema.json';
6
+ let cachedRegistry;
7
+ function registry() {
8
+ if (cachedRegistry !== undefined)
9
+ return cachedRegistry;
10
+ const built = createSpecRegistry([capabilitySchema]);
11
+ if (built.kind === 'err') {
12
+ throw new Error(`@kindgi/capabilities: bundled schema failed to compile: ${built.error.message}`);
13
+ }
14
+ cachedRegistry = built.value;
15
+ return cachedRegistry;
16
+ }
17
+ /**
18
+ * Validate a capability declaration against `@kindgi/specs/capability.schema.json`
19
+ * and return a typed `Capability` on success. Called by pack authors at
20
+ * agent construction — a rejection here surfaces at pack init, well
21
+ * before any user request touches the flow.
22
+ */
23
+ export function defineCapability(spec) {
24
+ const r = registry().validate(CAPABILITY_SCHEMA_ID, spec);
25
+ if (r.kind === 'ok')
26
+ return r;
27
+ const err = r.error;
28
+ if (err.code !== 'validation-error') {
29
+ throw new Error(`@kindgi/capabilities: unexpected schema error ${err.code}: ${err.message}`);
30
+ }
31
+ const issues = err.errors.map((e) => {
32
+ const ajv = e;
33
+ return {
34
+ path: typeof ajv.instancePath === 'string' ? ajv.instancePath : '',
35
+ message: typeof ajv.message === 'string' ? ajv.message : 'validation failed',
36
+ };
37
+ });
38
+ return {
39
+ kind: 'err',
40
+ error: { code: 'invalid-capability', message: err.message, issues },
41
+ };
42
+ }
43
+ /** The `$id` of the JSON Schema this loader validates against. */
44
+ export const CAPABILITY_SCHEMA_URI = CAPABILITY_SCHEMA_ID;
45
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIpD,OAAO,gBAAgB,MAAM,0BAA0B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAI9E,MAAM,oBAAoB,GAAG,sDAAsD,CAAC;AAEpF,IAAI,cAAwC,CAAC;AAC7C,SAAS,QAAQ;IACf,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC;IACxD,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,2DAA2D,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CACjF,CAAC;IACJ,CAAC;IACD,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC;IAC7B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC,QAAQ,CAAa,oBAAoB,EAAE,IAAI,CAAC,CAAC;IACtE,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;IACpB,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,iDAAiD,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAClC,MAAM,GAAG,GAAG,CAAkD,CAAC;QAC/D,OAAO;YACL,IAAI,EAAE,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;YAClE,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB;SAC7E,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE;KACpE,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC"}
@@ -0,0 +1,67 @@
1
+ import type { TenantId } from '@kindgi/types';
2
+ /**
3
+ * Errors emitted by @kindgi/capabilities. Every variant carries a `code`
4
+ * for pattern matching; messages are human-readable, not API contract.
5
+ */
6
+ export type CapabilityError = InvalidCapabilityError | InvalidProviderError | DuplicateProviderError | CapabilityUnsatisfiableError | BudgetExceededError;
7
+ /** `defineCapability` rejected the declaration shape (schema mismatch). */
8
+ export interface InvalidCapabilityError {
9
+ readonly code: 'invalid-capability';
10
+ readonly message: string;
11
+ readonly issues: readonly {
12
+ readonly path: string;
13
+ readonly message: string;
14
+ }[];
15
+ }
16
+ /** Provider registration (`createProviderRegistry(...).register`) rejected the metadata shape. */
17
+ export interface InvalidProviderError {
18
+ readonly code: 'invalid-provider';
19
+ readonly message: string;
20
+ readonly reason: string;
21
+ }
22
+ /** Provider registration was called with an id already registered for the tenant. */
23
+ export interface DuplicateProviderError {
24
+ readonly code: 'duplicate-provider';
25
+ readonly message: string;
26
+ readonly providerId: string;
27
+ }
28
+ /**
29
+ * The router couldn't find any provider satisfying the capability
30
+ * declaration + tenant policy. `reasons` explains which requirement
31
+ * rejected which `(provider, model)` candidate.
32
+ */
33
+ export interface CapabilityUnsatisfiableError {
34
+ readonly code: 'capability-unsatisfiable';
35
+ readonly message: string;
36
+ /**
37
+ * One entry per requirement, indicating which providers matched
38
+ * and which didn't. Each rejection carries a structured
39
+ * `RejectionReason` — callers can `switch (r.reason.code)` to route
40
+ * on specific failure modes (e.g. surface an "add region" tip when
41
+ * every failure is `region-mismatch`).
42
+ */
43
+ readonly reasons: readonly {
44
+ readonly requirement: string;
45
+ readonly satisfyingProviders: readonly string[];
46
+ readonly rejectingProviders: readonly {
47
+ readonly id: string;
48
+ readonly reason: import('./types.js').RejectionReason;
49
+ }[];
50
+ }[];
51
+ readonly tenantId?: TenantId;
52
+ }
53
+ /**
54
+ * A model invocation exceeded the caller's declared `budget`. Cost meter
55
+ * emits this either pre-flight (if the estimated cost is already over
56
+ * budget) or post-flight (if actual cost overran).
57
+ */
58
+ export interface BudgetExceededError {
59
+ readonly code: 'budget-exceeded';
60
+ readonly message: string;
61
+ readonly limit: {
62
+ readonly kind: 'cost' | 'tokens' | 'duration';
63
+ readonly value: number;
64
+ };
65
+ readonly actual: number;
66
+ }
67
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,sBAAsB,GACtB,oBAAoB,GACpB,sBAAsB,GACtB,4BAA4B,GAC5B,mBAAmB,CAAC;AAExB,2EAA2E;AAC3E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjF;AAED,kGAAkG;AAClG,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS;QACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;QAChD,QAAQ,CAAC,kBAAkB,EAAE,SAAS;YACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;YACpB,QAAQ,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,eAAe,CAAC;SACvD,EAAE,CAAC;KACL,EAAE,CAAC;IACJ,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB"}
package/dist/errors.js ADDED
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ export {};
4
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
@@ -0,0 +1,10 @@
1
+ export { createAdapterFactoryRegistry } from './adapter-factory.js';
2
+ export type { AdapterConfig, AdapterFactory, AdapterFactoryEntry, AdapterFactoryInput, AdapterFactoryRegistry, PrepareEvent, } from './adapter-factory.js';
3
+ export { CAPABILITY_SCHEMA_URI, defineCapability } from './define.js';
4
+ export { createProviderRegistry } from './registry.js';
5
+ export { matchTuples, route } from './router.js';
6
+ export type { RouteInput } from './router.js';
7
+ export { BUILT_IN_CAPABILITY_KINDS, DEFAULT_CAPABILITY_KIND, FEATURES } from './types.js';
8
+ export type { Budget, BuiltInCapabilityKind, Capability, CapabilityKind, ComparisonOp, Feature, ModelCallInput, ModelCallResult, ModelMessage, ModelInfo, ModelProvider, ModelToolCall, ModelToolDefinition, Preference, ProviderMetadata, ProviderModelPick, ProviderRegistry, RejectionReason, Requirement, RoutingDecision, StructuredOutputRequest, TenantPolicy, UpperBoundOp, UsageCounters, } from './types.js';
9
+ export type { BudgetExceededError, CapabilityError, CapabilityUnsatisfiableError, DuplicateProviderError, InvalidCapabilityError, InvalidProviderError, } from './errors.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,YAAY,EACV,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,YAAY,GACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC1F,YAAY,EACV,MAAM,EACN,qBAAqB,EACrB,UAAU,EACV,cAAc,EACd,YAAY,EACZ,OAAO,EACP,cAAc,EACd,eAAe,EACf,YAAY,EACZ,SAAS,EACT,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,eAAe,EACf,uBAAuB,EACvB,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ export { createAdapterFactoryRegistry } from './adapter-factory.js';
4
+ export { CAPABILITY_SCHEMA_URI, defineCapability } from './define.js';
5
+ export { createProviderRegistry } from './registry.js';
6
+ export { matchTuples, route } from './router.js';
7
+ export { BUILT_IN_CAPABILITY_KINDS, DEFAULT_CAPABILITY_KIND, FEATURES } from './types.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AASpE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Result, TenantId } from '@kindgi/types';
2
+ import type { CapabilityError } from './errors.js';
3
+ import type { ModelProvider, ProviderRegistry } from './types.js';
4
+ /**
5
+ * Create an in-memory registry of model providers. Tenant-scoped:
6
+ * each tenant owns its own `providerId → ModelProvider` map. The
7
+ * router receives a tenant's slice, so cross-tenant leakage is
8
+ * impossible at the routing layer.
9
+ *
10
+ * Registration is validated for shape: provider `id` + `region`
11
+ * non-empty; `models[]` non-empty with unique `name` per entry;
12
+ * per-model `contextWindow` positive integer; per-model `cost`
13
+ * non-negative; optional per-model `p95LatencyMs` / `maxOutputTokens`
14
+ * well-shaped; `invoke` is a function. Duplicate ids within a tenant
15
+ * are refused — accidental clobber of a running provider would be
16
+ * catastrophic under a live workload. The same `providerId` may be
17
+ * registered under different tenants (that's the whole point).
18
+ */
19
+ export declare function createProviderRegistry(seed?: readonly {
20
+ readonly tenantId: TenantId;
21
+ readonly provider: ModelProvider;
22
+ }[]): {
23
+ readonly registry: ProviderRegistry;
24
+ register(tenantId: TenantId, provider: ModelProvider): Result<void, CapabilityError>;
25
+ };
26
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAgD,MAAM,aAAa,CAAC;AACjG,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,GAAE,SAAS;IAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,EAAO,GACtF;IACD,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;CACtF,CAsJA"}
@@ -0,0 +1,156 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * Create an in-memory registry of model providers. Tenant-scoped:
5
+ * each tenant owns its own `providerId → ModelProvider` map. The
6
+ * router receives a tenant's slice, so cross-tenant leakage is
7
+ * impossible at the routing layer.
8
+ *
9
+ * Registration is validated for shape: provider `id` + `region`
10
+ * non-empty; `models[]` non-empty with unique `name` per entry;
11
+ * per-model `contextWindow` positive integer; per-model `cost`
12
+ * non-negative; optional per-model `p95LatencyMs` / `maxOutputTokens`
13
+ * well-shaped; `invoke` is a function. Duplicate ids within a tenant
14
+ * are refused — accidental clobber of a running provider would be
15
+ * catastrophic under a live workload. The same `providerId` may be
16
+ * registered under different tenants (that's the whole point).
17
+ */
18
+ export function createProviderRegistry(seed = []) {
19
+ const byTenant = new Map();
20
+ function tenantMap(tenantId) {
21
+ let m = byTenant.get(tenantId);
22
+ if (m === undefined) {
23
+ m = new Map();
24
+ byTenant.set(tenantId, m);
25
+ }
26
+ return m;
27
+ }
28
+ function validate(p) {
29
+ if (typeof p.metadata.id !== 'string' || p.metadata.id.length === 0) {
30
+ return {
31
+ code: 'invalid-provider',
32
+ message: 'provider.metadata.id required',
33
+ reason: 'empty-id',
34
+ };
35
+ }
36
+ if (typeof p.metadata.region !== 'string' || p.metadata.region.length === 0) {
37
+ return {
38
+ code: 'invalid-provider',
39
+ message: `provider "${p.metadata.id}" missing metadata.region`,
40
+ reason: 'empty-region',
41
+ };
42
+ }
43
+ if (!Array.isArray(p.metadata.models) || p.metadata.models.length === 0) {
44
+ return {
45
+ code: 'invalid-provider',
46
+ message: `provider "${p.metadata.id}" must expose at least one model in metadata.models[]`,
47
+ reason: 'empty-models',
48
+ };
49
+ }
50
+ const seenNames = new Set();
51
+ for (const m of p.metadata.models) {
52
+ if (typeof m.name !== 'string' || m.name.length === 0) {
53
+ return {
54
+ code: 'invalid-provider',
55
+ message: `provider "${p.metadata.id}" has a model with empty name`,
56
+ reason: 'empty-model-name',
57
+ };
58
+ }
59
+ if (seenNames.has(m.name)) {
60
+ return {
61
+ code: 'invalid-provider',
62
+ message: `provider "${p.metadata.id}" declares model "${m.name}" more than once in metadata.models[]`,
63
+ reason: 'duplicate-model-name',
64
+ };
65
+ }
66
+ seenNames.add(m.name);
67
+ if (typeof m.contextWindow !== 'number' ||
68
+ m.contextWindow <= 0 ||
69
+ !Number.isInteger(m.contextWindow)) {
70
+ return {
71
+ code: 'invalid-provider',
72
+ message: `provider "${p.metadata.id}" model "${m.name}" contextWindow must be a positive integer`,
73
+ reason: 'invalid-context-window',
74
+ };
75
+ }
76
+ if (typeof m.cost?.promptUsdPer1kTokens !== 'number' ||
77
+ m.cost.promptUsdPer1kTokens < 0 ||
78
+ typeof m.cost.completionUsdPer1kTokens !== 'number' ||
79
+ m.cost.completionUsdPer1kTokens < 0) {
80
+ return {
81
+ code: 'invalid-provider',
82
+ message: `provider "${p.metadata.id}" model "${m.name}" cost table must have non-negative promptUsdPer1kTokens + completionUsdPer1kTokens`,
83
+ reason: 'invalid-cost',
84
+ };
85
+ }
86
+ if (m.p95LatencyMs !== undefined &&
87
+ (typeof m.p95LatencyMs !== 'number' || m.p95LatencyMs < 0)) {
88
+ return {
89
+ code: 'invalid-provider',
90
+ message: `provider "${p.metadata.id}" model "${m.name}" p95LatencyMs must be a non-negative number`,
91
+ reason: 'invalid-p95-latency',
92
+ };
93
+ }
94
+ if (m.maxOutputTokens !== undefined &&
95
+ (typeof m.maxOutputTokens !== 'number' ||
96
+ m.maxOutputTokens <= 0 ||
97
+ !Number.isInteger(m.maxOutputTokens))) {
98
+ return {
99
+ code: 'invalid-provider',
100
+ message: `provider "${p.metadata.id}" model "${m.name}" maxOutputTokens must be a positive integer`,
101
+ reason: 'invalid-max-output-tokens',
102
+ };
103
+ }
104
+ }
105
+ if (typeof p.invoke !== 'function') {
106
+ return {
107
+ code: 'invalid-provider',
108
+ message: `provider "${p.metadata.id}" invoke must be a function`,
109
+ reason: 'invalid-invoke',
110
+ };
111
+ }
112
+ return undefined;
113
+ }
114
+ function register(tenantId, provider) {
115
+ const invalid = validate(provider);
116
+ if (invalid !== undefined)
117
+ return { kind: 'err', error: invalid };
118
+ const m = tenantMap(tenantId);
119
+ if (m.has(provider.metadata.id)) {
120
+ const dup = {
121
+ code: 'duplicate-provider',
122
+ message: `Provider "${provider.metadata.id}" is already registered for tenant "${tenantId}"`,
123
+ providerId: provider.metadata.id,
124
+ };
125
+ return { kind: 'err', error: dup };
126
+ }
127
+ m.set(provider.metadata.id, provider);
128
+ return { kind: 'ok', value: undefined };
129
+ }
130
+ const registry = {
131
+ register(tenantId, provider) {
132
+ const r = register(tenantId, provider);
133
+ if (r.kind === 'err')
134
+ throw new Error(r.error.message);
135
+ },
136
+ get(tenantId, id) {
137
+ return byTenant.get(tenantId)?.get(id);
138
+ },
139
+ list(tenantId) {
140
+ const m = byTenant.get(tenantId);
141
+ if (m === undefined)
142
+ return [];
143
+ return [...m.values()];
144
+ },
145
+ has(tenantId, id) {
146
+ return byTenant.get(tenantId)?.has(id) ?? false;
147
+ },
148
+ };
149
+ for (const entry of seed) {
150
+ const r = register(entry.tenantId, entry.provider);
151
+ if (r.kind === 'err')
152
+ throw new Error(`seed provider "${entry.provider.metadata.id}" rejected for tenant "${entry.tenantId}": ${r.error.message}`);
153
+ }
154
+ return { registry, register };
155
+ }
156
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}