@exellix/graph-engine 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/README.md +11 -12
- package/dist/src/compile/authoringDocumentHelpers.d.ts +9 -0
- package/dist/src/compile/authoringDocumentHelpers.js +18 -0
- package/dist/src/compile/compileExellixExecutablePlan.d.ts +8 -0
- package/dist/src/compile/compileExellixExecutablePlan.js +75 -0
- package/dist/src/index.d.ts +4 -6
- package/dist/src/index.js +2 -4
- package/dist/src/runtime/ExellixGraphRuntime.d.ts +11 -37
- package/dist/src/runtime/ExellixGraphRuntime.js +78 -173
- package/dist/src/runtime/aiTasksStrategyPhases.js +7 -3
- package/dist/src/runtime/buildAiTasksRunTaskRequest.d.ts +6 -8
- package/dist/src/runtime/buildAiTasksRunTaskRequest.js +2 -7
- package/dist/src/runtime/executionMatrixHost.d.ts +6 -3
- package/dist/src/runtime/executionMatrixHost.js +6 -4
- package/dist/src/runtime/runTaskNodePlan.d.ts +15 -0
- package/dist/src/runtime/runTaskNodePlan.js +46 -0
- package/dist/src/runtime/studioGraphExecuteRequest.d.ts +5 -30
- package/dist/src/runtime/studioGraphExecuteRequest.js +14 -50
- package/dist/src/runtime/taskNodeRunTaskPreflight.d.ts +7 -5
- package/dist/src/runtime/taskNodeRunTaskPreflight.js +31 -26
- package/dist/src/types/refs.d.ts +1 -1
- package/dist/testkit/authoringGraphFixtures.d.ts +8 -0
- package/dist/testkit/authoringGraphFixtures.js +249 -0
- package/dist/testkit/buildExecuteGraphInput.d.ts +3 -3
- package/dist/testkit/buildExecuteGraphInput.js +8 -4
- package/dist/testkit/flatGraphToAuthoring.d.ts +29 -0
- package/dist/testkit/flatGraphToAuthoring.js +281 -0
- package/dist/testkit/index.d.ts +3 -0
- package/dist/testkit/index.js +3 -0
- package/dist/testkit/runTaskNodePlanAssertions.d.ts +34 -0
- package/dist/testkit/runTaskNodePlanAssertions.js +32 -0
- package/package.json +8 -7
- package/dist/src/adapters/compileExellixExecutablePlan.d.ts +0 -8
- package/dist/src/adapters/compileExellixExecutablePlan.js +0 -18
- package/dist/src/adapters/migrateExellixGraphModelToAuthoring.d.ts +0 -6
- package/dist/src/adapters/migrateExellixGraphModelToAuthoring.js +0 -273
- package/dist/src/adapters/patchFinalizerPlans.d.ts +0 -7
- package/dist/src/adapters/patchFinalizerPlans.js +0 -63
- package/dist/src/runtime/graphResponseMigration.d.ts +0 -7
- package/dist/src/runtime/graphResponseMigration.js +0 -44
|
@@ -1,40 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ExecuteGraphInput, GraphRuntimeObject } from './ExellixGraphRuntime.js';
|
|
1
|
+
import type { ExecuteGraphInput } from './ExellixGraphRuntime.js';
|
|
3
2
|
/**
|
|
4
3
|
* Removed from the graphs-studio execute envelope (7.8.3+). No reader, no fallback.
|
|
5
|
-
* Default model selection belongs on
|
|
4
|
+
* Default model selection belongs on authoring graph executable profile only.
|
|
6
5
|
*/
|
|
7
6
|
export declare const STUDIO_GRAPH_EXECUTE_REMOVED_KEYS: readonly ["graphDefaultModel"];
|
|
8
7
|
export type StudioGraphExecuteRemovedKey = (typeof STUDIO_GRAPH_EXECUTE_REMOVED_KEYS)[number];
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
* {@link ExecuteGraphInput}. Credential and simulate-only fields are host concerns;
|
|
12
|
-
* graph-engine validates shape and forbidden keys only.
|
|
13
|
-
*/
|
|
14
|
-
export type StudioGraphExecuteRequest = {
|
|
15
|
-
mode: 'graph';
|
|
16
|
-
graph: Graph;
|
|
17
|
-
jobId: string;
|
|
18
|
-
runtime: Pick<GraphRuntimeObject, 'input' | 'inputs' | 'jobMemory' | 'taskMemory' | 'executionMemory' | 'outputsMemory' | 'variables' | 'jobVariables' | 'taskVariables' | 'nodes'>;
|
|
19
|
-
studioId?: string;
|
|
20
|
-
executionMode?: string;
|
|
21
|
-
runLogMode?: GraphRuntimeObject['runLogMode'];
|
|
22
|
-
maxRunLogEntries?: number;
|
|
23
|
-
maxRunLogDataJsonChars?: number;
|
|
24
|
-
graphExecution?: {
|
|
25
|
-
mode?: GraphRuntimeObject['mode'];
|
|
26
|
-
goalNodeId?: string;
|
|
27
|
-
dimension?: string;
|
|
28
|
-
};
|
|
29
|
-
runTaskDiagnostics?: GraphRuntimeObject['runTaskDiagnostics'];
|
|
30
|
-
exampleIndex?: number;
|
|
31
|
-
validateGraphEntrySeed?: boolean;
|
|
32
|
-
openrouterApiKey?: string;
|
|
33
|
-
};
|
|
8
|
+
/** @deprecated Prefer {@link AuthoringGraphDocument} from `@x12i/graphenix-executable-contracts`. */
|
|
9
|
+
export type StudioGraphExecuteRequest = import('@x12i/graphenix-executable-contracts').StudioGraphExecuteRequest;
|
|
34
10
|
export declare function getStudioGraphExecuteRemovedKeyViolations(request: unknown): StudioGraphExecuteRemovedKey[];
|
|
35
11
|
/**
|
|
36
12
|
* Rejects removed studio execute keys (notably `graphDefaultModel`).
|
|
37
|
-
* Hosts must persist model defaults on `graph.modelConfig` and stop sending request-level mirrors.
|
|
38
13
|
*/
|
|
39
14
|
export declare function assertCanonicalStudioGraphExecuteRequest(request: unknown, context?: {
|
|
40
15
|
jobId?: string;
|
|
@@ -46,6 +21,6 @@ export type BuildGraphExecutionRequestFromStudioExecuteOptions = {
|
|
|
46
21
|
};
|
|
47
22
|
/**
|
|
48
23
|
* Maps a validated studio execute envelope to {@link ExecuteGraphInput}.
|
|
49
|
-
*
|
|
24
|
+
* Delegates validate + compile to `@x12i/graphenix-execute-envelope`.
|
|
50
25
|
*/
|
|
51
26
|
export declare function buildGraphExecutionRequestFromStudioExecute(request: StudioGraphExecuteRequest, options?: BuildGraphExecutionRequestFromStudioExecuteOptions): ExecuteGraphInput;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildGraphExecutionRequestFromStudioExecute as buildAuthoringRequest } from '@x12i/graphenix-execute-envelope';
|
|
2
2
|
import { ExellixGraphError } from '../errors/ExellixGraphError.js';
|
|
3
3
|
import { ExellixGraphErrorCode } from '../errors/exellixGraphErrorCodes.js';
|
|
4
4
|
/**
|
|
5
5
|
* Removed from the graphs-studio execute envelope (7.8.3+). No reader, no fallback.
|
|
6
|
-
* Default model selection belongs on
|
|
6
|
+
* Default model selection belongs on authoring graph executable profile only.
|
|
7
7
|
*/
|
|
8
8
|
export const STUDIO_GRAPH_EXECUTE_REMOVED_KEYS = ['graphDefaultModel'];
|
|
9
9
|
function isPlainObject(v) {
|
|
@@ -16,63 +16,27 @@ export function getStudioGraphExecuteRemovedKeyViolations(request) {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Rejects removed studio execute keys (notably `graphDefaultModel`).
|
|
19
|
-
* Hosts must persist model defaults on `graph.modelConfig` and stop sending request-level mirrors.
|
|
20
19
|
*/
|
|
21
20
|
export function assertCanonicalStudioGraphExecuteRequest(request, context) {
|
|
22
21
|
const removed = getStudioGraphExecuteRemovedKeyViolations(request);
|
|
23
22
|
if (removed.length > 0) {
|
|
24
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, `Studio graph execute request must not include removed field(s): ${removed.join(', ')}. Model defaults belong on graph
|
|
23
|
+
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, `Studio graph execute request must not include removed field(s): ${removed.join(', ')}. Model defaults belong on the authoring graph executable profile only; request-level graphDefaultModel was removed with no legacy fallback.`, { ...context, removedKeys: removed });
|
|
25
24
|
}
|
|
26
|
-
if (!isPlainObject(request)) {
|
|
27
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request
|
|
28
|
-
}
|
|
29
|
-
if (request.mode !== 'graph') {
|
|
30
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request mode must be "graph".', context);
|
|
31
|
-
}
|
|
32
|
-
const jobId = typeof request.jobId === 'string' ? request.jobId.trim() : '';
|
|
33
|
-
if (!jobId) {
|
|
34
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request requires a non-empty jobId.', context);
|
|
35
|
-
}
|
|
36
|
-
if (!isPlainObject(request.graph)) {
|
|
37
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request requires graph (GraphModelObject).', { ...context, jobId });
|
|
38
|
-
}
|
|
39
|
-
if (!isPlainObject(request.runtime)) {
|
|
40
|
-
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request requires runtime.', { ...context, jobId });
|
|
25
|
+
if (!isPlainObject(request) || request.mode !== 'graph' || typeof request.jobId !== 'string') {
|
|
26
|
+
throw new ExellixGraphError(ExellixGraphErrorCode.NON_CANONICAL_STUDIO_GRAPH_EXECUTE_REQUEST, 'Studio graph execute request requires mode graph and jobId.', context);
|
|
41
27
|
}
|
|
42
28
|
}
|
|
43
29
|
/**
|
|
44
30
|
* Maps a validated studio execute envelope to {@link ExecuteGraphInput}.
|
|
45
|
-
*
|
|
31
|
+
* Delegates validate + compile to `@x12i/graphenix-execute-envelope`.
|
|
46
32
|
*/
|
|
47
33
|
export function buildGraphExecutionRequestFromStudioExecute(request, options) {
|
|
48
|
-
assertCanonicalStudioGraphExecuteRequest(request
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
id: jobId,
|
|
57
|
-
jobId,
|
|
58
|
-
agentId: options?.agentId ?? 'standalone-agent',
|
|
59
|
-
jobTypeId: options?.jobTypeId ?? 'exellix-graph-job',
|
|
60
|
-
},
|
|
61
|
-
...request.runtime,
|
|
62
|
-
...(request.graphExecution?.mode != null ? { mode: request.graphExecution.mode } : {}),
|
|
63
|
-
...(request.graphExecution?.goalNodeId != null
|
|
64
|
-
? { goalNodeId: request.graphExecution.goalNodeId }
|
|
65
|
-
: {}),
|
|
66
|
-
...(request.graphExecution?.dimension != null ? { dimension: request.graphExecution.dimension } : {}),
|
|
67
|
-
...(request.runLogMode != null ? { runLogMode: request.runLogMode } : {}),
|
|
68
|
-
...(request.maxRunLogEntries != null ? { maxRunLogEntries: request.maxRunLogEntries } : {}),
|
|
69
|
-
...(request.maxRunLogDataJsonChars != null
|
|
70
|
-
? { maxRunLogDataJsonChars: request.maxRunLogDataJsonChars }
|
|
71
|
-
: {}),
|
|
72
|
-
...(request.runTaskDiagnostics != null ? { runTaskDiagnostics: request.runTaskDiagnostics } : {}),
|
|
73
|
-
};
|
|
74
|
-
return {
|
|
75
|
-
plan: compileExellixExecutablePlan(request.graph, runtime),
|
|
76
|
-
runtime,
|
|
77
|
-
};
|
|
34
|
+
assertCanonicalStudioGraphExecuteRequest(request, {
|
|
35
|
+
jobId: request.jobId,
|
|
36
|
+
graphId: request.graph?.id,
|
|
37
|
+
});
|
|
38
|
+
return buildAuthoringRequest(request, {
|
|
39
|
+
agentId: options?.agentId,
|
|
40
|
+
jobTypeId: options?.jobTypeId,
|
|
41
|
+
});
|
|
78
42
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Graph-level preflight for `@exellix/ai-tasks` validation and analysis on task nodes.
|
|
3
|
-
* Builds the same outbound {@link RunTaskRequest} as `executeNode` (without
|
|
3
|
+
* Builds the same outbound {@link RunTaskRequest} as `executeNode` (without `runTask`).
|
|
4
4
|
*/
|
|
5
5
|
import type { RunTaskRequest } from '@exellix/ai-tasks';
|
|
6
6
|
import { type RunTaskInvokeValidationResult, type RunTaskValidationResult, type ValidateRunTaskInvokeParams } from '@exellix/ai-tasks';
|
|
7
|
+
import type { NodeExecutionPlan } from '@x12i/graphenix-executable-contracts';
|
|
7
8
|
import type { GraphAiModelConfig, Job, TaskNode } from '../types/refs.js';
|
|
8
|
-
import type {
|
|
9
|
+
import type { RunTaskDiagnostics, SkillKeyResolutionOptions } from '../types/options.js';
|
|
9
10
|
export type TaskNodeRunTaskPreflightSkipReason = 'local_skill' | 'finalizer';
|
|
10
11
|
export type BuildTaskNodeRunTaskRequestResult = {
|
|
11
12
|
runnable: true;
|
|
@@ -29,20 +30,21 @@ export type BuildTaskNodeRunTaskRequestArgs = {
|
|
|
29
30
|
graphRunTaskId?: string;
|
|
30
31
|
/** Host job id on `job.jobId` / `job.id`; defaults from `job` when omitted. */
|
|
31
32
|
runTaskJobId?: string;
|
|
32
|
-
/**
|
|
33
|
+
/** Frozen per-node plan from compile; when omitted a minimal plan is synthesized and patched from modelConfig. */
|
|
34
|
+
nodePlan?: NodeExecutionPlan;
|
|
35
|
+
/** Resolved graph model profiles (required for runnable MAIN when nodePlan is omitted). */
|
|
33
36
|
modelConfig: GraphAiModelConfig;
|
|
34
37
|
runTaskIdentity?: Record<string, unknown>;
|
|
35
38
|
runTaskExecutionMode?: 'default' | 'trace';
|
|
36
39
|
runTaskDiagnostics?: RunTaskDiagnostics;
|
|
37
40
|
jobKnowledgePatch?: Record<string, unknown>;
|
|
38
41
|
taskKnowledgePatch?: Record<string, unknown>;
|
|
39
|
-
graphExecutionPipeline?: ExecutionStepOption[];
|
|
40
42
|
skillKeyResolution?: SkillKeyResolutionOptions;
|
|
41
43
|
clearSynthesizedContextPerNode?: boolean;
|
|
42
44
|
};
|
|
43
45
|
/**
|
|
44
46
|
* Materialize the outbound `RunTaskRequest` graph-engine would send for a task node
|
|
45
|
-
* (mirrors `executeNode` request assembly; does not
|
|
47
|
+
* (mirrors `executeNode` request assembly; does not invoke `runTask`).
|
|
46
48
|
*/
|
|
47
49
|
export declare function buildTaskNodeRunTaskRequest(args: BuildTaskNodeRunTaskRequestArgs): Promise<BuildTaskNodeRunTaskRequestResult>;
|
|
48
50
|
export type ValidateTaskNodeRunTaskConfigArgs = BuildTaskNodeRunTaskRequestArgs;
|
|
@@ -3,7 +3,6 @@ import { toRunTaskModelConfig } from './graphAiModelConfig.js';
|
|
|
3
3
|
import { resolveTaskKey } from './resolveTaskKey.js';
|
|
4
4
|
import { isLocalSkillKey } from './localSkills/index.js';
|
|
5
5
|
import { buildAiTasksRunTaskRequest, extractRunTaskStrategyOverrides, } from './buildAiTasksRunTaskRequest.js';
|
|
6
|
-
import { resolveExecutionPipelineForTaskNode } from './resolveExecutionPipelineForTaskNode.js';
|
|
7
6
|
import { resolveTaskNodeInputsForRunTask } from './resolveTaskNodeInputs.js';
|
|
8
7
|
import { assertAiTasksNodeExtensionsValid } from '../inspection/validateAiTasksNodeExtensions.js';
|
|
9
8
|
import { buildRunTaskMainInput, extractCallerInputsBag } from './resolveGraphEngineMemoryPaths.js';
|
|
@@ -11,10 +10,10 @@ import { mirrorStructuredInputOntoExecutionMemory, } from './materializeStructur
|
|
|
11
10
|
import { xynthesizedOutboundForNode } from './graphRunExecutionSeed.js';
|
|
12
11
|
import { buildTaskNodeJobContext } from './buildTaskNodeJobContext.js';
|
|
13
12
|
import { resolveNarrixForTaskNode } from './resolveNarrixForTaskNode.js';
|
|
14
|
-
import {
|
|
15
|
-
import { buildMainLlmCallForRunTask, buildRunTaskIdentityEnvelope, shouldForwardRunTaskTraceMode, } from './runTaskAugments.js';
|
|
13
|
+
import { buildRunTaskIdentityEnvelope, shouldForwardRunTaskTraceMode, } from './runTaskAugments.js';
|
|
16
14
|
import { mirrorTaskVariablesOnExecution, readExecutionVariableBuckets, } from './executionVariableBuckets.js';
|
|
17
15
|
import { newGraphRunTaskId } from './graphRunIdentity.js';
|
|
16
|
+
import { patchNodePlanMainModelFromWire, resolveRunTaskNodePlan } from './runTaskNodePlan.js';
|
|
18
17
|
function isPlainRecord(v) {
|
|
19
18
|
return v != null && typeof v === 'object' && !Array.isArray(v);
|
|
20
19
|
}
|
|
@@ -33,7 +32,7 @@ function mergeKnowledgePatchIntoRunTaskMemory(memory, patch) {
|
|
|
33
32
|
}
|
|
34
33
|
/**
|
|
35
34
|
* Materialize the outbound `RunTaskRequest` graph-engine would send for a task node
|
|
36
|
-
* (mirrors `executeNode` request assembly; does not
|
|
35
|
+
* (mirrors `executeNode` request assembly; does not invoke `runTask`).
|
|
37
36
|
*/
|
|
38
37
|
export async function buildTaskNodeRunTaskRequest(args) {
|
|
39
38
|
const node = args.node;
|
|
@@ -59,23 +58,22 @@ export async function buildTaskNodeRunTaskRequest(args) {
|
|
|
59
58
|
node: node,
|
|
60
59
|
runtimeTaskVariables: args.taskVariables,
|
|
61
60
|
});
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
const wireModelConfig = toRunTaskModelConfig(args.modelConfig);
|
|
62
|
+
let runTaskNodePlan = resolveRunTaskNodePlan({
|
|
63
|
+
nodePlan: args.nodePlan,
|
|
64
|
+
skillKey,
|
|
65
|
+
nodeId: String(node.id),
|
|
66
66
|
});
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
: undefined;
|
|
72
|
-
const includeContextInPrompt = hasSynthesizedContextPreStep && preStepConfig?.autoEnableContext !== true;
|
|
73
|
-
const variableBuckets = readExecutionVariableBuckets(execution);
|
|
74
|
-
const jobVariables = variableBuckets.jobVariables;
|
|
67
|
+
if (!args.nodePlan) {
|
|
68
|
+
runTaskNodePlan = patchNodePlanMainModelFromWire(runTaskNodePlan, wireModelConfig);
|
|
69
|
+
}
|
|
70
|
+
const hasSynthesizedContextPreStep = runTaskNodePlan.executionUnits.some((u) => u.unitKind === 'externalPreUtility' || u.unitKind === 'pipelinePhase');
|
|
75
71
|
const hasExistingSynthesizedContext = execution.synthesizedContext != null;
|
|
76
72
|
const clearSynthForTask = args.clearSynthesizedContextPerNode === true &&
|
|
77
73
|
hasSynthesizedContextPreStep &&
|
|
78
74
|
hasExistingSynthesizedContext;
|
|
75
|
+
const variableBuckets = readExecutionVariableBuckets(execution);
|
|
76
|
+
const jobVariables = variableBuckets.jobVariables;
|
|
79
77
|
const nodeBindings = resolveTaskNodeInputsForRunTask({ node, execution });
|
|
80
78
|
const jobContext = buildTaskNodeJobContext({
|
|
81
79
|
node,
|
|
@@ -115,12 +113,21 @@ export async function buildTaskNodeRunTaskRequest(args) {
|
|
|
115
113
|
mirrorStructuredInputOntoExecutionMemory(executionForTask, taskInput);
|
|
116
114
|
const runTaskJobMemory = mergeKnowledgePatchIntoRunTaskMemory(args.jobMemory, args.jobKnowledgePatch);
|
|
117
115
|
const runTaskTaskMemory = mergeKnowledgePatchIntoRunTaskMemory(args.taskMemory, args.taskKnowledgePatch);
|
|
118
|
-
const wireModelConfig = toRunTaskModelConfig(args.modelConfig);
|
|
119
|
-
const effectiveLlmCall = buildMainLlmCallForRunTask(wireModelConfig, node.taskConfiguration?.llmCall);
|
|
120
116
|
const forwardRunTaskTrace = shouldForwardRunTaskTraceMode({
|
|
121
117
|
runTaskExecutionMode: args.runTaskExecutionMode,
|
|
122
118
|
});
|
|
123
|
-
const metaStrats =
|
|
119
|
+
const metaStrats = runTaskNodePlan.invokeContract?.pipeline &&
|
|
120
|
+
typeof runTaskNodePlan.invokeContract.pipeline === 'object' &&
|
|
121
|
+
Array.isArray(runTaskNodePlan.invokeContract.pipeline.executionStrategies)
|
|
122
|
+
? runTaskNodePlan.invokeContract.pipeline
|
|
123
|
+
.executionStrategies
|
|
124
|
+
: node.taskConfiguration?.executionStrategies;
|
|
125
|
+
const outputValidationFromPlan = runTaskNodePlan.invokeContract?.validation &&
|
|
126
|
+
typeof runTaskNodePlan.invokeContract.validation === 'object' &&
|
|
127
|
+
'aiTasksOutputValidation' in runTaskNodePlan.invokeContract.validation
|
|
128
|
+
? runTaskNodePlan.invokeContract.validation
|
|
129
|
+
.aiTasksOutputValidation
|
|
130
|
+
: undefined;
|
|
124
131
|
const ov = node.taskConfiguration?.aiTasksOutputValidation;
|
|
125
132
|
const request = buildAiTasksRunTaskRequest({
|
|
126
133
|
skillKey,
|
|
@@ -138,16 +145,13 @@ export async function buildTaskNodeRunTaskRequest(args) {
|
|
|
138
145
|
executionMemory: executionForTask,
|
|
139
146
|
jobContext,
|
|
140
147
|
prevNodeId: args.prevNodeId,
|
|
141
|
-
executionPipeline: executionPipeline,
|
|
142
|
-
includeContextInPrompt: includeContextInPrompt === true ? true : undefined,
|
|
143
148
|
narrix: narrix ?? undefined,
|
|
144
149
|
...extractRunTaskStrategyOverrides(node.taskConfiguration),
|
|
145
|
-
outputValidation:
|
|
146
|
-
|
|
147
|
-
|
|
150
|
+
outputValidation: outputValidationFromPlan ??
|
|
151
|
+
(ov != null && typeof ov === 'object' && !Array.isArray(ov) && 'schema' in ov
|
|
152
|
+
? ov
|
|
153
|
+
: undefined),
|
|
148
154
|
diagnostics: args.runTaskDiagnostics,
|
|
149
|
-
modelConfig: wireModelConfig,
|
|
150
|
-
llmCall: effectiveLlmCall,
|
|
151
155
|
identity: buildRunTaskIdentityEnvelope({
|
|
152
156
|
base: args.runTaskIdentity,
|
|
153
157
|
nodeMeta: node.taskConfiguration,
|
|
@@ -162,6 +166,7 @@ export async function buildTaskNodeRunTaskRequest(args) {
|
|
|
162
166
|
executionStrategies: Array.isArray(metaStrats) ? metaStrats : [],
|
|
163
167
|
xynthesized: xynthesizedOutboundForNode(execution, String(node.id)),
|
|
164
168
|
smartInput: node.smartInput,
|
|
169
|
+
nodePlan: runTaskNodePlan,
|
|
165
170
|
});
|
|
166
171
|
return { runnable: true, skillKey, request };
|
|
167
172
|
}
|
package/dist/src/types/refs.d.ts
CHANGED
|
@@ -680,7 +680,7 @@ export interface GraphDocumentMetadata {
|
|
|
680
680
|
graphResponse?: GraphResponseContract;
|
|
681
681
|
/**
|
|
682
682
|
* Graph execution defaults and labels.
|
|
683
|
-
* Planner mode is still selected by `executeGraph({
|
|
683
|
+
* Planner mode is still selected by `executeGraph({ plan, runtime }).runtime.mode` (or plan.schedulingPolicy) and defaults to `forward`;
|
|
684
684
|
* output labels in this block shape `stepsResponses`, not `ExecuteGraphResult.finalOutput`.
|
|
685
685
|
*/
|
|
686
686
|
graphExecution?: GraphExecutionDefaults;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuthoringGraphDocument } from '@x12i/graphenix-executable-contracts';
|
|
2
|
+
/** Single ai-task + select finalizer — mirrors legacy flat `buildAiTaskGraph` tests. */
|
|
3
|
+
export declare function buildAiTaskAuthoringGraph(graphId: string): AuthoringGraphDocument;
|
|
4
|
+
/** deterministic-rule local skill + select finalizer. */
|
|
5
|
+
export declare function buildLocalSkillAuthoringGraph(graphId: string): AuthoringGraphDocument;
|
|
6
|
+
/** Fan-in Q&A graph used by graph.response mapping tests. */
|
|
7
|
+
export declare function buildGraphResponseMappingAuthoringGraph(graphId: string): AuthoringGraphDocument;
|
|
8
|
+
export declare function withAuthoringGraphModelConfig(doc: AuthoringGraphDocument, modelConfig: Record<string, unknown>): AuthoringGraphDocument;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { GRAPHENIX_FORMAT_VERSION } from '@x12i/graphenix-core';
|
|
2
|
+
import { EXECUTABLE_PROFILE_NAMESPACE, EXECUTABLE_PROFILE_VERSION, FINALIZER_NODE_KIND, FINALIZER_NODE_PROFILE, TASK_NODE_KIND, TASK_NODE_PROFILE, } from '@x12i/graphenix-executable-contracts';
|
|
3
|
+
function defaultExecutableModelConfig() {
|
|
4
|
+
return {
|
|
5
|
+
version: 'graph-model-config/v1',
|
|
6
|
+
cases: [
|
|
7
|
+
{
|
|
8
|
+
id: 'default',
|
|
9
|
+
modelConfig: {
|
|
10
|
+
preActionModel: { kind: 'profileChoice', key: 'cheap/default' },
|
|
11
|
+
skillModel: { kind: 'profileChoice', key: 'pro/default' },
|
|
12
|
+
postActionModel: { kind: 'profileChoice', key: 'cheap/default' },
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
fallbackPolicy: {
|
|
17
|
+
enabled: true,
|
|
18
|
+
allowedTriggers: [
|
|
19
|
+
'nodeSlotMissing',
|
|
20
|
+
'nodeModelUnavailable',
|
|
21
|
+
'nodeModelUnsupported',
|
|
22
|
+
'nodeProviderNotConfigured',
|
|
23
|
+
'nodeModelRateLimited',
|
|
24
|
+
'nodeModelTransientFailure',
|
|
25
|
+
],
|
|
26
|
+
maxAttemptsPerSlot: 1,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function authoringShell(graphId, nodes, edges, graphResponseShape, extra) {
|
|
31
|
+
const taskNodes = nodes.filter((n) => n.kind === TASK_NODE_KIND);
|
|
32
|
+
const finalizer = nodes.find((n) => n.kind === FINALIZER_NODE_KIND);
|
|
33
|
+
return {
|
|
34
|
+
formatVersion: GRAPHENIX_FORMAT_VERSION,
|
|
35
|
+
id: graphId.startsWith('graph:') ? graphId : `graph:${graphId}`,
|
|
36
|
+
revision: '1.0.0',
|
|
37
|
+
name: graphId,
|
|
38
|
+
graph: {
|
|
39
|
+
nodes,
|
|
40
|
+
edges,
|
|
41
|
+
inputs: taskNodes.map((node) => ({
|
|
42
|
+
id: `graph-input:${node.id}`,
|
|
43
|
+
name: 'Input Record',
|
|
44
|
+
type: 'builtin:object',
|
|
45
|
+
target: { nodeId: node.id, portId: 'in:record' },
|
|
46
|
+
contract: { semanticKind: 'record', required: true, schema: { type: 'object' } },
|
|
47
|
+
})),
|
|
48
|
+
outputs: finalizer
|
|
49
|
+
? [
|
|
50
|
+
{
|
|
51
|
+
id: 'graph-output:final',
|
|
52
|
+
name: 'Final Output',
|
|
53
|
+
type: 'builtin:object',
|
|
54
|
+
source: { nodeId: finalizer.id, portId: 'out:final' },
|
|
55
|
+
contract: { semanticKind: 'final-output', required: true, schema: { type: 'object' } },
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
: [],
|
|
59
|
+
metadata: {
|
|
60
|
+
graphResponse: { shape: graphResponseShape },
|
|
61
|
+
extensions: {
|
|
62
|
+
[EXECUTABLE_PROFILE_NAMESPACE]: {
|
|
63
|
+
profileVersion: EXECUTABLE_PROFILE_VERSION,
|
|
64
|
+
modelConfig: defaultExecutableModelConfig(),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
...extra,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
types: [],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Single ai-task + select finalizer — mirrors legacy flat `buildAiTaskGraph` tests. */
|
|
74
|
+
export function buildAiTaskAuthoringGraph(graphId) {
|
|
75
|
+
const taskId = 'ask-1';
|
|
76
|
+
const finalId = 'final';
|
|
77
|
+
const taskNode = {
|
|
78
|
+
id: taskId,
|
|
79
|
+
kind: TASK_NODE_KIND,
|
|
80
|
+
inputs: [{ id: 'in:record', direction: 'input', type: 'builtin:object', required: true }],
|
|
81
|
+
outputs: [{ id: 'out:answer', direction: 'output', type: 'builtin:object' }],
|
|
82
|
+
parameters: {
|
|
83
|
+
profile: TASK_NODE_PROFILE,
|
|
84
|
+
nodeType: 'task',
|
|
85
|
+
skillKey: 'professional-answer',
|
|
86
|
+
executionMapping: {
|
|
87
|
+
path: 'answers.ask1',
|
|
88
|
+
mode: 'replace',
|
|
89
|
+
map: { answer: 'output.answer' },
|
|
90
|
+
},
|
|
91
|
+
taskConfiguration: { executionStrategies: [] },
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
const finalizerNode = {
|
|
95
|
+
id: finalId,
|
|
96
|
+
kind: FINALIZER_NODE_KIND,
|
|
97
|
+
inputs: [{ id: 'in:answer', direction: 'input', type: 'builtin:object', required: true }],
|
|
98
|
+
outputs: [{ id: 'out:final', direction: 'output', type: 'builtin:object' }],
|
|
99
|
+
parameters: {
|
|
100
|
+
profile: FINALIZER_NODE_PROFILE,
|
|
101
|
+
nodeType: 'finalizer',
|
|
102
|
+
finalizerType: 'select',
|
|
103
|
+
inputs: {
|
|
104
|
+
answer: { type: 'executionMemoryPath', path: 'answers.ask1.answer' },
|
|
105
|
+
},
|
|
106
|
+
config: {
|
|
107
|
+
strategy: 'select',
|
|
108
|
+
selector: { type: 'firstPresent', order: ['answer'] },
|
|
109
|
+
},
|
|
110
|
+
outputMapping: {
|
|
111
|
+
path: 'answers.ask1',
|
|
112
|
+
mode: 'replace',
|
|
113
|
+
map: { answer: 'output.parsed' },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
return authoringShell(graphId, [taskNode, finalizerNode], [{ id: 'edge:ask-final', from: { nodeId: taskId, portId: 'out:answer' }, to: { nodeId: finalId, portId: 'in:answer' } }], { answer: { type: 'outputsMemoryPath', path: 'answers.ask1.answer' } });
|
|
118
|
+
}
|
|
119
|
+
/** deterministic-rule local skill + select finalizer. */
|
|
120
|
+
export function buildLocalSkillAuthoringGraph(graphId) {
|
|
121
|
+
const taskId = 'rule-1';
|
|
122
|
+
const finalId = 'final';
|
|
123
|
+
const taskNode = {
|
|
124
|
+
id: taskId,
|
|
125
|
+
kind: TASK_NODE_KIND,
|
|
126
|
+
inputs: [{ id: 'in:record', direction: 'input', type: 'builtin:object', required: true }],
|
|
127
|
+
outputs: [{ id: 'out:answer', direction: 'output', type: 'builtin:object' }],
|
|
128
|
+
parameters: {
|
|
129
|
+
profile: TASK_NODE_PROFILE,
|
|
130
|
+
nodeType: 'task',
|
|
131
|
+
skillKey: 'deterministic-rule',
|
|
132
|
+
taskConfiguration: {
|
|
133
|
+
rules: [{ id: 'always', condition: { all: [] }, output: { decision: 'go' } }],
|
|
134
|
+
firstMatchWins: true,
|
|
135
|
+
},
|
|
136
|
+
executionMapping: {
|
|
137
|
+
path: 'rule',
|
|
138
|
+
mode: 'replace',
|
|
139
|
+
map: { decision: 'output.output.decision' },
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
const finalizerNode = {
|
|
144
|
+
id: finalId,
|
|
145
|
+
kind: FINALIZER_NODE_KIND,
|
|
146
|
+
inputs: [{ id: 'in:answer', direction: 'input', type: 'builtin:object', required: true }],
|
|
147
|
+
outputs: [{ id: 'out:final', direction: 'output', type: 'builtin:object' }],
|
|
148
|
+
parameters: {
|
|
149
|
+
profile: FINALIZER_NODE_PROFILE,
|
|
150
|
+
nodeType: 'finalizer',
|
|
151
|
+
finalizerType: 'select',
|
|
152
|
+
inputs: {
|
|
153
|
+
decision: { type: 'executionMemoryPath', path: 'rule.decision' },
|
|
154
|
+
},
|
|
155
|
+
config: {
|
|
156
|
+
strategy: 'select',
|
|
157
|
+
selector: { type: 'firstPresent', order: ['decision'] },
|
|
158
|
+
},
|
|
159
|
+
outputMapping: {
|
|
160
|
+
path: 'rule',
|
|
161
|
+
mode: 'replace',
|
|
162
|
+
map: { decision: 'output.parsed' },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
return authoringShell(graphId, [taskNode, finalizerNode], [{ id: 'edge:rule-final', from: { nodeId: taskId, portId: 'out:answer' }, to: { nodeId: finalId, portId: 'in:answer' } }], { decision: { type: 'outputsMemoryPath', path: 'rule.decision' } });
|
|
167
|
+
}
|
|
168
|
+
/** Fan-in Q&A graph used by graph.response mapping tests. */
|
|
169
|
+
export function buildGraphResponseMappingAuthoringGraph(graphId) {
|
|
170
|
+
const q1 = 'q1';
|
|
171
|
+
const q2 = 'q2';
|
|
172
|
+
const finalId = 'final';
|
|
173
|
+
const makeTask = (id, path, question) => ({
|
|
174
|
+
id,
|
|
175
|
+
kind: TASK_NODE_KIND,
|
|
176
|
+
inputs: [{ id: 'in:record', direction: 'input', type: 'builtin:object', required: true }],
|
|
177
|
+
outputs: [{ id: 'out:answer', direction: 'output', type: 'builtin:object' }],
|
|
178
|
+
parameters: {
|
|
179
|
+
profile: TASK_NODE_PROFILE,
|
|
180
|
+
nodeType: 'task',
|
|
181
|
+
skillKey: 'professional-answer',
|
|
182
|
+
taskVariable: { question },
|
|
183
|
+
executionMapping: {
|
|
184
|
+
path: `answers.${path}`,
|
|
185
|
+
mode: 'replace',
|
|
186
|
+
map: { shortAnswer: 'output.parsed.shortAnswer' },
|
|
187
|
+
},
|
|
188
|
+
taskConfiguration: { executionStrategies: [] },
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
const finalizerNode = {
|
|
192
|
+
id: finalId,
|
|
193
|
+
kind: FINALIZER_NODE_KIND,
|
|
194
|
+
inputs: [
|
|
195
|
+
{ id: 'in:q1', direction: 'input', type: 'builtin:object', required: true },
|
|
196
|
+
{ id: 'in:q2', direction: 'input', type: 'builtin:object', required: true },
|
|
197
|
+
],
|
|
198
|
+
outputs: [{ id: 'out:final', direction: 'output', type: 'builtin:object' }],
|
|
199
|
+
parameters: {
|
|
200
|
+
profile: FINALIZER_NODE_PROFILE,
|
|
201
|
+
nodeType: 'finalizer',
|
|
202
|
+
finalizerType: 'aggregate',
|
|
203
|
+
config: {
|
|
204
|
+
sections: [
|
|
205
|
+
{ sourceNodeId: q1, sourcePortId: 'out:answer', executionMemoryPath: 'answers.q1' },
|
|
206
|
+
{ sourceNodeId: q2, sourcePortId: 'out:answer', executionMemoryPath: 'answers.q2' },
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
const doc = authoringShell(graphId, [makeTask(q1, 'q1', 'Q1?'), makeTask(q2, 'q2', 'Q2?'), finalizerNode], [
|
|
212
|
+
{ id: 'edge:q1-final', from: { nodeId: q1, portId: 'out:answer' }, to: { nodeId: finalId, portId: 'in:q1' } },
|
|
213
|
+
{ id: 'edge:q2-final', from: { nodeId: q2, portId: 'out:answer' }, to: { nodeId: finalId, portId: 'in:q2' } },
|
|
214
|
+
], {
|
|
215
|
+
answers: {
|
|
216
|
+
type: 'firstPresent',
|
|
217
|
+
sources: [
|
|
218
|
+
{
|
|
219
|
+
answer: {
|
|
220
|
+
type: 'object',
|
|
221
|
+
properties: {
|
|
222
|
+
shortAnswer: { type: 'outputsMemoryPath', path: 'answers.q1.shortAnswer' },
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
answer: {
|
|
228
|
+
type: 'object',
|
|
229
|
+
properties: {
|
|
230
|
+
shortAnswer: { type: 'outputsMemoryPath', path: 'answers.q2.shortAnswer' },
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
return doc;
|
|
238
|
+
}
|
|
239
|
+
export function withAuthoringGraphModelConfig(doc, modelConfig) {
|
|
240
|
+
const next = structuredClone(doc);
|
|
241
|
+
const metadata = next.graph.metadata;
|
|
242
|
+
if (!metadata?.extensions)
|
|
243
|
+
return next;
|
|
244
|
+
const profile = metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
|
|
245
|
+
if (profile && typeof profile === 'object') {
|
|
246
|
+
Object.assign(profile, { modelConfig });
|
|
247
|
+
}
|
|
248
|
+
return next;
|
|
249
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuthoringGraphDocument } from '@x12i/graphenix-executable-contracts';
|
|
2
2
|
import type { ExecuteGraphInput, GraphRuntimeObject } from '../src/runtime/ExellixGraphRuntime.js';
|
|
3
|
-
/** Builds `{ plan, runtime }` for tests and hosts
|
|
4
|
-
export declare function buildExecuteGraphInput(
|
|
3
|
+
/** Builds `{ plan, runtime }` for tests and hosts with a Graphenix 2.x {@link AuthoringGraphDocument}. */
|
|
4
|
+
export declare function buildExecuteGraphInput(doc: AuthoringGraphDocument | Record<string, unknown>, runtime: GraphRuntimeObject): ExecuteGraphInput;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { compileExellixExecutablePlan } from '../src/
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { compileExellixExecutablePlan } from '../src/compile/compileExellixExecutablePlan.js';
|
|
2
|
+
import { flatTestGraphToAuthoringDocument, isAuthoringGraphDocument } from './flatGraphToAuthoring.js';
|
|
3
|
+
function normalizeAuthoringDocument(input) {
|
|
4
|
+
return isAuthoringGraphDocument(input) ? input : flatTestGraphToAuthoringDocument(input);
|
|
5
|
+
}
|
|
6
|
+
/** Builds `{ plan, runtime }` for tests and hosts with a Graphenix 2.x {@link AuthoringGraphDocument}. */
|
|
7
|
+
export function buildExecuteGraphInput(doc, runtime) {
|
|
4
8
|
return {
|
|
5
|
-
plan: compileExellixExecutablePlan(
|
|
9
|
+
plan: compileExellixExecutablePlan(normalizeAuthoringDocument(doc), runtime),
|
|
6
10
|
runtime,
|
|
7
11
|
};
|
|
8
12
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AuthoringGraphDocument } from '@x12i/graphenix-executable-contracts';
|
|
2
|
+
export declare function isAuthoringGraphDocument(v: unknown): v is AuthoringGraphDocument;
|
|
3
|
+
export declare function defaultExecutableModelConfig(): {
|
|
4
|
+
version: "graph-model-config/v1";
|
|
5
|
+
cases: {
|
|
6
|
+
id: string;
|
|
7
|
+
modelConfig: {
|
|
8
|
+
preActionModel: {
|
|
9
|
+
kind: "profileChoice";
|
|
10
|
+
key: string;
|
|
11
|
+
};
|
|
12
|
+
skillModel: {
|
|
13
|
+
kind: "profileChoice";
|
|
14
|
+
key: string;
|
|
15
|
+
};
|
|
16
|
+
postActionModel: {
|
|
17
|
+
kind: "profileChoice";
|
|
18
|
+
key: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}[];
|
|
22
|
+
fallbackPolicy: {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
allowedTriggers: readonly ["nodeSlotMissing", "nodeModelUnavailable", "nodeModelUnsupported", "nodeProviderNotConfigured", "nodeModelRateLimited", "nodeModelTransientFailure"];
|
|
25
|
+
maxAttemptsPerSlot: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/** Converts legacy flat exellix test graphs into Graphenix 2.x {@link AuthoringGraphDocument}. */
|
|
29
|
+
export declare function flatTestGraphToAuthoringDocument(flat: Record<string, unknown>): AuthoringGraphDocument;
|