ai-data-workflow-logic 0.1.8 → 0.1.10

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-data-workflow-logic",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "private": false,
5
5
  "description": "EagerDataFlow-backed AI Data Workflow RunGraph helpers",
6
6
  "type": "module",
@@ -11,13 +11,15 @@
11
11
  "./filesystem": "./src/filesystem.ts"
12
12
  },
13
13
  "dependencies": {
14
- "ai-data-workflow-contract": "0.1.4",
15
- "ai-workflow-contract": "0.1.7",
16
- "ai-workflow-logic": "0.1.7",
14
+ "ai-data-workflow-contract": "0.1.5",
15
+ "ai-workflow-contract": "0.1.8",
16
+ "ai-workflow-logic": "0.1.9",
17
17
  "eager-data-flow-contract": "0.1.3",
18
18
  "eager-data-flow-logic": "0.1.4",
19
19
  "flow-step-space-logic": "0.1.1",
20
- "work-ctrl-flow-logic": "0.1.3"
20
+ "task-manager-contract": "0.1.3",
21
+ "task-manager-logic": "0.1.6",
22
+ "work-ctrl-flow-logic": "0.1.4"
21
23
  },
22
24
  "files": [
23
25
  "src"
@@ -0,0 +1,142 @@
1
+ import {
2
+ deepFrozenCanonicalOwnDataClone,
3
+ type ImmutableJsonValue,
4
+ type TaskArtifactBody,
5
+ type TaskArtifactRef,
6
+ type TaskRecord,
7
+ type TaskSettlementReceipt,
8
+ } from 'task-manager-contract';
9
+ import type { FrozenHolonTaskTarget, HolonTaskTarget } from 'ai-workflow-contract';
10
+ import { normalizeHolonTaskTarget } from 'ai-workflow-contract';
11
+ import { assertFrozenHolonTaskTarget } from 'ai-workflow-logic/run-freeze';
12
+ import type { TaskManagerRuntime } from 'task-manager-logic';
13
+
14
+ export interface AIDataHolonTaskMaterial {
15
+ readonly materialPortRef: `resource://${string}`;
16
+ readonly artifact: TaskArtifactRef;
17
+ readonly body: TaskArtifactBody;
18
+ }
19
+
20
+ export interface AIDataHolonTaskMaterialValidationInput {
21
+ readonly schemaRef: `resource://${string}`;
22
+ readonly materials: readonly AIDataHolonTaskMaterial[];
23
+ }
24
+
25
+ /** Runtime-owned ResourcePackage schema/material validation port. */
26
+ export interface AIDataHolonTaskMaterialValidationPort {
27
+ validateSettlementMaterial(input: AIDataHolonTaskMaterialValidationInput): Promise<ImmutableJsonValue>;
28
+ }
29
+
30
+ export interface AIDataHolonTaskRuntime {
31
+ readonly taskManager: TaskManagerRuntime;
32
+ readonly materials: AIDataHolonTaskMaterialValidationPort;
33
+ }
34
+
35
+ export interface ConsumeAIDataHolonTaskInput {
36
+ readonly frozenTarget: FrozenHolonTaskTarget;
37
+ readonly taskSpaceId: string;
38
+ readonly taskId: string;
39
+ readonly settlementCommandId: string;
40
+ }
41
+
42
+ export interface ConsumeAIDataHolonTaskResult {
43
+ readonly kind: 'ai-data-holon-task-settlement';
44
+ readonly taskSpaceId: string;
45
+ readonly taskId: string;
46
+ readonly settlementReceiptId: string;
47
+ readonly materialDigests: readonly `sha256:${string}`[];
48
+ readonly output: ImmutableJsonValue;
49
+ }
50
+
51
+ /**
52
+ * Processor that projects a settled organization task into an AI Data value.
53
+ * Generic actor/session state and live Holon sources are intentionally absent
54
+ * from this runtime boundary.
55
+ */
56
+ export async function consumeAIDataHolonTask(
57
+ runtime: AIDataHolonTaskRuntime,
58
+ input: ConsumeAIDataHolonTaskInput,
59
+ _config: Readonly<Record<string, never>>,
60
+ ): Promise<ConsumeAIDataHolonTaskResult> {
61
+ const proof = assertFrozenHolonTaskTarget(input.frozenTarget);
62
+ const snapshot = await runtime.taskManager.owner.readSnapshot(input.taskSpaceId);
63
+ if (!snapshot) fail('TASK_SPACE_MISSING', input.taskSpaceId);
64
+ const task = snapshot.tasks.find((candidate) => candidate.taskId === input.taskId);
65
+ if (!task || task.profile.profileKind !== 'depa.ai.organization-task' || task.profile.schemaVersion !== 1) {
66
+ fail('TASK_PROFILE_MISMATCH', input.taskId);
67
+ }
68
+ const target = normalizeHolonTaskTarget(task.profile.facts.target);
69
+ assertSameTarget(target, proof.target);
70
+ const receipt = await runtime.taskManager.owner.readReceiptByCommand(
71
+ input.taskSpaceId,
72
+ input.settlementCommandId,
73
+ );
74
+ assertSettlement(receipt, task, input.taskId);
75
+ if (task.status !== 'Succeeded') fail('TASK_NOT_SUCCEEDED', `${task.taskId}:${task.status}`);
76
+
77
+ const materials = await readExactMaterials(runtime, input.taskSpaceId, task, target);
78
+ const output = deepFrozenCanonicalOwnDataClone(await runtime.materials.validateSettlementMaterial({
79
+ schemaRef: target.output.schemaRef,
80
+ materials,
81
+ }));
82
+ return deepFrozenCanonicalOwnDataClone({
83
+ kind: 'ai-data-holon-task-settlement',
84
+ taskSpaceId: input.taskSpaceId,
85
+ taskId: input.taskId,
86
+ settlementReceiptId: receipt.receiptId,
87
+ materialDigests: materials.map(({ artifact }) => artifact.digest),
88
+ output,
89
+ });
90
+ }
91
+
92
+ async function readExactMaterials(
93
+ runtime: AIDataHolonTaskRuntime,
94
+ taskSpaceId: string,
95
+ task: TaskRecord,
96
+ target: HolonTaskTarget,
97
+ ): Promise<readonly AIDataHolonTaskMaterial[]> {
98
+ if (task.outputArtifacts.length !== target.output.materialPortRefs.length) {
99
+ fail('MATERIAL_PORT_MISMATCH', 'settlement artifact count does not match the frozen target');
100
+ }
101
+ const byPort = new Map<string, TaskArtifactRef>();
102
+ for (const artifact of task.outputArtifacts) {
103
+ if (artifact.name === undefined || !target.output.materialPortRefs.includes(artifact.name as `resource://${string}`)
104
+ || byPort.has(artifact.name)) {
105
+ fail('MATERIAL_PORT_MISMATCH', 'artifact names must map one-to-one to declared MaterialPorts');
106
+ }
107
+ byPort.set(artifact.name, artifact);
108
+ }
109
+ const materials: AIDataHolonTaskMaterial[] = [];
110
+ for (const materialPortRef of target.output.materialPortRefs) {
111
+ const artifact = byPort.get(materialPortRef);
112
+ if (!artifact) fail('MATERIAL_PORT_MISSING', materialPortRef);
113
+ const body = await runtime.taskManager.owner.readArtifact(taskSpaceId, artifact.digest);
114
+ if (!body || body.digest !== artifact.digest || body.mediaType !== artifact.mediaType
115
+ || body.sizeBytes !== artifact.sizeBytes) {
116
+ fail('MATERIAL_BODY_MISMATCH', artifact.digest);
117
+ }
118
+ materials.push(deepFrozenCanonicalOwnDataClone({ materialPortRef, artifact, body }));
119
+ }
120
+ return deepFrozenCanonicalOwnDataClone(materials);
121
+ }
122
+
123
+ function assertSettlement(
124
+ receipt: Awaited<ReturnType<TaskManagerRuntime['owner']['readReceiptByCommand']>>,
125
+ task: TaskRecord,
126
+ taskId: string,
127
+ ): asserts receipt is TaskSettlementReceipt {
128
+ if (!receipt || receipt.kind !== 'task-settlement-receipt' || receipt.taskId !== taskId
129
+ || receipt.status !== task.status || receipt.toRevision < receipt.fromRevision) {
130
+ fail('SETTLEMENT_RECEIPT_MISMATCH', taskId);
131
+ }
132
+ }
133
+
134
+ function assertSameTarget(actual: HolonTaskTarget, expected: HolonTaskTarget): void {
135
+ if (JSON.stringify(actual) !== JSON.stringify(expected)) {
136
+ fail('FROZEN_TARGET_MISMATCH', expected.invocation.nodeId);
137
+ }
138
+ }
139
+
140
+ function fail(code: string, detail: string): never {
141
+ throw new Error(`AI_DATA_HOLON_TASK_${code}: ${detail}`);
142
+ }
package/src/index.ts CHANGED
@@ -61,6 +61,8 @@ import {
61
61
  } from 'ai-workflow-logic';
62
62
  import { assertFrozenAIAgentTaskBinding } from 'ai-workflow-logic/run-freeze';
63
63
 
64
+ export * from './holon-task.js';
65
+
64
66
  export interface CreateAIDataWorkflowCheckpointInput {
65
67
  readonly instanceId: string;
66
68
  readonly definition: FlowDefinitionArtifactIdentity;