ai-workflow-contract 0.1.9 → 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 +2 -2
- package/src/index.ts +5 -2
- 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",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"eager-data-flow-contract": "0.1.4",
|
|
13
|
-
"halfcode-compiler.xnl": "0.
|
|
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,7 +4,8 @@ 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';
|
|
@@ -22,6 +23,7 @@ import type {
|
|
|
22
23
|
} from 'work-ctrl-flow-contract';
|
|
23
24
|
|
|
24
25
|
export * from './holon-task.js';
|
|
26
|
+
export * from './resource-kind-contracts.js';
|
|
25
27
|
|
|
26
28
|
export {
|
|
27
29
|
FLOW_INSTANCE_SCHEMA_VERSION,
|
|
@@ -148,7 +150,8 @@ export interface ProjectAIWorkflowAppBundlesOptions {
|
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
export interface LoadedAIWorkflowResourcePackage {
|
|
151
|
-
readonly
|
|
153
|
+
readonly authoredTree: AuthoredResourceTree;
|
|
154
|
+
readonly tree: ResolvedResourceTree;
|
|
152
155
|
readonly appBundles: readonly AIWorkflowAppBundleProjection[];
|
|
153
156
|
}
|
|
154
157
|
|
|
@@ -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
|
+
}
|