ai-workflow-contract 0.2.0 → 0.2.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.
- package/package.json +2 -2
- package/src/agent-code.ts +46 -0
- package/src/index.ts +51 -1
- package/src/resource-kind-contracts.ts +156 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-workflow-contract",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared AI workflow contracts over WorkCtrlFlow and EagerDataFlow substrates",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"eager-data-flow-contract": "0.1.4",
|
|
13
|
-
"halfcode-compiler.xnl": "0.3.
|
|
13
|
+
"halfcode-compiler.xnl": "0.3.1",
|
|
14
14
|
"task-manager-contract": "0.1.3",
|
|
15
15
|
"work-ctrl-flow-contract": "0.1.3"
|
|
16
16
|
},
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CodeBinding, FrozenCodeClosure } from 'halfcode-compiler.xnl/application-assembly';
|
|
2
|
+
import type { ResourceRecord, Sha256Digest } from 'halfcode-compiler.xnl/resource-core';
|
|
3
|
+
import type { FlowClosedObject } from 'work-ctrl-flow-contract';
|
|
4
|
+
import type { AIWorkflowTypedResourceRef } from './index.js';
|
|
5
|
+
|
|
6
|
+
export type AIAgentCodeResourceKind = 'AgentContextPipeline' | 'AgentMessageSource';
|
|
7
|
+
/** Closed identity derived from the actual native resolver output. */
|
|
8
|
+
export interface AIAgentResolvedResourceIdentity {
|
|
9
|
+
readonly resourceId: string;
|
|
10
|
+
readonly readerId: string;
|
|
11
|
+
readonly readerSpecVersion: number;
|
|
12
|
+
readonly effectiveContentDigest: Sha256Digest;
|
|
13
|
+
readonly readerProfileId: string;
|
|
14
|
+
readonly resolutionReceiptDigest: Sha256Digest;
|
|
15
|
+
}
|
|
16
|
+
interface AIAgentCodeProjectionBase {
|
|
17
|
+
readonly kind: AIAgentCodeResourceKind;
|
|
18
|
+
readonly resource: ResourceRecord;
|
|
19
|
+
readonly config: FlowClosedObject;
|
|
20
|
+
readonly assets: Readonly<Record<string, 'text' | 'json'>>;
|
|
21
|
+
readonly dependencies: readonly AIWorkflowTypedResourceRef[];
|
|
22
|
+
}
|
|
23
|
+
export type AIAgentCodeResourceProjection = AIAgentCodeProjectionBase & (
|
|
24
|
+
| { readonly mode: 'native'; readonly binding: CodeBinding }
|
|
25
|
+
| { readonly mode: 'legacy'; readonly content: string }
|
|
26
|
+
);
|
|
27
|
+
export interface FrozenAIAgentCodeArtifact {
|
|
28
|
+
readonly resourceResolution?: AIAgentResolvedResourceIdentity;
|
|
29
|
+
readonly schemaVersion: 'ai-workflow.agent-code-artifact/v1';
|
|
30
|
+
readonly resourceId: string;
|
|
31
|
+
readonly resourceDigest: Sha256Digest;
|
|
32
|
+
readonly config: FlowClosedObject;
|
|
33
|
+
readonly closure: FrozenCodeClosure;
|
|
34
|
+
}
|
|
35
|
+
export interface AIAgentCodeExecutionIdentity {
|
|
36
|
+
readonly resourceId: string;
|
|
37
|
+
readonly resourceDigest: Sha256Digest;
|
|
38
|
+
readonly artifactDigest: Sha256Digest;
|
|
39
|
+
readonly closureDigest: string;
|
|
40
|
+
}
|
|
41
|
+
/** Runtime handle. Persist artifact/identity, never the callable. */
|
|
42
|
+
export interface CompiledAIAgentCodeExecution {
|
|
43
|
+
readonly artifact: FrozenAIAgentCodeArtifact;
|
|
44
|
+
readonly artifactDigest: Sha256Digest;
|
|
45
|
+
readonly execute: (runtime: unknown, input: unknown) => unknown;
|
|
46
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
|
|
25
25
|
export * from './holon-task.js';
|
|
26
26
|
export * from './resource-kind-contracts.js';
|
|
27
|
+
export * from './agent-code.js';
|
|
27
28
|
|
|
28
29
|
export {
|
|
29
30
|
FLOW_INSTANCE_SCHEMA_VERSION,
|
|
@@ -260,6 +261,7 @@ export interface MaterialBindingProjection {
|
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
export interface AIWorkflowAgentResourceProjection {
|
|
264
|
+
readonly codeResources?: readonly import('./agent-code.js').AIAgentCodeResourceProjection[];
|
|
263
265
|
readonly agentDefinitions: readonly AIAgentDefinitionProjection[];
|
|
264
266
|
readonly materialPorts: readonly MaterialPortProjection[];
|
|
265
267
|
readonly materialBindings: readonly MaterialBindingProjection[];
|
|
@@ -267,6 +269,8 @@ export interface AIWorkflowAgentResourceProjection {
|
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
export interface AIWorkflowRunResourceFreezeReceipt {
|
|
272
|
+
readonly resourceResolutions?: readonly import('./agent-code.js').AIAgentResolvedResourceIdentity[];
|
|
273
|
+
readonly codeExecutions?: readonly import('./agent-code.js').AIAgentCodeExecutionIdentity[];
|
|
270
274
|
readonly schemaVersion: 'ai-workflow.run-resource-freeze/v1';
|
|
271
275
|
readonly task: AIWorkflowAgentTaskRef;
|
|
272
276
|
readonly bindingResourceIds: readonly string[];
|
|
@@ -276,6 +280,8 @@ export interface AIWorkflowRunResourceFreezeReceipt {
|
|
|
276
280
|
|
|
277
281
|
/** In-memory proof projected only from an admitted run-resource freeze receipt. */
|
|
278
282
|
export interface FrozenAIAgentTaskBinding {
|
|
283
|
+
readonly resourceResolutions?: readonly import('./agent-code.js').AIAgentResolvedResourceIdentity[];
|
|
284
|
+
readonly codeExecutions?: readonly import('./agent-code.js').AIAgentCodeExecutionIdentity[];
|
|
279
285
|
readonly schemaVersion: 'ai-workflow.frozen-agent-task-binding/v1';
|
|
280
286
|
readonly task: AIWorkflowAgentTaskRef;
|
|
281
287
|
readonly semanticFingerprint: Sha256Digest;
|
|
@@ -323,6 +329,13 @@ export interface AIAgentDefinitionAuthoringEvidence {
|
|
|
323
329
|
readonly planDigest: Sha256Digest;
|
|
324
330
|
readonly transactionId: string;
|
|
325
331
|
readonly receiptDigest: Sha256Digest;
|
|
332
|
+
readonly revision?: {
|
|
333
|
+
readonly candidateRef: `resource://${string}`;
|
|
334
|
+
readonly candidateDigest: Sha256Digest;
|
|
335
|
+
readonly contentDigest: Sha256Digest;
|
|
336
|
+
readonly registryRevision: Sha256Digest;
|
|
337
|
+
readonly feedback: AIAgentDefinitionRevisionFeedback;
|
|
338
|
+
};
|
|
326
339
|
}
|
|
327
340
|
|
|
328
341
|
export interface AIAgentDefinitionCandidate {
|
|
@@ -363,9 +376,30 @@ export interface AuthorNewAIAgentDefinitionDecision
|
|
|
363
376
|
readonly proposal: ResourceAuthoringProposal;
|
|
364
377
|
}
|
|
365
378
|
|
|
379
|
+
/** Upstream causal references, never diagnostic or publication authority. */
|
|
380
|
+
export interface AIAgentDefinitionRevisionFeedback {
|
|
381
|
+
readonly observationRef: string;
|
|
382
|
+
readonly attemptRef: string;
|
|
383
|
+
readonly verificationRef: string;
|
|
384
|
+
readonly requirementDigest: Sha256Digest;
|
|
385
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
386
|
+
readonly candidateDigest: Sha256Digest;
|
|
387
|
+
readonly previousExecutionFingerprint: Sha256Digest;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface ReviseExistingAIAgentDefinitionDecision
|
|
391
|
+
extends AIAgentDefinitionSelectionDecisionBase {
|
|
392
|
+
readonly mode: 'revise-existing';
|
|
393
|
+
readonly candidateRef: `resource://${string}`;
|
|
394
|
+
readonly candidateDigest: Sha256Digest;
|
|
395
|
+
readonly feedback: AIAgentDefinitionRevisionFeedback;
|
|
396
|
+
readonly proposal: ResourceAuthoringProposal;
|
|
397
|
+
}
|
|
398
|
+
|
|
366
399
|
export type AIAgentDefinitionSelectionDecision =
|
|
367
400
|
| SelectExistingAIAgentDefinitionDecision
|
|
368
|
-
| AuthorNewAIAgentDefinitionDecision
|
|
401
|
+
| AuthorNewAIAgentDefinitionDecision
|
|
402
|
+
| ReviseExistingAIAgentDefinitionDecision;
|
|
369
403
|
|
|
370
404
|
export type AIAgentDefinitionSelectionRejectionCode =
|
|
371
405
|
| 'decision-invalid'
|
|
@@ -375,6 +409,9 @@ export type AIAgentDefinitionSelectionRejectionCode =
|
|
|
375
409
|
| 'candidate-digest-mismatch'
|
|
376
410
|
| 'candidate-incompatible'
|
|
377
411
|
| 'authoring-in-progress'
|
|
412
|
+
| 'selection-owner-required'
|
|
413
|
+
| 'selection-owner-mismatch'
|
|
414
|
+
| 'revision-feedback-invalid'
|
|
378
415
|
| 'authoring-proposal-invalid';
|
|
379
416
|
|
|
380
417
|
export interface SelectedAIAgentDefinitionAdmission {
|
|
@@ -396,6 +433,18 @@ export interface AuthorNewAIAgentDefinitionAdmission {
|
|
|
396
433
|
readonly reason: string;
|
|
397
434
|
}
|
|
398
435
|
|
|
436
|
+
export interface ReviseExistingAIAgentDefinitionAdmission {
|
|
437
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
438
|
+
readonly status: 'revision-request';
|
|
439
|
+
readonly requirementDigest: Sha256Digest;
|
|
440
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
441
|
+
readonly agentDefinitionRef: `resource://${string}`;
|
|
442
|
+
readonly candidate: AIAgentDefinitionCandidate;
|
|
443
|
+
readonly feedback: AIAgentDefinitionRevisionFeedback;
|
|
444
|
+
readonly proposal: ResourceAuthoringProposal;
|
|
445
|
+
readonly reason: string;
|
|
446
|
+
}
|
|
447
|
+
|
|
399
448
|
export interface RejectedAIAgentDefinitionAdmission {
|
|
400
449
|
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
401
450
|
readonly status: 'rejected';
|
|
@@ -406,6 +455,7 @@ export interface RejectedAIAgentDefinitionAdmission {
|
|
|
406
455
|
export type AIAgentDefinitionSelectionAdmission =
|
|
407
456
|
| SelectedAIAgentDefinitionAdmission
|
|
408
457
|
| AuthorNewAIAgentDefinitionAdmission
|
|
458
|
+
| ReviseExistingAIAgentDefinitionAdmission
|
|
409
459
|
| RejectedAIAgentDefinitionAdmission;
|
|
410
460
|
|
|
411
461
|
export type AIWorkflowNodeType =
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type KindSpecRevision,
|
|
7
7
|
type KindSubjectOwner,
|
|
8
8
|
type PortableSpec,
|
|
9
|
+
type SpecResolutionDefinition,
|
|
9
10
|
} from 'halfcode-compiler.xnl/resource-core';
|
|
10
11
|
import {
|
|
11
12
|
createKindSpecRevision,
|
|
@@ -148,6 +149,91 @@ function authoredSpecSchema(kind: DepaAIResourceKind): JsonSchema {
|
|
|
148
149
|
});
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
/** Native code recipes have a separate writer contract; legacy Content stays spec 1. */
|
|
153
|
+
function nativeCodeSpecSchema(): JsonSchema {
|
|
154
|
+
const string = Object.freeze({ type: 'string', minLength: 1, pattern: '^\\S(?:[\\s\\S]*\\S)?$' });
|
|
155
|
+
const emptyObject = Object.freeze({ type: 'object', properties: Object.freeze({}), additionalProperties: false });
|
|
156
|
+
const emptyBody = Object.freeze({ type: 'array', maxItems: 0 });
|
|
157
|
+
const node = (tag: string, properties: JsonSchema, body: JsonSchema = emptyBody): JsonSchema => Object.freeze({
|
|
158
|
+
type: 'object',
|
|
159
|
+
required: Object.freeze(['tag', 'metadata', 'properties', 'body', 'subdomains']),
|
|
160
|
+
properties: Object.freeze({
|
|
161
|
+
tag: Object.freeze({ const: tag }),
|
|
162
|
+
resourceId: string,
|
|
163
|
+
metadata: emptyObject,
|
|
164
|
+
properties,
|
|
165
|
+
body,
|
|
166
|
+
subdomains: emptyObject,
|
|
167
|
+
}),
|
|
168
|
+
additionalProperties: false,
|
|
169
|
+
});
|
|
170
|
+
const closedProperties = (properties: Readonly<Record<string, JsonSchema>>, required = Object.keys(properties)): JsonSchema => Object.freeze({
|
|
171
|
+
type: 'object', required: Object.freeze(required), properties: Object.freeze(properties), additionalProperties: false,
|
|
172
|
+
});
|
|
173
|
+
return Object.freeze({
|
|
174
|
+
type: 'object',
|
|
175
|
+
required: Object.freeze(['properties', 'body', 'subdomains']),
|
|
176
|
+
properties: Object.freeze({
|
|
177
|
+
properties: closedProperties({ lifecycle: string, description: Object.freeze({ type: 'string' }) }, []),
|
|
178
|
+
body: emptyBody,
|
|
179
|
+
subdomains: closedProperties({
|
|
180
|
+
CodeBinding: node('CodeBinding', closedProperties({ packageName: string, module: string, exportName: string })),
|
|
181
|
+
Config: node('Config', closedProperties({ value: Object.freeze({ type: 'object' }) })),
|
|
182
|
+
Assets: node('Assets', emptyObject, Object.freeze({
|
|
183
|
+
type: 'array',
|
|
184
|
+
items: node('Asset', closedProperties({ path: string, format: Object.freeze({ enum: Object.freeze(['text', 'json']) }) })),
|
|
185
|
+
})),
|
|
186
|
+
DependencyRefs: node('DependencyRefs', emptyObject, Object.freeze({
|
|
187
|
+
type: 'array',
|
|
188
|
+
items: node('DependencyRef', closedProperties({
|
|
189
|
+
kind: string,
|
|
190
|
+
ref: Object.freeze({ type: 'string', pattern: '^resource://\\S+$' }),
|
|
191
|
+
})),
|
|
192
|
+
})),
|
|
193
|
+
}, ['CodeBinding']),
|
|
194
|
+
}),
|
|
195
|
+
additionalProperties: false,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function codeRecipeSpecSchema(kind: DepaAIResourceKind): JsonSchema {
|
|
200
|
+
const legacy = authoredSpecSchema(kind) as Readonly<Record<string, unknown>>;
|
|
201
|
+
return Object.freeze({
|
|
202
|
+
oneOf: Object.freeze([
|
|
203
|
+
nativeCodeSpecSchema(),
|
|
204
|
+
Object.freeze({
|
|
205
|
+
...legacy,
|
|
206
|
+
properties: Object.freeze({
|
|
207
|
+
...(legacy.properties as Readonly<Record<string, unknown>>),
|
|
208
|
+
subdomains: Object.freeze({
|
|
209
|
+
type: 'object', required: Object.freeze(['Content']),
|
|
210
|
+
properties: Object.freeze({ CodeBinding: false }),
|
|
211
|
+
}),
|
|
212
|
+
}),
|
|
213
|
+
}),
|
|
214
|
+
]),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function nativeCodeSemanticContract(kind: DepaAIResourceKind): KindSemanticContract {
|
|
219
|
+
const authority = 'ai-workflow-contract/depa-ai-resource-kinds/v2';
|
|
220
|
+
return Object.freeze({
|
|
221
|
+
semanticValidatorFingerprint: digestCanonical(Object.freeze({
|
|
222
|
+
authority, kind, role: 'closed-native-code-recipe-validation',
|
|
223
|
+
fields: Object.freeze(['CodeBinding', 'Config', 'Assets', 'DependencyRefs']),
|
|
224
|
+
config: 'closed-json-object', assets: 'source-root-relative-text-or-json',
|
|
225
|
+
legacy: 'exclusive-Content-requires-explicit-compatibility-resolver',
|
|
226
|
+
})),
|
|
227
|
+
referenceProjectionFingerprint: digestCanonical(Object.freeze({
|
|
228
|
+
authority, kind, role: 'typed-resource-reference-projection', relations: Object.freeze(['code-dependency']),
|
|
229
|
+
})),
|
|
230
|
+
compilerInputFingerprint: digestCanonical(Object.freeze({
|
|
231
|
+
authority, kind, role: 'native-code-binding-and-frozen-closure-projection',
|
|
232
|
+
fields: Object.freeze(['packageName', 'module', 'exportName', 'config', 'assets', 'dependencyRefs']),
|
|
233
|
+
})),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
151
237
|
function semanticContract(kind: DepaAIResourceKind): KindSemanticContract {
|
|
152
238
|
return Object.freeze({
|
|
153
239
|
semanticValidatorFingerprint: digestCanonical(Object.freeze({
|
|
@@ -175,26 +261,26 @@ function readerRegistration(
|
|
|
175
261
|
kind: DepaAIResourceKind,
|
|
176
262
|
revision: KindSpecRevision,
|
|
177
263
|
): KindReaderRegistration<PortableSpec> {
|
|
178
|
-
const readerId = `ai-workflow-contract.${kind}.reader.
|
|
264
|
+
const readerId = `ai-workflow-contract.${kind}.reader.v${revision.specVersion}`;
|
|
179
265
|
return Object.freeze({
|
|
180
266
|
readerId,
|
|
181
267
|
subjectFqn: revision.subjectFqn,
|
|
182
268
|
readerSpecVersion: revision.specVersion,
|
|
183
269
|
contractFingerprint: revision.contractFingerprint,
|
|
184
270
|
readerImplementationFingerprint: digestCanonical(Object.freeze({
|
|
185
|
-
authority:
|
|
271
|
+
authority: `ai-workflow-contract/depa-ai-resource-kinds/v${revision.specVersion}`,
|
|
186
272
|
readerId,
|
|
187
273
|
kind,
|
|
188
274
|
contractFingerprint: revision.contractFingerprint,
|
|
189
275
|
operations: KIND_SEMANTIC_OPERATIONS[kind],
|
|
190
276
|
implementation: 'identity-read-of-halfcode-validated-portable-spec',
|
|
191
277
|
})),
|
|
192
|
-
compatibilityPolicy: 'exact',
|
|
278
|
+
compatibilityPolicy: revision.specVersion === 1 ? 'exact' : 'backward-transitive',
|
|
193
279
|
read: (spec: PortableSpec): PortableSpec => spec,
|
|
194
280
|
});
|
|
195
281
|
}
|
|
196
282
|
|
|
197
|
-
function renderKindDefinition(owner: KindSubjectOwner,
|
|
283
|
+
function renderKindDefinition(owner: KindSubjectOwner, revisions: readonly KindSpecRevision[]): string {
|
|
198
284
|
return [
|
|
199
285
|
`<KindDefinition #${owner.subjectFqn} envelopeVersion="${DEPA_AI_RESOURCE_ENVELOPE_VERSION}" specVersion=1 {`,
|
|
200
286
|
' lifecycle = "Stable"',
|
|
@@ -205,16 +291,18 @@ function renderKindDefinition(owner: KindSubjectOwner, revision: KindSpecRevisio
|
|
|
205
291
|
` description = "Canonical depa-flows ${owner.kind} resource contract."`,
|
|
206
292
|
'} (',
|
|
207
293
|
' <SpecRevisions [',
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
294
|
+
...revisions.flatMap((revision) => [
|
|
295
|
+
` <SpecRevision #v${revision.specVersion} {`,
|
|
296
|
+
` specVersion = ${revision.specVersion}`,
|
|
297
|
+
` schemaRef = "vfs://./spec-v${revision.specVersion}.schema.json"`,
|
|
298
|
+
` schemaFingerprint = "${revision.schemaFingerprint}"`,
|
|
299
|
+
` contractFingerprint = "${revision.contractFingerprint}"`,
|
|
300
|
+
` semanticValidatorFingerprint = "${revision.semanticContract.semanticValidatorFingerprint}"`,
|
|
301
|
+
` referenceProjectionFingerprint = "${revision.semanticContract.referenceProjectionFingerprint}"`,
|
|
302
|
+
` compilerInputFingerprint = "${revision.semanticContract.compilerInputFingerprint}"`,
|
|
303
|
+
` stability = "${revision.stability}"`,
|
|
304
|
+
' }>',
|
|
305
|
+
]),
|
|
218
306
|
' ]>',
|
|
219
307
|
')>',
|
|
220
308
|
'',
|
|
@@ -246,16 +334,36 @@ function createContract(kind: DepaAIResourceKind): DepaAIResourceKindContract {
|
|
|
246
334
|
owner,
|
|
247
335
|
revision,
|
|
248
336
|
reader: readerRegistration(kind, revision),
|
|
249
|
-
kindDefinitionSource: renderKindDefinition(owner, revision),
|
|
337
|
+
kindDefinitionSource: renderKindDefinition(owner, [revision]),
|
|
250
338
|
});
|
|
251
339
|
}
|
|
252
340
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
341
|
+
const LEGACY_KIND_CONTRACTS = DEPA_AI_RESOURCE_KINDS.map(createContract);
|
|
342
|
+
|
|
343
|
+
export const DEPA_AI_RESOURCE_KIND_CONTRACTS: readonly DepaAIResourceKindContract[] = Object.freeze([
|
|
344
|
+
...LEGACY_KIND_CONTRACTS,
|
|
345
|
+
...LEGACY_KIND_CONTRACTS.filter(({ kind }) => kind === 'AgentMessageSource' || kind === 'AgentContextPipeline').map((legacy) => {
|
|
346
|
+
const { kind } = legacy;
|
|
347
|
+
const revision = createKindSpecRevision({
|
|
348
|
+
kind,
|
|
349
|
+
subjectFqn: legacy.subjectFqn,
|
|
350
|
+
specVersion: 2,
|
|
351
|
+
specSchema: codeRecipeSpecSchema(kind),
|
|
352
|
+
semanticContract: nativeCodeSemanticContract(kind),
|
|
353
|
+
sourceContractFingerprint: legacy.owner.sourceContract.sourceContractFingerprint,
|
|
354
|
+
stability: 'stable',
|
|
355
|
+
});
|
|
356
|
+
return Object.freeze({
|
|
357
|
+
...legacy,
|
|
358
|
+
revision,
|
|
359
|
+
reader: readerRegistration(kind, revision),
|
|
360
|
+
kindDefinitionSource: renderKindDefinition(legacy.owner, [legacy.revision, revision]),
|
|
361
|
+
});
|
|
362
|
+
}),
|
|
363
|
+
]);
|
|
256
364
|
|
|
257
365
|
export const DEPA_AI_RESOURCE_KIND_OWNERS: readonly KindSubjectOwner[] = Object.freeze(
|
|
258
|
-
|
|
366
|
+
LEGACY_KIND_CONTRACTS.map((contract) => contract.owner),
|
|
259
367
|
);
|
|
260
368
|
|
|
261
369
|
export const DEPA_AI_RESOURCE_KIND_SPEC_REVISIONS: readonly KindSpecRevision[] = Object.freeze(
|
|
@@ -266,16 +374,40 @@ export const DEPA_AI_RESOURCE_KIND_READER_REGISTRATIONS: readonly KindReaderRegi
|
|
|
266
374
|
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => contract.reader),
|
|
267
375
|
);
|
|
268
376
|
|
|
269
|
-
const CONTRACTS_BY_KIND: ReadonlyMap<
|
|
270
|
-
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => [contract.kind
|
|
377
|
+
const CONTRACTS_BY_KIND: ReadonlyMap<string, DepaAIResourceKindContract> = new Map(
|
|
378
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => [`${contract.kind}@${contract.revision.specVersion}`, contract]),
|
|
271
379
|
);
|
|
272
380
|
|
|
273
|
-
export function depaAIResourceKindContract(kind: DepaAIResourceKind): DepaAIResourceKindContract {
|
|
274
|
-
const contract = CONTRACTS_BY_KIND.get(kind);
|
|
275
|
-
if (!contract) throw new Error(`Unknown depa AI resource Kind '${kind}'.`);
|
|
381
|
+
export function depaAIResourceKindContract(kind: DepaAIResourceKind, specVersion: number = DEPA_AI_RESOURCE_SPEC_VERSION): DepaAIResourceKindContract {
|
|
382
|
+
const contract = CONTRACTS_BY_KIND.get(`${kind}@${specVersion}`);
|
|
383
|
+
if (!contract) throw new Error(`Unknown depa AI resource Kind '${kind}' spec version '${specVersion}'.`);
|
|
276
384
|
return contract;
|
|
277
385
|
}
|
|
278
386
|
|
|
387
|
+
export const DEPA_AI_RESOURCE_KIND_SPEC_RESOLUTIONS: readonly SpecResolutionDefinition[] = Object.freeze(
|
|
388
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.filter((contract) => contract.revision.specVersion === 2).map((contract) => {
|
|
389
|
+
const writer = depaAIResourceKindContract(contract.kind, 1);
|
|
390
|
+
const identity = Object.freeze({
|
|
391
|
+
id: `ai-workflow-contract.${contract.kind}.v1-to-v2`,
|
|
392
|
+
subjectFqn: contract.subjectFqn,
|
|
393
|
+
ownerPackageId: contract.owner.ownerPackageId,
|
|
394
|
+
ownerPackageFingerprint: contract.owner.ownerPackageFingerprint,
|
|
395
|
+
writerSpecVersion: 1,
|
|
396
|
+
readerSpecVersion: 2,
|
|
397
|
+
writerContractFingerprint: writer.revision.contractFingerprint,
|
|
398
|
+
readerContractFingerprint: contract.revision.contractFingerprint,
|
|
399
|
+
});
|
|
400
|
+
return Object.freeze({
|
|
401
|
+
...identity,
|
|
402
|
+
resolutionFingerprint: digestCanonical(Object.freeze({
|
|
403
|
+
...identity,
|
|
404
|
+
implementation: 'identity-Content-preservation-requires-explicit-legacy-code-resolver',
|
|
405
|
+
})),
|
|
406
|
+
resolve: (spec: PortableSpec): PortableSpec => spec,
|
|
407
|
+
});
|
|
408
|
+
}),
|
|
409
|
+
);
|
|
410
|
+
|
|
279
411
|
function compareCodeUnits(left: string, right: string): number {
|
|
280
412
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
281
413
|
}
|