ai-workflow-logic 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.
@@ -755,7 +755,10 @@ function normalizeAIDataRunGraph(value: unknown, runId: string, location: string
755
755
  'id', 'tag', 'nodeType', 'generation', 'status', 'declarationIndex', 'inputs',
756
756
  'outputs', 'config', 'dependsOn', 'dependents', 'reusePolicy',
757
757
  ],
758
- ['semanticFingerprint', 'result', 'invalidatedBy'],
758
+ [
759
+ 'subflow', 'childInvocation', 'childFreezeReceipt', 'childTerminalReceipt',
760
+ 'semanticFingerprint', 'result', 'invalidatedBy',
761
+ ],
759
762
  nodeLocation,
760
763
  );
761
764
  const storedId = canonicalIdentity(dataField(node, 'id', `${nodeLocation}.id`), `${nodeLocation}.id`);
@@ -778,6 +781,46 @@ function normalizeAIDataRunGraph(value: unknown, runId: string, location: string
778
781
  normalizeAIDataInputs(dataField(node, 'inputs', `${nodeLocation}.inputs`), `${nodeLocation}.inputs`);
779
782
  uniqueIdentityArray(dataField(node, 'outputs', `${nodeLocation}.outputs`), `${nodeLocation}.outputs`);
780
783
  const config = plainRecord(dataField(node, 'config', `${nodeLocation}.config`), `${nodeLocation}.config`);
784
+ const tag = String(dataField(node, 'tag', `${nodeLocation}.tag`));
785
+ const hasSubflow = Object.prototype.hasOwnProperty.call(node, 'subflow');
786
+ if (tag === 'SubFlowNode' && !hasSubflow) {
787
+ invalid('AI_DATA_SUBFLOW_BINDING_MISSING', `${nodeLocation}.subflow`, 'SubFlowNode requires an exact durable child binding.');
788
+ }
789
+ if (tag !== 'SubFlowNode' && hasSubflow) {
790
+ invalid('AI_DATA_SUBFLOW_BINDING_INVALID', `${nodeLocation}.subflow`, 'Only SubFlowNode may carry a child binding.');
791
+ }
792
+ if (hasSubflow) normalizeAIDataSubflowBinding(dataField(node, 'subflow', `${nodeLocation}.subflow`), `${nodeLocation}.subflow`);
793
+ const hasChildInvocation = Object.prototype.hasOwnProperty.call(node, 'childInvocation');
794
+ const hasChildFreeze = Object.prototype.hasOwnProperty.call(node, 'childFreezeReceipt');
795
+ const hasChildTerminal = Object.prototype.hasOwnProperty.call(node, 'childTerminalReceipt');
796
+ if ((hasChildInvocation || hasChildFreeze || hasChildTerminal) && tag !== 'SubFlowNode') {
797
+ invalid('AI_DATA_CHILD_INVOCATION_NODE_INVALID', nodeLocation, 'Only SubFlowNode may carry child invocation facts.');
798
+ }
799
+ if ((hasChildFreeze || hasChildTerminal) && !hasChildInvocation) {
800
+ invalid('AI_DATA_CHILD_INVOCATION_IDENTITY_MISSING', nodeLocation, 'Child receipts require a reserved invocation identity.');
801
+ }
802
+ if (hasChildInvocation) {
803
+ const identity = normalizeAIDataChildInvocationIdentity(
804
+ dataField(node, 'childInvocation', `${nodeLocation}.childInvocation`),
805
+ graphRunId,
806
+ nodeId,
807
+ generation,
808
+ dataField(node, 'subflow', `${nodeLocation}.subflow`),
809
+ `${nodeLocation}.childInvocation`,
810
+ );
811
+ if (hasChildFreeze) normalizeAIDataChildFreezeReceipt(
812
+ dataField(node, 'childFreezeReceipt', `${nodeLocation}.childFreezeReceipt`),
813
+ identity,
814
+ `${nodeLocation}.childFreezeReceipt`,
815
+ );
816
+ if (hasChildTerminal) normalizeAIDataChildTerminalReceipt(
817
+ dataField(node, 'childTerminalReceipt', `${nodeLocation}.childTerminalReceipt`),
818
+ identity,
819
+ node,
820
+ String(status),
821
+ `${nodeLocation}.childTerminalReceipt`,
822
+ );
823
+ }
781
824
  const dependsOn = uniqueIdentityArray(dataField(node, 'dependsOn', `${nodeLocation}.dependsOn`), `${nodeLocation}.dependsOn`);
782
825
  const dependents = uniqueIdentityArray(dataField(node, 'dependents', `${nodeLocation}.dependents`), `${nodeLocation}.dependents`);
783
826
  normalizeReusePolicy(
@@ -811,6 +854,17 @@ function normalizeAIDataRunGraph(value: unknown, runId: string, location: string
811
854
  `${nodeLocation}.result`,
812
855
  );
813
856
  normalizeAIDataResultOutput(resultValue, node, String(status), bindingDefinition, `${nodeLocation}.result`);
857
+ if (hasChildTerminal) {
858
+ const childReceipt = plainRecord(
859
+ dataField(node, 'childTerminalReceipt', `${nodeLocation}.childTerminalReceipt`),
860
+ `${nodeLocation}.childTerminalReceipt`,
861
+ );
862
+ if (String(status) === 'Succeeded'
863
+ && JSON.stringify(dataField(childReceipt, 'output', `${nodeLocation}.childTerminalReceipt.output`))
864
+ !== JSON.stringify(dataField(plainRecord(resultValue, `${nodeLocation}.result`), 'output', `${nodeLocation}.result.output`))) {
865
+ invalid('AI_DATA_CHILD_PARENT_OUTPUT_MISMATCH', `${nodeLocation}.result.output`, 'Parent result must equal the accepted child output.');
866
+ }
867
+ }
814
868
  }
815
869
  const invalidationFacts: string[] = [];
816
870
  if (Object.prototype.hasOwnProperty.call(node, 'invalidatedBy')) {
@@ -988,12 +1042,176 @@ function normalizeInitialAIDataNodeProjection(
988
1042
  ? dataField(definitionNode, 'config', `${location}.bindingNode.config`)
989
1043
  : {},
990
1044
  dependsOn: eagerDefinitionDependencies(definition, definitionNode, nodeId, location),
1045
+ ...(dataField(definitionNode, 'tag', `${location}.bindingNode.tag`) === 'SubFlowNode'
1046
+ ? {
1047
+ subflow: {
1048
+ kind: 'declared',
1049
+ flowRef: dataField(definitionNode, 'flow', `${location}.bindingNode.flow`),
1050
+ },
1051
+ }
1052
+ : {}),
991
1053
  };
992
1054
  for (const field of ['tag', 'declarationIndex', 'inputs', 'outputs', 'config', 'dependsOn'] as const) {
993
1055
  if (JSON.stringify(dataField(node, field, `${location}.${field}`)) !== JSON.stringify(projected[field])) {
994
1056
  invalid('AI_DATA_NODE_PROJECTION_MISMATCH', `${location}.${field}`, `Initial run node ${field} differs from its binding projection.`);
995
1057
  }
996
1058
  }
1059
+ if (Object.prototype.hasOwnProperty.call(projected, 'subflow')
1060
+ && JSON.stringify(dataField(node, 'subflow', `${location}.subflow`)) !== JSON.stringify(projected.subflow)) {
1061
+ invalid('AI_DATA_NODE_PROJECTION_MISMATCH', `${location}.subflow`, 'Initial run node subflow differs from its binding projection.');
1062
+ }
1063
+ }
1064
+
1065
+ function normalizeAIDataSubflowBinding(value: unknown, location: string): void {
1066
+ const binding = plainRecord(value, location);
1067
+ const kind = dataField(binding, 'kind', `${location}.kind`);
1068
+ if (kind === 'declared') {
1069
+ exactRecord(value, ['kind', 'flowRef'], [], location);
1070
+ } else if (kind === 'autonomous') {
1071
+ const autonomous = exactRecord(
1072
+ value,
1073
+ ['kind', 'schemaVersion', 'capabilityId', 'catalogDigest', 'definitionRef', 'flowRef', 'contractDigest'],
1074
+ [],
1075
+ location,
1076
+ );
1077
+ if (dataField(autonomous, 'schemaVersion', `${location}.schemaVersion`) !== 'depa.ai-data-subflow-binding/v1') {
1078
+ invalid('AI_DATA_SUBFLOW_BINDING_VERSION_INVALID', `${location}.schemaVersion`, 'Unsupported autonomous child binding version.');
1079
+ }
1080
+ const definitionRef = canonicalIdentity(dataField(autonomous, 'definitionRef', `${location}.definitionRef`), `${location}.definitionRef`);
1081
+ if (!definitionRef.startsWith('resource://')) {
1082
+ invalid('AI_DATA_SUBFLOW_DEFINITION_REF_INVALID', `${location}.definitionRef`, 'Child definition must use resource:// identity.');
1083
+ }
1084
+ for (const field of ['capabilityId', 'catalogDigest', 'contractDigest'] as const) {
1085
+ canonicalIdentity(dataField(autonomous, field, `${location}.${field}`), `${location}.${field}`);
1086
+ }
1087
+ } else {
1088
+ invalid('AI_DATA_SUBFLOW_BINDING_KIND_INVALID', `${location}.kind`, 'Child binding kind must be declared or autonomous.');
1089
+ }
1090
+ const flowRef = canonicalIdentity(dataField(binding, 'flowRef', `${location}.flowRef`), `${location}.flowRef`);
1091
+ if (!flowRef.startsWith('eager-data-flow://')) {
1092
+ invalid('AI_DATA_SUBFLOW_FLOW_REF_INVALID', `${location}.flowRef`, 'Child flow must use eager-data-flow:// identity.');
1093
+ }
1094
+ }
1095
+
1096
+ interface NormalizedAIDataChildInvocationIdentity {
1097
+ readonly invocationKey: string;
1098
+ readonly childInstanceId: string;
1099
+ readonly childRunId: string;
1100
+ readonly definitionRef: string;
1101
+ readonly flowRef: string;
1102
+ readonly contractDigest: string;
1103
+ }
1104
+
1105
+ function normalizeAIDataChildInvocationIdentity(
1106
+ value: unknown,
1107
+ parentRunId: string,
1108
+ parentNodeId: string,
1109
+ parentGeneration: number,
1110
+ subflowValue: unknown,
1111
+ location: string,
1112
+ ): NormalizedAIDataChildInvocationIdentity {
1113
+ const identity = exactRecord(value, [
1114
+ 'schemaVersion', 'invocationKey', 'parentInstanceId', 'parentRunId', 'parentNodeId', 'parentGeneration',
1115
+ 'childInstanceId', 'childRunId', 'subflow',
1116
+ ], [], location);
1117
+ if (dataField(identity, 'schemaVersion', `${location}.schemaVersion`) !== 'depa.ai-data-child-invocation/v1') {
1118
+ invalid('AI_DATA_CHILD_INVOCATION_SCHEMA_INVALID', `${location}.schemaVersion`, 'Unsupported child invocation schema.');
1119
+ }
1120
+ canonicalIdentity(dataField(identity, 'parentInstanceId', `${location}.parentInstanceId`), `${location}.parentInstanceId`);
1121
+ if (canonicalIdentity(dataField(identity, 'parentRunId', `${location}.parentRunId`), `${location}.parentRunId`) !== parentRunId
1122
+ || canonicalIdentity(dataField(identity, 'parentNodeId', `${location}.parentNodeId`), `${location}.parentNodeId`) !== parentNodeId
1123
+ || nonNegativeSafeInteger(dataField(identity, 'parentGeneration', `${location}.parentGeneration`), `${location}.parentGeneration`) !== parentGeneration) {
1124
+ invalid('AI_DATA_CHILD_INVOCATION_PARENT_MISMATCH', location, 'Child invocation identity must bind the owning parent node generation.');
1125
+ }
1126
+ const subflow = dataField(identity, 'subflow', `${location}.subflow`);
1127
+ normalizeAIDataSubflowBinding(subflow, `${location}.subflow`);
1128
+ if (JSON.stringify(subflow) !== JSON.stringify(subflowValue)) {
1129
+ invalid('AI_DATA_CHILD_INVOCATION_SUBFLOW_MISMATCH', `${location}.subflow`, 'Child invocation must bind the exact node subflow.');
1130
+ }
1131
+ const normalizedSubflow = plainRecord(subflow, `${location}.subflow`);
1132
+ if (dataField(normalizedSubflow, 'kind', `${location}.subflow.kind`) !== 'autonomous') {
1133
+ invalid('AI_DATA_CHILD_INVOCATION_SUBFLOW_INVALID', `${location}.subflow`, 'Durable child invocation requires an autonomous subflow binding.');
1134
+ }
1135
+ return {
1136
+ invocationKey: canonicalIdentity(dataField(identity, 'invocationKey', `${location}.invocationKey`), `${location}.invocationKey`),
1137
+ childInstanceId: canonicalIdentity(dataField(identity, 'childInstanceId', `${location}.childInstanceId`), `${location}.childInstanceId`),
1138
+ childRunId: canonicalIdentity(dataField(identity, 'childRunId', `${location}.childRunId`), `${location}.childRunId`),
1139
+ definitionRef: canonicalIdentity(dataField(normalizedSubflow, 'definitionRef', `${location}.subflow.definitionRef`), `${location}.subflow.definitionRef`),
1140
+ flowRef: canonicalIdentity(dataField(normalizedSubflow, 'flowRef', `${location}.subflow.flowRef`), `${location}.subflow.flowRef`),
1141
+ contractDigest: canonicalIdentity(dataField(normalizedSubflow, 'contractDigest', `${location}.subflow.contractDigest`), `${location}.subflow.contractDigest`),
1142
+ };
1143
+ }
1144
+
1145
+ function assertAIDataChildReceiptIdentity(
1146
+ value: Record<string, unknown>,
1147
+ identity: NormalizedAIDataChildInvocationIdentity,
1148
+ location: string,
1149
+ ): void {
1150
+ for (const [field, expected] of Object.entries(identity)) {
1151
+ if (field === 'definitionRef' || field === 'flowRef' || field === 'contractDigest'
1152
+ || field === 'invocationKey' || field === 'childInstanceId' || field === 'childRunId') {
1153
+ if (canonicalIdentity(dataField(value, field, `${location}.${field}`), `${location}.${field}`) !== expected) {
1154
+ invalid('AI_DATA_CHILD_RECEIPT_IDENTITY_MISMATCH', `${location}.${field}`, 'Child receipt does not match the reserved invocation.');
1155
+ }
1156
+ }
1157
+ }
1158
+ }
1159
+
1160
+ function normalizeAIDataChildFreezeReceipt(
1161
+ value: unknown,
1162
+ identity: NormalizedAIDataChildInvocationIdentity,
1163
+ location: string,
1164
+ ): void {
1165
+ const receipt = exactRecord(value, [
1166
+ 'schemaVersion', 'invocationKey', 'childInstanceId', 'childRunId', 'definitionRef', 'flowRef',
1167
+ 'contractDigest', 'definitionRevision', 'definitionDigest',
1168
+ ], [], location);
1169
+ if (dataField(receipt, 'schemaVersion', `${location}.schemaVersion`) !== 'depa.ai-data-child-invocation/v1') {
1170
+ invalid('AI_DATA_CHILD_FREEZE_SCHEMA_INVALID', `${location}.schemaVersion`, 'Unsupported child freeze schema.');
1171
+ }
1172
+ assertAIDataChildReceiptIdentity(receipt, identity, location);
1173
+ canonicalIdentity(dataField(receipt, 'definitionRevision', `${location}.definitionRevision`), `${location}.definitionRevision`);
1174
+ canonicalIdentity(dataField(receipt, 'definitionDigest', `${location}.definitionDigest`), `${location}.definitionDigest`);
1175
+ }
1176
+
1177
+ function normalizeAIDataChildTerminalReceipt(
1178
+ value: unknown,
1179
+ identity: NormalizedAIDataChildInvocationIdentity,
1180
+ node: Record<string, unknown>,
1181
+ nodeStatus: string,
1182
+ location: string,
1183
+ ): void {
1184
+ const base = plainRecord(value, location);
1185
+ const terminalStatus = dataField(base, 'status', `${location}.status`);
1186
+ const receipt = exactRecord(value, [
1187
+ 'schemaVersion', 'invocationKey', 'childInstanceId', 'childRunId', 'definitionRef', 'flowRef',
1188
+ 'contractDigest', 'status', 'receiptDigest',
1189
+ ...(terminalStatus === 'Succeeded' ? ['output'] : ['failureCode', 'failureMessage']),
1190
+ ], [], location);
1191
+ if (dataField(receipt, 'schemaVersion', `${location}.schemaVersion`) !== 'depa.ai-data-child-invocation/v1') {
1192
+ invalid('AI_DATA_CHILD_TERMINAL_SCHEMA_INVALID', `${location}.schemaVersion`, 'Unsupported child terminal schema.');
1193
+ }
1194
+ if (terminalStatus !== 'Succeeded' && terminalStatus !== 'Failed') {
1195
+ invalid('AI_DATA_CHILD_TERMINAL_STATUS_INVALID', `${location}.status`, 'Child terminal receipt must be Succeeded or Failed.');
1196
+ }
1197
+ if (terminalStatus !== nodeStatus) {
1198
+ invalid('AI_DATA_CHILD_TERMINAL_PARENT_STATUS_MISMATCH', `${location}.status`, 'Child terminal status must equal its parent node status.');
1199
+ }
1200
+ assertAIDataChildReceiptIdentity(receipt, identity, location);
1201
+ canonicalIdentity(dataField(receipt, 'receiptDigest', `${location}.receiptDigest`), `${location}.receiptDigest`);
1202
+ if (terminalStatus === 'Succeeded') {
1203
+ const output = plainRecord(dataField(receipt, 'output', `${location}.output`), `${location}.output`);
1204
+ const expected = [...identityArray(
1205
+ dataField(node, 'outputs', `${location}.nodeOutputs`),
1206
+ `${location}.nodeOutputs`,
1207
+ )].sort(compareCodeUnits);
1208
+ if (JSON.stringify(stringDataKeys(output, `${location}.output`).sort(compareCodeUnits)) !== JSON.stringify(expected)) {
1209
+ invalid('AI_DATA_CHILD_TERMINAL_OUTPUT_MISMATCH', `${location}.output`, 'Child output keys must equal the parent SubFlowNode ports.');
1210
+ }
1211
+ } else {
1212
+ canonicalIdentity(dataField(receipt, 'failureCode', `${location}.failureCode`), `${location}.failureCode`);
1213
+ canonicalIdentity(dataField(receipt, 'failureMessage', `${location}.failureMessage`), `${location}.failureMessage`);
1214
+ }
997
1215
  }
998
1216
 
999
1217
  function eagerDefinitionDependencies(
@@ -1321,7 +1539,7 @@ function normalizeAIDataPatchNodeSpec(value: unknown, location: string): string
1321
1539
  const spec = exactRecord(
1322
1540
  value,
1323
1541
  ['id'],
1324
- ['tag', 'nodeType', 'declarationIndex', 'inputs', 'outputs', 'config', 'dependsOn', 'reusePolicy'],
1542
+ ['tag', 'nodeType', 'declarationIndex', 'inputs', 'outputs', 'config', 'subflow', 'dependsOn', 'reusePolicy'],
1325
1543
  location,
1326
1544
  );
1327
1545
  const nodeId = canonicalIdentity(dataField(spec, 'id', `${location}.id`), `${location}.id`);
@@ -1333,7 +1551,7 @@ function normalizeAIDataPatchNodeChanges(value: unknown, location: string): void
1333
1551
  const changes = exactRecord(
1334
1552
  value,
1335
1553
  [],
1336
- ['tag', 'nodeType', 'inputs', 'outputs', 'config', 'dependsOn', 'reusePolicy'],
1554
+ ['tag', 'nodeType', 'inputs', 'outputs', 'config', 'subflow', 'dependsOn', 'reusePolicy'],
1337
1555
  location,
1338
1556
  );
1339
1557
  normalizeAIDataPatchNodeFields(changes, location);
@@ -1349,6 +1567,10 @@ function normalizeAIDataPatchNodeFields(record: Record<string, unknown>, locatio
1349
1567
  if (Object.prototype.hasOwnProperty.call(record, field)) uniqueIdentityArray(dataField(record, field, `${location}.${field}`), `${location}.${field}`);
1350
1568
  }
1351
1569
  if (Object.prototype.hasOwnProperty.call(record, 'config')) plainRecord(dataField(record, 'config', `${location}.config`), `${location}.config`);
1570
+ if (Object.prototype.hasOwnProperty.call(record, 'subflow')) {
1571
+ const value = dataField(record, 'subflow', `${location}.subflow`);
1572
+ if (value !== null) normalizeAIDataSubflowBinding(value, `${location}.subflow`);
1573
+ }
1352
1574
  if (Object.prototype.hasOwnProperty.call(record, 'reusePolicy')) {
1353
1575
  const reuse = exactRecord(dataField(record, 'reusePolicy', `${location}.reusePolicy`), ['policy', 'source', 'nodeType'], [], `${location}.reusePolicy`);
1354
1576
  canonicalIdentity(dataField(reuse, 'nodeType', `${location}.reusePolicy.nodeType`), `${location}.reusePolicy.nodeType`);
package/src/run-freeze.ts CHANGED
@@ -18,7 +18,6 @@ import {
18
18
  buildResourceDependencySnapshot,
19
19
  composeLayeredResourceRegistry,
20
20
  loadResourceTree,
21
- resolveEffectiveResourceContentIdentities,
22
21
  sha256Digest,
23
22
  type EffectiveResourceRegistry,
24
23
  type ResourceContentIdentity,
@@ -26,6 +25,10 @@ import {
26
25
  } from 'halfcode-compiler.xnl/resource-core';
27
26
  import { projectAIWorkflowAgentResources } from './agent-resources.js';
28
27
  import { sourceRegistryForAIWorkflowAgentResourceProjection } from './agent-resource-brand.js';
28
+ import {
29
+ createResolvedAIWorkflowContentIdentityIndex,
30
+ resolveAIWorkflowResourceTree,
31
+ } from './resource-resolution.js';
29
32
 
30
33
  export interface FreezeAIWorkflowRunResourcesInput {
31
34
  readonly registry: EffectiveResourceRegistry;
@@ -39,14 +42,15 @@ export async function freezeAIWorkflowRunResourcesFromDirectory(
39
42
  rootDir: string,
40
43
  task: AIWorkflowAgentTaskRef,
41
44
  ): Promise<AIWorkflowRunResourceFreezeReceipt> {
42
- const tree = await loadResourceTree({ rootDir });
45
+ const authoredTree = await loadResourceTree({ rootDir });
46
+ const tree = resolveAIWorkflowResourceTree(authoredTree);
43
47
  const layers = [{ id: 'workspace', tree }] as const;
44
48
  const registry = composeLayeredResourceRegistry({ layers });
45
49
  return freezeAIWorkflowRunResources({
46
50
  registry,
47
51
  projection: projectAIWorkflowAgentResources(registry),
48
52
  task,
49
- contentIdentities: resolveEffectiveResourceContentIdentities({ registry, layers }),
53
+ contentIdentities: createResolvedAIWorkflowContentIdentityIndex(tree),
50
54
  });
51
55
  }
52
56
 
@@ -72,13 +76,14 @@ export async function freezeAIWorkflowHolonTaskTargetFromDirectory(
72
76
  rootDir: string,
73
77
  target: HolonTaskTarget,
74
78
  ): Promise<AIWorkflowHolonTaskTargetFreezeReceipt> {
75
- const tree = await loadResourceTree({ rootDir });
79
+ const authoredTree = await loadResourceTree({ rootDir });
80
+ const tree = resolveAIWorkflowResourceTree(authoredTree);
76
81
  const layers = [{ id: 'workspace', tree }] as const;
77
82
  const registry = composeLayeredResourceRegistry({ layers });
78
83
  return freezeAIWorkflowHolonTaskTarget({
79
84
  registry,
80
85
  target,
81
- contentIdentities: resolveEffectiveResourceContentIdentities({ registry, layers }),
86
+ contentIdentities: createResolvedAIWorkflowContentIdentityIndex(tree),
82
87
  });
83
88
  }
84
89
 
@@ -329,16 +334,26 @@ function semanticResourceFingerprint(
329
334
  },
330
335
  agent: {
331
336
  resourceId: agent.resource.resourceId,
332
- messages: agent.messages.map((message) => ({
333
- id: message.id,
334
- role: message.role,
335
- prompt: [message.prompt.kind, message.prompt.resource.resourceId],
336
- schema: message.schema ? {
337
- kind: message.schema.kind,
338
- resourceId: message.schema.resource.resourceId,
339
- value: message.schema.schema,
340
- } : null,
341
- })),
337
+ messagePrefix: agent.messagePrefix.map((item) => item.type === 'message'
338
+ ? {
339
+ type: item.type,
340
+ id: item.id,
341
+ role: item.role,
342
+ prompt: [item.prompt.kind, item.prompt.resource.resourceId],
343
+ schema: item.schema ? {
344
+ kind: item.schema.kind,
345
+ resourceId: item.schema.resource.resourceId,
346
+ value: item.schema.schema,
347
+ } : null,
348
+ }
349
+ : {
350
+ type: item.type,
351
+ id: item.id,
352
+ source: [item.source.kind, item.source.resource.resourceId],
353
+ }),
354
+ contextPipeline: agent.contextPipeline
355
+ ? [agent.contextPipeline.kind, agent.contextPipeline.resource.resourceId]
356
+ : null,
342
357
  inputSchema: agent.inputSchema ? {
343
358
  kind: agent.inputSchema.kind,
344
359
  resourceId: agent.inputSchema.resource.resourceId,