@exellix/graph-engine 7.8.0 → 7.8.2

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,10 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.8.2
4
+
5
+ ### Fixed
6
+
7
+ - **ai-tasks error propagation:** Node failures preserve upstream `error.code` and full `error.message` from `@exellix/ai-tasks` (no `TASK_RUN_FAILED: {skillKey}` message wrapper).
8
+ - **Activix node fail records:** `failRecord` updates include `errorCode` alongside the upstream error message.
9
+
10
+ ### Changed
11
+
12
+ - **Dependencies:** `@exellix/ai-tasks` ^8.8.0 (transitive: `@exellix/ai-skills` ≥6.5.0, `@exellix/xynthesis` ≥4.6.0, `@x12i/ai-profiles` ≥3.2.0).
13
+
14
+ ### Added
15
+
16
+ - **Tests:** SubNets (`graph-qcrbz6t`) synthesis PRE alias pass-through; ai-tasks `SKILL_MODEL_RESOLUTION_FAILED` / `XYNTHESIS_*` error surfacing on `node:fail` and Activix `failRecord`.
17
+
18
+ ## 7.8.1
19
+
20
+ ### Changed
21
+
22
+ - **Dependencies:** `@exellix/ai-tasks` ^8.7.0 (transitive floors: `@exellix/ai-skills` ≥6.3.7, `@exellix/xynthesis` ≥4.4.9, `@x12i/ai-gateway` ≥10.0.6, `@x12i/ai-profiles` ≥2.1.1).
23
+ - **Synthesize finalizer:** outbound `runTask` includes `executionStrategies: []`.
24
+ - **Step retry:** token-limit retries no longer mutate `llmCall` completion budget fields (Optimixer-owned).
25
+ - **`buildMainLlmCallForRunTask`:** strips `maxTokens`, `maxTokensCap`, and legacy token keys from forwarded `llmCall`.
26
+ - **`buildAiTasksRunTaskRequest`:** rejects provider API key passthrough on `taskConfiguration` (env-only).
27
+ - **Default graph profile triplet:** `cheap/default`, `pro/default`, `cheap/default`.
28
+ - **testkit:** removed `xynthesisModel` debug fallback in `RealTasksClient`.
29
+
3
30
  ## 7.7.9
4
31
 
5
32
  ### Changed
6
33
 
7
34
  - **Documentation:** Align README, [`.docs/exellix-graph-engine-format.md`](.docs/exellix-graph-engine-format.md), format docs, and [`.docs/ai-tasks-model-profile-aliases-7x.md`](.docs/ai-tasks-model-profile-aliases-7x.md) with ai-tasks **8.6.8** / funcx **4.4.4**: three-slot `modelConfig`, graph-only selection (7.7+), partial task overrides (7.7.8+), studio preflight via `@exellix/graph-composer`, funcx-for-runx vs xynthesis-for-execution-strategies.
35
+ - **Cross-package boundary:** [`.docs/graph-engine-ai-tasks-boundary.md`](.docs/graph-engine-ai-tasks-boundary.md) — normative graph-engine ↔ ai-tasks contract; [upstream-doc-patches/@exellix/ai-tasks/](upstream-doc-patches/@exellix/ai-tasks/README.md) — copy-ready ai-tasks doc fixes (RUNTASK_REQUEST, flow-io xynthesis-pre/post, workplan status).
8
36
 
9
37
  ### Dependencies
10
38
 
package/README.md CHANGED
@@ -32,7 +32,7 @@ A minimal, focused SDK for executing graphs in the exellix ecosystem.
32
32
  | Layer 01 / 08 graph entry & response contracts | [`.docs/graph-io-visibility.md`](.docs/graph-io-visibility.md) |
33
33
  | Graph entry `dataFilters` v1 / public evaluator | [`.docs/data-filters-evaluation.md`](.docs/data-filters-evaluation.md) |
34
34
  | Task-node `conditions` + conditional `modelConfig.cases` (runx) | [`.docs/task-node-conditions-evaluation.md`](.docs/task-node-conditions-evaluation.md) |
