ai-workflow-contract 0.1.7 → 0.1.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-workflow-contract",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "description": "Shared AI workflow contracts over WorkCtrlFlow and EagerDataFlow substrates",
6
6
  "type": "module",
@@ -9,8 +9,9 @@
9
9
  ".": "./src/index.ts"
10
10
  },
11
11
  "dependencies": {
12
- "eager-data-flow-contract": "0.1.3",
13
- "halfcode-compiler.xnl": "0.2.2",
12
+ "eager-data-flow-contract": "0.1.4",
13
+ "halfcode-compiler.xnl": "0.2.9",
14
+ "task-manager-contract": "0.1.3",
14
15
  "work-ctrl-flow-contract": "0.1.3"
15
16
  },
16
17
  "files": [
@@ -0,0 +1,320 @@
1
+ import type { ImmutableJsonValue, TaskProfileEnvelope } from 'task-manager-contract';
2
+ import { canonicalOwnDataClone } from 'task-manager-contract';
3
+
4
+ export const HOLON_TASK_TARGET_SCHEMA_VERSION = 'ai-workflow.holon-task-target/v1' as const;
5
+ export const HOLON_TASK_SNAPSHOT_RECEIPT_SCHEMA_VERSION = 'ai-workflow.holon-task-snapshot-receipt/v1' as const;
6
+ export const AI_ORGANIZATION_TASK_PROFILE_KIND = 'depa.ai.organization-task' as const;
7
+
8
+ export type HolonTaskResourceRef = `resource://${string}`;
9
+ export type HolonTaskDigest = `sha256:${string}`;
10
+ type ClosedRecord<Shape> = Readonly<Record<string, ImmutableJsonValue>> & Readonly<Shape>;
11
+
12
+ export type HolonTaskTarget = ClosedRecord<{
13
+ readonly kind: 'holon-task-target';
14
+ readonly schemaVersion: typeof HOLON_TASK_TARGET_SCHEMA_VERSION;
15
+ readonly invocation: ClosedRecord<{
16
+ readonly workflowKind: 'AICtrlWorkflow' | 'AIDataWorkflow';
17
+ readonly workflowRef: HolonTaskResourceRef;
18
+ readonly nodeId: string;
19
+ readonly invocationId: string;
20
+ }>;
21
+ readonly holon: ClosedRecord<{
22
+ readonly rootHolonRef: string;
23
+ readonly effectiveAt: string;
24
+ }>;
25
+ readonly executionBinding: ClosedRecord<{
26
+ readonly ref: HolonTaskResourceRef;
27
+ readonly digest: HolonTaskDigest;
28
+ }>;
29
+ readonly taskSpace: ClosedRecord<{
30
+ readonly profileRef: HolonTaskResourceRef;
31
+ readonly policyRef: HolonTaskResourceRef;
32
+ readonly requiredRoleRefs: readonly string[];
33
+ readonly requiredCapabilityRefs: readonly HolonTaskResourceRef[];
34
+ }>;
35
+ readonly output: ClosedRecord<{
36
+ readonly schemaRef: HolonTaskResourceRef;
37
+ readonly materialPortRefs: readonly HolonTaskResourceRef[];
38
+ }>;
39
+ }>;
40
+
41
+ export type HolonTaskSnapshotReceipt = ClosedRecord<{
42
+ readonly kind: 'holon-task-snapshot-receipt';
43
+ readonly schemaVersion: typeof HOLON_TASK_SNAPSHOT_RECEIPT_SCHEMA_VERSION;
44
+ readonly taskSpaceId: string;
45
+ readonly holonRef: string;
46
+ readonly effectiveAt: string;
47
+ readonly holonSnapshotRef: string;
48
+ readonly holonSnapshotDigest: HolonTaskDigest;
49
+ readonly snapshotArtifactDigest: HolonTaskDigest;
50
+ readonly issuerReceiptId: HolonTaskDigest;
51
+ readonly issuerReceiptArtifactDigest: HolonTaskDigest;
52
+ readonly executionBindingRef: HolonTaskResourceRef;
53
+ readonly executionBindingDigest: HolonTaskDigest;
54
+ readonly eligibleMemberRefs: readonly string[];
55
+ readonly eligibleRoleRefs: readonly string[];
56
+ }>;
57
+
58
+ export type HolonTaskSnapshotAdoptionReceipt = ClosedRecord<{
59
+ readonly kind: 'holon-task-snapshot-adoption-receipt';
60
+ readonly schemaVersion: 'ai-workflow.holon-task-snapshot-adoption-receipt/v1';
61
+ readonly taskSpaceId: string;
62
+ readonly previousTaskId: string;
63
+ readonly successorTaskId: string;
64
+ readonly previousIssuerReceiptId: HolonTaskDigest;
65
+ readonly successorIssuerReceiptId: HolonTaskDigest;
66
+ readonly executionBindingDigest: HolonTaskDigest;
67
+ readonly adoptedAt: string;
68
+ }>;
69
+
70
+ export type AIOrganizationTaskProfileFacts = ClosedRecord<{
71
+ target: HolonTaskTarget;
72
+ snapshotReceipt: HolonTaskSnapshotReceipt;
73
+ assignmentReceipt: null;
74
+ memberRuntimeRef: null;
75
+ settlementReceipt: null;
76
+ snapshotAdoptions: readonly HolonTaskSnapshotAdoptionReceipt[];
77
+ }>;
78
+
79
+ export type AIOrganizationTaskProfile = TaskProfileEnvelope<
80
+ typeof AI_ORGANIZATION_TASK_PROFILE_KIND,
81
+ AIOrganizationTaskProfileFacts
82
+ >;
83
+
84
+ export interface AIWorkflowHolonTaskTargetFreezeReceipt {
85
+ readonly schemaVersion: 'ai-workflow.holon-task-target-freeze/v1';
86
+ readonly target: HolonTaskTarget;
87
+ readonly dependencySnapshot: Readonly<{
88
+ readonly registryRevision: string;
89
+ readonly snapshotRevision: HolonTaskDigest;
90
+ readonly closureResourceIds: readonly string[];
91
+ }>;
92
+ readonly semanticFingerprint: HolonTaskDigest;
93
+ }
94
+
95
+ /** In-memory capability projected only from an authentic target freeze receipt. */
96
+ export interface FrozenHolonTaskTarget {
97
+ readonly schemaVersion: 'ai-workflow.frozen-holon-task-target/v1';
98
+ readonly target: HolonTaskTarget;
99
+ readonly semanticFingerprint: HolonTaskDigest;
100
+ readonly snapshotRevision: HolonTaskDigest;
101
+ readonly closureResourceIds: readonly string[];
102
+ }
103
+
104
+ export function holonTaskTargetFromNodeConfig(
105
+ configInput: unknown,
106
+ expected: Readonly<{
107
+ readonly workflowKind: 'AICtrlWorkflow' | 'AIDataWorkflow';
108
+ readonly workflowRef: HolonTaskResourceRef;
109
+ readonly nodeId: string;
110
+ }>,
111
+ ): HolonTaskTarget | undefined {
112
+ const config = record(canonicalOwnDataClone(configInput), '$config');
113
+ if (!Object.prototype.hasOwnProperty.call(config, 'holonTaskTarget')) return undefined;
114
+ const target = normalizeHolonTaskTarget(config.holonTaskTarget);
115
+ if (target.invocation.workflowKind !== expected.workflowKind
116
+ || target.invocation.workflowRef !== expected.workflowRef
117
+ || target.invocation.nodeId !== expected.nodeId) {
118
+ invalid('$config.holonTaskTarget.invocation', 'Target invocation identity does not match the authored node');
119
+ }
120
+ return target;
121
+ }
122
+
123
+ export class HolonTaskContractError extends Error {
124
+ constructor(readonly path: string, message: string) {
125
+ super(`${path}: ${message}`);
126
+ this.name = 'HolonTaskContractError';
127
+ }
128
+ }
129
+
130
+ export function normalizeHolonTaskTarget(value: unknown): HolonTaskTarget {
131
+ const root = record(canonicalOwnDataClone(value), '$target');
132
+ exactKeys(root, ['kind', 'schemaVersion', 'invocation', 'holon', 'executionBinding', 'taskSpace', 'output'], '$target');
133
+ exactLiteral(root.kind, 'holon-task-target', '$target.kind');
134
+ exactLiteral(root.schemaVersion, HOLON_TASK_TARGET_SCHEMA_VERSION, '$target.schemaVersion');
135
+
136
+ const invocation = record(root.invocation, '$target.invocation');
137
+ exactKeys(invocation, ['workflowKind', 'workflowRef', 'nodeId', 'invocationId'], '$target.invocation');
138
+ const workflowKind = oneOf(invocation.workflowKind, ['AICtrlWorkflow', 'AIDataWorkflow'] as const, '$target.invocation.workflowKind');
139
+ const holon = record(root.holon, '$target.holon');
140
+ exactKeys(holon, ['rootHolonRef', 'effectiveAt'], '$target.holon');
141
+ const executionBinding = record(root.executionBinding, '$target.executionBinding');
142
+ exactKeys(executionBinding, ['ref', 'digest'], '$target.executionBinding');
143
+ const taskSpace = record(root.taskSpace, '$target.taskSpace');
144
+ exactKeys(taskSpace, ['profileRef', 'policyRef', 'requiredRoleRefs', 'requiredCapabilityRefs'], '$target.taskSpace');
145
+ const output = record(root.output, '$target.output');
146
+ exactKeys(output, ['schemaRef', 'materialPortRefs'], '$target.output');
147
+
148
+ return Object.freeze({
149
+ kind: 'holon-task-target',
150
+ schemaVersion: HOLON_TASK_TARGET_SCHEMA_VERSION,
151
+ invocation: Object.freeze({
152
+ workflowKind,
153
+ workflowRef: resourceRef(invocation.workflowRef, '$target.invocation.workflowRef'),
154
+ nodeId: exactString(invocation.nodeId, '$target.invocation.nodeId'),
155
+ invocationId: exactString(invocation.invocationId, '$target.invocation.invocationId'),
156
+ }),
157
+ holon: Object.freeze({
158
+ rootHolonRef: exactString(holon.rootHolonRef, '$target.holon.rootHolonRef'),
159
+ effectiveAt: utcInstant(holon.effectiveAt, '$target.holon.effectiveAt'),
160
+ }),
161
+ executionBinding: Object.freeze({
162
+ ref: resourceRef(executionBinding.ref, '$target.executionBinding.ref'),
163
+ digest: digest(executionBinding.digest, '$target.executionBinding.digest'),
164
+ }),
165
+ taskSpace: Object.freeze({
166
+ profileRef: resourceRef(taskSpace.profileRef, '$target.taskSpace.profileRef'),
167
+ policyRef: resourceRef(taskSpace.policyRef, '$target.taskSpace.policyRef'),
168
+ requiredRoleRefs: stringArray(taskSpace.requiredRoleRefs, '$target.taskSpace.requiredRoleRefs'),
169
+ requiredCapabilityRefs: resourceRefArray(taskSpace.requiredCapabilityRefs, '$target.taskSpace.requiredCapabilityRefs'),
170
+ }),
171
+ output: Object.freeze({
172
+ schemaRef: resourceRef(output.schemaRef, '$target.output.schemaRef'),
173
+ materialPortRefs: resourceRefArray(output.materialPortRefs, '$target.output.materialPortRefs'),
174
+ }),
175
+ });
176
+ }
177
+
178
+ export function normalizeHolonTaskSnapshotReceipt(value: unknown): HolonTaskSnapshotReceipt {
179
+ const root = record(canonicalOwnDataClone(value), '$snapshotReceipt');
180
+ exactKeys(root, [
181
+ 'kind', 'schemaVersion', 'taskSpaceId', 'holonRef', 'effectiveAt', 'holonSnapshotRef',
182
+ 'holonSnapshotDigest', 'snapshotArtifactDigest', 'issuerReceiptId',
183
+ 'issuerReceiptArtifactDigest', 'executionBindingRef', 'executionBindingDigest',
184
+ 'eligibleMemberRefs', 'eligibleRoleRefs',
185
+ ], '$snapshotReceipt');
186
+ exactLiteral(root.kind, 'holon-task-snapshot-receipt', '$snapshotReceipt.kind');
187
+ exactLiteral(root.schemaVersion, HOLON_TASK_SNAPSHOT_RECEIPT_SCHEMA_VERSION, '$snapshotReceipt.schemaVersion');
188
+ return Object.freeze({
189
+ kind: 'holon-task-snapshot-receipt',
190
+ schemaVersion: HOLON_TASK_SNAPSHOT_RECEIPT_SCHEMA_VERSION,
191
+ taskSpaceId: exactString(root.taskSpaceId, '$snapshotReceipt.taskSpaceId'),
192
+ holonRef: exactString(root.holonRef, '$snapshotReceipt.holonRef'),
193
+ effectiveAt: utcInstant(root.effectiveAt, '$snapshotReceipt.effectiveAt'),
194
+ holonSnapshotRef: exactString(root.holonSnapshotRef, '$snapshotReceipt.holonSnapshotRef'),
195
+ holonSnapshotDigest: digest(root.holonSnapshotDigest, '$snapshotReceipt.holonSnapshotDigest'),
196
+ snapshotArtifactDigest: digest(root.snapshotArtifactDigest, '$snapshotReceipt.snapshotArtifactDigest'),
197
+ issuerReceiptId: digest(root.issuerReceiptId, '$snapshotReceipt.issuerReceiptId'),
198
+ issuerReceiptArtifactDigest: digest(root.issuerReceiptArtifactDigest, '$snapshotReceipt.issuerReceiptArtifactDigest'),
199
+ executionBindingRef: resourceRef(root.executionBindingRef, '$snapshotReceipt.executionBindingRef'),
200
+ executionBindingDigest: digest(root.executionBindingDigest, '$snapshotReceipt.executionBindingDigest'),
201
+ eligibleMemberRefs: stringArray(root.eligibleMemberRefs, '$snapshotReceipt.eligibleMemberRefs'),
202
+ eligibleRoleRefs: stringArray(root.eligibleRoleRefs, '$snapshotReceipt.eligibleRoleRefs'),
203
+ });
204
+ }
205
+
206
+ export function createAIOrganizationTaskProfile(
207
+ targetInput: unknown,
208
+ receiptInput: unknown,
209
+ adoptionInputs: readonly unknown[] = [],
210
+ ): AIOrganizationTaskProfile {
211
+ const target = normalizeHolonTaskTarget(targetInput);
212
+ const snapshotReceipt = normalizeHolonTaskSnapshotReceipt(receiptInput);
213
+ if (snapshotReceipt.taskSpaceId.length === 0
214
+ || snapshotReceipt.holonRef !== target.holon.rootHolonRef
215
+ || snapshotReceipt.effectiveAt !== target.holon.effectiveAt
216
+ || snapshotReceipt.executionBindingRef !== target.executionBinding.ref
217
+ || snapshotReceipt.executionBindingDigest !== target.executionBinding.digest) {
218
+ invalid('$profile', 'Snapshot receipt does not bind the exact target facts');
219
+ }
220
+ return Object.freeze({
221
+ kind: 'task-profile',
222
+ profileKind: AI_ORGANIZATION_TASK_PROFILE_KIND,
223
+ schemaVersion: 1,
224
+ facts: Object.freeze({
225
+ target,
226
+ snapshotReceipt,
227
+ assignmentReceipt: null,
228
+ memberRuntimeRef: null,
229
+ settlementReceipt: null,
230
+ snapshotAdoptions: Object.freeze(adoptionInputs.map(normalizeHolonTaskSnapshotAdoptionReceipt)),
231
+ }),
232
+ });
233
+ }
234
+
235
+ export function normalizeHolonTaskSnapshotAdoptionReceipt(value: unknown): HolonTaskSnapshotAdoptionReceipt {
236
+ const root = record(canonicalOwnDataClone(value), '$snapshotAdoptionReceipt');
237
+ exactKeys(root, [
238
+ 'kind', 'schemaVersion', 'taskSpaceId', 'previousTaskId', 'successorTaskId',
239
+ 'previousIssuerReceiptId', 'successorIssuerReceiptId', 'executionBindingDigest', 'adoptedAt',
240
+ ], '$snapshotAdoptionReceipt');
241
+ exactLiteral(root.kind, 'holon-task-snapshot-adoption-receipt', '$snapshotAdoptionReceipt.kind');
242
+ exactLiteral(root.schemaVersion, 'ai-workflow.holon-task-snapshot-adoption-receipt/v1', '$snapshotAdoptionReceipt.schemaVersion');
243
+ return Object.freeze({
244
+ kind: 'holon-task-snapshot-adoption-receipt',
245
+ schemaVersion: 'ai-workflow.holon-task-snapshot-adoption-receipt/v1',
246
+ taskSpaceId: exactString(root.taskSpaceId, '$snapshotAdoptionReceipt.taskSpaceId'),
247
+ previousTaskId: exactString(root.previousTaskId, '$snapshotAdoptionReceipt.previousTaskId'),
248
+ successorTaskId: exactString(root.successorTaskId, '$snapshotAdoptionReceipt.successorTaskId'),
249
+ previousIssuerReceiptId: digest(root.previousIssuerReceiptId, '$snapshotAdoptionReceipt.previousIssuerReceiptId'),
250
+ successorIssuerReceiptId: digest(root.successorIssuerReceiptId, '$snapshotAdoptionReceipt.successorIssuerReceiptId'),
251
+ executionBindingDigest: digest(root.executionBindingDigest, '$snapshotAdoptionReceipt.executionBindingDigest'),
252
+ adoptedAt: utcInstant(root.adoptedAt, '$snapshotAdoptionReceipt.adoptedAt'),
253
+ });
254
+ }
255
+
256
+ function record(value: unknown, path: string): Readonly<Record<string, unknown>> {
257
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) invalid(path, 'Expected an object');
258
+ return value as Readonly<Record<string, unknown>>;
259
+ }
260
+
261
+ function exactKeys(value: Readonly<Record<string, unknown>>, expected: readonly string[], path: string): void {
262
+ const actual = Object.keys(value);
263
+ const expectedSet = new Set(expected);
264
+ const extra = actual.find((key) => !expectedSet.has(key));
265
+ if (extra !== undefined) invalid(`${path}.${extra}`, 'Unsupported field');
266
+ const missing = expected.find((key) => !Object.prototype.hasOwnProperty.call(value, key));
267
+ if (missing !== undefined) invalid(`${path}.${missing}`, 'Required field is missing');
268
+ }
269
+
270
+ function exactString(value: unknown, path: string): string {
271
+ if (typeof value !== 'string' || value.length === 0 || value !== value.trim()) invalid(path, 'Expected an exact non-empty string');
272
+ return value;
273
+ }
274
+
275
+ function exactLiteral<const Value extends string>(value: unknown, expected: Value, path: string): Value {
276
+ if (value !== expected) invalid(path, `Expected '${expected}'`);
277
+ return expected;
278
+ }
279
+
280
+ function oneOf<const Values extends readonly string[]>(value: unknown, expected: Values, path: string): Values[number] {
281
+ if (typeof value !== 'string' || !expected.includes(value)) invalid(path, `Expected one of ${expected.join('|')}`);
282
+ return value as Values[number];
283
+ }
284
+
285
+ function resourceRef(value: unknown, path: string): HolonTaskResourceRef {
286
+ const ref = exactString(value, path);
287
+ if (!/^resource:\/\/[^/\s][^\s]*$/.test(ref)) invalid(path, 'Expected a canonical resource:// reference');
288
+ return ref as HolonTaskResourceRef;
289
+ }
290
+
291
+ function digest(value: unknown, path: string): HolonTaskDigest {
292
+ if (typeof value !== 'string' || !/^sha256:[0-9a-f]{64}$/.test(value)) invalid(path, 'Expected a canonical SHA-256 digest');
293
+ return value as HolonTaskDigest;
294
+ }
295
+
296
+ function utcInstant(value: unknown, path: string): string {
297
+ const instant = exactString(value, path);
298
+ const parsed = Date.parse(instant);
299
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(instant)
300
+ || Number.isNaN(parsed) || new Date(parsed).toISOString() !== instant) invalid(path, 'Expected a canonical UTC instant');
301
+ return instant;
302
+ }
303
+
304
+ function stringArray(value: unknown, path: string): readonly string[] {
305
+ if (!Array.isArray(value)) invalid(path, 'Expected an array');
306
+ const result = Object.freeze(value.map((item, index) => exactString(item, `${path}[${index}]`)));
307
+ if (new Set(result).size !== result.length) invalid(path, 'Duplicate values are not allowed');
308
+ return result;
309
+ }
310
+
311
+ function resourceRefArray(value: unknown, path: string): readonly HolonTaskResourceRef[] {
312
+ if (!Array.isArray(value)) invalid(path, 'Expected an array');
313
+ const result = Object.freeze(value.map((item, index) => resourceRef(item, `${path}[${index}]`)));
314
+ if (new Set(result).size !== result.length) invalid(path, 'Duplicate values are not allowed');
315
+ return result;
316
+ }
317
+
318
+ function invalid(path: string, message: string): never {
319
+ throw new HolonTaskContractError(path, message);
320
+ }
package/src/index.ts CHANGED
@@ -8,6 +8,9 @@ import type {
8
8
  ResourceValue,
9
9
  Sha256Digest,
10
10
  } from 'halfcode-compiler.xnl/resource-core';
