@exellix/graph-engine 8.0.1 → 8.1.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/dist/src/compile/authoringDocumentHelpers.d.ts +9 -0
  4. package/dist/src/compile/authoringDocumentHelpers.js +18 -0
  5. package/dist/src/compile/compileExellixExecutablePlan.d.ts +4 -5
  6. package/dist/src/compile/compileExellixExecutablePlan.js +67 -16
  7. package/dist/src/index.d.ts +2 -5
  8. package/dist/src/index.js +1 -3
  9. package/dist/src/runtime/ExellixGraphRuntime.d.ts +11 -37
  10. package/dist/src/runtime/ExellixGraphRuntime.js +77 -171
  11. package/dist/src/runtime/aiTasksStrategyPhases.js +7 -3
  12. package/dist/src/runtime/buildAiTasksRunTaskRequest.d.ts +6 -8
  13. package/dist/src/runtime/buildAiTasksRunTaskRequest.js +2 -7
  14. package/dist/src/runtime/executionMatrixHost.d.ts +5 -2
  15. package/dist/src/runtime/executionMatrixHost.js +4 -2
  16. package/dist/src/runtime/runTaskNodePlan.d.ts +15 -0
  17. package/dist/src/runtime/runTaskNodePlan.js +46 -0
  18. package/dist/src/runtime/studioGraphExecuteRequest.d.ts +5 -30
  19. package/dist/src/runtime/studioGraphExecuteRequest.js +14 -50
  20. package/dist/src/runtime/taskNodeRunTaskPreflight.d.ts +7 -5
  21. package/dist/src/runtime/taskNodeRunTaskPreflight.js +31 -26
  22. package/dist/testkit/authoringGraphFixtures.d.ts +8 -0
  23. package/dist/testkit/authoringGraphFixtures.js +249 -0
  24. package/dist/testkit/buildExecuteGraphInput.d.ts +3 -3
  25. package/dist/testkit/buildExecuteGraphInput.js +7 -3
  26. package/dist/testkit/flatGraphToAuthoring.d.ts +29 -0
  27. package/dist/testkit/flatGraphToAuthoring.js +281 -0
  28. package/dist/testkit/index.d.ts +3 -0
  29. package/dist/testkit/index.js +3 -0
  30. package/dist/testkit/runTaskNodePlanAssertions.d.ts +34 -0
  31. package/dist/testkit/runTaskNodePlanAssertions.js +32 -0
  32. package/package.json +8 -8
  33. package/dist/src/runtime/graphResponseMigration.d.ts +0 -7
  34. package/dist/src/runtime/graphResponseMigration.js +0 -44
