@x12i/ai-gateway 9.1.3 → 9.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -789,7 +789,9 @@ const response = await gateway.invoke({
789
789
 
790
790
  - **`GatewayConfig.templateRendering`** — default `TemplateRenderOptions` for every `invoke()` render path (merged after packaged **`src/defaults/template-rendering.json`**, which ships with **`subPathSearch.enabled: false`**). Your gateway config overrides that JSON.
791
791
  - **`templateRenderOptions` on the request** (`ChatRequest` / `AIInvokeRequest`) — merged on top of the gateway default for that call only (per-field override; `subPathSearch` fields merge with request winning).
792
- - Supported fields match the parser: **`templateId`**, **`subPathSearch`** (`enabled`, `roots`), **`silentMissingMustTokens`** (legacy Handlebars-style silence for missing MUST paths).
792
+ - **Smart Input (optional shorthand on the request)** top-level **`smartInput`** (`SmartInputConfig`) and **`smartInputRenderOptions`** (`SmartInputRenderOptions`) are merged into the same Rendrix options object **after** `GatewayConfig.templateRendering` and **before** `templateRenderOptions`. If you set the same field both as a shorthand and inside **`templateRenderOptions`**, the nested **`templateRenderOptions`** value wins. Templates use the **`{{smartInput}}`** insertion macro (see **`@x12i/rendrix`**). Types **`SmartInputConfig`** and **`SmartInputRenderOptions`** are re-exported from this package.
793
+ - For programmatic merges (tests or wrappers), use **`mergeGatewayAndRequestTemplateRenderOptions`** (same rules as `buildMessages`).
794
+ - Supported fields match the parser: **`templateId`**, **`subPathSearch`** (`enabled`, `roots`), **`silentMissingMustTokens`** (legacy Handlebars-style silence for missing MUST paths), **`smartInput`**, **`smartInputRenderOptions`**.
793
795
  - **Sub-path root priority:** `subPathSearch.roots` is an **ordered** list. The parser tries roots in **array order**; **the first root that resolves the leaf path wins** (see ISSUE-005). There is no separate “priority” field—the order of `roots` *is* the priority. Omit `roots` when `enabled` is true to use **`@x12i/rendrix`** packaged defaults.
794
796
 
795
797
  ```typescript
package/dist/index.d.ts CHANGED
@@ -16,9 +16,12 @@ export * from '@x12i/ai-providers-router';
16
16
  export { AIGateway } from './gateway.js';
17
17
  export { InstructionNotFoundError, InstructionBackendError } from './instruction-errors.js';
18
18
  export { autoRegisterProviders } from './gateway-provider-auto-register.js';
19
- export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
19
+ export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions, SmartInputConfig, SmartInputRenderOptions } from './types.js';
20
20
  export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
21
- export { mergeTemplateRenderOptions } from './template-render-merge.js';
21
+ export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
22
+ export type { GatewayTemplateRenderRequestSlice } from './template-render-merge.js';
23
+ export { GATEWAY_DUAL_MEMORY_ROOTS, buildMemoryResolutionRootFromWorkingMemory, coalesceMergedInputBucket, extractCallerInputsBag, mapSmartInputPathsInputsToInput, parseLooseJsonObject, prepareWorkingMemoryForTemplateRender, resolveGatewayMemoryPathValue } from './memory-path-resolution.js';
24
+ export type { GatewayDualMemoryRoot } from './memory-path-resolution.js';
22
25
  export type { UsageTier } from './types.js';
23
26
  export { Activix } from '@x12i/activix';
24
27
  export type { ActivixRunContext, FindByRunContextCriteria, GetJobActivitiesInput, GetJobActivitiesResult } from '@x12i/activix';
package/dist/index.js CHANGED
@@ -18,7 +18,8 @@ export { AIGateway } from './gateway.js';
18
18
  export { InstructionNotFoundError, InstructionBackendError } from './instruction-errors.js';
19
19
  export { autoRegisterProviders } from './gateway-provider-auto-register.js';
20
20
  export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
21
- export { mergeTemplateRenderOptions } from './template-render-merge.js';
21
+ export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
22
+ export { GATEWAY_DUAL_MEMORY_ROOTS, buildMemoryResolutionRootFromWorkingMemory, coalesceMergedInputBucket, extractCallerInputsBag, mapSmartInputPathsInputsToInput, parseLooseJsonObject, prepareWorkingMemoryForTemplateRender, resolveGatewayMemoryPathValue } from './memory-path-resolution.js';
22
23
  // Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
23
24
  // (x-models was previously used for RPM/TPM tracking but is no longer integrated)
24
25
  // Re-export activity tracking primitives (Activix)
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Dual memory roots `input` (merged MAIN payload) and `inputs` (caller / graph-entry bag).
3
+ * Aligned with @exellix/graph-engine ≥ 5.5.0 resolution rules for template / smart-input paths.
4
+ */
5
+ export declare const GATEWAY_DUAL_MEMORY_ROOTS: readonly ["input", "inputs"];
6
+ export type GatewayDualMemoryRoot = (typeof GATEWAY_DUAL_MEMORY_ROOTS)[number];
7
+ /**
8
+ * Parse JSON object shapes from strings (matches graph-engine `parseLooseJsonObject`).
9
+ */
10
+ export declare function parseLooseJsonObject(value: unknown): Record<string, unknown> | undefined;
11
+ /** Caller / graph-entry bag from `workingMemory.inputs`. */
12
+ export declare function extractCallerInputsBag(workingMemory: unknown): Record<string, unknown> | undefined;
13
+ /** Merged MAIN bucket from `workingMemory.input` (object or parsed JSON string). */
14
+ export declare function coalesceMergedInputBucket(workingMemory: unknown): unknown;
15
+ /**
16
+ * Resolve a dotted path against working memory with dual-root rules:
17
+ * - `inputs` / `inputs.*` → caller bag first, then merged `input`
18
+ * - `input` / `input.*` → merged `input` first, then caller `inputs`
19
+ * - other paths → direct lookup on working memory
20
+ */
21
+ export declare function resolveGatewayMemoryPathValue(workingMemory: unknown, path: string): unknown;
22
+ /**
23
+ * Working-memory view for Rendrix / smart-input: preserves all keys but overlays
24
+ * `input` and `inputs` with dual-root merge views (does not rewrite authored paths).
25
+ */
26
+ export declare function buildMemoryResolutionRootFromWorkingMemory(workingMemory: unknown): Record<string, unknown>;
27
+ /**
28
+ * When WM carries `input` and/or `inputs`, return a resolution root for template rendering.
29
+ * Otherwise returns the original reference unchanged.
30
+ */
31
+ export declare function prepareWorkingMemoryForTemplateRender(workingMemory: unknown): unknown;
32
+ /** Optional migration: rewrite `inputs.*` smart-input / memory paths to `input.*`. */
33
+ export declare function mapSmartInputPathsInputsToInput(paths: string[]): string[];
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Dual memory roots `input` (merged MAIN payload) and `inputs` (caller / graph-entry bag).
3
+ * Aligned with @exellix/graph-engine ≥ 5.5.0 resolution rules for template / smart-input paths.
4
+ */
5
+ export const GATEWAY_DUAL_MEMORY_ROOTS = ['input', 'inputs'];
6
+ function isPlainObject(value) {
7
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
8
+ }
9
+ /**
10
+ * Parse JSON object shapes from strings (matches graph-engine `parseLooseJsonObject`).
11
+ */
12
+ export function parseLooseJsonObject(value) {
13
+ if (isPlainObject(value))
14
+ return value;
15
+ if (typeof value !== 'string')
16
+ return undefined;
17
+ const trimmed = value.trim();
18
+ if (!trimmed.startsWith('{'))
19
+ return undefined;
20
+ try {
21
+ const parsed = JSON.parse(trimmed);
22
+ return isPlainObject(parsed) ? parsed : undefined;
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ /** Caller / graph-entry bag from `workingMemory.inputs`. */
29
+ export function extractCallerInputsBag(workingMemory) {
30
+ if (!isPlainObject(workingMemory))
31
+ return undefined;
32
+ const inputs = workingMemory.inputs;
33
+ return isPlainObject(inputs) ? inputs : undefined;
34
+ }
35
+ /** Merged MAIN bucket from `workingMemory.input` (object or parsed JSON string). */
36
+ export function coalesceMergedInputBucket(workingMemory) {
37
+ if (!isPlainObject(workingMemory))
38
+ return undefined;
39
+ const raw = workingMemory.input;
40
+ if (raw === undefined || raw === null)
41
+ return undefined;
42
+ const parsed = parseLooseJsonObject(raw);
43
+ return parsed !== undefined ? parsed : raw;
44
+ }
45
+ function getValueAtPath(obj, path) {
46
+ if (obj == null)
47
+ return undefined;
48
+ if (path === '' || path === 'this' || path === '.')
49
+ return obj;
50
+ const parts = path.split('.');
51
+ let cur = obj;
52
+ for (const part of parts) {
53
+ if (cur == null || typeof cur !== 'object')
54
+ return undefined;
55
+ cur = cur[part];
56
+ }
57
+ return cur;
58
+ }
59
+ function asObjectBucket(value) {
60
+ const parsed = parseLooseJsonObject(value);
61
+ if (parsed)
62
+ return parsed;
63
+ return isPlainObject(value) ? value : undefined;
64
+ }
65
+ /**
66
+ * Shallow-deep merge for template lookup: primary wins per key; nested plain objects merge recursively.
67
+ */
68
+ function mergeBucketViews(primary, fallback) {
69
+ const pObj = asObjectBucket(primary);
70
+ const fObj = asObjectBucket(fallback);
71
+ if (!pObj && !fObj) {
72
+ if (primary !== undefined && primary !== null)
73
+ return primary;
74
+ return fallback;
75
+ }
76
+ if (!pObj)
77
+ return { ...fObj };
78
+ if (!fObj)
79
+ return { ...pObj };
80
+ const keys = new Set([...Object.keys(pObj), ...Object.keys(fObj)]);
81
+ const view = {};
82
+ for (const key of keys) {
83
+ const pv = pObj[key];
84
+ const fv = fObj[key];
85
+ if (isPlainObject(pv) && isPlainObject(fv)) {
86
+ view[key] = mergeBucketViews(pv, fv);
87
+ }
88
+ else {
89
+ view[key] = pv !== undefined ? pv : fv;
90
+ }
91
+ }
92
+ return view;
93
+ }
94
+ /**
95
+ * Resolve a dotted path against working memory with dual-root rules:
96
+ * - `inputs` / `inputs.*` → caller bag first, then merged `input`
97
+ * - `input` / `input.*` → merged `input` first, then caller `inputs`
98
+ * - other paths → direct lookup on working memory
99
+ */
100
+ export function resolveGatewayMemoryPathValue(workingMemory, path) {
101
+ const trimmed = path.trim();
102
+ if (!trimmed)
103
+ return undefined;
104
+ const dot = trimmed.indexOf('.');
105
+ const root = dot >= 0 ? trimmed.slice(0, dot) : trimmed;
106
+ const tail = dot >= 0 ? trimmed.slice(dot + 1) : '';
107
+ if (root === 'inputs') {
108
+ const primary = extractCallerInputsBag(workingMemory);
109
+ const fallback = coalesceMergedInputBucket(workingMemory);
110
+ if (!tail) {
111
+ if (primary && Object.keys(primary).length > 0)
112
+ return primary;
113
+ return fallback;
114
+ }
115
+ const fromPrimary = primary ? getValueAtPath(primary, tail) : undefined;
116
+ if (fromPrimary !== undefined)
117
+ return fromPrimary;
118
+ return fallback !== undefined ? getValueAtPath(fallback, tail) : undefined;
119
+ }
120
+ if (root === 'input') {
121
+ const primary = coalesceMergedInputBucket(workingMemory);
122
+ const fallback = extractCallerInputsBag(workingMemory);
123
+ if (!tail) {
124
+ if (primary !== undefined && primary !== null)
125
+ return primary;
126
+ return fallback;
127
+ }
128
+ const fromPrimary = primary !== undefined ? getValueAtPath(primary, tail) : undefined;
129
+ if (fromPrimary !== undefined)
130
+ return fromPrimary;
131
+ return fallback ? getValueAtPath(fallback, tail) : undefined;
132
+ }
133
+ return getValueAtPath(workingMemory, trimmed);
134
+ }
135
+ /**
136
+ * Working-memory view for Rendrix / smart-input: preserves all keys but overlays
137
+ * `input` and `inputs` with dual-root merge views (does not rewrite authored paths).
138
+ */
139
+ export function buildMemoryResolutionRootFromWorkingMemory(workingMemory) {
140
+ if (!isPlainObject(workingMemory))
141
+ return {};
142
+ const inputsBag = extractCallerInputsBag(workingMemory);
143
+ const mergedInput = coalesceMergedInputBucket(workingMemory);
144
+ return {
145
+ ...workingMemory,
146
+ input: mergeBucketViews(mergedInput, inputsBag),
147
+ inputs: mergeBucketViews(inputsBag, mergedInput)
148
+ };
149
+ }
150
+ /**
151
+ * When WM carries `input` and/or `inputs`, return a resolution root for template rendering.
152
+ * Otherwise returns the original reference unchanged.
153
+ */
154
+ export function prepareWorkingMemoryForTemplateRender(workingMemory) {
155
+ if (!isPlainObject(workingMemory))
156
+ return workingMemory;
157
+ if (workingMemory.input === undefined && workingMemory.inputs === undefined) {
158
+ return workingMemory;
159
+ }
160
+ return buildMemoryResolutionRootFromWorkingMemory(workingMemory);
161
+ }
162
+ /** Optional migration: rewrite `inputs.*` smart-input / memory paths to `input.*`. */
163
+ export function mapSmartInputPathsInputsToInput(paths) {
164
+ return paths.map((p) => {
165
+ const t = p.trim();
166
+ if (t === 'inputs')
167
+ return 'input';
168
+ if (t.startsWith('inputs.'))
169
+ return `input.${t.slice('inputs.'.length)}`;
170
+ return p;
171
+ });
172
+ }
@@ -4,7 +4,7 @@
4
4
  * Handles flex-md format exclusively
5
5
  */
6
6
  import { parseTemplate } from './template-parser.js';
7
- import { mergeTemplateRenderOptions } from './template-render-merge.js';
7
+ import { mergeGatewayAndRequestTemplateRenderOptions } from './template-render-merge.js';
8
8
  import { resolveNestedInstructionsBlock } from './gateway-instructions.js';
9
9
  // Type guard
10
10
  // AIRequest is distinguished by having primaryObjectType or objectTypes
@@ -379,7 +379,7 @@ export async function buildMessages(request, config, options = {}) {
379
379
  const shortTermMemory = options.shortTermMemory;
380
380
  const experienceMemory = options.experienceMemory;
381
381
  const knowledgeMemory = options.knowledgeMemory;
382
- const templateRenderOptions = mergeTemplateRenderOptions(config.templateRendering, request.templateRenderOptions);
382
+ const templateRenderOptions = mergeGatewayAndRequestTemplateRenderOptions(config.templateRendering, request);
383
383
  if (request.instructions) {
384
384
  if (typeof request.instructions === 'string') {
385
385
  logger.info('Using instructions as template text', {
@@ -4,6 +4,7 @@
4
4
  * Uses @x12i/rendrix (v4+) to parse templates with workingMemory.
5
5
  * TemplateResolutionError from the parser is rethrown; other errors fall back to the raw template.
6
6
  */
7
+ import { prepareWorkingMemoryForTemplateRender } from './memory-path-resolution.js';
7
8
  let rendrixModule = null;
8
9
  let parserLoadPromise = null;
9
10
  async function loadRendrix() {
@@ -48,6 +49,7 @@ export async function parseTemplate(template, workingMemory, taskConfig, shortTe
48
49
  if (!workingMemory) {
49
50
  return template;
50
51
  }
52
+ const wmForRender = prepareWorkingMemoryForTemplateRender(workingMemory);
51
53
  await loadRendrix();
52
54
  if (!rendrixModule) {
53
55
  return template;
@@ -57,18 +59,18 @@ export async function parseTemplate(template, workingMemory, taskConfig, shortTe
57
59
  ? rendrixModule
58
60
  : rendrixModule.default || rendrixModule;
59
61
  if (typeof api.render === 'function') {
60
- return await api.render(template, workingMemory, shortTermMemory, experienceMemory, knowledgeMemory, undefined, // functionsMap
62
+ return await api.render(template, wmForRender, shortTermMemory, experienceMemory, knowledgeMemory, undefined, // functionsMap
61
63
  undefined, // choiceOptions
62
64
  undefined, // filesContent
63
65
  templateRenderOptions);
64
66
  }
65
67
  if (typeof api.parse === 'function') {
66
- return await api.parse(template, workingMemory);
68
+ return await api.parse(template, wmForRender);
67
69
  }
68
70
  else if (typeof api === 'function') {
69
71
  const parser = new api();
70
72
  if (typeof parser.parse === 'function') {
71
- return await parser.parse(template, workingMemory);
73
+ return await parser.parse(template, wmForRender);
72
74
  }
73
75
  }
74
76
  return template;
@@ -1,9 +1,20 @@
1
1
  /**
2
2
  * Merge @x12i/rendrix TemplateRenderOptions from gateway defaults and per-request overrides.
3
3
  */
4
- import type { TemplateRenderOptions } from '@x12i/rendrix';
4
+ import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
5
+ /** Request fields that participate in gateway + Rendrix template option merging. */
6
+ export type GatewayTemplateRenderRequestSlice = {
7
+ smartInput?: SmartInputConfig;
8
+ smartInputRenderOptions?: SmartInputRenderOptions;
9
+ templateRenderOptions?: TemplateRenderOptions;
10
+ };
5
11
  /**
6
12
  * Deep-merge template render options. Request/gateway overrides win per field.
7
13
  * For `subPathSearch`, `roots` on the override replace the base list when present.
8
14
  */
9
15
  export declare function mergeTemplateRenderOptions(base?: TemplateRenderOptions, override?: TemplateRenderOptions): TemplateRenderOptions | undefined;
16
+ /**
17
+ * Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
18
+ * Same merge order as {@link buildMessages}.
19
+ */
20
+ export declare function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering: TemplateRenderOptions | undefined, request: GatewayTemplateRenderRequestSlice): TemplateRenderOptions | undefined;
@@ -6,6 +6,10 @@ function hasMeaningfulOptions(o) {
6
6
  return true;
7
7
  if (o.silentMissingMustTokens !== undefined)
8
8
  return true;
9
+ if (o.smartInput !== undefined)
10
+ return true;
11
+ if (o.smartInputRenderOptions !== undefined)
12
+ return true;
9
13
  if (o.subPathSearch !== undefined) {
10
14
  const s = o.subPathSearch;
11
15
  return (s.enabled !== undefined ||
@@ -38,3 +42,18 @@ export function mergeTemplateRenderOptions(base, override) {
38
42
  }
39
43
  return hasMeaningfulOptions(merged) ? merged : undefined;
40
44
  }
45
+ /**
46
+ * Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
47
+ * Same merge order as {@link buildMessages}.
48
+ */
49
+ export function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering, request) {
50
+ const requestSmartTemplateOpts = request.smartInput !== undefined || request.smartInputRenderOptions !== undefined
51
+ ? {
52
+ ...(request.smartInput !== undefined ? { smartInput: request.smartInput } : {}),
53
+ ...(request.smartInputRenderOptions !== undefined
54
+ ? { smartInputRenderOptions: request.smartInputRenderOptions }
55
+ : {})
56
+ }
57
+ : undefined;
58
+ return mergeTemplateRenderOptions(mergeTemplateRenderOptions(gatewayTemplateRendering, requestSmartTemplateOpts), request.templateRenderOptions);
59
+ }
package/dist/types.d.ts CHANGED
@@ -8,7 +8,7 @@ type AIProvider = string;
8
8
  type AIModel = string;
9
9
  export type UsageTier = string;
10
10
  import type { Activix } from '@x12i/activix';
11
- import type { TemplateRenderOptions } from '@x12i/rendrix';
11
+ import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
12
12
  import type { Logxer } from '@x12i/logxer';
13
13
  /**
14
14
  * Diagnostics options for opt-in authoritative tracing.
@@ -168,8 +168,8 @@ export type ActivityIdentity = {
168
168
  */
169
169
  actionRef?: string;
170
170
  };
171
- /** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, etc.). */
172
- export type { TemplateRenderOptions } from '@x12i/rendrix';
171
+ /** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, smartInput, etc.). */
172
+ export type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
173
173
  type LLMRequest = Parameters<LLMProviderRouter['invoke']>[0];
174
174
  type LLMResponse = Awaited<ReturnType<LLMProviderRouter['invoke']>>;
175
175
  /**
@@ -626,6 +626,10 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
626
626
  * Working memory (optional) - Affects all template parsing
627
627
  * Passed to Rendrix (v4+) for template variable substitution.
628
628
  * Plain {{path}} tokens are MUST paths: undefined after merge throws TemplateResolutionError (rethrown by the gateway).
629
+ *
630
+ * Dual roots (graph-engine / ai-tasks contract): `inputs` is the caller / graph-entry bag;
631
+ * `input` is the merged MAIN payload (object or JSON string). Smart-input and `input.*` / `inputs.*`
632
+ * paths resolve with cross-root fallback before render (see `resolveGatewayMemoryPathValue`).
629
633
  */
630
634
  workingMemory?: unknown;
631
635
  /**
@@ -635,6 +639,17 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
635
639
  * the full list or only set `enabled` and inherit `roots` from the gateway default merge.
636
640
  */
637
641
  templateRenderOptions?: TemplateRenderOptions;
642
+ /**
643
+ * Smart Input paths for Rendrix `{{smartInput}}` (optional shorthand).
644
+ * Merged into render options after gateway `templateRendering` and before `templateRenderOptions`
645
+ * (nested `templateRenderOptions.smartInput` wins when both are set).
646
+ */
647
+ smartInput?: SmartInputConfig;
648
+ /**
649
+ * Rendering controls for Smart Input markdown (optional shorthand).
650
+ * Merged the same way as `smartInput`; `templateRenderOptions.smartInputRenderOptions` wins when both are set.
651
+ */
652
+ smartInputRenderOptions?: SmartInputRenderOptions;
638
653
  /**
639
654
  * Messages array - Optional, can be used instead of instructions/prompt
640
655
  * If provided, will be appended as-is after built messages; instructions template text is still parsed for the system message when present
@@ -21,7 +21,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.resetObjectTypesLibrary = exports.getObjectTypesLibrary = exports.initializeObjectTypesLibrary = exports.getObjectTypesForAgent = exports.getObjectType = exports.OBJECT_TYPES_LIBRARY = exports.assertValidAIRequest = exports.formatDiagnostic = exports.runValidationTests = exports.createValidationTestCases = exports.createTestAIRequest = exports.supportsJSONMode = exports.diagnoseResponse = exports.diagnoseRequest = exports.validateResponse = exports.extractJSON = exports.validateJSON = exports.validateAIRequest = exports.DEFAULT_RATE_LIMIT_ENABLED = exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = exports.GatewayRateLimiter = exports.runtimeObjects = exports.DebugLogAbstract = exports.createLogxer = exports.gatewayLogDebug = exports.withActivityIdentity = exports.activityIdentityToLogMeta = exports.ensureGatewayRequestIdentity = exports.ActivityManager = exports.Activix = exports.mergeTemplateRenderOptions = exports.pickRequestIdsFromRouterLike = exports.tryExtractRouterLikePayloadFromErrorChain = exports.buildInvokeRejectionMetadata = exports.attachGatewayInvokeRejectionMetadata = exports.autoRegisterProviders = exports.InstructionBackendError = exports.InstructionNotFoundError = exports.AIGateway = exports.FallbackExhaustedError = exports.ProviderNotFoundError = exports.createRouterFromConfig = exports.createRouter = exports.LLMProviderRouter = void 0;
24
+ exports.getObjectTypesForAgent = exports.getObjectType = exports.OBJECT_TYPES_LIBRARY = exports.assertValidAIRequest = exports.formatDiagnostic = exports.runValidationTests = exports.createValidationTestCases = exports.createTestAIRequest = exports.supportsJSONMode = exports.diagnoseResponse = exports.diagnoseRequest = exports.validateResponse = exports.extractJSON = exports.validateJSON = exports.validateAIRequest = exports.DEFAULT_RATE_LIMIT_ENABLED = exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = exports.GatewayRateLimiter = exports.runtimeObjects = exports.DebugLogAbstract = exports.createLogxer = exports.gatewayLogDebug = exports.withActivityIdentity = exports.activityIdentityToLogMeta = exports.ensureGatewayRequestIdentity = exports.ActivityManager = exports.Activix = exports.resolveGatewayMemoryPathValue = exports.prepareWorkingMemoryForTemplateRender = exports.parseLooseJsonObject = exports.mapSmartInputPathsInputsToInput = exports.extractCallerInputsBag = exports.coalesceMergedInputBucket = exports.buildMemoryResolutionRootFromWorkingMemory = exports.GATEWAY_DUAL_MEMORY_ROOTS = exports.mergeTemplateRenderOptions = exports.mergeGatewayAndRequestTemplateRenderOptions = exports.pickRequestIdsFromRouterLike = exports.tryExtractRouterLikePayloadFromErrorChain = exports.buildInvokeRejectionMetadata = exports.attachGatewayInvokeRejectionMetadata = exports.autoRegisterProviders = exports.InstructionBackendError = exports.InstructionNotFoundError = exports.AIGateway = exports.FallbackExhaustedError = exports.ProviderNotFoundError = exports.createRouterFromConfig = exports.createRouter = exports.LLMProviderRouter = void 0;
25
+ exports.resetObjectTypesLibrary = exports.getObjectTypesLibrary = exports.initializeObjectTypesLibrary = void 0;
25
26
  // Re-export router class and types (base functionality)
26
27
  var ai_providers_router_1 = require("@x12i/ai-providers-router");
27
28
  Object.defineProperty(exports, "LLMProviderRouter", { enumerable: true, get: function () { return ai_providers_router_1.LLMProviderRouter; } });
@@ -49,7 +50,17 @@ Object.defineProperty(exports, "buildInvokeRejectionMetadata", { enumerable: tru
49
50
  Object.defineProperty(exports, "tryExtractRouterLikePayloadFromErrorChain", { enumerable: true, get: function () { return gateway_utils_js_1.tryExtractRouterLikePayloadFromErrorChain; } });
50
51
  Object.defineProperty(exports, "pickRequestIdsFromRouterLike", { enumerable: true, get: function () { return gateway_utils_js_1.pickRequestIdsFromRouterLike; } });
51
52
  var template_render_merge_js_1 = require("./template-render-merge.cjs");
53
+ Object.defineProperty(exports, "mergeGatewayAndRequestTemplateRenderOptions", { enumerable: true, get: function () { return template_render_merge_js_1.mergeGatewayAndRequestTemplateRenderOptions; } });
52
54
  Object.defineProperty(exports, "mergeTemplateRenderOptions", { enumerable: true, get: function () { return template_render_merge_js_1.mergeTemplateRenderOptions; } });
55
+ var memory_path_resolution_js_1 = require("./memory-path-resolution.cjs");
56
+ Object.defineProperty(exports, "GATEWAY_DUAL_MEMORY_ROOTS", { enumerable: true, get: function () { return memory_path_resolution_js_1.GATEWAY_DUAL_MEMORY_ROOTS; } });
57
+ Object.defineProperty(exports, "buildMemoryResolutionRootFromWorkingMemory", { enumerable: true, get: function () { return memory_path_resolution_js_1.buildMemoryResolutionRootFromWorkingMemory; } });
58
+ Object.defineProperty(exports, "coalesceMergedInputBucket", { enumerable: true, get: function () { return memory_path_resolution_js_1.coalesceMergedInputBucket; } });
59
+ Object.defineProperty(exports, "extractCallerInputsBag", { enumerable: true, get: function () { return memory_path_resolution_js_1.extractCallerInputsBag; } });
60
+ Object.defineProperty(exports, "mapSmartInputPathsInputsToInput", { enumerable: true, get: function () { return memory_path_resolution_js_1.mapSmartInputPathsInputsToInput; } });
61
+ Object.defineProperty(exports, "parseLooseJsonObject", { enumerable: true, get: function () { return memory_path_resolution_js_1.parseLooseJsonObject; } });
62
+ Object.defineProperty(exports, "prepareWorkingMemoryForTemplateRender", { enumerable: true, get: function () { return memory_path_resolution_js_1.prepareWorkingMemoryForTemplateRender; } });
63
+ Object.defineProperty(exports, "resolveGatewayMemoryPathValue", { enumerable: true, get: function () { return memory_path_resolution_js_1.resolveGatewayMemoryPathValue; } });
53
64
  // Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
54
65
  // (x-models was previously used for RPM/TPM tracking but is no longer integrated)
55
66
  // Re-export activity tracking primitives (Activix)
@@ -16,9 +16,12 @@ export * from '@x12i/ai-providers-router';
16
16
  export { AIGateway } from './gateway.js';
17
17
  export { InstructionNotFoundError, InstructionBackendError } from './instruction-errors.js';
18
18
  export { autoRegisterProviders } from './gateway-provider-auto-register.js';
19
- export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
19
+ export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions, SmartInputConfig, SmartInputRenderOptions } from './types.js';
20
20
  export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
21
- export { mergeTemplateRenderOptions } from './template-render-merge.js';
21
+ export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
22
+ export type { GatewayTemplateRenderRequestSlice } from './template-render-merge.js';
23
+ export { GATEWAY_DUAL_MEMORY_ROOTS, buildMemoryResolutionRootFromWorkingMemory, coalesceMergedInputBucket, extractCallerInputsBag, mapSmartInputPathsInputsToInput, parseLooseJsonObject, prepareWorkingMemoryForTemplateRender, resolveGatewayMemoryPathValue } from './memory-path-resolution.js';
24
+ export type { GatewayDualMemoryRoot } from './memory-path-resolution.js';
22
25
  export type { UsageTier } from './types.js';
23
26
  export { Activix } from '@x12i/activix';
24
27
  export type { ActivixRunContext, FindByRunContextCriteria, GetJobActivitiesInput, GetJobActivitiesResult } from '@x12i/activix';
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ /**
3
+ * Dual memory roots `input` (merged MAIN payload) and `inputs` (caller / graph-entry bag).
4
+ * Aligned with @exellix/graph-engine ≥ 5.5.0 resolution rules for template / smart-input paths.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.GATEWAY_DUAL_MEMORY_ROOTS = void 0;
8
+ exports.parseLooseJsonObject = parseLooseJsonObject;
9
+ exports.extractCallerInputsBag = extractCallerInputsBag;
10
+ exports.coalesceMergedInputBucket = coalesceMergedInputBucket;
11
+ exports.resolveGatewayMemoryPathValue = resolveGatewayMemoryPathValue;
12
+ exports.buildMemoryResolutionRootFromWorkingMemory = buildMemoryResolutionRootFromWorkingMemory;
13
+ exports.prepareWorkingMemoryForTemplateRender = prepareWorkingMemoryForTemplateRender;
14
+ exports.mapSmartInputPathsInputsToInput = mapSmartInputPathsInputsToInput;
15
+ exports.GATEWAY_DUAL_MEMORY_ROOTS = ['input', 'inputs'];
16
+ function isPlainObject(value) {
17
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
18
+ }
19
+ /**
20
+ * Parse JSON object shapes from strings (matches graph-engine `parseLooseJsonObject`).
21
+ */
22
+ function parseLooseJsonObject(value) {
23
+ if (isPlainObject(value))
24
+ return value;
25
+ if (typeof value !== 'string')
26
+ return undefined;
27
+ const trimmed = value.trim();
28
+ if (!trimmed.startsWith('{'))
29
+ return undefined;
30
+ try {
31
+ const parsed = JSON.parse(trimmed);
32
+ return isPlainObject(parsed) ? parsed : undefined;
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ }
38
+ /** Caller / graph-entry bag from `workingMemory.inputs`. */
39
+ function extractCallerInputsBag(workingMemory) {
40
+ if (!isPlainObject(workingMemory))
41
+ return undefined;
42
+ const inputs = workingMemory.inputs;
43
+ return isPlainObject(inputs) ? inputs : undefined;
44
+ }
45
+ /** Merged MAIN bucket from `workingMemory.input` (object or parsed JSON string). */
46
+ function coalesceMergedInputBucket(workingMemory) {
47
+ if (!isPlainObject(workingMemory))
48
+ return undefined;
49
+ const raw = workingMemory.input;
50
+ if (raw === undefined || raw === null)
51
+ return undefined;
52
+ const parsed = parseLooseJsonObject(raw);
53
+ return parsed !== undefined ? parsed : raw;
54
+ }
55
+ function getValueAtPath(obj, path) {
56
+ if (obj == null)
57
+ return undefined;
58
+ if (path === '' || path === 'this' || path === '.')
59
+ return obj;
60
+ const parts = path.split('.');
61
+ let cur = obj;
62
+ for (const part of parts) {
63
+ if (cur == null || typeof cur !== 'object')
64
+ return undefined;
65
+ cur = cur[part];
66
+ }
67
+ return cur;
68
+ }
69
+ function asObjectBucket(value) {
70
+ const parsed = parseLooseJsonObject(value);
71
+ if (parsed)
72
+ return parsed;
73
+ return isPlainObject(value) ? value : undefined;
74
+ }
75
+ /**
76
+ * Shallow-deep merge for template lookup: primary wins per key; nested plain objects merge recursively.
77
+ */
78
+ function mergeBucketViews(primary, fallback) {
79
+ const pObj = asObjectBucket(primary);
80
+ const fObj = asObjectBucket(fallback);
81
+ if (!pObj && !fObj) {
82
+ if (primary !== undefined && primary !== null)
83
+ return primary;
84
+ return fallback;
85
+ }
86
+ if (!pObj)
87
+ return { ...fObj };
88
+ if (!fObj)
89
+ return { ...pObj };
90
+ const keys = new Set([...Object.keys(pObj), ...Object.keys(fObj)]);
91
+ const view = {};
92
+ for (const key of keys) {
93
+ const pv = pObj[key];
94
+ const fv = fObj[key];
95
+ if (isPlainObject(pv) && isPlainObject(fv)) {
96
+ view[key] = mergeBucketViews(pv, fv);
97
+ }
98
+ else {
99
+ view[key] = pv !== undefined ? pv : fv;
100
+ }
101
+ }
102
+ return view;
103
+ }
104
+ /**
105
+ * Resolve a dotted path against working memory with dual-root rules:
106
+ * - `inputs` / `inputs.*` → caller bag first, then merged `input`
107
+ * - `input` / `input.*` → merged `input` first, then caller `inputs`
108
+ * - other paths → direct lookup on working memory
109
+ */
110
+ function resolveGatewayMemoryPathValue(workingMemory, path) {
111
+ const trimmed = path.trim();
112
+ if (!trimmed)
113
+ return undefined;
114
+ const dot = trimmed.indexOf('.');
115
+ const root = dot >= 0 ? trimmed.slice(0, dot) : trimmed;
116
+ const tail = dot >= 0 ? trimmed.slice(dot + 1) : '';
117
+ if (root === 'inputs') {
118
+ const primary = extractCallerInputsBag(workingMemory);
119
+ const fallback = coalesceMergedInputBucket(workingMemory);
120
+ if (!tail) {
121
+ if (primary && Object.keys(primary).length > 0)
122
+ return primary;
123
+ return fallback;
124
+ }
125
+ const fromPrimary = primary ? getValueAtPath(primary, tail) : undefined;
126
+ if (fromPrimary !== undefined)
127
+ return fromPrimary;
128
+ return fallback !== undefined ? getValueAtPath(fallback, tail) : undefined;
129
+ }
130
+ if (root === 'input') {
131
+ const primary = coalesceMergedInputBucket(workingMemory);
132
+ const fallback = extractCallerInputsBag(workingMemory);
133
+ if (!tail) {
134
+ if (primary !== undefined && primary !== null)
135
+ return primary;
136
+ return fallback;
137
+ }
138
+ const fromPrimary = primary !== undefined ? getValueAtPath(primary, tail) : undefined;
139
+ if (fromPrimary !== undefined)
140
+ return fromPrimary;
141
+ return fallback ? getValueAtPath(fallback, tail) : undefined;
142
+ }
143
+ return getValueAtPath(workingMemory, trimmed);
144
+ }
145
+ /**
146
+ * Working-memory view for Rendrix / smart-input: preserves all keys but overlays
147
+ * `input` and `inputs` with dual-root merge views (does not rewrite authored paths).
148
+ */
149
+ function buildMemoryResolutionRootFromWorkingMemory(workingMemory) {
150
+ if (!isPlainObject(workingMemory))
151
+ return {};
152
+ const inputsBag = extractCallerInputsBag(workingMemory);
153
+ const mergedInput = coalesceMergedInputBucket(workingMemory);
154
+ return {
155
+ ...workingMemory,
156
+ input: mergeBucketViews(mergedInput, inputsBag),
157
+ inputs: mergeBucketViews(inputsBag, mergedInput)
158
+ };
159
+ }
160
+ /**
161
+ * When WM carries `input` and/or `inputs`, return a resolution root for template rendering.
162
+ * Otherwise returns the original reference unchanged.
163
+ */
164
+ function prepareWorkingMemoryForTemplateRender(workingMemory) {
165
+ if (!isPlainObject(workingMemory))
166
+ return workingMemory;
167
+ if (workingMemory.input === undefined && workingMemory.inputs === undefined) {
168
+ return workingMemory;
169
+ }
170
+ return buildMemoryResolutionRootFromWorkingMemory(workingMemory);
171
+ }
172
+ /** Optional migration: rewrite `inputs.*` smart-input / memory paths to `input.*`. */
173
+ function mapSmartInputPathsInputsToInput(paths) {
174
+ return paths.map((p) => {
175
+ const t = p.trim();
176
+ if (t === 'inputs')
177
+ return 'input';
178
+ if (t.startsWith('inputs.'))
179
+ return `input.${t.slice('inputs.'.length)}`;
180
+ return p;
181
+ });
182
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Dual memory roots `input` (merged MAIN payload) and `inputs` (caller / graph-entry bag).
3
+ * Aligned with @exellix/graph-engine ≥ 5.5.0 resolution rules for template / smart-input paths.
4
+ */
5
+ export declare const GATEWAY_DUAL_MEMORY_ROOTS: readonly ["input", "inputs"];
6
+ export type GatewayDualMemoryRoot = (typeof GATEWAY_DUAL_MEMORY_ROOTS)[number];
7
+ /**
8
+ * Parse JSON object shapes from strings (matches graph-engine `parseLooseJsonObject`).
9
+ */
10
+ export declare function parseLooseJsonObject(value: unknown): Record<string, unknown> | undefined;
11
+ /** Caller / graph-entry bag from `workingMemory.inputs`. */
12
+ export declare function extractCallerInputsBag(workingMemory: unknown): Record<string, unknown> | undefined;
13
+ /** Merged MAIN bucket from `workingMemory.input` (object or parsed JSON string). */
14
+ export declare function coalesceMergedInputBucket(workingMemory: unknown): unknown;
15
+ /**
16
+ * Resolve a dotted path against working memory with dual-root rules:
17
+ * - `inputs` / `inputs.*` → caller bag first, then merged `input`
18
+ * - `input` / `input.*` → merged `input` first, then caller `inputs`
19
+ * - other paths → direct lookup on working memory
20
+ */
21
+ export declare function resolveGatewayMemoryPathValue(workingMemory: unknown, path: string): unknown;
22
+ /**
23
+ * Working-memory view for Rendrix / smart-input: preserves all keys but overlays
24
+ * `input` and `inputs` with dual-root merge views (does not rewrite authored paths).
25
+ */
26
+ export declare function buildMemoryResolutionRootFromWorkingMemory(workingMemory: unknown): Record<string, unknown>;
27
+ /**
28
+ * When WM carries `input` and/or `inputs`, return a resolution root for template rendering.
29
+ * Otherwise returns the original reference unchanged.
30
+ */
31
+ export declare function prepareWorkingMemoryForTemplateRender(workingMemory: unknown): unknown;
32
+ /** Optional migration: rewrite `inputs.*` smart-input / memory paths to `input.*`. */
33
+ export declare function mapSmartInputPathsInputsToInput(paths: string[]): string[];
@@ -415,7 +415,7 @@ async function buildMessages(request, config, options = {}) {
415
415
  const shortTermMemory = options.shortTermMemory;
416
416
  const experienceMemory = options.experienceMemory;
417
417
  const knowledgeMemory = options.knowledgeMemory;
418
- const templateRenderOptions = (0, template_render_merge_js_1.mergeTemplateRenderOptions)(config.templateRendering, request.templateRenderOptions);
418
+ const templateRenderOptions = (0, template_render_merge_js_1.mergeGatewayAndRequestTemplateRenderOptions)(config.templateRendering, request);
419
419
  if (request.instructions) {
420
420
  if (typeof request.instructions === 'string') {
421
421
  logger.info('Using instructions as template text', {
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.parseTemplate = parseTemplate;
43
43
  exports.isParserAvailable = isParserAvailable;
44
+ const memory_path_resolution_js_1 = require("./memory-path-resolution.cjs");
44
45
  let rendrixModule = null;
45
46
  let parserLoadPromise = null;
46
47
  async function loadRendrix() {
@@ -85,6 +86,7 @@ async function parseTemplate(template, workingMemory, taskConfig, shortTermMemor
85
86
  if (!workingMemory) {
86
87
  return template;
87
88
  }
89
+ const wmForRender = (0, memory_path_resolution_js_1.prepareWorkingMemoryForTemplateRender)(workingMemory);
88
90
  await loadRendrix();
89
91
  if (!rendrixModule) {
90
92
  return template;
@@ -94,18 +96,18 @@ async function parseTemplate(template, workingMemory, taskConfig, shortTermMemor
94
96
  ? rendrixModule
95
97
  : rendrixModule.default || rendrixModule;
96
98
  if (typeof api.render === 'function') {
97
- return await api.render(template, workingMemory, shortTermMemory, experienceMemory, knowledgeMemory, undefined, // functionsMap
99
+ return await api.render(template, wmForRender, shortTermMemory, experienceMemory, knowledgeMemory, undefined, // functionsMap
98
100
  undefined, // choiceOptions
99
101
  undefined, // filesContent
100
102
  templateRenderOptions);
101
103
  }
102
104
  if (typeof api.parse === 'function') {
103
- return await api.parse(template, workingMemory);
105
+ return await api.parse(template, wmForRender);
104
106
  }
105
107
  else if (typeof api === 'function') {
106
108
  const parser = new api();
107
109
  if (typeof parser.parse === 'function') {
108
- return await parser.parse(template, workingMemory);
110
+ return await parser.parse(template, wmForRender);
109
111
  }
110
112
  }
111
113
  return template;
@@ -4,11 +4,16 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.mergeTemplateRenderOptions = mergeTemplateRenderOptions;
7
+ exports.mergeGatewayAndRequestTemplateRenderOptions = mergeGatewayAndRequestTemplateRenderOptions;
7
8
  function hasMeaningfulOptions(o) {
8
9
  if (o.templateId !== undefined)
9
10
  return true;
10
11
  if (o.silentMissingMustTokens !== undefined)
11
12
  return true;
13
+ if (o.smartInput !== undefined)
14
+ return true;
15
+ if (o.smartInputRenderOptions !== undefined)
16
+ return true;
12
17
  if (o.subPathSearch !== undefined) {
13
18
  const s = o.subPathSearch;
14
19
  return (s.enabled !== undefined ||
@@ -41,3 +46,18 @@ function mergeTemplateRenderOptions(base, override) {
41
46
  }
42
47
  return hasMeaningfulOptions(merged) ? merged : undefined;
43
48
  }
49
+ /**
50
+ * Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
51
+ * Same merge order as {@link buildMessages}.
52
+ */
53
+ function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering, request) {
54
+ const requestSmartTemplateOpts = request.smartInput !== undefined || request.smartInputRenderOptions !== undefined
55
+ ? {
56
+ ...(request.smartInput !== undefined ? { smartInput: request.smartInput } : {}),
57
+ ...(request.smartInputRenderOptions !== undefined
58
+ ? { smartInputRenderOptions: request.smartInputRenderOptions }
59
+ : {})
60
+ }
61
+ : undefined;
62
+ return mergeTemplateRenderOptions(mergeTemplateRenderOptions(gatewayTemplateRendering, requestSmartTemplateOpts), request.templateRenderOptions);
63
+ }
@@ -1,9 +1,20 @@
1
1
  /**
2
2
  * Merge @x12i/rendrix TemplateRenderOptions from gateway defaults and per-request overrides.
3
3
  */
4
- import type { TemplateRenderOptions } from '@x12i/rendrix';
4
+ import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
5
+ /** Request fields that participate in gateway + Rendrix template option merging. */
6
+ export type GatewayTemplateRenderRequestSlice = {
7
+ smartInput?: SmartInputConfig;
8
+ smartInputRenderOptions?: SmartInputRenderOptions;
9
+ templateRenderOptions?: TemplateRenderOptions;
10
+ };
5
11
  /**
6
12
  * Deep-merge template render options. Request/gateway overrides win per field.
7
13
  * For `subPathSearch`, `roots` on the override replace the base list when present.
8
14
  */
9
15
  export declare function mergeTemplateRenderOptions(base?: TemplateRenderOptions, override?: TemplateRenderOptions): TemplateRenderOptions | undefined;
16
+ /**
17
+ * Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
18
+ * Same merge order as {@link buildMessages}.
19
+ */
20
+ export declare function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering: TemplateRenderOptions | undefined, request: GatewayTemplateRenderRequestSlice): TemplateRenderOptions | undefined;
@@ -8,7 +8,7 @@ type AIProvider = string;
8
8
  type AIModel = string;
9
9
  export type UsageTier = string;
10
10
  import type { Activix } from '@x12i/activix';
11
- import type { TemplateRenderOptions } from '@x12i/rendrix';
11
+ import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
12
12
  import type { Logxer } from '@x12i/logxer';
13
13
  /**
14
14
  * Diagnostics options for opt-in authoritative tracing.
@@ -168,8 +168,8 @@ export type ActivityIdentity = {
168
168
  */
169
169
  actionRef?: string;
170
170
  };
171
- /** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, etc.). */
172
- export type { TemplateRenderOptions } from '@x12i/rendrix';
171
+ /** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, smartInput, etc.). */
172
+ export type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
173
173
  type LLMRequest = Parameters<LLMProviderRouter['invoke']>[0];
174
174
  type LLMResponse = Awaited<ReturnType<LLMProviderRouter['invoke']>>;
175
175
  /**
@@ -626,6 +626,10 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
626
626
  * Working memory (optional) - Affects all template parsing
627
627
  * Passed to Rendrix (v4+) for template variable substitution.
628
628
  * Plain {{path}} tokens are MUST paths: undefined after merge throws TemplateResolutionError (rethrown by the gateway).
629
+ *
630
+ * Dual roots (graph-engine / ai-tasks contract): `inputs` is the caller / graph-entry bag;
631
+ * `input` is the merged MAIN payload (object or JSON string). Smart-input and `input.*` / `inputs.*`
632
+ * paths resolve with cross-root fallback before render (see `resolveGatewayMemoryPathValue`).
629
633
  */
630
634
  workingMemory?: unknown;
631
635
  /**
@@ -635,6 +639,17 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
635
639
  * the full list or only set `enabled` and inherit `roots` from the gateway default merge.
636
640
  */
637
641
  templateRenderOptions?: TemplateRenderOptions;
642
+ /**
643
+ * Smart Input paths for Rendrix `{{smartInput}}` (optional shorthand).
644
+ * Merged into render options after gateway `templateRendering` and before `templateRenderOptions`
645
+ * (nested `templateRenderOptions.smartInput` wins when both are set).
646
+ */
647
+ smartInput?: SmartInputConfig;
648
+ /**
649
+ * Rendering controls for Smart Input markdown (optional shorthand).
650
+ * Merged the same way as `smartInput`; `templateRenderOptions.smartInputRenderOptions` wins when both are set.
651
+ */
652
+ smartInputRenderOptions?: SmartInputRenderOptions;
638
653
  /**
639
654
  * Messages array - Optional, can be used instead of instructions/prompt
640
655
  * If provided, will be appended as-is after built messages; instructions template text is still parsed for the system message when present
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x12i/ai-gateway",
3
- "version": "9.1.3",
3
+ "version": "9.1.6",
4
4
  "description": "AI Gateway - Unified interface for LLM provider routing and management",
5
5
  "type": "module",
6
6
  "exports": {
@@ -61,7 +61,7 @@
61
61
  "license": "mit",
62
62
  "dependencies": {
63
63
  "@x12i/ai-providers-router": "^4.7.7",
64
- "@x12i/rendrix": "^4.2.0",
64
+ "@x12i/rendrix": "^4.3.0",
65
65
  "@aws-sdk/s3-request-presigner": "^3.953.0",
66
66
  "@x12i/env": "^4.0.1",
67
67
  "@x12i/logxer": "^4.3.5",