11
+ import type {
12
+ ResourceAuthoringProposal,
13
+ } from 'halfcode-compiler.xnl/authoring-runtime';
11
14
  import type {
12
15
  FlowBundleSpec,
13
16
  FlowClosedObject,
@@ -18,6 +21,8 @@ import type {
18
21
  WorkCtrlFlowRuntime,
19
22
  } from 'work-ctrl-flow-contract';
20
23
 
24
+ export * from './holon-task.js';
25
+
21
26
  export {
22
27
  FLOW_INSTANCE_SCHEMA_VERSION,
23
28
  FLOW_RUN_CHECKPOINT_SCHEMA_VERSION,
@@ -154,6 +159,8 @@ export type MaterialCardinality = 'one' | 'many';
154
159
  export type AIWorkflowAgentResourceRelation =
155
160
  | 'agent-message-prompt'
156
161
  | 'agent-message-schema'
162
+ | 'agent-message-source'
163
+ | 'agent-context-pipeline'
157
164
  | 'agent-input-schema'
158
165
  | 'agent-output-schema'
159
166
  | 'agent-tool'
@@ -194,6 +201,20 @@ export interface AIAgentMessageProjection {
194
201
  readonly schema?: AIWorkflowMessageSchemaProjection;
195
202
  }
196
203
 
204
+ export interface AIAgentStaticMessagePrefixProjection extends AIAgentMessageProjection {
205
+ readonly type: 'message';
206
+ }
207
+
208
+ export interface AIAgentMessageSourcePrefixProjection {
209
+ readonly type: 'message-source';
210
+ readonly id: string;
211
+ readonly source: AIWorkflowTypedResourceRef;
212
+ }
213
+
214
+ export type AIAgentMessagePrefixItemProjection =
215
+ | AIAgentStaticMessagePrefixProjection
216
+ | AIAgentMessageSourcePrefixProjection;
217
+
197
218
  export interface MaterialPortProjection {
198
219
  readonly kind: 'MaterialPort';
199
220
  readonly fqn: string;
@@ -208,7 +229,10 @@ export interface AIAgentDefinitionProjection {
208
229
  readonly kind: 'AIAgentDefinition';
209
230
  readonly fqn: string;
210
231
  readonly resource: ResourceRecord;
232
+ readonly messagePrefix: readonly AIAgentMessagePrefixItemProjection[];
233
+ /** Static compatibility view for legacy consumers during MessagePrefix adoption. */
211
234
  readonly messages: readonly AIAgentMessageProjection[];
235
+ readonly contextPipeline?: AIWorkflowTypedResourceRef;
212
236
  readonly inputSchema?: AIWorkflowMessageSchemaProjection;
213
237
  readonly outputSchema?: AIWorkflowMessageSchemaProjection;
214
238
  readonly tools: readonly AIWorkflowTypedResourceRef[];
@@ -256,6 +280,131 @@ export interface FrozenAIAgentTaskBinding {
256
280
  readonly closureResourceIds: readonly string[];
257
281
  }
258
282
 
283
+ export const AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION =
284
+ 'ai-workflow.agent-definition-selection/v1' as const;
285
+
286
+ export interface AIAgentTaskRequirement {
287
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
288
+ readonly requirementId: string;
289
+ /** Audit/model evidence only. It is never a code-level routing input. */
290
+ readonly objective: string;
291
+ readonly inputSchemaRef?: `resource://${string}`;
292
+ readonly outputSchemaRef?: `resource://${string}`;
293
+ readonly requiredToolRefs: readonly `resource://${string}`[];
294
+ readonly requiredEffectPolicyRef?: `resource://${string}`;
295
+ readonly requiredToolMode?: AIWorkflowEffectToolMode;
296
+ readonly requiredMaterialPortRefs: readonly `resource://${string}`[];
297
+ readonly requiredContextPipelineRef?: `resource://${string}`;
298
+ readonly requiredMessageSourceRefs: readonly `resource://${string}`[];
299
+ }
300
+
301
+ export interface AIAgentTaskRequirementProjection {
302
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
303
+ readonly requirement: AIAgentTaskRequirement;
304
+ readonly requirementDigest: Sha256Digest;
305
+ }
306
+
307
+ export interface AIAgentDefinitionCandidateContract {
308
+ readonly inputSchemaRef?: `resource://${string}`;
309
+ readonly outputSchemaRef?: `resource://${string}`;
310
+ readonly toolRefs: readonly `resource://${string}`[];
311
+ readonly effectPolicyRef?: `resource://${string}`;
312
+ readonly effectToolMode?: AIWorkflowEffectToolMode;
313
+ readonly materialPortRefs: readonly `resource://${string}`[];
314
+ readonly contextPipelineRef?: `resource://${string}`;
315
+ readonly messageSourceRefs: readonly `resource://${string}`[];
316
+ }
317
+
318
+ export interface AIAgentDefinitionAuthoringEvidence {
319
+ readonly schemaVersion: 'ai-workflow.agent-definition-authoring-evidence/v1';
320
+ readonly planDigest: Sha256Digest;
321
+ readonly transactionId: string;
322
+ readonly receiptDigest: Sha256Digest;
323
+ }
324
+
325
+ export interface AIAgentDefinitionCandidate {
326
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
327
+ readonly agentDefinitionRef: `resource://${string}`;
328
+ readonly contentDigest: Sha256Digest;
329
+ readonly registryRevision: Sha256Digest;
330
+ readonly contract: AIAgentDefinitionCandidateContract;
331
+ readonly candidateDigest: Sha256Digest;
332
+ readonly authoringEvidence?: AIAgentDefinitionAuthoringEvidence;
333
+ }
334
+
335
+ export interface AIAgentDefinitionCandidateSet {
336
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
337
+ readonly registryRevision: Sha256Digest;
338
+ readonly candidates: readonly AIAgentDefinitionCandidate[];
339
+ readonly candidateSetDigest: Sha256Digest;
340
+ }
341
+
342
+ interface AIAgentDefinitionSelectionDecisionBase {
343
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
344
+ readonly requirementDigest: Sha256Digest;
345
+ readonly candidateSetDigest: Sha256Digest;
346
+ readonly reason: string;
347
+ }
348
+
349
+ export interface SelectExistingAIAgentDefinitionDecision
350
+ extends AIAgentDefinitionSelectionDecisionBase {
351
+ readonly mode: 'select-existing';
352
+ readonly candidateRef: `resource://${string}`;
353
+ readonly candidateDigest: Sha256Digest;
354
+ }
355
+
356
+ export interface AuthorNewAIAgentDefinitionDecision
357
+ extends AIAgentDefinitionSelectionDecisionBase {
358
+ readonly mode: 'author-new';
359
+ readonly agentDefinitionRef: `resource://${string}`;
360
+ readonly proposal: ResourceAuthoringProposal;
361
+ }
362
+
363
+ export type AIAgentDefinitionSelectionDecision =
364
+ | SelectExistingAIAgentDefinitionDecision
365
+ | AuthorNewAIAgentDefinitionDecision;
366
+
367
+ export type AIAgentDefinitionSelectionRejectionCode =
368
+ | 'decision-invalid'
369
+ | 'requirement-stale'
370
+ | 'candidate-set-stale'
371
+ | 'candidate-missing'
372
+ | 'candidate-digest-mismatch'
373
+ | 'candidate-incompatible'
374
+ | 'authoring-in-progress'
375
+ | 'authoring-proposal-invalid';
376
+
377
+ export interface SelectedAIAgentDefinitionAdmission {
378
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
379
+ readonly status: 'selected';
380
+ readonly requirementDigest: Sha256Digest;
381
+ readonly candidateSetDigest: Sha256Digest;
382
+ readonly candidate: AIAgentDefinitionCandidate;
383
+ readonly reason: string;
384
+ }
385
+
386
+ export interface AuthorNewAIAgentDefinitionAdmission {
387
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
388
+ readonly status: 'authoring-request';
389
+ readonly requirementDigest: Sha256Digest;
390
+ readonly candidateSetDigest: Sha256Digest;
391
+ readonly agentDefinitionRef: `resource://${string}`;
392
+ readonly proposal: ResourceAuthoringProposal;
393
+ readonly reason: string;
394
+ }
395
+
396
+ export interface RejectedAIAgentDefinitionAdmission {
397
+ readonly schemaVersion: typeof AI_AGENT_DEFINITION_SELECTION_SCHEMA_VERSION;
398
+ readonly status: 'rejected';
399
+ readonly code: AIAgentDefinitionSelectionRejectionCode;
400
+ readonly message: string;
401
+ }
402
+
403
+ export type AIAgentDefinitionSelectionAdmission =
404
+ | SelectedAIAgentDefinitionAdmission
405
+ | AuthorNewAIAgentDefinitionAdmission
406
+ | RejectedAIAgentDefinitionAdmission;
407
+
259
408
  export type AIWorkflowNodeType =
260
409
  | 'agent'
261
410
  | 'data'
@@ -408,8 +557,8 @@ export interface AIWorkflowExecutionReceipt {
408
557
  }
409
558
 
410
559
  export type AIAgentSelector =
411
- | { readonly byInstanceId: string; readonly byInstanceName?: never }
412
- | { readonly byInstanceName: string; readonly byInstanceId?: never };
560
+ | { readonly byId: string; readonly byName?: never }
561
+ | { readonly byName: string; readonly byId?: never };
413
562
 
414
563
  export interface AIAgentInvocation<Input extends FlowClosedValue = FlowClosedValue> {
415
564
  readonly kind: 'ai.agent';