@exellix/graph-engine 7.8.2 → 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.
Files changed (35) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +26 -24
  3. package/dist/src/compile/compileExellixExecutablePlan.d.ts +9 -0
  4. package/dist/src/compile/compileExellixExecutablePlan.js +24 -0
  5. package/dist/src/errors/exellixGraphErrorCodes.d.ts +5 -0
  6. package/dist/src/errors/exellixGraphErrorCodes.js +5 -0
  7. package/dist/src/index.d.ts +10 -2
  8. package/dist/src/index.js +6 -2
  9. package/dist/src/plan/aiModelSelectionWire.d.ts +11 -0
  10. package/dist/src/plan/aiModelSelectionWire.js +39 -0
  11. package/dist/src/plan/applyNodePlanInvoke.d.ts +10 -0
  12. package/dist/src/plan/applyNodePlanInvoke.js +67 -0
  13. package/dist/src/plan/embeddedGraphToExellixGraph.d.ts +5 -0
  14. package/dist/src/plan/embeddedGraphToExellixGraph.js +131 -0
  15. package/dist/src/plan/planDeferredGates.d.ts +16 -0
  16. package/dist/src/plan/planDeferredGates.js +118 -0
  17. package/dist/src/plan/planExecuteEntry.d.ts +12 -0
  18. package/dist/src/plan/planExecuteEntry.js +73 -0
  19. package/dist/src/plan/planExecutionPipeline.d.ts +11 -0
  20. package/dist/src/plan/planExecutionPipeline.js +54 -0
  21. package/dist/src/plan/planModelConfig.d.ts +10 -0
  22. package/dist/src/plan/planModelConfig.js +46 -0
  23. package/dist/src/runtime/ExellixGraphRuntime.d.ts +9 -6
  24. package/dist/src/runtime/ExellixGraphRuntime.js +134 -97
  25. package/dist/src/runtime/executionMatrixHost.d.ts +1 -1
  26. package/dist/src/runtime/executionMatrixHost.js +3 -2
  27. package/dist/src/runtime/studioGraphExecuteRequest.d.ts +51 -0
  28. package/dist/src/runtime/studioGraphExecuteRequest.js +78 -0
  29. package/dist/src/types/refs.d.ts +1 -1
  30. package/dist/testkit/buildExecuteGraphInput.d.ts +4 -0
  31. package/dist/testkit/buildExecuteGraphInput.js +8 -0
  32. package/dist/testkit/index.d.ts +1 -0
  33. package/dist/testkit/index.js +1 -0
  34. package/dist/testkit/testModelAliasRuntime.js +2 -2
  35. package/package.json +8 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
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
+
11
+ ## 8.0.0
12
+
13
+ ### Breaking
14
+
15
+ - **`executeGraph({ plan, runtime })` only** — removed `ExecuteGraphInput.model`. Hosts compile with `compileExellixExecutablePlan` or `@x12i/graphenix-plan-compiler` before invoke.
16
+ - **`ExecuteGraphResult.graphAudit` → `planAudit`** (`{ planHash, source }`).
17
+ - Execute-time model case selection and `assertCanonicalGraphDocument` removed from the run path; frozen `plan.nodePlans` / `plan.finalizerPlans` drive model config and invoke contracts.
18
+
19
+ ### Added
20
+
21
+ - **`@x12i/graphenix-*` integration:** plan validation, deferred gates, trace events (`ExecuteGraphResult.trace`), and exports for `ExecutableGraphPlanV2`.
22
+ - **`compileExellixExecutablePlan`**, **`migrateLegacyGraphModelObjectToGraphenixExecutable`** (re-export from `@x12i/graphenix-authoring-format`) — host compile helpers for legacy exellix `GraphModelObject`.
23
+ - **`buildAuthoringStudioGraphExecutionRequest`** re-export from `@x12i/graphenix-execute-envelope`.
24
+
25
+ See [`BREAKING-CHANGES.md`](BREAKING-CHANGES.md) §8.0.0.
26
+
27
+ ## 7.8.3
28
+
29
+ ### Breaking
30
+
31
+ - **Studio graph execute envelope:** `graphDefaultModel` removed with **no legacy reader**. Request-level model defaults duplicated `graph.modelConfig` and were never applied by graph-engine. Hosts (graphs-studio) must persist defaults on **`graph.modelConfig` only** and stop sending `graphDefaultModel`.
32
+ - **Validation:** `assertCanonicalStudioGraphExecuteRequest` and `buildGraphExecutionRequestFromStudioExecute` reject the removed key (`NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST`).
33
+
34
+ ### Added
35
+
36
+ - **Documentation:** [`formats-documentations/graph-format-boundaries.md`](formats-documentations/graph-format-boundaries.md) — four-layer model (graph / runtime / studio envelope / studio DB), field mapping from playground payloads, and explicit list of what is not on `GraphModelObject`.
37
+
3
38
  ## 7.8.2
