@exellix/graph-engine 8.5.0 → 8.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 8.6.0 — Graphenix 2.7.3 (no-legacy web + narrix pipeline)
4
+
5
+ ### Breaking
6
+
7
+ - **Legacy web scope removed:** Hard-reject `taskConfiguration.aiTaskProfile.webScoping`, `narrix.enableWebScope`, `forceWebScope`, `webScopeQuestions`, and related narrix web keys. Author **`taskConfiguration.aiTaskProfile.webQueryTemplate`** (optional `webQueryTemplates[]`, `webScopeOptions`).
8
+ - **`RunTaskRequest` wire:** Root `narrix` / `narrixMode` / `narrixInput` / `narrixScope` removed (ai-tasks **10.0.12+**). Graph-engine merges graph `variables.narrix` into **`nodePlan.invokeContract.pipeline.narrix`** via `patchNodePlanRuntimePipeline`.
9
+ - **Deleted** `applyAiTaskProfileWebScopingToNarrix` — web scope is plan-compiler PRE `webScope` unit + ai-tasks dispatch, not host-side narrix merge.
10
+
11
+ ### Changed
12
+
13
+ - **`@exellix/ai-tasks` ^10.0.13**, **`@exellix/ai-skills` ^6.12.5**, **`@x12i/catalox` ^5.9.8**.
14
+ - **`@x12i/graphenix-*` ^2.7.3** — includes **`response.persistency`** (`newRecord`, `link.*`) on graph wire (GRX-NOTE-001 / MRX-FRS-002 intent).
15
+ - **`check:no-legacy`** — floors ai-tasks ≥10.0.12, ai-skills ≥6.12.4, graphenix-* ≥2.7.3.
16
+
17
+ ### Added
18
+
19
+ - **`patchNodePlanRuntimePipeline`**, **`resolveRunTaskNodePlan`** — runtime narrix pipeline merge + narrative unit injection on minimal/uncompiled plans.
20
+ - **Exports:** `NarrixModeKey`, `NarrixRunInput`, `NarrixScope` types (local, compatible with plan wire).
21
+
22
+ ### Downstream
23
+
24
+ - **graphs-studio:** see [`docs/handoff/graphs-studio-graphenix-2.7.3.md`](docs/handoff/graphs-studio-graphenix-2.7.3.md).
25
+
3
26
  ## 8.5.0 — Graphenix 2.7.0 + CR-006 (graphEntry.inputs removed)
4
27
 
5
28
  ### Breaking
@@ -13,7 +13,8 @@
13
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
- export type { AiTaskProfileMetadata, AiTaskProfileWebScoping, AiTaskProfileInputSynthesis, } from './types/aiTaskProfile.js';
16
+ export type { AiTaskProfileMetadata, AiTaskProfileInputSynthesis, } from './types/aiTaskProfile.js';
17
+ export { hasWebScopeAuthoring } from './types/aiTaskProfile.js';
17
18
  export type { ExecutionStrategyInvocation, ExecutionStrategyPhase, ExecutionStrategyWrapperKey, SmartInputConfig, TaskStrategyItemData, XynthesizedDestinationScope, XynthesizedMemory, XynthesizedOutputConfig, } from './types/aiTasksDerivedTypes.js';
18
19
  export type { Graph, GraphModelObject, GraphAiModelConfig, PartialGraphAiModelConfig, GraphModelAliasConfig, GraphRuntimeNodeConfig, TaskNodeRuntimeObject, GraphDocumentMetadata, GraphEntryContract, GraphResponseDefinition, GraphResponseMissingBehavior, GraphResponseSelector, GraphResponseShape, GraphResponseContract, GraphResponseMapping, GraphResponseMappingMissingBehavior, GraphResponseMappingSelector, GraphResponseMappingTarget, GraphExecutionDefaults, GraphExecutionMode, GraphOutputMode, GraphFlowOutline, GraphCoreObjective, GraphNodesResponses, GraphNode, TaskNode, TaskNodeConditions, TaskNodeConditionWhen, TaskNodeJsonCondition, TaskNodeJsConditionFunction, TaskNodeAiCondition, TaskNodeConditionParameters, ModelConfigSelection, ModelConfigCase, TaskNodePureMetadata, TaskNodeExecutionPipelineStep, TaskOutputValidation, FinalizerNode, FinalizerInputBinding, OutputSchema, AggregateFinalizerConfig, BundleFinalizerConfig, SelectFinalizerConfig, SynthesizeFinalizerConfig, UtilityExecutionPolicy, Job, CatalogPlanningKind, CatalogRequestStatus, CatalogBinding, ScopedQuestionCatalogRequestEntry, DiscoveryDefinitionCatalogRequestEntry, DiscoveryDefinitionCatalogRequest, DiscoveryDefinitionPlanningFields, CatalogRequestEntry, StructuredDataFiltersV1, ConditionsDataFilters, } from './types/refs.js';
19
20
  export { mergeGraphDocumentModel, EXELLIX_GRAPH_MODEL_VARIABLE_KEY, EXELLIX_STRUCTURED_DATA_FILTERS_V1, } from './types/refs.js';
