@exellix/ai-tasks 8.4.1 → 8.4.3

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 (95) hide show
  1. package/.docs/DOWNSTREAM_ENV.md +42 -0
  2. package/.docs/FEEDBACK_TO_CLIENT_DOWNSTREAM_FIXES.md +64 -0
  3. package/.docs/INTERMEDIATE_STEPS.md +82 -0
  4. package/.docs/activity-structure.md +31 -0
  5. package/.docs/ai-task-ai-scoping-spec.md +338 -0
  6. package/.docs/ai-tasks-model-profile-aliases-7x.md +74 -0
  7. package/.docs/blockers-and-issues.md +346 -0
  8. package/.docs/building-runTask-sdk.md +659 -0
  9. package/.docs/building-skill-execution-orchestrator.md +968 -0
  10. package/.docs/code-used-before/run-task.txt +39 -0
  11. package/.docs/code-used-before/task-executor.ts.old +57 -0
  12. package/.docs/code-used-before/test-run-task.ts.old +42 -0
  13. package/.docs/code-used-before/types.txt +23 -0
  14. package/.docs/env-ready-policy.md +40 -0
  15. package/.docs/flow-io/flow-README.md +76 -0
  16. package/.docs/flow-io/narrix.md +124 -0
  17. package/.docs/flow-io/web-scoping.md +135 -0
  18. package/.docs/flow-io/xynthesis-post.md +154 -0
  19. package/.docs/flow-io/xynthesis-pre.md +181 -0
  20. package/.docs/gap-analysis.md +201 -0
  21. package/.docs/integration-facts-ai-tasks.md +109 -0
  22. package/.docs/investigation/ai-skills.md +170 -0
  23. package/.docs/investigation/external-packages-assignments.md +66 -0
  24. package/.docs/investigation/integration-summary.md +20 -0
  25. package/.docs/investigation/narrix-catalox.md +29 -0
  26. package/.docs/investigation/workplan-close-graph-engine-gaps.md +101 -0
  27. package/.docs/logging-stack.md +30 -0
  28. package/.docs/memory-narrix-adapter-developer-guide.md +402 -0
  29. package/.docs/memory-narrix-adapter-requirements.md +112 -0
  30. package/.docs/narrix-context-consumption-gap.md +184 -0
  31. package/.docs/narrix-context-downstream-report.md +30 -0
  32. package/.docs/narrix-ingest-and-packs-library-spec.md +240 -0
  33. package/.docs/narrix-record-input-current-design.md +48 -0
  34. package/.docs/pacakge.md +48 -0
  35. package/.docs/possible-components/README.md +11 -0
  36. package/.docs/possible-components/integration/README.md +10 -0
  37. package/.docs/possible-components/integration/gaps-when-merging.md +16 -0
  38. package/.docs/possible-components/integration/platform.md +54 -0
  39. package/.docs/possible-components/integration/reintegrate-into-ai-tasks.md +26 -0
  40. package/.docs/possible-components/integration/roadmap-and-checklists.md +54 -0
  41. package/.docs/possible-components/post-component/README.md +18 -0
  42. package/.docs/possible-components/post-component/builder-guide.md +175 -0
  43. package/.docs/possible-components/post-component/gaps-and-artifacts.md +52 -0
  44. package/.docs/possible-components/post-component/handler-audit.md +47 -0
  45. package/.docs/possible-components/post-component/handler-polish.md +41 -0
  46. package/.docs/possible-components/post-component/unified-protocol.md +59 -0
  47. package/.docs/possible-components/pre-component/README.md +22 -0
  48. package/.docs/possible-components/pre-component/builder-guide.md +127 -0
  49. package/.docs/possible-components/pre-component/gaps-and-artifacts.md +35 -0
  50. package/.docs/possible-components/pre-component/handler-ai-scoping.md +45 -0
  51. package/.docs/possible-components/pre-component/handler-narrix-preprocessor.md +49 -0
  52. package/.docs/possible-components/pre-component/handler-narrix-system2.md +35 -0
  53. package/.docs/possible-components/pre-component/handler-synthesized-context.md +65 -0
  54. package/.docs/possible-components/pre-component/handler-web-scope.md +29 -0
  55. package/.docs/possible-components/pre-component/unified-protocol.md +89 -0
  56. package/.docs/prefer-openrouter-routing-policy.md +132 -0
  57. package/.docs/questions-for-ai-skills.md +123 -0
  58. package/.docs/realtime-narrixing-gap-analysis.md +40 -0
  59. package/.docs/realtime-narrixing.md +433 -0
  60. package/.docs/run-context-object.md +32 -0
  61. package/.docs/session-id-usage.md +26 -0
  62. package/.docs/skill-library-spec.md +249 -0
  63. package/.docs/synthesized-context-strategy-spec.md +906 -0
  64. package/.docs/upstream-issue/2026-03-21_woroces-ai-tasks_ISSUE-006_web-scope-question-from-cni-entity.md +46 -0
  65. package/.docs/web-scopper-embed.md +93 -0
  66. package/.docs/xynthesis-wiring-and-io.md +12 -0
  67. package/README.md +15 -13
  68. package/dist/index.d.ts +2 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/internal/runPostStepLlmCall.d.ts.map +1 -1
  73. package/dist/internal/runPostStepLlmCall.js +4 -2
  74. package/dist/internal/runPostStepLlmCall.js.map +1 -1
  75. package/dist/invocation/resolveProfileInvocationRouting.js +2 -2
  76. package/dist/invocation/resolveProfileInvocationRouting.js.map +1 -1
  77. package/dist/utils/aiProfileModelFormat.d.ts +2 -2
  78. package/dist/utils/aiProfileModelFormat.js +2 -2
  79. package/dist/utils/aiProfilesCatalog.d.ts +16 -0
  80. package/dist/utils/aiProfilesCatalog.d.ts.map +1 -0
  81. package/dist/utils/aiProfilesCatalog.js +23 -0
  82. package/dist/utils/aiProfilesCatalog.js.map +1 -0
  83. package/dist/utils/resolveAiProfileModel.d.ts +2 -2
  84. package/dist/utils/resolveAiProfileModel.d.ts.map +1 -1
  85. package/dist/utils/resolveAiProfileModel.js +5 -5
  86. package/dist/utils/resolveAiProfileModel.js.map +1 -1
  87. package/dist/utils/routeModelConfigSlots.d.ts +3 -1
  88. package/dist/utils/routeModelConfigSlots.d.ts.map +1 -1
  89. package/dist/utils/routeModelConfigSlots.js +2 -1
  90. package/dist/utils/routeModelConfigSlots.js.map +1 -1
  91. package/documenations/upstream-feature-requests/README.md +2 -1
  92. package/documenations/upstream-feature-requests/ai-tasks-wrap-up-after-upstream.md +7 -4
  93. package/documenations/upstream-feature-requests/xynthesis-ai-profiles-2.1-import-break.md +324 -0
  94. package/documenations/upstream-feature-requests/xynthesis-orchestrator-invoke-contract-4.2.md +6 -4
  95. package/package.json +3 -2
