ai-workflow-contract 0.1.8 → 0.2.0
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 +3 -3
- package/src/index.ts +154 -4
- package/src/resource-kind-contracts.ts +281 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-workflow-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared AI workflow contracts over WorkCtrlFlow and EagerDataFlow substrates",
|
|
6
6
|
"type": "module",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
".": "./src/index.ts"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"eager-data-flow-contract": "0.1.
|
|
13
|
-
"halfcode-compiler.xnl": "0.
|
|
12
|
+
"eager-data-flow-contract": "0.1.4",
|
|
13
|
+
"halfcode-compiler.xnl": "0.3.0",
|
|
14
14
|
"task-manager-contract": "0.1.3",
|
|
15
15
|
"work-ctrl-flow-contract": "0.1.3"
|
|
16
16
|
},
|
package/src/index.ts
CHANGED
|
@@ -4,10 +4,14 @@ import type {
|
|
|
4
4
|
ResourceDependencySnapshot,
|
|
5
5
|
ResourceRecord,
|
|
6
6
|
ResourceRegistry,
|
|
7
|
-
|
|
7
|
+
AuthoredResourceTree,
|
|
8
|
+
ResolvedResourceTree,
|
|
8
9
|
ResourceValue,
|
|
9
10
|
Sha256Digest,
|
|
10
11
|
} from 'halfcode-compiler.xnl/resource-core';
|
|
12
|
+
import type {
|
|
13
|
+
ResourceAuthoringProposal,
|
|
14
|
+
} from 'halfcode-compiler.xnl/authoring-runtime';
|
|
11
15
|
import type {
|
|
12
16
|
FlowBundleSpec,
|
|
13
17
|
FlowClosedObject,
|
|
@@ -19,6 +23,7 @@ import type {
|
|
|
19
23
|
} from 'work-ctrl-flow-contract';
|
|
20
24
|
|
|
21
25
|
export * from './holon-task.js';
|
|
26
|
+
export * from './resource-kind-contracts.js';
|
|
22
27
|
|
|
23
28
|
export {
|
|
24
29
|
FLOW_INSTANCE_SCHEMA_VERSION,
|
|
@@ -145,7 +150,8 @@ export interface ProjectAIWorkflowAppBundlesOptions {
|
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
export interface LoadedAIWorkflowResourcePackage {
|
|
148
|
-
readonly
|
|
153
|
+
readonly authoredTree: AuthoredResourceTree;
|
|
154
|
+
readonly tree: ResolvedResourceTree;
|
|
149
155
|
readonly appBundles: readonly AIWorkflowAppBundleProjection[];
|
|
150
156
|
}
|
|
151
157
|
|
|
@@ -156,6 +162,8 @@ export type MaterialCardinality = 'one' | 'many';
|
|
|
156
162
|
export type AIWorkflowAgentResourceRelation =
|
|
157
163
|
| 'agent-message-prompt'
|
|
158
164
|
| 'agent-message-schema'
|
|
165
|
+
| 'agent-message-source'
|
|
166
|
+
| 'agent-context-pipeline'
|
|
159
167
|
| 'agent-input-schema'
|
|
160
168
|
| 'agent-output-schema'
|
|
161
169
|
| 'agent-tool'
|
|
@@ -196,6 +204,20 @@ export interface AIAgentMessageProjection {
|
|
|
196
204
|
readonly schema?: AIWorkflowMessageSchemaProjection;
|
|
197
205
|
}
|
|
198
206
|
|
|
207
|
+
export interface AIAgentStaticMessagePrefixProjection extends AIAgentMessageProjection {
|
|
208
|
+
readonly type: 'message';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface AIAgentMessageSourcePrefixProjection {
|
|
212
|
+
readonly type: 'message-source';
|
|
213
|
+
readonly id: string;
|
|
214
|
+
readonly source: AIWorkflowTypedResourceRef;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export type AIAgentMessagePrefixItemProjection =
|
|
218
|
+
| AIAgentStaticMessagePrefixProjection
|
|
219
|
+
| AIAgentMessageSourcePrefixProjection;
|
|
220
|
+
|
|
199
221
|
export interface MaterialPortProjection {
|
|
200
222
|
readonly kind: 'MaterialPort';
|
|
201
223
|
readonly fqn: string;
|
|
@@ -210,7 +232,10 @@ export interface AIAgentDefinitionProjection {
|
|
|
210
232
|
readonly kind: 'AIAgentDefinition';
|
|
211
233
|
readonly fqn: string;
|
|
212
234
|
readonly resource: ResourceRecord;
|
|
235
|
+
readonly messagePrefix: readonly AIAgentMessagePrefixItemProjection[];
|
|
236
|
+
/** Static compatibility view for legacy consumers during MessagePrefix adoption. */
|
|
213
237
|
readonly messages: readonly AIAgentMessageProjection[];
|
|
238
|
+
readonly contextPipeline?: AIWorkflowTypedResourceRef;
|
|
214
239
|
readonly inputSchema?: AIWorkflowMessageSchemaProjection;
|
|
215
240
|
readonly outputSchema?: AIWorkflowMessageSchemaProjection;
|
|
216
241
|
readonly tools: readonly AIWorkflowTypedResourceRef[];
|
|
@@ -258,6 +283,131 @@ export interface FrozenAIAgentTaskBinding {
|
|
|
258
283
|
readonly closureResourceIds: readonly string[];
|
|
259
284
|
}
|
|
260
285
|
|
|
286
|
+
export const AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION =
|
|
287
|
+
'ai-workflow.agent-definition-selection/v1' as const;
|
|
288
|
+
|
|
289
|
+
export interface AIAgentTaskRequirement {
|
|
290
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
291
|
+
readonly requirementId: string;
|
|
292
|
+
/** Audit/model evidence only. It is never a code-level routing input. */
|
|
293
|
+
readonly objective: string;
|
|
294
|
+
readonly inputSchemaRef?: `resource://${string}`;
|
|
295
|
+
readonly outputSchemaRef?: `resource://${string}`;
|
|
296
|
+
readonly requiredToolRefs: readonly `resource://${string}`[];
|
|
297
|
+
readonly requiredEffectPolicyRef?: `resource://${string}`;
|
|
298
|
+
readonly requiredToolMode?: AIWorkflowEffectToolMode;
|
|
299
|
+
readonly requiredMaterialPortRefs: readonly `resource://${string}`[];
|
|
300
|
+
readonly requiredContextPipelineRef?: `resource://${string}`;
|
|
301
|
+
readonly requiredMessageSourceRefs: readonly `resource://${string}`[];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface AIAgentTaskRequirementProjection {
|
|
305
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
306
|
+
readonly requirement: AIAgentTaskRequirement;
|
|
307
|
+
readonly requirementDigest: Sha256Digest;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface AIAgentDefinitionCandidateContract {
|
|
311
|
+
readonly inputSchemaRef?: `resource://${string}`;
|
|
312
|
+
readonly outputSchemaRef?: `resource://${string}`;
|
|
313
|
+
readonly toolRefs: readonly `resource://${string}`[];
|
|
314
|
+
readonly effectPolicyRef?: `resource://${string}`;
|
|
315
|
+
readonly effectToolMode?: AIWorkflowEffectToolMode;
|
|
316
|
+
readonly materialPortRefs: readonly `resource://${string}`[];
|
|
317
|
+
readonly contextPipelineRef?: `resource://${string}`;
|
|
318
|
+
readonly messageSourceRefs: readonly `resource://${string}`[];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface AIAgentDefinitionAuthoringEvidence {
|
|
322
|
+
readonly schemaVersion: 'ai-workflow.agent-definition-authoring-evidence/v1';
|
|
323
|
+
readonly planDigest: Sha256Digest;
|
|
324
|
+
readonly transactionId: string;
|
|
325
|
+
readonly receiptDigest: Sha256Digest;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface AIAgentDefinitionCandidate {
|
|
329
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
330
|
+
readonly agentDefinitionRef: `resource://${string}`;
|
|
331
|
+
readonly contentDigest: Sha256Digest;
|
|
332
|
+
readonly registryRevision: Sha256Digest;
|
|
333
|
+
readonly contract: AIAgentDefinitionCandidateContract;
|
|
334
|
+
readonly candidateDigest: Sha256Digest;
|
|
335
|
+
readonly authoringEvidence?: AIAgentDefinitionAuthoringEvidence;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface AIAgentDefinitionCandidateSet {
|
|
339
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
340
|
+
readonly registryRevision: Sha256Digest;
|
|
341
|
+
readonly candidates: readonly AIAgentDefinitionCandidate[];
|
|
342
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
interface AIAgentDefinitionSelectionDecisionBase {
|
|
346
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
347
|
+
readonly requirementDigest: Sha256Digest;
|
|
348
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
349
|
+
readonly reason: string;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface SelectExistingAIAgentDefinitionDecision
|
|
353
|
+
extends AIAgentDefinitionSelectionDecisionBase {
|
|
354
|
+
readonly mode: 'select-existing';
|
|
355
|
+
readonly candidateRef: `resource://${string}`;
|
|
356
|
+
readonly candidateDigest: Sha256Digest;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export interface AuthorNewAIAgentDefinitionDecision
|
|
360
|
+
extends AIAgentDefinitionSelectionDecisionBase {
|
|
361
|
+
readonly mode: 'author-new';
|
|
362
|
+
readonly agentDefinitionRef: `resource://${string}`;
|
|
363
|
+
readonly proposal: ResourceAuthoringProposal;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export type AIAgentDefinitionSelectionDecision =
|
|
367
|
+
| SelectExistingAIAgentDefinitionDecision
|
|
368
|
+
| AuthorNewAIAgentDefinitionDecision;
|
|
369
|
+
|
|
370
|
+
export type AIAgentDefinitionSelectionRejectionCode =
|
|
371
|
+
| 'decision-invalid'
|
|
372
|
+
| 'requirement-stale'
|
|
373
|
+
| 'candidate-set-stale'
|
|
374
|
+
| 'candidate-missing'
|
|
375
|
+
| 'candidate-digest-mismatch'
|
|
376
|
+
| 'candidate-incompatible'
|
|
377
|
+
| 'authoring-in-progress'
|
|
378
|
+
| 'authoring-proposal-invalid';
|
|
379
|
+
|
|
380
|
+
export interface SelectedAIAgentDefinitionAdmission {
|
|
381
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
382
|
+
readonly status: 'selected';
|
|
383
|
+
readonly requirementDigest: Sha256Digest;
|
|
384
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
385
|
+
readonly candidate: AIAgentDefinitionCandidate;
|
|
386
|
+
readonly reason: string;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface AuthorNewAIAgentDefinitionAdmission {
|
|
390
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
391
|
+
readonly status: 'authoring-request';
|
|
392
|
+
readonly requirementDigest: Sha256Digest;
|
|
393
|
+
readonly candidateSetDigest: Sha256Digest;
|
|
394
|
+
readonly agentDefinitionRef: `resource://${string}`;
|
|
395
|
+
readonly proposal: ResourceAuthoringProposal;
|
|
396
|
+
readonly reason: string;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface RejectedAIAgentDefinitionAdmission {
|
|
400
|
+
readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
|
|
401
|
+
readonly status: 'rejected';
|
|
402
|
+
readonly code: AIAgentDefinitionSelectionRejectionCode;
|
|
403
|
+
readonly message: string;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type AIAgentDefinitionSelectionAdmission =
|
|
407
|
+
| SelectedAIAgentDefinitionAdmission
|
|
408
|
+
| AuthorNewAIAgentDefinitionAdmission
|
|
409
|
+
| RejectedAIAgentDefinitionAdmission;
|
|
410
|
+
|
|
261
411
|
export type AIWorkflowNodeType =
|
|
262
412
|
| 'agent'
|
|
263
413
|
| 'data'
|
|
@@ -410,8 +560,8 @@ export interface AIWorkflowExecutionReceipt {
|
|
|
410
560
|
}
|
|
411
561
|
|
|
412
562
|
export type AIAgentSelector =
|
|
413
|
-
| { readonly
|
|
414
|
-
| { readonly
|
|
563
|
+
| { readonly byId: string; readonly byName?: never }
|
|
564
|
+
| { readonly byName: string; readonly byId?: never };
|
|
415
565
|
|
|
416
566
|
export interface AIAgentInvocation<Input extends FlowClosedValue = FlowClosedValue> {
|
|
417
567
|
readonly kind: 'ai.agent';
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import {
|
|
2
|
+
digestCanonical,
|
|
3
|
+
type JsonSchema,
|
|
4
|
+
type KindReaderRegistration,
|
|
5
|
+
type KindSemanticContract,
|
|
6
|
+
type KindSpecRevision,
|
|
7
|
+
type KindSubjectOwner,
|
|
8
|
+
type PortableSpec,
|
|
9
|
+
} from 'halfcode-compiler.xnl/resource-core';
|
|
10
|
+
import {
|
|
11
|
+
createKindSpecRevision,
|
|
12
|
+
createKindSubjectOwner,
|
|
13
|
+
} from 'halfcode-compiler.xnl/kind-definition';
|
|
14
|
+
|
|
15
|
+
export const DEPA_AI_RESOURCE_KINDS = Object.freeze([
|
|
16
|
+
'AIAgentDefinition',
|
|
17
|
+
'AgentMessageSource',
|
|
18
|
+
'AgentContextPipeline',
|
|
19
|
+
'Prompt',
|
|
20
|
+
'Tool',
|
|
21
|
+
'MessageSchema',
|
|
22
|
+
'EffectPolicy',
|
|
23
|
+
'MaterialPort',
|
|
24
|
+
'MaterialBinding',
|
|
25
|
+
'RequestMaterial',
|
|
26
|
+
'ContextMaterial',
|
|
27
|
+
'AIWorkflowAppBundle',
|
|
28
|
+
'AICtrlWorkflow',
|
|
29
|
+
'AIDataWorkflow',
|
|
30
|
+
] as const);
|
|
31
|
+
|
|
32
|
+
export type DepaAIResourceKind = (typeof DEPA_AI_RESOURCE_KINDS)[number];
|
|
33
|
+
|
|
34
|
+
export const DEPA_AI_RESOURCE_ENVELOPE_VERSION = 'halfcode.resource-envelope/v1' as const;
|
|
35
|
+
export const DEPA_AI_RESOURCE_SPEC_VERSION = 1 as const;
|
|
36
|
+
export const DEPA_AI_RESOURCE_KIND_OWNER_PACKAGE_ID = 'ai-workflow-contract' as const;
|
|
37
|
+
export const DEPA_AI_RESOURCE_SEMANTIC_API_VERSION = 'depa.flows/v1' as const;
|
|
38
|
+
|
|
39
|
+
const subjectFqnFor = (kind: DepaAIResourceKind): `Depa.Flows.KindDefinition.${DepaAIResourceKind}` =>
|
|
40
|
+
`Depa.Flows.KindDefinition.${kind}`;
|
|
41
|
+
|
|
42
|
+
export const DEPA_AI_RESOURCE_KIND_OWNER_PACKAGE_FINGERPRINT = digestCanonical(Object.freeze({
|
|
43
|
+
authority: 'ai-workflow-contract/depa-ai-resource-kinds/v1',
|
|
44
|
+
ownerPackageId: DEPA_AI_RESOURCE_KIND_OWNER_PACKAGE_ID,
|
|
45
|
+
subjects: Object.freeze(DEPA_AI_RESOURCE_KINDS.map(subjectFqnFor).sort(compareCodeUnits)),
|
|
46
|
+
semanticContractVersion: DEPA_AI_RESOURCE_SEMANTIC_API_VERSION,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
interface KindSchemaShape {
|
|
50
|
+
readonly requiredProperties?: readonly string[];
|
|
51
|
+
readonly requiredSubdomains?: readonly string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const KIND_SCHEMA_SHAPES: Readonly<Record<DepaAIResourceKind, KindSchemaShape>> = Object.freeze({
|
|
55
|
+
AIAgentDefinition: Object.freeze({ requiredSubdomains: Object.freeze(['ToolRefs', 'MaterialPortRefs']) }),
|
|
56
|
+
AgentMessageSource: Object.freeze({ requiredSubdomains: Object.freeze(['Content']) }),
|
|
57
|
+
AgentContextPipeline: Object.freeze({ requiredSubdomains: Object.freeze(['Content']) }),
|
|
58
|
+
Prompt: Object.freeze({ requiredProperties: Object.freeze(['template']) }),
|
|
59
|
+
Tool: Object.freeze({}),
|
|
60
|
+
MessageSchema: Object.freeze({ requiredProperties: Object.freeze(['schema']) }),
|
|
61
|
+
EffectPolicy: Object.freeze({ requiredProperties: Object.freeze(['toolMode']) }),
|
|
62
|
+
MaterialPort: Object.freeze({ requiredProperties: Object.freeze(['materialKind', 'required', 'cardinality']) }),
|
|
63
|
+
MaterialBinding: Object.freeze({ requiredSubdomains: Object.freeze(['AgentTaskRef', 'PortRef', 'MaterialRef']) }),
|
|
64
|
+
RequestMaterial: Object.freeze({ requiredProperties: Object.freeze(['value']) }),
|
|
65
|
+
ContextMaterial: Object.freeze({ requiredProperties: Object.freeze(['value']) }),
|
|
66
|
+
AIWorkflowAppBundle: Object.freeze({ requiredSubdomains: Object.freeze(['WorkflowBindings']) }),
|
|
67
|
+
AICtrlWorkflow: Object.freeze({}),
|
|
68
|
+
AIDataWorkflow: Object.freeze({}),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const KIND_SEMANTIC_OPERATIONS: Readonly<Record<DepaAIResourceKind, readonly string[]>> = Object.freeze({
|
|
72
|
+
AIAgentDefinition: Object.freeze(['projectAIWorkflowAgentResources', 'freezeAIAgentTaskResources']),
|
|
73
|
+
AgentMessageSource: Object.freeze(['projectAIWorkflowAgentResources', 'compileAgentMessageSource']),
|
|
74
|
+
AgentContextPipeline: Object.freeze(['projectAIWorkflowAgentResources', 'compileAgentContextPipeline']),
|
|
75
|
+
Prompt: Object.freeze(['projectAIWorkflowAgentResources', 'compileAgentMessagePrefix']),
|
|
76
|
+
Tool: Object.freeze(['projectAIWorkflowAgentResources', 'freezeAIAgentTaskResources']),
|
|
77
|
+
MessageSchema: Object.freeze(['projectAIWorkflowAgentResources', 'validateExecutableMessageSchema']),
|
|
78
|
+
EffectPolicy: Object.freeze(['projectAIWorkflowAgentResources', 'validateExecutableEffectPolicy']),
|
|
79
|
+
MaterialPort: Object.freeze(['projectAIWorkflowAgentResources', 'validateMaterialPortBindings']),
|
|
80
|
+
MaterialBinding: Object.freeze(['projectAIWorkflowAgentResources', 'freezeAIAgentTaskResources']),
|
|
81
|
+
RequestMaterial: Object.freeze(['projectAIWorkflowAgentResources', 'projectMaterialValue']),
|
|
82
|
+
ContextMaterial: Object.freeze(['projectAIWorkflowAgentResources', 'projectMaterialValue']),
|
|
83
|
+
AIWorkflowAppBundle: Object.freeze(['projectAIWorkflowAppBundles']),
|
|
84
|
+
AICtrlWorkflow: Object.freeze(['loadAICtrlWorkflowSources', 'projectAIWorkflowAppBundles']),
|
|
85
|
+
AIDataWorkflow: Object.freeze(['loadAIDataWorkflowSources', 'projectAIWorkflowAppBundles']),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const KIND_REFERENCE_ROLES: Readonly<Record<DepaAIResourceKind, readonly string[]>> = Object.freeze({
|
|
89
|
+
AIAgentDefinition: Object.freeze([
|
|
90
|
+
'message-prompt',
|
|
91
|
+
'message-schema',
|
|
92
|
+
'message-source',
|
|
93
|
+
'context-pipeline',
|
|
94
|
+
'input-schema',
|
|
95
|
+
'output-schema',
|
|
96
|
+
'tool',
|
|
97
|
+
'effect-policy',
|
|
98
|
+
'material-port',
|
|
99
|
+
]),
|
|
100
|
+
AgentMessageSource: Object.freeze([]),
|
|
101
|
+
AgentContextPipeline: Object.freeze([]),
|
|
102
|
+
Prompt: Object.freeze([]),
|
|
103
|
+
Tool: Object.freeze([]),
|
|
104
|
+
MessageSchema: Object.freeze([]),
|
|
105
|
+
EffectPolicy: Object.freeze([]),
|
|
106
|
+
MaterialPort: Object.freeze(['schema']),
|
|
107
|
+
MaterialBinding: Object.freeze(['agent-task', 'material-port', 'material-value']),
|
|
108
|
+
RequestMaterial: Object.freeze([]),
|
|
109
|
+
ContextMaterial: Object.freeze([]),
|
|
110
|
+
AIWorkflowAppBundle: Object.freeze(['workflow-binding']),
|
|
111
|
+
AICtrlWorkflow: Object.freeze([]),
|
|
112
|
+
AIDataWorkflow: Object.freeze([]),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export interface DepaAIResourceKindContract {
|
|
116
|
+
readonly kind: DepaAIResourceKind;
|
|
117
|
+
readonly subjectFqn: `Depa.Flows.KindDefinition.${DepaAIResourceKind}`;
|
|
118
|
+
readonly owner: KindSubjectOwner;
|
|
119
|
+
readonly revision: KindSpecRevision;
|
|
120
|
+
readonly reader: KindReaderRegistration<PortableSpec>;
|
|
121
|
+
readonly kindDefinitionSource: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function authoredSpecSchema(kind: DepaAIResourceKind): JsonSchema {
|
|
125
|
+
const shape = KIND_SCHEMA_SHAPES[kind];
|
|
126
|
+
const propertiesSchema = Object.freeze({
|
|
127
|
+
type: 'object',
|
|
128
|
+
...(shape.requiredProperties && shape.requiredProperties.length > 0
|
|
129
|
+
? { required: Object.freeze([...shape.requiredProperties]) }
|
|
130
|
+
: {}),
|
|
131
|
+
});
|
|
132
|
+
const subdomainsSchema = Object.freeze({
|
|
133
|
+
type: 'object',
|
|
134
|
+
...(shape.requiredSubdomains && shape.requiredSubdomains.length > 0
|
|
135
|
+
? { required: Object.freeze([...shape.requiredSubdomains]) }
|
|
136
|
+
: {}),
|
|
137
|
+
});
|
|
138
|
+
return Object.freeze({
|
|
139
|
+
type: 'object',
|
|
140
|
+
required: Object.freeze(['properties', 'body', 'subdomains']),
|
|
141
|
+
properties: Object.freeze({
|
|
142
|
+
properties: propertiesSchema,
|
|
143
|
+
body: Object.freeze({ type: 'array' }),
|
|
144
|
+
subdomains: subdomainsSchema,
|
|
145
|
+
text: Object.freeze({ type: 'string' }),
|
|
146
|
+
}),
|
|
147
|
+
additionalProperties: false,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function semanticContract(kind: DepaAIResourceKind): KindSemanticContract {
|
|
152
|
+
return Object.freeze({
|
|
153
|
+
semanticValidatorFingerprint: digestCanonical(Object.freeze({
|
|
154
|
+
authority: 'ai-workflow-contract/depa-ai-resource-kinds/v1',
|
|
155
|
+
kind,
|
|
156
|
+
role: 'closed-domain-semantic-validation',
|
|
157
|
+
operations: KIND_SEMANTIC_OPERATIONS[kind],
|
|
158
|
+
})),
|
|
159
|
+
referenceProjectionFingerprint: digestCanonical(Object.freeze({
|
|
160
|
+
authority: 'ai-workflow-contract/depa-ai-resource-kinds/v1',
|
|
161
|
+
kind,
|
|
162
|
+
role: 'typed-resource-reference-projection',
|
|
163
|
+
relations: KIND_REFERENCE_ROLES[kind],
|
|
164
|
+
})),
|
|
165
|
+
compilerInputFingerprint: digestCanonical(Object.freeze({
|
|
166
|
+
authority: 'ai-workflow-contract/depa-ai-resource-kinds/v1',
|
|
167
|
+
kind,
|
|
168
|
+
role: 'authored-spec-envelope-projection',
|
|
169
|
+
fields: Object.freeze(['properties', 'body', 'subdomains', 'text']),
|
|
170
|
+
})),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function readerRegistration(
|
|
175
|
+
kind: DepaAIResourceKind,
|
|
176
|
+
revision: KindSpecRevision,
|
|
177
|
+
): KindReaderRegistration<PortableSpec> {
|
|
178
|
+
const readerId = `ai-workflow-contract.${kind}.reader.v1`;
|
|
179
|
+
return Object.freeze({
|
|
180
|
+
readerId,
|
|
181
|
+
subjectFqn: revision.subjectFqn,
|
|
182
|
+
readerSpecVersion: revision.specVersion,
|
|
183
|
+
contractFingerprint: revision.contractFingerprint,
|
|
184
|
+
readerImplementationFingerprint: digestCanonical(Object.freeze({
|
|
185
|
+
authority: 'ai-workflow-contract/depa-ai-resource-kinds/v1',
|
|
186
|
+
readerId,
|
|
187
|
+
kind,
|
|
188
|
+
contractFingerprint: revision.contractFingerprint,
|
|
189
|
+
operations: KIND_SEMANTIC_OPERATIONS[kind],
|
|
190
|
+
implementation: 'identity-read-of-halfcode-validated-portable-spec',
|
|
191
|
+
})),
|
|
192
|
+
compatibilityPolicy: 'exact',
|
|
193
|
+
read: (spec: PortableSpec): PortableSpec => spec,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function renderKindDefinition(owner: KindSubjectOwner, revision: KindSpecRevision): string {
|
|
198
|
+
return [
|
|
199
|
+
`<KindDefinition #${owner.subjectFqn} envelopeVersion="${DEPA_AI_RESOURCE_ENVELOPE_VERSION}" specVersion=1 {`,
|
|
200
|
+
' lifecycle = "Stable"',
|
|
201
|
+
` resourceKind = "${owner.kind}"`,
|
|
202
|
+
` subjectFqn = "${owner.subjectFqn}"`,
|
|
203
|
+
' sourceShapes = ["single-file"]',
|
|
204
|
+
` documentCardinality = "${owner.sourceContract.documentCardinality}"`,
|
|
205
|
+
` description = "Canonical depa-flows ${owner.kind} resource contract."`,
|
|
206
|
+
'} (',
|
|
207
|
+
' <SpecRevisions [',
|
|
208
|
+
` <SpecRevision #v${revision.specVersion} {`,
|
|
209
|
+
` specVersion = ${revision.specVersion}`,
|
|
210
|
+
' schemaRef = "vfs://./spec-v1.schema.json"',
|
|
211
|
+
` schemaFingerprint = "${revision.schemaFingerprint}"`,
|
|
212
|
+
` contractFingerprint = "${revision.contractFingerprint}"`,
|
|
213
|
+
` semanticValidatorFingerprint = "${revision.semanticContract.semanticValidatorFingerprint}"`,
|
|
214
|
+
` referenceProjectionFingerprint = "${revision.semanticContract.referenceProjectionFingerprint}"`,
|
|
215
|
+
` compilerInputFingerprint = "${revision.semanticContract.compilerInputFingerprint}"`,
|
|
216
|
+
` stability = "${revision.stability}"`,
|
|
217
|
+
' }>',
|
|
218
|
+
' ]>',
|
|
219
|
+
')>',
|
|
220
|
+
'',
|
|
221
|
+
].join('\n');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createContract(kind: DepaAIResourceKind): DepaAIResourceKindContract {
|
|
225
|
+
const subjectFqn = subjectFqnFor(kind);
|
|
226
|
+
const owner = createKindSubjectOwner({
|
|
227
|
+
kind,
|
|
228
|
+
subjectFqn,
|
|
229
|
+
ownerPackageId: DEPA_AI_RESOURCE_KIND_OWNER_PACKAGE_ID,
|
|
230
|
+
ownerPackageFingerprint: DEPA_AI_RESOURCE_KIND_OWNER_PACKAGE_FINGERPRINT,
|
|
231
|
+
sourceShapes: Object.freeze(['single-file']),
|
|
232
|
+
documentCardinality: 'one',
|
|
233
|
+
});
|
|
234
|
+
const revision = createKindSpecRevision({
|
|
235
|
+
kind,
|
|
236
|
+
subjectFqn,
|
|
237
|
+
specVersion: DEPA_AI_RESOURCE_SPEC_VERSION,
|
|
238
|
+
specSchema: authoredSpecSchema(kind),
|
|
239
|
+
semanticContract: semanticContract(kind),
|
|
240
|
+
sourceContractFingerprint: owner.sourceContract.sourceContractFingerprint,
|
|
241
|
+
stability: 'stable',
|
|
242
|
+
});
|
|
243
|
+
return Object.freeze({
|
|
244
|
+
kind,
|
|
245
|
+
subjectFqn,
|
|
246
|
+
owner,
|
|
247
|
+
revision,
|
|
248
|
+
reader: readerRegistration(kind, revision),
|
|
249
|
+
kindDefinitionSource: renderKindDefinition(owner, revision),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export const DEPA_AI_RESOURCE_KIND_CONTRACTS: readonly DepaAIResourceKindContract[] = Object.freeze(
|
|
254
|
+
DEPA_AI_RESOURCE_KINDS.map(createContract),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
export const DEPA_AI_RESOURCE_KIND_OWNERS: readonly KindSubjectOwner[] = Object.freeze(
|
|
258
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => contract.owner),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
export const DEPA_AI_RESOURCE_KIND_SPEC_REVISIONS: readonly KindSpecRevision[] = Object.freeze(
|
|
262
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => contract.revision),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
export const DEPA_AI_RESOURCE_KIND_READER_REGISTRATIONS: readonly KindReaderRegistration<PortableSpec>[] = Object.freeze(
|
|
266
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => contract.reader),
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const CONTRACTS_BY_KIND: ReadonlyMap<DepaAIResourceKind, DepaAIResourceKindContract> = new Map(
|
|
270
|
+
DEPA_AI_RESOURCE_KIND_CONTRACTS.map((contract) => [contract.kind, contract]),
|
|
271
|
+
);
|
|
272
|
+
|
|
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}'.`);
|
|
276
|
+
return contract;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function compareCodeUnits(left: string, right: string): number {
|
|
280
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
281
|
+
}
|