35
- | **Model profile aliases** (7.x+: graph = aliases / `profile/choice`; ai-tasks resolves per phase) | [`BREAKING-CHANGES.md`](BREAKING-CHANGES.md) §7.6 / §7.7, [`.docs/ai-tasks-model-profile-aliases-7x.md`](.docs/ai-tasks-model-profile-aliases-7x.md) |
35
+ | **Model profile aliases** (7.x+: graph = aliases / `profile/choice`; ai-tasks resolves per phase) | [`BREAKING-CHANGES.md`](BREAKING-CHANGES.md) §7.6 / §7.7, [`.docs/ai-tasks-model-profile-aliases-7x.md`](.docs/ai-tasks-model-profile-aliases-7x.md), [`.docs/graph-engine-ai-tasks-boundary.md`](.docs/graph-engine-ai-tasks-boundary.md) |
36
36
  | Platform vs implementation (no domain operators in schema) | [`.docs/platform-generic-vs-implementation.md`](.docs/platform-generic-vs-implementation.md) |
37
37
  | Activix records, `runContext`, collection tracking (`@x12i/activix` 8.4+) | [`.docs/activix-records.md`](.docs/activix-records.md) |
38
38
  | Bundled graph examples & bundle README | [`graphs/README.md`](graphs/README.md) |