@@ -0,0 +1,281 @@
1
+ import { GRAPHENIX_FORMAT_VERSION } from '@x12i/graphenix-core';
2
+ import { EXECUTABLE_PROFILE_NAMESPACE, EXECUTABLE_PROFILE_VERSION, FINALIZER_NODE_KIND, FINALIZER_NODE_PROFILE, TASK_NODE_KIND, TASK_NODE_PROFILE, } from '@x12i/graphenix-executable-contracts';
3
+ const ALIAS_TO_CHOICE = {
4
+ cheap: 'cheap/default',
5
+ balanced: 'vol/default',
6
+ deep: 'deep/openai_deep',
7
+ pro: 'pro/default',
8
+ };
9
+ function isPlainRecord(v) {
10
+ return v != null && typeof v === 'object' && !Array.isArray(v);
11
+ }
12
+ export function isAuthoringGraphDocument(v) {
13
+ return isPlainRecord(v) && typeof v.formatVersion === 'string' && isPlainRecord(v.graph);
14
+ }
15
+ function toProfileChoice(value) {
16
+ if (isPlainRecord(value) && value.kind === 'profileChoice' && typeof value.key === 'string') {
17
+ return value;
18
+ }
19
+ if (typeof value === 'string' && value.trim().length > 0) {
20
+ const key = value.includes('/') ? value : ALIAS_TO_CHOICE[value] ?? `${value}/default`;
21
+ return { kind: 'profileChoice', key };
22
+ }
23
+ return { kind: 'profileChoice', key: 'pro/default' };
24
+ }
25
+ export function defaultExecutableModelConfig() {
26
+ return {
27
+ version: 'graph-model-config/v1',
28
+ cases: [
29
+ {
30
+ id: 'default',
31
+ modelConfig: {
32
+ preActionModel: { kind: 'profileChoice', key: 'cheap/default' },
33
+ skillModel: { kind: 'profileChoice', key: 'pro/default' },
34
+ postActionModel: { kind: 'profileChoice', key: 'cheap/default' },
35
+ },
36
+ },
37
+ ],
38
+ fallbackPolicy: {
39
+ enabled: true,
40
+ allowedTriggers: [
41
+ 'nodeSlotMissing',
42
+ 'nodeModelUnavailable',
43
+ 'nodeModelUnsupported',
44
+ 'nodeProviderNotConfigured',
45
+ 'nodeModelRateLimited',
46
+ 'nodeModelTransientFailure',
47
+ ],
48
+ maxAttemptsPerSlot: 1,
49
+ },
50
+ };
51
+ }
52
+ function flatModelConfigToAuthoring(modelConfig) {
53
+ if (!isPlainRecord(modelConfig) || !Array.isArray(modelConfig.cases)) {
54
+ return undefined;
55
+ }
56
+ return {
57
+ version: 'graph-model-config/v1',
58
+ cases: modelConfig.cases.map((entry, index) => {
59
+ const row = isPlainRecord(entry) ? entry : {};
60
+ const mc = isPlainRecord(row.modelConfig) ? row.modelConfig : {};
61
+ const casesLen = modelConfig.cases.length;
62
+ return {
63
+ id: typeof row.id === 'string' && row.id.trim().length > 0 ? row.id : index === casesLen - 1 ? 'default' : `case-${index}`,
64
+ ...(row.when != null ? { when: row.when } : {}),
65
+ modelConfig: {
66
+ preActionModel: toProfileChoice(mc.preActionModel),
67
+ skillModel: toProfileChoice(mc.skillModel),
68
+ postActionModel: toProfileChoice(mc.postActionModel),
69
+ },
70
+ };
71
+ }),
72
+ fallbackPolicy: defaultExecutableModelConfig().fallbackPolicy,
73
+ };
74
+ }
75
+ function normalizeKnowledgeRefs(refs) {
76
+ if (!Array.isArray(refs))
77
+ return refs;
78
+ return refs.map((ref) => {
79
+ if (typeof ref === 'string')
80
+ return { id: ref };
81
+ return ref;
82
+ });
83
+ }
84
+ function normalizeSmartInput(smartInput) {
85
+ if (!isPlainRecord(smartInput) || !Array.isArray(smartInput.paths))
86
+ return smartInput;
87
+ return {
88
+ ...smartInput,
89
+ paths: smartInput.paths.map((entry) => {
90
+ if (typeof entry === 'string') {
91
+ const path = entry.startsWith('taskVariables.') || entry.startsWith('jobVariables.')
92
+ ? `executionMemory.${entry}`
93
+ : entry;
94
+ return { path };
95
+ }
96
+ if (isPlainRecord(entry) && typeof entry.path === 'string') {
97
+ const path = entry.path;
98
+ if (path.startsWith('taskVariables.') || path.startsWith('jobVariables.')) {
99
+ return { ...entry, path: `executionMemory.${path}` };
100
+ }
101
+ }
102
+ return entry;
103
+ }),
104
+ };
105
+ }
106
+ function normalizeJsonConditions(conditions) {
107
+ if (!isPlainRecord(conditions))
108
+ return conditions;
109
+ const next = { ...conditions };
110
+ const jc = next.jsonConditions;
111
+ if (jc != null && !Array.isArray(jc)) {
112
+ if (isPlainRecord(jc) && isPlainRecord(jc.condition) && Array.isArray(jc.condition.all)) {
113
+ next.jsonConditions = jc.condition.all;
114
+ }
115
+ else {
116
+ next.jsonConditions = [jc];
117
+ }
118
+ }
119
+ return next;
120
+ }
121
+ function patchTaskConfigurationModelConfig(taskConfiguration) {
122
+ if (!isPlainRecord(taskConfiguration) || !isPlainRecord(taskConfiguration.modelConfig)) {
123
+ return taskConfiguration;
124
+ }
125
+ const next = structuredClone(taskConfiguration);
126
+ const authored = flatModelConfigToAuthoring(next.modelConfig);
127
+ if (authored)
128
+ next.modelConfig = authored;
129
+ return next;
130
+ }
131
+ function flatTaskNodeToAuthoring(node) {
132
+ const { id, skillKey, taskVariable, executionMapping, taskConfiguration, inputsConfig, conditions, variables, metadata, executionPipeline, taskKnowledge, smartInput, data, } = node;
133
+ const parameters = {
134
+ profile: TASK_NODE_PROFILE,
135
+ nodeType: 'task',
136
+ };
137
+ if (typeof skillKey === 'string')
138
+ parameters.skillKey = skillKey;
139
+ if (taskVariable !== undefined)
140
+ parameters.taskVariable = taskVariable;
141
+ if (executionMapping !== undefined)
142
+ parameters.executionMapping = executionMapping;
143
+ if (inputsConfig !== undefined)
144
+ parameters.inputsConfig = inputsConfig;
145
+ if (conditions !== undefined)
146
+ parameters.conditions = normalizeJsonConditions(conditions);
147
+ if (variables !== undefined)
148
+ parameters.variables = variables;
149
+ if (metadata !== undefined)
150
+ parameters.metadata = metadata;
151
+ if (executionPipeline !== undefined)
152
+ parameters.executionPipeline = executionPipeline;
153
+ if (taskKnowledge !== undefined)
154
+ parameters.taskKnowledge = normalizeKnowledgeRefs(taskKnowledge);
155
+ if (smartInput !== undefined)
156
+ parameters.smartInput = normalizeSmartInput(smartInput);
157
+ if (data !== undefined)
158
+ parameters.data = data;
159
+ if (taskConfiguration !== undefined) {
160
+ parameters.taskConfiguration = patchTaskConfigurationModelConfig(taskConfiguration);
161
+ }
162
+ else {
163
+ parameters.taskConfiguration = { executionStrategies: [] };
164
+ }
165
+ return {
166
+ id: String(id),
167
+ kind: TASK_NODE_KIND,
168
+ inputs: [{ id: 'in:record', direction: 'input', type: 'builtin:object', required: true }],
169
+ outputs: [{ id: 'out:answer', direction: 'output', type: 'builtin:object' }],
170
+ parameters,
171
+ };
172
+ }
173
+ function flatFinalizerNodeToAuthoring(node, incoming) {
174
+ const finalizerId = String(node.id);
175
+ const upstream = incoming.filter((e) => e.to === finalizerId);
176
+ const inputs = upstream.length > 0
177
+ ? upstream.map((edge) => ({
178
+ id: `in:${edge.from}`,
179
+ direction: 'input',
180
+ type: 'builtin:object',
181
+ required: true,
182
+ }))
183
+ : [{ id: 'in:final', direction: 'input', type: 'builtin:object', required: false }];
184
+ const parameters = {
185
+ profile: FINALIZER_NODE_PROFILE,
186
+ nodeType: 'finalizer',
187
+ finalizerType: node.finalizerType,
188
+ config: isPlainRecord(node.config) ? node.config : {},
189
+ };
190
+ if (node.inputs !== undefined)
191
+ parameters.inputs = node.inputs;
192
+ if (node.outputMapping !== undefined)
193
+ parameters.outputMapping = node.outputMapping;
194
+ return {
195
+ id: finalizerId,
196
+ kind: FINALIZER_NODE_KIND,
197
+ inputs,
198
+ outputs: [{ id: 'out:final', direction: 'output', type: 'builtin:object' }],
199
+ parameters,
200
+ };
201
+ }
202
+ function flatEdgeToAuthoring(edge, index) {
203
+ const from = String(edge.from);
204
+ const to = String(edge.to);
205
+ return {
206
+ id: typeof edge.id === 'string' ? edge.id : `edge:${index}:${from}:${to}`,
207
+ from: { nodeId: from, portId: 'out:answer' },
208
+ to: { nodeId: to, portId: `in:${from === to ? 'final' : from}` },
209
+ ...(edge.when != null ? { when: edge.when } : {}),
210
+ };
211
+ }
212
+ /** Converts legacy flat exellix test graphs into Graphenix 2.x {@link AuthoringGraphDocument}. */
213
+ export function flatTestGraphToAuthoringDocument(flat) {
214
+ const graphId = String(flat.id ?? 'test-graph');
215
+ const nodesRaw = Array.isArray(flat.nodes) ? flat.nodes : [];
216
+ const edgesRaw = Array.isArray(flat.edges) ? flat.edges : [];
217
+ const edgesTyped = edgesRaw.filter(isPlainRecord).map((e) => ({ from: String(e.from), to: String(e.to) }));
218
+ const nodes = nodesRaw.filter(isPlainRecord).map((node) => {
219
+ const type = String(node.type ?? 'task');
220
+ if (type === 'finalizer')
221
+ return flatFinalizerNodeToAuthoring(node, edgesTyped);
222
+ return flatTaskNodeToAuthoring(node);
223
+ });
224
+ const edges = edgesRaw.filter(isPlainRecord).map((edge, index) => flatEdgeToAuthoring(edge, index));
225
+ const flatResponse = isPlainRecord(flat.response) ? flat.response : {};
226
+ const responseShape = isPlainRecord(flatResponse) && isPlainRecord(flatResponse.shape)
227
+ ? flatResponse.shape
228
+ : isPlainRecord(flatResponse)
229
+ ? flatResponse
230
+ : {};
231
+ const metadata = isPlainRecord(flat.metadata) ? { ...flat.metadata } : {};
232
+ if (Array.isArray(flat.jobKnowledge))
233
+ metadata.jobKnowledge = normalizeKnowledgeRefs(flat.jobKnowledge);
234
+ if (Array.isArray(flat.taskKnowledge))
235
+ metadata.taskKnowledge = normalizeKnowledgeRefs(flat.taskKnowledge);
236
+ const executableProfile = {
237
+ profileVersion: EXECUTABLE_PROFILE_VERSION,
238
+ modelConfig: flatModelConfigToAuthoring(flat.modelConfig) ?? defaultExecutableModelConfig(),
239
+ };
240
+ metadata.graphResponse = {
241
+ ...(flatResponse.missing != null ? { missing: flatResponse.missing } : {}),
242
+ ...(flatResponse.version != null ? { version: flatResponse.version } : {}),
243
+ shape: responseShape,
244
+ };
245
+ metadata.extensions = {
246
+ ...(isPlainRecord(metadata.extensions) ? metadata.extensions : {}),
247
+ [EXECUTABLE_PROFILE_NAMESPACE]: executableProfile,
248
+ };
249
+ const taskNodes = nodes.filter((n) => n.kind === TASK_NODE_KIND);
250
+ const finalizer = nodes.find((n) => n.kind === FINALIZER_NODE_KIND);
251
+ return {
252
+ formatVersion: GRAPHENIX_FORMAT_VERSION,
253
+ id: graphId.startsWith('graph:') ? graphId : `graph:${graphId}`,
254
+ revision: typeof flat.version === 'string' ? flat.version : '1.0.0',
255
+ name: graphId,
256
+ graph: {
257
+ nodes: nodes,
258
+ edges,
259
+ inputs: taskNodes.map((node) => ({
260
+ id: `graph-input:${node.id}`,
261
+ name: 'Input Record',
262
+ type: 'builtin:object',
263
+ target: { nodeId: node.id, portId: 'in:record' },
264
+ contract: { semanticKind: 'record', required: true, schema: { type: 'object' } },
265
+ })),
266
+ outputs: finalizer
267
+ ? [
268
+ {
269
+ id: 'graph-output:final',
270
+ name: 'Final Output',
271
+ type: 'builtin:object',
272
+ source: { nodeId: finalizer.id, portId: 'out:final' },
273
+ contract: { semanticKind: 'final-output', required: true, schema: { type: 'object' } },
274
+ },
275
+ ]
276
+ : [],
277
+ metadata,
278
+ },
279
+ types: [],
280
+ };
281
+ }
@@ -3,4 +3,7 @@ export { DepGraphEngineFactory } from './depGraphEngineFactory.js';
3
3
  export { RealTasksClient } from './RealTasksClient.js';
