ai-workflow-logic 0.2.1 → 0.2.3
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 +12 -11
- package/src/agent-invocation.ts +62 -2
- package/src/agent-state.ts +3 -2
- package/src/checkpoint-filesystem.ts +23 -10
- package/src/checkpoint-profile.ts +3 -0
- package/src/checkpoint-sidecar.ts +77 -16
- package/src/checkpoint-store.ts +58 -8
- package/src/core.ts +2 -22
- package/src/definitions.ts +30 -0
- package/src/delegation.ts +387 -0
- package/src/index.ts +1 -0
- package/src/run-checkpoint.ts +30 -6
- package/src/run-freeze.ts +0 -125
- package/src/holon-task.ts +0 -199
package/src/run-freeze.ts
CHANGED
|
@@ -10,12 +10,6 @@ import type {
|
|
|
10
10
|
CompiledAIAgentCodeExecution,
|
|
11
11
|
AIAgentCodeExecutionIdentity,
|
|
12
12
|
} from 'ai-workflow-contract';
|
|
13
|
-
import {
|
|
14
|
-
normalizeHolonTaskTarget,
|
|
15
|
-
type AIWorkflowHolonTaskTargetFreezeReceipt,
|
|
16
|
-
type FrozenHolonTaskTarget,
|
|
17
|
-
type HolonTaskTarget,
|
|
18
|
-
} from 'ai-workflow-contract';
|
|
19
13
|
import {
|
|
20
14
|
buildResourceDependencySnapshot,
|
|
21
15
|
composeLayeredResourceRegistry,
|
|
@@ -72,125 +66,6 @@ export class AIWorkflowRunResourceFreezeError extends Error {
|
|
|
72
66
|
const authenticFreezeReceipts = new WeakSet<object>();
|
|
73
67
|
const authenticTaskBindings = new WeakSet<object>();
|
|
74
68
|
const receiptByTaskBinding = new WeakMap<object, AIWorkflowRunResourceFreezeReceipt>();
|
|
75
|
-
const authenticHolonTargetFreezeReceipts = new WeakSet<object>();
|
|
76
|
-
const authenticFrozenHolonTargets = new WeakSet<object>();
|
|
77
|
-
|
|
78
|
-
export interface FreezeAIWorkflowHolonTaskTargetInput {
|
|
79
|
-
readonly registry: EffectiveResourceRegistry;
|
|
80
|
-
readonly target: HolonTaskTarget;
|
|
81
|
-
readonly contentIdentities: ReadonlyMap<string, ResourceContentIdentity>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function freezeAIWorkflowHolonTaskTargetFromDirectory(
|
|
85
|
-
rootDir: string,
|
|
86
|
-
target: HolonTaskTarget,
|
|
87
|
-
): Promise<AIWorkflowHolonTaskTargetFreezeReceipt> {
|
|
88
|
-
const authoredTree = await loadResourceTree({ rootDir });
|
|
89
|
-
const tree = resolveAIWorkflowResourceTree(authoredTree);
|
|
90
|
-
const layers = [{ id: 'workspace', tree }] as const;
|
|
91
|
-
const registry = composeLayeredResourceRegistry({ layers });
|
|
92
|
-
return freezeAIWorkflowHolonTaskTarget({
|
|
93
|
-
registry,
|
|
94
|
-
target,
|
|
95
|
-
contentIdentities: createResolvedAIWorkflowContentIdentityIndex(tree),
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function freezeAIWorkflowHolonTaskTarget(
|
|
100
|
-
input: FreezeAIWorkflowHolonTaskTargetInput,
|
|
101
|
-
): AIWorkflowHolonTaskTargetFreezeReceipt {
|
|
102
|
-
const target = normalizeHolonTaskTarget(input.target);
|
|
103
|
-
const references = Object.freeze([
|
|
104
|
-
target.invocation.workflowRef,
|
|
105
|
-
target.executionBinding.ref,
|
|
106
|
-
target.taskSpace.profileRef,
|
|
107
|
-
target.taskSpace.policyRef,
|
|
108
|
-
...target.taskSpace.requiredCapabilityRefs,
|
|
109
|
-
target.output.schemaRef,
|
|
110
|
-
...target.output.materialPortRefs,
|
|
111
|
-
]);
|
|
112
|
-
const roots = references.map(resourceIdFromRef).filter((value): value is string => value !== undefined);
|
|
113
|
-
if (roots.length !== references.length) throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
114
|
-
diagnostic('AI_RUN_HOLON_TARGET_REF_INVALID', 'run-freeze:holon-target', 'Every target reference must be one exact resource:// identity.'),
|
|
115
|
-
]));
|
|
116
|
-
const workflowId = resourceIdFromRef(target.invocation.workflowRef)!;
|
|
117
|
-
const workflow = input.registry.byId.get(workflowId)?.resource;
|
|
118
|
-
if (!workflow || workflow.kind !== target.invocation.workflowKind) throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
119
|
-
diagnostic('AI_RUN_HOLON_TARGET_WORKFLOW_MISSING', target.invocation.workflowRef, 'Target workflow is absent or has another kind.'),
|
|
120
|
-
]));
|
|
121
|
-
const bindingId = resourceIdFromRef(target.executionBinding.ref)!;
|
|
122
|
-
const binding = input.registry.byId.get(bindingId)?.resource;
|
|
123
|
-
if (!binding || binding.kind !== 'HolonExecutionBinding') throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
124
|
-
diagnostic('AI_RUN_HOLON_EXECUTION_BINDING_MISSING', target.executionBinding.ref, 'Execution binding is absent or has another kind.'),
|
|
125
|
-
]));
|
|
126
|
-
const bindingIdentity = input.contentIdentities.get(bindingId);
|
|
127
|
-
if (!bindingIdentity || bindingIdentity.contentDigest !== target.executionBinding.digest) {
|
|
128
|
-
throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
129
|
-
diagnostic('AI_RUN_HOLON_EXECUTION_BINDING_DIGEST_MISMATCH', target.executionBinding.ref, 'Execution binding digest differs from the admitted resource content identity.'),
|
|
130
|
-
]));
|
|
131
|
-
}
|
|
132
|
-
for (const resourceId of roots) {
|
|
133
|
-
if (!input.registry.byId.get(resourceId)?.resource || !input.contentIdentities.has(resourceId)) {
|
|
134
|
-
throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
135
|
-
diagnostic('AI_RUN_HOLON_TARGET_CLOSURE_MISSING', `resource://${resourceId}`, 'Target closure member is absent from the admitted registry.'),
|
|
136
|
-
]));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
const dependencySnapshot = buildResourceDependencySnapshot({
|
|
140
|
-
registry: input.registry,
|
|
141
|
-
roots,
|
|
142
|
-
edges: references.slice(1).map((ref, index) => ({
|
|
143
|
-
fromResourceId: workflowId,
|
|
144
|
-
toResourceId: resourceIdFromRef(ref)!,
|
|
145
|
-
relation: 'workflow-holon-task-target',
|
|
146
|
-
declaredBy: `${workflowId}#${target.invocation.nodeId}:${index}`,
|
|
147
|
-
})),
|
|
148
|
-
contentIdentities: input.contentIdentities,
|
|
149
|
-
});
|
|
150
|
-
const closureResourceIds = Object.freeze(dependencySnapshot.closure.map(({ resourceId }) => resourceId));
|
|
151
|
-
const semanticFingerprint = sha256Digest(JSON.stringify({
|
|
152
|
-
schemaVersion: 'ai-workflow.holon-task-target-semantic/v1',
|
|
153
|
-
target,
|
|
154
|
-
closure: dependencySnapshot.closure.map(({ resourceId, kind, contentDigest }) => ({ resourceId, kind, contentDigest })),
|
|
155
|
-
}));
|
|
156
|
-
const receipt = Object.freeze({
|
|
157
|
-
schemaVersion: 'ai-workflow.holon-task-target-freeze/v1' as const,
|
|
158
|
-
target,
|
|
159
|
-
dependencySnapshot: Object.freeze({
|
|
160
|
-
registryRevision: dependencySnapshot.registryRevision,
|
|
161
|
-
snapshotRevision: dependencySnapshot.snapshotRevision,
|
|
162
|
-
closureResourceIds,
|
|
163
|
-
}),
|
|
164
|
-
semanticFingerprint,
|
|
165
|
-
});
|
|
166
|
-
authenticHolonTargetFreezeReceipts.add(receipt);
|
|
167
|
-
return receipt;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export function projectFrozenHolonTaskTarget(
|
|
171
|
-
receipt: AIWorkflowHolonTaskTargetFreezeReceipt,
|
|
172
|
-
): FrozenHolonTaskTarget {
|
|
173
|
-
if (!authenticHolonTargetFreezeReceipts.has(receipt as object)) throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
174
|
-
diagnostic('AI_RUN_HOLON_TARGET_FREEZE_RECEIPT_UNTRUSTED', 'run-freeze:holon-target-receipt', 'Target proof requires the authentic receipt produced by run freeze.'),
|
|
175
|
-
]));
|
|
176
|
-
const proof = Object.freeze({
|
|
177
|
-
schemaVersion: 'ai-workflow.frozen-holon-task-target/v1' as const,
|
|
178
|
-
target: receipt.target,
|
|
179
|
-
semanticFingerprint: receipt.semanticFingerprint,
|
|
180
|
-
snapshotRevision: receipt.dependencySnapshot.snapshotRevision,
|
|
181
|
-
closureResourceIds: receipt.dependencySnapshot.closureResourceIds,
|
|
182
|
-
});
|
|
183
|
-
authenticFrozenHolonTargets.add(proof);
|
|
184
|
-
return proof;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function assertFrozenHolonTaskTarget(value: FrozenHolonTaskTarget): FrozenHolonTaskTarget {
|
|
188
|
-
if (!authenticFrozenHolonTargets.has(value as object)) throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
189
|
-
diagnostic('AI_RUN_HOLON_TARGET_PROOF_UNTRUSTED', 'run-freeze:holon-target-proof', 'Holon task target was not projected from an authentic target freeze receipt.'),
|
|
190
|
-
]));
|
|
191
|
-
return value;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
69
|
export function freezeAIWorkflowRunResources(
|
|
195
70
|
input: FreezeAIWorkflowRunResourcesInput,
|
|
196
71
|
): AIWorkflowRunResourceFreezeReceipt {
|
package/src/holon-task.ts
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAIOrganizationTaskProfile,
|
|
3
|
-
normalizeHolonTaskTarget,
|
|
4
|
-
normalizeHolonTaskSnapshotReceipt,
|
|
5
|
-
type HolonTaskSnapshotReceipt,
|
|
6
|
-
type AIOrganizationTaskProfile,
|
|
7
|
-
type HolonTaskTarget,
|
|
8
|
-
} from 'ai-workflow-contract';
|
|
9
|
-
import {
|
|
10
|
-
canonicalHolonEffectiveSnapshotIssuanceReceiptBytes,
|
|
11
|
-
parseHolonEffectiveSnapshotBytes,
|
|
12
|
-
parseHolonEffectiveSnapshotIssuanceReceiptBytes,
|
|
13
|
-
} from 'holarchy-core-contract';
|
|
14
|
-
import { sha256Digest } from 'halfcode-compiler.xnl/resource-core';
|
|
15
|
-
import type { TaskArtifactBody, TaskArtifactRef } from 'task-manager-contract';
|
|
16
|
-
import { createTaskSpace, type TaskManagerRuntime, type TaskProcessorResult } from 'task-manager-logic';
|
|
17
|
-
import type { TaskTransitionReceipt } from 'task-manager-contract';
|
|
18
|
-
|
|
19
|
-
export interface HolonOrganizationSnapshotReadInput {
|
|
20
|
-
readonly rootHolonRef: string;
|
|
21
|
-
readonly effectiveAt: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface HolonOrganizationSnapshotReadResult {
|
|
25
|
-
readonly snapshotBytes: Uint8Array;
|
|
26
|
-
readonly issuanceReceiptBytes: Uint8Array;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface HolonOrganizationSnapshotReadPort {
|
|
30
|
-
readEffectiveSnapshot(input: HolonOrganizationSnapshotReadInput): Promise<HolonOrganizationSnapshotReadResult>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface CreateHolonTaskSpaceRuntime {
|
|
34
|
-
readonly taskManager: TaskManagerRuntime;
|
|
35
|
-
readonly organizationSnapshots: HolonOrganizationSnapshotReadPort;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface CreateHolonTaskSpaceInput {
|
|
39
|
-
readonly commandId: string;
|
|
40
|
-
readonly taskSpaceId: string;
|
|
41
|
-
readonly taskId: string;
|
|
42
|
-
readonly taskName: string;
|
|
43
|
-
readonly target: HolonTaskTarget;
|
|
44
|
-
readonly createdAt: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface CreateHolonTaskSpaceConfig {
|
|
48
|
-
readonly maxTasks: number;
|
|
49
|
-
readonly maxRelations: number;
|
|
50
|
-
readonly maxLeaseDurationMs: number;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface CreateHolonTaskSpaceResult extends TaskProcessorResult<TaskTransitionReceipt> {
|
|
54
|
-
readonly snapshotReceipt: HolonTaskSnapshotReceipt;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface PreparedHolonTaskSnapshot {
|
|
58
|
-
readonly target: HolonTaskTarget;
|
|
59
|
-
readonly snapshotReceipt: HolonTaskSnapshotReceipt;
|
|
60
|
-
readonly profile: AIOrganizationTaskProfile;
|
|
61
|
-
readonly artifactRefs: readonly TaskArtifactRef[];
|
|
62
|
-
readonly artifactBodies: readonly TaskArtifactBody[];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export async function prepareHolonTaskSnapshot(
|
|
66
|
-
runtime: Pick<CreateHolonTaskSpaceRuntime, 'organizationSnapshots'>,
|
|
67
|
-
input: Readonly<{
|
|
68
|
-
readonly taskSpaceId: string;
|
|
69
|
-
readonly target: HolonTaskTarget;
|
|
70
|
-
readonly snapshotAdoptions?: readonly unknown[];
|
|
71
|
-
}>,
|
|
72
|
-
): Promise<PreparedHolonTaskSnapshot> {
|
|
73
|
-
const target = normalizeHolonTaskTarget(input.target);
|
|
74
|
-
const issued = await runtime.organizationSnapshots.readEffectiveSnapshot({
|
|
75
|
-
rootHolonRef: target.holon.rootHolonRef,
|
|
76
|
-
effectiveAt: target.holon.effectiveAt,
|
|
77
|
-
});
|
|
78
|
-
const snapshotBytes = exactBytes(issued.snapshotBytes, 'snapshotBytes');
|
|
79
|
-
const receiptBytes = exactBytes(issued.issuanceReceiptBytes, 'issuanceReceiptBytes');
|
|
80
|
-
const snapshot = await parseHolonEffectiveSnapshotBytes(snapshotBytes);
|
|
81
|
-
const issuerReceipt = parseHolonEffectiveSnapshotIssuanceReceiptBytes(receiptBytes, snapshot);
|
|
82
|
-
if (snapshot.rootHolonRef !== target.holon.rootHolonRef || snapshot.effectiveAt !== target.holon.effectiveAt) {
|
|
83
|
-
throw new Error('HOLON_TASK_SNAPSHOT_TARGET_MISMATCH: issuer snapshot does not bind the requested Holon/effectiveAt');
|
|
84
|
-
}
|
|
85
|
-
const canonicalReceiptBytes = canonicalHolonEffectiveSnapshotIssuanceReceiptBytes(issuerReceipt, snapshot);
|
|
86
|
-
if (!sameBytes(receiptBytes, canonicalReceiptBytes)) {
|
|
87
|
-
throw new Error('HOLON_TASK_ISSUER_RECEIPT_NON_CANONICAL: issuer receipt bytes changed during validation');
|
|
88
|
-
}
|
|
89
|
-
const snapshotArtifact = artifact(snapshotBytes, 'application/vnd.holarchy.effective-snapshot+json', 'holon-effective-snapshot.json');
|
|
90
|
-
const receiptArtifact = artifact(receiptBytes, 'application/vnd.holarchy.snapshot-issuance-receipt+json', 'holon-effective-snapshot-receipt.json');
|
|
91
|
-
const eligibleMemberRefs = Object.freeze(snapshot.records.filter((record) => record.kind === 'Member').map((record) => record.id).sort(compareUtf16));
|
|
92
|
-
const eligibleRoleRefs = Object.freeze(snapshot.records.filter((record) => record.kind === 'Role').map((record) => record.id).sort(compareUtf16));
|
|
93
|
-
const snapshotReceipt = normalizeHolonTaskSnapshotReceipt({
|
|
94
|
-
kind: 'holon-task-snapshot-receipt',
|
|
95
|
-
schemaVersion: 'ai-workflow.holon-task-snapshot-receipt/v1',
|
|
96
|
-
taskSpaceId: exactString(input.taskSpaceId, 'taskSpaceId'),
|
|
97
|
-
holonRef: snapshot.rootHolonRef,
|
|
98
|
-
effectiveAt: snapshot.effectiveAt,
|
|
99
|
-
holonSnapshotRef: snapshot.snapshotId,
|
|
100
|
-
holonSnapshotDigest: snapshot.treeDigest,
|
|
101
|
-
snapshotArtifactDigest: snapshotArtifact.ref.digest,
|
|
102
|
-
issuerReceiptId: sha256Digest(receiptBytes),
|
|
103
|
-
issuerReceiptArtifactDigest: receiptArtifact.ref.digest,
|
|
104
|
-
executionBindingRef: target.executionBinding.ref,
|
|
105
|
-
executionBindingDigest: target.executionBinding.digest,
|
|
106
|
-
eligibleMemberRefs,
|
|
107
|
-
eligibleRoleRefs,
|
|
108
|
-
});
|
|
109
|
-
return Object.freeze({
|
|
110
|
-
target,
|
|
111
|
-
snapshotReceipt,
|
|
112
|
-
profile: createAIOrganizationTaskProfile(target, snapshotReceipt, input.snapshotAdoptions),
|
|
113
|
-
artifactRefs: Object.freeze([snapshotArtifact.ref, receiptArtifact.ref]),
|
|
114
|
-
artifactBodies: Object.freeze([snapshotArtifact.body, receiptArtifact.body]),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export async function createHolonTaskSpace(
|
|
119
|
-
runtime: CreateHolonTaskSpaceRuntime,
|
|
120
|
-
input: CreateHolonTaskSpaceInput,
|
|
121
|
-
config: CreateHolonTaskSpaceConfig,
|
|
122
|
-
): Promise<CreateHolonTaskSpaceResult> {
|
|
123
|
-
const prepared = await prepareHolonTaskSnapshot(runtime, {
|
|
124
|
-
taskSpaceId: input.taskSpaceId,
|
|
125
|
-
target: input.target,
|
|
126
|
-
});
|
|
127
|
-
const result = await createTaskSpace(runtime.taskManager, {
|
|
128
|
-
kind: 'task-space.create',
|
|
129
|
-
commandId: exactString(input.commandId, 'commandId'),
|
|
130
|
-
taskSpaceId: prepared.snapshotReceipt.taskSpaceId,
|
|
131
|
-
createdAt: input.createdAt,
|
|
132
|
-
definition: {
|
|
133
|
-
kind: 'task-space-definition',
|
|
134
|
-
taskSpaceId: prepared.snapshotReceipt.taskSpaceId,
|
|
135
|
-
name: input.taskName,
|
|
136
|
-
schemaVersion: 1,
|
|
137
|
-
tasks: [{
|
|
138
|
-
kind: 'task',
|
|
139
|
-
taskId: exactString(input.taskId, 'taskId'),
|
|
140
|
-
name: exactString(input.taskName, 'taskName'),
|
|
141
|
-
order: 0,
|
|
142
|
-
profile: prepared.profile,
|
|
143
|
-
inputArtifacts: prepared.artifactRefs,
|
|
144
|
-
}],
|
|
145
|
-
relations: [{
|
|
146
|
-
kind: 'parent-child',
|
|
147
|
-
relationId: `root:${input.taskId}`,
|
|
148
|
-
parentTaskId: null,
|
|
149
|
-
childTaskId: input.taskId,
|
|
150
|
-
order: 0,
|
|
151
|
-
}],
|
|
152
|
-
},
|
|
153
|
-
artifactBodies: prepared.artifactBodies,
|
|
154
|
-
}, config);
|
|
155
|
-
return Object.freeze({ ...result, snapshotReceipt: prepared.snapshotReceipt });
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function artifact(bytes: Uint8Array, mediaType: string, name: string): {
|
|
159
|
-
readonly ref: TaskArtifactRef;
|
|
160
|
-
readonly body: TaskArtifactBody;
|
|
161
|
-
} {
|
|
162
|
-
const digest = sha256Digest(bytes);
|
|
163
|
-
const ref = Object.freeze({
|
|
164
|
-
kind: 'task-artifact-ref' as const,
|
|
165
|
-
digest,
|
|
166
|
-
mediaType,
|
|
167
|
-
sizeBytes: bytes.byteLength,
|
|
168
|
-
name,
|
|
169
|
-
});
|
|
170
|
-
return Object.freeze({
|
|
171
|
-
ref,
|
|
172
|
-
body: Object.freeze({
|
|
173
|
-
kind: 'task-artifact-body' as const,
|
|
174
|
-
digest,
|
|
175
|
-
mediaType,
|
|
176
|
-
sizeBytes: bytes.byteLength,
|
|
177
|
-
encoding: 'base64' as const,
|
|
178
|
-
data: Buffer.from(bytes).toString('base64'),
|
|
179
|
-
}),
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function exactBytes(value: Uint8Array, name: string): Uint8Array {
|
|
184
|
-
if (!(value instanceof Uint8Array) || value.byteLength === 0) throw new Error(`HOLON_TASK_${name.toUpperCase()}_INVALID`);
|
|
185
|
-
return Uint8Array.from(value);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function exactString(value: string, name: string): string {
|
|
189
|
-
if (typeof value !== 'string' || value.length === 0 || value !== value.trim()) throw new Error(`HOLON_TASK_${name.toUpperCase()}_INVALID`);
|
|
190
|
-
return value;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function sameBytes(left: Uint8Array, right: Uint8Array): boolean {
|
|
194
|
-
return left.byteLength === right.byteLength && left.every((byte, index) => byte === right[index]);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function compareUtf16(left: string, right: string): number {
|
|
198
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
199
|
-
}
|