4
39
 
5
40
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@ A minimal, focused SDK for executing graphs in the exellix ecosystem.
4
4
 
5
5
  ## What this package does and does not
6
6
 
7
- **In scope — what this package does:** On each **`createExellixGraphRuntime(...).executeGraph({ model, runtime })`** invocation, it runs **exactly one graph run** (validate modelplan → nodes → finalizer) until that run **completes or fails**, then returns the result. There is **no** batching, queueing, or multi-job orchestration inside this package — each call is one logical run. You supply the static **`model: GraphModelObject`**, planner (`GraphEngineFactory`), tasks client, and dynamic **`runtime: GraphRuntimeObject`** with the mandatory host `jobId`, `job` envelope, active `input`, memory, variables, and per-run options. The engine generates a fresh **`taskId`** (UUID) per invocation and sends it on **every** `runTask` request together with **`jobId`**. That is the **entire** product role of graph-engine.
7
+ **In scope — what this package does:** On each **`createExellixGraphRuntime(...).executeGraph({ plan, runtime })`** invocation, it runs **exactly one graph run** (validate planschedule waves → nodes → finalizer) until that run **completes or fails**, then returns the result. There is **no** batching, queueing, or multi-job orchestration inside this package — each call is one logical run. You supply a compiled v2 **`plan: ExecutableGraphPlanV2`** (from `@x12i/graphenix-plan-compiler` or {@link compileExellixExecutablePlan}), planner (`GraphEngineFactory`), tasks client, and dynamic **`runtime: GraphRuntimeObject`** with the mandatory host `jobId`, `job` envelope, active `input`, memory, variables, and per-run options. The engine generates a fresh **`taskId`** (UUID) per invocation and sends it on **every** `runTask` request together with **`jobId`**. That is the **entire** product role of graph-engine.
8
8
 
9
9
  **Out of scope — what this package does not do:** It does **not** schedule work, own **execution matrices**, manage **claims** or **rows**, persist **job** lifecycle, implement **retry/requeue policy**, or **track** runs across tenants or sessions. Optional helpers and docs for matrix *hosts* only help **build arguments** for the same single-run API; they do **not** move orchestration into this package. Integrations (e.g. Activix graph-run events) emit data **for that call** when you wire an `eventEmitter` — they do not make graph-engine a workflow or matrix service.
10
10
 
@@ -12,8 +12,8 @@ A minimal, focused SDK for executing graphs in the exellix ecosystem.
12
12
 
13
13
  `exellix-graph-engine` does exactly this loop:
14
14
 
15
- 1. **Validate graph model:** The caller supplies **`model: GraphModelObject`** directly in the execution request. The effective correlation **`graphId`** on the result and in telemetry is **`model.id`**.
16
- 2. `plan = graphenix.plan(...)`
15
+ 1. **Validate executable plan:** The caller supplies **`plan: ExecutableGraphPlanV2`** (compiled upstream). The effective correlation **`graphId`** on the result and in telemetry is **`plan.source.graphId`**.
16
+ 2. `executeGraph({ plan, runtime })`
17
17
  3. For each runnable node:
18
18
  - Map node → `skillKey` (strict rules)
19
19
  - If `skillKey` is a **local skill** (`scoped-data-reader`, `deterministic-rule`, `scoped-answer-writer`, `scoped-answer-assembler`), run it in-process (no `ai-tasks` call); otherwise call `ai-tasks.runTask(...)`