4
4
  export { createTestExellixGraphRuntime } from './testModelAliasRuntime.js';
5
5
  export { buildExecuteGraphInput } from './buildExecuteGraphInput.js';
6
+ export { buildAiTaskAuthoringGraph, buildLocalSkillAuthoringGraph, buildGraphResponseMappingAuthoringGraph, withAuthoringGraphModelConfig, } from './authoringGraphFixtures.js';
7
+ export { flatTestGraphToAuthoringDocument, isAuthoringGraphDocument } from './flatGraphToAuthoring.js';
8
+ export { runTaskMainModelSelection, runTaskMainModelSlot, expectMainSkillModelKey, } from './runTaskNodePlanAssertions.js';
6
9
  export { tryLoadExellixAiTasksRuntimeSubtree, loadExellixGraphRuntimeObjects, } from './exellixRuntimeObjects.js';
@@ -3,4 +3,7 @@ export { DepGraphEngineFactory } from './depGraphEngineFactory.js';
3
3
  export { RealTasksClient } from './RealTasksClient.js';
4
4
  export { createTestExellixGraphRuntime } from './testModelAliasRuntime.js';
5
5
  export { buildExecuteGraphInput } from './buildExecuteGraphInput.js';
6
+ export { buildAiTaskAuthoringGraph, buildLocalSkillAuthoringGraph, buildGraphResponseMappingAuthoringGraph, withAuthoringGraphModelConfig, } from './authoringGraphFixtures.js';
7
+ export { flatTestGraphToAuthoringDocument, isAuthoringGraphDocument } from './flatGraphToAuthoring.js';
8
+ export { runTaskMainModelSelection, runTaskMainModelSlot, expectMainSkillModelKey, } from './runTaskNodePlanAssertions.js';
6
9
  export { tryLoadExellixAiTasksRuntimeSubtree, loadExellixGraphRuntimeObjects, } from './exellixRuntimeObjects.js';
