@exellix/ai-tasks 8.1.16 → 8.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.env.example +10 -0
  2. package/dist/core/task-sdk.d.ts.map +1 -1
  3. package/dist/core/task-sdk.js +1187 -1159
  4. package/dist/core/task-sdk.js.map +1 -1
  5. package/dist/errors/runTaskExecutionError.d.ts +63 -0
  6. package/dist/errors/runTaskExecutionError.d.ts.map +1 -0
  7. package/dist/errors/runTaskExecutionError.js +167 -0
  8. package/dist/errors/runTaskExecutionError.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +5 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/invocation/buildRunTaskResultMeta.d.ts +7 -0
  14. package/dist/invocation/buildRunTaskResultMeta.d.ts.map +1 -0
  15. package/dist/invocation/buildRunTaskResultMeta.js +38 -0
  16. package/dist/invocation/buildRunTaskResultMeta.js.map +1 -0
  17. package/dist/invocation/formatEngineLabel.d.ts +4 -0
  18. package/dist/invocation/formatEngineLabel.d.ts.map +1 -0
  19. package/dist/invocation/formatEngineLabel.js +19 -0
  20. package/dist/invocation/formatEngineLabel.js.map +1 -0
  21. package/dist/invocation/index.d.ts +9 -0
  22. package/dist/invocation/index.d.ts.map +1 -0
  23. package/dist/invocation/index.js +8 -0
  24. package/dist/invocation/index.js.map +1 -0
  25. package/dist/invocation/invocationPolicy.d.ts +6 -0
  26. package/dist/invocation/invocationPolicy.d.ts.map +1 -0
  27. package/dist/invocation/invocationPolicy.js +6 -0
  28. package/dist/invocation/invocationPolicy.js.map +1 -0
  29. package/dist/invocation/parseProfileSlot.d.ts +6 -0
  30. package/dist/invocation/parseProfileSlot.d.ts.map +1 -0
  31. package/dist/invocation/parseProfileSlot.js +12 -0
  32. package/dist/invocation/parseProfileSlot.js.map +1 -0
  33. package/dist/invocation/preferOpenRouterPolicy.d.ts +37 -0
  34. package/dist/invocation/preferOpenRouterPolicy.d.ts.map +1 -0
  35. package/dist/invocation/preferOpenRouterPolicy.js +81 -0
  36. package/dist/invocation/preferOpenRouterPolicy.js.map +1 -0
  37. package/dist/invocation/resolveInvocationPlan.d.ts +7 -0
  38. package/dist/invocation/resolveInvocationPlan.d.ts.map +1 -0
  39. package/dist/invocation/resolveInvocationPlan.js +40 -0
  40. package/dist/invocation/resolveInvocationPlan.js.map +1 -0
  41. package/dist/invocation/resolveProfileInvocationRouting.d.ts +31 -0
  42. package/dist/invocation/resolveProfileInvocationRouting.d.ts.map +1 -0
  43. package/dist/invocation/resolveProfileInvocationRouting.js +140 -0
  44. package/dist/invocation/resolveProfileInvocationRouting.js.map +1 -0
  45. package/dist/invocation/types.d.ts +67 -0
  46. package/dist/invocation/types.d.ts.map +1 -0
  47. package/dist/invocation/types.js +2 -0
  48. package/dist/invocation/types.js.map +1 -0
  49. package/dist/logxer/aiTasksDiagnosticCodes.d.ts +1 -0
  50. package/dist/logxer/aiTasksDiagnosticCodes.d.ts.map +1 -1
  51. package/dist/logxer/aiTasksDiagnosticCodes.js +1 -0
  52. package/dist/logxer/aiTasksDiagnosticCodes.js.map +1 -1
  53. package/dist/observability/classifyRunTaskFailure.d.ts +33 -0
  54. package/dist/observability/classifyRunTaskFailure.d.ts.map +1 -0
  55. package/dist/observability/classifyRunTaskFailure.js +111 -0
  56. package/dist/observability/classifyRunTaskFailure.js.map +1 -0
  57. package/dist/observability/llmRouteContext.d.ts +26 -0
  58. package/dist/observability/llmRouteContext.d.ts.map +1 -0
  59. package/dist/observability/llmRouteContext.js +92 -0
  60. package/dist/observability/llmRouteContext.js.map +1 -0
  61. package/dist/observability/logRunTaskFailure.d.ts +10 -0
  62. package/dist/observability/logRunTaskFailure.d.ts.map +1 -0
  63. package/dist/observability/logRunTaskFailure.js +87 -0
  64. package/dist/observability/logRunTaskFailure.js.map +1 -0
  65. package/dist/strategies/direct-execution-strategy.d.ts.map +1 -1
  66. package/dist/strategies/direct-execution-strategy.js +38 -4
  67. package/dist/strategies/direct-execution-strategy.js.map +1 -1
  68. package/dist/types/index.d.ts +1 -0
  69. package/dist/types/index.d.ts.map +1 -1
  70. package/dist/types/index.js.map +1 -1
  71. package/dist/utils/aiProfileModelFormat.d.ts +9 -0
  72. package/dist/utils/aiProfileModelFormat.d.ts.map +1 -0
  73. package/dist/utils/aiProfileModelFormat.js +116 -0
  74. package/dist/utils/aiProfileModelFormat.js.map +1 -0
  75. package/dist/utils/resolveAiProfileModel.d.ts +8 -7
  76. package/dist/utils/resolveAiProfileModel.d.ts.map +1 -1
  77. package/dist/utils/resolveAiProfileModel.js +15 -108
  78. package/dist/utils/resolveAiProfileModel.js.map +1 -1
  79. package/documenations/upstream-feature-requests/logxer-failure-classification-and-causal-diagnostics.md +403 -0
  80. package/package.json +7 -7
@@ -6,6 +6,7 @@ import { buildExecutionStrategyRequestPayload, runOptimizerFuncx, runPlannerFunc
6
6
  import { resolveSafeExecutionStrategyCatalogDefaultFunctionId } from "../execution-strategies/executionStrategyCatalogMetadata.js";
7
7
  import { SYNTHESIZED_CONTEXT } from "../types/index.js";
8
8
  import { runAuditPostStep } from "../post-steps/audit/runAudit.js";
9
+ import { buildRunTaskResultMetaFromModelId } from "../invocation/buildRunTaskResultMeta.js";
9
10
  import { runPolishPostStep } from "../post-steps/polish/runPolish.js";
10
11
  import { getLocalTask } from "../localTasks/registry.js";
11
12
  import { registerBuiltInLocalTasks } from "../localTasks/index.js";
@@ -16,6 +17,7 @@ import { DebugLogAbstract, fieldEvidence } from "@x12i/logxer";
16
17
  import { configureFuncxLogging } from "@x12i/funcx";
17
18
  import { AI_TASKS_DIAGNOSTIC_CODES } from "../logxer/aiTasksDiagnosticCodes.js";
18
19
  import { patchRunTaskLogContext, runAiTasksWithObservabilityContext, } from "../logxer/aiTasksLogContext.js";
20
+ import { logAndEnrichRunTaskFailure } from "../observability/logRunTaskFailure.js";
19
21
  import { getAiTasksLogxer } from "../logxer/packageLogxers.js";
20
22
  import { assertRequiredRunSkillCorrelation } from "../utils/assertRequiredRunSkillCorrelation.js";
21
23
  import { compileTaskConfigurationOnRunTaskRequest } from "../compile/compileTaskConfiguration.js";
@@ -449,183 +451,165 @@ export class WorexClientTasks {
449
451
  };
450
452
  };