@@ -71,6 +72,7 @@ export { buildAiTasksRunTaskRequest, extractRunTaskMetadataPassthrough, extractR
71
72
  export type { BuildAiTasksRunTaskRequestArgs, RunTaskMetadataPassthrough, } from './runtime/buildAiTasksRunTaskRequest.js';
72
73
  export { buildTaskNodeJobContext } from './runtime/buildTaskNodeJobContext.js';
73
74
  export { resolveNarrixForTaskNode } from './runtime/resolveNarrixForTaskNode.js';
75
+ export { patchNodePlanMainModelFromWire, patchNodePlanRuntimePipeline, resolveRunTaskNodePlan, } from './runtime/runTaskNodePlan.js';
74
76
  export { runTaskResponseSucceeded } from './runtime/runTaskResponse.js';
75
77
  export { buildTaskNodeRunTaskRequest, validateTaskNodeRunTaskConfig, validateTaskNodeRunTaskInvoke, } from './runtime/taskNodeRunTaskPreflight.js';
76
78
  export type { BuildTaskNodeRunTaskRequestArgs, BuildTaskNodeRunTaskRequestResult, TaskNodeRunTaskPreflightSkipReason, ValidateTaskNodeRunTaskConfigArgs, ValidateTaskNodeRunTaskConfigResult, ValidateTaskNodeRunTaskInvokeArgs, ValidateTaskNodeRunTaskInvokeResult, } from './runtime/taskNodeRunTaskPreflight.js';
@@ -88,7 +90,6 @@ export type { GraphStudioDocument } from './runtime/graphModelStudioSeparation.j
88
90
  export { STUDIO_GRAPH_EXECUTE_REMOVED_KEYS, getStudioGraphExecuteRemovedKeyViolations, assertCanonicalStudioGraphExecuteRequest, buildGraphExecutionRequestFromStudioExecute, } from './runtime/studioGraphExecuteRequest.js';
89
91
  export type { StudioGraphExecuteRemovedKey, StudioGraphExecuteRequest, BuildGraphExecutionRequestFromStudioExecuteOptions, } from './runtime/studioGraphExecuteRequest.js';
90
92
  export { computeGraphDocumentContentSha256, stableStringifyGraphDocument, } from './runtime/graphDocumentFingerprint.js';
91
- export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
92
93
  export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
93
94
  export type { ExecutableGraphPlanV2, NodeExecutionPlan, ExecutionUnitPlanV2, } from '@x12i/graphenix-executable-contracts';
94
95
  export type { AuthoringGraphDocument } from '@x12i/graphenix-executable-contracts';
@@ -118,6 +119,6 @@ export { createPlaygroundReporter } from './playground/index.js';
118
119
  export type { CreatePlaygroundReporterOptions, PlaygroundDebugArtifact, PlaygroundDebugArtifactKind, PlaygroundDebugSnapshot, PlaygroundReporter, PlaygroundStep, } from './playground/PlaygroundReporter.js';
119
120
  export { getNodeScopingQuestion, getNodeMemoryShape, getNodeNarrixDiscovery, fetchNodeScopingData, inspectNode, resolveNodeSkillKey, getGraphNodes, getGraphCatalogs, inspectGraph, collectPredicatePaths, executionMemoryPathTail, executionMemoryTailsMatch, getNodeExecutionMemoryWriteTails, getNodeControlDependencies, getNodeSideEffects, inspectFinalizer, inspectNodeContract, inspectGraphContracts, EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID, EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID, EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY, EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY, getVirtualGraphEntryLayer, getVirtualGraphResponseLayer, materializeVirtualBoundaryDiagram, stripMaterializedVirtualBoundaryDiagram, validateCatalogPlanning, isCatalogBinding, isCatalogRequestEntry, inspectGraphModelSelection, } from './inspection/index.js';
120
121
  export type { GraphModelSelectionInspection, NodeModelSelection, ModelSelectionSource, NodeScopingQuestion, NodeScopeSource, NodeScopeTarget, NodeScopingData, NodeMemoryShape, MemoryPath, NodeNarrixDiscovery, NodeInspection, GraphInspection, NodeIOEdge, GraphCatalogs, CatalogBindingSummary, CatalogPlanningValidationIssue, GraphVirtualIO, GraphVirtualIONode, GraphVirtualIOEdge, GraphVirtualIONodeRole, VirtualGraphEntryLayer, VirtualGraphResponseLayer, MaterializeVirtualBoundaryDiagramOptions, MaterializedVirtualBoundaryDiagram, MaterializedVirtualBoundaryDiagramMeta, InspectNodeContractOptions, LocalSkillKey, NodeExecutionType, FactProvenance, ProvenancedSection, NodeInputBindingEntry, ScopedDataDependency, NodeInputContract, ExecutionMemoryWriteSpec, NodeOutputContract, NodeSideEffects, ControlBranchEntry, NodeControlContract, NodeValidationContract, FinalizerContractInspection, NodeContractInspection, GraphContractsInspection, } from './inspection/index.js';
121
- export type { NarrixPreProcessorConfig, WebScopeQuestion, LocalTaskHandler, LocalTaskContext } from './types/narrix.js';
122
+ export type { NarrixPreProcessorConfig, NarrixModeKey, NarrixRunInput, NarrixScope, ResolvedNarrixWirePayload, LocalTaskHandler, LocalTaskContext, } from './types/narrix.js';
122
123
  export { shutdownMemorixRuntime } from './runtime/localSkills/memorixRuntime.js';
123
124
  export type { ScopedDataReaderConfig, ScopedDataReaderOutput, ScopedDataReaderPackOutput, ScopedAnswerAssemblerConfig, ScopedAnswerAssemblerOutput, ScopedAnswerWriterConfig, ScopedAnswerWriterOutput, } from './runtime/localSkills/index.js';
package/dist/src/index.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * `{ executeGraph({ plan, runtime }: GraphExecutionRequest) }`. Hosts compile upstream via
13
13
  * {@link compileExellixExecutablePlan} or `@x12i/graphenix-plan-compiler`.
14
14
  */
15
+ export { hasWebScopeAuthoring } from './types/aiTaskProfile.js';
15
16
  export { mergeGraphDocumentModel, EXELLIX_GRAPH_MODEL_VARIABLE_KEY, EXELLIX_STRUCTURED_DATA_FILTERS_V1, } from './types/refs.js';
16
17
  export { getTaskConfiguration } from './types/taskNodeConfiguration.js';
17
18
  export { AI_TASKS_RUN_LOG_METADATA_KEY, AI_TASKS_LOGXER_RUN_ID_METADATA_KEY, DEFAULT_MAX_RUN_LOG_ENTRIES, DEFAULT_MAX_RUN_LOG_DATA_JSON_CHARS, } from './types/runLog.js';
@@ -54,6 +55,7 @@ export { assertHostJobId, newGraphRunTaskId } from './runtime/graphRunIdentity.j
54
55
  export { buildAiTasksRunTaskRequest, extractRunTaskMetadataPassthrough, extractRunTaskStrategyOverrides, resolveJobTypeId, resolveTaskTypeId, } from './runtime/buildAiTasksRunTaskRequest.js';
55
56
  export { buildTaskNodeJobContext } from './runtime/buildTaskNodeJobContext.js';
56
57
  export { resolveNarrixForTaskNode } from './runtime/resolveNarrixForTaskNode.js';
58
+ export { patchNodePlanMainModelFromWire, patchNodePlanRuntimePipeline, resolveRunTaskNodePlan, } from './runtime/runTaskNodePlan.js';
57
59
  export { runTaskResponseSucceeded } from './runtime/runTaskResponse.js';
58
60
  export { buildTaskNodeRunTaskRequest, validateTaskNodeRunTaskConfig, validateTaskNodeRunTaskInvoke, } from './runtime/taskNodeRunTaskPreflight.js';
59
61
  /** Re-exported from `@exellix/ai-tasks` — preflight validation without `runTask`. */
@@ -64,7 +66,6 @@ export { assertCanonicalGraphRuntimeObject } from './runtime/validateCanonicalGr
64
66
  export { GRAPH_ENTRY_STUDIO_ONLY_KEYS, GRAPH_METADATA_STUDIO_ONLY_KEYS, stripGraphModelStudioFields, primaryRuntimeInputFromStudioDocument, getGraphEntryStudioOnlyKeyViolations, getGraphMetadataStudioOnlyKeyViolations, } from './runtime/graphModelStudioSeparation.js';
65
67
  export { STUDIO_GRAPH_EXECUTE_REMOVED_KEYS, getStudioGraphExecuteRemovedKeyViolations, assertCanonicalStudioGraphExecuteRequest, buildGraphExecutionRequestFromStudioExecute, } from './runtime/studioGraphExecuteRequest.js';
66
68
  export { computeGraphDocumentContentSha256, stableStringifyGraphDocument, } from './runtime/graphDocumentFingerprint.js';
67
- export { applyAiTaskProfileWebScopingToNarrix, mapAiTaskProfileQuestionsToWebScopeQuestions, } from './runtime/applyAiTaskProfileWebScopingToNarrix.js';
68
69
  // New runtime with injection seam
69
70
  export { createExellixGraphRuntime } from './runtime/ExellixGraphRuntime.js';
70
71
  export { compileExellixExecutablePlan } from './compile/compileExellixExecutablePlan.js';
@@ -1,5 +1,6 @@
1
- import { isLocalSkillKey } from '../runtime/localSkills/index.js';
1
+ import { hasWebScopeAuthoring } from '../types/aiTaskProfile.js';
2
2
  import { readTaskNodeInputsConfig } from '../runtime/readTaskNodeInputsConfig.js';
3
+ import { isLocalSkillKey } from '../runtime/localSkills/index.js';
3
4
  import { getNodeMemoryShape, getNodeNarrixDiscovery, inspectNode, resolveNodeSkillKey, } from './nodeInspection.js';
4
5
  import { getGraphNodes } from './graphInspection.js';
5
6
  import { getNodeControlDependencies } from './controlInspection.js';
@@ -217,9 +218,8 @@ function buildInputContract(node, memoryShape) {
217
218
  ? [
218
219
  {
219
220
  enabled: true,
220
- entityIdPath: narrixDisc.webScope.entityIdPath,
221
- entityTypePath: narrixDisc.webScope.entityTypePath,
222
- questions: narrixDisc.webScope.questions,
221
+ webQueryTemplate: narrixDisc.webScope.webQueryTemplate,
222
+ webQueryTemplates: narrixDisc.webScope.webQueryTemplates,
223
223
  },
224
224
  ]
225
225
  : [];
@@ -292,19 +292,11 @@ function buildOutputContract(node) {
292
292
  }
293
293
  const tc = task.taskConfiguration;
294
294
  const webCfg = tc?.aiTaskProfile;
295
- const webScoping = webCfg?.webScoping;
296
- const narrixCfg = tc?.narrix;
297
295
  const webWrites = [];
298
- if (narrixCfg?.enableWebScope === true) {
299
- webWrites.push({
300
- path: 'webContext',
301
- source: 'taskConfiguration.narrix.enableWebScope → @exellix/ai-tasks (runtime-known)',
302
- });
303
- }
304
- else if (webScoping && webScoping.enabled === true) {
296
+ if (hasWebScopeAuthoring(webCfg)) {
305
297
  webWrites.push({
306
298
  path: 'webContext',
307
- source: 'taskConfiguration.aiTaskProfile.webScopingexecuteNode (runtime-known)',
299
+ source: 'taskConfiguration.aiTaskProfile.webQueryTemplatePRE webScope unit (runtime-known)',
308
300
  });
309
301
  }
310
302
  const synthWrites = [];
@@ -356,8 +348,7 @@ export function getNodeSideEffects(node) {
356
348
  const tc = node.taskConfiguration;
357
349
  runsNarrix = tc?.narrix != null && typeof tc.narrix === 'object';
358
350
  const web = tc?.aiTaskProfile;
359
- const ws = web?.webScoping;
360
- runsLocalWebScope = ws?.enabled === true;
351
+ runsLocalWebScope = hasWebScopeAuthoring(web);
361
352
  const inputSynth = web?.inputSynthesis;
362
353
  runsPreSynthesis = inputSynth?.enabled === true;
363
354
  }
@@ -1,5 +1,6 @@
1
1
  import { getGraphNodes } from './graphInspection.js';
2
2
  import { getNodeNarrixDiscovery } from './nodeInspection.js';
3
+ import { hasWebScopeAuthoring } from '../types/aiTaskProfile.js';
3
4
  /**
4
5
  * Recursively collects leaf `path` strings from a graph edge predicate.
5
6
  */
@@ -64,8 +65,7 @@ export function getNodeExecutionMemoryWriteTails(node) {
64
65
  }
65
66
  const tc = task.taskConfiguration;
66
67
  const profile = tc?.aiTaskProfile;
67
- const ws = profile?.webScoping;
68
- if (ws?.enabled === true) {
68
+ if (hasWebScopeAuthoring(profile)) {
69
69
  tails.add('webContext');
70
70
  }
71
71
  const inputSynth = profile?.inputSynthesis;
@@ -1,4 +1,4 @@
1
- import { mapAiTaskProfileQuestionsToWebScopeQuestions } from '../runtime/applyAiTaskProfileWebScopingToNarrix.js';
1
+ import { hasWebScopeAuthoring } from '../types/aiTaskProfile.js';
2
2
  import { readTaskNodeInputsConfig } from '../runtime/readTaskNodeInputsConfig.js';
3
3
  import { runScopedDataReader } from '../runtime/localSkills/scopedDataReader.js';
4
4
  // ---------------------------------------------------------------------------
@@ -364,8 +364,8 @@ export function getNodeNarrixDiscovery(node) {
364
364
  if (!narrix || typeof narrix !== 'object')
365
365
  return null;
366
366
  const n = narrix;
367
- const web = task.taskConfiguration?.aiTaskProfile?.webScoping;
368
- const enableWebScope = n.enableWebScope === true || web?.enabled === true;
367
+ const profile = task.taskConfiguration?.aiTaskProfile;
368
+ const enableWebScope = hasWebScopeAuthoring(profile);
369
369
  return {
370
370
  nodeId: node.id,
371
371
  enabled: true,
@@ -374,13 +374,12 @@ export function getNodeNarrixDiscovery(node) {
374
374
  narrativeTypeIds: Array.isArray(n.narrativeTypeIds) ? n.narrativeTypeIds : undefined,
375
375
  webScope: {
376
376
  enabled: enableWebScope,
377
- forced: undefined,
378
- questions: Array.isArray(web?.questions) && web.questions.length > 0
379
- ? mapAiTaskProfileQuestionsToWebScopeQuestions(web.questions)
380
- : undefined,
381
- entityIdPath: undefined,
382
- entityTypePath: undefined,
383
- enrichFromRaw: undefined,
377
+ ...(typeof profile?.webQueryTemplate === 'string'
378
+ ? { webQueryTemplate: profile.webQueryTemplate }
379
+ : {}),
380
+ ...(Array.isArray(profile?.webQueryTemplates) && profile.webQueryTemplates.length > 0
381
+ ? { webQueryTemplates: profile.webQueryTemplates }
382
+ : {}),
384
383
  },
385
384
  outputPaths: {
386
385
  signals: 'executionMemory._narrix.scoping.signals',
@@ -1,8 +1,7 @@
1
1
  import type { CatalogBinding, CatalogRequestEntry, GraphDocumentMetadata, GraphEdge, GraphNode, GraphPredicate, GraphReadabilityKind } from '../types/refs.js';
2
- import type { WebScopeQuestion } from '../types/narrix.js';
3
2
  import type { ScopedDataReaderOutput, ScopedDataReaderPackOutput } from '../runtime/localSkills/scopedDataReader.js';
4
3
  import type { LocalSkillKey } from '../runtime/localSkills/index.js';
5
- export type { GraphEdge, GraphPredicate, GraphReadabilityKind, WebScopeQuestion, LocalSkillKey };
4
+ export type { GraphEdge, GraphPredicate, GraphReadabilityKind, LocalSkillKey };
6
5
  export type { ScopedDataReaderOutput, ScopedDataReaderPackOutput };
7
6
  /**
8
7
  * The scoping question for a single node: what it asks, where it reads its data from,
@@ -98,18 +97,10 @@ export type NodeNarrixDiscovery = {
98
97
  /** Narrative type ids the engine focuses discovery on. */
99
98
  narrativeTypeIds?: string[];
100
99
  webScope: {
101
- /** Whether web scoping is enabled. */
100
+ /** Whether a webQueryTemplate (or pack) is authored on aiTaskProfile. */
102
101
  enabled: boolean;
103
- /** When true, skips DB short-circuit and always fetches from web. */
104
- forced?: boolean;
105
- /** Web scope questions with stable ids and purposes. */
106
- questions?: WebScopeQuestion[];
107
- /** Dot-path to entity id in execution memory for web scope. */
108
- entityIdPath?: string;
109
- /** Dot-path to entity type in execution memory for web scope. */
110
- entityTypePath?: string;
111
- /** Whether CVE/vendor/product tokens are appended to the web-scope question from raw input. */
112
- enrichFromRaw?: boolean;
102
+ webQueryTemplate?: string;
103
+ webQueryTemplates?: string[];
113
104
  };
114
105
  /** Fixed execution-memory paths where narrix writes its output. */
115
106
  outputPaths: {
@@ -26,7 +26,7 @@ import { buildRunLog, extractLogxerCorrelationFromMetadata, extractTaskRunLogFro
26
26
  import { setRuntimeObjectsLastJobId, summarizeRuntimeObjectsForPlayground } from "./runtimeObjects.js";
27
27
  import { DebugLogAbstract, bindGraphEngineRunLogxer, clearGraphEngineRunLogxer, createGraphEngineLogxer, ensureGraphEngineLogxerOnRuntimeObjects, logGraphEngineErrorCode, patchGraphNodeLogContext, runGraphWithLogContext, traceExecutionMemory, } from "./graphEngineLogxer.js";
28
28
  import { runWithAiTasksStackLogging } from "@exellix/ai-tasks";
29
- import { nodePlanFromFinalizerPlan, patchNodePlanMainModelFromWire, resolveRunTaskNodePlan, } from "./runTaskNodePlan.js";
29
+ import { nodePlanFromFinalizerPlan, patchNodePlanMainModelFromWire, patchNodePlanRuntimePipeline, resolveRunTaskNodePlan, } from "./runTaskNodePlan.js";
30
30
  import { assertHostJobId, newGraphRunTaskId } from "./graphRunIdentity.js";
31
31
  import { resolveTaskKey } from "./resolveTaskKey.js";
32
32
  import { buildPredicateEvalContextForNode, readExecutionVariableBuckets, seedGraphVariableBucketsFromRuntime, } from "./variables.js";
@@ -675,7 +675,6 @@ export function createExellixGraphRuntime(opts) {
675
675
  ? { ...input.node.taskConfiguration.narrix }
676
676
  : undefined,
677
677
  graphVariablesNarrix: jobVariables?.narrix,
678
- aiTaskProfile: input.node?.taskConfiguration?.aiTaskProfile,
679
678
  });
680
679
  const metaTk = input.node?.taskConfiguration?.taskKind;
681
680
  const taskKindForward = metaTk === "decision" || metaTk === "utility" || metaTk === "content" ? metaTk : undefined;
@@ -689,6 +688,11 @@ export function createExellixGraphRuntime(opts) {
689
688
  if (!input.nodePlan && input.requireCompiledNodePlan !== true) {
690
689
  runTaskNodePlan = patchNodePlanMainModelFromWire(runTaskNodePlan, wireModelConfig);
691
690
  }
691
+ runTaskNodePlan = patchNodePlanRuntimePipeline({
692
+ plan: runTaskNodePlan,
693
+ resolvedNarrix: narrix ?? undefined,
694
+ taskConfiguration: input.node?.taskConfiguration,
695
+ });
692
696
  const startedAt = Date.now();
693
697
  const hasSynthesizedContextPreStep = runTaskNodePlan.executionUnits.some((u) => u.unitKind === "externalPreUtility" || u.unitKind === "pipelinePhase");
694
698
  const hasExistingSynthesizedContext = execution != null &&
@@ -791,7 +795,6 @@ export function createExellixGraphRuntime(opts) {
791
795
  executionMemory: executionMemoryForWire,
792
796
  jobContext,
793
797
  prevNodeId: input.prevNodeId,
794
- narrix: narrix ?? undefined,
795
798
  ...extractRunTaskStrategyOverrides(input.node?.taskConfiguration),
796
799
  outputValidation: outputValidationFromPlan ??
797
800
  (input.node?.taskConfiguration?.aiTasksOutputValidation != null &&
@@ -11,13 +11,12 @@ import type { RunTaskRequest } from '@exellix/ai-tasks';
11
11
  import type { GraphExecutionTraceV2, NodeExecutionPlan } from '@x12i/graphenix-executable-contracts';
12
12
  import type { SmartInputConfig, XynthesizedMemory } from '../types/aiTasksDerivedTypes.js';
13
13
  import type { Job } from '../types/refs.js';
14
- import type { ResolvedNarrixWirePayload } from '../types/narrix.js';
15
14
  /** Request/metadata keys that must never carry provider API secrets (env-only). */
16
15
  export declare const FORBIDDEN_RUN_TASK_SECRET_KEYS: readonly ["openrouterApiKey", "OPENROUTER_API_KEY", "OPEN_ROUTER_KEY", "apiKey", "api_key", "openRouterApiKey"];
17
- /** Reads task-node `taskConfiguration` keys forwarded to `@exellix/ai-tasks` `RunTaskRequest` (runtime strategy / Narrix wiring). */
18
- export declare function extractRunTaskStrategyOverrides(taskConfiguration: Record<string, unknown> | undefined | null): Partial<Pick<BuildAiTasksRunTaskRequestArgs, 'narrixMode' | 'inputStrategyKey' | 'narrixInput'>>;
16
+ /** Reads task-node `taskConfiguration.inputStrategyKey` for `@exellix/ai-tasks` `RunTaskRequest`. */
17
+ export declare function extractRunTaskStrategyOverrides(taskConfiguration: Record<string, unknown> | undefined | null): Partial<Pick<BuildAiTasksRunTaskRequestArgs, 'inputStrategyKey'>>;
19
18
  /** Optional `RunTaskRequest` fields commonly authored on task-node `taskConfiguration` (whitelist — closed merge order). */
20
- export type RunTaskMetadataPassthrough = Partial<Pick<RunTaskRequest, 'narrixScope' | 'aiScoping' | 'aiScopingOptions' | 'timeoutMs' | 'templateRenderOptions' | 'smartInputRenderOptions' | 'templateTokens' | 'aiEngineId' | 'sessionId' | 'agentType' | 'gatewayDiagnostics' | 'context' | 'knowledge' | 'executionStrategyCatalogItems'>>;
19
+ export type RunTaskMetadataPassthrough = Partial<Pick<RunTaskRequest, 'aiScoping' | 'aiScopingOptions' | 'timeoutMs' | 'templateRenderOptions' | 'smartInputRenderOptions' | 'templateTokens' | 'aiEngineId' | 'sessionId' | 'agentType' | 'gatewayDiagnostics' | 'context' | 'knowledge' | 'executionStrategyCatalogItems'>>;
21
20
  /**
22
21
  * Whitelisted optional transport fields from task-node `taskConfiguration` for `@exellix/ai-tasks` ≥ 7.2.x
23
22
  * (`RunSkillRequest` / `RunTaskRequest` extras not covered by {@link extractRunTaskStrategyOverrides}).
@@ -42,7 +41,6 @@ export type BuildAiTasksRunTaskRequestArgs = {
42
41
  executionMemory?: Record<string, unknown>;
43
42
  jobContext?: Record<string, unknown>;
44
43
  prevNodeId?: string;
45
- narrix?: ResolvedNarrixWirePayload;
46
44
  outputValidation?: RunTaskRequest['outputValidation'];
47
45
  diagnostics?: RunTaskRequest['diagnostics'];
48
46
  identity?: Record<string, unknown>;
@@ -51,10 +49,7 @@ export type BuildAiTasksRunTaskRequestArgs = {
51
49
  autoValidateDecisionOutput?: boolean;
52
50
  /** Overrides default `resolveTaskTypeId(skillKey, nodeId, taskConfiguration)` e.g. engine strategy phases. */
53
51
  taskTypeIdOverride?: string;
54
- /** Usually from `taskConfiguration.narrixMode` via {@link extractRunTaskStrategyOverrides}. */
55
- narrixMode?: RunTaskRequest['narrixMode'];
56
52
  inputStrategyKey?: RunTaskRequest['inputStrategyKey'];
57
- narrixInput?: RunTaskRequest['narrixInput'];
58
53
  /** Required on every request for ai-tasks ≥ 7.1.x — use `[]` for plain MAIN. */
59
54
  executionStrategies?: RunTaskRequest['executionStrategies'];
60
55
  xynthesized?: XynthesizedMemory;
@@ -18,25 +18,17 @@ function assertNoSecretPassthrough(taskConfiguration, context) {
18
18
  }
19
19
  }
20
20
  }
21
- /** Reads task-node `taskConfiguration` keys forwarded to `@exellix/ai-tasks` `RunTaskRequest` (runtime strategy / Narrix wiring). */
21
+ /** Reads task-node `taskConfiguration.inputStrategyKey` for `@exellix/ai-tasks` `RunTaskRequest`. */
22
22
  export function extractRunTaskStrategyOverrides(taskConfiguration) {
23
23
  assertNoSecretPassthrough(taskConfiguration, 'extractRunTaskStrategyOverrides');
24
24
  if (taskConfiguration == null || typeof taskConfiguration !== 'object' || Array.isArray(taskConfiguration))
25
25
  return {};
26
26
  const m = taskConfiguration;
27
27
  const out = {};
28
- const narrixMode = m.narrixMode;
29
- if (typeof narrixMode === 'string' && narrixMode.trim() !== '') {
30
- out.narrixMode = narrixMode.trim();
31
- }
32
28
  const inputStrategyKey = m.inputStrategyKey;
33
29
  if (typeof inputStrategyKey === 'string' && inputStrategyKey.trim() !== '') {
34
30
  out.inputStrategyKey = inputStrategyKey.trim();
35
31
  }
36
- const narrixInput = m.narrixInput;
37
- if (narrixInput != null && typeof narrixInput === 'object' && !Array.isArray(narrixInput)) {
38
- out.narrixInput = narrixInput;
39
- }
40
32
  return out;
41
33
  }
42
34
  /**
@@ -49,10 +41,6 @@ export function extractRunTaskMetadataPassthrough(taskConfiguration) {
49
41
  return {};
50
42
  const m = taskConfiguration;
51
43
  const out = {};
52
- const narrixScope = m.narrixScope;
53
- if (narrixScope != null && typeof narrixScope === 'object' && !Array.isArray(narrixScope)) {
54
- out.narrixScope = narrixScope;
55
- }
56
44
  const aiScoping = m.aiScoping;
57
45
  if (Array.isArray(aiScoping)) {
58
46
  out.aiScoping = aiScoping;
@@ -162,16 +150,13 @@ export function buildAiTasksRunTaskRequest(args) {
162
150
  ...(args.executionMemory != null ? { executionMemory: args.executionMemory } : {}),
163
151
  ...(args.jobContext != null ? { jobContext: args.jobContext } : {}),
164
152
  ...(args.prevNodeId != null && args.prevNodeId !== '' ? { prevNodeId: args.prevNodeId } : {}),
165
- ...(args.narrix != null ? { narrix: args.narrix } : {}),
166
153
  ...(args.outputValidation != null ? { outputValidation: args.outputValidation } : {}),
167
154
  ...(args.diagnostics != null ? { diagnostics: args.diagnostics } : {}),
168
155
  ...(args.identity != null ? { identity: args.identity } : {}),
169
156
  ...(args.executionMode != null ? { executionMode: args.executionMode } : {}),
170
157
  ...(args.taskKind != null ? { taskKind: args.taskKind } : {}),
171
158
  ...(args.autoValidateDecisionOutput !== undefined ? { autoValidateDecisionOutput: args.autoValidateDecisionOutput } : {}),
172
- ...(args.narrixMode != null ? { narrixMode: args.narrixMode } : {}),
173
159
  ...(args.inputStrategyKey != null ? { inputStrategyKey: args.inputStrategyKey } : {}),
174
- ...(args.narrixInput != null ? { narrixInput: args.narrixInput } : {}),
175
160
  executionStrategies,
176
161
  ...(args.xynthesized != null ? { xynthesized: args.xynthesized } : {}),
177
162
  ...(smartInputForward != null ? { smartInput: smartInputForward } : {}),
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Builds the `RunTaskRequest.taskConfiguration` blob for `@exellix/ai-tasks` ≥ 7.7 compile-at-invoke.
3
- * Root-level fields already lifted by graph-engine are omitted; compile-only authoring (e.g.
4
- * `aiTaskStrategies`, `aiTaskProfile`) remains on the blob.
2
+ * Builds the `RunTaskRequest.taskConfiguration` blob for legacy compile-at-invoke (no `nodePlan`).
3
+ * With graphenix node plans, narrix / narrixMode / narrixInput / narrixScope live on
4
+ * `nodePlan.invokeContract.pipeline` instead see {@link patchNodePlanRuntimePipeline}.
5
5
  */
6
6
  /**
7
7
  * Subset of node `taskConfiguration` forwarded on `RunTaskRequest.taskConfiguration` for ai-tasks compile.
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Builds the `RunTaskRequest.taskConfiguration` blob for `@exellix/ai-tasks` ≥ 7.7 compile-at-invoke.
3
- * Root-level fields already lifted by graph-engine are omitted; compile-only authoring (e.g.
4
- * `aiTaskStrategies`, `aiTaskProfile`) remains on the blob.
2
+ * Builds the `RunTaskRequest.taskConfiguration` blob for legacy compile-at-invoke (no `nodePlan`).
3
+ * With graphenix node plans, narrix / narrixMode / narrixInput / narrixScope live on
4
+ * `nodePlan.invokeContract.pipeline` instead see {@link patchNodePlanRuntimePipeline}.
5
5
  */
6
6
  const RUN_TASK_LIFTED_TASK_CONFIGURATION_KEYS = new Set([
7
7
  'taskTypeId',
@@ -10,10 +10,6 @@ const RUN_TASK_LIFTED_TASK_CONFIGURATION_KEYS = new Set([
10
10
  'modelConfig',
11
11
  'llmCall',
12
12
  'timeoutMs',
13
- 'narrix',
14
- 'narrixMode',
15
- 'narrixInput',
16
- 'narrixScope',
17
13
  'inputStrategyKey',
18
14
  'aiTasksOutputValidation',
19
15
  'taskKind',
@@ -1,14 +1,10 @@
1
1
  import type { NarrixPreProcessorConfig, ResolvedNarrixWirePayload } from '../types/narrix.js';
2
- import type { AiTaskProfileMetadata } from '../types/aiTaskProfile.js';
3
2
  /**
4
- * Resolves outbound `RunTaskRequest.narrix`: starts from node `taskConfiguration.narrix`,
5
- * shallow-merges graph-level `variables.narrix`, then applies `enableWebScope` / `webScopeQuestions`
6
- * via {@link applyAiTaskProfileWebScopingToNarrix}.
7
- *
8
- * Shared by {@link ExellixGraphRuntime}.
3
+ * Resolves discovery narrix for runtime plan patching: shallow-merge of node `taskConfiguration.narrix`
4
+ * with graph-level `variables.narrix`. Web scope is a PRE `webScope` unit compiled from
5
+ * `taskConfiguration.aiTaskProfile.webQueryTemplate` (Graphenix 2.7.x+).
9
6
  */
10
7
  export declare function resolveNarrixForTaskNode(args: {
11
8
  nodeMetadataNarrix: NarrixPreProcessorConfig | undefined;
12
9
  graphVariablesNarrix: Partial<NarrixPreProcessorConfig> | undefined;
13
- aiTaskProfile: AiTaskProfileMetadata | undefined;
14
10
  }): ResolvedNarrixWirePayload | undefined;
@@ -1,10 +1,7 @@
1
- import { applyAiTaskProfileWebScopingToNarrix } from './applyAiTaskProfileWebScopingToNarrix.js';
2
1
  /**
3
- * Resolves outbound `RunTaskRequest.narrix`: starts from node `taskConfiguration.narrix`,
4
- * shallow-merges graph-level `variables.narrix`, then applies `enableWebScope` / `webScopeQuestions`
5
- * via {@link applyAiTaskProfileWebScopingToNarrix}.
6
- *
7
- * Shared by {@link ExellixGraphRuntime}.
2
+ * Resolves discovery narrix for runtime plan patching: shallow-merge of node `taskConfiguration.narrix`
3
+ * with graph-level `variables.narrix`. Web scope is a PRE `webScope` unit compiled from
4
+ * `taskConfiguration.aiTaskProfile.webQueryTemplate` (Graphenix 2.7.x+).
8
5
  */
9
6
  export function resolveNarrixForTaskNode(args) {
10
7
  let resolved = args.nodeMetadataNarrix != null ? { ...args.nodeMetadataNarrix } : undefined;
@@ -15,5 +12,5 @@ export function resolveNarrixForTaskNode(args) {
15
12
  ...(resolved ?? {}),
16
13
  };
17
14
  }
18
- return applyAiTaskProfileWebScopingToNarrix(resolved, args.aiTaskProfile);
15
+ return resolved;
19
16
  }
@@ -1,4 +1,5 @@
1
1
  import type { FinalizerExecutionPlan, NodeExecutionPlan } from '@x12i/graphenix-executable-contracts';
2
+ import type { NarrixPreProcessorConfig } from '../types/narrix.js';
2
3
  import type { RunTaskModelConfigWire } from './graphAiModelConfig.js';
3
4
  /** Resolve the frozen node plan required by `@exellix/ai-tasks` ≥ 9. */
4
5
  export declare function resolveRunTaskNodePlan(args: {
@@ -10,6 +11,15 @@ export declare function resolveRunTaskNodePlan(args: {
10
11
  }): NodeExecutionPlan;
11
12
  /** Standalone {@link executeNode} without compile: patch MAIN unit selection from resolved graph profiles. */
12
13
  export declare function patchNodePlanMainModelFromWire(plan: NodeExecutionPlan, wire: RunTaskModelConfigWire): NodeExecutionPlan;
14
+ /**
15
+ * Patches graphenix node-plan invoke pipeline with runtime narrix resolution (graph `variables.narrix`
16
+ * merge) and optional `taskConfiguration` narrixScope / mode / input when absent from compile.
17
+ */
18
+ export declare function patchNodePlanRuntimePipeline(args: {
19
+ plan: NodeExecutionPlan;
20
+ resolvedNarrix?: NarrixPreProcessorConfig;
21
+ taskConfiguration?: Record<string, unknown>;
22
+ }): NodeExecutionPlan;
13
23
  export declare function nodePlanFromFinalizerPlan(args: {
14
24
  finalizerId: string;
15
25
  utilityKey: string;
@@ -1,4 +1,7 @@
1
1
  import { minimalNodePlanForSkillKey } from '@exellix/ai-tasks';
2
+ function isPlainRecord(v) {
3
+ return v != null && typeof v === 'object' && !Array.isArray(v);
4
+ }
2
5
  function mainSkillUnit(plan) {
3
6
  return plan.executionUnits.find((u) => u.unitKind === 'mainSkill');
4
7
  }
@@ -7,6 +10,102 @@ function selectionFromWireSlot(value) {
7
10
  return undefined;
8
11
  return { kind: 'profileChoice', key: value.trim() };
9
12
  }
13
+ function resolveNarrativeMode(pipeline, tc) {
14
+ const explicit = pipeline.narrixMode ?? tc?.narrixMode;
15
+ if (explicit === 'preprocessor' || explicit === 'handler')
16
+ return explicit;
17
+ if (explicit === 'off')
18
+ return 'off';
19
+ if (pipeline.narrixInput != null || tc?.narrixInput != null)
20
+ return 'handler';
21
+ if (pipeline.narrix != null || tc?.narrix != null)
22
+ return 'preprocessor';
23
+ return 'off';
24
+ }
25
+ function planHasNarrativeUnit(plan) {
26
+ return plan.executionUnits.some((u) => u.unitKind === 'narrativePreprocessor' || u.unitKind === 'narrativeHandler');
27
+ }
28
+ function defaultPreActionSelection(plan) {
29
+ const preUtility = plan.executionUnits.find((u) => u.unitKind === 'externalPreUtility');
30
+ if (preUtility?.modelSelection) {
31
+ return { selection: preUtility.modelSelection, source: preUtility.modelSource ?? 'graphDefault' };
32
+ }
33
+ return {
34
+ selection: { kind: 'profileChoice', key: 'cheap/default' },
35
+ source: 'graphDefault',
36
+ };
37
+ }
38
+ /** Standalone executeNode path: mirror Graphenix `buildNarrativeUnits` when plan was not compiled. */
39
+ function injectRuntimeNarrativeUnitsIfAbsent(plan, pipeline, taskConfiguration) {
40
+ if (planHasNarrativeUnit(plan))
41
+ return plan;
42
+ const mode = resolveNarrativeMode(pipeline, taskConfiguration);
43
+ if (mode === 'off')
44
+ return plan;
45
+ const narrix = isPlainRecord(pipeline.narrix) ? pipeline.narrix : {};
46
+ const narrixInput = isPlainRecord(pipeline.narrixInput) ? pipeline.narrixInput : {};
47
+ const attachToField = (typeof narrix.attachToField === 'string' && narrix.attachToField) ||
48
+ (typeof narrixInput.attachToField === 'string' && narrixInput.attachToField) ||
49
+ undefined;
50
+ const narrativeWriteKey = attachToField ?? 'executionMemory._narrative';
51
+ const datasetId = (typeof narrix.datasetId === 'string' && narrix.datasetId) ||
52
+ (typeof narrixInput.datasetId === 'string' && narrixInput.datasetId) ||
53
+ undefined;
54
+ const preModel = defaultPreActionSelection(plan);
55
+ const nodeId = plan.nodeId;
56
+ const narrativeContract = {
57
+ reads: ['input'],
58
+ writes: [
59
+ {
60
+ destination: 'execution',
61
+ key: narrativeWriteKey,
62
+ mode: 'merge',
63
+ },
64
+ ],
65
+ };
66
+ const bumpedUnits = plan.executionUnits.map((u) => ({
67
+ ...u,
68
+ order: u.order + 1,
69
+ }));
70
+ let narrativeUnit;
71
+ if (mode === 'preprocessor') {
72
+ narrativeUnit = {
73
+ unitId: `unit:${nodeId}:narrative:pre`,
74
+ nodeId,
75
+ unitKind: 'narrativePreprocessor',
76
+ invokeMode: 'narrativePreprocessor',
77
+ order: 0,
78
+ strategyKey: 'narrative-preprocessor',
79
+ modelSlot: 'preActionModel',
80
+ modelSelection: preModel.selection,
81
+ modelSource: preModel.source,
82
+ unitParams: { datasetId, attachToField },
83
+ invokeContract: narrativeContract,
84
+ sourcePath: '/runtime/narrativePreprocessor',
85
+ };
86
+ }
87
+ else {
88
+ narrativeUnit = {
89
+ unitId: `unit:${nodeId}:narrative:handler`,
90
+ nodeId,
91
+ unitKind: 'narrativeHandler',
92
+ invokeMode: 'narrativeHandler',
93
+ order: 0,
94
+ strategyKey: 'narrative-handler',
95
+ modelSlot: 'preActionModel',
96
+ modelSelection: preModel.selection,
97
+ modelSource: preModel.source,
98
+ terminal: true,
99
+ unitParams: { datasetId, attachToField, narrixInput },
100
+ invokeContract: narrativeContract,
101
+ sourcePath: '/runtime/narrativeHandler',
102
+ };
103
+ }
104
+ return {
105
+ ...plan,
106
+ executionUnits: [narrativeUnit, ...bumpedUnits],
107
+ };
108
+ }
10
109
  /** Resolve the frozen node plan required by `@exellix/ai-tasks` ≥ 9. */
11
110
  export function resolveRunTaskNodePlan(args) {
12
111
  if (args.nodePlan)
@@ -27,6 +126,39 @@ export function patchNodePlanMainModelFromWire(plan, wire) {
27
126
  }
28
127
  return next;
29
128
  }
129
+ /**
130
+ * Patches graphenix node-plan invoke pipeline with runtime narrix resolution (graph `variables.narrix`
131
+ * merge) and optional `taskConfiguration` narrixScope / mode / input when absent from compile.
132
+ */
133
+ export function patchNodePlanRuntimePipeline(args) {
134
+ const tc = args.taskConfiguration;
135
+ const narrixScope = tc?.narrixScope;
136
+ const narrixMode = tc?.narrixMode;
137
+ const narrixInput = tc?.narrixInput;
138
+ const hasPatch = args.resolvedNarrix != null ||
139
+ (narrixScope != null && typeof narrixScope === 'object' && !Array.isArray(narrixScope)) ||
140
+ (typeof narrixMode === 'string' && narrixMode.trim() !== '') ||
141
+ narrixInput != null;
142
+ if (!hasPatch)
143
+ return args.plan;
144
+ const next = structuredClone(args.plan);
145
+ const ic = next.invokeContract ?? {};
146
+ const pipeline = { ...(isPlainRecord(ic.pipeline) ? ic.pipeline : {}) };
147
+ if (args.resolvedNarrix != null) {
148
+ pipeline.narrix = { ...args.resolvedNarrix };
149
+ }
150
+ if (narrixScope != null && typeof narrixScope === 'object' && !Array.isArray(narrixScope)) {
151
+ pipeline.narrixScope = narrixScope;
152
+ }
153
+ if (pipeline.narrixMode === undefined && typeof narrixMode === 'string' && narrixMode.trim() !== '') {
154
+ pipeline.narrixMode = narrixMode.trim();
155
+ }
156
+ if (pipeline.narrixInput === undefined && narrixInput != null) {
157
+ pipeline.narrixInput = narrixInput;
158
+ }
159
+ next.invokeContract = { ...ic, pipeline };
160
+ return injectRuntimeNarrativeUnitsIfAbsent(next, pipeline, tc);
161
+ }
30
162
  export function nodePlanFromFinalizerPlan(args) {
31
163
  const slots = args.finalizerPlan?.modelSlots;
32
164
  const plan = minimalNodePlanForSkillKey(args.utilityKey, args.finalizerId);
@@ -12,7 +12,7 @@ import { resolveNarrixForTaskNode } from './resolveNarrixForTaskNode.js';
12
12
  import { buildRunTaskIdentityEnvelope, shouldForwardRunTaskTraceMode, } from './runTaskAugments.js';
13
13
  import { readExecutionVariableBuckets } from './executionVariableBuckets.js';
14
14
  import { newGraphRunTaskId } from './graphRunIdentity.js';
15
- import { patchNodePlanMainModelFromWire, resolveRunTaskNodePlan } from './runTaskNodePlan.js';
15
+ import { patchNodePlanMainModelFromWire, patchNodePlanRuntimePipeline, resolveRunTaskNodePlan } from './runTaskNodePlan.js';
16
16
  function isPlainRecord(v) {
17
17
  return v != null && typeof v === 'object' && !Array.isArray(v);
18
18
  }
@@ -81,7 +81,11 @@ export async function buildTaskNodeRunTaskRequest(args) {
81
81
  ? { ...node.taskConfiguration.narrix }
82
82
  : undefined,
83
83
  graphVariablesNarrix: jobVariables?.narrix,
84
- aiTaskProfile: node.taskConfiguration?.aiTaskProfile,
84
+ });
85
+ runTaskNodePlan = patchNodePlanRuntimePipeline({
86
+ plan: runTaskNodePlan,
87
+ resolvedNarrix: narrix ?? undefined,
88
+ taskConfiguration: node.taskConfiguration,
85
89
  });
86
90
  const metaTk = node.taskConfiguration?.taskKind;
87
91
  const taskKindForward = metaTk === 'decision' || metaTk === 'utility' || metaTk === 'content' ? metaTk : undefined;
@@ -141,7 +145,6 @@ export async function buildTaskNodeRunTaskRequest(args) {
141
145
  executionMemory: executionMemoryForWire,
142
146
  jobContext,
143
147
  prevNodeId: args.prevNodeId,
144
- narrix: narrix ?? undefined,
145
148
  ...extractRunTaskStrategyOverrides(node.taskConfiguration),
146
149
  outputValidation: outputValidationFromPlan ??
147
150
  (ov != null && typeof ov === 'object' && !Array.isArray(ov) && 'schema' in ov
@@ -98,8 +98,9 @@ const LEGACY_METADATA_TO_TASK_CONFIGURATION = {
98
98
  executionMemory: 'runtime.executionMemory',
99
99
  outputsMemory: 'runtime.outputsMemory',
100
100
  };
101
- /** Web-scope keys are not allowed under `taskConfiguration.narrix` except `enableWebScope` (use `taskConfiguration.aiTaskProfile.webScoping` for questions). */
101
+ /** Web-scope keys are not allowed under `taskConfiguration.narrix` (use `taskConfiguration.aiTaskProfile.webQueryTemplate`). */
102
102
  const FORBIDDEN_NARRIX_WEB_KEYS = [
103
+ 'enableWebScope',
103
104
  'forceWebScope',
104
105
  'webScopeQuestions',
105
106
  'webScoping',
@@ -550,18 +551,16 @@ export function assertCanonicalTaskNode(node, context, options) {
550
551
  }
551
552
  const narrixTc = tc && isPlainObject(tc.narrix) ? tc.narrix : undefined;
552
553
  if (narrixTc) {
553
- if ('enableWebScope' in narrixTc &&
554
- narrixTc.enableWebScope != null &&
555
- typeof narrixTc.enableWebScope !== 'boolean') {
556
- throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_TASK_NODE, `Task node "${String(node.id)}": taskConfiguration.narrix.enableWebScope must be a boolean when present.`, { jobId: context?.jobId, graphId: context?.graphId, nodeId: String(node.id), narrixWebKey: 'enableWebScope' });
557
- }
558
554
  for (const k of FORBIDDEN_NARRIX_WEB_KEYS) {
559
555
  if (k in narrixTc) {
560
- throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_TASK_NODE, `Task node "${String(node.id)}": taskConfiguration.narrix.${k} is forbidden — author web scope under taskConfiguration.aiTaskProfile.webScoping.`, { jobId: context?.jobId, graphId: context?.graphId, nodeId: String(node.id), narrixWebKey: k });
556
+ throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_TASK_NODE, `Task node "${String(node.id)}": taskConfiguration.narrix.${k} is forbidden — author web scope under taskConfiguration.aiTaskProfile.webQueryTemplate.`, { jobId: context?.jobId, graphId: context?.graphId, nodeId: String(node.id), narrixWebKey: k });
561
557
  }
562
558
  }
563
559
  }
564
560
  const profile = tc && isPlainObject(tc.aiTaskProfile) ? tc.aiTaskProfile : undefined;
561
+ if (profile && 'webScoping' in profile && profile.webScoping != null) {
562
+ throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_TASK_NODE, `Task node "${String(node.id)}": taskConfiguration.aiTaskProfile.webScoping is not allowed — use webQueryTemplate (Rendrix string).`, { jobId: context?.jobId, graphId: context?.graphId, nodeId: String(node.id) });
563
+ }
565
564
  const inputSynthesis = profile && isPlainObject(profile.inputSynthesis) ? profile.inputSynthesis : undefined;
566
565
  if (inputSynthesis && 'alsoWriteLegacySynthesizedContext' in inputSynthesis) {
567
566
  throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_TASK_NODE, `Task node "${String(node.id)}": taskConfiguration.aiTaskProfile.inputSynthesis.alsoWriteLegacySynthesizedContext is removed in 5.x.`, { jobId: context?.jobId, graphId: context?.graphId, nodeId: String(node.id) });
@@ -1,13 +1,7 @@
1
1
  /**
2
2
  * Optional task metadata aligned with `@x12i/graph-composer` authoring / `reportTaskNodeProtocolGaps`.
3
- * Exellix-graph-engine merges {@link AiTaskProfileMetadata.webScoping} into `taskConfiguration.narrix` for execution
4
- * when `enabled: true` and `questions` is non-empty (see `applyAiTaskProfileWebScopingToNarrix`).
3
+ * Web scope is authored via {@link AiTaskProfileMetadata.webQueryTemplate} (Graphenix 2.7.3+ PRE `webScope` unit).
5
4
  */
6
- export type AiTaskProfileWebScoping = {
7
- enabled: boolean;
8
- /** When `enabled` is `true`, must be a non-empty array of non-empty strings (graph-composer contract). */
9
- questions?: string[];
10
- };
11
5
  export type AiTaskProfileInputSynthesis = {
12
6
  enabled: boolean;
13
7
  /** Memory paths fed to PRE `synthesized-context` when `enabled` (validated against graph-engine allowlist). */
@@ -23,19 +17,20 @@ export type AiTaskProfileInputSynthesis = {
23
17
  strategyKey?: string;
24
18
  };
25
19
  /**
26
- * PRE/POST strategies, optional web scoping, optional input synthesis for AI task nodes.
20
+ * PRE/POST strategies, optional web query template, optional input synthesis for AI task nodes.
27
21
  * `@x12i/graph-composer` requires `preStrategyKey` / `postStrategyKey` for validated AI nodes.
28
- * Exellix-graph-engine merges `webScoping` into the resolved narrix payload for execution when active.
29
- *
30
- * **Runtime (graph-engine ≥5):** When `preStrategyKey` / `postStrategyKey` are non-empty strings, the executor issues
31
- * additional `@exellix/ai-tasks` **`runTask`** calls (utility `skillKey`) **before** and **after** the MAIN node task — graph-engine does **not** call the Xynthesis package directly. Results are merged under **`execution.xynthesis.pre`** / **`execution.xynthesis.post`** (historical execution-memory slot names). This is separate from `executionPipeline` PRE `synthesized-context`, which still runs inside a single ai-tasks `runTask`.
32
22
  *
33
- * **`inputSynthesis` runtime:** When `enabled`, graph-engine translates this block into an ai-tasks PRE
34
- * `synthesized-context` step inside the **same** `runTask` call (distinct from engine-level PRE/POST strategy utilities).
23
+ * **Web scope (Graphenix 2.7.3+):** Non-empty `webQueryTemplate` (or `webQueryTemplates[]`) compiles to a PRE
24
+ * `webScope` unit; graph-engine does not merge web intent into `taskConfiguration.narrix`.
35
25
  */
36
26
  export type AiTaskProfileMetadata = {
37
27
  preStrategyKey?: string;
38
28
  postStrategyKey?: string;
39
- webScoping?: AiTaskProfileWebScoping;
29
+ /** Rendrix template for PRE webScope (e.g. `Patch status for {{input.cveId}}?`). */
30
+ webQueryTemplate?: string;
31
+ /** Pack-mode web query templates (`webQueryTemplate` optional when non-empty). */
32
+ webQueryTemplates?: string[];
33
+ webScopeOptions?: Record<string, unknown>;
40
34
  inputSynthesis?: AiTaskProfileInputSynthesis;
41
35
  };
36
+ export declare function hasWebScopeAuthoring(profile: AiTaskProfileMetadata | undefined): boolean;
@@ -1,6 +1,14 @@
1
1
  /**
2
2
  * Optional task metadata aligned with `@x12i/graph-composer` authoring / `reportTaskNodeProtocolGaps`.
3
- * Exellix-graph-engine merges {@link AiTaskProfileMetadata.webScoping} into `taskConfiguration.narrix` for execution
4
- * when `enabled: true` and `questions` is non-empty (see `applyAiTaskProfileWebScopingToNarrix`).
3
+ * Web scope is authored via {@link AiTaskProfileMetadata.webQueryTemplate} (Graphenix 2.7.3+ PRE `webScope` unit).
5
4
  */
6
- export {};
5
+ export function hasWebScopeAuthoring(profile) {
6
+ if (profile == null)
7
+ return false;
8
+ if (typeof profile.webQueryTemplate === 'string' && profile.webQueryTemplate.trim().length > 0) {
9
+ return true;
10
+ }
11
+ const pack = profile.webQueryTemplates;
12
+ return (Array.isArray(pack) &&
13
+ pack.some((entry) => typeof entry === 'string' && entry.trim().length > 0));
14
+ }
@@ -1,22 +1,39 @@
1
- import type { RunTaskRequest } from '@exellix/ai-tasks';
2
- /** Same as `RunTaskRequest['narrix']` (ai-tasks exports `RunTaskRequest` but not this alias on the root barrel). */
3
- type AITasksNarrixPreProcessorConfig = NonNullable<RunTaskRequest['narrix']>;
1
+ /** Canonical Narrix invocation modes (Graphenix plan / ai-tasks narrative units). */
2
+ export type NarrixModeKey = 'off' | 'preprocessor' | 'handler';
3
+ /** Filters Narrix handler output before writing to task memory. */
4
+ export type NarrixScope = {
5
+ includeSignals?: string[];
6
+ excludeSignals?: string[];
7
+ includeStories?: string[];
8
+ excludeStories?: string[];
9
+ [key: string]: unknown;
10
+ };
11
+ /** Structured Narrix handler input (ai-tasks `NarrixRunInput` shape). */
12
+ export type NarrixRunInput = ({
13
+ medium: 'record';
14
+ datasetId: string;
15
+ record: Record<string, unknown>;
16
+ } & Record<string, unknown>) | ({
17
+ medium: 'text';
18
+ datasetId: string;
19
+ text: string;
20
+ } & Record<string, unknown>) | ({
21
+ medium: 'docs';
22
+ datasetId: string;
23
+ document: Record<string, unknown>;
24
+ } & Record<string, unknown>) | ({
25
+ medium: 'chat';
26
+ datasetId: string;
27
+ thread: Record<string, unknown>;
28
+ } & Record<string, unknown>);
4
29
  /**
5
- * Graph-engine wire shape for the resolved `RunTaskRequest.narrix` payload after merging
6
- * `taskConfiguration.narrix` with graph variables and optional `taskConfiguration.aiTaskProfile.webScoping`.
30
+ * Resolved discovery narrix after merging node `taskConfiguration.narrix` with graph-level
31
+ * `variables.narrix`. Patched onto `nodePlan.invokeContract.pipeline.narrix` before `runTask`.
7
32
  */
8
- export type ResolvedNarrixWirePayload = AITasksNarrixPreProcessorConfig;
9
- /** One web-scope question on the resolved narrix wire payload; produced from `aiTaskProfile.webScoping.questions`. */
10
- export type WebScopeQuestion = {
11
- id: string;
12
- question: string;
13
- purpose?: string;
14
- };
33
+ export type ResolvedNarrixWirePayload = NarrixPreProcessorConfig;
15
34
  /**
16
- * Authoring shape for `taskConfiguration.narrix` on a graph task node.
17
- *
18
- * Discovery fields plus `enableWebScope` (forwarded to `RunTaskRequest.narrix.enableWebScope`).
19
- * Question packs for web scoping may also be supplied via `taskConfiguration.aiTaskProfile.webScoping`.
35
+ * Authoring shape for `taskConfiguration.narrix` on a graph task node (discovery fields only).
36
+ * Web scope is authored on `taskConfiguration.aiTaskProfile.webQueryTemplate` (Graphenix 2.7.3+).
20
37
  */
21
38
  export type NarrixPreProcessorConfig = {
22
39
  /** Which pack and entity type the engine runs (e.g. `"network.vuln.instances"`). */
@@ -30,13 +47,6 @@ export type NarrixPreProcessorConfig = {
30
47
  narrativeTypeIds?: string[];
31
48
  /** Framework question this node answers (e.g. q0, q1, q2, q3, q5, q6). */
32
49
  questionId?: string;
33
- /** When true, ai-tasks runs `@exellix/narrix-web-scoper` after CNI and writes `executionMemory.webContext`. */
34
- enableWebScope?: boolean;
35
- /**
36
- * When true with `enableWebScope`, skip internal web-scoper if `executionMemory.webContextMarkdown` is already set.
37
- * See `@exellix/ai-tasks` `NarrixPreProcessorConfig.skipWebScopeWhenExternalWebMarkdownPresent`.
38
- */
39
- skipWebScopeWhenExternalWebMarkdownPresent?: boolean;
40
50
  /** Execution memory key for the Narrix attachment (default `_narrix` in ai-tasks). */
41
51
  attachToField?: string;
42
52
  };
@@ -63,4 +73,3 @@ export interface LocalTaskContext {
63
73
  masterSkillId?: string;
64
74
  masterSkillActivityId?: string;
65
75
  }
66
- export {};
@@ -1,4 +1,5 @@
1
- import type { InputStrategyKey, LlmCallConfig, NarrixModeKey, NarrixRunInput, RunTaskRequest } from '@exellix/ai-tasks';
1
+ import type { InputStrategyKey, LlmCallConfig, RunTaskRequest } from '@exellix/ai-tasks';
2
+ import type { NarrixModeKey, NarrixRunInput, NarrixScope } from './narrix.js';
2
3
  import type { ExecutionStrategyInvocation, TaskStrategyItemData } from './aiTasksDerivedTypes.js';
3
4
  import type { AiTaskProfileMetadata } from './aiTaskProfile.js';
4
5
  import type { ModelConfigSelection } from './refs.js';
@@ -49,7 +50,7 @@ export type TaskNodeTaskConfiguration = {
49
50
  identity?: Record<string, unknown>;
50
51
  runTaskIdentity?: Record<string, unknown>;
51
52
  memoryKey?: string;
52
- narrixScope?: RunTaskRequest['narrixScope'];
53
+ narrixScope?: NarrixScope;
53
54
  aiScoping?: RunTaskRequest['aiScoping'];
54
55
  aiScopingOptions?: RunTaskRequest['aiScopingOptions'];
55
56
  timeoutMs?: number;
@@ -0,0 +1,13 @@
1
+ # graphs-studio — Graphenix 2.7.3 alignment handoff
2
+
3
+ Shipped with **@exellix/graph-engine@8.6.0** / **@exellix/graph-composer@2.12.0**.
4
+
5
+ Full checklist: see Exellix monorepo `docs/handoff/graphs-studio-graphenix-2.7.3.md` (canonical copy). Summary:
6
+
7
+ 1. **Web scope:** `taskConfiguration.aiTaskProfile.webQueryTemplate` — remove `webScoping` and narrix web keys.
8
+ 2. **Graph entry:** no `graphEntry.inputs` (CR-006); use `requiredExecutionPaths` + jobs-ui data sources.
9
+ 3. **Persistency:** `response.persistency` with `newRecord` + optional `link` (Graphenix 2.7.3).
10
+ 4. **Preflight:** show `nodePlan.invokeContract.pipeline`, not root `RunTaskRequest.narrix`.
11
+ 5. **CRS-FRS-005:** PRE synthesis export parity still pending in studio (separate track).
12
+
13
+ Pin: `graph-engine ^8.6.0`, `graph-composer ^2.12.0`, `ai-tasks ^10.0.12+`, `graphenix ^2.7.3`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exellix/graph-engine",
3
- "version": "8.5.0",
3
+ "version": "8.6.0",
4
4
  "type": "module",
5
5
  "description": "Graph executor SDK",
6
6
  "main": "dist/src/index.js",
@@ -20,7 +20,8 @@
20
20
  "dist/**",
21
21
  ".env.example",
22
22
  "CHANGELOG.md",
23
- "README.md"
23
+ "README.md",
24
+ "docs/handoff/**"
24
25
  ],
25
26
  "scripts": {
26
27
  "prebuild": "node scripts/clean-dist.mjs",
@@ -52,27 +53,27 @@
52
53
  "access": "public"
53
54
  },
54
55
  "dependencies": {
55
- "@exellix/ai-skills": "^6.12.3",
56
- "@exellix/ai-tasks": "^10.0.9",
56
+ "@exellix/ai-skills": "^6.12.5",
57
+ "@exellix/ai-tasks": "^10.0.13",
57
58
  "@x12i/activix": "^8.6.3",
58
- "@x12i/catalox": "^5.9.7",
59
+ "@x12i/catalox": "^5.9.8",
59
60
  "@x12i/env": "^4.0.1",
60
61
  "@x12i/funcx": "^4.9.13",
61
62
  "@x12i/graphenix": "^2.5.0",
62
- "@x12i/graphenix-authoring-format": "^2.7.0",
63
- "@x12i/graphenix-core": "^2.7.0",
64
- "@x12i/graphenix-executable-contracts": "^2.7.0",
65
- "@x12i/graphenix-executable-format": "^2.7.0",
66
- "@x12i/graphenix-execute-envelope": "^2.7.0",
63
+ "@x12i/graphenix-authoring-format": "^2.7.3",
64
+ "@x12i/graphenix-core": "^2.7.3",
65
+ "@x12i/graphenix-executable-contracts": "^2.7.3",
66
+ "@x12i/graphenix-executable-format": "^2.7.3",
67
+ "@x12i/graphenix-execute-envelope": "^2.7.3",
67
68
  "@x12i/graphenix-format": "^2.0.0",
68
- "@x12i/graphenix-plan-compiler": "^2.7.0",
69
- "@x12i/graphenix-plan-format": "^2.7.0",
70
- "@x12i/graphenix-task-node-format": "^2.7.0",
71
- "@x12i/graphenix-trace-format": "^2.7.0",
69
+ "@x12i/graphenix-plan-compiler": "^2.7.3",
70
+ "@x12i/graphenix-plan-format": "^2.7.3",
71
+ "@x12i/graphenix-task-node-format": "^2.7.3",
72
+ "@x12i/graphenix-trace-format": "^2.7.3",
72
73
  "@x12i/logxer": "^4.6.0",
73
- "@x12i/memorix-descriptors": "1.7.0",
74
- "@x12i/memorix-retrieval": "1.12.0",
75
- "@x12i/memorix-writer": "1.1.0",
74
+ "@x12i/memorix-descriptors": "1.10.0",
75
+ "@x12i/memorix-retrieval": "1.14.0",
76
+ "@x12i/memorix-writer": "1.3.0",
76
77
  "@x12i/rendrix": "^4.3.0",
77
78
  "@x12i/runx": "^1.3.2"
78
79
  },
@@ -1,15 +0,0 @@
1
- import type { AiTaskProfileMetadata } from '../types/aiTaskProfile.js';
2
- import type { NarrixPreProcessorConfig, ResolvedNarrixWirePayload, WebScopeQuestion } from '../types/narrix.js';
3
- /**
4
- * Maps graph-composer `string[]` web questions to narrix-web-scoper object shape.
5
- * Synthetic ids are stable per index for a given node run.
6
- */
7
- export declare function mapAiTaskProfileQuestionsToWebScopeQuestions(questions: string[]): WebScopeQuestion[];
8
- /**
9
- * Returns the resolved outbound `RunTaskRequest.narrix` payload.
10
- *
11
- * `enableWebScope` is forwarded from `taskConfiguration.narrix` (default `false`) and may be set to
12
- * `true` when `taskConfiguration.aiTaskProfile.webScoping` is active. `webScopeQuestions` are derived
13
- * only from the ai-task profile.
14
- */
15
- export declare function applyAiTaskProfileWebScopingToNarrix(narrix: NarrixPreProcessorConfig | undefined, aiTaskProfile: AiTaskProfileMetadata | undefined): ResolvedNarrixWirePayload | undefined;
@@ -1,43 +0,0 @@
1
- /**
2
- * Maps graph-composer `string[]` web questions to narrix-web-scoper object shape.
3
- * Synthetic ids are stable per index for a given node run.
4
- */
5
- export function mapAiTaskProfileQuestionsToWebScopeQuestions(questions) {
6
- const out = [];
7
- let i = 0;
8
- for (const q of questions) {
9
- const t = typeof q === 'string' ? q.trim() : '';
10
- if (!t)
11
- continue;
12
- out.push({ id: `aiTaskProfile-q-${i}`, question: t });
13
- i += 1;
14
- }
15
- return out;
16
- }
17
- function webScopingFromProfileIsActive(profile) {
18
- if (profile?.webScoping?.enabled !== true)
19
- return false;
20
- const qs = profile.webScoping.questions;
21
- if (!Array.isArray(qs) || qs.length === 0)
22
- return false;
23
- return mapAiTaskProfileQuestionsToWebScopeQuestions(qs).length > 0;
24
- }
25
- /**
26
- * Returns the resolved outbound `RunTaskRequest.narrix` payload.
27
- *
28
- * `enableWebScope` is forwarded from `taskConfiguration.narrix` (default `false`) and may be set to
29
- * `true` when `taskConfiguration.aiTaskProfile.webScoping` is active. `webScopeQuestions` are derived
30
- * only from the ai-task profile.
31
- */
32
- export function applyAiTaskProfileWebScopingToNarrix(narrix, aiTaskProfile) {
33
- const profileActive = webScopingFromProfileIsActive(aiTaskProfile);
34
- if (narrix == null && !profileActive) {
35
- return undefined;
36
- }
37
- const wire = (narrix != null ? { ...narrix } : {});
38
- wire.enableWebScope = narrix?.enableWebScope === true || profileActive;
39
- if (profileActive) {
40
- wire.webScopeQuestions = mapAiTaskProfileQuestionsToWebScopeQuestions(aiTaskProfile.webScoping.questions);
41
- }
42
- return wire;
43
- }