@@ -149,11 +149,18 @@ export function createActivixNodeActivityIntegration(ax, options) {
149
149
  : typeof err === 'object' && err && 'message' in err
150
150
  ? String(err.message)
151
151
  : String(err ?? 'unknown error');
152
+ const errorCode = (() => {
153
+ if (err == null || typeof err !== 'object')
154
+ return undefined;
155
+ const code = err.code;
156
+ return code != null ? String(code) : undefined;
157
+ })();
152
158
  const outerResponse = nodeEvent.data?.response;
153
159
  const outerMemoryEnd = nodeEvent.data?.memoryAfter;
154
160
  const recordId = await recordPromise;
155
161
  await ax.failRecord(recordId, message, {
156
162
  failedAt: nodeEvent.timestamp,
163
+ ...(errorCode != null ? { errorCode } : {}),
157
164
  outer: {
158
165
  output: {
159
166
  response: outerResponse,
@@ -422,6 +422,7 @@ export function createExellixGraphRuntime(opts) {
422
422
  },
423
423
  modelConfig: wireModelConfig,
424
424
  llmCall: effectiveLlmCall,
425
+ executionStrategies: [],
425
426
  ...(forwardRunTaskTrace ? { executionMode: "trace" } : {}),
426
427
  ...((input.runTaskDiagnostics ?? opts.runTaskDiagnostics) != null
427
428
  ? { diagnostics: input.runTaskDiagnostics ?? opts.runTaskDiagnostics }
@@ -962,8 +963,10 @@ export function createExellixGraphRuntime(opts) {
962
963
  const resMeta = res.metadata ?? res.meta;
963
964
  const taskRunLog = [...retryOutcome.syntheticRunLog, ...extractTaskRunLogFromMetadata(resMeta)];
964
965
  const logxerCorrelationId = extractLogxerCorrelationFromMetadata(resMeta);
965
- const err = new Error(`TASK_RUN_FAILED: ${skillKey}`);
966
- err.code = res.error?.code ?? "TASK_RUN_FAILED";
966
+ const taskErrorMessage = res.error?.message ?? "Task run failed";
967
+ const taskErrorCode = res.error?.code ?? "TASK_RUN_FAILED";
968
+ const err = new Error(taskErrorMessage);
969
+ err.code = taskErrorCode;
967
970
  err.skillKey = skillKey;
968
971
  err.diagnostics = res.diagnostics;
969
972
  err.nodeId = input.node?.id;
@@ -13,6 +13,8 @@ import type { Job } from '../types/refs.js';
13
13
  import type { RunTaskModelConfigWire } from './graphAiModelConfig.js';
14
14
  import type { ExecutionStepOption } from '../types/options.js';
15
15
  import type { ResolvedNarrixWirePayload } from '../types/narrix.js';
16
+ /** Request/metadata keys that must never carry provider API secrets (env-only). */
17
+ export declare const FORBIDDEN_RUN_TASK_SECRET_KEYS: readonly ["openrouterApiKey", "OPENROUTER_API_KEY", "OPEN_ROUTER_KEY", "apiKey", "api_key", "openRouterApiKey"];
16
18
  /** Reads task-node `taskConfiguration` keys forwarded to `@exellix/ai-tasks` `RunTaskRequest` (runtime strategy / Narrix wiring). */
17
19
  export declare function extractRunTaskStrategyOverrides(taskConfiguration: Record<string, unknown> | undefined | null): Partial<Pick<BuildAiTasksRunTaskRequestArgs, 'narrixMode' | 'inputStrategyKey' | 'narrixInput'>>;
18
20
  /** Optional `RunTaskRequest` fields commonly authored on task-node `taskConfiguration` (whitelist — closed merge order). */
@@ -1,7 +1,27 @@
1
1
  import { buildRunTaskTaskConfigurationForward } from './buildRunTaskTaskConfigurationForward.js';
2
2
  import { normalizeSmartInputConfigForRunTask } from './smartInputPaths.js';
3
+ /** Request/metadata keys that must never carry provider API secrets (env-only). */
4
+ export const FORBIDDEN_RUN_TASK_SECRET_KEYS = [
5
+ 'openrouterApiKey',
6
+ 'OPENROUTER_API_KEY',
7
+ 'OPEN_ROUTER_KEY',
8
+ 'apiKey',
9
+ 'api_key',
10
+ 'openRouterApiKey',
11
+ ];
12
+ function assertNoSecretPassthrough(taskConfiguration, context) {
13
+ if (taskConfiguration == null || typeof taskConfiguration !== 'object' || Array.isArray(taskConfiguration)) {
14
+ return;
15
+ }
16
+ for (const key of FORBIDDEN_RUN_TASK_SECRET_KEYS) {
17
+ if (key in taskConfiguration && taskConfiguration[key] !== undefined) {
18
+ throw new Error(`${context}: taskConfiguration.${key} is forbidden — provider API keys belong in process environment only (e.g. OPENROUTER_API_KEY).`);
19
+ }
20
+ }
21
+ }
3
22
  /** Reads task-node `taskConfiguration` keys forwarded to `@exellix/ai-tasks` `RunTaskRequest` (runtime strategy / Narrix wiring). */
4
23
  export function extractRunTaskStrategyOverrides(taskConfiguration) {
24
+ assertNoSecretPassthrough(taskConfiguration, 'extractRunTaskStrategyOverrides');
5
25
  if (taskConfiguration == null || typeof taskConfiguration !== 'object' || Array.isArray(taskConfiguration))
6
26
  return {};
7
27
  const m = taskConfiguration;
@@ -25,6 +45,7 @@ export function extractRunTaskStrategyOverrides(taskConfiguration) {
25
45
  * (`RunSkillRequest` / `RunTaskRequest` extras not covered by {@link extractRunTaskStrategyOverrides}).
26
46
  */
27
47
  export function extractRunTaskMetadataPassthrough(taskConfiguration) {
48
+ assertNoSecretPassthrough(taskConfiguration, 'extractRunTaskMetadataPassthrough');
28
49
  if (taskConfiguration == null || typeof taskConfiguration !== 'object' || Array.isArray(taskConfiguration))
29
50
  return {};
30
51
  const m = taskConfiguration;
@@ -3,9 +3,9 @@ import { ExellixGraphErrorCode } from '../errors/exellixGraphErrorCodes.js';
3
3
  import { isGraphAiModelConfig } from './modelConfigSelection.js';
4
4
  /** Profile alias names used when no modelConfig tier resolves. */
5
5
  export const DEFAULT_GRAPH_AI_MODEL_PROFILE_CONFIG = {
6
- preActionModel: 'cheap',
7
- skillModel: 'balanced',
8
- postActionModel: 'cheap',
6
+ preActionModel: 'cheap/default',
7
+ skillModel: 'pro/default',
8
+ postActionModel: 'cheap/default',
9
9
  };
10
10
  /**
11
11
  * Illustrative concrete ids for {@link DEFAULT_GRAPH_AI_MODEL_PROFILE_CONFIG}.
@@ -3,6 +3,9 @@
3
3
  */
4
4
  import type { LlmCallConfig } from '@exellix/ai-tasks';
5
5
  import type { RunTaskModelConfigWire } from './graphAiModelConfig.js';
6
+ /** Completion budget fields removed from outbound runTask wires (ai-tasks 8.6+ / Optimixer-owned). */
7
+ export declare const STRIPPED_LLM_CALL_TOKEN_KEYS: readonly ["maxTokens", "maxTokensCap", "max_tokens", "max_completion_tokens", "max_output_tokens"];
8
+ export declare function stripLlmCallTokenCapFields(llmCall: Record<string, unknown> | undefined | null): Record<string, unknown> | undefined;
6
9
  export declare function mergeDefinedLlmCallParts(...parts: Array<Record<string, unknown> | undefined | null>): Record<string, unknown> | undefined;
7
10
  /**
8
11
  * MAIN-only `llmCall` for ai-tasks 8.4+: `model` is always {@link RunTaskModelConfigWire.skillModel};
@@ -1,3 +1,20 @@
1
+ /** Completion budget fields removed from outbound runTask wires (ai-tasks 8.6+ / Optimixer-owned). */
2
+ export const STRIPPED_LLM_CALL_TOKEN_KEYS = [
3
+ 'maxTokens',
4
+ 'maxTokensCap',
5
+ 'max_tokens',
6
+ 'max_completion_tokens',
7
+ 'max_output_tokens',
8
+ ];
9
+ export function stripLlmCallTokenCapFields(llmCall) {
10
+ if (!llmCall || typeof llmCall !== 'object' || Array.isArray(llmCall))
11
+ return undefined;
12
+ const out = { ...llmCall };
13
+ for (const key of STRIPPED_LLM_CALL_TOKEN_KEYS) {
14
+ delete out[key];
15
+ }
16
+ return Object.keys(out).length > 0 ? out : undefined;
17
+ }
1
18
  export function mergeDefinedLlmCallParts(...parts) {
2
19
  const out = {};
3
20
  for (const p of parts) {
@@ -8,6 +25,9 @@ export function mergeDefinedLlmCallParts(...parts) {
8
25
  out[k] = v;
9
26
  }
10
27
  }
28
+ for (const key of STRIPPED_LLM_CALL_TOKEN_KEYS) {
29
+ delete out[key];
30
+ }
11
31
  return Object.keys(out).length > 0 ? out : undefined;
12
32
  }
13
33
  /**
@@ -2,13 +2,8 @@ import type { RunLogEntry } from '../types/runLog.js';
2
2
  import type { RunTaskRequest, RunTaskResponse, StepRetryPolicy } from '../types/options.js';
3
3
  import type { TaskNode } from '../types/refs.js';
4
4
  import type { StepAttemptRecord } from '../types/results.js';
5
- export type ResolvedStepRetryPolicy = Required<Pick<StepRetryPolicy, 'maxAttempts' | 'retryOnTimeout' | 'retryOnTokenLimit' | 'tokenBumpMultiplier' | 'tokenBumpCap' | 'baseMaxTokensFallback'>>;
5
+ export type ResolvedStepRetryPolicy = Required<Pick<StepRetryPolicy, 'maxAttempts' | 'retryOnTimeout' | 'retryOnTokenLimit'>>;
6
6
  export declare function resolveStepRetryPolicy(graphPolicy: StepRetryPolicy | undefined, node: Pick<TaskNode, 'taskConfiguration'> | undefined): ResolvedStepRetryPolicy;
7
- /**
8
- * Reads the effective completion cap from outbound `llmCall`.
9
- * ai-tasks v8 canonical field is `maxTokensCap`; legacy `maxTokens` / `max_tokens` still honored.
10
- */
11
- export declare function readMaxTokensFromRunTaskRequest(req: RunTaskRequest): number | undefined;
12
7
  export type RunTaskWithRetryResult = {
13
8
  response: RunTaskResponse;
14
9
  attempts: StepAttemptRecord[];
@@ -4,9 +4,6 @@ const DEFAULT_POLICY = {
4
4
  maxAttempts: 3,
5
5
  retryOnTimeout: true,
6
6
  retryOnTokenLimit: true,
7
- tokenBumpMultiplier: 2,
8
- tokenBumpCap: 16_000,
9
- baseMaxTokensFallback: 2000,
10
7
  };
11
8
  export function resolveStepRetryPolicy(graphPolicy, node) {
12
9
  const nodeRaw = node?.taskConfiguration?.stepRetryPolicy;
@@ -17,24 +14,8 @@ export function resolveStepRetryPolicy(graphPolicy, node) {
17
14
  maxAttempts,
18
15
  retryOnTimeout: merged.retryOnTimeout !== false,
19
16
  retryOnTokenLimit: merged.retryOnTokenLimit !== false,
20
- tokenBumpMultiplier: Math.max(1, merged.tokenBumpMultiplier ?? DEFAULT_POLICY.tokenBumpMultiplier),
21
- tokenBumpCap: Math.max(1, merged.tokenBumpCap ?? DEFAULT_POLICY.tokenBumpCap),
22
- baseMaxTokensFallback: Math.max(1, merged.baseMaxTokensFallback ?? DEFAULT_POLICY.baseMaxTokensFallback),
23
17
  };
24
18
  }
25
- function readNum(v) {
26
- return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
27
- }
28
- /**
29
- * Reads the effective completion cap from outbound `llmCall`.
30
- * ai-tasks v8 canonical field is `maxTokensCap`; legacy `maxTokens` / `max_tokens` still honored.
31
- */
32
- export function readMaxTokensFromRunTaskRequest(req) {
33
- const llm = req.llmCall;
34
- return (readNum(llm?.maxTokensCap) ??
35
- readNum(llm?.maxTokens) ??
36
- readNum(llm?.max_tokens));
37
- }
38
19
  function shallowCloneRunTaskRequest(req) {
39
20
  return {
40
21
  ...req,
@@ -49,16 +30,6 @@ function shallowCloneRunTaskRequest(req) {
49
30
  : {}),
50
31
  };
51
32
  }
52
- function applyTokenBump(workingReq, policy) {
53
- const current = readMaxTokensFromRunTaskRequest(workingReq) ?? policy.baseMaxTokensFallback;
54
- const after = Math.min(policy.tokenBumpCap, Math.floor(current * policy.tokenBumpMultiplier));
55
- const bumped = workingReq.llmCall != null && typeof workingReq.llmCall === 'object' && !Array.isArray(workingReq.llmCall)
56
- ? { ...workingReq.llmCall }
57
- : {};
58
- bumped.maxTokensCap = after;
59
- workingReq.llmCall = bumped;
60
- return { before: current, after };
61
- }
62
33
  function classifyThrownError(err) {
63
34
  if (err == null || typeof err !== 'object')
64
35
  return 'other';
@@ -140,7 +111,6 @@ export async function runRunTaskWithRetry(args) {
140
111
  }
141
112
  const endedAt = Date.now();
142
113
  const durationMs = endedAt - startedAt;
143
- const maxTok = readMaxTokensFromRunTaskRequest(workingReq);
144
114
  if (thrown != null) {
145
115
  const c = classifyThrownError(thrown);
146
116
  attempts.push({
@@ -152,7 +122,6 @@ export async function runRunTaskWithRetry(args) {
152
122
  classification: c,
153
123
  errorCode: thrown?.code,
154
124
  errorMessage: thrown?.message,
155
- maxTokensRequested: maxTok,
156
125
  });
157
126
  pushSyntheticRunLog(syntheticRunLog, {
158
127
  nodeId,
@@ -162,7 +131,6 @@ export async function runRunTaskWithRetry(args) {
162
131
  data: {
163
132
  classification: c,
164
133
  errorCode: thrown?.code,
165
- maxTokensRequested: maxTok,
166
134
  },
167
135
  });
168
136
  if (!shouldRetryClassification(c, policy, attemptIndex)) {
@@ -172,13 +140,12 @@ export async function runRunTaskWithRetry(args) {
172
140
  throw err;
173
141
  }
174
142
  if (c === 'token-limit' && policy.retryOnTokenLimit) {
175
- const { before, after } = applyTokenBump(workingReq, policy);
176
143
  pushSyntheticRunLog(syntheticRunLog, {
177
144
  nodeId,
178
145
  skillKey,
179
146
  level: 'info',
180
- message: `step retry ${attemptIndex + 2}/${policy.maxAttempts}: token-limit bump maxTokensCap ${before} -> ${after}`,
181
- data: { classification: c, maxTokensBefore: before, maxTokensAfter: after, attempt: attemptIndex + 1 },
147
+ message: `step retry ${attemptIndex + 2}/${policy.maxAttempts}: token-limit (completion budget is Optimixer-owned; request unchanged)`,
148
+ data: { classification: c, attempt: attemptIndex + 1 },
182
149
  });
183
150
  }
184
151
  continue;
@@ -196,7 +163,6 @@ export async function runRunTaskWithRetry(args) {
196
163
  startedAt,
197
164
  endedAt,
198
165
  durationMs,
199
- maxTokensRequested: maxTok,
200
166
  });
201
167
  return { response, attempts, syntheticRunLog, lastRequest: workingReq };
202
168
  }
@@ -210,7 +176,6 @@ export async function runRunTaskWithRetry(args) {
210
176
  classification: c,
211
177
  errorCode: response.error?.code,
212
178
  errorMessage: response.error?.message,
213
- maxTokensRequested: maxTok,
214
179
  });
215
180
  pushSyntheticRunLog(syntheticRunLog, {
216
181
  nodeId,
@@ -220,20 +185,18 @@ export async function runRunTaskWithRetry(args) {
220
185
  data: {
221
186
  classification: c,
222
187
  errorCode: response.error?.code,
223
- maxTokensRequested: maxTok,
224
188
  },
225
189
  });
226
190
  if (!shouldRetryClassification(c, policy, attemptIndex)) {
227
191
  return { response, attempts, syntheticRunLog, lastRequest: workingReq };
228
192
  }
229
193
  if (c === 'token-limit' && policy.retryOnTokenLimit) {
230
- const { before, after } = applyTokenBump(workingReq, policy);
231
194
  pushSyntheticRunLog(syntheticRunLog, {
232
195
  nodeId,
233
196
  skillKey,
234
197
  level: 'info',
235
- message: `step retry ${attemptIndex + 2}/${policy.maxAttempts}: token-limit bump maxTokensCap ${before} -> ${after}`,
236
- data: { classification: c, maxTokensBefore: before, maxTokensAfter: after, attempt: attemptIndex + 1 },
198
+ message: `step retry ${attemptIndex + 2}/${policy.maxAttempts}: token-limit (completion budget is Optimixer-owned; request unchanged)`,
199
+ data: { classification: c, attempt: attemptIndex + 1 },
237
200
  });
238
201
  }
239
202
  }
@@ -31,17 +31,8 @@ export interface StepRetryPolicy {
31
31
  maxAttempts?: number;
32
32
  /** When false, timeouts do not trigger an automatic retry. Default **true**. */
33
33
  retryOnTimeout?: boolean;
34
- /** When false, token-limit signals do not trigger retry / bump. Default **true**. */
34
+ /** When false, token-limit signals do not trigger retry. Default **true**. Completion budget is Optimixer-owned — retries re-run unchanged. */
35
35
  retryOnTokenLimit?: boolean;
36
- /** Applied to effective max tokens before each token-limit retry (default **2**). */
37
- tokenBumpMultiplier?: number;
38
- /** Upper bound for `maxTokens` after bump (default **16000**). */
39
- tokenBumpCap?: number;
40
- /**
41
- * Used when `llmCall.maxTokensCap` (or legacy `maxTokens` / `max_tokens`) is unset on the outbound request
42
- * before the first token-limit retry bump (default **2000**).
43
- */
44
- baseMaxTokensFallback?: number;
45
36
  }
46
37
  /** MAIN gate before `runTask`: empty execution input / synthesis context (graphs-studio G1, G4). */
47
38
  export type MainReadinessPolicy = 'fail' | 'warn' | 'off';
@@ -83,16 +83,11 @@ export class RealTasksClient {
83
83
  const mc = aiTasksRequest.modelConfig;
84
84
  const effective = mc
85
85
  ? {
86
- preActionModel: mc.preActionModel ?? mc.xynthesisModel,
86
+ preActionModel: mc.preActionModel,
87
87
  skillModel: mc.skillModel,
88
- postActionModel: mc.postActionModel ?? mc.skillModel,
88
+ postActionModel: mc.postActionModel,
89
89
  }
90
- : aiTasksRequest.config
91
- ? {
92
- provider: aiTasksRequest.config.provider,
93
- model: aiTasksRequest.config.model,
94
- }
95
- : { provider: '(none)', model: '(none)' };
90
+ : { preActionModel: '(none)', skillModel: '(none)', postActionModel: '(none)' };
96
91
  console.log('[AI_PROVIDER] RealTasksClient → ai-tasks:', effective);
97
92
  }
98
93
  const sdk = await getPackagedClientPromise();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exellix/graph-engine",
3
- "version": "7.8.0",
3
+ "version": "7.8.2",
4
4
  "type": "module",
5
5
  "description": "Graph executor SDK",
6
6
  "main": "dist/src/index.js",
@@ -25,7 +25,7 @@
25
25
  "scripts": {
26
26
  "prebuild": "node scripts/clean-dist.mjs",
27
27
  "build": "tsc",
28
- "test": "npm run build && npm run check:no-legacy && tsx --test --test-force-exit tests/model-alias-contract.test.ts tests/reports-fixtures-pre-synthesis.test.ts tests/passthrough-parity.test.ts tests/step-retry-llm-call.test.ts tests/run-log-diagnostics.test.ts",
28
+ "test": "npm run build && npm run check:no-legacy && tsx --test --test-force-exit tests/model-alias-contract.test.ts tests/ai-tasks-error-propagation.test.ts tests/reports-fixtures-pre-synthesis.test.ts tests/passthrough-parity.test.ts tests/step-retry-llm-call.test.ts tests/run-log-diagnostics.test.ts",
29
29
  "test:full": "npm run build && npm run check:no-legacy && tsx --test --test-force-exit tests/graph-engine.test.ts tests/passthrough-parity.test.ts tests/task-node-run-task-preflight.test.ts tests/reports-fixtures-pre-synthesis.test.ts tests/model-alias-contract.test.ts tests/step-retry-llm-call.test.ts",
30
30
  "test:live": "npm run run:pre-synthesis",
31
31
  "test:subnets-graph-fixture": "npm run build && node --test tests/subnets-graph.fixture.test.mjs",
@@ -52,7 +52,7 @@
52
52
  "access": "public"
53
53
  },
54
54
  "dependencies": {
55
- "@exellix/ai-tasks": "^8.6.8",
55
+ "@exellix/ai-tasks": "^8.8.0",
56
56
  "@x12i/activix": "8.5.0",
57
57
  "@x12i/catalox": "5.1.3",
58
58
  "@x12i/env": "4.0.1",