451
453
  return runAiTasksWithObservabilityContext({ logging: this.stackLogging }, async () => {
452
- // `@exellix/ai-skills` requires stable ids on each gateway request; callers may omit for simple runs.
453
- const taskId = input.taskId?.trim() ? input.taskId : randomUUID();
454
- const jobId = input.jobId?.trim() ? input.jobId : randomUUID();
455
- input.taskId = taskId;
456
- input.jobId = jobId;
457
- // Optional activix tracking (non-fatal).
458
- const ax = await getActivixClient().catch(() => null);
459
- const correlationId = ax ? taskId : undefined;
460
- patchRunTaskLogContext({
461
- jobId,
462
- taskId,
463
- correlationId,
464
- graphId: input.graphId,
465
- nodeId: input.nodeId,
466
- });
467
- const coreSkillId = input.coreSkillId;
468
- const upstreamIdentity = isRecord(input.identity) ? input.identity : undefined;
469
- const executingSkillId = coreSkillId ?? input.skillKey;
470
- const effectiveIdentity = {
471
- ...(upstreamIdentity ?? {}),
472
- ...(upstreamIdentity?.taskId ? {} : { taskId }),
473
- ...(upstreamIdentity?.skillId ? {} : { skillId: executingSkillId }),
474
- };
475
- const normalizedSmartInput = input.smartInput !== undefined && input.smartInput !== null
476
- ? normalizeSmartInputConfig(input.smartInput)
477
- : undefined;
478
- let request = withDefaultDecisionValidation({
479
- ...input,
480
- identity: effectiveIdentity,
481
- ...(normalizedSmartInput !== undefined ? { smartInput: normalizedSmartInput } : {}),
482
- });
483
- let xynthesizedPatchAccumulator;
484
- const knobs = resolveRunTaskRuntimeKnobs(request);
485
- const baseTraceMeta = () => ({
486
- jobId,
487
- taskId,
454
+ const failContext = () => ({
488
455
  skillKey: input.skillKey,
489
- executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
490
- narrixMode: knobs.narrixMode,
491
- agentId: input.agentId,
456
+ jobId: input.jobId,
457
+ taskId: input.taskId,
492
458
  graphId: input.graphId,
493
459
  nodeId: input.nodeId,
494
- prevNodeId: input.prevNodeId,
495
- masterSkillId: input.masterSkillId,
496
- masterSkillActivityId: input.masterSkillActivityId,
497
- hasPipeline: Array.isArray(input.executionPipeline) && input.executionPipeline.length > 0,
498
- hasNarrix: !!input.narrix,
499
- hasNarrixInput: !!input.narrixInput,
460
+ agentId: input.agentId,
461
+ modelConfig: input.modelConfig,
500
462
  });
501
- const modelUsedFromResult = (result) => {
502
- if (!result || typeof result !== "object")
503
- return undefined;
504
- const r = result;
505
- const candidates = [
506
- r?.metadata?.modelUsed,
507
- r?.metadata?.model,
508
- r?.gatewayResponse?.model,
509
- r?.enhancedResponse?.model,
510
- r?.model,
511
- ];
512
- const found = candidates.find((x) => typeof x === "string" && x.trim().length > 0);
513
- return typeof found === "string" ? found : undefined;
514
- };
515
- const finalize = (result) => {
516
- const downstreamIdentity = extractDownstreamIdentity(result);
517
- const identityToReturn = downstreamIdentity ??
518
- (upstreamIdentity ? effectiveIdentity : undefined);
519
- if (identityToReturn) {
520
- result.identity = identityToReturn;
521
- result.metadata = { ...(result.metadata ?? {}), identity: identityToReturn };
522
- }
523
- const smartInputRenderResult = extractSmartInputRenderResult(result);
524
- if (smartInputRenderResult) {
525
- result.smartInputRenderResult = smartInputRenderResult;
526
- }
527
- result.metadata = {
528
- ...result.metadata,
463
+ try {
464
+ // `@exellix/ai-skills` requires stable ids on each gateway request; callers may omit for simple runs.
465
+ const taskId = input.taskId?.trim() ? input.taskId : randomUUID();
466
+ const jobId = input.jobId?.trim() ? input.jobId : randomUUID();
467
+ input.taskId = taskId;
468
+ input.jobId = jobId;
469
+ // Optional activix tracking (non-fatal).
470
+ const ax = await getActivixClient().catch(() => null);
471
+ const correlationId = ax ? taskId : undefined;
472
+ patchRunTaskLogContext({
473
+ jobId,
529
474
  taskId,
530
- ...(coreSkillId ? { skillId: coreSkillId } : {}),
531
- identityPresent: (input.identity !== undefined),
532
- ...(smartInputRenderResult ? { smartInputRenderResult } : {}),
475
+ correlationId,
476
+ graphId: input.graphId,
477
+ nodeId: input.nodeId,
478
+ });
479
+ const coreSkillId = input.coreSkillId;
480
+ const upstreamIdentity = isRecord(input.identity) ? input.identity : undefined;
481
+ const executingSkillId = coreSkillId ?? input.skillKey;
482
+ const effectiveIdentity = {
483
+ ...(upstreamIdentity ?? {}),
484
+ ...(upstreamIdentity?.taskId ? {} : { taskId }),
485
+ ...(upstreamIdentity?.skillId ? {} : { skillId: executingSkillId }),
533
486
  };
534
- const patchJob = xynthesizedPatchAccumulator?.job && Object.keys(xynthesizedPatchAccumulator.job).length > 0;
535
- const patchTask = xynthesizedPatchAccumulator?.task && Object.keys(xynthesizedPatchAccumulator.task).length > 0;
536
- const patchExecution = xynthesizedPatchAccumulator?.execution &&
537
- Object.keys(xynthesizedPatchAccumulator.execution).length > 0;
538
- if (patchJob || patchTask || patchExecution) {
539
- result.xynthesizedPatch = xynthesizedPatchAccumulator;
540
- }
541
- return result;
542
- };
543
- const hasPipeline = Array.isArray(input.executionPipeline) && input.executionPipeline.length > 0;
544
- const hasNarrix = !!input.narrix;
545
- const hasNarrixInput = !!input.narrixInput;
546
- // Activix 6+: correlation + task identity belong in `runContext`, not a parallel top-level `identity` field.
547
- const runContext = {
548
- ...effectiveIdentity,
549
- sessionId: taskId,
550
- };
551
- const baseMeta = {
552
- skillKey: input.skillKey,
553
- executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
554
- narrixMode: knobs.narrixMode,
555
- jobId: input.jobId,
556
- agentId: input.agentId,
557
- graphId: input.graphId,
558
- nodeId: input.nodeId,
559
- prevNodeId: input.prevNodeId,
560
- masterSkillId: input.masterSkillId,
561
- masterSkillActivityId: input.masterSkillActivityId,
562
- runContext,
563
- hasPipeline,
564
- hasNarrix,
565
- hasNarrixInput,
566
- };
567
- const runDirect = async (req, options) => {
568
- const traceTask = {
569
- taskType: "ai-task",
570
- details: "direct execution (skills/gateway)",
571
- metadata: {
572
- ...baseTraceMeta(),
573
- phase: "direct",
574
- overrideContextProvided: options?.overrideContext !== undefined,
575
- captureContextProvided: options?.captureContext !== undefined,
576
- synthesisContextAuthoritative: options?.synthesisContextAuthoritative === true,
577
- ...(traceCollector
578
- ? {
579
- smartInput: {
580
- paths: req.smartInput?.paths ?? [],
581
- },
582
- }
583
- : {}),
584
- },
487
+ const normalizedSmartInput = input.smartInput !== undefined && input.smartInput !== null
488
+ ? normalizeSmartInputConfig(input.smartInput)
489
+ : undefined;
490
+ let request = withDefaultDecisionValidation({
491
+ ...input,
492
+ identity: effectiveIdentity,
493
+ ...(normalizedSmartInput !== undefined ? { smartInput: normalizedSmartInput } : {}),
494
+ });
495
+ let xynthesizedPatchAccumulator;
496
+ const knobs = resolveRunTaskRuntimeKnobs(request);
497
+ const baseTraceMeta = () => ({
498
+ jobId,
499
+ taskId,
500
+ skillKey: input.skillKey,
501
+ executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
502
+ narrixMode: knobs.narrixMode,
503
+ agentId: input.agentId,
504
+ graphId: input.graphId,
505
+ nodeId: input.nodeId,
506
+ prevNodeId: input.prevNodeId,
507
+ masterSkillId: input.masterSkillId,
508
+ masterSkillActivityId: input.masterSkillActivityId,
509
+ hasPipeline: Array.isArray(input.executionPipeline) && input.executionPipeline.length > 0,
510
+ hasNarrix: !!input.narrix,
511
+ hasNarrixInput: !!input.narrixInput,
512
+ });
513
+ const modelUsedFromResult = (result) => {
514
+ if (!result || typeof result !== "object")
515
+ return undefined;
516
+ const r = result;
517
+ const candidates = [
518
+ r?.metadata?.modelUsed,
519
+ r?.metadata?.model,
520
+ r?.gatewayResponse?.model,
521
+ r?.enhancedResponse?.model,
522
+ r?.model,
523
+ ];
524
+ const found = candidates.find((x) => typeof x === "string" && x.trim().length > 0);
525
+ return typeof found === "string" ? found : undefined;
585
526
  };
586
- return traceWrap(traceCollector, traceTask, async () => withPhaseRecord({
587
- ax,
588
- correlationId,
589
- phase: "direct",
590
- meta: {
591
- ...baseMeta,
592
- outer: activixOuterTier({
593
- kind: "runTask.request",
594
- skillKey: req.skillKey,
595
- executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
596
- jobId: req.jobId,
597
- agentId: req.agentId,
598
- graphId: req.graphId,
599
- nodeId: req.nodeId,
600
- masterSkillId: req.masterSkillId,
601
- masterSkillActivityId: req.masterSkillActivityId,
602
- includeContextInPrompt: req.includeContextInPrompt === true,
603
- hasPipeline: Array.isArray(req.executionPipeline) && req.executionPipeline.length > 0,
604
- hasNarrix: !!req.narrix,
605
- hasNarrixInput: !!req.narrixInput,
606
- input: summarizeForOuter(req.input, 4_000),
607
- }, null, { phase: "direct" }),
608
- // pipeline MAIN vs DIRECT is still tracked as the same phase label ("direct")
609
- hasPipeline: !!req.executionPipeline,
610
- hasNarrix: !!req.narrix,
611
- hasNarrixInput: !!req.narrixInput,
612
- overrideContextProvided: options?.overrideContext !== undefined,
613
- captureContextProvided: options?.captureContext !== undefined,
614
- synthesisContextAuthoritative: options?.synthesisContextAuthoritative === true,
615
- },
616
- fn: async () => this._executeDirect(req, {
617
- ...options,
618
- validationCorrelationId: taskId,
619
- traceCollector,
620
- }),
621
- onSuccessUpdates: (result) => {
622
- const steps = result?.intermediateSteps;
623
- return {
624
- instructionVersion: result?.metadata?.instructionVersion,
625
- activityId: result?.metadata?.activityId,
626
- durationMs: result?.metadata?.durationMs,
627
- hasIntermediateSteps: Array.isArray(steps) && steps.length > 0,
628
- stepCount: Array.isArray(steps) ? steps.length : undefined,
527
+ const finalize = (result) => {
528
+ const downstreamIdentity = extractDownstreamIdentity(result);
529
+ const identityToReturn = downstreamIdentity ??
530
+ (upstreamIdentity ? effectiveIdentity : undefined);
531
+ if (identityToReturn) {
532
+ result.identity = identityToReturn;
533
+ result.metadata = { ...(result.metadata ?? {}), identity: identityToReturn };
534
+ }
535
+ const smartInputRenderResult = extractSmartInputRenderResult(result);
536
+ if (smartInputRenderResult) {
537
+ result.smartInputRenderResult = smartInputRenderResult;
538
+ }
539
+ const resolvedModelForMeta = modelUsedFromResult(result);
540
+ const invocationMeta = buildRunTaskResultMetaFromModelId(resolvedModelForMeta, {
541
+ requestId: typeof result?.metadata?.requestId === "string"
542
+ ? result.metadata.requestId
543
+ : typeof result?.metadata?.activityId === "string"
544
+ ? result.metadata.activityId
545
+ : undefined,
546
+ });
547
+ result.metadata = {
548
+ ...result.metadata,
549
+ taskId,
550
+ ...(coreSkillId ? { skillId: coreSkillId } : {}),
551
+ identityPresent: (input.identity !== undefined),
552
+ ...(smartInputRenderResult ? { smartInputRenderResult } : {}),
553
+ ...(invocationMeta ?? {}),
554
+ };
555
+ const patchJob = xynthesizedPatchAccumulator?.job && Object.keys(xynthesizedPatchAccumulator.job).length > 0;
556
+ const patchTask = xynthesizedPatchAccumulator?.task && Object.keys(xynthesizedPatchAccumulator.task).length > 0;
557
+ const patchExecution = xynthesizedPatchAccumulator?.execution &&
558
+ Object.keys(xynthesizedPatchAccumulator.execution).length > 0;
559
+ if (patchJob || patchTask || patchExecution) {
560
+ result.xynthesizedPatch = xynthesizedPatchAccumulator;
561
+ }
562
+ return result;
563
+ };
564
+ const hasPipeline = Array.isArray(input.executionPipeline) && input.executionPipeline.length > 0;
565
+ const hasNarrix = !!input.narrix;
566
+ const hasNarrixInput = !!input.narrixInput;
567
+ // Activix 6+: correlation + task identity belong in `runContext`, not a parallel top-level `identity` field.
568
+ const runContext = {
569
+ ...effectiveIdentity,
570
+ sessionId: taskId,
571
+ };
572
+ const baseMeta = {
573
+ skillKey: input.skillKey,
574
+ executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
575
+ narrixMode: knobs.narrixMode,
576
+ jobId: input.jobId,
577
+ agentId: input.agentId,
578
+ graphId: input.graphId,
579
+ nodeId: input.nodeId,
580
+ prevNodeId: input.prevNodeId,
581
+ masterSkillId: input.masterSkillId,
582
+ masterSkillActivityId: input.masterSkillActivityId,
583
+ runContext,
584
+ hasPipeline,
585
+ hasNarrix,
586
+ hasNarrixInput,
587
+ };
588
+ const runDirect = async (req, options) => {
589
+ const traceTask = {
590
+ taskType: "ai-task",
591
+ details: "direct execution (skills/gateway)",
592
+ metadata: {
593
+ ...baseTraceMeta(),
594
+ phase: "direct",
595
+ overrideContextProvided: options?.overrideContext !== undefined,
596
+ captureContextProvided: options?.captureContext !== undefined,
597
+ synthesisContextAuthoritative: options?.synthesisContextAuthoritative === true,
598
+ ...(traceCollector
599
+ ? {
600
+ smartInput: {
601
+ paths: req.smartInput?.paths ?? [],
602
+ },
603
+ }
604
+ : {}),
605
+ },
606
+ };
607
+ return traceWrap(traceCollector, traceTask, async () => withPhaseRecord({
608
+ ax,
609
+ correlationId,
610
+ phase: "direct",
611
+ meta: {
612
+ ...baseMeta,
629
613
  outer: activixOuterTier({
630
614
  kind: "runTask.request",
631
615
  skillKey: req.skillKey,
@@ -641,116 +625,75 @@ export class WorexClientTasks {
641
625
  hasNarrix: !!req.narrix,
642
626
  hasNarrixInput: !!req.narrixInput,
643
627
  input: summarizeForOuter(req.input, 4_000),
644
- }, {
645
- kind: "runTask.response",
646
- skillKey: result?.skillKey,
647
- // Keep this intentionally small; rawText / flexMd payloads can be huge.
648
- metadata: summarizeForOuter(result?.metadata, 4_000),
649
- parsed: summarizeForOuter(result?.parsed, 8_000),
650
- }, { phase: "direct" }),
651
- };
652
- },
653
- }), (result) => {
654
- const modelUsed = modelUsedFromResult(result);
655
- const r = result;
656
- return {
657
- modelUsed: modelUsed ?? null,
658
- metadata: {
659
- activityId: r?.metadata?.activityId,
660
- instructionVersion: r?.metadata?.instructionVersion,
661
- durationMs: r?.metadata?.durationMs,
662
- outputValidation: r?.metadata?.outputValidation,
628
+ }, null, { phase: "direct" }),
629
+ // pipeline MAIN vs DIRECT is still tracked as the same phase label ("direct")
630
+ hasPipeline: !!req.executionPipeline,
631
+ hasNarrix: !!req.narrix,
632
+ hasNarrixInput: !!req.narrixInput,
633
+ overrideContextProvided: options?.overrideContext !== undefined,
634
+ captureContextProvided: options?.captureContext !== undefined,
635
+ synthesisContextAuthoritative: options?.synthesisContextAuthoritative === true,
663
636
  },
664
- };
665
- });
666
- };
667
- const runMainWithExecutionStrategies = async (req, options) => {
668
- const strat = knobs.resolvedExecutionStrategies;
669
- let working = { ...req };
670
- const prefixSteps = [];
671
- for (let pi = 0; pi < strat.orderedBefore.length; pi++) {
672
- const spec = strat.orderedBefore[pi];
673
- if (spec.strategyKey !== "planner")
674
- continue;
675
- const payload = buildExecutionStrategyRequestPayload({
676
- skillKey: working.skillKey,
677
- input: working.input,
678
- variables: working.variables,
679
- jobContext: working.jobContext,
680
- jobMemory: working.jobMemory,
681
- taskMemory: working.taskMemory,
682
- executionMemory: working.executionMemory,
683
- jobId: working.jobId,
684
- taskId: working.taskId,
685
- agentId: working.agentId,
686
- graphId: working.graphId,
687
- nodeId: working.nodeId,
688
- prevNodeId: working.prevNodeId,
689
- coreSkillId: working.coreSkillId,
690
- includeContextInPrompt: working.includeContextInPrompt,
691
- });
692
- const catalogDefaultFunctionId = resolveSafeExecutionStrategyCatalogDefaultFunctionId(req.executionStrategyCatalogItems, spec);
693
- const plannerOut = await runPlannerFuncx({
694
- args: spec.args,
695
- requestPayload: payload,
696
- defaultFunctionId: catalogDefaultFunctionId,
697
- });
698
- working = applyPlannerOutputToRequest(working, plannerOut, pi);
699
- prefixSteps.push({
700
- step: prefixSteps.length + 1,
701
- id: `executionStrategy.planner.${pi}`,
702
- ok: true,
703
- summary: "FuncX planner (execution/plan)",
704
- outputExcerpt: {
705
- hasInstructions: typeof plannerOut.instructions === "string",
706
- hasPrompt: typeof plannerOut.prompt === "string",
707
- variableKeys: plannerOut.variables ? Object.keys(plannerOut.variables).slice(0, 20) : [],
708
- functionIdSource: typeof spec.args?.functionId === "string"
709
- ? "invocation"
710
- : catalogDefaultFunctionId
711
- ? "catalog"
712
- : "code-default",
637
+ fn: async () => this._executeDirect(req, {
638
+ ...options,
639
+ validationCorrelationId: taskId,
640
+ traceCollector,
641
+ }),
642
+ onSuccessUpdates: (result) => {
643
+ const steps = result?.intermediateSteps;
644
+ return {
645
+ instructionVersion: result?.metadata?.instructionVersion,
646
+ activityId: result?.metadata?.activityId,
647
+ durationMs: result?.metadata?.durationMs,
648
+ hasIntermediateSteps: Array.isArray(steps) && steps.length > 0,
649
+ stepCount: Array.isArray(steps) ? steps.length : undefined,
650
+ outer: activixOuterTier({
651
+ kind: "runTask.request",
652
+ skillKey: req.skillKey,
653
+ executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
654
+ jobId: req.jobId,
655
+ agentId: req.agentId,
656
+ graphId: req.graphId,
657
+ nodeId: req.nodeId,
658
+ masterSkillId: req.masterSkillId,
659
+ masterSkillActivityId: req.masterSkillActivityId,
660
+ includeContextInPrompt: req.includeContextInPrompt === true,
661
+ hasPipeline: Array.isArray(req.executionPipeline) && req.executionPipeline.length > 0,
662
+ hasNarrix: !!req.narrix,
663
+ hasNarrixInput: !!req.narrixInput,
664
+ input: summarizeForOuter(req.input, 4_000),
665
+ }, {
666
+ kind: "runTask.response",
667
+ skillKey: result?.skillKey,
668
+ // Keep this intentionally small; rawText / flexMd payloads can be huge.
669
+ metadata: summarizeForOuter(result?.metadata, 4_000),
670
+ parsed: summarizeForOuter(result?.parsed, 8_000),
671
+ }, { phase: "direct" }),
672
+ };
713
673
  },
714
- });
715
- if (traceCollector) {
716
- traceCollector.push({
717
- taskType: "pre-execution",
718
- details: "execution strategy planner (FuncX)",
674
+ }), (result) => {
675
+ const modelUsed = modelUsedFromResult(result);
676
+ const r = result;
677
+ return {
678
+ modelUsed: modelUsed ?? null,
719
679
  metadata: {
720
- ...baseTraceMeta(),
721
- phase: "execution_strategy_planner",
722
- plannerIndex: pi,
680
+ activityId: r?.metadata?.activityId,
681
+ instructionVersion: r?.metadata?.instructionVersion,
682
+ durationMs: r?.metadata?.durationMs,
683
+ outputValidation: r?.metadata?.outputValidation,
723
684
  },
724
- modelUsed: null,
725
- });
726
- }
727
- }
728
- const mergePrefixSteps = (result) => {
729
- if (prefixSteps.length === 0)
730
- return result;
731
- const existing = (result.intermediateSteps ?? []);
732
- const shifted = existing.map((s, i) => ({ ...s, step: prefixSteps.length + i + 1 }));
733
- result.intermediateSteps = [...prefixSteps, ...shifted];
734
- return result;
685
+ };
686
+ });
735
687
  };
736
- const primary = strat.primaryOptimizer;
737
- const maxIter = strat.effectivePrimaryOptimizerMaxIterations;
738
- if (!primary) {
739
- return mergePrefixSteps(await runDirect(working, options));
740
- }
741
- let last;
742
- for (let iter = 0; iter < maxIter; iter++) {
743
- last = await runDirect(working, options);
744
- const mainSummary = {
745
- rawText: typeof last.rawText === "string" ? String(last.rawText).slice(0, 12_000) : undefined,
746
- parsed: last.parsed,
747
- skillKey: last.skillKey,
748
- metadata: last.metadata ? summarizeForOuter(last.metadata, 6_000) : undefined,
749
- };
750
- const evalOut = await runOptimizerFuncx({
751
- args: primary.args,
752
- defaultFunctionId: resolveSafeExecutionStrategyCatalogDefaultFunctionId(req.executionStrategyCatalogItems, primary),
753
- requestPayload: buildExecutionStrategyRequestPayload({
688
+ const runMainWithExecutionStrategies = async (req, options) => {
689
+ const strat = knobs.resolvedExecutionStrategies;
690
+ let working = { ...req };
691
+ const prefixSteps = [];
692
+ for (let pi = 0; pi < strat.orderedBefore.length; pi++) {
693
+ const spec = strat.orderedBefore[pi];
694
+ if (spec.strategyKey !== "planner")
695
+ continue;
696
+ const payload = buildExecutionStrategyRequestPayload({
754
697
  skillKey: working.skillKey,
755
698
  input: working.input,
756
699
  variables: working.variables,
@@ -766,757 +709,864 @@ export class WorexClientTasks {
766
709
  prevNodeId: working.prevNodeId,
767
710
  coreSkillId: working.coreSkillId,
768
711
  includeContextInPrompt: working.includeContextInPrompt,
769
- }),
770
- mainResultSummary: mainSummary,
771
- iterationIndex: iter,
772
- });
773
- if (traceCollector) {
774
- traceCollector.push({
775
- taskType: "ai-task",
776
- details: "execution strategy optimizer (FuncX)",
777
- metadata: {
778
- ...baseTraceMeta(),
779
- phase: "execution_strategy_optimizer",
780
- iterationIndex: iter,
781
- satisfied: evalOut.satisfied === true,
712
+ });
713
+ const catalogDefaultFunctionId = resolveSafeExecutionStrategyCatalogDefaultFunctionId(req.executionStrategyCatalogItems, spec);
714
+ const plannerOut = await runPlannerFuncx({
715
+ args: spec.args,
716
+ requestPayload: payload,
717
+ defaultFunctionId: catalogDefaultFunctionId,
718
+ });
719
+ working = applyPlannerOutputToRequest(working, plannerOut, pi);
720
+ prefixSteps.push({
721
+ step: prefixSteps.length + 1,
722
+ id: `executionStrategy.planner.${pi}`,
723
+ ok: true,
724
+ summary: "FuncX planner (execution/plan)",
725
+ outputExcerpt: {
726
+ hasInstructions: typeof plannerOut.instructions === "string",
727
+ hasPrompt: typeof plannerOut.prompt === "string",
728
+ variableKeys: plannerOut.variables ? Object.keys(plannerOut.variables).slice(0, 20) : [],
729
+ functionIdSource: typeof spec.args?.functionId === "string"
730
+ ? "invocation"
731
+ : catalogDefaultFunctionId
732
+ ? "catalog"
733
+ : "code-default",
782
734
  },
783
- modelUsed: modelUsedFromResult(last) ?? null,
784
735
  });
736
+ if (traceCollector) {
737
+ traceCollector.push({
738
+ taskType: "pre-execution",
739
+ details: "execution strategy planner (FuncX)",
740
+ metadata: {
741
+ ...baseTraceMeta(),
742
+ phase: "execution_strategy_planner",
743
+ plannerIndex: pi,
744
+ },
745
+ modelUsed: null,
746
+ });
747
+ }
785
748
  }
786
- if (evalOut.satisfied) {
787
- return mergePrefixSteps(last);
749
+ const mergePrefixSteps = (result) => {
750
+ if (prefixSteps.length === 0)
751
+ return result;
752
+ const existing = (result.intermediateSteps ?? []);
753
+ const shifted = existing.map((s, i) => ({ ...s, step: prefixSteps.length + i + 1 }));
754
+ result.intermediateSteps = [...prefixSteps, ...shifted];
755
+ return result;
756
+ };
757
+ const primary = strat.primaryOptimizer;
758
+ const maxIter = strat.effectivePrimaryOptimizerMaxIterations;
759
+ if (!primary) {
760
+ return mergePrefixSteps(await runDirect(working, options));
788
761
  }
789
- if (iter === maxIter - 1) {
790
- return mergePrefixSteps(last);
762
+ let last;
763
+ for (let iter = 0; iter < maxIter; iter++) {
764
+ last = await runDirect(working, options);
765
+ const mainSummary = {
766
+ rawText: typeof last.rawText === "string" ? String(last.rawText).slice(0, 12_000) : undefined,
767
+ parsed: last.parsed,
768
+ skillKey: last.skillKey,
769
+ metadata: last.metadata ? summarizeForOuter(last.metadata, 6_000) : undefined,
770
+ };
771
+ const evalOut = await runOptimizerFuncx({
772
+ args: primary.args,
773
+ defaultFunctionId: resolveSafeExecutionStrategyCatalogDefaultFunctionId(req.executionStrategyCatalogItems, primary),
774
+ requestPayload: buildExecutionStrategyRequestPayload({
775
+ skillKey: working.skillKey,
776
+ input: working.input,
777
+ variables: working.variables,
778
+ jobContext: working.jobContext,
779
+ jobMemory: working.jobMemory,
780
+ taskMemory: working.taskMemory,
781
+ executionMemory: working.executionMemory,
782
+ jobId: working.jobId,
783
+ taskId: working.taskId,
784
+ agentId: working.agentId,
785
+ graphId: working.graphId,
786
+ nodeId: working.nodeId,
787
+ prevNodeId: working.prevNodeId,
788
+ coreSkillId: working.coreSkillId,
789
+ includeContextInPrompt: working.includeContextInPrompt,
790
+ }),
791
+ mainResultSummary: mainSummary,
792
+ iterationIndex: iter,
793
+ });
794
+ if (traceCollector) {
795
+ traceCollector.push({
796
+ taskType: "ai-task",
797
+ details: "execution strategy optimizer (FuncX)",
798
+ metadata: {
799
+ ...baseTraceMeta(),
800
+ phase: "execution_strategy_optimizer",
801
+ iterationIndex: iter,
802
+ satisfied: evalOut.satisfied === true,
803
+ },
804
+ modelUsed: modelUsedFromResult(last) ?? null,
805
+ });
806
+ }
807
+ if (evalOut.satisfied) {
808
+ return mergePrefixSteps(last);
809
+ }
810
+ if (iter === maxIter - 1) {
811
+ return mergePrefixSteps(last);
812
+ }
813
+ working = applyOptimizerFeedbackToRequest(working, evalOut, iter + 1);
791
814
  }
792
- working = applyOptimizerFeedbackToRequest(working, evalOut, iter + 1);
793
- }
794
- return mergePrefixSteps(last);
795
- };
796
- // NARRIX task-level pre-processor + structured handler: `narrixMode` (+ inference) via `resolveRunTaskRuntimeKnobs`.
797
- if (knobs.narrixMode === "preprocessor" && request.narrix) {
798
- const narrixCfg = request.narrix;
799
- await traceWrap(traceCollector, {
800
- taskType: "pre-execution",
801
- details: "narrix preprocessor",
802
- metadata: {
803
- ...baseTraceMeta(),
804
- phase: "narrix",
805
- datasetId: narrixCfg.datasetId,
806
- attachToField: narrixCfg.attachToField ?? "_narrix",
807
- enableWebScope: narrixCfg.enableWebScope === true,
808
- },
809
- }, async () => withPhaseRecord({
810
- ax,
811
- correlationId,
812
- phase: "narrix",
813
- meta: {
814
- ...baseMeta,
815
- narrixAttachToField: narrixCfg.attachToField ?? "_narrix",
816
- outer: activixOuterTier({
817
- kind: "narrix.preProcessor.request",
815
+ return mergePrefixSteps(last);
816
+ };
817
+ // NARRIX task-level pre-processor + structured handler: `narrixMode` (+ inference) via `resolveRunTaskRuntimeKnobs`.
818
+ if (knobs.narrixMode === "preprocessor" && request.narrix) {
819
+ const narrixCfg = request.narrix;
820
+ await traceWrap(traceCollector, {
821
+ taskType: "pre-execution",
822
+ details: "narrix preprocessor",
823
+ metadata: {
824
+ ...baseTraceMeta(),
825
+ phase: "narrix",
818
826
  datasetId: narrixCfg.datasetId,
819
827
  attachToField: narrixCfg.attachToField ?? "_narrix",
820
828
  enableWebScope: narrixCfg.enableWebScope === true,
821
- webScoping: narrixCfg.webScoping ? summarizeForOuter(narrixCfg.webScoping, 2_000) : undefined,
822
- requestInput: summarizeForOuter(request.input, 4_000),
823
- }, null, { phase: "narrix" }),
824
- },
825
- fn: async () => {
826
- const adaptResult = adaptMemorixToNarrixInput({
827
- datasetId: narrixCfg.datasetId,
828
- mediumHint: "record",
829
- memorix: {
829
+ },
830
+ }, async () => withPhaseRecord({
831
+ ax,
832
+ correlationId,
833
+ phase: "narrix",
834
+ meta: {
835
+ ...baseMeta,
836
+ narrixAttachToField: narrixCfg.attachToField ?? "_narrix",
837
+ outer: activixOuterTier({
838
+ kind: "narrix.preProcessor.request",
839
+ datasetId: narrixCfg.datasetId,
840
+ attachToField: narrixCfg.attachToField ?? "_narrix",
841
+ enableWebScope: narrixCfg.enableWebScope === true,
842
+ webScoping: narrixCfg.webScoping ? summarizeForOuter(narrixCfg.webScoping, 2_000) : undefined,
843
+ requestInput: summarizeForOuter(request.input, 4_000),
844
+ }, null, { phase: "narrix" }),
845
+ },
846
+ fn: async () => {
847
+ const adaptResult = adaptMemorixToNarrixInput({
848
+ datasetId: narrixCfg.datasetId,
849
+ mediumHint: "record",
850
+ memorix: {
851
+ jobMemory: request.jobMemory,
852
+ executionMemory: request.executionMemory,
853
+ input: request.input,
854
+ },
855
+ }, {
856
+ record: {
857
+ minKeys: 1,
858
+ preferPaths: [
859
+ "executionMemory.input.raw",
860
+ "executionMemory.inputs.*.raw",
861
+ "jobMemory.record",
862
+ "jobMemory.currentRecord",
863
+ "executionMemory.input.record",
864
+ "executionMemory.record",
865
+ "taskMemory.currentRecord",
866
+ "*.currentRecord",
867
+ "*.record",
868
+ ],
869
+ },
870
+ });
871
+ if (!adaptResult.ok) {
872
+ const attempted = adaptResult.attempted?.length ? ` Attempted: ${adaptResult.attempted.join(", ")}.` : "";
873
+ const summary = adaptResult.foundSummary ? ` Seen: ${adaptResult.foundSummary}` : "";
874
+ throw new Error(`NARRIX pre-processor: no usable input. ${adaptResult.message}.${attempted}${summary}`);
875
+ }
876
+ const ctx = {
877
+ skillKey: request.skillKey,
830
878
  jobMemory: request.jobMemory,
879
+ taskMemory: request.taskMemory,
831
880
  executionMemory: request.executionMemory,
832
- input: request.input,
833
- },
834
- }, {
835
- record: {
836
- minKeys: 1,
837
- preferPaths: [
838
- "executionMemory.input.raw",
839
- "executionMemory.inputs.*.raw",
840
- "jobMemory.record",
841
- "jobMemory.currentRecord",
842
- "executionMemory.input.record",
843
- "executionMemory.record",
844
- "taskMemory.currentRecord",
845
- "*.currentRecord",
846
- "*.record",
847
- ],
848
- },
849
- });
850
- if (!adaptResult.ok) {
851
- const attempted = adaptResult.attempted?.length ? ` Attempted: ${adaptResult.attempted.join(", ")}.` : "";
852
- const summary = adaptResult.foundSummary ? ` Seen: ${adaptResult.foundSummary}` : "";
853
- throw new Error(`NARRIX pre-processor: no usable input. ${adaptResult.message}.${attempted}${summary}`);
881
+ variables: input.variables,
882
+ xynthesized: request.xynthesized,
883
+ smartInput: request.smartInput,
884
+ jobId: input.jobId,
885
+ taskId: request.taskId,
886
+ agentId: input.agentId,
887
+ graphId: input.graphId,
888
+ nodeId: input.nodeId,
889
+ prevNodeId: input.prevNodeId,
890
+ coreSkillId: input.coreSkillId,
891
+ masterSkillId: request.masterSkillId,
892
+ masterSkillActivityId: request.masterSkillActivityId,
893
+ };
894
+ const narrixResult = await narrixRunHandler({ input: adaptResult.narrixInput, ctx });
895
+ if (!narrixResult.ok) {
896
+ const fail = narrixResult;
897
+ throw new Error(`NARRIX pre-processor failed: ${fail.error}${fail.message ? ` - ${fail.message}` : ""}`);
898
+ }
899
+ const attachment = buildNarrixAttachment(narrixResult);
900
+ const attachToField = narrixCfg.attachToField ?? "_narrix";
901
+ let webContextEntry = undefined;
902
+ let webContextAvailable;
903
+ let webContextReason;
904
+ const externalWebMdPreNarrix = typeof request.executionMemory?.webContextMarkdown === "string" &&
905
+ request.executionMemory.webContextMarkdown.trim().length > 0;
906
+ const skipWebScopeForExternalMd = narrixCfg.skipWebScopeWhenExternalWebMarkdownPresent === true && externalWebMdPreNarrix;
907
+ if (narrixCfg.enableWebScope === true && !skipWebScopeForExternalMd) {
908
+ const successResult = narrixResult;
909
+ const entity = adaptResult.narrixInput.medium === "record"
910
+ ? adaptResult.narrixInput.record
911
+ : undefined;
912
+ const scopeFields = resolveWebScopeQuestionAndTemplates({
913
+ narrix: narrixCfg,
914
+ requestInput: request.input,
915
+ successResult,
916
+ entity,
917
+ });
918
+ const webScopeOpts = hasNonEmptyWebScoping(narrixCfg.webScoping)
919
+ ? { scoping: narrixCfg.webScoping }
920
+ : undefined;
921
+ const activixPatch = webScopeActivixCorrelationPatch({
922
+ jobId: request.jobId,
923
+ taskId: request.taskId,
924
+ sessionId: request.taskId,
925
+ });
926
+ const packQs = scopeFields.packQuestions;
927
+ if (Array.isArray(packQs) && packQs.length > 0) {
928
+ webContextEntry = await runWebScopeQuestionPack({
929
+ datasetId: narrixCfg.datasetId,
930
+ subjectId: successResult.entity.entityKey,
931
+ entityKind: successResult.entity.entityKind,
932
+ entity,
933
+ cni: successResult.cni,
934
+ ...activixPatch,
935
+ questions: packQs,
936
+ }, webScopeOpts);
937
+ }
938
+ else {
939
+ const { packQuestions: _pq, ...genericScope } = scopeFields;
940
+ void _pq;
941
+ webContextEntry = await runWebScope({
942
+ datasetId: narrixCfg.datasetId,
943
+ subjectId: successResult.entity.entityKey,
944
+ entityKind: successResult.entity.entityKind,
945
+ entity,
946
+ cni: successResult.cni,
947
+ ...activixPatch,
948
+ ...genericScope,
949
+ }, webScopeOpts);
950
+ }
951
+ if (webContextEntry && typeof webContextEntry === "object") {
952
+ const wc = webContextEntry;
953
+ webContextAvailable = typeof wc.available === "boolean" ? wc.available : undefined;
954
+ webContextReason = typeof wc.reason === "string" ? wc.reason : undefined;
955
+ }
956
+ if (webContextEntry &&
957
+ typeof webContextEntry === "object" &&
958
+ webContextEntry.available === false) {
959
+ const miss = webContextEntry;
960
+ if (process.env.NARRIX_DEBUG === "1") {
961
+ getAiTasksLogxer().warnCode(AI_TASKS_DIAGNOSTIC_CODES.NARRIX_WEB_SCOPE_MISS, {
962
+ source: "@exellix/ai-tasks",
963
+ debugKind: DebugLogAbstract.ANOMALY,
964
+ diagnostics: {
965
+ summary: "Narrix web scope miss",
966
+ actual: miss.error ?? miss.reason ?? "web context unavailable",
967
+ },
968
+ evidence: [
969
+ fieldEvidence("webContext.reason", miss.reason ?? null),
970
+ fieldEvidence("webContext.error", miss.error ?? null),
971
+ ],
972
+ });
973
+ }
974
+ if (traceCollector) {
975
+ traceCollector.push({
976
+ taskType: "pre-execution",
977
+ details: "narrix web scope miss",
978
+ metadata: {
979
+ ...baseTraceMeta(),
980
+ phase: "narrix",
981
+ webContext: { available: false, reason: miss.reason, error: miss.error },
982
+ },
983
+ modelUsed: null,
984
+ });
985
+ }
986
+ }
987
+ }
988
+ request = {
989
+ ...request,
990
+ executionMemory: {
991
+ ...(request.executionMemory || {}),
992
+ [attachToField]: attachment,
993
+ ...(webContextEntry !== undefined ? { webContext: webContextEntry } : {}),
994
+ },
995
+ jobMemory: request.jobMemory ? { ...request.jobMemory, _narrix: attachment } : { _narrix: attachment },
996
+ };
997
+ const scopingSignalsCount = Array.isArray(attachment?.scoping?.signals) ? attachment.scoping.signals.length : undefined;
998
+ const scopingStoriesCount = Array.isArray(attachment?.scoping?.stories) ? attachment.scoping.stories.length : undefined;
999
+ const discoverySignalsCount = Array.isArray(attachment?.discovery?.signals) ? attachment.discovery.signals.length : undefined;
1000
+ const discoveryStoriesCount = Array.isArray(attachment?.discovery?.stories) ? attachment.discovery.stories.length : undefined;
1001
+ const entityKey = narrixResult?.entity?.entityKey;
1002
+ const entityKind = narrixResult?.entity?.entityKind;
1003
+ return {
1004
+ datasetId: narrixCfg.datasetId,
1005
+ attachToField,
1006
+ enableWebScope: narrixCfg.enableWebScope === true,
1007
+ webContextAvailable,
1008
+ webContextReason,
1009
+ attachmentMeta: isRecord(attachment?.meta) ? attachment.meta : undefined,
1010
+ scopingSignalsCount,
1011
+ scopingStoriesCount,
1012
+ discoverySignalsCount,
1013
+ discoveryStoriesCount,
1014
+ entityKey: typeof entityKey === "string" ? entityKey : undefined,
1015
+ entityKind: typeof entityKind === "string" ? entityKind : undefined,
1016
+ medium: typeof adaptResult.narrixInput?.medium === "string" ? adaptResult.narrixInput.medium : undefined,
1017
+ };
1018
+ },
1019
+ onSuccessUpdates: (r) => ({
1020
+ outer: activixOuterTier({
1021
+ kind: "narrix.preProcessor.request",
1022
+ datasetId: narrixCfg.datasetId,
1023
+ attachToField: narrixCfg.attachToField ?? "_narrix",
1024
+ enableWebScope: narrixCfg.enableWebScope === true,
1025
+ webScoping: narrixCfg.webScoping ? summarizeForOuter(narrixCfg.webScoping, 2_000) : undefined,
1026
+ requestInput: summarizeForOuter(request.input, 4_000),
1027
+ }, {
1028
+ kind: "narrix.preProcessor.result",
1029
+ datasetId: r.datasetId,
1030
+ attachToField: r.attachToField,
1031
+ enableWebScope: r.enableWebScope,
1032
+ entity: r.entityKey ? { entityKey: r.entityKey, entityKind: r.entityKind } : undefined,
1033
+ counts: {
1034
+ scopingSignals: r.scopingSignalsCount,
1035
+ scopingStories: r.scopingStoriesCount,
1036
+ discoverySignals: r.discoverySignalsCount,
1037
+ discoveryStories: r.discoveryStoriesCount,
1038
+ },
1039
+ webContext: r.enableWebScope
1040
+ ? { available: r.webContextAvailable, reason: r.webContextReason }
1041
+ : undefined,
1042
+ attachmentMeta: r.attachmentMeta,
1043
+ }, { phase: "narrix" }),
1044
+ }),
1045
+ }));
1046
+ }
1047
+ // Structured Narrix (`narrixInput`): same enrichment as legacy `narrix-then-direct`, but runs before local tasks / pipeline PRE.
1048
+ if (knobs.narrixMode === "handler") {
1049
+ if (!request.narrixInput) {
1050
+ throw new Error(`narrixMode "handler" requires narrixInput. ` +
1051
+ `Provide { medium, datasetId, ... } or { $path: "jobMemory.currentRecord" } on the request.`);
1052
+ }
1053
+ const resolvedNarrixInput = resolveNarrixInput(request.narrixInput, request.jobMemory);
1054
+ if (!resolvedNarrixInput) {
1055
+ throw new Error(`narrixMode "handler": narrixInput could not be resolved. ` +
1056
+ `Ensure it has medium and datasetId, or that $path points to a valid object in jobMemory.`);
1057
+ }
1058
+ let narrixThenDirectPhaseRecordId = null;
1059
+ if (ax && correlationId) {
1060
+ try {
1061
+ narrixThenDirectPhaseRecordId = (await ax.startRecord({
1062
+ correlationId,
1063
+ phase: "narrix_then_direct",
1064
+ ...baseMeta,
1065
+ narrixDatasetId: resolvedNarrixInput.datasetId,
1066
+ narrixMedium: resolvedNarrixInput.medium,
1067
+ outer: activixOuterTier({
1068
+ kind: "narrixThenDirect.request",
1069
+ skillKey: request.skillKey,
1070
+ jobId: request.jobId,
1071
+ agentId: request.agentId,
1072
+ narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1073
+ }, null, { phase: "narrix_then_direct" }),
1074
+ })).recordId;
1075
+ }
1076
+ catch {
1077
+ narrixThenDirectPhaseRecordId = null;
854
1078
  }
855
- const ctx = {
1079
+ }
1080
+ try {
1081
+ const narrixStarted = Date.now();
1082
+ const narrixHandlerCtx = {
856
1083
  skillKey: request.skillKey,
857
1084
  jobMemory: request.jobMemory,
858
1085
  taskMemory: request.taskMemory,
859
1086
  executionMemory: request.executionMemory,
860
- variables: input.variables,
1087
+ variables: request.variables,
861
1088
  xynthesized: request.xynthesized,
862
1089
  smartInput: request.smartInput,
863
- jobId: input.jobId,
1090
+ jobId: request.jobId,
864
1091
  taskId: request.taskId,
865
- agentId: input.agentId,
866
- graphId: input.graphId,
867
- nodeId: input.nodeId,
868
- prevNodeId: input.prevNodeId,
869
- coreSkillId: input.coreSkillId,
1092
+ agentId: request.agentId,
1093
+ graphId: request.graphId,
1094
+ nodeId: request.nodeId,
1095
+ prevNodeId: request.prevNodeId,
1096
+ coreSkillId: request.coreSkillId,
870
1097
  masterSkillId: request.masterSkillId,
871
1098
  masterSkillActivityId: request.masterSkillActivityId,
872
1099
  };
873
- const narrixResult = await narrixRunHandler({ input: adaptResult.narrixInput, ctx });
1100
+ const narrixResult = await traceWrap(traceCollector, {
1101
+ taskType: "pre-execution",
1102
+ details: "narrix structured handler (narrixInput)",
1103
+ metadata: {
1104
+ ...baseTraceMeta(),
1105
+ phase: "narrix_then_direct",
1106
+ datasetId: resolvedNarrixInput.datasetId,
1107
+ medium: resolvedNarrixInput.medium,
1108
+ },
1109
+ }, async () => narrixRunHandler({ input: resolvedNarrixInput, ctx: narrixHandlerCtx }), (r) => ({
1110
+ metadata: { ok: r?.ok === true },
1111
+ modelUsed: null,
1112
+ }));
1113
+ const narrixDurationMs = Date.now() - narrixStarted;
874
1114
  if (!narrixResult.ok) {
875
1115
  const fail = narrixResult;
876
- throw new Error(`NARRIX pre-processor failed: ${fail.error}${fail.message ? ` - ${fail.message}` : ""}`);
877
- }
878
- const attachment = buildNarrixAttachment(narrixResult);
879
- const attachToField = narrixCfg.attachToField ?? "_narrix";
880
- let webContextEntry = undefined;
881
- let webContextAvailable;
882
- let webContextReason;
883
- const externalWebMdPreNarrix = typeof request.executionMemory?.webContextMarkdown === "string" &&
884
- request.executionMemory.webContextMarkdown.trim().length > 0;
885
- const skipWebScopeForExternalMd = narrixCfg.skipWebScopeWhenExternalWebMarkdownPresent === true && externalWebMdPreNarrix;
886
- if (narrixCfg.enableWebScope === true && !skipWebScopeForExternalMd) {
887
- const successResult = narrixResult;
888
- const entity = adaptResult.narrixInput.medium === "record"
889
- ? adaptResult.narrixInput.record
890
- : undefined;
891
- const scopeFields = resolveWebScopeQuestionAndTemplates({
892
- narrix: narrixCfg,
893
- requestInput: request.input,
894
- successResult,
895
- entity,
896
- });
897
- const webScopeOpts = hasNonEmptyWebScoping(narrixCfg.webScoping)
898
- ? { scoping: narrixCfg.webScoping }
899
- : undefined;
900
- const activixPatch = webScopeActivixCorrelationPatch({
901
- jobId: request.jobId,
902
- taskId: request.taskId,
903
- sessionId: request.taskId,
904
- });
905
- const packQs = scopeFields.packQuestions;
906
- if (Array.isArray(packQs) && packQs.length > 0) {
907
- webContextEntry = await runWebScopeQuestionPack({
908
- datasetId: narrixCfg.datasetId,
909
- subjectId: successResult.entity.entityKey,
910
- entityKind: successResult.entity.entityKind,
911
- entity,
912
- cni: successResult.cni,
913
- ...activixPatch,
914
- questions: packQs,
915
- }, webScopeOpts);
916
- }
917
- else {
918
- const { packQuestions: _pq, ...genericScope } = scopeFields;
919
- void _pq;
920
- webContextEntry = await runWebScope({
921
- datasetId: narrixCfg.datasetId,
922
- subjectId: successResult.entity.entityKey,
923
- entityKind: successResult.entity.entityKind,
924
- entity,
925
- cni: successResult.cni,
926
- ...activixPatch,
927
- ...genericScope,
928
- }, webScopeOpts);
929
- }
930
- if (webContextEntry && typeof webContextEntry === "object") {
931
- const wc = webContextEntry;
932
- webContextAvailable = typeof wc.available === "boolean" ? wc.available : undefined;
933
- webContextReason = typeof wc.reason === "string" ? wc.reason : undefined;
934
- }
935
- if (webContextEntry &&
936
- typeof webContextEntry === "object" &&
937
- webContextEntry.available === false) {
938
- const miss = webContextEntry;
939
- if (process.env.NARRIX_DEBUG === "1") {
940
- getAiTasksLogxer().warnCode(AI_TASKS_DIAGNOSTIC_CODES.NARRIX_WEB_SCOPE_MISS, {
941
- source: "@exellix/ai-tasks",
942
- debugKind: DebugLogAbstract.ANOMALY,
943
- diagnostics: {
944
- summary: "Narrix web scope miss",
945
- actual: miss.error ?? miss.reason ?? "web context unavailable",
946
- },
947
- evidence: [
948
- fieldEvidence("webContext.reason", miss.reason ?? null),
949
- fieldEvidence("webContext.error", miss.error ?? null),
950
- ],
951
- });
952
- }
953
- if (traceCollector) {
954
- traceCollector.push({
955
- taskType: "pre-execution",
956
- details: "narrix web scope miss",
957
- metadata: {
958
- ...baseTraceMeta(),
959
- phase: "narrix",
960
- webContext: { available: false, reason: miss.reason, error: miss.error },
961
- },
962
- modelUsed: null,
963
- });
964
- }
1116
+ if (ax && correlationId && narrixThenDirectPhaseRecordId) {
1117
+ await ax
1118
+ .failRecord(narrixThenDirectPhaseRecordId, new Error(`Narrix handler failed: ${fail.error}${fail.message ? ` - ${fail.message}` : ""}`), {
1119
+ errorMessage: fail.message ? `${fail.error} - ${fail.message}` : fail.error,
1120
+ errorCode: fail.code,
1121
+ narrixDurationMs,
1122
+ })
1123
+ .catch(() => undefined);
965
1124
  }
1125
+ return withTrace({
1126
+ skillKey: request.skillKey,
1127
+ rawText: JSON.stringify(narrixResult, null, 2),
1128
+ flexMd: { frame: "narrixThenDirect.v1", payloads: { narrix: JSON.stringify(narrixResult) } },
1129
+ parsed: {
1130
+ ok: false,
1131
+ error: narrixResult.error,
1132
+ phase: "narrix",
1133
+ message: narrixResult.message,
1134
+ },
1135
+ metadata: {
1136
+ instructionVersion: "narrix-then-direct",
1137
+ narrix: { ...narrixResult, durationMs: narrixDurationMs },
1138
+ narrixMode: knobs.narrixMode,
1139
+ inputStrategyKey: knobs.inputStrategyKey,
1140
+ executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
1141
+ },
1142
+ });
966
1143
  }
1144
+ const filteredEntry = applyNarrixScope(narrixResult, request.narrixScope);
1145
+ const existingNarrix = Array.isArray(request.taskMemory?.narrix)
1146
+ ? request.taskMemory.narrix
1147
+ : [];
1148
+ const updatedTaskMemory = {
1149
+ ...(request.taskMemory ?? {}),
1150
+ narrix: [...existingNarrix, filteredEntry],
1151
+ };
1152
+ const skillInput = typeof request.input === "object" && request.input !== null
1153
+ ? { ...request.input, narrixContext: filteredEntry }
1154
+ : { narrixContext: filteredEntry };
967
1155
  request = {
968
1156
  ...request,
969
- executionMemory: {
970
- ...(request.executionMemory || {}),
971
- [attachToField]: attachment,
972
- ...(webContextEntry !== undefined ? { webContext: webContextEntry } : {}),
973
- },
974
- jobMemory: request.jobMemory ? { ...request.jobMemory, _narrix: attachment } : { _narrix: attachment },
975
- };
976
- const scopingSignalsCount = Array.isArray(attachment?.scoping?.signals) ? attachment.scoping.signals.length : undefined;
977
- const scopingStoriesCount = Array.isArray(attachment?.scoping?.stories) ? attachment.scoping.stories.length : undefined;
978
- const discoverySignalsCount = Array.isArray(attachment?.discovery?.signals) ? attachment.discovery.signals.length : undefined;
979
- const discoveryStoriesCount = Array.isArray(attachment?.discovery?.stories) ? attachment.discovery.stories.length : undefined;
980
- const entityKey = narrixResult?.entity?.entityKey;
981
- const entityKind = narrixResult?.entity?.entityKind;
982
- return {
983
- datasetId: narrixCfg.datasetId,
984
- attachToField,
985
- enableWebScope: narrixCfg.enableWebScope === true,
986
- webContextAvailable,
987
- webContextReason,
988
- attachmentMeta: isRecord(attachment?.meta) ? attachment.meta : undefined,
989
- scopingSignalsCount,
990
- scopingStoriesCount,
991
- discoverySignalsCount,
992
- discoveryStoriesCount,
993
- entityKey: typeof entityKey === "string" ? entityKey : undefined,
994
- entityKind: typeof entityKind === "string" ? entityKind : undefined,
995
- medium: typeof adaptResult.narrixInput?.medium === "string" ? adaptResult.narrixInput.medium : undefined,
1157
+ taskMemory: updatedTaskMemory,
1158
+ input: skillInput,
996
1159
  };
997
- },
998
- onSuccessUpdates: (r) => ({
999
- outer: activixOuterTier({
1000
- kind: "narrix.preProcessor.request",
1001
- datasetId: narrixCfg.datasetId,
1002
- attachToField: narrixCfg.attachToField ?? "_narrix",
1003
- enableWebScope: narrixCfg.enableWebScope === true,
1004
- webScoping: narrixCfg.webScoping ? summarizeForOuter(narrixCfg.webScoping, 2_000) : undefined,
1005
- requestInput: summarizeForOuter(request.input, 4_000),
1006
- }, {
1007
- kind: "narrix.preProcessor.result",
1008
- datasetId: r.datasetId,
1009
- attachToField: r.attachToField,
1010
- enableWebScope: r.enableWebScope,
1011
- entity: r.entityKey ? { entityKey: r.entityKey, entityKind: r.entityKind } : undefined,
1012
- counts: {
1013
- scopingSignals: r.scopingSignalsCount,
1014
- scopingStories: r.scopingStoriesCount,
1015
- discoverySignals: r.discoverySignalsCount,
1016
- discoveryStories: r.discoveryStoriesCount,
1017
- },
1018
- webContext: r.enableWebScope
1019
- ? { available: r.webContextAvailable, reason: r.webContextReason }
1020
- : undefined,
1021
- attachmentMeta: r.attachmentMeta,
1022
- }, { phase: "narrix" }),
1023
- }),
1024
- }));
1025
- }
1026
- // Structured Narrix (`narrixInput`): same enrichment as legacy `narrix-then-direct`, but runs before local tasks / pipeline PRE.
1027
- if (knobs.narrixMode === "handler") {
1028
- if (!request.narrixInput) {
1029
- throw new Error(`narrixMode "handler" requires narrixInput. ` +
1030
- `Provide { medium, datasetId, ... } or { $path: "jobMemory.currentRecord" } on the request.`);
1031
- }
1032
- const resolvedNarrixInput = resolveNarrixInput(request.narrixInput, request.jobMemory);
1033
- if (!resolvedNarrixInput) {
1034
- throw new Error(`narrixMode "handler": narrixInput could not be resolved. ` +
1035
- `Ensure it has medium and datasetId, or that $path points to a valid object in jobMemory.`);
1036
- }
1037
- let narrixThenDirectPhaseRecordId = null;
1038
- if (ax && correlationId) {
1039
- try {
1040
- narrixThenDirectPhaseRecordId = (await ax.startRecord({
1041
- correlationId,
1042
- phase: "narrix_then_direct",
1043
- ...baseMeta,
1044
- narrixDatasetId: resolvedNarrixInput.datasetId,
1045
- narrixMedium: resolvedNarrixInput.medium,
1046
- outer: activixOuterTier({
1047
- kind: "narrixThenDirect.request",
1048
- skillKey: request.skillKey,
1049
- jobId: request.jobId,
1050
- agentId: request.agentId,
1051
- narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1052
- }, null, { phase: "narrix_then_direct" }),
1053
- })).recordId;
1054
- }
1055
- catch {
1056
- narrixThenDirectPhaseRecordId = null;
1057
- }
1058
- }
1059
- try {
1060
- const narrixStarted = Date.now();
1061
- const narrixHandlerCtx = {
1062
- skillKey: request.skillKey,
1063
- jobMemory: request.jobMemory,
1064
- taskMemory: request.taskMemory,
1065
- executionMemory: request.executionMemory,
1066
- variables: request.variables,
1067
- xynthesized: request.xynthesized,
1068
- smartInput: request.smartInput,
1069
- jobId: request.jobId,
1070
- taskId: request.taskId,
1071
- agentId: request.agentId,
1072
- graphId: request.graphId,
1073
- nodeId: request.nodeId,
1074
- prevNodeId: request.prevNodeId,
1075
- coreSkillId: request.coreSkillId,
1076
- masterSkillId: request.masterSkillId,
1077
- masterSkillActivityId: request.masterSkillActivityId,
1078
- };
1079
- const narrixResult = await traceWrap(traceCollector, {
1080
- taskType: "pre-execution",
1081
- details: "narrix structured handler (narrixInput)",
1082
- metadata: {
1083
- ...baseTraceMeta(),
1084
- phase: "narrix_then_direct",
1085
- datasetId: resolvedNarrixInput.datasetId,
1086
- medium: resolvedNarrixInput.medium,
1087
- },
1088
- }, async () => narrixRunHandler({ input: resolvedNarrixInput, ctx: narrixHandlerCtx }), (r) => ({
1089
- metadata: { ok: r?.ok === true },
1090
- modelUsed: null,
1091
- }));
1092
- const narrixDurationMs = Date.now() - narrixStarted;
1093
- if (!narrixResult.ok) {
1094
- const fail = narrixResult;
1095
1160
  if (ax && correlationId && narrixThenDirectPhaseRecordId) {
1096
1161
  await ax
1097
- .failRecord(narrixThenDirectPhaseRecordId, new Error(`Narrix handler failed: ${fail.error}${fail.message ? ` - ${fail.message}` : ""}`), {
1098
- errorMessage: fail.message ? `${fail.error} - ${fail.message}` : fail.error,
1099
- errorCode: fail.code,
1162
+ .completeRecord(narrixThenDirectPhaseRecordId, {
1100
1163
  narrixDurationMs,
1164
+ outer: activixOuterTier({
1165
+ kind: "narrixThenDirect.request",
1166
+ skillKey: request.skillKey,
1167
+ jobId: request.jobId,
1168
+ agentId: request.agentId,
1169
+ narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1170
+ }, {
1171
+ kind: "narrixThenDirect.result",
1172
+ ok: true,
1173
+ durationMs: narrixDurationMs,
1174
+ }, { phase: "narrix_then_direct" }),
1101
1175
  })
1102
1176
  .catch(() => undefined);
1103
1177
  }
1104
- return withTrace({
1105
- skillKey: request.skillKey,
1106
- rawText: JSON.stringify(narrixResult, null, 2),
1107
- flexMd: { frame: "narrixThenDirect.v1", payloads: { narrix: JSON.stringify(narrixResult) } },
1108
- parsed: {
1109
- ok: false,
1110
- error: narrixResult.error,
1111
- phase: "narrix",
1112
- message: narrixResult.message,
1113
- },
1114
- metadata: {
1115
- instructionVersion: "narrix-then-direct",
1116
- narrix: { ...narrixResult, durationMs: narrixDurationMs },
1117
- narrixMode: knobs.narrixMode,
1118
- inputStrategyKey: knobs.inputStrategyKey,
1119
- executionStrategiesSummary: executionStrategiesSummaryFromKnobs(knobs),
1120
- },
1121
- });
1122
1178
  }
1123
- const filteredEntry = applyNarrixScope(narrixResult, request.narrixScope);
1124
- const existingNarrix = Array.isArray(request.taskMemory?.narrix)
1125
- ? request.taskMemory.narrix
1126
- : [];
1127
- const updatedTaskMemory = {
1128
- ...(request.taskMemory ?? {}),
1129
- narrix: [...existingNarrix, filteredEntry],
1130
- };
1131
- const skillInput = typeof request.input === "object" && request.input !== null
1132
- ? { ...request.input, narrixContext: filteredEntry }
1133
- : { narrixContext: filteredEntry };
1134
- request = {
1135
- ...request,
1136
- taskMemory: updatedTaskMemory,
1137
- input: skillInput,
1138
- };
1139
- if (ax && correlationId && narrixThenDirectPhaseRecordId) {
1140
- await ax
1141
- .completeRecord(narrixThenDirectPhaseRecordId, {
1142
- narrixDurationMs,
1143
- outer: activixOuterTier({
1144
- kind: "narrixThenDirect.request",
1145
- skillKey: request.skillKey,
1146
- jobId: request.jobId,
1147
- agentId: request.agentId,
1148
- narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1149
- }, {
1150
- kind: "narrixThenDirect.result",
1151
- ok: true,
1152
- durationMs: narrixDurationMs,
1153
- }, { phase: "narrix_then_direct" }),
1154
- })
1155
- .catch(() => undefined);
1179
+ catch (error) {
1180
+ if (ax && correlationId && narrixThenDirectPhaseRecordId) {
1181
+ await ax
1182
+ .failRecord(narrixThenDirectPhaseRecordId, error instanceof Error ? error : new Error(String(error)), {
1183
+ errorMessage: error instanceof Error ? error.message : String(error),
1184
+ errorCode: error?.code,
1185
+ outer: activixOuterTier({
1186
+ kind: "narrixThenDirect.request",
1187
+ skillKey: request.skillKey,
1188
+ jobId: request.jobId,
1189
+ agentId: request.agentId,
1190
+ narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1191
+ }, {
1192
+ kind: "narrixThenDirect.error",
1193
+ message: error instanceof Error ? error.message : String(error),
1194
+ }, { phase: "narrix_then_direct" }),
1195
+ })
1196
+ .catch(() => undefined);
1197
+ }
1198
+ throw error;
1156
1199
  }
1157
1200
  }
1158
- catch (error) {
1159
- if (ax && correlationId && narrixThenDirectPhaseRecordId) {
1160
- await ax
1161
- .failRecord(narrixThenDirectPhaseRecordId, error instanceof Error ? error : new Error(String(error)), {
1162
- errorMessage: error instanceof Error ? error.message : String(error),
1163
- errorCode: error?.code,
1201
+ // Local task dispatch: if a handler is registered, run it and return (no enrichment)
1202
+ const handler = getLocalTask(request.skillKey);
1203
+ if (handler) {
1204
+ const result = await traceWrap(traceCollector, {
1205
+ taskType: "pre-execution",
1206
+ details: "local task handler",
1207
+ metadata: {
1208
+ ...baseTraceMeta(),
1209
+ phase: "local",
1210
+ localSkillKey: request.skillKey,
1211
+ },
1212
+ modelUsed: null,
1213
+ }, async () => withPhaseRecord({
1214
+ ax,
1215
+ correlationId,
1216
+ phase: "local",
1217
+ meta: {
1218
+ ...baseMeta,
1219
+ localSkillKey: request.skillKey,
1164
1220
  outer: activixOuterTier({
1165
- kind: "narrixThenDirect.request",
1221
+ kind: "localTask.request",
1166
1222
  skillKey: request.skillKey,
1167
1223
  jobId: request.jobId,
1168
1224
  agentId: request.agentId,
1169
- narrixInput: summarizeForOuter(resolvedNarrixInput, 6_000),
1170
- }, {
1171
- kind: "narrixThenDirect.error",
1172
- message: error instanceof Error ? error.message : String(error),
1173
- }, { phase: "narrix_then_direct" }),
1174
- })
1175
- .catch(() => undefined);
1176
- }
1177
- throw error;
1178
- }
1179
- }
1180
- // Local task dispatch: if a handler is registered, run it and return (no enrichment)
1181
- const handler = getLocalTask(request.skillKey);
1182
- if (handler) {
1183
- const result = await traceWrap(traceCollector, {
1184
- taskType: "pre-execution",
1185
- details: "local task handler",
1186
- metadata: {
1187
- ...baseTraceMeta(),
1188
- phase: "local",
1189
- localSkillKey: request.skillKey,
1190
- },
1191
- modelUsed: null,
1192
- }, async () => withPhaseRecord({
1193
- ax,
1194
- correlationId,
1195
- phase: "local",
1196
- meta: {
1197
- ...baseMeta,
1198
- localSkillKey: request.skillKey,
1199
- outer: activixOuterTier({
1200
- kind: "localTask.request",
1201
- skillKey: request.skillKey,
1202
- jobId: request.jobId,
1203
- agentId: request.agentId,
1204
- input: summarizeForOuter(request.input, 4_000),
1205
- }, null, { phase: "local" }),
1206
- },
1207
- fn: async () => {
1208
- const started = Date.now();
1209
- const ctx = {
1210
- skillKey: request.skillKey,
1211
- jobMemory: request.jobMemory,
1212
- taskMemory: request.taskMemory,
1213
- executionMemory: request.executionMemory,
1214
- variables: input.variables,
1215
- xynthesized: request.xynthesized,
1216
- smartInput: request.smartInput,
1217
- jobId: input.jobId,
1218
- taskId: input.taskId,
1219
- agentId: input.agentId,
1220
- graphId: input.graphId,
1221
- nodeId: input.nodeId,
1222
- prevNodeId: input.prevNodeId,
1223
- coreSkillId: input.coreSkillId,
1224
- masterSkillId: request.masterSkillId,
1225
- masterSkillActivityId: request.masterSkillActivityId,
1226
- };
1227
- const value = await handler({ input: request.input, ctx });
1228
- const durationMs = Date.now() - started;
1229
- let parsed = value;
1230
- let intermediateSteps;
1231
- if (value !== null &&
1232
- typeof value === "object" &&
1233
- !Array.isArray(value) &&
1234
- "intermediateSteps" in value) {
1235
- const steps = value.intermediateSteps;
1236
- if (Array.isArray(steps) &&
1237
- steps.length > 0 &&
1238
- steps.every((s) => typeof s === "object" && s !== null && "step" in s && "id" in s && "ok" in s)) {
1239
- intermediateSteps = steps;
1240
- const { intermediateSteps: _removed, ...rest } = value;
1241
- parsed = (Object.keys(rest).length > 0 ? rest : undefined);
1242
- }
1243
- }
1244
- const response = {
1245
- skillKey: request.skillKey,
1246
- rawText: JSON.stringify(value, null, 2),
1247
- flexMd: {
1248
- frame: "localTask.v1",
1249
- payloads: { value: JSON.stringify(value, null, 2) },
1250
- },
1251
- parsed,
1252
- metadata: {
1253
- instructionVersion: "local",
1254
- activityId: undefined,
1255
- durationMs,
1256
- localSkillKey: request.skillKey,
1257
- },
1258
- };
1259
- if (intermediateSteps)
1260
- response.intermediateSteps = intermediateSteps;
1261
- if (isStrictDecisionTask(request)) {
1262
- const parsedMissing = response.parsed === undefined || response.parsed === null;
1263
- if (parsedMissing) {
1264
- throw new Error(`Decision task "${request.skillKey}" did not return response.parsed`);
1225
+ input: summarizeForOuter(request.input, 4_000),
1226
+ }, null, { phase: "local" }),
1227
+ },
1228
+ fn: async () => {
1229
+ const started = Date.now();
1230
+ const ctx = {
1231
+ skillKey: request.skillKey,
1232
+ jobMemory: request.jobMemory,
1233
+ taskMemory: request.taskMemory,
1234
+ executionMemory: request.executionMemory,
1235
+ variables: input.variables,
1236
+ xynthesized: request.xynthesized,
1237
+ smartInput: request.smartInput,
1238
+ jobId: input.jobId,
1239
+ taskId: input.taskId,
1240
+ agentId: input.agentId,
1241
+ graphId: input.graphId,
1242
+ nodeId: input.nodeId,
1243
+ prevNodeId: input.prevNodeId,
1244
+ coreSkillId: input.coreSkillId,
1245
+ masterSkillId: request.masterSkillId,
1246
+ masterSkillActivityId: request.masterSkillActivityId,
1247
+ };
1248
+ const value = await handler({ input: request.input, ctx });
1249
+ const durationMs = Date.now() - started;
1250
+ let parsed = value;
1251
+ let intermediateSteps;
1252
+ if (value !== null &&
1253
+ typeof value === "object" &&
1254
+ !Array.isArray(value) &&
1255
+ "intermediateSteps" in value) {
1256
+ const steps = value.intermediateSteps;
1257
+ if (Array.isArray(steps) &&
1258
+ steps.length > 0 &&
1259
+ steps.every((s) => typeof s === "object" && s !== null && "step" in s && "id" in s && "ok" in s)) {
1260
+ intermediateSteps = steps;
1261
+ const { intermediateSteps: _removed, ...rest } = value;
1262
+ parsed = (Object.keys(rest).length > 0 ? rest : undefined);
1263
+ }
1265
1264
  }
1266
- }
1267
- const outputValidation = request.outputValidation;
1268
- if (outputValidation?.schema) {
1269
- const validateWhenMissing = outputValidation.validateWhenMissing !== false;
1270
- if (validateWhenMissing || response.parsed !== undefined) {
1271
- const vr = validateParsedOutput(response.parsed, outputValidation.schema);
1272
- vr.correlationId = taskId;
1273
- response.metadata = { ...response.metadata, outputValidation: vr };
1274
- if (!vr.ok && (outputValidation.mode ?? "fail") === "fail") {
1275
- throw new Error(`outputValidation failed for skillKey ${request.skillKey}: ` +
1276
- vr.errors.map((e) => `${e.path} ${e.message}`).join("; "));
1265
+ const response = {
1266
+ skillKey: request.skillKey,
1267
+ rawText: JSON.stringify(value, null, 2),
1268
+ flexMd: {
1269
+ frame: "localTask.v1",
1270
+ payloads: { value: JSON.stringify(value, null, 2) },
1271
+ },
1272
+ parsed,
1273
+ metadata: {
1274
+ instructionVersion: "local",
1275
+ activityId: undefined,
1276
+ durationMs,
1277
+ localSkillKey: request.skillKey,
1278
+ },
1279
+ };
1280
+ if (intermediateSteps)
1281
+ response.intermediateSteps = intermediateSteps;
1282
+ if (isStrictDecisionTask(request)) {
1283
+ const parsedMissing = response.parsed === undefined || response.parsed === null;
1284
+ if (parsedMissing) {
1285
+ throw new Error(`Decision task "${request.skillKey}" did not return response.parsed`);
1277
1286
  }
1278
- if (!vr.ok && (outputValidation.mode ?? "fail") === "warn") {
1287
+ }
1288
+ const outputValidation = request.outputValidation;
1289
+ if (outputValidation?.schema) {
1290
+ const validateWhenMissing = outputValidation.validateWhenMissing !== false;
1291
+ if (validateWhenMissing || response.parsed !== undefined) {
1292
+ const vr = validateParsedOutput(response.parsed, outputValidation.schema);
1293
+ vr.correlationId = taskId;
1294
+ response.metadata = { ...response.metadata, outputValidation: vr };
1295
+ if (!vr.ok && (outputValidation.mode ?? "fail") === "fail") {
1296
+ throw new Error(`outputValidation failed for skillKey ${request.skillKey}: ` +
1297
+ vr.errors.map((e) => `${e.path} ${e.message}`).join("; "));
1298
+ }
1299
+ if (!vr.ok && (outputValidation.mode ?? "fail") === "warn") {
1300
+ }
1279
1301
  }
1280
1302
  }
1281
- }
1282
- return response;
1283
- },
1284
- onSuccessUpdates: (result) => {
1285
- const steps = result?.intermediateSteps;
1286
- return {
1287
- localSkillKey: result?.metadata?.localSkillKey,
1288
- durationMs: result?.metadata?.durationMs,
1289
- hasIntermediateSteps: Array.isArray(steps) && steps.length > 0,
1290
- stepCount: Array.isArray(steps) ? steps.length : undefined,
1291
- outer: activixOuterTier({
1292
- kind: "localTask.request",
1293
- skillKey: request.skillKey,
1294
- jobId: request.jobId,
1295
- agentId: request.agentId,
1296
- input: summarizeForOuter(request.input, 4_000),
1297
- }, {
1298
- kind: "localTask.response",
1299
- skillKey: result?.skillKey,
1300
- metadata: summarizeForOuter(result?.metadata, 4_000),
1301
- parsed: summarizeForOuter(result?.parsed, 8_000),
1302
- }, { phase: "local" }),
1303
- };
1304
- },
1305
- }), (r) => ({
1306
- metadata: {
1307
- durationMs: r?.metadata?.durationMs,
1308
- },
1309
- modelUsed: null,
1310
- }));
1311
- return withTrace(finalize(result));
1312
- }
1313
- // Execution pipeline: when request.executionPipeline is set, run PRE steps then main then POST
1314
- const pipeline = request.executionPipeline;
1315
- if (pipeline && Array.isArray(pipeline) && pipeline.length > 0) {
1316
- const mainSteps = pipeline.filter((s) => s.phase === "main");
1317
- if (mainSteps.length !== 1) {
1318
- throw new Error(`executionPipeline must have exactly one step with phase "main"; got ${mainSteps.length}. skillKey: ${request.skillKey}`);
1303
+ return response;
1304
+ },
1305
+ onSuccessUpdates: (result) => {
1306
+ const steps = result?.intermediateSteps;
1307
+ return {
1308
+ localSkillKey: result?.metadata?.localSkillKey,
1309
+ durationMs: result?.metadata?.durationMs,
1310
+ hasIntermediateSteps: Array.isArray(steps) && steps.length > 0,
1311
+ stepCount: Array.isArray(steps) ? steps.length : undefined,
1312
+ outer: activixOuterTier({
1313
+ kind: "localTask.request",
1314
+ skillKey: request.skillKey,
1315
+ jobId: request.jobId,
1316
+ agentId: request.agentId,
1317
+ input: summarizeForOuter(request.input, 4_000),
1318
+ }, {
1319
+ kind: "localTask.response",
1320
+ skillKey: result?.skillKey,
1321
+ metadata: summarizeForOuter(result?.metadata, 4_000),
1322
+ parsed: summarizeForOuter(result?.parsed, 8_000),
1323
+ }, { phase: "local" }),
1324
+ };
1325
+ },
1326
+ }), (r) => ({
1327
+ metadata: {
1328
+ durationMs: r?.metadata?.durationMs,
1329
+ },
1330
+ modelUsed: null,
1331
+ }));
1332
+ return withTrace(finalize(result));
1319
1333
  }
1320
- const preSteps = pipeline.filter((s) => s.phase === "pre");
1321
- let overrideContext;
1322
- let synthesizedArtifact;
1323
- let detectedTemplateCores = [];
1324
- // Aggregated trace-mode-only LlmCallObservations from PRE synthesis (markdown/structured/questionDriven).
1325
- // Lifted into `result.metadata.synthesizedContextLlmCalls` once the pipeline finishes.
1326
- const aggregatedSynthLlmCalls = [];
1327
- for (const step of preSteps) {
1328
- if (step.type !== SYNTHESIZED_CONTEXT) {
1329
- throw new Error(`executionPipeline: unsupported PRE step type "${String(step.type)}". Only "${SYNTHESIZED_CONTEXT}" (Xynthesis synthesized-context) is supported.`);
1334
+ // Execution pipeline: when request.executionPipeline is set, run PRE steps then main then POST
1335
+ const pipeline = request.executionPipeline;
1336
+ if (pipeline && Array.isArray(pipeline) && pipeline.length > 0) {
1337
+ const mainSteps = pipeline.filter((s) => s.phase === "main");
1338
+ if (mainSteps.length !== 1) {
1339
+ throw new Error(`executionPipeline must have exactly one step with phase "main"; got ${mainSteps.length}. skillKey: ${request.skillKey}`);
1330
1340
  }
1331
- {
1332
- const config = (step.config ?? {});
1333
- if (request.includeContextInPrompt !== true && config.autoEnableContext !== true) {
1334
- throw new Error("synthesized-context PRE step requires includeContextInPrompt: true or synthesisConfig.autoEnableContext: true");
1341
+ const preSteps = pipeline.filter((s) => s.phase === "pre");
1342
+ let overrideContext;
1343
+ let synthesizedArtifact;
1344
+ let detectedTemplateCores = [];
1345
+ // Aggregated trace-mode-only LlmCallObservations from PRE synthesis (markdown/structured/questionDriven).
1346
+ // Lifted into `result.metadata.synthesizedContextLlmCalls` once the pipeline finishes.
1347
+ const aggregatedSynthLlmCalls = [];
1348
+ for (const step of preSteps) {
1349
+ if (step.type !== SYNTHESIZED_CONTEXT) {
1350
+ throw new Error(`executionPipeline: unsupported PRE step type "${String(step.type)}". Only "${SYNTHESIZED_CONTEXT}" (Xynthesis synthesized-context) is supported.`);
1335
1351
  }
1336
- const reqWithContext = { ...request, includeContextInPrompt: true };
1337
- const cachedSynth = request.executionMemory?.synthesizedContext;
1338
- const preStepResult = config.reuseCachedSynthesizedContext === true &&
1339
- cachedSynth &&
1340
- reuseableSynthesizedArtifact(cachedSynth)
1341
- ? {
1342
- contextMarkdown: contextMarkdownFromArtifact(cachedSynth),
1343
- artifact: cachedSynth,
1344
- synthesizedInput: request.executionMemory?.synthesizedInput,
1352
+ {
1353
+ const config = (step.config ?? {});
1354
+ if (request.includeContextInPrompt !== true && config.autoEnableContext !== true) {
1355
+ throw new Error("synthesized-context PRE step requires includeContextInPrompt: true or synthesisConfig.autoEnableContext: true");
1345
1356
  }
1346
- : await traceWrap(traceCollector, {
1347
- taskType: "pre-execution",
1348
- details: "synthesized-context pre step",
1349
- metadata: {
1350
- ...baseTraceMeta(),
1351
- phase: "pipeline_pre",
1352
- preStepType: "synthesized-context",
1353
- synthesisMode: resolveSynthesisMode(config),
1354
- reusedCache: false,
1355
- ...(config.xynthesizedOutput && traceCollector
1356
- ? {
1357
- xynthesized: {
1358
- inputPathsUsed: [...(config.memoryPaths ?? [])],
1359
- outputDestination: config.xynthesizedOutput.destination,
1360
- outputKey: config.xynthesizedOutput.outputKey,
1361
- patchKeys: [config.xynthesizedOutput.outputKey],
1362
- },
1363
- smartInput: {
1364
- paths: reqWithContext.smartInput?.paths ?? [],
1365
- },
1366
- }
1367
- : traceCollector
1357
+ const reqWithContext = { ...request, includeContextInPrompt: true };
1358
+ const cachedSynth = request.executionMemory?.synthesizedContext;
1359
+ const preStepResult = config.reuseCachedSynthesizedContext === true &&
1360
+ cachedSynth &&
1361
+ reuseableSynthesizedArtifact(cachedSynth)
1362
+ ? {
1363
+ contextMarkdown: contextMarkdownFromArtifact(cachedSynth),
1364
+ artifact: cachedSynth,
1365
+ synthesizedInput: request.executionMemory?.synthesizedInput,
1366
+ }
1367
+ : await traceWrap(traceCollector, {
1368
+ taskType: "pre-execution",
1369
+ details: "synthesized-context pre step",
1370
+ metadata: {
1371
+ ...baseTraceMeta(),
1372
+ phase: "pipeline_pre",
1373
+ preStepType: "synthesized-context",
1374
+ synthesisMode: resolveSynthesisMode(config),
1375
+ reusedCache: false,
1376
+ ...(config.xynthesizedOutput && traceCollector
1368
1377
  ? {
1378
+ xynthesized: {
1379
+ inputPathsUsed: [...(config.memoryPaths ?? [])],
1380
+ outputDestination: config.xynthesizedOutput.destination,
1381
+ outputKey: config.xynthesizedOutput.outputKey,
1382
+ patchKeys: [config.xynthesizedOutput.outputKey],
1383
+ },
1369
1384
  smartInput: {
1370
1385
  paths: reqWithContext.smartInput?.paths ?? [],
1371
1386
  },
1372
1387
  }
1388
+ : traceCollector
1389
+ ? {
1390
+ smartInput: {
1391
+ paths: reqWithContext.smartInput?.paths ?? [],
1392
+ },
1393
+ }
1394
+ : {}),
1395
+ },
1396
+ }, async () => withPhaseRecord({
1397
+ ax,
1398
+ correlationId,
1399
+ phase: "pipeline_pre",
1400
+ meta: {
1401
+ ...baseMeta,
1402
+ preStepType: "synthesized-context",
1403
+ outer: activixOuterTier({
1404
+ kind: "pipelinePre.synthesizedContext.request",
1405
+ skillKey: reqWithContext.skillKey,
1406
+ jobId: reqWithContext.jobId,
1407
+ agentId: reqWithContext.agentId,
1408
+ contextSourcePolicy: config?.contextSourcePolicy,
1409
+ synthesisMode: resolveSynthesisMode(config),
1410
+ input: summarizeForOuter(reqWithContext.input, 4_000),
1411
+ }, null, { phase: "pipeline_pre" }),
1412
+ },
1413
+ fn: async () => this._runSynthesizedContextPreStep(reqWithContext, config, traceCollector),
1414
+ onSuccessUpdates: (r) => ({
1415
+ outer: activixOuterTier({
1416
+ kind: "pipelinePre.synthesizedContext.request",
1417
+ skillKey: reqWithContext.skillKey,
1418
+ jobId: reqWithContext.jobId,
1419
+ agentId: reqWithContext.agentId,
1420
+ contextSourcePolicy: config?.contextSourcePolicy,
1421
+ synthesisMode: resolveSynthesisMode(config),
1422
+ input: summarizeForOuter(reqWithContext.input, 4_000),
1423
+ }, {
1424
+ kind: "pipelinePre.synthesizedContext.result",
1425
+ contextMarkdown: summarizeForOuter(r.contextMarkdown, 8_000),
1426
+ artifact: r.artifact
1427
+ ? {
1428
+ mode: r.artifact.mode,
1429
+ templateCores: r.artifact?.templateCores ?? [],
1430
+ question: typeof r.artifact?.question === "string"
1431
+ ? summarizeForOuter(r.artifact.question, 2_000)
1432
+ : undefined,
1433
+ }
1434
+ : undefined,
1435
+ }, { phase: "pipeline_pre" }),
1436
+ }),
1437
+ }), (r) => ({
1438
+ metadata: {
1439
+ synthesizedContextChars: typeof r.contextMarkdown === "string" ? r.contextMarkdown.length : 0,
1440
+ ...(config.xynthesizedOutput && traceCollector
1441
+ ? {
1442
+ xynthesized: {
1443
+ inputPathsUsed: [...(config.memoryPaths ?? [])],
1444
+ outputDestination: config.xynthesizedOutput.destination,
1445
+ outputKey: config.xynthesizedOutput.outputKey,
1446
+ patchKeys: [config.xynthesizedOutput.outputKey],
1447
+ },
1448
+ }
1373
1449
  : {}),
1374
- },
1375
- }, async () => withPhaseRecord({
1376
- ax,
1377
- correlationId,
1378
- phase: "pipeline_pre",
1379
- meta: {
1380
- ...baseMeta,
1381
- preStepType: "synthesized-context",
1382
- outer: activixOuterTier({
1383
- kind: "pipelinePre.synthesizedContext.request",
1384
- skillKey: reqWithContext.skillKey,
1385
- jobId: reqWithContext.jobId,
1386
- agentId: reqWithContext.agentId,
1387
- contextSourcePolicy: config?.contextSourcePolicy,
1388
- synthesisMode: resolveSynthesisMode(config),
1389
- input: summarizeForOuter(reqWithContext.input, 4_000),
1390
- }, null, { phase: "pipeline_pre" }),
1391
- },
1392
- fn: async () => this._runSynthesizedContextPreStep(reqWithContext, config, traceCollector),
1393
- onSuccessUpdates: (r) => ({
1394
- outer: activixOuterTier({
1395
- kind: "pipelinePre.synthesizedContext.request",
1396
- skillKey: reqWithContext.skillKey,
1397
- jobId: reqWithContext.jobId,
1398
- agentId: reqWithContext.agentId,
1399
- contextSourcePolicy: config?.contextSourcePolicy,
1450
+ },
1451
+ }));
1452
+ overrideContext = preStepResult.contextMarkdown;
1453
+ synthesizedArtifact = preStepResult.artifact;
1454
+ if (traceCollector && preStepResult.synthesizedContextLlmCalls) {
1455
+ aggregatedSynthLlmCalls.push(...preStepResult.synthesizedContextLlmCalls);
1456
+ }
1457
+ if (synthesizedArtifact) {
1458
+ detectedTemplateCores = synthesizedArtifact?.templateCores ?? [];
1459
+ }
1460
+ const xynthOut = config.xynthesizedOutput;
1461
+ const writeLegacyToExecutionMemory = !xynthOut || xynthOut.alsoWriteLegacySynthesizedContext !== false;
1462
+ if (synthesizedArtifact && writeLegacyToExecutionMemory) {
1463
+ request = {
1464
+ ...request,
1465
+ executionMemory: {
1466
+ ...(request.executionMemory ?? {}),
1467
+ synthesizedContext: synthesizedArtifact,
1468
+ ...(preStepResult.synthesizedInput ? { synthesizedInput: preStepResult.synthesizedInput } : {}),
1469
+ },
1470
+ };
1471
+ }
1472
+ if (xynthOut) {
1473
+ const synthesizedResult = synthesizedResultForXynthesizedPatch(synthesizedArtifact, preStepResult.contextMarkdown);
1474
+ const { nextXynthesized, patchSlice } = applyXynthesizedOutputWrite(request.xynthesized, xynthOut, synthesizedResult);
1475
+ request = { ...request, xynthesized: nextXynthesized };
1476
+ xynthesizedPatchAccumulator = mergeXynthesizedPatchSlices(xynthesizedPatchAccumulator, patchSlice);
1477
+ }
1478
+ if (traceCollector &&
1479
+ config.reuseCachedSynthesizedContext === true &&
1480
+ cachedSynth &&
1481
+ reuseableSynthesizedArtifact(cachedSynth)) {
1482
+ traceCollector.push({
1483
+ taskType: "pre-execution",
1484
+ details: "synthesized-context pre step (reused cached artifact)",
1485
+ metadata: {
1486
+ ...baseTraceMeta(),
1487
+ phase: "pipeline_pre",
1488
+ preStepType: "synthesized-context",
1400
1489
  synthesisMode: resolveSynthesisMode(config),
1401
- input: summarizeForOuter(reqWithContext.input, 4_000),
1402
- }, {
1403
- kind: "pipelinePre.synthesizedContext.result",
1404
- contextMarkdown: summarizeForOuter(r.contextMarkdown, 8_000),
1405
- artifact: r.artifact
1490
+ reusedCache: true,
1491
+ ...(config.xynthesizedOutput
1406
1492
  ? {
1407
- mode: r.artifact.mode,
1408
- templateCores: r.artifact?.templateCores ?? [],
1409
- question: typeof r.artifact?.question === "string"
1410
- ? summarizeForOuter(r.artifact.question, 2_000)
1411
- : undefined,
1493
+ xynthesized: {
1494
+ inputPathsUsed: [...(config.memoryPaths ?? [])],
1495
+ outputDestination: config.xynthesizedOutput.destination,
1496
+ outputKey: config.xynthesizedOutput.outputKey,
1497
+ patchKeys: [config.xynthesizedOutput.outputKey],
1498
+ },
1499
+ smartInput: {
1500
+ paths: request.smartInput?.paths ?? [],
1501
+ },
1412
1502
  }
1413
- : undefined,
1414
- }, { phase: "pipeline_pre" }),
1415
- }),
1416
- }), (r) => ({
1417
- metadata: {
1418
- synthesizedContextChars: typeof r.contextMarkdown === "string" ? r.contextMarkdown.length : 0,
1419
- ...(config.xynthesizedOutput && traceCollector
1420
- ? {
1421
- xynthesized: {
1422
- inputPathsUsed: [...(config.memoryPaths ?? [])],
1423
- outputDestination: config.xynthesizedOutput.destination,
1424
- outputKey: config.xynthesizedOutput.outputKey,
1425
- patchKeys: [config.xynthesizedOutput.outputKey],
1426
- },
1427
- }
1428
- : {}),
1429
- },
1430
- }));
1431
- overrideContext = preStepResult.contextMarkdown;
1432
- synthesizedArtifact = preStepResult.artifact;
1433
- if (traceCollector && preStepResult.synthesizedContextLlmCalls) {
1434
- aggregatedSynthLlmCalls.push(...preStepResult.synthesizedContextLlmCalls);
1503
+ : {
1504
+ smartInput: {
1505
+ paths: request.smartInput?.paths ?? [],
1506
+ },
1507
+ }),
1508
+ },
1509
+ modelUsed: null,
1510
+ });
1511
+ }
1512
+ break;
1435
1513
  }
1436
- if (synthesizedArtifact) {
1437
- detectedTemplateCores = synthesizedArtifact?.templateCores ?? [];
1514
+ }
1515
+ const synthesizedFromExecution = request.executionMemory?.synthesizedContext &&
1516
+ typeof request.executionMemory.synthesizedContext === "object";
1517
+ const mainContextSource = synthesizedFromExecution ? "synthesizedContext" : "unsynthesized";
1518
+ if (mainContextSource === "synthesizedContext") {
1519
+ const artifact = request.executionMemory?.synthesizedContext;
1520
+ if (artifact && typeof artifact === "object" && typeof artifact.contextMarkdown === "string") {
1521
+ overrideContext = artifact.contextMarkdown;
1438
1522
  }
1439
- const xynthOut = config.xynthesizedOutput;
1440
- const writeLegacyToExecutionMemory = !xynthOut || xynthOut.alsoWriteLegacySynthesizedContext !== false;
1441
- if (synthesizedArtifact && writeLegacyToExecutionMemory) {
1442
- request = {
1443
- ...request,
1444
- executionMemory: {
1445
- ...(request.executionMemory ?? {}),
1446
- synthesizedContext: synthesizedArtifact,
1447
- ...(preStepResult.synthesizedInput ? { synthesizedInput: preStepResult.synthesizedInput } : {}),
1523
+ }
1524
+ const postSteps = pipeline.filter((s) => s.phase === "post");
1525
+ const observability = {
1526
+ synthesisEnabled: preSteps.some((s) => s.type === SYNTHESIZED_CONTEXT),
1527
+ effectiveExecutionPipeline: pipeline,
1528
+ synthesizedContextPresent: synthesizedFromExecution,
1529
+ mainContextSource,
1530
+ detectedTemplateCores,
1531
+ synthesisMode: synthesizedArtifact?.mode === "markdown" || synthesizedArtifact?.mode === "structured"
1532
+ ? synthesizedArtifact.mode
1533
+ : undefined,
1534
+ };
1535
+ const directOpts = {
1536
+ overrideContext,
1537
+ synthesisContextAuthoritative: mainContextSource === "synthesizedContext",
1538
+ };
1539
+ if (postSteps.length === 0) {
1540
+ const result = finalize(await runMainWithExecutionStrategies(request, directOpts));
1541
+ if (overrideContext !== undefined) {
1542
+ const synthesisStep = {
1543
+ step: 1,
1544
+ id: "synthesis",
1545
+ ok: true,
1546
+ summary: "context synthesized",
1547
+ outputExcerpt: {
1548
+ mainContextSource,
1549
+ synthesizedContextPresent: observability.synthesizedContextPresent,
1550
+ detectedTemplateCores: observability.detectedTemplateCores ?? [],
1448
1551
  },
1449
1552
  };
1553
+ const existingSteps = result.intermediateSteps ?? [];
1554
+ result.intermediateSteps = [
1555
+ synthesisStep,
1556
+ ...existingSteps.map((s, i) => ({ ...s, step: i + 2 })),
1557
+ ];
1450
1558
  }
1451
- if (xynthOut) {
1452
- const synthesizedResult = synthesizedResultForXynthesizedPatch(synthesizedArtifact, preStepResult.contextMarkdown);
1453
- const { nextXynthesized, patchSlice } = applyXynthesizedOutputWrite(request.xynthesized, xynthOut, synthesizedResult);
1454
- request = { ...request, xynthesized: nextXynthesized };
1455
- xynthesizedPatchAccumulator = mergeXynthesizedPatchSlices(xynthesizedPatchAccumulator, patchSlice);
1456
- }
1457
- if (traceCollector &&
1458
- config.reuseCachedSynthesizedContext === true &&
1459
- cachedSynth &&
1460
- reuseableSynthesizedArtifact(cachedSynth)) {
1461
- traceCollector.push({
1462
- taskType: "pre-execution",
1463
- details: "synthesized-context pre step (reused cached artifact)",
1464
- metadata: {
1465
- ...baseTraceMeta(),
1466
- phase: "pipeline_pre",
1467
- preStepType: "synthesized-context",
1468
- synthesisMode: resolveSynthesisMode(config),
1469
- reusedCache: true,
1470
- ...(config.xynthesizedOutput
1471
- ? {
1472
- xynthesized: {
1473
- inputPathsUsed: [...(config.memoryPaths ?? [])],
1474
- outputDestination: config.xynthesizedOutput.destination,
1475
- outputKey: config.xynthesizedOutput.outputKey,
1476
- patchKeys: [config.xynthesizedOutput.outputKey],
1477
- },
1478
- smartInput: {
1479
- paths: request.smartInput?.paths ?? [],
1480
- },
1481
- }
1482
- : {
1483
- smartInput: {
1484
- paths: request.smartInput?.paths ?? [],
1485
- },
1486
- }),
1487
- },
1488
- modelUsed: null,
1489
- });
1559
+ attachExecutionStateAndObservability(result, request, observability);
1560
+ if (traceCollector && aggregatedSynthLlmCalls.length > 0) {
1561
+ result.metadata = {
1562
+ ...(result.metadata ?? {}),
1563
+ synthesizedContextLlmCalls: aggregatedSynthLlmCalls,
1564
+ };
1490
1565
  }
1491
- break;
1492
- }
1493
- }
1494
- const synthesizedFromExecution = request.executionMemory?.synthesizedContext &&
1495
- typeof request.executionMemory.synthesizedContext === "object";
1496
- const mainContextSource = synthesizedFromExecution ? "synthesizedContext" : "unsynthesized";
1497
- if (mainContextSource === "synthesizedContext") {
1498
- const artifact = request.executionMemory?.synthesizedContext;
1499
- if (artifact && typeof artifact === "object" && typeof artifact.contextMarkdown === "string") {
1500
- overrideContext = artifact.contextMarkdown;
1566
+ return withTrace(result);
1501
1567
  }
1502
- }
1503
- const postSteps = pipeline.filter((s) => s.phase === "post");
1504
- const observability = {
1505
- synthesisEnabled: preSteps.some((s) => s.type === SYNTHESIZED_CONTEXT),
1506
- effectiveExecutionPipeline: pipeline,
1507
- synthesizedContextPresent: synthesizedFromExecution,
1508
- mainContextSource,
1509
- detectedTemplateCores,
1510
- synthesisMode: synthesizedArtifact?.mode === "markdown" || synthesizedArtifact?.mode === "structured"
1511
- ? synthesizedArtifact.mode
1512
- : undefined,
1513
- };
1514
- const directOpts = {
1515
- overrideContext,
1516
- synthesisContextAuthoritative: mainContextSource === "synthesizedContext",
1517
- };
1518
- if (postSteps.length === 0) {
1519
- const result = finalize(await runMainWithExecutionStrategies(request, directOpts));
1568
+ const capture = { contextMarkdown: "" };
1569
+ let result = finalize(await runMainWithExecutionStrategies(request, { ...directOpts, captureContext: capture }));
1520
1570
  if (overrideContext !== undefined) {
1521
1571
  const synthesisStep = {
1522
1572
  step: 1,
@@ -1535,212 +1585,190 @@ export class WorexClientTasks {
1535
1585
  ...existingSteps.map((s, i) => ({ ...s, step: i + 2 })),
1536
1586
  ];
1537
1587
  }
1538
- attachExecutionStateAndObservability(result, request, observability);
1539
- if (traceCollector && aggregatedSynthLlmCalls.length > 0) {
1540
- result.metadata = {
1541
- ...(result.metadata ?? {}),
1542
- synthesizedContextLlmCalls: aggregatedSynthLlmCalls,
1543
- };
1544
- }
1545
- return withTrace(result);
1546
- }
1547
- const capture = { contextMarkdown: "" };
1548
- let result = finalize(await runMainWithExecutionStrategies(request, { ...directOpts, captureContext: capture }));
1549
- if (overrideContext !== undefined) {
1550
- const synthesisStep = {
1551
- step: 1,
1552
- id: "synthesis",
1553
- ok: true,
1554
- summary: "context synthesized",
1555
- outputExcerpt: {
1556
- mainContextSource,
1557
- synthesizedContextPresent: observability.synthesizedContextPresent,
1558
- detectedTemplateCores: observability.detectedTemplateCores ?? [],
1559
- },
1560
- };
1561
- const existingSteps = result.intermediateSteps ?? [];
1562
- result.intermediateSteps = [
1563
- synthesisStep,
1564
- ...existingSteps.map((s, i) => ({ ...s, step: i + 2 })),
1565
- ];
1566
- }
1567
- let currentOutput = typeof result.rawText === "string"
1568
- ? result.rawText
1569
- : JSON.stringify(result.parsed ?? result.rawText ?? "", null, 2);
1570
- const postStepsMeta = {};
1571
- let nextStepNumber = (result.intermediateSteps?.length ?? 0) + 1;
1572
- const reRunMain = (overrideContextWithFeedback) => runDirect(request, { overrideContext: overrideContextWithFeedback });
1573
- for (const step of postSteps) {
1574
- if (step.type === "audit") {
1575
- const auditResult = await traceWrap(traceCollector, {
1576
- taskType: "post-execution",
1577
- details: "audit post step",
1578
- metadata: {
1579
- ...baseTraceMeta(),
1588
+ let currentOutput = typeof result.rawText === "string"
1589
+ ? result.rawText
1590
+ : JSON.stringify(result.parsed ?? result.rawText ?? "", null, 2);
1591
+ const postStepsMeta = {};
1592
+ let nextStepNumber = (result.intermediateSteps?.length ?? 0) + 1;
1593
+ const reRunMain = (overrideContextWithFeedback) => runDirect(request, { overrideContext: overrideContextWithFeedback });
1594
+ for (const step of postSteps) {
1595
+ if (step.type === "audit") {
1596
+ const auditResult = await traceWrap(traceCollector, {
1597
+ taskType: "post-execution",
1598
+ details: "audit post step",
1599
+ metadata: {
1600
+ ...baseTraceMeta(),
1601
+ phase: "audit",
1602
+ postStepType: "audit",
1603
+ },
1604
+ }, async () => withPhaseRecord({
1605
+ ax,
1606
+ correlationId,
1580
1607
  phase: "audit",
1581
- postStepType: "audit",
1582
- },
1583
- }, async () => withPhaseRecord({
1584
- ax,
1585
- correlationId,
1586
- phase: "audit",
1587
- meta: {
1588
- ...baseMeta,
1589
- postStepType: "audit",
1590
- outer: activixOuterTier({
1591
- kind: "postStep.audit.request",
1592
- skillKey: request.skillKey,
1593
- jobId: request.jobId,
1594
- agentId: request.agentId,
1595
- input: summarizeForOuter({
1596
- currentOutput,
1597
- hasContextMarkdown: !!capture.contextMarkdown,
1598
- }, 8_000),
1599
- }, null, { phase: "audit" }),
1600
- },
1601
- fn: async () => runAuditPostStep({
1602
- request,
1603
- mainResult: result,
1604
- contextMarkdown: capture.contextMarkdown,
1605
- config: (step.config ?? {}),
1606
- reRunMain,
1607
- traceCollector,
1608
- }),
1609
- onSuccessUpdates: (auditResult) => ({
1610
- totalCycles: auditResult.metadata?.totalCycles,
1611
- allMustPassed: auditResult.metadata?.allMustPassed,
1612
- synthesisUsed: auditResult.metadata?.synthesisUsed,
1613
- durationMs: auditResult.metadata?.durationMs,
1614
- outer: activixOuterTier({
1615
- kind: "postStep.audit.request",
1616
- skillKey: request.skillKey,
1617
- jobId: request.jobId,
1618
- agentId: request.agentId,
1619
- input: summarizeForOuter({
1620
- currentOutput,
1621
- hasContextMarkdown: !!capture.contextMarkdown,
1622
- }, 8_000),
1623
- }, {
1624
- kind: "postStep.audit.result",
1625
- outputText: summarizeForOuter(auditResult.outputText, 8_000),
1626
- metadata: summarizeForOuter(auditResult.metadata, 6_000),
1627
- }, { phase: "audit" }),
1628
- }),
1629
- }), (r) => ({
1630
- metadata: {
1631
- durationMs: r?.metadata?.durationMs,
1632
- totalCycles: r?.metadata?.totalCycles,
1633
- allMustPassed: r?.metadata?.allMustPassed,
1634
- },
1635
- modelUsed: r?.metadata?.modelUsed ?? null,
1636
- }));
1637
- currentOutput = auditResult.outputText;
1638
- postStepsMeta.audit = auditResult.metadata;
1639
- const stepsWithNumbers = auditResult.intermediateSteps.map((s) => ({
1640
- ...s,
1641
- step: nextStepNumber++,
1642
- }));
1643
- result.intermediateSteps = [
1644
- ...(result.intermediateSteps ?? []),
1645
- ...stepsWithNumbers,
1646
- ];
1647
- }
1648
- else if (step.type === "polish") {
1649
- const polishResult = await traceWrap(traceCollector, {
1650
- taskType: "post-execution",
1651
- details: "polish post step",
1652
- metadata: {
1653
- ...baseTraceMeta(),
1608
+ meta: {
1609
+ ...baseMeta,
1610
+ postStepType: "audit",
1611
+ outer: activixOuterTier({
1612
+ kind: "postStep.audit.request",
1613
+ skillKey: request.skillKey,
1614
+ jobId: request.jobId,
1615
+ agentId: request.agentId,
1616
+ input: summarizeForOuter({
1617
+ currentOutput,
1618
+ hasContextMarkdown: !!capture.contextMarkdown,
1619
+ }, 8_000),
1620
+ }, null, { phase: "audit" }),
1621
+ },
1622
+ fn: async () => runAuditPostStep({
1623
+ request,
1624
+ mainResult: result,
1625
+ contextMarkdown: capture.contextMarkdown,
1626
+ config: (step.config ?? {}),
1627
+ reRunMain,
1628
+ traceCollector,
1629
+ }),
1630
+ onSuccessUpdates: (auditResult) => ({
1631
+ totalCycles: auditResult.metadata?.totalCycles,
1632
+ allMustPassed: auditResult.metadata?.allMustPassed,
1633
+ synthesisUsed: auditResult.metadata?.synthesisUsed,
1634
+ durationMs: auditResult.metadata?.durationMs,
1635
+ outer: activixOuterTier({
1636
+ kind: "postStep.audit.request",
1637
+ skillKey: request.skillKey,
1638
+ jobId: request.jobId,
1639
+ agentId: request.agentId,
1640
+ input: summarizeForOuter({
1641
+ currentOutput,
1642
+ hasContextMarkdown: !!capture.contextMarkdown,
1643
+ }, 8_000),
1644
+ }, {
1645
+ kind: "postStep.audit.result",
1646
+ outputText: summarizeForOuter(auditResult.outputText, 8_000),
1647
+ metadata: summarizeForOuter(auditResult.metadata, 6_000),
1648
+ }, { phase: "audit" }),
1649
+ }),
1650
+ }), (r) => ({
1651
+ metadata: {
1652
+ durationMs: r?.metadata?.durationMs,
1653
+ totalCycles: r?.metadata?.totalCycles,
1654
+ allMustPassed: r?.metadata?.allMustPassed,
1655
+ },
1656
+ modelUsed: r?.metadata?.modelUsed ?? null,
1657
+ }));
1658
+ currentOutput = auditResult.outputText;
1659
+ postStepsMeta.audit = auditResult.metadata;
1660
+ const stepsWithNumbers = auditResult.intermediateSteps.map((s) => ({
1661
+ ...s,
1662
+ step: nextStepNumber++,
1663
+ }));
1664
+ result.intermediateSteps = [
1665
+ ...(result.intermediateSteps ?? []),
1666
+ ...stepsWithNumbers,
1667
+ ];
1668
+ }
1669
+ else if (step.type === "polish") {
1670
+ const polishResult = await traceWrap(traceCollector, {
1671
+ taskType: "post-execution",
1672
+ details: "polish post step",
1673
+ metadata: {
1674
+ ...baseTraceMeta(),
1675
+ phase: "polish",
1676
+ postStepType: "polish",
1677
+ },
1678
+ }, async () => withPhaseRecord({
1679
+ ax,
1680
+ correlationId,
1654
1681
  phase: "polish",
1655
- postStepType: "polish",
1656
- },
1657
- }, async () => withPhaseRecord({
1658
- ax,
1659
- correlationId,
1660
- phase: "polish",
1661
- meta: {
1662
- ...baseMeta,
1663
- postStepType: "polish",
1664
- outer: activixOuterTier({
1665
- kind: "postStep.polish.request",
1666
- skillKey: request.skillKey,
1682
+ meta: {
1683
+ ...baseMeta,
1684
+ postStepType: "polish",
1685
+ outer: activixOuterTier({
1686
+ kind: "postStep.polish.request",
1687
+ skillKey: request.skillKey,
1688
+ jobId: request.jobId,
1689
+ agentId: request.agentId,
1690
+ input: summarizeForOuter({ currentOutput }, 8_000),
1691
+ }, null, { phase: "polish" }),
1692
+ },
1693
+ fn: async () => runPolishPostStep({
1694
+ currentOutput,
1695
+ config: (step.config ?? {}),
1696
+ originalInput: step.config?.includeOriginalContext ? request.input : undefined,
1697
+ promptContext: step.config?.includeOriginalContext ? capture.contextMarkdown : undefined,
1698
+ traceCollector,
1667
1699
  jobId: request.jobId,
1668
- agentId: request.agentId,
1669
- input: summarizeForOuter({ currentOutput }, 8_000),
1670
- }, null, { phase: "polish" }),
1671
- },
1672
- fn: async () => runPolishPostStep({
1673
- currentOutput,
1674
- config: (step.config ?? {}),
1675
- originalInput: step.config?.includeOriginalContext ? request.input : undefined,
1676
- promptContext: step.config?.includeOriginalContext ? capture.contextMarkdown : undefined,
1677
- traceCollector,
1678
- jobId: request.jobId,
1679
- taskId: request.taskId,
1680
- skillKey: request.skillKey,
1681
- agentId: request.agentId,
1682
- graphId: request.graphId,
1683
- nodeId: request.nodeId,
1684
- prevNodeId: request.prevNodeId,
1685
- coreSkillId: request.coreSkillId,
1686
- masterSkillId: request.masterSkillId,
1687
- identity: request.identity,
1688
- }),
1689
- onSuccessUpdates: (polishResult) => ({
1690
- totalPasses: polishResult.metadata?.totalPasses,
1691
- durationMs: polishResult.metadata?.durationMs,
1692
- outer: activixOuterTier({
1693
- kind: "postStep.polish.request",
1700
+ taskId: request.taskId,
1694
1701
  skillKey: request.skillKey,
1695
- jobId: request.jobId,
1696
1702
  agentId: request.agentId,
1697
- input: summarizeForOuter({ currentOutput }, 8_000),
1698
- }, {
1699
- kind: "postStep.polish.result",
1700
- outputText: summarizeForOuter(polishResult.outputText, 8_000),
1701
- metadata: summarizeForOuter(polishResult.metadata, 6_000),
1702
- }, { phase: "polish" }),
1703
- }),
1704
- }), (r) => ({
1705
- metadata: {
1706
- durationMs: r?.metadata?.durationMs,
1707
- totalPasses: r?.metadata?.totalPasses,
1708
- },
1709
- modelUsed: r?.metadata?.modelUsed ?? null,
1710
- }));
1711
- currentOutput = polishResult.outputText;
1712
- postStepsMeta.polish = polishResult.metadata;
1713
- const stepsWithNumbers = polishResult.intermediateSteps.map((s) => ({
1714
- ...s,
1715
- step: nextStepNumber++,
1716
- }));
1717
- result.intermediateSteps = [
1718
- ...(result.intermediateSteps ?? []),
1719
- ...stepsWithNumbers,
1720
- ];
1703
+ graphId: request.graphId,
1704
+ nodeId: request.nodeId,
1705
+ prevNodeId: request.prevNodeId,
1706
+ coreSkillId: request.coreSkillId,
1707
+ masterSkillId: request.masterSkillId,
1708
+ identity: request.identity,
1709
+ }),
1710
+ onSuccessUpdates: (polishResult) => ({
1711
+ totalPasses: polishResult.metadata?.totalPasses,
1712
+ durationMs: polishResult.metadata?.durationMs,
1713
+ outer: activixOuterTier({
1714
+ kind: "postStep.polish.request",
1715
+ skillKey: request.skillKey,
1716
+ jobId: request.jobId,
1717
+ agentId: request.agentId,
1718
+ input: summarizeForOuter({ currentOutput }, 8_000),
1719
+ }, {
1720
+ kind: "postStep.polish.result",
1721
+ outputText: summarizeForOuter(polishResult.outputText, 8_000),
1722
+ metadata: summarizeForOuter(polishResult.metadata, 6_000),
1723
+ }, { phase: "polish" }),
1724
+ }),
1725
+ }), (r) => ({
1726
+ metadata: {
1727
+ durationMs: r?.metadata?.durationMs,
1728
+ totalPasses: r?.metadata?.totalPasses,
1729
+ },
1730
+ modelUsed: r?.metadata?.modelUsed ?? null,
1731
+ }));
1732
+ currentOutput = polishResult.outputText;
1733
+ postStepsMeta.polish = polishResult.metadata;
1734
+ const stepsWithNumbers = polishResult.intermediateSteps.map((s) => ({
1735
+ ...s,
1736
+ step: nextStepNumber++,
1737
+ }));
1738
+ result.intermediateSteps = [
1739
+ ...(result.intermediateSteps ?? []),
1740
+ ...stepsWithNumbers,
1741
+ ];
1742
+ }
1721
1743
  }
1744
+ result.rawText = currentOutput;
1745
+ result.parsed = currentOutput;
1746
+ result.metadata = {
1747
+ ...(result.metadata ?? {}),
1748
+ postSteps: postStepsMeta,
1749
+ ...(traceCollector && aggregatedSynthLlmCalls.length > 0
1750
+ ? { synthesizedContextLlmCalls: aggregatedSynthLlmCalls }
1751
+ : {}),
1752
+ };
1753
+ attachExecutionStateAndObservability(result, request, observability, knobs);
1754
+ return withTrace(result);
1755
+ }
1756
+ // MAIN path (direct / gateway skill). Narrix handler runs earlier when `narrixMode === "handler"`.
1757
+ {
1758
+ const result = finalize(await runMainWithExecutionStrategies(request));
1759
+ attachExecutionStateAndObservability(result, request, {
1760
+ synthesisEnabled: false,
1761
+ synthesizedContextPresent: !!request.executionMemory?.synthesizedContext,
1762
+ mainContextSource: "unsynthesized",
1763
+ }, knobs);
1764
+ return withTrace(result);
1722
1765
  }
1723
- result.rawText = currentOutput;
1724
- result.parsed = currentOutput;
1725
- result.metadata = {
1726
- ...(result.metadata ?? {}),
1727
- postSteps: postStepsMeta,
1728
- ...(traceCollector && aggregatedSynthLlmCalls.length > 0
1729
- ? { synthesizedContextLlmCalls: aggregatedSynthLlmCalls }
1730
- : {}),
1731
- };
1732
- attachExecutionStateAndObservability(result, request, observability, knobs);
1733
- return withTrace(result);
1734
1766
  }
1735
- // MAIN path (direct / gateway skill). Narrix handler runs earlier when `narrixMode === "handler"`.
1736
- {
1737
- const result = finalize(await runMainWithExecutionStrategies(request));
1738
- attachExecutionStateAndObservability(result, request, {
1739
- synthesisEnabled: false,
1740
- synthesizedContextPresent: !!request.executionMemory?.synthesizedContext,
1741
- mainContextSource: "unsynthesized",
1742
- }, knobs);
1743
- return withTrace(result);
1767
+ catch (error) {
1768
+ throw logAndEnrichRunTaskFailure({
1769
+ cause: error,
1770
+ ...failContext(),
1771
+ });
1744
1772
  }
1745
1773
  });
1746
1774
  }