@@ -0,0 +1,402 @@
1
+ # Memory Narrix Adapter — developer guide
2
+
3
+ This document is for the developer who will **implement** the Memory Narrix Adapter.
4
+ It assumes no prior knowledge of Narrix, ai-tasks memory, or the current implementation.
5
+ You should be able to build the component using **only**:
6
+
7
+ - `memory-narrix-adapter-requirements.md` (what the adapter must do), and
8
+ - this guide (background, shapes, and concrete examples).
9
+
10
+ You do **not** need to read the rest of the codebase to get started.
11
+
12
+ ---
13
+
14
+ ## High-level picture
15
+
16
+ - Ai-tasks is a task runner that keeps **memory** for tasks and jobs (JSON-like objects).
17
+ - Narrix is an **enrichment engine** that takes some input (a record, text, docs, or chat) and returns enriched data (signals, stories, etc.).
18
+ - The **Memory Narrix Adapter** sits in between:
19
+ - It receives **memory** (an arbitrary object) plus a few required parameters.
20
+ - It **interprets** that memory and decides how to turn it into a Narrix input.
21
+ - It either returns a **valid Narrix input** or a **structured “bad input” result** explaining why it cannot.
22
+
23
+ You are **not** responsible for calling Narrix, only for constructing the input object Narrix expects.
24
+
25
+ ---
26
+
27
+ ## What Narrix expects (input shapes)
28
+
29
+ Narrix supports four input “media”. The adapter’s job is to output **exactly one** of these shapes or say “bad input”.
30
+
31
+ ```ts
32
+ // Unified input (NarrixRunInput)
33
+
34
+ type NarrixRunInputRecord = {
35
+ medium: "record";
36
+ datasetId: string;
37
+ record: Record<string, unknown>;
38
+ // Optional; passed through to Narrix runner
39
+ sourceMeta?: Record<string, unknown>;
40
+ };
41
+
42
+ type NarrixRunInputText = {
43
+ medium: "text";
44
+ datasetId: string;
45
+ text: string;
46
+ meta?: Record<string, unknown>;
47
+ };
48
+
49
+ type NarrixRunInputDocs = {
50
+ medium: "docs";
51
+ datasetId: string;
52
+ document: {
53
+ pages: { text: string; pageId?: string; pageNumber?: number; index?: number; mime?: string; meta?: Record<string, unknown> }[];
54
+ docId?: string;
55
+ title?: string;
56
+ };
57
+ };
58
+
59
+ type NarrixRunInputChat = {
60
+ medium: "chat";
61
+ datasetId: string;
62
+ thread: {
63
+ messages: { role: "user" | "assistant" | "system" | "tool" | "other"; text: string; id?: string; ts?: number; authorId?: string; meta?: Record<string, unknown> }[];
64
+ threadId?: string;
65
+ title?: string;
66
+ participants?: string[];
67
+ };
68
+ };
69
+
70
+ type NarrixRunInput =
71
+ | NarrixRunInputRecord
72
+ | NarrixRunInputText
73
+ | NarrixRunInputDocs
74
+ | NarrixRunInputChat;
75
+ ```
76
+
77
+ You do not need to know how Narrix uses these; just construct one of these shapes.
78
+
79
+ ---
80
+
81
+ ## What “memory” looks like (conceptually)
82
+
83
+ Ai-tasks has three main memory levels. In practice these are just JSON-like objects; you do **not** need to know all fields:
84
+
85
+ - **jobMemory** — Long-lived data for the job (e.g. “current record”, job-wide metadata).
86
+ - **taskMemory** — Data produced by this task or previous tasks (e.g. prior Narrix runs).
87
+ - **executionMemory** — Execution-specific data (inputs, raw payloads, sourceMeta, internal state).
88
+
89
+ When ai-tasks calls the adapter, it can pass:
90
+
91
+ - Any one of these objects, or
92
+ - A **merged** object that contains pieces from multiple levels, or
93
+ - A completely different object that still has useful data.
94
+
95
+ You should treat the memory input as:
96
+
97
+ ```ts
98
+ type MemoryLike = unknown; // could be any JSON-like object
99
+ ```
100
+
101
+ Your job is to **inspect** this object and decide:
102
+
103
+ - What kind of thing it looks like (record, text, docs, chat, or “unknown”), and
104
+ - Which **subset** (if any) should be used as Narrix input.
105
+
106
+ You may also receive:
107
+
108
+ - A `datasetId` (always required).
109
+ - An optional **medium hint** (e.g. `"record"` or `"text"`) that you should respect when reasonable.
110
+
111
+ ---
112
+
113
+ ## Suggested adapter API (for implementation)
114
+
115
+ The requirements doc deliberately does not fix the exact API.
116
+ This is a suggested shape you can use when implementing the component.
117
+
118
+ ```ts
119
+ type MemoryNarrixAdapterInput = {
120
+ datasetId: string;
121
+ // Optional hint from caller; when present, prefer this medium
122
+ mediumHint?: "record" | "text" | "docs" | "chat";
123
+ // Arbitrary memory object (job + task + execution, or any JSON-like object)
124
+ memory: unknown;
125
+ };
126
+
127
+ type InterpretationKind = "record" | "text" | "docs" | "chat" | "mixed" | "unknown";
128
+
129
+ type InterpretationStrategy = "selection" | "transformation" | "serialization" | "none";
130
+
131
+ type MemoryNarrixAdapterSuccess = {
132
+ ok: true;
133
+ narrixInput: NarrixRunInput;
134
+ interpretation: {
135
+ kind: InterpretationKind;
136
+ // e.g. "jobMemory.currentRecord", "executionMemory.input.raw", "entire memory serialized as text"
137
+ sourceDescription: string;
138
+ // "guessed" vs "hinted" vs "exact"
139
+ confidence: "guessed" | "hinted" | "exact";
140
+ strategy: InterpretationStrategy;
141
+ };
142
+ };
143
+
144
+ type MemoryNarrixAdapterFailure = {
145
+ ok: false;
146
+ error: "NO_USABLE_INPUT" | "UNSUPPORTED_SHAPE" | "INCONSISTENT_DATA";
147
+ message: string;
148
+ attempted: string[]; // short descriptions of strategies you tried
149
+ foundSummary: string; // short description of what was in memory
150
+ interpretation?: {
151
+ kind: InterpretationKind;
152
+ strategy: InterpretationStrategy;
153
+ };
154
+ };
155
+
156
+ type MemoryNarrixAdapterResult = MemoryNarrixAdapterSuccess | MemoryNarrixAdapterFailure;
157
+ ```
158
+
159
+ You can adjust names, but the **ideas** must all be present:
160
+
161
+ - `NarrixRunInput` on success.
162
+ - Structured, non-throwing “bad input” on failure.
163
+ - Interpretation metadata (what it looked at, what it thought it was, and how it decided).
164
+
165
+ ---
166
+
167
+ ## What the adapter must actually do (step-by-step)
168
+
169
+ When called, the adapter should:
170
+
171
+ 1. **Inspect the memory object.**
172
+ - If it is not an object at all (e.g. `null`, a number, a string), you will probably end up returning a “bad input” result unless you decide to treat it as text.
173
+ - If it is an object, look at its fields and nested structures.
174
+
175
+ 2. **Optionally respect the medium hint.**
176
+ - If `mediumHint` is `"record"`, first try to find a record-shaped object.
177
+ - If `mediumHint` is `"text"`, first try to extract or serialize text.
178
+ - If no hint is provided, you decide the order of strategies (see examples below).
179
+
180
+ 3. **Try strategies, in a deterministic order.** For example:
181
+ - **Record strategy:** Look for a single JSON object that can be treated as a record.
182
+ - **Chat strategy:** Look for something that looks like a list of chat messages.
183
+ - **Docs strategy:** Look for something that looks like a list of pages with text.
184
+ - **Text strategy:** If nothing else matches, consider serializing the whole memory to text.
185
+
186
+ 4. **If a strategy succeeds, produce `NarrixRunInput`.**
187
+ - Make sure the resulting object matches one of the Narrix run input shapes exactly.
188
+ - Include `datasetId` (from the adapter input).
189
+ - For `record` medium, also set `sourceMeta` if you can infer it from memory.
190
+
191
+ 5. **Always return interpretation metadata.**
192
+ - Even on success, indicate where you got the data and how confident you were.
193
+ - On failure, list what you tried and what you found.
194
+
195
+ 6. **Never throw for “bad input”.**
196
+ - If the memory is unusable, return a `MemoryNarrixAdapterFailure`.
197
+ - The caller (ai-tasks) is responsible for turning that into an error response.
198
+
199
+ ---
200
+
201
+ ## How this replaces current behavior
202
+
203
+ Today, ai-tasks has multiple scattered pieces of logic:
204
+
205
+ - `resolvePreProcessorInput` — scans specific fields to find a `record` and `sourceMeta`.
206
+ - `normalizeInput` — validates and normalizes any Narrix input into the four media.
207
+ - `resolveNarrixInput` — resolves `{ $path: "jobMemory.currentRecord" }` into a concrete object.
208
+
209
+ The Memory Narrix Adapter **replaces all of that** with a single component:
210
+
211
+ - Ai-tasks will give you **datasetId**, optional **medium hint**, and a **memory object**.
212
+ - You return either a valid `NarrixRunInput` plus interpretation, or a structured “bad input”.
213
+ - Ai-tasks no longer needs to know where the record lives or how to normalize inputs.
214
+
215
+ You do **not** need to exactly copy today’s priority order; you only need to meet the requirements in `memory-narrix-adapter-requirements.md`.
216
+
217
+ ---
218
+
219
+ ## Example scenarios
220
+
221
+ These examples are illustrative, not exhaustive. They show how to think about memory and what the adapter might do.
222
+
223
+ ### 1. Simple record in memory
224
+
225
+ **Input:**
226
+
227
+ ```ts
228
+ const input: MemoryNarrixAdapterInput = {
229
+ datasetId: "vuln-dataset",
230
+ mediumHint: "record",
231
+ memory: {
232
+ jobMemory: {
233
+ currentRecord: { id: "v-123", severity: "high", title: "Example vuln" },
234
+ sourceMeta: { source: "scanner-x" },
235
+ },
236
+ },
237
+ };
238
+ ```
239
+
240
+ **Expected behavior:**
241
+
242
+ - Detect that `jobMemory.currentRecord` is a record-shaped object.
243
+ - Treat this as `medium: "record"`.
244
+ - Use `jobMemory.sourceMeta` as `sourceMeta`.
245
+
246
+ **Output (success):**
247
+
248
+ ```ts
249
+ {
250
+ ok: true,
251
+ narrixInput: {
252
+ medium: "record",
253
+ datasetId: "vuln-dataset",
254
+ record: { id: "v-123", severity: "high", title: "Example vuln" },
255
+ sourceMeta: { source: "scanner-x" },
256
+ },
257
+ interpretation: {
258
+ kind: "record",
259
+ sourceDescription: "jobMemory.currentRecord",
260
+ confidence: "hinted",
261
+ strategy: "selection",
262
+ },
263
+ }
264
+ ```
265
+
266
+ ### 2. Chat-like memory without a hint
267
+
268
+ **Input:**
269
+
270
+ ```ts
271
+ const input: MemoryNarrixAdapterInput = {
272
+ datasetId: "support-chat",
273
+ memory: {
274
+ thread: {
275
+ messages: [
276
+ { role: "user", text: "hi" },
277
+ { role: "assistant", text: "hello" },
278
+ ],
279
+ },
280
+ },
281
+ };
282
+ ```
283
+
284
+ **Expected behavior:**
285
+
286
+ - Detect that `thread.messages` is an array of `{ role, text }`.
287
+ - Classify this as `kind: "chat"`.
288
+ - Build a `NarrixRunInputChat`.
289
+
290
+ **Output (success, shape only):**
291
+
292
+ ```ts
293
+ {
294
+ ok: true,
295
+ narrixInput: {
296
+ medium: "chat",
297
+ datasetId: "support-chat",
298
+ thread: {
299
+ messages: [
300
+ { role: "user", text: "hi" },
301
+ { role: "assistant", text: "hello" },
302
+ ],
303
+ },
304
+ },
305
+ interpretation: {
306
+ kind: "chat",
307
+ sourceDescription: "thread.messages",
308
+ confidence: "guessed",
309
+ strategy: "selection",
310
+ },
311
+ }
312
+ ```
313
+
314
+ ### 3. Whole memory serialized as text
315
+
316
+ **Input:**
317
+
318
+ ```ts
319
+ const input: MemoryNarrixAdapterInput = {
320
+ datasetId: "debug-dataset",
321
+ memory: {
322
+ jobMemory: { /* many fields */ },
323
+ taskMemory: { /* many fields */ },
324
+ executionMemory: { /* many fields */ },
325
+ },
326
+ };
327
+ ```
328
+
329
+ **Expected behavior:**
330
+
331
+ - None of the specific strategies (record, chat, docs) find a good match.
332
+ - As a last resort, decide to **serialize** the entire memory object into a text blob (e.g. JSON string).
333
+ - Return a `medium: "text"` input.
334
+
335
+ **Output (success, shape only):**
336
+
337
+ ```ts
338
+ {
339
+ ok: true,
340
+ narrixInput: {
341
+ medium: "text",
342
+ datasetId: "debug-dataset",
343
+ text: "<serialized memory here>",
344
+ },
345
+ interpretation: {
346
+ kind: "text",
347
+ sourceDescription: "entire memory serialized",
348
+ confidence: "guessed",
349
+ strategy: "serialization",
350
+ },
351
+ }
352
+ ```
353
+
354
+ ### 4. Bad input
355
+
356
+ **Input:**
357
+
358
+ ```ts
359
+ const input: MemoryNarrixAdapterInput = {
360
+ datasetId: "any",
361
+ memory: 42,
362
+ };
363
+ ```
364
+
365
+ **Expected behavior:**
366
+
367
+ - No usable structure (it’s just a number).
368
+ - Return a failure result.
369
+
370
+ **Output (failure, shape only):**
371
+
372
+ ```ts
373
+ {
374
+ ok: false,
375
+ error: "NO_USABLE_INPUT",
376
+ message: "Memory is not an object; cannot derive Narrix input.",
377
+ attempted: ["checked for record", "checked for chat", "checked for docs", "considered text serialization"],
378
+ foundSummary: "memory is a number (42)",
379
+ interpretation: {
380
+ kind: "unknown",
381
+ strategy: "none",
382
+ },
383
+ }
384
+ ```
385
+
386
+ ---
387
+
388
+ ## How to work with these docs
389
+
390
+ You should read:
391
+
392
+ - `memory-narrix-adapter-requirements.md` — what the component is **responsible for** and how ai-tasks will use it.
393
+ - This developer guide — background on Narrix input shapes, memory, suggested API, and example behaviors.
394
+
395
+ You do **not** need to match today’s implementation details (priority order, exact property names) unless you choose to.
396
+ Your implementation should focus on:
397
+
398
+ - Producing valid Narrix inputs,
399
+ - Providing clear interpretation metadata,
400
+ - Returning structured failures instead of throwing, and
401
+ - Being easy to extend as new memory shapes or strategies appear.
402
+
@@ -0,0 +1,112 @@
1
+ # Memory Narrix Adapter — requirements definition
2
+
3
+ This document defines requirements for a **component** (not a one-off function) whose job is to take memory and other required inputs and produce what NARRIX needs: either a valid NARRIX input, a decision about which subset of the input to use, or an explicit "bad input" result. The component is intended to be extended over time; ai-tasks will call it and remove the current ad-hoc resolution logic once the adapter exists.
4
+
5
+ ---
6
+
7
+ ## Name and responsibility
8
+
9
+ - **Name:** Memory Narrix Adapter (or equivalent; the name should reflect "memory to NARRIX input").
10
+ - **Responsibility:** Bring NARRIX the information it needs from memory. Given required inputs and **any** object (e.g. job memory, task memory, execution memory, the whole memory, or a mix), the adapter either:
11
+ 1. **Decides** which subset of the input to use as NARRIX input (intelligent selection), or
12
+ 2. **Transforms** what it gets into something that conforms to the NARRIX protocol and works as input, or
13
+ 3. **Reports** that the input is bad / unusable.
14
+
15
+ The adapter is an intelligent adapter: it understands the NARRIX protocol, understands the shape of memory, and produces a clear outcome (usable input or "bad input").
16
+
17
+ ---
18
+
19
+ ## Knowing or guessing what we're looking at
20
+
21
+ The adapter must be able to **know or at least guess what it is looking at** based on what it finds in the memory. That is:
22
+
23
+ - **Need:** Callers (and NARRIX) benefit from understanding the *nature* of the data: e.g. "this is a single record," "this looks like a chat thread," "this is job-level context," "this is a document with pages," "this is a large memory object that could be serialized as text." The adapter inspects the provided object and, from structure and content, infers or classifies what kind of input it is. That interpretation drives which NARRIX medium and shape to use and whether the input is usable at all.
24
+ - **Input:** The same memory/arbitrary object the adapter receives. No extra "type" hint is required from the caller (though the caller **may** provide a medium hint — see below); the adapter figures it out from what's there.
25
+ - **Output:** The adapter's result exposes this interpretation: which part of memory was used, what it classified the content as, and whether that was inferred ("guess") or known. This supports debugging, observability, and correct handling without the caller having to know memory layout.
26
+
27
+ The Memory Narrix Adapter doesn't only select or transform — it **interprets** what it found. The new Narrix component will implement how that interpretation works (heuristics, schema hints, conventions); this document states the need and that inputs/outputs must support it.
28
+
29
+ ---
30
+
31
+ ## Inputs to the component
32
+
33
+ - **`datasetId`** — Required. Determines which Narrix pack/entity to use. Always provided by the caller (e.g. from `request.narrix.datasetId` or equivalent config).
34
+ - **Medium hint (optional)** — The caller may suggest a medium (e.g. `"record"`, `"text"`). When provided, the adapter prefers that medium; when not provided, it auto-detects from what it finds. This supports both "I know what this is" and "figure it out" use cases.
35
+ - **Memory / arbitrary object** — The adapter receives "memory" (or any object): e.g. full or partial `jobMemory`, `taskMemory`, `executionMemory`, the **entire memory** as one object, or a merged view. It can be anything.
36
+
37
+ The key requirement: the adapter can take **any** such object and attempt to derive NARRIX input from it.
38
+
39
+ ### Whole memory as input
40
+
41
+ A critical scenario: the adapter receives the **entire memory** (job + task + execution, or all of them merged). It does not just look for a specific field; it can decide to use the whole thing (e.g. serialize it for text medium), or pick the most relevant part. The adapter understands that memory has levels (job, task, execution) and can reason about which level or part is most useful for NARRIX.
42
+
43
+ ---
44
+
45
+ ## NARRIX protocol (what the adapter targets)
46
+
47
+ The adapter's output must align with the NARRIX run input contract. Valid inputs are one of four media:
48
+
49
+ - **record** — `{ medium: "record", datasetId, record, sourceMeta? }`
50
+ - **text** — `{ medium: "text", datasetId, text, meta? }`
51
+ - **docs** — `{ medium: "docs", datasetId, document: { pages, docId?, title? } }`
52
+ - **chat** — `{ medium: "chat", datasetId, thread: { messages, threadId?, title?, participants? } }`
53
+
54
+ The adapter's job is to produce something that fits one of these shapes (or to say it cannot).
55
+
56
+ ### sourceMeta
57
+
58
+ When producing a record-medium input, the adapter must also resolve **`sourceMeta`** (metadata about the record's origin). Today this is found separately from the record itself (e.g. `executionMemory.input.sourceMeta` or `jobMemory.sourceMeta`). The adapter takes over this responsibility: it knows where to look for sourceMeta and includes it in the output when relevant.
59
+
60
+ ### Legacy formats
61
+
62
+ The adapter must handle **legacy shapes** that lack a `medium` field, e.g. `{ datasetId, recordType, record }`. Today these are normalized in `task.ts` `normalizeInput()`. The adapter subsumes that normalization: if it receives something that looks like a legacy input, it interprets and converts it.
63
+
64
+ ---
65
+
66
+ ## Outputs of the component
67
+
68
+ The component produces one of:
69
+
70
+ 1. **Usable NARRIX input**
71
+ A concrete `NarrixRunInput` (one of the four media above), either by:
72
+ - **Selection:** Choosing a subset of the provided object (e.g. "use the record found at this path") and returning it in the right shape, or
73
+ - **Transformation:** Converting the given object (or a part of it) into a valid `NarrixRunInput` (e.g. serializing memory into text, extracting fields to form a record, restructuring chat messages).
74
+
75
+ 2. **Bad input**
76
+ A structured result (not a thrown error) indicating the provided memory/object cannot be used to form valid NARRIX input. Must include at minimum:
77
+ - **What was attempted** — what the adapter tried to do (e.g. "looked for a record, tried text serialization").
78
+ - **Why it failed** — reason (e.g. "no record-shaped data found, memory is empty, incompatible shape").
79
+ - **What was found** — what was actually in the memory (summary, not the full object), so the caller can produce a useful error message.
80
+
81
+ 3. **Interpretation metadata** (always present, on both success and failure)
82
+ - Which part of memory was used (or inspected).
83
+ - What the content was classified as (record, chat, document, text, mixed, unknown).
84
+ - Whether the classification was inferred ("guess") or known (e.g. medium hint was provided).
85
+ - Which strategy was applied (selection, transformation, serialization).
86
+
87
+ ---
88
+
89
+ ## Behavior (requirements)
90
+
91
+ - **Extensible** — New strategies, memory shapes, or media can be added without ai-tasks having to know the details. New behavior goes in one place.
92
+ - **Deterministic where possible** — Same inputs produce the same decision/transformation unless the design explicitly allows non-determinism.
93
+ - **No hidden global state** — Decisions are based only on the provided inputs and the provided memory object.
94
+ - **Clear contract** — Inputs and outputs are well-defined so ai-tasks (or any other caller) can integrate without depending on implementation details.
95
+ - **Subsumes existing normalization** — The adapter replaces both `resolvePreProcessorInput` (pre-processor record resolution) and `normalizeInput` (media validation/normalization in task.ts). One component, one place.
96
+
97
+ ---
98
+
99
+ ## Integration (after the component exists)
100
+
101
+ - Ai-tasks will **use** the Memory Narrix Adapter when it needs to run NARRIX. Both execution paths (pre-processor and NARRIX_THEN_DIRECT) can use it. Ai-tasks passes `datasetId`, optional medium hint, and the relevant memory.
102
+ - Ai-tasks will **remove** the old resolution logic:
103
+ - `resolvePreProcessorInput` (the 6-step priority-list record scavenger).
104
+ - `resolveNarrixInput` in task-sdk (the `$path` resolver for NARRIX_THEN_DIRECT).
105
+ - `normalizeInput` in task.ts (the media validation/normalization).
106
+ - The exact API (method name, parameters, return type) will be defined when the component is implemented; this document specifies the responsibility and the input/output semantics.
107
+
108
+ ---
109
+
110
+ ## Relation to current design
111
+
112
+ The current behavior (where the record comes from, and its problems) is described in [narrix-record-input-current-design.md](./narrix-record-input-current-design.md). The Memory Narrix Adapter is intended to replace that with a single, explicit component that can interpret memory, select or transform it into NARRIX input (or report bad input), and be extended over time.