@@ -0,0 +1,34 @@
1
+ /** Test helpers for ai-tasks ≥ 9 nodePlan wire shape. */
2
+ type ExecutionUnitLike = Record<string, unknown> & {
3
+ unitKind?: string;
4
+ };
5
+ export declare function runTaskMainModelSelection(req: {
6
+ nodePlan?: {
7
+ executionUnits?: ExecutionUnitLike[];
8
+ };
9
+ }): unknown;
10
+ export declare function runTaskMainModelSlot(req: {
11
+ nodePlan?: {
12
+ executionUnits?: ExecutionUnitLike[];
13
+ };
14
+ }): unknown;
15
+ export declare function runTaskModelSelectionTriplet(req: {
16
+ nodePlan?: {
17
+ executionUnits?: ExecutionUnitLike[];
18
+ };
19
+ }): {
20
+ preActionModel: string | undefined;
21
+ skillModel: string | undefined;
22
+ postActionModel: string | undefined;
23
+ } | undefined;
24
+ /** Assert helper: compiled plan exposes profileChoice on MAIN unit (skillModel slot). */
25
+ export declare function expectMainSkillModelKey(req: {
26
+ nodePlan?: {
27
+ executionUnits?: ExecutionUnitLike[];
28
+ };
29
+ }, key: string): {
30
+ modelSelection: unknown;
31
+ modelSlot: unknown;
32
+ key: string | undefined;
33
+ };
34
+ export {};
@@ -0,0 +1,32 @@
1
+ /** Test helpers for ai-tasks ≥ 9 nodePlan wire shape. */
2
+ function mainSkillUnit(nodePlan) {
3
+ return nodePlan?.executionUnits?.find((u) => u.unitKind === 'mainSkill');
4
+ }
5
+ export function runTaskMainModelSelection(req) {
6
+ return mainSkillUnit(req.nodePlan)?.modelSelection;
7
+ }
8
+ export function runTaskMainModelSlot(req) {
9
+ return mainSkillUnit(req.nodePlan)?.modelSlot;
10
+ }
11
+ export function runTaskModelSelectionTriplet(req) {
12
+ const main = mainSkillUnit(req.nodePlan);
13
+ const selection = main?.modelSelection;
14
+ if (!selection || selection.kind !== 'profileChoice' || typeof selection.key !== 'string') {
15
+ return undefined;
16
+ }
17
+ const slot = typeof main?.modelSlot === 'string' ? main.modelSlot : 'skillModel';
18
+ return {
19
+ preActionModel: slot === 'preActionModel' ? selection.key : undefined,
20
+ skillModel: slot === 'skillModel' ? selection.key : undefined,
21
+ postActionModel: slot === 'postActionModel' ? selection.key : undefined,
22
+ };
23
+ }
24
+ /** Assert helper: compiled plan exposes profileChoice on MAIN unit (skillModel slot). */
25
+ export function expectMainSkillModelKey(req, key) {
26
+ const main = mainSkillUnit(req.nodePlan);
27
+ return {
28
+ modelSelection: main?.modelSelection,
29
+ modelSlot: main?.modelSlot,
30
+ key: main?.modelSelection?.key === key ? key : undefined,
31
+ };
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exellix/graph-engine",
3
- "version": "8.0.1",
3
+ "version": "8.1.0",
4
4
  "type": "module",
5
5
  "description": "Graph executor SDK",
6
6
  "main": "dist/src/index.js",
@@ -52,19 +52,19 @@
52
52
  "access": "public"
53
53
  },