@@ -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 still comes from `executeGraph({ model, runtime }).runtime.mode`; `outputMode` does not decide the returned `finalOutput`.
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`** (see [Run identity](#run-identity-host-jobid-and-engine-taskid) below). Helpers such as **`buildMatrixJobForGraphRun`** align **`id`** and **`job.jobId`** on the `job` object so you can call **`runtime.executeGraph({ model, 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.
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
 
@@ -97,7 +97,7 @@ Lower-level helpers (`validateRunTaskConfig`, `validateRunTaskInvoke`, `analyzeE
97
97
  ## Quick Start
98
98
 
99
99
  ```typescript
100
- import { createExellixGraphRuntime } from '@exellix/graph-engine';
100
+ import { compileExellixExecutablePlan, createExellixGraphRuntime } from '@exellix/graph-engine';
101
101
 
102
102
  const runtime = createExellixGraphRuntime({
103
103
  graphLoader: myGraphLoader,
@@ -121,15 +121,18 @@ const graphModel = {
121
121
  // …
122
122
  };
123
123
 
124
+ const graphRuntime = {
125
+ jobId: 'job-123',
126
+ job: { agentId: 'agent-1', input: {} },
127
+ input: { question: 'Analyze this record' },
128
+ };
129
+
130
+ const plan = compileExellixExecutablePlan(graphModel, graphRuntime);
131
+
124
132
  // Host correlation id (required). Engine sets `job.id` / `job.jobId` from it and generates `result.taskId`.
125
133
  const result = await runtime.executeGraph({
126
- model: graphModel,
127
- runtime: {
128
- jobId: 'job-123',
129
- job: { agentId: 'agent-1', input: {} },
130
- input: { question: 'Analyze this record' },
131
- // no modelConfig or aliasConfig on runtime (removed in 7.7)
132
- },
134
+ plan,
135
+ runtime: graphRuntime,
133
136
  });
134
137
 
135
138
  // Canonical business output + per-run ids:
@@ -138,11 +141,11 @@ console.log(result.finalOutput, result.jobId, result.taskId);
138
141
 
139
142
  ## Public API
140
143
 
141
- ### `runtime.executeGraph({ model, runtime })`
144
+ ### `runtime.executeGraph({ plan, runtime })`
142
145
 
143
146
  Execute a complete graph through the **single canonical client API**: `createExellixGraphRuntime(...)`. The runtime owns local-skill interception, conditional edge filtering, optional `eventEmitter`, optional `debugMode`, and produces one `ExecuteGraphResult` shape.
144
147
 
145
- Every call requires a static **`model: GraphModelObject`** and a dynamic **`runtime: GraphRuntimeObject`**. `runtime.jobId` is mandatory and non-empty. The engine also generates a **`taskId`** (UUID) per invocation. Together they form the **identity** forwarded to **`@exellix/ai-tasks`** (`runTask({ jobId, taskId, … })`), graph/node **`eventEmitter`** payloads, structured **`runLog`**, and Activix **`runContext`** / record metadata.
148
+ Every call requires a compiled v2 **`plan: ExecutableGraphPlanV2`** and a dynamic **`runtime: GraphRuntimeObject`**. Hosts compile authoring graphs with `@x12i/graphenix-plan-compiler` (or {@link compileExellixExecutablePlan} for legacy exellix `GraphModelObject`) before invoke. `runtime.jobId` is mandatory and non-empty. The engine also generates a **`taskId`** (UUID) per invocation. Together they form the **identity** forwarded to **`@exellix/ai-tasks`** (`runTask({ jobId, taskId, … })`), graph/node **`eventEmitter`** payloads, structured **`runLog`**, and Activix **`runContext`** / record metadata.
146
149
 
147
150
  ```typescript
148
151
  import { createExellixGraphRuntime } from '@exellix/graph-engine';
@@ -210,10 +213,11 @@ interface ExecuteGraphResult {
210
213
  runLogOmittedCount?: number;
211
214
  logxerCorrelationId?: string;
212
215
  debug?: { nodes: NodeTraceEntry[] }; // populated only when debugMode: true
213
- graphAudit?: {
214
- source: 'model';
215
- contentSha256: string; // stable JSON + SHA-256 of supplied model (audit / matrix persistence)
216
+ planAudit?: {
217
+ planHash: string;
218
+ source: string;
216
219
  };
220
+ trace?: unknown;
217
221
  }
218
222
  ```
219
223
 
@@ -234,13 +238,11 @@ const runtime = createExellixGraphRuntime({
234
238
  playgroundReporter,
235
239
  });
236
240
 
241
+ const plan = compileExellixExecutablePlan(graphModel, graphRuntime);
242
+
237
243
  await runtime.executeGraph({
238
- model,
239
- runtime: {
240
- jobId: 'job-123',
241
- job,
242
- input,
243
- },
244
+ plan,
245
+ runtime: graphRuntime,
244
246
  });
245
247
 
246
248
  // Inspect full node request/response payloads in memory.
@@ -0,0 +1,9 @@
1
+ import type { CompileExecutablePlanV2Options, ExecutableGraphPlanV2 } from '@x12i/graphenix-executable-contracts';
2
+ import type { Graph, GraphModelObject } from '../types/refs.js';
3
+ import type { GraphRuntimeObject } from '../runtime/ExellixGraphRuntime.js';
4
+ export type CompileExellixExecutablePlanOptions = CompileExecutablePlanV2Options;
5
+ /**
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.
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
+ }
@@ -13,6 +13,11 @@ export declare enum ExellixGraphErrorCode {
13
13
  INVALID_GRAPH = "INVALID_GRAPH",
14
14
  /** Graph JSON has forbidden top-level keys; document metadata must be under `metadata` only. */
15
15
  NON_CANONICAL_GRAPH_DOCUMENT = "NON_CANONICAL_GRAPH_DOCUMENT",
16
+ /**
17
+ * Graphs-studio execute envelope carries a removed or forbidden key (e.g. request-level `graphDefaultModel`).
18
+ * Model defaults belong on `graph.modelConfig` only.
19
+ */
20
+ NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST = "NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST",
16
21
  /** Runtime object carries forbidden model / llmCall overrides (graph document only since 7.7). */
17
22
  NON_CANONICAL_GRAPH_RUNTIME = "NON_CANONICAL_GRAPH_RUNTIME",
18
23
  /**
@@ -14,6 +14,11 @@ export var ExellixGraphErrorCode;
14
14
  ExellixGraphErrorCode["INVALID_GRAPH"] = "INVALID_GRAPH";
15
15
  /** Graph JSON has forbidden top-level keys; document metadata must be under `metadata` only. */
16
16
  ExellixGraphErrorCode["NON_CANONICAL_GRAPH_DOCUMENT"] = "NON_CANONICAL_GRAPH_DOCUMENT";
17
+ /**
18
+ * Graphs-studio execute envelope carries a removed or forbidden key (e.g. request-level `graphDefaultModel`).
19
+ * Model defaults belong on `graph.modelConfig` only.
20
+ */
21
+ ExellixGraphErrorCode["NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST"] = "NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST";
17
22
  /** Runtime object carries forbidden model / llmCall overrides (graph document only since 7.7). */
18
23
  ExellixGraphErrorCode["NON_CANONICAL_GRAPH_RUNTIME"] = "NON_CANONICAL_GRAPH_RUNTIME";
19
24
  /**
@@ -9,8 +9,8 @@
9
9
  * 5. Repeat until done/fail
10
10
  *
11
11
  * Single canonical entry point: {@link createExellixGraphRuntime} returns
12
- * `{ executeGraph({ model, runtime }: GraphExecutionRequest) }`. The legacy functional `executeGraph`
13
- * and the `ExellixGraphClient` class were removed in 5.0.
12
+ * `{ executeGraph({ plan, runtime }: GraphExecutionRequest) }`. Hosts compile upstream via
13
+ * {@link compileExellixExecutablePlan} or `@x12i/graphenix-plan-compiler`.
14
14
  */
15
15
  export type { HostExecuteGraphRunOptions, MainReadinessPolicy, ExecutionStepOption, StepRetryPolicy, ActivixNodeActivityExellixConfig, SkillKeyResolutionOptions, RunTaskRequest as ExellixGraphRunTaskRequest, RunTaskResponse as ExellixGraphRunTaskResponse, } from './types/options.js';
16
16
  export type { AiTaskProfileMetadata, AiTaskProfileWebScoping, AiTaskProfileInputSynthesis, } from './types/aiTaskProfile.js';
@@ -83,11 +83,19 @@ export type { AssertCanonicalGraphDocumentOptions, CanonicalGraphDocumentValidat
83
83
  export { assertCanonicalGraphRuntimeObject } from './runtime/validateCanonicalGraphRuntime.js';
84
84
  export { GRAPH_ENTRY_STUDIO_ONLY_KEYS, GRAPH_METADATA_STUDIO_ONLY_KEYS, stripGraphModelStudioFields, primaryRuntimeInputFromStudioDocument, getGraphEntryStudioOnlyKeyViolations, getGraphMetadataStudioOnlyKeyViolations, getGraphEntryEmptyInputPathViolations, } from './runtime/graphModelStudioSeparation.js';
85
85
  export type { GraphStudioDocument } from './runtime/graphModelStudioSeparation.js';
86
+ export { STUDIO_GRAPH_EXECUTE_REMOVED_KEYS, getStudioGraphExecuteRemovedKeyViolations, assertCanonicalStudioGraphExecuteRequest, buildGraphExecutionRequestFromStudioExecute, } from './runtime/studioGraphExecuteRequest.js';
87
+ export type { StudioGraphExecuteRemovedKey, StudioGraphExecuteRequest, BuildGraphExecutionRequestFromStudioExecuteOptions, } from './runtime/studioGraphExecuteRequest.js';
86
88
  export { computeGraphDocumentContentSha256, stableStringifyGraphDocument, } from './runtime/graphDocumentFingerprint.js';
87
89
  export { migrateLegacyGraphResponse, migrateLegacyGraphResponseDefinition, } from './runtime/graphResponseMigration.js';
88
90
  export type { MigrateGraphResponseResult } from './runtime/graphResponseMigration.js';
89
91
  export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
90
92
  export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
93
+ export type { ExecutableGraphPlanV2, NodeExecutionPlan, ExecutionUnitPlanV2, } from '@x12i/graphenix-executable-contracts';
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';
98
+ export { buildGraphExecutionRequestFromStudioExecute as buildAuthoringStudioGraphExecutionRequest } from '@x12i/graphenix-execute-envelope';
91
99
  export type { RunTaskRequest, RunTaskResponse, TasksClientLike, GraphLoader as RuntimeGraphLoader, ExecuteGraphInput, GraphExecutionRequest, GraphRuntimeObject, GraphKnowledgeResolver, GraphKnowledgeResolverContext, ExecuteGraphResult, ExellixGraphRuntimeOptions, } from './runtime/ExellixGraphRuntime.js';
92
100
  export type { PlanStatus, GraphPlan, GraphEngine, GraphEngineFactory, } from './runtime/GraphEngine.js';
93
101
  export { InMemoryGraphLoader, DepGraphEngineFactory } from '../testkit/index.js';
package/dist/src/index.js CHANGED
@@ -9,8 +9,8 @@
9
9
  * 5. Repeat until done/fail
10
10
  *
11
11
  * Single canonical entry point: {@link createExellixGraphRuntime} returns
12
- * `{ executeGraph({ model, runtime }: GraphExecutionRequest) }`. The legacy functional `executeGraph`
13
- * and the `ExellixGraphClient` class were removed in 5.0.
12
+ * `{ executeGraph({ plan, runtime }: GraphExecutionRequest) }`. Hosts compile upstream via
13
+ * {@link compileExellixExecutablePlan} or `@x12i/graphenix-plan-compiler`.
14
14
  */
15
15
  export { mergeGraphDocumentModel, EXELLIX_GRAPH_MODEL_VARIABLE_KEY, EXELLIX_STRUCTURED_DATA_FILTERS_V1, } from './types/refs.js';
16
16
  export { getTaskConfiguration } from './types/taskNodeConfiguration.js';
@@ -61,11 +61,15 @@ export { buildExellixGraphRuntimeObjects, setRuntimeObjectsLastJobId, summarizeR
61
61
  export { assertCanonicalGraphDocument, assertCanonicalTaskNode, getCanonicalGraphDocumentViolations, CANONICAL_GRAPH_TOP_LEVEL_KEYS, } from './runtime/validateCanonicalGraphDocument.js';
62
62
  export { assertCanonicalGraphRuntimeObject } from './runtime/validateCanonicalGraphRuntime.js';
63
63
  export { GRAPH_ENTRY_STUDIO_ONLY_KEYS, GRAPH_METADATA_STUDIO_ONLY_KEYS, stripGraphModelStudioFields, primaryRuntimeInputFromStudioDocument, getGraphEntryStudioOnlyKeyViolations, getGraphMetadataStudioOnlyKeyViolations, getGraphEntryEmptyInputPathViolations, } from './runtime/graphModelStudioSeparation.js';
64
+ export { STUDIO_GRAPH_EXECUTE_REMOVED_KEYS, getStudioGraphExecuteRemovedKeyViolations, assertCanonicalStudioGraphExecuteRequest, buildGraphExecutionRequestFromStudioExecute, } from './runtime/studioGraphExecuteRequest.js';
64
65
  export { computeGraphDocumentContentSha256, stableStringifyGraphDocument, } from './runtime/graphDocumentFingerprint.js';
65
66
  export { migrateLegacyGraphResponse, migrateLegacyGraphResponseDefinition, } from './runtime/graphResponseMigration.js';
66
67
  export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
67
68
  // New runtime with injection seam
68
69
  export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
70
+ export { compileExellixExecutablePlan } from './compile/compileExellixExecutablePlan.js';
71
+ export { migrateLegacyGraphModelObjectToGraphenixExecutable, } from '@x12i/graphenix-authoring-format';
72
+ export { buildGraphExecutionRequestFromStudioExecute as buildAuthoringStudioGraphExecutionRequest } from '@x12i/graphenix-execute-envelope';
69
73
  // Testkit (in-memory loader, dep engine, recording client — sample NARRIX tasks: `@exellix/graph-engine/testkit`)
70
74
  export { InMemoryGraphLoader, DepGraphEngineFactory } from '../testkit/index.js';
71
75
  // Graph loaders
@@ -0,0 +1,11 @@
1
+ import type { AiModelSelection } from '@x12i/graphenix-executable-contracts';
2
+ import type { ResolvedInvocationSnapshot } from '@x12i/graphenix-executable-contracts';
3
+ /**
4
+ * Maps plan {@link AiModelSelection} to ai-tasks 8.4+ wire profile strings.
5
+ */
6
+ export declare function aiModelSelectionToWireString(selection: AiModelSelection | undefined): string | undefined;
7
+ export declare function resolvedSnapshotToWireString(snapshot: ResolvedInvocationSnapshot | undefined): string | undefined;
8
+ export declare function unitModelWireString(args: {
9
+ modelSelection?: AiModelSelection;
10
+ resolvedInvocationSnapshot?: ResolvedInvocationSnapshot;
11
+ }): string | undefined;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Maps plan {@link AiModelSelection} to ai-tasks 8.4+ wire profile strings.
3
+ */
4
+ export function aiModelSelectionToWireString(selection) {
5
+ if (selection == null)
6
+ return undefined;
7
+ if (selection.kind === 'profileChoice')
8
+ return selection.key.trim();
9
+ if (selection.kind === 'profile') {
10
+ const profile = selection.profile.trim();
11
+ const choice = typeof selection.choice === 'string' ? selection.choice.trim() : '';
12
+ return choice ? `${profile}/${choice}` : profile;
13
+ }
14
+ if (selection.kind === 'model') {
15
+ const modelId = typeof selection.modelId === 'string'
16
+ ? selection.modelId
17
+ : typeof selection.model === 'string'
18
+ ? selection.model
19
+ : '';
20
+ return `${selection.provider}/${modelId}`.replace(/\/+/g, '/');
21
+ }
22
+ return undefined;
23
+ }
24
+ export function resolvedSnapshotToWireString(snapshot) {
25
+ if (snapshot == null)
26
+ return undefined;
27
+ if (snapshot.purpose === 'strictReplay' || snapshot.purpose === 'debugReplay') {
28
+ return `${snapshot.provider}/${snapshot.modelId}`;
29
+ }
30
+ if (snapshot.profileChoiceKey)
31
+ return snapshot.profileChoiceKey;
32
+ return undefined;
33
+ }
34
+ export function unitModelWireString(args) {
35
+ const fromSnapshot = resolvedSnapshotToWireString(args.resolvedInvocationSnapshot);
36
+ if (fromSnapshot)
37
+ return fromSnapshot;
38
+ return aiModelSelectionToWireString(args.modelSelection);
39
+ }
@@ -0,0 +1,10 @@
1
+ import type { FinalizerExecutionPlan, NodeExecutionPlan } from '@x12i/graphenix-executable-contracts';
2
+ import type { TaskNode } from '../types/refs.js';
3
+ /** Merge frozen plan invoke contract onto exellix task node before execution. */
4
+ export declare function applyNodePlanInvoke(node: TaskNode, nodePlan: NodeExecutionPlan): TaskNode;
5
+ export declare function finalizerPlanForId(plan: {
6
+ finalizerPlans: Record<string, FinalizerExecutionPlan>;
7
+ }, nodeId: string): FinalizerExecutionPlan | undefined;
8
+ export declare function nodePlanForId(plan: {
9
+ nodePlans: Record<string, NodeExecutionPlan>;
10
+ }, nodeId: string): NodeExecutionPlan | undefined;
@@ -0,0 +1,67 @@
1
+ function isPlainRecord(v) {
2
+ return v != null && typeof v === 'object' && !Array.isArray(v);
3
+ }
4
+ /** Merge frozen plan invoke contract onto exellix task node before execution. */
5
+ export function applyNodePlanInvoke(node, nodePlan) {
6
+ const patched = structuredClone(node);
7
+ const ic = nodePlan.invokeContract;
8
+ if (!ic)
9
+ return patched;
10
+ if (ic.taskVariable != null)
11
+ patched.taskVariable = structuredClone(ic.taskVariable);
12
+ if (ic.inputsConfig != null)
13
+ patched.inputsConfig = structuredClone(ic.inputsConfig);
14
+ if (ic.executionMapping != null)
15
+ patched.executionMapping = structuredClone(ic.executionMapping);
16
+ if (ic.jobContextMapping != null)
17
+ patched.jobContextMapping = structuredClone(ic.jobContextMapping);
18
+ if (ic.smartInput != null)
19
+ patched.smartInput = structuredClone(ic.smartInput);
20
+ if (ic.scope != null)
21
+ patched.scope = structuredClone(ic.scope);
22
+ if (ic.memory != null)
23
+ patched.memory = structuredClone(ic.memory);
24
+ if (Array.isArray(ic.knowledgeRefs?.taskKnowledge)) {
25
+ patched.taskKnowledge = ic.knowledgeRefs.taskKnowledge.map((ref) => {
26
+ if (typeof ref === 'string')
27
+ return ref;
28
+ if (isPlainRecord(ref) && typeof ref.id === 'string')
29
+ return ref.id;
30
+ return String(ref);
31
+ });
32
+ }
33
+ const tc = { ...(patched.taskConfiguration ?? {}) };
34
+ const pipeline = ic.pipeline;
35
+ if (isPlainRecord(pipeline)) {
36
+ if (pipeline.executionStrategies !== undefined)
37
+ tc.executionStrategies = pipeline.executionStrategies;
38
+ if (pipeline.aiTaskStrategies !== undefined)
39
+ tc.aiTaskStrategies = pipeline.aiTaskStrategies;
40
+ if (pipeline.aiTaskProfile !== undefined)
41
+ tc.aiTaskProfile = pipeline.aiTaskProfile;
42
+ if (pipeline.narrix !== undefined)
43
+ tc.narrix = pipeline.narrix;
44
+ if (pipeline.narrixInput !== undefined)
45
+ tc.narrixInput = pipeline.narrixInput;
46
+ if (pipeline.narrixMode !== undefined)
47
+ tc.narrixMode = pipeline.narrixMode;
48
+ if (pipeline.llmCall !== undefined)
49
+ tc.llmCall = pipeline.llmCall;
50
+ }
51
+ if (ic.validation?.aiTasksOutputValidation != null) {
52
+ tc.aiTasksOutputValidation = ic.validation.aiTasksOutputValidation;
53
+ }
54
+ if (ic.validation?.outputValidation != null) {
55
+ patched.outputValidation = ic.validation.outputValidation;
56
+ }
57
+ if (ic.localConfig != null)
58
+ Object.assign(tc, ic.localConfig);
59
+ patched.taskConfiguration = tc;
60
+ return patched;
61
+ }
62
+ export function finalizerPlanForId(plan, nodeId) {
63
+ return plan.finalizerPlans[nodeId];
64
+ }
65
+ export function nodePlanForId(plan, nodeId) {
66
+ return plan.nodePlans[nodeId];
67
+ }
@@ -0,0 +1,5 @@
1
+ import type { ExecutableGraphPlanV2, NormalizedExecutableGraphDocument } from '@x12i/graphenix-executable-contracts';
2
+ import type { Graph } from '../types/refs.js';
3
+ /** Materialize exellix {@link Graph} from plan embedded normalized authoring graph. */
4
+ export declare function embeddedGraphToExellixGraph(plan: ExecutableGraphPlanV2): Graph;
5
+ export declare function getEmbeddedExecutableDocument(plan: ExecutableGraphPlanV2): NormalizedExecutableGraphDocument;
@@ -0,0 +1,131 @@
1
+ import { getFinalizerNodeConfig, getTaskNodeConfig, isExecutableFinalizerNode, isExecutableTaskNode, } from '@x12i/graphenix-executable-contracts';
2
+ function isPlainRecord(v) {
3
+ return v != null && typeof v === 'object' && !Array.isArray(v);
4
+ }
5
+ function taskNodeFromExecutableNode(node) {
6
+ const params = getTaskNodeConfig(node);
7
+ if (!params) {
8
+ throw new Error(`Expected executable task node "${node.id}"`);
9
+ }
10
+ const tc = isPlainRecord(params.taskConfiguration) ? { ...params.taskConfiguration } : {};
11
+ const out = {
12
+ id: node.id,
13
+ type: 'task',
14
+ skillKey: typeof params.skillKey === 'string' ? params.skillKey : undefined,
15
+ };
16
+ if (params.taskVariable !== undefined)
17
+ out.taskVariable = structuredClone(params.taskVariable);
18
+ if (params.inputsConfig !== undefined)
19
+ out.inputsConfig = structuredClone(params.inputsConfig);
20
+ if (params.executionMapping !== undefined) {
21
+ out.executionMapping = structuredClone(params.executionMapping);
22
+ }
23
+ if (Array.isArray(params.taskKnowledge)) {
24
+ out.taskKnowledge = params.taskKnowledge.map((ref) => {
25
+ if (typeof ref === 'string')
26
+ return ref;
27
+ if (isPlainRecord(ref) && typeof ref.id === 'string')
28
+ return ref.id;
29
+ return String(ref);
30
+ });
31
+ }
32
+ if (params.conditions !== undefined)
33
+ out.conditions = structuredClone(params.conditions);
34
+ if (isPlainRecord(params.variables))
35
+ out.variables = structuredClone(params.variables);
36
+ if (isPlainRecord(params.metadata))
37
+ out.metadata = structuredClone(params.metadata);
38
+ out.taskConfiguration = tc;
39
+ const pipeline = params.executionPipeline;
40
+ if (Array.isArray(pipeline))
41
+ out.executionPipeline = structuredClone(pipeline);
42
+ return out;
43
+ }
44
+ function finalizerNodeFromExecutableNode(node) {
45
+ const params = getFinalizerNodeConfig(node);
46
+ if (!params) {
47
+ throw new Error(`Expected executable finalizer node "${node.id}"`);
48
+ }
49
+ const paramsRecord = params;
50
+ return {
51
+ id: node.id,
52
+ type: 'finalizer',
53
+ finalizerType: params.finalizerType,
54
+ config: isPlainRecord(params.config) ? structuredClone(params.config) : {},
55
+ inputs: isPlainRecord(params.inputs) ? structuredClone(params.inputs) : undefined,
56
+ ...(isPlainRecord(paramsRecord.outputMapping)
57
+ ? { outputMapping: structuredClone(paramsRecord.outputMapping) }
58
+ : {}),
59
+ };
60
+ }
61
+ function knowledgeRefsToExellixStrings(refs) {
62
+ if (!Array.isArray(refs))
63
+ return undefined;
64
+ return refs.map((ref) => {
65
+ if (typeof ref === 'string')
66
+ return ref;
67
+ if (isPlainRecord(ref) && typeof ref.id === 'string')
68
+ return ref.id;
69
+ return String(ref);
70
+ });
71
+ }
72
+ function edgesFromPlan(plan) {
73
+ return plan.topology.edges.map((edgeRef) => {
74
+ const deferred = plan.deferredGates.edgeGates[edgeRef.edgeId];
75
+ const out = {
76
+ from: edgeRef.from.nodeId,
77
+ to: edgeRef.to.nodeId,
78
+ };
79
+ if (deferred?.when != null)
80
+ out.when = deferred.when;
81
+ return out;
82
+ });
83
+ }
84
+ function responseFromEmbedded(doc, plan) {
85
+ const metaResponse = doc.graph.metadata?.graphResponse;
86
+ if (isPlainRecord(metaResponse)) {
87
+ const out = {
88
+ shape: isPlainRecord(metaResponse.shape) ? structuredClone(metaResponse.shape) : {},
89
+ };
90
+ if (metaResponse.missing !== undefined) {
91
+ out.missing = metaResponse.missing;
92
+ }
93
+ if (metaResponse.version !== undefined) {
94
+ out.version = metaResponse.version;
95
+ }
96
+ return out;
97
+ }
98
+ if (isPlainRecord(plan.contracts?.response?.finalOutputSchema)) {
99
+ return { shape: { type: 'literal', value: {} } };
100
+ }
101
+ return { shape: {} };
102
+ }
103
+ /** Materialize exellix {@link Graph} from plan embedded normalized authoring graph. */
104
+ export function embeddedGraphToExellixGraph(plan) {
105
+ if (plan.normalizedGraph.mode !== 'embedded') {
106
+ throw new Error('embeddedGraphToExellixGraph requires embedded normalizedGraph');
107
+ }
108
+ const doc = plan.normalizedGraph.graph;
109
+ const nodes = [];
110
+ for (const node of doc.graph.nodes) {
111
+ if (isExecutableTaskNode(node))
112
+ nodes.push(taskNodeFromExecutableNode(node));
113
+ else if (isExecutableFinalizerNode(node))
114
+ nodes.push(finalizerNodeFromExecutableNode(node));
115
+ }
116
+ return {
117
+ id: plan.source.graphId,
118
+ version: plan.source.graphRevision,
119
+ nodes,
120
+ edges: edgesFromPlan(plan),
121
+ response: responseFromEmbedded(doc, plan),
122
+ metadata: isPlainRecord(doc.graph.metadata) ? structuredClone(doc.graph.metadata) : undefined,
123
+ jobKnowledge: knowledgeRefsToExellixStrings(isPlainRecord(doc.graph.metadata) ? doc.graph.metadata.jobKnowledge : undefined),
124
+ };
125
+ }
126
+ export function getEmbeddedExecutableDocument(plan) {
127
+ if (plan.normalizedGraph.mode !== 'embedded') {
128
+ throw new Error('getEmbeddedExecutableDocument requires embedded normalizedGraph');
129
+ }
130
+ return plan.normalizedGraph.graph;
131
+ }
@@ -0,0 +1,16 @@
1
+ import type { DeferredEdgeGate, DeferredGateSet, DeferredNodeGate, ExecutableGraphPlanV2 } from '@x12i/graphenix-executable-contracts';
2
+ import type { RunxClient } from '@x12i/runx';
3
+ import type { TaskNodeConditionEvalContext } from '../runtime/taskNodeConditionsEvaluation.js';
4
+ export declare function evaluateDeferredNodeGate(gate: DeferredNodeGate | undefined, ctx: TaskNodeConditionEvalContext, executionInput: Record<string, unknown>, runx?: RunxClient): Promise<{
5
+ ok: boolean;
6
+ skipReason?: string;
7
+ }>;
8
+ export declare function evaluateDeferredEdgeGate(gate: DeferredEdgeGate | undefined, ctx: TaskNodeConditionEvalContext): boolean;
9
+ export declare function buildIncomingEdgeGateMap(plan: ExecutableGraphPlanV2): Map<string, DeferredEdgeGate[]>;
10
+ export declare function nodeDeferredGate(plan: ExecutableGraphPlanV2, nodeId: string): DeferredNodeGate | undefined;
11
+ export declare function hasPlanConditionalEdges(plan: ExecutableGraphPlanV2): boolean;
12
+ export declare function evaluatePlanEntryGates(gates: DeferredGateSet['entryGates'] | undefined, executionInput: Record<string, unknown>, ctx: TaskNodeConditionEvalContext, runx?: RunxClient): Promise<{
13
+ ok: boolean;
14
+ reason?: string;
15
+ }>;
16
+ export declare function planNeedsRunx(plan: ExecutableGraphPlanV2): boolean;