@exellix/graph-engine 8.0.0 → 8.0.1
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/CHANGELOG.md +9 -1
- package/README.md +10 -11
- package/dist/src/{adapters → compile}/compileExellixExecutablePlan.d.ts +2 -1
- package/dist/src/compile/compileExellixExecutablePlan.js +24 -0
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.js +2 -2
- package/dist/src/runtime/ExellixGraphRuntime.js +1 -2
- package/dist/src/runtime/executionMatrixHost.d.ts +1 -1
- package/dist/src/runtime/executionMatrixHost.js +2 -2
- package/dist/src/runtime/studioGraphExecuteRequest.js +1 -1
- package/dist/src/types/refs.d.ts +1 -1
- package/dist/testkit/buildExecuteGraphInput.js +1 -1
- package/package.json +4 -3
- package/dist/src/adapters/compileExellixExecutablePlan.js +0 -18
- package/dist/src/adapters/migrateExellixGraphModelToAuthoring.d.ts +0 -6
- package/dist/src/adapters/migrateExellixGraphModelToAuthoring.js +0 -273
- package/dist/src/adapters/patchFinalizerPlans.d.ts +0 -7
- package/dist/src/adapters/patchFinalizerPlans.js +0 -63
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.0.1
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Zero local compile workarounds:** removed local migration/finalizer patches; `compileExellixExecutablePlan` uses `@x12i/graphenix-authoring-format` ≥1.0.2 and `@x12i/graphenix-plan-compiler` ≥1.0.1 only.
|
|
8
|
+
- Re-export `migrateLegacyGraphModelObjectToGraphenixExecutable` from authoring-format (upstream name; no exellix alias).
|
|
9
|
+
- **Docs / layout:** compile helper lives under `src/compile/`; execute path no longer runs response migration (compile-only).
|
|
10
|
+
|
|
3
11
|
## 8.0.0
|
|
4
12
|
|
|
5
13
|
### Breaking
|
|
@@ -11,7 +19,7 @@
|
|
|
11
19
|
### Added
|
|
12
20
|
|
|
13
21
|
- **`@x12i/graphenix-*` integration:** plan validation, deferred gates, trace events (`ExecuteGraphResult.trace`), and exports for `ExecutableGraphPlanV2`.
|
|
14
|
-
- **`compileExellixExecutablePlan`**, **`
|
|
22
|
+
- **`compileExellixExecutablePlan`**, **`migrateLegacyGraphModelObjectToGraphenixExecutable`** (re-export from `@x12i/graphenix-authoring-format`) — host compile helpers for legacy exellix `GraphModelObject`.
|
|
15
23
|
- **`buildAuthoringStudioGraphExecutionRequest`** re-export from `@x12i/graphenix-execute-envelope`.
|
|
16
24
|
|
|
17
25
|
See [`BREAKING-CHANGES.md`](BREAKING-CHANGES.md) §8.0.0.
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ The **`runTask`** wire contract (identity, canonical **`input`**, optional extra
|
|
|
43
43
|
|
|
44
44
|
An executable graph model object may have **only** these **top-level** keys: `id`, `version`, `modelConfig`, `jobKnowledge`, `nodes`, `edges`, `variables`, `response`, `metadata`. The required root **`response`** is the single executable final response contract used to build `ExecuteGraphResult.finalOutput`. Document-model and authoring fields (`name`, `description`, `exellixContractTarget`, `graphExecution`, `graphEntry`, `catalogRequests`, and similar) belong **under `metadata`** only. Node-scoped `taskKnowledge` belongs under each task node, not at the model root. Runtime state (`input`, `jobMemory`, `taskMemory`, `executionMemory`, `outputsMemory`, per-run options) belongs under the execution request’s **`runtime`** object and is rejected on the model. **`runtime.modelConfig`**, **`runtime.aliasConfig`**, and **`runtime.nodes[id].modelConfig`** were removed in **7.7** — model profiles belong on the graph document only.
|
|
45
45
|
|
|
46
|
-
`metadata.graphExecution` can document graph execution defaults and labels, including `mode: 'forward' | 'backward' | 'hybrid'`, optional `goalNodeId`, optional `dimension`, `outputMode: 'mappedAggregation' | 'lastExitNode'`, `coreObjective`, optional `nodesResponses`, and metadata-only `flowOutline: 'linearSequence' | 'convergingParallelFlow'`. Planner mode
|
|
46
|
+
`metadata.graphExecution` can document graph execution defaults and labels, including `mode: 'forward' | 'backward' | 'hybrid'`, optional `goalNodeId`, optional `dimension`, `outputMode: 'mappedAggregation' | 'lastExitNode'`, `coreObjective`, optional `nodesResponses`, and metadata-only `flowOutline: 'linearSequence' | 'convergingParallelFlow'`. Planner mode comes from `plan.schedulingPolicy.mode` or `runtime.mode`; `outputMode` does not decide the returned `finalOutput`.
|
|
47
47
|
|
|
48
48
|
Enforcement: `executeGraph`, `createExellixGraphRuntime().executeGraph`, `executeNode` when a graph is passed in context, `inspectGraph`, `inspectGraphContracts`, `validateCatalogPlanning`, and Catalox graph validators call this check. Failures throw `ExellixGraphError` with code `NON_CANONICAL_GRAPH_DOCUMENT`. For CI or custom loaders, call **`assertCanonicalGraphDocument`** (exported from the package root) on parsed JSON before execution. **`loadGraph`** returns whatever the loader parsed; validation runs when you execute or inspect, not necessarily on load.
|
|
49
49
|
|
|
@@ -57,7 +57,7 @@ npm install @exellix/graph-engine
|
|
|
57
57
|
|
|
58
58
|
### Execution matrix hosts (`@exellix/exellix-runtime`) — documentation only for the engine
|
|
59
59
|
|
|
60
|
-
Matrix **claim**, **rows**, and **retry policy** live outside this package. If your host wires **matrix → graph run**, see [.docs/execution-matrix-handoff.md](.docs/execution-matrix-handoff.md) for how **you** should inject `runtime.executeGraph`, resolve **`metadata.graphEntry` per model**, seed **`runtime.executionMemory`**, and pass **`runtime.jobId
|
|
60
|
+
Matrix **claim**, **rows**, and **retry policy** live outside this package. If your host wires **matrix → graph run**, see [.docs/execution-matrix-handoff.md](.docs/execution-matrix-handoff.md) for how **you** should inject `runtime.executeGraph`, compile **`GraphModelObject` → plan**, resolve **`metadata.graphEntry` per model**, seed **`runtime.executionMemory`**, and pass **`runtime.jobId`**. Helpers such as **`buildMatrixJobForGraphRun`** align **`id`** and **`job.jobId`** on the `job` object so you can call **`runtime.executeGraph({ plan, runtime: { jobId: job.jobId, job, … } })`**. Those exports are **optional helpers for callers**; they do **not** expand graph-engine’s role beyond **executing the single run** when invoked.
|
|
61
61
|
|
|
62
62
|
### Configuration (`.env`)
|
|
63
63
|
|
|
@@ -213,10 +213,11 @@ interface ExecuteGraphResult {
|
|
|
213
213
|
runLogOmittedCount?: number;
|
|
214
214
|
logxerCorrelationId?: string;
|
|
215
215
|
debug?: { nodes: NodeTraceEntry[] }; // populated only when debugMode: true
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
planAudit?: {
|
|
217
|
+
planHash: string;
|
|
218
|
+
source: string;
|
|
219
219
|
};
|
|
220
|
+
trace?: unknown;
|
|
220
221
|
}
|
|
221
222
|
```
|
|
222
223
|
|
|
@@ -237,13 +238,11 @@ const runtime = createExellixGraphRuntime({
|
|
|
237
238
|
playgroundReporter,
|
|
238
239
|
});
|
|
239
240
|
|
|
241
|
+
const plan = compileExellixExecutablePlan(graphModel, graphRuntime);
|
|
242
|
+
|
|
240
243
|
await runtime.executeGraph({
|
|
241
|
-
|
|
242
|
-
runtime:
|
|
243
|
-
jobId: 'job-123',
|
|
244
|
-
job,
|
|
245
|
-
input,
|
|
246
|
-
},
|
|
244
|
+
plan,
|
|
245
|
+
runtime: graphRuntime,
|
|
247
246
|
});
|
|
248
247
|
|
|
249
248
|
// Inspect full node request/response payloads in memory.
|
|
@@ -3,6 +3,7 @@ import type { Graph, GraphModelObject } from '../types/refs.js';
|
|
|
3
3
|
import type { GraphRuntimeObject } from '../runtime/ExellixGraphRuntime.js';
|
|
4
4
|
export type CompileExellixExecutablePlanOptions = CompileExecutablePlanV2Options;
|
|
5
5
|
/**
|
|
6
|
-
* Host/test helper: exellix
|
|
6
|
+
* Host/test helper: exellix {@link GraphModelObject} + runtime → validated v2 executable plan.
|
|
7
|
+
* Migration and plan compilation live in `@x12i/graphenix-*`; graph-engine does not duplicate format logic.
|
|
7
8
|
*/
|
|
8
9
|
export declare function compileExellixExecutablePlan(model: Graph | GraphModelObject, runtime: GraphRuntimeObject, options?: CompileExellixExecutablePlanOptions): ExecutableGraphPlanV2;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { migrateLegacyGraphModelObjectToGraphenixExecutable, } from '@x12i/graphenix-authoring-format';
|
|
2
|
+
import { compileExecutablePlanV2 } from '@x12i/graphenix-plan-compiler';
|
|
3
|
+
import { validateExecutablePlan } from '@x12i/graphenix-plan-format';
|
|
4
|
+
import { EXELLIX_STRUCTURED_DATA_FILTERS_V1 } from '../types/refs.js';
|
|
5
|
+
import { migrateLegacyGraphResponse } from '../runtime/graphResponseMigration.js';
|
|
6
|
+
/** Exellix host hooks passed into upstream {@link migrateLegacyGraphModelObjectToGraphenixExecutable}. */
|
|
7
|
+
const EXELLIX_LEGACY_MIGRATE_OPTIONS = {
|
|
8
|
+
preprocessLegacy: (legacy) => migrateLegacyGraphResponse(legacy).graph,
|
|
9
|
+
structuredDataFiltersVersion: EXELLIX_STRUCTURED_DATA_FILTERS_V1,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Host/test helper: exellix {@link GraphModelObject} + runtime → validated v2 executable plan.
|
|
13
|
+
* Migration and plan compilation live in `@x12i/graphenix-*`; graph-engine does not duplicate format logic.
|
|
14
|
+
*/
|
|
15
|
+
export function compileExellixExecutablePlan(model, runtime, options) {
|
|
16
|
+
const authoring = migrateLegacyGraphModelObjectToGraphenixExecutable(model, EXELLIX_LEGACY_MIGRATE_OPTIONS);
|
|
17
|
+
const plan = compileExecutablePlanV2(authoring, runtime, options);
|
|
18
|
+
const validation = validateExecutablePlan(plan);
|
|
19
|
+
if (!validation.valid) {
|
|
20
|
+
const summary = validation.errors.map((e) => `${e.path}: ${e.message}`).join('; ');
|
|
21
|
+
throw new Error(`compileExellixExecutablePlan: invalid plan: ${summary}`);
|
|
22
|
+
}
|
|
23
|
+
return plan;
|
|
24
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -91,9 +91,10 @@ export type { MigrateGraphResponseResult } from './runtime/graphResponseMigratio
|
|
|
91
91
|
export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
|
|
92
92
|
export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
|
|
93
93
|
export type { ExecutableGraphPlanV2, NodeExecutionPlan, ExecutionUnitPlanV2, } from '@x12i/graphenix-executable-contracts';
|
|
94
|
-
export { compileExellixExecutablePlan } from './
|
|
95
|
-
export type { CompileExellixExecutablePlanOptions } from './
|
|
96
|
-
export {
|
|
94
|
+
export { compileExellixExecutablePlan } from './compile/compileExellixExecutablePlan.js';
|
|
95
|
+
export type { CompileExellixExecutablePlanOptions } from './compile/compileExellixExecutablePlan.js';
|
|
96
|
+
export { migrateLegacyGraphModelObjectToGraphenixExecutable, } from '@x12i/graphenix-authoring-format';
|
|
97
|
+
export type { LegacyGraphModelObject, MigrateLegacyGraphModelOptions, } from '@x12i/graphenix-authoring-format';
|
|
97
98
|
export { buildGraphExecutionRequestFromStudioExecute as buildAuthoringStudioGraphExecutionRequest } from '@x12i/graphenix-execute-envelope';
|
|
98
99
|
export type { RunTaskRequest, RunTaskResponse, TasksClientLike, GraphLoader as RuntimeGraphLoader, ExecuteGraphInput, GraphExecutionRequest, GraphRuntimeObject, GraphKnowledgeResolver, GraphKnowledgeResolverContext, ExecuteGraphResult, ExellixGraphRuntimeOptions, } from './runtime/ExellixGraphRuntime.js';
|
|
99
100
|
export type { PlanStatus, GraphPlan, GraphEngine, GraphEngineFactory, } from './runtime/GraphEngine.js';
|
package/dist/src/index.js
CHANGED
|
@@ -67,8 +67,8 @@ export { migrateLegacyGraphResponse, migrateLegacyGraphResponseDefinition, } fro
|
|
|
67
67
|
export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
|
|
68
68
|
// New runtime with injection seam
|
|
69
69
|
export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
|
|
70
|
-
export { compileExellixExecutablePlan } from './
|
|
71
|
-
export {
|
|
70
|
+
export { compileExellixExecutablePlan } from './compile/compileExellixExecutablePlan.js';
|
|
71
|
+
export { migrateLegacyGraphModelObjectToGraphenixExecutable, } from '@x12i/graphenix-authoring-format';
|
|
72
72
|
export { buildGraphExecutionRequestFromStudioExecute as buildAuthoringStudioGraphExecutionRequest } from '@x12i/graphenix-execute-envelope';
|
|
73
73
|
// Testkit (in-memory loader, dep engine, recording client — sample NARRIX tasks: `@exellix/graph-engine/testkit`)
|
|
74
74
|
export { InMemoryGraphLoader, DepGraphEngineFactory } from '../testkit/index.js';
|
|
@@ -25,7 +25,6 @@ import { executeDeterministicFinalizer, executeSynthesizeFinalizer } from "./fin
|
|
|
25
25
|
import { createFinalizerError } from "./finalizers/errors.js";
|
|
26
26
|
import { assertCanonicalGraphRuntimeObject } from "./validateCanonicalGraphRuntime.js";
|
|
27
27
|
import { applyGraphResponseDefinition } from "./graphResponseMapping.js";
|
|
28
|
-
import { migrateLegacyGraphResponse } from "./graphResponseMigration.js";
|
|
29
28
|
import { buildAiTasksObservabilityRecord } from "./aiTasksObservability.js";
|
|
30
29
|
import { buildMainLlmCallForRunTask, buildRunTaskIdentityEnvelope, shouldForwardRunTaskTraceMode, } from "./runTaskAugments.js";
|
|
31
30
|
import { buildRunLog, extractLogxerCorrelationFromMetadata, extractTaskRunLogFromMetadata, resolveRunLogLimits, } from "./buildRunLog.js";
|
|
@@ -1160,7 +1159,7 @@ export function createExellixGraphRuntime(opts) {
|
|
|
1160
1159
|
const { plan: suppliedPlan, runtime } = input;
|
|
1161
1160
|
const { plan } = preparePlanExecuteEntry(suppliedPlan, runtime);
|
|
1162
1161
|
const materialized = embeddedGraphToExellixGraph(plan);
|
|
1163
|
-
const graph =
|
|
1162
|
+
const graph = materialized;
|
|
1164
1163
|
const merged = mergeExellixGraphRuntimeInvocation(runtime, opts);
|
|
1165
1164
|
const scheduling = plan.schedulingPolicy;
|
|
1166
1165
|
const plannerMode = scheduling?.mode ?? runtime.mode;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Host helpers for execution-matrix style orchestrators (e.g. `@exellix/exellix-runtime`).
|
|
3
3
|
*
|
|
4
4
|
* Graph-engine does not call matrix claim APIs; the host injects `executeGraph` and supplies
|
|
5
|
-
* a `{
|
|
5
|
+
* a `{ plan, runtime }` request with per-graph `GraphEntryContract` + seeded
|
|
6
6
|
* `runtime.executionMemory` objects built here.
|
|
7
7
|
*/
|
|
8
8
|
import type { Graph, GraphEntryContract, GraphEntryExecutionInputSpec, Job } from '../types/refs.js';
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Host helpers for execution-matrix style orchestrators (e.g. `@exellix/exellix-runtime`).
|
|
3
3
|
*
|
|
4
4
|
* Graph-engine does not call matrix claim APIs; the host injects `executeGraph` and supplies
|
|
5
|
-
* a `{
|
|
5
|
+
* a `{ plan, runtime }` request with per-graph `GraphEntryContract` + seeded
|
|
6
6
|
* `runtime.executionMemory` objects built here.
|
|
7
7
|
*/
|
|
8
|
-
import { compileExellixExecutablePlan } from '../
|
|
8
|
+
import { compileExellixExecutablePlan } from '../compile/compileExellixExecutablePlan.js';
|
|
9
9
|
import { mergeGraphDocumentModel } from '../types/refs.js';
|
|
10
10
|
import { createExellixGraphRuntime } from './ExellixGraphRuntime.js';
|
|
11
11
|
import { selectByPath, writeByPath } from './pathExpr.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compileExellixExecutablePlan } from '../
|
|
1
|
+
import { compileExellixExecutablePlan } from '../compile/compileExellixExecutablePlan.js';
|
|
2
2
|
import { ExellixGraphError } from '../errors/ExellixGraphError.js';
|
|
3
3
|
import { ExellixGraphErrorCode } from '../errors/exellixGraphErrorCodes.js';
|
|
4
4
|
/**
|
package/dist/src/types/refs.d.ts
CHANGED
|
@@ -680,7 +680,7 @@ export interface GraphDocumentMetadata {
|
|
|
680
680
|
graphResponse?: GraphResponseContract;
|
|
681
681
|
/**
|
|
682
682
|
* Graph execution defaults and labels.
|
|
683
|
-
* Planner mode is still selected by `executeGraph({
|
|
683
|
+
* Planner mode is still selected by `executeGraph({ plan, runtime }).runtime.mode` (or plan.schedulingPolicy) and defaults to `forward`;
|
|
684
684
|
* output labels in this block shape `stepsResponses`, not `ExecuteGraphResult.finalOutput`.
|
|
685
685
|
*/
|
|
686
686
|
graphExecution?: GraphExecutionDefaults;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compileExellixExecutablePlan } from '../src/
|
|
1
|
+
import { compileExellixExecutablePlan } from '../src/compile/compileExellixExecutablePlan.js';
|
|
2
2
|
/** Builds `{ plan, runtime }` for tests and hosts that still author exellix GraphModelObject JSON. */
|
|
3
3
|
export function buildExecuteGraphInput(model, runtime) {
|
|
4
4
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exellix/graph-engine",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Graph executor SDK",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -58,11 +58,13 @@
|
|
|
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",
|
|
61
62
|
"@x12i/graphenix-executable-contracts": "^1.0.0",
|
|
63
|
+
"@x12i/graphenix-executable-format": "^2.0.1",
|
|
62
64
|
"@x12i/graphenix-execute-envelope": "^1.0.0",
|
|
63
65
|
"@x12i/graphenix-format": "2.0.0",
|
|
66
|
+
"@x12i/graphenix-plan-compiler": "^1.0.1",
|
|
64
67
|
"@x12i/graphenix-plan-format": "^1.0.0",
|
|
65
|
-
"@x12i/graphenix-plan-compiler": "^1.0.0",
|
|
66
68
|
"@x12i/graphenix-trace-format": "^1.0.0",
|
|
67
69
|
"@x12i/logxer": "^4.6.0",
|
|
68
70
|
"@x12i/memorix-descriptors": "1.6.0",
|
|
@@ -73,7 +75,6 @@
|
|
|
73
75
|
},
|
|
74
76
|
"devDependencies": {
|
|
75
77
|
"@types/node": "25.9.1",
|
|
76
|
-
"@x12i/graphenix-authoring-format": "^1.0.1",
|
|
77
78
|
"tsx": "4.22.3",
|
|
78
79
|
"typescript": "6.0.3"
|
|
79
80
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { compileExecutablePlanV2 } from '@x12i/graphenix-plan-compiler';
|
|
2
|
-
import { validateExecutablePlan } from '@x12i/graphenix-plan-format';
|
|
3
|
-
import { migrateExellixGraphModelToAuthoring } from './migrateExellixGraphModelToAuthoring.js';
|
|
4
|
-
import { patchFinalizerPlansOnExecutablePlan } from './patchFinalizerPlans.js';
|
|
5
|
-
/**
|
|
6
|
-
* Host/test helper: exellix graph model + runtime → validated v2 executable plan.
|
|
7
|
-
*/
|
|
8
|
-
export function compileExellixExecutablePlan(model, runtime, options) {
|
|
9
|
-
const authoring = migrateExellixGraphModelToAuthoring(model);
|
|
10
|
-
const compiled = compileExecutablePlanV2(authoring, runtime, options);
|
|
11
|
-
const plan = patchFinalizerPlansOnExecutablePlan(compiled, runtime);
|
|
12
|
-
const validation = validateExecutablePlan(plan);
|
|
13
|
-
if (!validation.valid) {
|
|
14
|
-
const summary = validation.errors.map((e) => `${e.path}: ${e.message}`).join('; ');
|
|
15
|
-
throw new Error(`compileExellixExecutablePlan: invalid plan: ${summary}`);
|
|
16
|
-
}
|
|
17
|
-
return plan;
|
|
18
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type AuthoringGraphDocument } from '@x12i/graphenix-executable-contracts';
|
|
2
|
-
import type { Graph, GraphModelObject } from '../types/refs.js';
|
|
3
|
-
/**
|
|
4
|
-
* Converts exellix {@link GraphModelObject} to graphenix {@link AuthoringGraphDocument} for plan compilation.
|
|
5
|
-
*/
|
|
6
|
-
export declare function migrateExellixGraphModelToAuthoring(model: Graph | GraphModelObject): AuthoringGraphDocument;
|
|
@@ -1,273 +0,0 @@
|
|
|
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
|
-
import { EXELLIX_STRUCTURED_DATA_FILTERS_V1 } from '../types/refs.js';
|
|
4
|
-
import { DEFAULT_GRAPH_AI_MODEL_PROFILE_CONFIG } from '../runtime/graphAiModelConfig.js';
|
|
5
|
-
import { migrateLegacyGraphResponse } from '../runtime/graphResponseMigration.js';
|
|
6
|
-
function isPlainRecord(v) {
|
|
7
|
-
return v != null && typeof v === 'object' && !Array.isArray(v);
|
|
8
|
-
}
|
|
9
|
-
function aliasToProfileChoice(value) {
|
|
10
|
-
const trimmed = value.trim();
|
|
11
|
-
if (trimmed.includes('/'))
|
|
12
|
-
return { kind: 'profileChoice', key: trimmed };
|
|
13
|
-
const shortcuts = {
|
|
14
|
-
cheap: 'cheap/default',
|
|
15
|
-
balanced: 'vol/default',
|
|
16
|
-
deep: 'deep/openai_deep',
|
|
17
|
-
pro: 'pro/default',
|
|
18
|
-
};
|
|
19
|
-
const key = shortcuts[trimmed] ?? `${trimmed}/default`;
|
|
20
|
-
return { kind: 'profileChoice', key };
|
|
21
|
-
}
|
|
22
|
-
function exellixModelConfigToExecutable(modelConfig) {
|
|
23
|
-
if (!modelConfig?.cases?.length)
|
|
24
|
-
return undefined;
|
|
25
|
-
const cases = modelConfig.cases.map((c, index) => {
|
|
26
|
-
const mc = c.modelConfig;
|
|
27
|
-
const modelConfigOut = {};
|
|
28
|
-
if (mc.preActionModel != null && String(mc.preActionModel).trim() !== '') {
|
|
29
|
-
modelConfigOut.preActionModel = aliasToProfileChoice(String(mc.preActionModel));
|
|
30
|
-
}
|
|
31
|
-
if (mc.skillModel != null && String(mc.skillModel).trim() !== '') {
|
|
32
|
-
modelConfigOut.skillModel = aliasToProfileChoice(String(mc.skillModel));
|
|
33
|
-
}
|
|
34
|
-
if (mc.postActionModel != null && String(mc.postActionModel).trim() !== '') {
|
|
35
|
-
modelConfigOut.postActionModel = aliasToProfileChoice(String(mc.postActionModel));
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
id: c.when == null ? 'default' : `case-${index}`,
|
|
39
|
-
...(c.when != null ? { when: c.when } : {}),
|
|
40
|
-
modelConfig: modelConfigOut,
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
const hasPartialCase = cases.some((c) => !c.modelConfig.preActionModel ||
|
|
44
|
-
!c.modelConfig.skillModel ||
|
|
45
|
-
!c.modelConfig.postActionModel);
|
|
46
|
-
return {
|
|
47
|
-
version: 'graph-model-config/v1',
|
|
48
|
-
cases,
|
|
49
|
-
...(hasPartialCase ? { inherit: true } : {}),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
const DEFAULT_EXECUTABLE_FALLBACK_POLICY = {
|
|
53
|
-
enabled: true,
|
|
54
|
-
allowedTriggers: [
|
|
55
|
-
'nodeSlotMissing',
|
|
56
|
-
'nodeModelUnavailable',
|
|
57
|
-
'nodeModelUnsupported',
|
|
58
|
-
'nodeProviderNotConfigured',
|
|
59
|
-
'nodeModelRateLimited',
|
|
60
|
-
'nodeModelTransientFailure',
|
|
61
|
-
],
|
|
62
|
-
maxAttemptsPerSlot: 1,
|
|
63
|
-
};
|
|
64
|
-
function defaultExecutableModelConfig() {
|
|
65
|
-
const mc = DEFAULT_GRAPH_AI_MODEL_PROFILE_CONFIG;
|
|
66
|
-
return {
|
|
67
|
-
version: 'graph-model-config/v1',
|
|
68
|
-
cases: [
|
|
69
|
-
{
|
|
70
|
-
id: 'default',
|
|
71
|
-
modelConfig: {
|
|
72
|
-
preActionModel: aliasToProfileChoice(mc.preActionModel),
|
|
73
|
-
skillModel: aliasToProfileChoice(mc.skillModel),
|
|
74
|
-
postActionModel: aliasToProfileChoice(mc.postActionModel),
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
fallbackPolicy: DEFAULT_EXECUTABLE_FALLBACK_POLICY,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function isStructuredExellixDataFilters(value) {
|
|
82
|
-
return (isPlainRecord(value) &&
|
|
83
|
-
value.version === EXELLIX_STRUCTURED_DATA_FILTERS_V1 &&
|
|
84
|
-
isPlainRecord(value.when));
|
|
85
|
-
}
|
|
86
|
-
function exellixGraphEntryToAuthoring(graphEntry) {
|
|
87
|
-
if (!isPlainRecord(graphEntry))
|
|
88
|
-
return graphEntry;
|
|
89
|
-
const next = structuredClone(graphEntry);
|
|
90
|
-
const dataFilters = next.dataFilters;
|
|
91
|
-
if (isStructuredExellixDataFilters(dataFilters)) {
|
|
92
|
-
next.dataFilters = [dataFilters.when];
|
|
93
|
-
}
|
|
94
|
-
return next;
|
|
95
|
-
}
|
|
96
|
-
/** Authoring validation requires jsonConditions as an array; exellix uses a CaseCondition object. */
|
|
97
|
-
function exellixConditionsToAuthoring(conditions) {
|
|
98
|
-
if (Array.isArray(conditions)) {
|
|
99
|
-
return { runWhen: conditions };
|
|
100
|
-
}
|
|
101
|
-
const runWhenEntry = {};
|
|
102
|
-
if (conditions.jsonConditions != null) {
|
|
103
|
-
runWhenEntry.jsonConditions = structuredClone(conditions.jsonConditions);
|
|
104
|
-
}
|
|
105
|
-
if (conditions.jsConditionFunction != null) {
|
|
106
|
-
runWhenEntry.jsConditionFunction = structuredClone(conditions.jsConditionFunction);
|
|
107
|
-
}
|
|
108
|
-
if (conditions.aiCondition != null) {
|
|
109
|
-
runWhenEntry.aiCondition = structuredClone(conditions.aiCondition);
|
|
110
|
-
}
|
|
111
|
-
const out = {};
|
|
112
|
-
if (Object.keys(runWhenEntry).length > 0) {
|
|
113
|
-
out.runWhen = [runWhenEntry];
|
|
114
|
-
}
|
|
115
|
-
if (conditions.dataFilters != null) {
|
|
116
|
-
out.dataFilters = structuredClone(conditions.dataFilters);
|
|
117
|
-
}
|
|
118
|
-
if (conditions.narratives != null) {
|
|
119
|
-
out.narratives = structuredClone(conditions.narratives);
|
|
120
|
-
}
|
|
121
|
-
return out;
|
|
122
|
-
}
|
|
123
|
-
function defaultPorts(nodeId) {
|
|
124
|
-
return {
|
|
125
|
-
in: `in:${nodeId}`,
|
|
126
|
-
out: `out:${nodeId}`,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
function exellixTaskNodeToExecutable(node) {
|
|
130
|
-
const ports = defaultPorts(String(node.id));
|
|
131
|
-
const params = {
|
|
132
|
-
profile: TASK_NODE_PROFILE,
|
|
133
|
-
nodeType: 'task',
|
|
134
|
-
skillKey: node.skillKey,
|
|
135
|
-
};
|
|
136
|
-
if (node.taskConfiguration != null)
|
|
137
|
-
params.taskConfiguration = structuredClone(node.taskConfiguration);
|
|
138
|
-
if (node.taskVariable != null)
|
|
139
|
-
params.taskVariable = structuredClone(node.taskVariable);
|
|
140
|
-
if (node.inputsConfig != null)
|
|
141
|
-
params.inputsConfig = structuredClone(node.inputsConfig);
|
|
142
|
-
if (node.executionMapping != null)
|
|
143
|
-
params.executionMapping = structuredClone(node.executionMapping);
|
|
144
|
-
if (node.conditions != null)
|
|
145
|
-
params.conditions = exellixConditionsToAuthoring(node.conditions);
|
|
146
|
-
if (Array.isArray(node.taskKnowledge)) {
|
|
147
|
-
params.taskKnowledge = exellixKnowledgeRefsToAuthoring(node.taskKnowledge);
|
|
148
|
-
}
|
|
149
|
-
if (node.variables != null)
|
|
150
|
-
params.variables = structuredClone(node.variables);
|
|
151
|
-
if (node.metadata != null)
|
|
152
|
-
params.metadata = structuredClone(node.metadata);
|
|
153
|
-
if (node.executionPipeline != null)
|
|
154
|
-
params.executionPipeline = structuredClone(node.executionPipeline);
|
|
155
|
-
if (node.jobContextMapping != null)
|
|
156
|
-
params.jobContextMapping = structuredClone(node.jobContextMapping);
|
|
157
|
-
if (node.scope != null)
|
|
158
|
-
params.scope = structuredClone(node.scope);
|
|
159
|
-
if (node.smartInput != null)
|
|
160
|
-
params.smartInput = exellixSmartInputToAuthoring(node.smartInput);
|
|
161
|
-
if (node.outputValidation != null)
|
|
162
|
-
params.outputValidation = structuredClone(node.outputValidation);
|
|
163
|
-
const nodeModelConfig = node.taskConfiguration?.modelConfig;
|
|
164
|
-
if (nodeModelConfig != null) {
|
|
165
|
-
const converted = exellixModelConfigToExecutable(nodeModelConfig);
|
|
166
|
-
if (converted) {
|
|
167
|
-
params.taskConfiguration = {
|
|
168
|
-
...(isPlainRecord(params.taskConfiguration) ? params.taskConfiguration : {}),
|
|
169
|
-
modelConfig: converted,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return {
|
|
174
|
-
id: String(node.id),
|
|
175
|
-
kind: TASK_NODE_KIND,
|
|
176
|
-
inputs: [{ id: ports.in, direction: 'input', type: 'builtin:object', required: false }],
|
|
177
|
-
outputs: [{ id: ports.out, direction: 'output', type: 'builtin:object' }],
|
|
178
|
-
parameters: params,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function exellixSmartInputToAuthoring(smartInput) {
|
|
182
|
-
if (!isPlainRecord(smartInput))
|
|
183
|
-
return structuredClone(smartInput);
|
|
184
|
-
const next = structuredClone(smartInput);
|
|
185
|
-
if (Array.isArray(next.paths)) {
|
|
186
|
-
next.paths = next.paths.map((entry) => typeof entry === 'string' ? { path: entry } : entry);
|
|
187
|
-
}
|
|
188
|
-
return next;
|
|
189
|
-
}
|
|
190
|
-
function exellixKnowledgeRefsToAuthoring(refs) {
|
|
191
|
-
return refs.map((ref) => ({ id: ref }));
|
|
192
|
-
}
|
|
193
|
-
function exellixFinalizerToExecutable(node) {
|
|
194
|
-
const n = node;
|
|
195
|
-
const ports = defaultPorts(String(node.id));
|
|
196
|
-
return {
|
|
197
|
-
id: String(node.id),
|
|
198
|
-
kind: FINALIZER_NODE_KIND,
|
|
199
|
-
inputs: [{ id: ports.in, direction: 'input', type: 'builtin:object', required: false }],
|
|
200
|
-
outputs: [{ id: ports.out, direction: 'output', type: 'builtin:object' }],
|
|
201
|
-
parameters: {
|
|
202
|
-
profile: FINALIZER_NODE_PROFILE,
|
|
203
|
-
nodeType: 'finalizer',
|
|
204
|
-
finalizerType: n.finalizerType,
|
|
205
|
-
config: isPlainRecord(n.config) ? structuredClone(n.config) : {},
|
|
206
|
-
...(n.inputs != null ? { inputs: structuredClone(n.inputs) } : {}),
|
|
207
|
-
...(n.outputMapping != null ? { outputMapping: structuredClone(n.outputMapping) } : {}),
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Converts exellix {@link GraphModelObject} to graphenix {@link AuthoringGraphDocument} for plan compilation.
|
|
213
|
-
*/
|
|
214
|
-
export function migrateExellixGraphModelToAuthoring(model) {
|
|
215
|
-
const legacyMigrated = migrateLegacyGraphResponse(structuredClone(model));
|
|
216
|
-
const source = legacyMigrated.graph;
|
|
217
|
-
const executableModelConfig = exellixModelConfigToExecutable(source.modelConfig) ?? defaultExecutableModelConfig();
|
|
218
|
-
const metadata = isPlainRecord(source.metadata) ? structuredClone(source.metadata) : {};
|
|
219
|
-
const extensions = isPlainRecord(metadata.extensions) ? { ...metadata.extensions } : {};
|
|
220
|
-
extensions[EXECUTABLE_PROFILE_NAMESPACE] = {
|
|
221
|
-
...(isPlainRecord(extensions[EXECUTABLE_PROFILE_NAMESPACE])
|
|
222
|
-
? extensions[EXECUTABLE_PROFILE_NAMESPACE]
|
|
223
|
-
: {}),
|
|
224
|
-
profileVersion: EXECUTABLE_PROFILE_VERSION,
|
|
225
|
-
modelConfig: executableModelConfig,
|
|
226
|
-
};
|
|
227
|
-
metadata.extensions = extensions;
|
|
228
|
-
if (metadata.graphEntry != null) {
|
|
229
|
-
metadata.graphEntry = exellixGraphEntryToAuthoring(metadata.graphEntry);
|
|
230
|
-
}
|
|
231
|
-
if (Array.isArray(source.jobKnowledge)) {
|
|
232
|
-
metadata.jobKnowledge = exellixKnowledgeRefsToAuthoring(source.jobKnowledge);
|
|
233
|
-
}
|
|
234
|
-
const nodes = (source.nodes ?? []).map((node) => {
|
|
235
|
-
const type = node.type ?? 'task';
|
|
236
|
-
if (type === 'finalizer')
|
|
237
|
-
return exellixFinalizerToExecutable(node);
|
|
238
|
-
return exellixTaskNodeToExecutable(node);
|
|
239
|
-
});
|
|
240
|
-
const portByNode = new Map();
|
|
241
|
-
for (const n of nodes)
|
|
242
|
-
portByNode.set(n.id, defaultPorts(n.id));
|
|
243
|
-
const edges = (source.edges ?? []).map((e, index) => {
|
|
244
|
-
const fromPorts = portByNode.get(e.from) ?? defaultPorts(e.from);
|
|
245
|
-
const toPorts = portByNode.get(e.to) ?? defaultPorts(e.to);
|
|
246
|
-
return {
|
|
247
|
-
id: `edge:${index}:${e.from}->${e.to}`,
|
|
248
|
-
from: { nodeId: e.from, portId: fromPorts.out },
|
|
249
|
-
to: { nodeId: e.to, portId: toPorts.in },
|
|
250
|
-
...(e.when != null ? { when: e.when } : {}),
|
|
251
|
-
};
|
|
252
|
-
});
|
|
253
|
-
const graphResponse = isPlainRecord(source.response)
|
|
254
|
-
? { shape: source.response.shape, ...source.response }
|
|
255
|
-
: undefined;
|
|
256
|
-
return {
|
|
257
|
-
formatVersion: GRAPHENIX_FORMAT_VERSION,
|
|
258
|
-
id: String(source.id),
|
|
259
|
-
revision: typeof source.version === 'string' ? source.version : '1.0.0',
|
|
260
|
-
name: typeof metadata.name === 'string' ? metadata.name : String(source.id),
|
|
261
|
-
graph: {
|
|
262
|
-
nodes,
|
|
263
|
-
edges,
|
|
264
|
-
inputs: [],
|
|
265
|
-
outputs: [],
|
|
266
|
-
metadata: {
|
|
267
|
-
...metadata,
|
|
268
|
-
...(graphResponse ? { graphResponse } : {}),
|
|
269
|
-
graphEntry: metadata.graphEntry,
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ExecutableGraphPlanV2 } from '@x12i/graphenix-executable-contracts';
|
|
2
|
-
import type { GraphRuntimeObject } from '../runtime/ExellixGraphRuntime.js';
|
|
3
|
-
/**
|
|
4
|
-
* `@x12i/graphenix-plan-compiler` v1.0.0 builds AI finalizer plans without resolved
|
|
5
|
-
* `finalizerModel` slots. Rebuild finalizer plans using published compiler helpers.
|
|
6
|
-
*/
|
|
7
|
-
export declare function patchFinalizerPlansOnExecutablePlan(plan: ExecutableGraphPlanV2, runtime: GraphRuntimeObject): ExecutableGraphPlanV2;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { getFinalizerNodeConfig, isExecutableFinalizerNode, } from '@x12i/graphenix-executable-contracts';
|
|
2
|
-
import { buildFinalizerPlans, buildDeterministicCaseContext, resolveGraphModelConfig, } from '@x12i/graphenix-plan-compiler';
|
|
3
|
-
const AI_FINALIZER_TYPES = new Set(['synthesize']);
|
|
4
|
-
/**
|
|
5
|
-
* `@x12i/graphenix-plan-compiler` v1.0.0 builds AI finalizer plans without resolved
|
|
6
|
-
* `finalizerModel` slots. Rebuild finalizer plans using published compiler helpers.
|
|
7
|
-
*/
|
|
8
|
-
export function patchFinalizerPlansOnExecutablePlan(plan, runtime) {
|
|
9
|
-
if (plan.normalizedGraph.mode !== 'embedded')
|
|
10
|
-
return plan;
|
|
11
|
-
const normalized = plan.normalizedGraph.graph;
|
|
12
|
-
const aiFinalizers = normalized.graph.nodes.filter(isExecutableFinalizerNode).filter((node) => {
|
|
13
|
-
const config = getFinalizerNodeConfig(node);
|
|
14
|
-
return config != null && AI_FINALIZER_TYPES.has(String(config.finalizerType));
|
|
15
|
-
});
|
|
16
|
-
if (aiFinalizers.length === 0)
|
|
17
|
-
return plan;
|
|
18
|
-
const context = buildDeterministicCaseContext(normalized, runtime);
|
|
19
|
-
const graphResolution = resolveGraphModelConfig(normalized, context);
|
|
20
|
-
const triplet = graphResolution.triplet;
|
|
21
|
-
if (triplet.preActionModel == null && triplet.skillModel == null && triplet.postActionModel == null) {
|
|
22
|
-
return plan;
|
|
23
|
-
}
|
|
24
|
-
const slotMeta = {
|
|
25
|
-
source: 'graphDefault',
|
|
26
|
-
inherited: true,
|
|
27
|
-
graphCaseId: graphResolution.caseId,
|
|
28
|
-
};
|
|
29
|
-
const resolvedFinalizerSlots = {};
|
|
30
|
-
for (const node of aiFinalizers) {
|
|
31
|
-
const finalizerSelection = triplet.postActionModel ?? triplet.skillModel ?? triplet.preActionModel;
|
|
32
|
-
if (finalizerSelection == null)
|
|
33
|
-
continue;
|
|
34
|
-
resolvedFinalizerSlots[node.id] = {
|
|
35
|
-
selection: finalizerSelection,
|
|
36
|
-
...slotMeta,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const finalizerPlans = buildFinalizerPlans(normalized, resolvedFinalizerSlots);
|
|
40
|
-
for (const node of aiFinalizers) {
|
|
41
|
-
const entry = finalizerPlans[node.id];
|
|
42
|
-
if (!entry)
|
|
43
|
-
continue;
|
|
44
|
-
entry.modelSlots = {
|
|
45
|
-
...(triplet.preActionModel != null
|
|
46
|
-
? { preActionModel: { selection: triplet.preActionModel, ...slotMeta } }
|
|
47
|
-
: {}),
|
|
48
|
-
...(triplet.skillModel != null
|
|
49
|
-
? { skillModel: { selection: triplet.skillModel, ...slotMeta } }
|
|
50
|
-
: {}),
|
|
51
|
-
...(triplet.postActionModel != null
|
|
52
|
-
? { postActionModel: { selection: triplet.postActionModel, ...slotMeta } }
|
|
53
|
-
: {}),
|
|
54
|
-
...(entry.modelSlots?.finalizerModel != null
|
|
55
|
-
? { finalizerModel: entry.modelSlots.finalizerModel }
|
|
56
|
-
: {}),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
...plan,
|
|
61
|
-
finalizerPlans,
|
|
62
|
-
};
|
|
63
|
-
}
|