@exellix/ai-tasks 10.0.9 → 10.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +32 -35
- package/RUNTASK_REQUEST.md +4 -4
- package/dist/activix/phaseTracking.d.ts +1 -1
- package/dist/activix/phaseTracking.d.ts.map +1 -1
- package/dist/activix/phaseTracking.js.map +1 -1
- package/dist/builders/task-request-builder.d.ts +1 -54
- package/dist/builders/task-request-builder.d.ts.map +1 -1
- package/dist/builders/task-request-builder.js +1 -180
- package/dist/builders/task-request-builder.js.map +1 -1
- package/dist/core/task-sdk.d.ts +4 -10
- package/dist/core/task-sdk.d.ts.map +1 -1
- package/dist/core/task-sdk.js +35 -117
- package/dist/core/task-sdk.js.map +1 -1
- package/dist/errors/runTaskExecutionError.d.ts +1 -1
- package/dist/errors/runTaskExecutionError.d.ts.map +1 -1
- package/dist/errors/runTaskExecutionError.js +0 -2
- package/dist/errors/runTaskExecutionError.js.map +1 -1
- package/dist/errors/smartInputValidationError.d.ts +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/resolveRunTaskRuntimeKnobs.d.ts +2 -5
- package/dist/internal/resolveRunTaskRuntimeKnobs.d.ts.map +1 -1
- package/dist/internal/resolveRunTaskRuntimeKnobs.js +3 -36
- package/dist/internal/resolveRunTaskRuntimeKnobs.js.map +1 -1
- package/dist/localTasks/collectEvidence.d.ts.map +1 -1
- package/dist/localTasks/collectEvidence.js +13 -23
- package/dist/localTasks/collectEvidence.js.map +1 -1
- package/dist/localTasks/decideWebScope.js +1 -1
- package/dist/localTasks/decideWebScope.js.map +1 -1
- package/dist/localTasks/index.d.ts +0 -1
- package/dist/localTasks/index.d.ts.map +1 -1
- package/dist/localTasks/index.js +2 -4
- package/dist/localTasks/index.js.map +1 -1
- package/dist/localTasks/playgroundSeedMain.d.ts +4 -0
- package/dist/localTasks/playgroundSeedMain.d.ts.map +1 -0
- package/dist/localTasks/playgroundSeedMain.js +26 -0
- package/dist/localTasks/playgroundSeedMain.js.map +1 -0
- package/dist/logxer/aiTasksDiagnosticCodes.d.ts +1 -1
- package/dist/logxer/aiTasksDiagnosticCodes.js +1 -1
- package/dist/logxer/aiTasksDiagnosticCodes.js.map +1 -1
- package/dist/narrix/narrixUnitExecution.d.ts.map +1 -1
- package/dist/narrix/narrixUnitExecution.js +1 -6
- package/dist/narrix/narrixUnitExecution.js.map +1 -1
- package/dist/narrix/webContextMarkdown.d.ts +2 -25
- package/dist/narrix/webContextMarkdown.d.ts.map +1 -1
- package/dist/narrix/webContextMarkdown.js +33 -57
- package/dist/narrix/webContextMarkdown.js.map +1 -1
- package/dist/node-execution/buildRequestFromNodePlan.d.ts.map +1 -1
- package/dist/node-execution/buildRequestFromNodePlan.js +0 -12
- package/dist/node-execution/buildRequestFromNodePlan.js.map +1 -1
- package/dist/node-execution/createNodeExecutionHost.d.ts.map +1 -1
- package/dist/node-execution/createNodeExecutionHost.js +1 -26
- package/dist/node-execution/createNodeExecutionHost.js.map +1 -1
- package/dist/node-execution/dispatchExecutionUnit.d.ts.map +1 -1
- package/dist/node-execution/dispatchExecutionUnit.js +0 -15
- package/dist/node-execution/dispatchExecutionUnit.js.map +1 -1
- package/dist/node-execution/executeNodeFromPlan.d.ts.map +1 -1
- package/dist/node-execution/executeNodeFromPlan.js +0 -15
- package/dist/node-execution/executeNodeFromPlan.js.map +1 -1
- package/dist/node-execution/executePlaygroundElement.d.ts +23 -0
- package/dist/node-execution/executePlaygroundElement.d.ts.map +1 -0
- package/dist/node-execution/executePlaygroundElement.js +80 -0
- package/dist/node-execution/executePlaygroundElement.js.map +1 -0
- package/dist/node-execution/index.d.ts +2 -0
- package/dist/node-execution/index.d.ts.map +1 -1
- package/dist/node-execution/index.js +1 -0
- package/dist/node-execution/index.js.map +1 -1
- package/dist/node-execution/types.d.ts +0 -2
- package/dist/node-execution/types.d.ts.map +1 -1
- package/dist/observability/classifyRunTaskFailure.d.ts +1 -1
- package/dist/observability/classifyRunTaskFailure.d.ts.map +1 -1
- package/dist/observability/classifyRunTaskFailure.js +0 -3
- package/dist/observability/classifyRunTaskFailure.js.map +1 -1
- package/dist/observability/extractAiTasksObservability.d.ts.map +1 -1
- package/dist/observability/extractAiTasksObservability.js +0 -8
- package/dist/observability/extractAiTasksObservability.js.map +1 -1
- package/dist/planWebScopeQuestions/index.d.ts +1 -1
- package/dist/planWebScopeQuestions/index.js +1 -1
- package/dist/rendrixUpstreamExports.d.ts +1 -1
- package/dist/rendrixUpstreamExports.d.ts.map +1 -1
- package/dist/rendrixUpstreamExports.js +1 -1
- package/dist/rendrixUpstreamExports.js.map +1 -1
- package/dist/synthesis/index.d.ts +1 -1
- package/dist/synthesis/index.js +1 -1
- package/dist/synthesis/resolveSourceMaterial.d.ts +3 -7
- package/dist/synthesis/resolveSourceMaterial.d.ts.map +1 -1
- package/dist/synthesis/resolveSourceMaterial.js +15 -78
- package/dist/synthesis/resolveSourceMaterial.js.map +1 -1
- package/dist/task-strategies/buildTaskStrategyCatalogDescriptor.d.ts +0 -1
- package/dist/task-strategies/buildTaskStrategyCatalogDescriptor.d.ts.map +1 -1
- package/dist/task-strategies/buildTaskStrategyCatalogDescriptor.js +1 -9
- package/dist/task-strategies/buildTaskStrategyCatalogDescriptor.js.map +1 -1
- package/dist/task-strategies/canonicalInputExecutionStrategies.d.ts +3 -4
- package/dist/task-strategies/canonicalInputExecutionStrategies.d.ts.map +1 -1
- package/dist/task-strategies/canonicalInputExecutionStrategies.js +3 -4
- package/dist/task-strategies/canonicalInputExecutionStrategies.js.map +1 -1
- package/dist/task-strategies/canonicalTaskStrategies.d.ts +2 -2
- package/dist/task-strategies/canonicalTaskStrategies.js +1 -1
- package/dist/task-strategies/canonicalTaskStrategies.js.map +1 -1
- package/dist/task-strategies/cataloxCatalogViews.d.ts +2 -5
- package/dist/task-strategies/cataloxCatalogViews.d.ts.map +1 -1
- package/dist/task-strategies/cataloxCatalogViews.js +3 -6
- package/dist/task-strategies/cataloxCatalogViews.js.map +1 -1
- package/dist/task-strategies/constants.d.ts +0 -4
- package/dist/task-strategies/constants.d.ts.map +1 -1
- package/dist/task-strategies/constants.js +0 -4
- package/dist/task-strategies/constants.js.map +1 -1
- package/dist/task-strategies/index.d.ts +4 -6
- package/dist/task-strategies/index.d.ts.map +1 -1
- package/dist/task-strategies/index.js +4 -5
- package/dist/task-strategies/index.js.map +1 -1
- package/dist/task-strategies/listAiTaskStrategies.d.ts +0 -2
- package/dist/task-strategies/listAiTaskStrategies.d.ts.map +1 -1
- package/dist/task-strategies/listAiTaskStrategies.js +1 -5
- package/dist/task-strategies/listAiTaskStrategies.js.map +1 -1
- package/dist/types/index.d.ts +1 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/task-types.d.ts +9 -133
- package/dist/types/task-types.d.ts.map +1 -1
- package/dist/types/task-types.js +0 -4
- package/dist/types/task-types.js.map +1 -1
- package/dist/types/web-scope-types.d.ts +20 -0
- package/dist/types/web-scope-types.d.ts.map +1 -0
- package/dist/types/web-scope-types.js +2 -0
- package/dist/types/web-scope-types.js.map +1 -0
- package/dist/utils/runTaskRequestShape.d.ts +1 -5
- package/dist/utils/runTaskRequestShape.d.ts.map +1 -1
- package/dist/utils/runTaskRequestShape.js +0 -26
- package/dist/utils/runTaskRequestShape.js.map +1 -1
- package/dist/utils/templateContext.d.ts +16 -0
- package/dist/utils/templateContext.d.ts.map +1 -0
- package/dist/utils/templateContext.js +35 -0
- package/dist/utils/templateContext.js.map +1 -0
- package/dist/validation/helpers.d.ts.map +1 -1
- package/dist/validation/helpers.js +3 -22
- package/dist/validation/helpers.js.map +1 -1
- package/dist/validation/validateRunTaskConfig.d.ts.map +1 -1
- package/dist/validation/validateRunTaskConfig.js +2 -0
- package/dist/validation/validateRunTaskConfig.js.map +1 -1
- package/dist/validation/validateRunTaskInvoke.d.ts.map +1 -1
- package/dist/validation/validateRunTaskInvoke.js +2 -0
- package/dist/validation/validateRunTaskInvoke.js.map +1 -1
- package/dist/validation/validateWebScopeUnit.d.ts +16 -0
- package/dist/validation/validateWebScopeUnit.d.ts.map +1 -0
- package/dist/validation/validateWebScopeUnit.js +107 -0
- package/dist/validation/validateWebScopeUnit.js.map +1 -0
- package/dist/web-scope/applyWebScopeToRequest.d.ts +11 -0
- package/dist/web-scope/applyWebScopeToRequest.d.ts.map +1 -0
- package/dist/web-scope/applyWebScopeToRequest.js +42 -0
- package/dist/web-scope/applyWebScopeToRequest.js.map +1 -0
- package/dist/web-scope/buildSearchInput.d.ts +22 -0
- package/dist/web-scope/buildSearchInput.d.ts.map +1 -0
- package/dist/web-scope/buildSearchInput.js +108 -0
- package/dist/web-scope/buildSearchInput.js.map +1 -0
- package/dist/web-scope/client.d.ts +12 -0
- package/dist/web-scope/client.d.ts.map +1 -0
- package/dist/web-scope/client.js +72 -0
- package/dist/web-scope/client.js.map +1 -0
- package/dist/web-scope/renderWebQueryTemplate.d.ts +14 -0
- package/dist/web-scope/renderWebQueryTemplate.d.ts.map +1 -0
- package/dist/web-scope/renderWebQueryTemplate.js +44 -0
- package/dist/web-scope/renderWebQueryTemplate.js.map +1 -0
- package/dist/web-scope/webContextMarkdown.d.ts +22 -0
- package/dist/web-scope/webContextMarkdown.d.ts.map +1 -0
- package/dist/web-scope/webContextMarkdown.js +163 -0
- package/dist/web-scope/webContextMarkdown.js.map +1 -0
- package/documenations/run-task-execution-flow.md +3 -7
- package/documenations/web-scoping-in-ai-tasks.md +88 -428
- package/package.json +16 -33
- package/dist/narrix/applyWebScopeToRequest.d.ts +0 -9
- package/dist/narrix/applyWebScopeToRequest.d.ts.map +0 -1
- package/dist/narrix/applyWebScopeToRequest.js +0 -156
- package/dist/narrix/applyWebScopeToRequest.js.map +0 -1
- package/dist/narrix/buildWebScopeScopeInput.d.ts +0 -39
- package/dist/narrix/buildWebScopeScopeInput.d.ts.map +0 -1
- package/dist/narrix/buildWebScopeScopeInput.js +0 -193
- package/dist/narrix/buildWebScopeScopeInput.js.map +0 -1
- package/dist/narrix/webScoper.d.ts +0 -43
- package/dist/narrix/webScoper.d.ts.map +0 -1
- package/dist/narrix/webScoper.js +0 -144
- package/dist/narrix/webScoper.js.map +0 -1
- package/documenations/activix.md +0 -187
|
@@ -1,503 +1,163 @@
|
|
|
1
1
|
## Web scoping in `@exellix/ai-tasks`
|
|
2
2
|
|
|
3
|
-
This document explains
|
|
3
|
+
This document explains how web scoping is wired into ai-tasks, how requests opt in, what data flows through `@x12i/web-scoper`, and what guarantees / failure modes exist.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## 1. High-level overview
|
|
8
8
|
|
|
9
|
-
- **Goal**:
|
|
10
|
-
- **
|
|
9
|
+
- **Goal**: Retrieve **external web context** for a search query (optionally enriched with record facts) and expose it on `executionMemory.webContext`.
|
|
10
|
+
- **Package**: [`@x12i/web-scoper`](https://www.npmjs.com/package/@x12i/web-scoper) — planning, Tavily search via `@x12i/search-adapter`, normalized `WebContext`.
|
|
11
|
+
- **Adapter layer**: `src/web-scope/` renders the unit's `webQueryTemplate` into `{ question, record?, options? }` (or a pack), then calls the scoper. No Graphenix, Activix, or NARRIX CNI fields are sent.
|
|
12
|
+
- **Trigger** (single, explicit): an `externalPreUtility` execution unit with **`strategyKey: "webScope"`**. There is **no** NARRIX trigger and **no** implicit question fallback.
|
|
13
|
+
- **Search query**: the **rendered `unitParams.webQueryTemplate`** (a Rendrix string, e.g. `"How to solve {{input.vulnerability}}?"`). The template is **required** when the unit is enabled.
|
|
14
|
+
- **Result**:
|
|
11
15
|
|
|
12
16
|
```ts
|
|
13
|
-
|
|
14
|
-
datasetId: "...",
|
|
15
|
-
enableWebScope: true, // ← opt-in; default is false/absent
|
|
16
|
-
};
|
|
17
|
+
ctx.executionMemory.webContext: WebScopeResult | WebScopePackResult
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
- After a NARRIX run completes successfully (CNI ingested + runner executed).
|
|
21
|
-
- Implemented in the **task SDK**, in the same flow that invokes the local NARRIX handler.
|
|
22
|
-
- **Where the result lands**:
|
|
20
|
+
Always set when the unit runs, including miss/error shapes (`ok: false`).
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
ctx.executionMemory.webContext: WebScoperResult
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
where `WebScoperResult` is defined by `@exellix/narrix-web-scoper` and is always present when `enableWebScope === true`, even on miss/error.
|
|
29
|
-
|
|
30
|
-
- **Failure stance**: **Lenient.** If web scoping fails or misses, the NARRIX task still runs and `_narrix` output is still attached. Web scoping only affects `executionMemory.webContext` and observability.
|
|
22
|
+
- **Failure stance**: **Lenient at runtime** (web scoping failures do not abort MAIN execution), but **loud and early at validation**: a missing/unresolvable `webQueryTemplate` is a config error.
|
|
31
23
|
|
|
32
24
|
---
|
|
33
25
|
|
|
34
|
-
## 2.
|
|
35
|
-
|
|
36
|
-
### 2.1. Request shape
|
|
37
|
-
|
|
38
|
-
ai-tasks exposes NARRIX as a **local task** in the task SDK. The entry-point for callers is a `RunTaskRequest` that may include a `narrix` section used by the NARRIX pre-processor.
|
|
39
|
-
|
|
40
|
-
The relevant part of the request is:
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
// src/types/task-types.ts (conceptual)
|
|
44
|
-
export interface NarrixPreProcessorConfig {
|
|
45
|
-
datasetId: string;
|
|
46
|
-
attachToField?: string;
|
|
47
|
-
enableWebScope?: boolean; // ← added for web scoping
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface RunTaskRequest {
|
|
51
|
-
skillKey: string;
|
|
52
|
-
input: unknown;
|
|
53
|
-
narrix?: NarrixPreProcessorConfig;
|
|
54
|
-
// ... other fields: executionMemory, variables, etc.
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
- **`narrix.datasetId`**: required; selects which NARRIX dataset / pack to run.
|
|
59
|
-
- **`narrix.enableWebScope`**:
|
|
60
|
-
- **`true`** → ai-tasks will attempt a web scoping call after NARRIX completes.
|
|
61
|
-
- **absent / `false`** → web scoping is **completely skipped** for this request.
|
|
62
|
-
|
|
63
|
-
### 2.2. Example from a graph builder (worox-graphs)
|
|
26
|
+
## 2. Scoper contract (`@x12i/web-scoper`)
|
|
64
27
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```jsonc
|
|
68
|
-
{
|
|
69
|
-
"metadata": {
|
|
70
|
-
"narrix": {
|
|
71
|
-
"datasetId": "network.vuln.instances",
|
|
72
|
-
"enableWebScope": true
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
In TypeScript:
|
|
28
|
+
### 2.1. Single search
|
|
79
29
|
|
|
80
30
|
```ts
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Only when that `enableWebScope` flag is `true` will ai-tasks invoke the web scoper.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## 3. Execution flow inside ai-tasks
|
|
93
|
-
|
|
94
|
-
### 3.1. NARRIX run
|
|
95
|
-
|
|
96
|
-
The normal NARRIX pipeline in ai-tasks is:
|
|
97
|
-
|
|
98
|
-
1. **Ingest** raw input into CNI via `@exellix/narrix-ingest`.
|
|
99
|
-
2. **Run** the NARRIX runner (`@exellix/narrix-runner`) with the CNI and `datasetId`.
|
|
100
|
-
3. **Attach** the NARRIX result to the task’s execution memory.
|
|
101
|
-
|
|
102
|
-
This produces a **success result** with a shape similar to:
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
export interface NarrixRunOutputSuccess {
|
|
106
|
-
entity: unknown;
|
|
107
|
-
signals: unknown;
|
|
108
|
-
stories: unknown;
|
|
109
|
-
passes: unknown;
|
|
110
|
-
meta: unknown;
|
|
111
|
-
cni?: unknown; // raw CNI (typed more strictly by narrix packages)
|
|
112
|
-
}
|
|
31
|
+
await scoper.search({
|
|
32
|
+
question: "Is CVE-2021-44228 patched in OpenSSL 3.0?",
|
|
33
|
+
record?: { cveId: "CVE-2021-44228", product: "openssl" },
|
|
34
|
+
options?: { maxQueries?: 3, freshnessDays?: 30, /* … */ },
|
|
35
|
+
});
|
|
36
|
+
// → { ok: true, context?: WebContext } | { ok: false, error?: { reason, message? } }
|
|
113
37
|
```
|
|
114
38
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### 3.2. Web scoping hook
|
|
118
|
-
|
|
119
|
-
After a successful NARRIX run, the task SDK checks `narrix.enableWebScope`:
|
|
120
|
-
|
|
121
|
-
1. If **absent/false**:
|
|
122
|
-
- **No web scoping call is made.**
|
|
123
|
-
- `executionMemory.webContext` remains `undefined`.
|
|
124
|
-
2. If **true**:
|
|
125
|
-
- ai-tasks builds scope fields via **`resolveWebScopeQuestionAndTemplates`** in `src/narrix/buildWebScopeScopeInput.ts`, then either calls **`runWebScope()`** (`scopeGeneric` / `ScopeInput`) or **`runWebScopeQuestionPack()`** (`scopeQuestionPack` / explicit questions) from `src/narrix/webScoper.ts`.
|
|
126
|
-
- The result is normalized to **`WebScoperResult`** and written into `executionMemory.webContext` **regardless of hit/miss/error**.
|
|
127
|
-
|
|
128
|
-
#### 3.2.1 Search question / templates / explicit questions (ISSUE-006, `@exellix/narrix-web-scoper` 1.2.0+)
|
|
129
|
-
|
|
130
|
-
Optional fields on **`RunTaskRequest.narrix`**:
|
|
131
|
-
|
|
132
|
-
| Field | Purpose |
|
|
133
|
-
|--------|--------|
|
|
134
|
-
| **`webScopeTemplates`** | Non-empty array → passed as `ScopeInput.webScopeTemplates`. Uses **athenix-parser** token syntax in the web-scoper; **replaces** normal query planning when set. |
|
|
135
|
-
| **`webScopeObjects`** | Merged on top of an **auto-built** context (CNI `knownFacts`, common `entity.graphized.vulnerability.*` fields, `question` / `baseQuestion`, `entityKey` / `label`). |
|
|
136
|
-
| **`webScopeQuestionTemplate`** | When **`webScopeTemplates` is not set**, optional **Handlebars** string to produce the search `question` from that context plus `input` (full task input). |
|
|
137
|
-
| **`webScopeQuestions`** | When **`webScopeTemplates` is not set**, optional list of explicit scope questions. Non-empty after trim → **`scopeQuestionPack`** with `WebScopeQuestion[]` (`id` generated when omitted). Shape: `Array<{ id?: string; question: string; source?: "manual" \| "ai-driven" }>`. |
|
|
138
|
-
| **`webScoping`** | Optional slice of **`WebScoperConfig.scoping`** from `@exellix/narrix-web-scoper` (snippets, caps, raw content, `maxQueries`, `freshnessDays`, etc.). When non-empty, ai-tasks builds a scoper for that request with `createWebScoper({ enabled: true, searchAdapter, scoping: narrix.webScoping })` so behavior matches upstream docs. Omit or leave empty to use the package default scoper (backward compatible). |
|
|
139
|
-
|
|
140
|
-
**Precedence:**
|
|
141
|
-
|
|
142
|
-
1. If **`webScopeTemplates`** is set (after trimming empty entries) → scoper receives **`webScopeTemplates`** + merged **`webScopeObjects`** only (no `question` / **`webScopeQuestions`** from this resolver).
|
|
143
|
-
2. Else if **`webScopeQuestions`** is non-empty after normalization → **`runWebScopeQuestionPack`** with **`questions`** only (no single **`question`** / Handlebars path).
|
|
144
|
-
3. Else if **`webScopeQuestionTemplate`** is set → **`question`** = Handlebars render; on template error, fall back to default enrichment.
|
|
145
|
-
4. Else → **`question`** = `input.question` (or string `input`) **plus** appended **CVE / vendor / product** tokens from context when those tokens are **not** already contained in the base question (case-insensitive).
|
|
146
|
-
|
|
147
|
-
When there is no base question and no enrichable facts, **`question`** may be omitted (empty resolver result).
|
|
148
|
-
|
|
149
|
-
Conceptually, the call looks like:
|
|
39
|
+
### 2.2. Question pack
|
|
150
40
|
|
|
151
41
|
```ts
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const scopeFields = resolveWebScopeQuestionAndTemplates({
|
|
157
|
-
narrix: narrixConfig,
|
|
158
|
-
requestInput: request.input,
|
|
159
|
-
successResult,
|
|
160
|
-
entity: /* record medium only */,
|
|
42
|
+
await scoper.searchMany({
|
|
43
|
+
questions: [{ id: "q1", question: "Patch status?" }, { id: "q2", question: "Workarounds?" }],
|
|
44
|
+
record?: { /* shared facts */ },
|
|
45
|
+
options?: { maxQueries?: 2 },
|
|
161
46
|
});
|
|
162
|
-
|
|
163
|
-
const base = {
|
|
164
|
-
datasetId: narrixConfig.datasetId,
|
|
165
|
-
subjectId: successResult.entity.entityKey,
|
|
166
|
-
entityKind: successResult.entity.entityKind,
|
|
167
|
-
entity: /* record */,
|
|
168
|
-
cni: successResult.cni,
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const webResult: WebScoperResult = scopeFields.packQuestions?.length
|
|
172
|
-
? await runWebScopeQuestionPack({ ...base, questions: scopeFields.packQuestions })
|
|
173
|
-
: await runWebScope({ ...base, ...scopeFields } as ScopeInput);
|
|
174
|
-
|
|
175
|
-
ctx.executionMemory.webContext = webResult;
|
|
47
|
+
// → WebScopePackResult with results + pack.scopes
|
|
176
48
|
```
|
|
177
49
|
|
|
178
|
-
|
|
50
|
+
### 2.3. WebContext shape
|
|
51
|
+
|
|
52
|
+
- **`context.findings[]`**, **`context.sources[]`** (each source requires **`retrievalStage`**: `"discovered" | "fetched" | "extracted"`).
|
|
53
|
+
- **`context.meta`**: `queriesUsed`, `retrievedAt`, `sourceCount`, `evidenceCount`, **`discoveredCount`**, optional intent/strategy/shape.
|
|
179
54
|
|
|
180
55
|
---
|
|
181
56
|
|
|
182
|
-
##
|
|
57
|
+
## 3. How ai-tasks compiles the payload
|
|
183
58
|
|
|
184
|
-
|
|
59
|
+
Implementation: **`src/web-scope/buildSearchInput.ts`**, **`src/web-scope/renderWebQueryTemplate.ts`**, **`src/web-scope/applyWebScopeToRequest.ts`**, **`src/web-scope/client.ts`**.
|
|
185
60
|
|
|
186
|
-
|
|
61
|
+
### 3.1. Query resolution — rendered template only
|
|
187
62
|
|
|
188
|
-
|
|
189
|
-
- Allows tests to **inject** a fake scoper via `setWebScoperForTesting`.
|
|
190
|
-
- Normalizes failures into a consistent `WebScoperResult`.
|
|
63
|
+
The search query is the **rendered `unitParams.webQueryTemplate`**. There is **no** fallback to `input.question`, `taskVariable.question`, or `executionMemory.taskVariables.question`.
|
|
191
64
|
|
|
192
|
-
|
|
65
|
+
1. `webScopeInvokeConfigFromUnitParams(unitParams)` reads `webQueryTemplate` (single) and/or `webQueryTemplates` (pack).
|
|
66
|
+
2. `renderWebQueryTemplate(template, request)` renders it with `@x12i/rendrix` `render()` against `buildTemplateContext(request)` — the same roots used by validation (`input`, `jobVariables`, `taskVariables`, `executionMemory`, …).
|
|
67
|
+
3. An empty render (e.g. a template that is only an unresolved token) yields no query → `{ ok: false, error: { reason: "no_queries" } }`.
|
|
193
68
|
|
|
194
|
-
|
|
195
|
-
- When the injected scoper returns `{ available: true, context, cached: false }`,
|
|
196
|
-
- `runWebScope` forwards that as-is, and tests assert:
|
|
69
|
+
### 3.2. Record resolution
|
|
197
70
|
|
|
198
|
-
|
|
199
|
-
assert.strictEqual(result.available, true);
|
|
200
|
-
assert.deepStrictEqual(result.context, webContext);
|
|
201
|
-
```
|
|
71
|
+
Merged from (when present):
|
|
202
72
|
|
|
203
|
-
-
|
|
204
|
-
|
|
205
|
-
|
|
73
|
+
- `input.record` or fields on object `input`
|
|
74
|
+
- `executionMemory.input` / `executionMemory.input.raw`
|
|
75
|
+
- CNI `knownFacts` (when facts are passed into the web-scope hop)
|
|
206
76
|
|
|
207
|
-
|
|
208
|
-
assert.strictEqual(result.available, false);
|
|
209
|
-
assert.strictEqual(result.reason, "notEligible");
|
|
210
|
-
```
|
|
77
|
+
The record carries **facts only** — the query comes from the template, which references those facts via `{{input.*}}`.
|
|
211
78
|
|
|
212
|
-
|
|
213
|
-
- When the scoper throws (e.g. network error, adapter unavailable),
|
|
214
|
-
- `runWebScope` **catches** the error and returns:
|
|
79
|
+
### 3.3. Options
|
|
215
80
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
81
|
+
| Source | Maps to |
|
|
82
|
+
|--------|---------|
|
|
83
|
+
| `unitParams.options` | `WebScopeOptions` (`maxQueries`, `freshnessDays`, domain filters, `queryTemplates`, …) |
|
|
219
84
|
|
|
220
|
-
|
|
85
|
+
There are no legacy `webScoping` / `webScopeOptions` / `webScopeQuestions` mappings and no NARRIX option sources.
|
|
221
86
|
|
|
222
|
-
|
|
223
|
-
assert.strictEqual(result.available, false);
|
|
224
|
-
assert.strictEqual(result.reason, "error");
|
|
225
|
-
assert.ok(result.error?.includes("search timed out"));
|
|
226
|
-
```
|
|
87
|
+
### 3.4. Pack mode
|
|
227
88
|
|
|
228
|
-
|
|
89
|
+
When `unitParams.webQueryTemplates` is a non-empty `string[]`, each template is rendered independently (`renderWebQueryTemplates`) into a `searchMany` question pack (UUID ids assigned per question). Otherwise a single `search` runs with the rendered `webQueryTemplate`.
|
|
229
90
|
|
|
230
|
-
|
|
91
|
+
### 3.5. The web-scope unit
|
|
231
92
|
|
|
232
|
-
|
|
233
|
-
// Hit
|
|
234
|
-
{
|
|
235
|
-
available: true;
|
|
236
|
-
context: WebContext; // rich object with findings, queriesUsed, sources, timestamps, ...
|
|
237
|
-
cached: boolean;
|
|
238
|
-
}
|
|
93
|
+
Graphenix / playground unit:
|
|
239
94
|
|
|
240
|
-
|
|
95
|
+
```json
|
|
241
96
|
{
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
97
|
+
"unitKind": "externalPreUtility",
|
|
98
|
+
"strategyKey": "webScope",
|
|
99
|
+
"unitParams": {
|
|
100
|
+
"enableWebScope": true,
|
|
101
|
+
"webQueryTemplate": "How to solve {{input.vulnerability}}?",
|
|
102
|
+
"options": { "maxQueries": 3 }
|
|
103
|
+
}
|
|
245
104
|
}
|
|
246
105
|
```
|
|
247
106
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
### 4.3. Source bodies and snippets (`WebSource`)
|
|
251
|
-
|
|
252
|
-
Upstream behavior is implemented in **`@exellix/narrix-web-scoper`** (and Tavily field mapping in **`@exellix/search-adapter`**). ai-tasks does not map provider JSON; it forwards **`RunTaskRequest.narrix.webScoping`** into the scoper factory when set. Field names and semantics follow the **`@exellix/narrix-web-scoper` README** (current releases use first-class **`providerContent`** / **`providerRawContent`**; **`content`** / **`rawContent`** are legacy mirrors for the same roles).
|
|
253
|
-
|
|
254
|
-
When **`webScoping.includeSourceSnippets`** is **`true`**, each `WebContext.sources[]` entry may include:
|
|
255
|
-
|
|
256
|
-
- **`providerContent`** / **`providerRawContent`**: bounded excerpt and optional raw payload from the adapter (when requested).
|
|
257
|
-
- **`content`** / **`rawContent`**: deprecated mirrors of **`providerContent`** / **`providerRawContent`**.
|
|
258
|
-
- **`snippet`**: primary excerpt for the source, chosen via **`webScoping.sourceExcerptFrom`** (default **`providerContent`**, or **`providerRawContent`**, with deprecated aliases **`content`** / **`rawContent`**).
|
|
259
|
-
- **`snippetCharCount`**, **`contentOrigin`**, **`retrievalStage`**, **`contentSource`**, **`score`** / **`rank`**: provenance and metadata when the adapter supplies them (see web-scoper README).
|
|
260
|
-
|
|
261
|
-
Defaults are backward compatible: **`includeSourceSnippets` defaults to false**, so these fields are omitted unless you opt in (via **`narrix.webScoping`** or the scoper’s own defaults when extended).
|
|
262
|
-
|
|
263
|
-
Optional caps (only apply when snippets are enabled):
|
|
264
|
-
|
|
265
|
-
- **`maxSnippetCharsPerSource`**: Unicode cap applied per source to **`providerContent`**, **`providerRawContent`** (and legacy mirrors), and the text chosen for **`snippet`**. When set to a positive number, it is also forwarded as **`snippetMaxChars`** on the shared search request so the adapter can normalize earlier.
|
|
266
|
-
- **`maxTotalWebContextChars`**: additional budget applied **only** to **`WebSource.snippet`** across sources (after each snippet’s per-source cap). It does **not** shrink stored **`providerContent`** / **`providerRawContent`**.
|
|
267
|
-
|
|
268
|
-
To request raw body text from the provider, set **`webScoping.snippetIncludeRawContent`** (e.g. **`true`** or **`"markdown"`**); it is forwarded as **`includeRawContent`** on search requests. Use **`@exellix/search-adapter`** and **`@exellix/narrix-web-scoper`** versions from the same release family as this repo’s dependencies.
|
|
269
|
-
|
|
270
|
-
Example:
|
|
271
|
-
|
|
272
|
-
```ts
|
|
273
|
-
narrix: {
|
|
274
|
-
datasetId: "network.vuln.instances",
|
|
275
|
-
enableWebScope: true,
|
|
276
|
-
webScoping: {
|
|
277
|
-
includeSourceSnippets: true,
|
|
278
|
-
maxQueries: 2,
|
|
279
|
-
maxSnippetCharsPerSource: 4000,
|
|
280
|
-
snippetIncludeRawContent: false,
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
## 5. How `executionMemory` is affected
|
|
288
|
-
|
|
289
|
-
### 5.1. Baseline (without web scoping)
|
|
290
|
-
|
|
291
|
-
Without web scoping, for a NARRIX task, `executionMemory` will generally contain:
|
|
292
|
-
|
|
293
|
-
- `executionMemory._narrix` — NARRIX run result (entity, signals, stories, passes, meta, etc.).
|
|
294
|
-
- Any initial `executionMemory` provided by the caller (e.g. `executionMemory.input.raw` for raw records).
|
|
295
|
-
|
|
296
|
-
`executionMemory.webContext` is **undefined** and should not be relied on.
|
|
297
|
-
|
|
298
|
-
### 5.2. With `enableWebScope: true`
|
|
299
|
-
|
|
300
|
-
When `enableWebScope` is true:
|
|
107
|
+
Playground input (record/facts only — referenced by the template):
|
|
301
108
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
even when the scoper returns a miss or throws an error.
|
|
309
|
-
|
|
310
|
-
- **Never removed / mutated**:
|
|
311
|
-
- `_narrix` (or the configured attachment field) is **still present and unchanged**, even when web scoping fails.
|
|
312
|
-
- Tests explicitly assert that `_narrix` remains present in the error path.
|
|
313
|
-
|
|
314
|
-
Key behaviors from `test/narrix/webScoper.test.ts`:
|
|
315
|
-
|
|
316
|
-
- When scoper succeeds:
|
|
317
|
-
- `webContext.available === true`
|
|
318
|
-
- `_narrix` is still present.
|
|
319
|
-
- When scoper fails:
|
|
320
|
-
- `_narrix` is **still present**.
|
|
321
|
-
- `webContext` exists with `available === false` and `reason === "error"`.
|
|
322
|
-
|
|
323
|
-
### 5.3. Question forwarding and enrichment
|
|
324
|
-
|
|
325
|
-
When the caller passes a **natural-language question** in `RunTaskRequest.input.question`, the NARRIX pre-processor derives **`ScopeInput.question`** via **`resolveWebScopeQuestionAndTemplates`** (see §3.2.1): the base string is usually that field, **optionally extended** with CVE / vendor / product from CNI `knownFacts` or common `entity.graphized` paths when those tokens are not already in the question. With **`narrix.webScopeTemplates`**, the scoper uses template-driven queries instead and **`question`** may be omitted.
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
await runTask({
|
|
329
|
-
skillKey: "skills/skill.local:webScopeTestQuestion",
|
|
330
|
-
narrix: { datasetId: "test.fixture", enableWebScope: true },
|
|
331
|
-
executionMemory: { input: { raw: { id: "v3" } } },
|
|
332
|
-
input: { question: "Is this vulnerability critical?" },
|
|
333
|
-
});
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"vulnerability": "CVE-2021-44228",
|
|
112
|
+
"vendor": "apache"
|
|
113
|
+
}
|
|
334
114
|
```
|
|
335
115
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
This allows the scoper to tailor its search and context building to the actual question the LLM or downstream logic is trying to answer, with **entity-specific tokens** when available.
|
|
116
|
+
`enableWebScope` (default `true`) is the on/off switch. When `false`, the unit is a no-op.
|
|
339
117
|
|
|
340
118
|
---
|
|
341
119
|
|
|
342
|
-
##
|
|
120
|
+
## 4. NARRIX (no longer triggers web scope)
|
|
343
121
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
The web scoper uses `@exellix/search-adapter` backed by Tavily. It requires:
|
|
347
|
-
|
|
348
|
-
- **`TAVILY_API_KEY`** — the API key for Tavily search.
|
|
349
|
-
|
|
350
|
-
Behavior:
|
|
351
|
-
|
|
352
|
-
- If `TAVILY_API_KEY` is **missing or invalid**:
|
|
353
|
-
- The scoper returns `available: false` with an appropriate `reason` (e.g. `"error"`).
|
|
354
|
-
- ai-tasks surfaces this as `executionMemory.webContext` with `available: false`.
|
|
355
|
-
- The task **continues** normally using NARRIX output only; `_narrix` is still present.
|
|
356
|
-
|
|
357
|
-
### 6.2. Other relevant flags
|
|
358
|
-
|
|
359
|
-
- `USE_NARRIX_INGEST`:
|
|
360
|
-
- When `"1"`, NARRIX ingest + runner are enabled and web scoping is meaningful.
|
|
361
|
-
- When not set, NARRIX-related flows (including web scoping) may be skipped or disabled in tests/playgrounds.
|
|
362
|
-
|
|
363
|
-
Optional per-request **`narrix.webScoping`** forwards snippet/cap/raw-content and query limits into `@exellix/narrix-web-scoper` (see §4.3). The main on/off switch remains **`enableWebScope`**.
|
|
122
|
+
Web scoping is **fully decoupled from NARRIX**. The NARRIX preprocessor/handler still builds its CNI attachment (`executionMemory._narrix` or `attachToField`), but it does **not** trigger or configure web search. To web-scope after NARRIX, add an explicit `webScope` unit to the node plan with its own `webQueryTemplate`.
|
|
364
123
|
|
|
365
124
|
---
|
|
366
125
|
|
|
367
|
-
##
|
|
368
|
-
|
|
369
|
-
Web scoping is explicitly designed to **never crash the task**:
|
|
126
|
+
## 5. Environment
|
|
370
127
|
|
|
371
|
-
-
|
|
372
|
-
- The task SDK:
|
|
373
|
-
- Continues to attach `_narrix` as usual.
|
|
374
|
-
- Stores a structured error in `executionMemory.webContext` for debugging.
|
|
128
|
+
- **`TAVILY_API_KEY`** — required for live search. When missing, `webContext.ok === false` with an appropriate error; the task continues.
|
|
375
129
|
|
|
376
|
-
|
|
130
|
+
Optional:
|
|
377
131
|
|
|
378
|
-
-
|
|
379
|
-
- `webContext.available === false`
|
|
380
|
-
- `webContext.reason === "error"`
|
|
381
|
-
- `webContext.error` contains a human-readable message.
|
|
382
|
-
- Freedom to treat web scoping as an **optional enhancement** while still observing its behavior in production.
|
|
132
|
+
- **`WEB_CONTEXT_MARKDOWN_MAX_CHARS`** — caps markdown built from web hits for LLM context (`src/narrix/webContextMarkdown.ts`).
|
|
383
133
|
|
|
384
134
|
---
|
|
385
135
|
|
|
386
|
-
##
|
|
387
|
-
|
|
388
|
-
From the perspective of a **local task handler**, web scoping is just another field on `ctx.executionMemory`:
|
|
136
|
+
## 6. Consuming `webContext` in tasks
|
|
389
137
|
|
|
390
138
|
```ts
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
webContext?: WebScoperResult;
|
|
396
|
-
_narrix?: unknown;
|
|
397
|
-
// ...
|
|
398
|
-
};
|
|
399
|
-
// ...other context fields...
|
|
400
|
-
};
|
|
401
|
-
}) => Promise<any>;
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### 8.1. Recommended consumption pattern
|
|
405
|
-
|
|
406
|
-
1. **Check for presence**:
|
|
407
|
-
|
|
408
|
-
```ts
|
|
409
|
-
const webContext = ctx.executionMemory?.webContext;
|
|
410
|
-
if (!webContext) {
|
|
411
|
-
// web scoping was not enabled for this task
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
2. **Branch on `available`**:
|
|
416
|
-
|
|
417
|
-
```ts
|
|
418
|
-
if (!webContext.available) {
|
|
419
|
-
// Option A: log / record reason and proceed without web data
|
|
420
|
-
// Option B: degrade gracefully (e.g. fallback to CNI-only reasoning)
|
|
421
|
-
} else {
|
|
422
|
-
// Safe to use webContext.context to enrich reasoning
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
3. **Do not rely on web scoping for correctness**:
|
|
427
|
-
- Handlers should behave sensibly even when `webContext` is absent or `available === false`.
|
|
428
|
-
- Web scoping is an **augmentation**, not a hard dependency.
|
|
429
|
-
|
|
430
|
-
### 8.2. Example usage (pseudocode)
|
|
431
|
-
|
|
432
|
-
```ts
|
|
433
|
-
registerLocalTask("skills/skill.local:example", async ({ input, ctx }) => {
|
|
434
|
-
const narrix = ctx.executionMemory?._narrix;
|
|
435
|
-
const web = ctx.executionMemory?.webContext;
|
|
436
|
-
|
|
437
|
-
if (web?.available) {
|
|
438
|
-
// Combine NARRIX narrative with fresh web evidence
|
|
439
|
-
return buildExplanationWithWeb(narrix, web.context);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Fallback: only NARRIX narrative
|
|
443
|
-
return buildExplanationFromNarrixOnly(narrix);
|
|
444
|
-
});
|
|
139
|
+
const web = ctx.executionMemory?.webContext;
|
|
140
|
+
if (web && "ok" in web && web.ok === true && web.context) {
|
|
141
|
+
// use web.context.sources, findings, summary
|
|
142
|
+
}
|
|
445
143
|
```
|
|
446
144
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
For skills executed through the task SDK with **`includeContextInPrompt: true`**, when NARRIX is in play ai-tasks appends a **Web sources (primary evidence)** markdown section derived from **`executionMemory.webContext`** (when **`available === true`**), using per-source **`providerRawContent`** → **`rawContent`** → **`providerContent`** → **`content`** → **`snippet`**, and labeling **`summary`** / **`findings`** as hints only. The same markdown is merged into source material for the **`synthesized-context`** PRE step under **`narrix-only`** / **`narrix+memory`** (with **`executionMemory.webContext`** stripped from the JSON memory slice when **`narrix+memory`** to avoid duplication). Implementation: **`src/narrix/webContextMarkdown.ts`**. Optional env **`WEB_CONTEXT_MARKDOWN_MAX_CHARS`** caps the size of that markdown string.
|
|
145
|
+
For **`includeContextInPrompt`** / synthesis PRE, ai-tasks builds **Web sources (primary evidence)** markdown when `ok === true`, preferring source `snippet` / `title`. Raw `webContext` JSON is omitted from synthesized memory slices when markdown is included (see `resolveSourceMaterial` tests). Always check **`ok`** on `WebScopeResult` / `WebScopePackResult`.
|
|
450
146
|
|
|
451
147
|
---
|
|
452
148
|
|
|
453
|
-
##
|
|
454
|
-
|
|
455
|
-
ai-tasks contains tests that exercise both **unit-level** and **integration-level** web scoping behavior:
|
|
456
|
-
|
|
457
|
-
- `test/narrix/webScoper.test.ts`:
|
|
458
|
-
- Unit-tests **`buildWebScopeTemplateContext`** / **`resolveWebScopeQuestionAndTemplates`** (question enrichment, Handlebars template, `webScopeTemplates` precedence).
|
|
459
|
-
- Unit-tests `runWebScope` with mocked `NarrixWebScoper`.
|
|
460
|
-
- Verifies:
|
|
461
|
-
- Pass-through of `available: true` and `context`.
|
|
462
|
-
- Stable miss handling (`available: false`, specific `reason`).
|
|
463
|
-
- Error → `available: false`, `reason: "error"`, populated `error`.
|
|
464
|
-
- Singleton reset behavior (`resetWebScoperSingleton`, `setWebScoperForTesting`).
|
|
465
|
-
- Integration with `runTask`:
|
|
466
|
-
- When `enableWebScope` is **absent**:
|
|
467
|
-
- `executionMemory.webContext` remains `undefined`.
|
|
468
|
-
- When `enableWebScope === true` and scoper returns success:
|
|
469
|
-
- `executionMemory.webContext.available === true`.
|
|
470
|
-
- `_narrix` is still present.
|
|
471
|
-
- When scoper throws:
|
|
472
|
-
- `_narrix` is still present.
|
|
473
|
-
- `webContext.available === false`, `webContext.reason === "error"`.
|
|
474
|
-
- When a question is provided (and `webScopeTemplates` is not set):
|
|
475
|
-
- `ScopeInput.question` equals `request.input.question` when there are no extra CNI/entity tokens to append; otherwise it is the **enriched** string (see §3.2.1).
|
|
476
|
-
- When `webScopeTemplates` is set:
|
|
477
|
-
- `ScopeInput.webScopeTemplates` / `webScopeObjects` are passed through as configured (merged with auto-built context).
|
|
478
|
-
|
|
479
|
-
These tests define the **public contract** of web scoping within ai-tasks: any change that breaks their assertions is a breaking change to web scoping behavior.
|
|
149
|
+
## 7. Testing
|
|
480
150
|
|
|
481
|
-
|
|
151
|
+
- **`test/web-scope/buildSearchInput.test.ts`** — template rendering, payload compilation, client error handling, `applyWebScopeToRequest`
|
|
152
|
+
- **`test/validation/validateWebScopeUnit.test.ts`** — required `webQueryTemplate` and token resolution checks
|
|
153
|
+
- **`test/narrix/webContextMarkdown.test.ts`** — markdown from `{ ok, context }`
|
|
154
|
+
- **`test/synthesis/resolveSourceMaterial.test.ts`** — web evidence in source material
|
|
155
|
+
- **`test/utils/collectEvidence.test.ts`** — local handler uses web scoper for query discovery
|
|
482
156
|
|
|
483
|
-
|
|
157
|
+
Run targeted tests:
|
|
484
158
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
- NARRIX → success result (`_narrix`) → web scoper via `ScopeInput` → `executionMemory.webContext`.
|
|
489
|
-
- **Consumer surface**:
|
|
490
|
-
- Local tasks read `ctx.executionMemory.webContext` and `_narrix`.
|
|
491
|
-
- **Failure behavior**:
|
|
492
|
-
- Web scoping is **non-fatal**.
|
|
493
|
-
- `_narrix` is always attached on success, independent of web scoping.
|
|
494
|
-
- `webContext` is always present when enabled, with `available` + `reason`/`error` for observability.
|
|
495
|
-
- **Config**:
|
|
496
|
-
- Controlled by per-request `enableWebScope`, optional `webScopeTemplates` / `webScopeObjects` / `webScopeQuestionTemplate` / **`webScoping`** on `narrix`, and `TAVILY_API_KEY` env.
|
|
497
|
-
|
|
498
|
-
With this, integrators should have enough detail to:
|
|
499
|
-
|
|
500
|
-
- Correctly enable web scoping from graphs / callers.
|
|
501
|
-
- Reliably consume `executionMemory.webContext` in local tasks.
|
|
502
|
-
- Understand and debug web scoping behavior in logs and execution memory without diving into the entire codebase.
|
|
159
|
+
```bash
|
|
160
|
+
cd ai-tasks && npm run build && npx tsc -p tsconfig.test.json && node --test dist-test/test/web-scope/buildSearchInput.test.js dist-test/test/validation/validateWebScopeUnit.test.js
|
|
161
|
+
```
|
|
503
162
|
|
|
163
|
+
Live Tavily: **`npm run test:e2e:webScope`** (requires `TAVILY_API_KEY`).
|