54
54
  "dependencies": {
55
- "@exellix/ai-tasks": "^8.8.0",
55
+ "@exellix/ai-tasks": "^9.0.0",
56
56
  "@x12i/activix": "8.5.0",
57
57
  "@x12i/catalox": "5.1.3",
58
58
  "@x12i/env": "4.0.1",
59
59
  "@x12i/funcx": "4.4.4",
60
60
  "@x12i/graphenix": "2.5.0",
61
- "@x12i/graphenix-authoring-format": "^1.0.2",
62
- "@x12i/graphenix-executable-contracts": "^1.0.0",
63
- "@x12i/graphenix-executable-format": "^2.0.1",
64
- "@x12i/graphenix-execute-envelope": "^1.0.0",
61
+ "@x12i/graphenix-authoring-format": "^1.1.0",
62
+ "@x12i/graphenix-executable-contracts": "^1.1.0",
63
+ "@x12i/graphenix-executable-format": "^2.1.2",
64
+ "@x12i/graphenix-execute-envelope": "^1.1.0",
65
65
  "@x12i/graphenix-format": "2.0.0",
66
- "@x12i/graphenix-plan-compiler": "^1.0.1",
67
- "@x12i/graphenix-plan-format": "^1.0.0",
66
+ "@x12i/graphenix-plan-compiler": "^1.1.0",
67
+ "@x12i/graphenix-plan-format": "^1.1.0",
68
68
  "@x12i/graphenix-trace-format": "^1.0.0",
69
69
  "@x12i/logxer": "^4.6.0",
70
70
  "@x12i/memorix-descriptors": "1.6.0",
@@ -1,7 +0,0 @@
1
- import type { GraphModelObject } from '../types/refs.js';
2
- export type MigrateGraphResponseResult<T> = {
3
- graph: T;
4
- migrated: boolean;
5
- };
6
- export declare function migrateLegacyGraphResponseDefinition<T extends object>(graph: T): MigrateGraphResponseResult<T>;
7
- export declare function migrateLegacyGraphResponse<T extends GraphModelObject | object>(graph: T): MigrateGraphResponseResult<T>;
@@ -1,44 +0,0 @@
1
- const LEGACY_RESPONSE_DROP_KEYS = new Set([
2
- 'version',
3
- 'target',
4
- 'primaryResponsePaths',
5
- 'debugResponsePaths',
6
- 'notableExecutionPaths',
7
- 'mappingPreset',
8
- ]);
9
- function isPlainObject(value) {
10
- return value != null && typeof value === 'object' && !Array.isArray(value);
11
- }
12
- function cloneGraph(graph) {
13
- return structuredClone(graph);
14
- }
15
- export function migrateLegacyGraphResponseDefinition(graph) {
16
- const graphRecord = graph;
17
- const metadata = isPlainObject(graphRecord.metadata) ? graphRecord.metadata : undefined;
18
- const graphResponse = metadata && isPlainObject(metadata.graphResponse) ? metadata.graphResponse : undefined;
19
- const legacyMapping = graphResponse && isPlainObject(graphResponse.responseMapping)
20
- ? graphResponse.responseMapping
21
- : undefined;
22
- if (graphRecord.response !== undefined || !legacyMapping) {
23
- return { graph, migrated: false };
24
- }
25
- const next = cloneGraph(graph);
26
- const nextRecord = next;
27
- const response = {};
28
- for (const [key, value] of Object.entries(legacyMapping)) {
29
- if (LEGACY_RESPONSE_DROP_KEYS.has(key))
30
- continue;
31
- response[key] = value;
32
- }
33
- if (!Object.prototype.hasOwnProperty.call(response, 'missing')) {
34
- response.missing = 'omit';
35
- }
36
- nextRecord.response = response;
37
- if (isPlainObject(nextRecord.metadata)) {
38
- delete nextRecord.metadata.graphResponse;
39
- }
40
- return { graph: next, migrated: true };
41
- }
42
- export function migrateLegacyGraphResponse(graph) {
43
- return migrateLegacyGraphResponseDefinition(graph);
44
- }