agent-nuvira 3.3.12 → 3.3.13
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/dist/agents/agents/reasoner.d.ts.map +1 -1
- package/dist/agents/agents/reasoner.js +13 -0
- package/dist/agents/agents/reasoner.js.map +1 -1
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +29 -9
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +34 -7
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts.map +1 -1
- package/dist/cli/cli-program.js +8 -0
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +21 -3
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +6 -0
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/knowledge.d.ts +23 -0
- package/dist/cli/knowledge.d.ts.map +1 -0
- package/dist/cli/knowledge.js +132 -0
- package/dist/cli/knowledge.js.map +1 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +45 -6
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/omniroute-control.d.ts +88 -0
- package/dist/cli/omniroute-control.d.ts.map +1 -0
- package/dist/cli/omniroute-control.js +179 -0
- package/dist/cli/omniroute-control.js.map +1 -0
- package/dist/cli/omniroute.d.ts +21 -0
- package/dist/cli/omniroute.d.ts.map +1 -0
- package/dist/cli/omniroute.js +67 -0
- package/dist/cli/omniroute.js.map +1 -0
- package/dist/config/types.d.ts +8 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context/history.d.ts +21 -0
- package/dist/context/history.d.ts.map +1 -1
- package/dist/context/history.js +50 -0
- package/dist/context/history.js.map +1 -1
- package/dist/gateway/hook-contract.d.ts +173 -0
- package/dist/gateway/hook-contract.d.ts.map +1 -0
- package/dist/gateway/hook-contract.js +352 -0
- package/dist/gateway/hook-contract.js.map +1 -0
- package/dist/gateway/hooks.d.ts.map +1 -1
- package/dist/gateway/hooks.js +14 -0
- package/dist/gateway/hooks.js.map +1 -1
- package/dist/inference/interface.d.ts +17 -0
- package/dist/inference/interface.d.ts.map +1 -1
- package/dist/inference/model-id-validation.d.ts +57 -0
- package/dist/inference/model-id-validation.d.ts.map +1 -0
- package/dist/inference/model-id-validation.js +127 -0
- package/dist/inference/model-id-validation.js.map +1 -0
- package/dist/inference/openai-compat-adapter.d.ts.map +1 -1
- package/dist/inference/openai-compat-adapter.js +12 -1
- package/dist/inference/openai-compat-adapter.js.map +1 -1
- package/dist/inference/provider-catalog.d.ts +11 -0
- package/dist/inference/provider-catalog.d.ts.map +1 -1
- package/dist/inference/provider-catalog.js +80 -0
- package/dist/inference/provider-catalog.js.map +1 -1
- package/dist/inference/route-resolver.d.ts +2 -8
- package/dist/inference/route-resolver.d.ts.map +1 -1
- package/dist/inference/route-resolver.js +17 -0
- package/dist/inference/route-resolver.js.map +1 -1
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +10 -8
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/inference/tools.d.ts +1 -0
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +20 -3
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/auto-router.d.ts +53 -0
- package/dist/learning/auto-router.d.ts.map +1 -1
- package/dist/learning/auto-router.js +73 -0
- package/dist/learning/auto-router.js.map +1 -1
- package/dist/learning/error-repair.d.ts +23 -1
- package/dist/learning/error-repair.d.ts.map +1 -1
- package/dist/learning/error-repair.js +58 -0
- package/dist/learning/error-repair.js.map +1 -1
- package/dist/learning/knowledge-base.d.ts +124 -0
- package/dist/learning/knowledge-base.d.ts.map +1 -0
- package/dist/learning/knowledge-base.js +337 -0
- package/dist/learning/knowledge-base.js.map +1 -0
- package/dist/learning/model-selection.d.ts +2 -1
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +35 -2
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/project-docs.d.ts +83 -0
- package/dist/learning/project-docs.d.ts.map +1 -0
- package/dist/learning/project-docs.js +132 -0
- package/dist/learning/project-docs.js.map +1 -0
- package/dist/learning/quota-ledger.d.ts +13 -0
- package/dist/learning/quota-ledger.d.ts.map +1 -1
- package/dist/learning/quota-ledger.js +28 -0
- package/dist/learning/quota-ledger.js.map +1 -1
- package/dist/learning/seeded-benchmark.d.ts +14 -0
- package/dist/learning/seeded-benchmark.d.ts.map +1 -1
- package/dist/learning/seeded-benchmark.js +43 -4
- package/dist/learning/seeded-benchmark.js.map +1 -1
- package/dist/security/secret-scan.d.ts +156 -0
- package/dist/security/secret-scan.d.ts.map +1 -0
- package/dist/security/secret-scan.js +525 -0
- package/dist/security/secret-scan.js.map +1 -0
- package/dist/tools/plan-store.d.ts +24 -2
- package/dist/tools/plan-store.d.ts.map +1 -1
- package/dist/tools/plan-store.js +42 -2
- package/dist/tools/plan-store.js.map +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +149 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/remediation-ladder.d.ts +91 -0
- package/dist/tools/remediation-ladder.d.ts.map +1 -0
- package/dist/tools/remediation-ladder.js +308 -0
- package/dist/tools/remediation-ladder.js.map +1 -0
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +26 -2
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/skills-hub.d.ts +7 -0
- package/dist/tools/skills-hub.d.ts.map +1 -1
- package/dist/tools/skills-hub.js +11 -2
- package/dist/tools/skills-hub.js.map +1 -1
- package/dist/tools/step-artifact.d.ts +35 -0
- package/dist/tools/step-artifact.d.ts.map +1 -0
- package/dist/tools/step-artifact.js +154 -0
- package/dist/tools/step-artifact.js.map +1 -0
- package/dist/tools/tool-loop.d.ts +6 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +27 -3
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/toolsets.js +4 -4
- package/dist/tools/toolsets.js.map +1 -1
- package/dist/tools/worktree.d.ts +11 -2
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +11 -2
- package/dist/tools/worktree.js.map +1 -1
- package/dist/web-dashboard/server.d.ts +29 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +372 -5
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +66 -0
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.d.ts +7 -0
- package/dist/web-dashboard/workspace-guard.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.js +70 -0
- package/dist/web-dashboard/workspace-guard.js.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js +210 -0
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js.map +1 -0
- package/src/web-dashboard/public/assets/index-tK8Y2qHB.css +1 -0
- package/src/web-dashboard/public/index.html +2 -2
- package/src/web-dashboard/public/assets/index-BrZcYhy6.js +0 -207
- package/src/web-dashboard/public/assets/index-BrZcYhy6.js.map +0 -1
- package/src/web-dashboard/public/assets/index-DsWczTa6.css +0 -1
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KnowledgeBase — tag-scoped, vectorized retrieval over a user's own documents.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. The retrieval engine (`src/learning/retrieval.ts`) vectorizes
|
|
5
|
+
* a REPO for token reduction and keys everything by file path; the tagged memory
|
|
6
|
+
* store (`src/tools/memory-tools.ts`) holds FACTS, not whole documents. Neither
|
|
7
|
+
* answers "I brought my documents, gave them a tag, and I want precise answers
|
|
8
|
+
* scoped to that tag." So a user asking about their own data had exactly one
|
|
9
|
+
* path — re-read the file into context on EVERY turn, which costs the document's
|
|
10
|
+
* tokens repeatedly and is slow on large files.
|
|
11
|
+
*
|
|
12
|
+
* This module pays that cost ONCE. A document is extracted, chunked and embedded
|
|
13
|
+
* a single time under a tag; each later question embeds a short query and
|
|
14
|
+
* retrieves its top-k chunks. The tag is a real scope: each tag gets its own
|
|
15
|
+
* vector namespace (`knowledge-<tag>`), so tags never bleed into each other and
|
|
16
|
+
* a tag can be forgotten without touching anything else.
|
|
17
|
+
*
|
|
18
|
+
* The retrieved chunks are USER DATA; the model supplies the generic half of an
|
|
19
|
+
* answer (and `web-research` supplies the net-based half). `formatKnowledgeContext`
|
|
20
|
+
* labels each chunk with its source file so the model can attribute precisely
|
|
21
|
+
* which part of an answer came from the user's data.
|
|
22
|
+
*
|
|
23
|
+
* Storage: vectors in the existing pluggable VectorStore (one JSON/FAISS file
|
|
24
|
+
* per namespace), a small manifest at `<memory>/knowledge-index.json` for
|
|
25
|
+
* listing/removal. Everything lives in the Nuvira data dir (`~/.nuvira/memory`),
|
|
26
|
+
* never in a repository or package.
|
|
27
|
+
*/
|
|
28
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
29
|
+
import { join, extname, basename } from 'node:path';
|
|
30
|
+
import { envBuff, resolveNuviraHome } from '../config/paths.js';
|
|
31
|
+
import { embed, RETRIEVAL_MODEL } from '../memory/embedder.js';
|
|
32
|
+
import { getVectorStore } from '../memory/vector-store.js';
|
|
33
|
+
import { chunkText, DEFAULT_CHUNK_TOKENS, DEFAULT_OVERLAP_TOKENS } from './retrieval.js';
|
|
34
|
+
import { logger } from '../utils/logger.js';
|
|
35
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
36
|
+
/** A tag is a sandboxed namespace segment: lowercase alphanumerics + hyphens, with at least one alphanumeric. */
|
|
37
|
+
export const KNOWLEDGE_TAG_RE = /^[a-z0-9-]*[a-z0-9][a-z0-9-]*$/;
|
|
38
|
+
/** Namespace prefix — keeps knowledge vectors apart from memory/history/repo. */
|
|
39
|
+
export const KNOWLEDGE_NAMESPACE_PREFIX = 'knowledge-';
|
|
40
|
+
/** Manifest of tags → documents (listing/removal only; vectors live elsewhere). */
|
|
41
|
+
export const KNOWLEDGE_MANIFEST_FILE = 'knowledge-index.json';
|
|
42
|
+
/** Default chunks returned per query. */
|
|
43
|
+
export const DEFAULT_KNOWLEDGE_TOP_K = 6;
|
|
44
|
+
/** Directories never walked when a tag is pointed at a folder. */
|
|
45
|
+
const IGNORE_DIRS = new Set([
|
|
46
|
+
'node_modules', '.git', 'dist', 'build', '.next', '.cache', '.venv', 'venv',
|
|
47
|
+
'__pycache__', '.turbo', '.nx', 'coverage', '.idea', '.vscode',
|
|
48
|
+
]);
|
|
49
|
+
/** Cap a directory walk so a stray `.` cannot index an entire disk. */
|
|
50
|
+
const MAX_FILES_PER_INGEST = 500;
|
|
51
|
+
/** Per-chunk text kept in metadata (matches retrieval.ts's budget). */
|
|
52
|
+
const MAX_EXTRACT_CHARS = 2_000_000;
|
|
53
|
+
// ─── Paths (resolved per call so tests that set NUVIRA_MEMORY_DIR are hermetic) ──
|
|
54
|
+
function memoryDir() {
|
|
55
|
+
return envBuff('MEMORY_DIR') || join(resolveNuviraHome(), 'memory');
|
|
56
|
+
}
|
|
57
|
+
function manifestPath() {
|
|
58
|
+
return join(memoryDir(), KNOWLEDGE_MANIFEST_FILE);
|
|
59
|
+
}
|
|
60
|
+
// ─── Tag handling ───────────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Normalize a user-supplied tag into the sandboxed form. `Dheeraj_Health_report`
|
|
63
|
+
* → `dheeraj-health-report`. This is deliberately forgiving: a human naming a
|
|
64
|
+
* tag should not have to know the namespace rules, and a tag is not a path.
|
|
65
|
+
*/
|
|
66
|
+
export function normalizeKnowledgeTag(tag) {
|
|
67
|
+
return tag
|
|
68
|
+
.trim()
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
71
|
+
.replace(/^-+|-+$/g, '')
|
|
72
|
+
.replace(/-{2,}/g, '-');
|
|
73
|
+
}
|
|
74
|
+
/** True when a (already-normalized) tag is valid and non-empty. */
|
|
75
|
+
export function isValidKnowledgeTag(tag) {
|
|
76
|
+
return KNOWLEDGE_TAG_RE.test(tag);
|
|
77
|
+
}
|
|
78
|
+
/** The VectorStore namespace for a tag. Assumes a normalized tag. */
|
|
79
|
+
export function namespaceForTag(tag) {
|
|
80
|
+
return `${KNOWLEDGE_NAMESPACE_PREFIX}${tag}`;
|
|
81
|
+
}
|
|
82
|
+
// ─── Manifest ───────────────────────────────────────────────────────────────
|
|
83
|
+
function emptyManifest() {
|
|
84
|
+
return { version: 1, tags: {} };
|
|
85
|
+
}
|
|
86
|
+
/** Read the tag manifest. Never throws — a missing/corrupt file yields empty. */
|
|
87
|
+
export function readKnowledgeManifest() {
|
|
88
|
+
try {
|
|
89
|
+
if (!existsSync(manifestPath()))
|
|
90
|
+
return emptyManifest();
|
|
91
|
+
const data = JSON.parse(readFileSync(manifestPath(), 'utf-8'));
|
|
92
|
+
if (!data || typeof data !== 'object' || typeof data.tags !== 'object')
|
|
93
|
+
return emptyManifest();
|
|
94
|
+
return { version: data.version ?? 1, tags: data.tags ?? {} };
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return emptyManifest();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function writeKnowledgeManifest(manifest) {
|
|
101
|
+
try {
|
|
102
|
+
if (!existsSync(memoryDir()))
|
|
103
|
+
mkdirSync(memoryDir(), { recursive: true });
|
|
104
|
+
writeFileSync(manifestPath(), JSON.stringify(manifest, null, 2), 'utf-8');
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Best-effort — the vectors are the source of truth; the manifest is an index.
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Every tag with its recorded documents/chunk counts (sorted by recency). */
|
|
111
|
+
export function listKnowledgeTags() {
|
|
112
|
+
return Object.values(readKnowledgeManifest().tags).sort((a, b) => b.updatedAt - a.updatedAt);
|
|
113
|
+
}
|
|
114
|
+
/** One tag's manifest entry, or null. */
|
|
115
|
+
export function getKnowledgeTag(tag) {
|
|
116
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
117
|
+
return readKnowledgeManifest().tags[normalized] ?? null;
|
|
118
|
+
}
|
|
119
|
+
// ─── File collection ────────────────────────────────────────────────────────
|
|
120
|
+
/** Recursively collect files under a path (bounded, ignores build/vendor dirs). */
|
|
121
|
+
export function collectKnowledgeFiles(root, out = [], depth = 0) {
|
|
122
|
+
if (out.length >= MAX_FILES_PER_INGEST || depth > 8)
|
|
123
|
+
return out;
|
|
124
|
+
let stat;
|
|
125
|
+
try {
|
|
126
|
+
stat = statSync(root);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
if (stat.isFile()) {
|
|
132
|
+
out.push(root);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
if (!stat.isDirectory())
|
|
136
|
+
return out;
|
|
137
|
+
let entries = [];
|
|
138
|
+
try {
|
|
139
|
+
entries = readdirSync(root);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
if (out.length >= MAX_FILES_PER_INGEST)
|
|
146
|
+
break;
|
|
147
|
+
if (IGNORE_DIRS.has(entry))
|
|
148
|
+
continue;
|
|
149
|
+
collectKnowledgeFiles(join(root, entry), out, depth + 1);
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
// ─── Text extraction ────────────────────────────────────────────────────────
|
|
154
|
+
/**
|
|
155
|
+
* Extract a file's text, reusing the `read_extract` manager so PDF/DOCX/XLSX/
|
|
156
|
+
* PPTX and text formats all work (and unsupported ones refuse with a reason
|
|
157
|
+
* instead of silently indexing a container's bytes).
|
|
158
|
+
*/
|
|
159
|
+
async function extractFileText(filePath) {
|
|
160
|
+
const ext = extname(filePath).toLowerCase();
|
|
161
|
+
// Plain text-ish formats need no heavy reader — read directly.
|
|
162
|
+
if (['.txt', '.md', '.markdown', '.csv', '.tsv', '.json', '.yaml', '.yml', '.log'].includes(ext)) {
|
|
163
|
+
try {
|
|
164
|
+
const text = readFileSync(filePath, 'utf-8');
|
|
165
|
+
return { ok: true, text: text.length > MAX_EXTRACT_CHARS ? text.slice(0, MAX_EXTRACT_CHARS) : text };
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const { getReadExtractManager } = await import('../tools/read-extract.js');
|
|
173
|
+
const result = await getReadExtractManager().extract(filePath);
|
|
174
|
+
if (!result.success || !result.text) {
|
|
175
|
+
return { ok: false, reason: result.error ?? result.code ?? 'extraction failed' };
|
|
176
|
+
}
|
|
177
|
+
return { ok: true, text: result.text };
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ─── Ingest ─────────────────────────────────────────────────────────────────
|
|
184
|
+
/**
|
|
185
|
+
* Ingest raw text under a tag. Idempotent per `<tag>:<sourcePath>#<i>` chunk id,
|
|
186
|
+
* so re-ingesting a changed document overwrites its chunks rather than
|
|
187
|
+
* duplicating them.
|
|
188
|
+
*/
|
|
189
|
+
export async function ingestKnowledgeText(tag, sourcePath, text, opts = {}) {
|
|
190
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
191
|
+
const chunkTokens = opts.chunkTokens ?? DEFAULT_CHUNK_TOKENS;
|
|
192
|
+
const overlapTokens = opts.overlapTokens ?? DEFAULT_OVERLAP_TOKENS;
|
|
193
|
+
const embedFn = opts.embedFn ?? ((t) => embed(t, undefined, false, RETRIEVAL_MODEL));
|
|
194
|
+
const label = `${normalized}:${sourcePath}`;
|
|
195
|
+
const chunks = chunkText(text, label, chunkTokens, overlapTokens);
|
|
196
|
+
const store = getVectorStore(namespaceForTag(normalized));
|
|
197
|
+
for (const chunk of chunks) {
|
|
198
|
+
let vector;
|
|
199
|
+
try {
|
|
200
|
+
vector = await embedFn(chunk.text);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// A failed embed leaves a zero vector (never outranks a real match).
|
|
204
|
+
vector = new Array(384).fill(0);
|
|
205
|
+
}
|
|
206
|
+
await store.insert(chunk.id, vector, {
|
|
207
|
+
kind: 'knowledge-chunk',
|
|
208
|
+
tag: normalized,
|
|
209
|
+
sourcePath,
|
|
210
|
+
chunkIndex: chunk.chunkIndex,
|
|
211
|
+
text: chunk.text,
|
|
212
|
+
tokenCount: chunk.tokenCount,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return chunks.length;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Ingest one or more files/directories under a tag. Extraction, chunking and
|
|
219
|
+
* embedding happen ONCE here; later questions only embed a short query.
|
|
220
|
+
*/
|
|
221
|
+
export async function ingestKnowledge(tag, paths, opts = {}) {
|
|
222
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
223
|
+
if (!isValidKnowledgeTag(normalized)) {
|
|
224
|
+
throw new Error(`Invalid knowledge tag '${tag}' — it must contain at least one letter or digit.`);
|
|
225
|
+
}
|
|
226
|
+
const result = { tag: normalized, files: 0, chunks: 0, skipped: [] };
|
|
227
|
+
const manifest = readKnowledgeManifest();
|
|
228
|
+
const entry = manifest.tags[normalized] ?? {
|
|
229
|
+
tag: normalized,
|
|
230
|
+
updatedAt: Date.now(),
|
|
231
|
+
chunkCount: 0,
|
|
232
|
+
documents: [],
|
|
233
|
+
};
|
|
234
|
+
// Flatten dirs → files, bounded.
|
|
235
|
+
const files = [];
|
|
236
|
+
for (const p of paths) {
|
|
237
|
+
if (existsSync(p)) {
|
|
238
|
+
collectKnowledgeFiles(p, files);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
result.skipped.push({ path: p, reason: 'not found' });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
for (const file of files) {
|
|
245
|
+
const extracted = await extractFileText(file);
|
|
246
|
+
if (!extracted.ok) {
|
|
247
|
+
result.skipped.push({ path: file, reason: extracted.reason });
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const chunks = await ingestKnowledgeText(normalized, file, extracted.text, opts);
|
|
252
|
+
result.files += 1;
|
|
253
|
+
result.chunks += chunks;
|
|
254
|
+
// Re-ingesting a changed document replaces its chunks; keep the recorded
|
|
255
|
+
// count in step by subtracting the previous contribution first.
|
|
256
|
+
const previous = entry.documents.find((d) => d.path === file);
|
|
257
|
+
if (previous)
|
|
258
|
+
entry.chunkCount -= previous.chunks;
|
|
259
|
+
entry.documents = entry.documents.filter((d) => d.path !== file);
|
|
260
|
+
entry.documents.push({ path: file, chunks, addedAt: Date.now() });
|
|
261
|
+
entry.chunkCount += chunks;
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
result.skipped.push({ path: file, reason: err instanceof Error ? err.message : String(err) });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
entry.updatedAt = Date.now();
|
|
268
|
+
manifest.tags[normalized] = entry;
|
|
269
|
+
writeKnowledgeManifest(manifest);
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
// ─── Query ──────────────────────────────────────────────────────────────────
|
|
273
|
+
/** Embed the question and return the tag's top-k chunks. Never throws. */
|
|
274
|
+
export async function queryKnowledge(tag, question, opts = {}) {
|
|
275
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
276
|
+
const topK = opts.topK ?? DEFAULT_KNOWLEDGE_TOP_K;
|
|
277
|
+
const embedFn = opts.embedFn ?? ((t) => embed(t, undefined, false, RETRIEVAL_MODEL));
|
|
278
|
+
try {
|
|
279
|
+
const queryVector = await embedFn(question);
|
|
280
|
+
const store = getVectorStore(namespaceForTag(normalized));
|
|
281
|
+
const results = await store.search(queryVector, topK, (entry) => {
|
|
282
|
+
return entry.metadata?.kind === 'knowledge-chunk' && entry.metadata?.tag === normalized;
|
|
283
|
+
});
|
|
284
|
+
return results.map(({ entry, similarity }) => ({
|
|
285
|
+
tag: normalized,
|
|
286
|
+
text: String(entry.metadata?.text ?? ''),
|
|
287
|
+
sourcePath: String(entry.metadata?.sourcePath ?? entry.id),
|
|
288
|
+
chunkIndex: Number(entry.metadata?.chunkIndex ?? 0),
|
|
289
|
+
similarity,
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
logger.debug(`Knowledge query failed for tag '${normalized}': ${err instanceof Error ? err.message : err}`);
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// ─── Forget ─────────────────────────────────────────────────────────────────
|
|
298
|
+
/** Remove a tag's vectors and manifest entry. Returns true when something was removed. */
|
|
299
|
+
export async function forgetKnowledgeTag(tag) {
|
|
300
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
301
|
+
const manifest = readKnowledgeManifest();
|
|
302
|
+
const existed = Boolean(manifest.tags[normalized]);
|
|
303
|
+
delete manifest.tags[normalized];
|
|
304
|
+
writeKnowledgeManifest(manifest);
|
|
305
|
+
try {
|
|
306
|
+
await getVectorStore(namespaceForTag(normalized)).clear();
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
// Best-effort — the manifest entry is already gone.
|
|
310
|
+
}
|
|
311
|
+
return existed;
|
|
312
|
+
}
|
|
313
|
+
// ─── Formatting for the model ───────────────────────────────────────────────
|
|
314
|
+
/**
|
|
315
|
+
* Render retrieved chunks as context that ATTRIBUTES each part to the user's
|
|
316
|
+
* data. The model can then answer the data half from here and the generic half
|
|
317
|
+
* from its own knowledge / `web-research`, and say which is which.
|
|
318
|
+
*/
|
|
319
|
+
export function formatKnowledgeContext(tag, hits) {
|
|
320
|
+
const normalized = normalizeKnowledgeTag(tag);
|
|
321
|
+
if (hits.length === 0) {
|
|
322
|
+
return `No entries found for knowledge tag '${normalized}'. Ingest documents first with the knowledge tool (action: add).`;
|
|
323
|
+
}
|
|
324
|
+
const parts = hits.map((h) => {
|
|
325
|
+
const name = basename(h.sourcePath);
|
|
326
|
+
return `--- [from your data: ${name} · chunk ${h.chunkIndex + 1} · sim ${h.similarity.toFixed(3)}] ---\n${h.text}`;
|
|
327
|
+
});
|
|
328
|
+
return [
|
|
329
|
+
`Knowledge tag: ${normalized} (${hits.length} relevant chunk${hits.length === 1 ? '' : 's'} from the user's own data)`,
|
|
330
|
+
'Treat the following as USER DATA — quote it for facts about the user. For general advice, combine it with your own knowledge and, when current guidance is needed, the web-research tool, and say which part is which.',
|
|
331
|
+
'',
|
|
332
|
+
...parts,
|
|
333
|
+
].join('\n');
|
|
334
|
+
}
|
|
335
|
+
// Re-export for tests/callers that want the raw embedding defaults.
|
|
336
|
+
export { DEFAULT_CHUNK_TOKENS, DEFAULT_OVERLAP_TOKENS };
|
|
337
|
+
//# sourceMappingURL=knowledge-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-base.js","sourceRoot":"","sources":["../../src/learning/knowledge-base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,+EAA+E;AAE/E,iHAAiH;AACjH,MAAM,CAAC,MAAM,gBAAgB,GAAG,gCAAgC,CAAC;AAEjE,iFAAiF;AACjF,MAAM,CAAC,MAAM,0BAA0B,GAAG,YAAY,CAAC;AAEvD,mFAAmF;AACnF,MAAM,CAAC,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAE9D,yCAAyC;AACzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,kEAAkE;AAClE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM;IAC3E,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS;CAC/D,CAAC,CAAC;AAEH,uEAAuE;AACvE,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,uEAAuE;AACvE,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAsDpC,oFAAoF;AAEpF,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,uBAAuB,CAAC,CAAC;AACpD,CAAC;AAED,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,GAAG;SACP,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,GAAG,0BAA0B,GAAG,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED,+EAA+E;AAE/E,SAAS,aAAa;IACpB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,qBAAqB;IACnC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;YAAE,OAAO,aAAa,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,CAAsB,CAAC;QACpF,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,aAAa,EAAE,CAAC;QAC/F,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,QAA2B;IACzD,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;YAAE,SAAS,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,aAAa,CAAC,YAAY,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,+EAA+E;IACjF,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;AAC/F,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,OAAO,qBAAqB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;AAC1D,CAAC;AAED,+EAA+E;AAE/E,mFAAmF;AACnF,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,MAAgB,EAAE,EAAE,KAAK,GAAG,CAAC;IAC/E,IAAI,GAAG,CAAC,MAAM,IAAI,oBAAoB,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAChE,IAAI,IAAI,CAAC;IACT,IAAI,CAAC;QACH,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QAAE,OAAO,GAAG,CAAC;IACpC,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,MAAM,IAAI,oBAAoB;YAAE,MAAM;QAC9C,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACrC,qBAAqB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+EAA+E;AAE/E;;;;GAIG;AACH,KAAK,UAAU,eAAe,CAAC,QAAgB;IAC7C,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5C,+DAA+D;IAC/D,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjG,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACvG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACjF,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,MAAM,qBAAqB,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACnF,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACjF,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAW,EACX,UAAkB,EAClB,IAAY,EACZ,OAAyB,EAAE;IAE3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,oBAAoB,CAAC;IAC7D,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC;IAE7F,MAAM,KAAK,GAAG,GAAG,UAAU,IAAI,UAAU,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,cAAc,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,MAAgB,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,MAAM,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE;YACnC,IAAI,EAAE,iBAAiB;YACvB,GAAG,EAAE,UAAU;YACf,UAAU;YACV,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,KAAe,EACf,OAAyB,EAAE;IAE3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,mDAAmD,CAAC,CAAC;IACpG,CAAC;IAED,MAAM,MAAM,GAAiB,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACnF,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,MAAM,KAAK,GAAsB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI;QAC5D,GAAG,EAAE,UAAU;QACf,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,UAAU,EAAE,CAAC;QACb,SAAS,EAAE,EAAE;KACd,CAAC;IAEF,iCAAiC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,qBAAqB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9D,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACjF,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;YAClB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;YACxB,yEAAyE;YACzE,gEAAgE;YAChE,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAC9D,IAAI,QAAQ;gBAAE,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC,MAAM,CAAC;YAClD,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YACjE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAClE,KAAK,CAAC,UAAU,IAAI,MAAM,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;IAClC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+EAA+E;AAE/E,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,QAAgB,EAChB,OAAyB,EAAE;IAE3B,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,uBAAuB,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC;IAE7F,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,cAAc,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,KAAkB,EAAE,EAAE;YAC3E,OAAO,KAAK,CAAC,QAAQ,EAAE,IAAI,KAAK,iBAAiB,IAAI,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,UAAU,CAAC;QAC1F,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;YAC7C,GAAG,EAAE,UAAU;YACf,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;YACxC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1D,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,IAAI,CAAC,CAAC;YACnD,UAAU;SACX,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,mCAAmC,UAAU,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5G,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,oDAAoD;IACtD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,IAAoB;IACtE,MAAM,UAAU,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,uCAAuC,UAAU,kEAAkE,CAAC;IAC7H,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACpC,OAAO,wBAAwB,IAAI,YAAY,CAAC,CAAC,UAAU,GAAG,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IACrH,CAAC,CAAC,CAAC;IACH,OAAO;QACL,kBAAkB,UAAU,KAAK,IAAI,CAAC,MAAM,kBAAkB,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,4BAA4B;QACtH,wNAAwN;QACxN,EAAE;QACF,GAAG,KAAK;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,oEAAoE;AACpE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -54,7 +54,8 @@ export declare function hasCredentials(configManager: ConfigManager, provider: s
|
|
|
54
54
|
export declare const MODEL_HEALTH_CEILING = 0.6;
|
|
55
55
|
/**
|
|
56
56
|
* Verified working models for a provider, ranked by learned health:
|
|
57
|
-
*
|
|
57
|
+
* strongest verification source first, then lowest error rate, then lowest
|
|
58
|
+
* latency, then most recently verified.
|
|
58
59
|
* Empty when nothing has been verified yet (cold start / no keys).
|
|
59
60
|
*
|
|
60
61
|
* MODELS AT/ABOVE `MODEL_HEALTH_CEILING` SORT AFTER THE HEALTHY ONES but are
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../src/learning/model-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAU1D,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,qEAAsE,CAAC;AAErG;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,CAAC;AAMnE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAA6B,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOtF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../src/learning/model-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAU1D,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,qEAAsE,CAAC;AAErG;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,CAAC;AAMnE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAA6B,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOtF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAqBxC;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA6C7D;AAcD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,aAAa,GAAG,cAAc,EAAE,CAuErF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,aAAa,GAAG,MAAM,CAE3E;AAED,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,iBAAiB,EAC1B,aAAa,CAAC,EAAE,aAAa,GAC5B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA0BjD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxG;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,aAAa,GAAG,MAAM,CAa5E"}
|
|
@@ -68,9 +68,28 @@ export function hasCredentials(configManager, provider) {
|
|
|
68
68
|
* failed outright.
|
|
69
69
|
*/
|
|
70
70
|
export const MODEL_HEALTH_CEILING = 0.6;
|
|
71
|
+
/**
|
|
72
|
+
* How much a verification SOURCE is worth when ranking models of equal health.
|
|
73
|
+
* Lower = more trustworthy, so it sorts first.
|
|
74
|
+
*
|
|
75
|
+
* A `spot-check` is a single 1-token generation: it proves the model NAME
|
|
76
|
+
* exists and accepts a request — it does NOT prove the model can hold a task.
|
|
77
|
+
* `telemetry` is real traffic (hundreds of samples), so it is the strongest
|
|
78
|
+
* evidence we have. Ranking them as equals let a model with six probe samples
|
|
79
|
+
* (observed live: `deepseek-v4-pro`, 6 samples) sit at errorRate 0 beside a
|
|
80
|
+
* model with 290 real calls (`deepseek-flash`) — and whenever the configured
|
|
81
|
+
* pin was dead, the fallback walk could then hand a caller a model that had
|
|
82
|
+
* never actually done a task. Real evidence must win.
|
|
83
|
+
*/
|
|
84
|
+
const SOURCE_CONFIDENCE = {
|
|
85
|
+
telemetry: 0,
|
|
86
|
+
'spot-check': 1,
|
|
87
|
+
probe: 2,
|
|
88
|
+
};
|
|
71
89
|
/**
|
|
72
90
|
* Verified working models for a provider, ranked by learned health:
|
|
73
|
-
*
|
|
91
|
+
* strongest verification source first, then lowest error rate, then lowest
|
|
92
|
+
* latency, then most recently verified.
|
|
74
93
|
* Empty when nothing has been verified yet (cold start / no keys).
|
|
75
94
|
*
|
|
76
95
|
* MODELS AT/ABOVE `MODEL_HEALTH_CEILING` SORT AFTER THE HEALTHY ONES but are
|
|
@@ -96,6 +115,13 @@ export function preferredModelsFor(provider) {
|
|
|
96
115
|
.sort((a, b) => {
|
|
97
116
|
const ea = registry.getEntry(provider, a);
|
|
98
117
|
const eb = registry.getEntry(provider, b);
|
|
118
|
+
// 1. Evidence strength. A model proven by real traffic must outrank one
|
|
119
|
+
// that only ever answered a 1-token probe — they are NOT equivalent
|
|
120
|
+
// evidence, and treating them as such is how an unproven model won.
|
|
121
|
+
const sa = SOURCE_CONFIDENCE[ea?.source ?? 'probe'] ?? 2;
|
|
122
|
+
const sb = SOURCE_CONFIDENCE[eb?.source ?? 'probe'] ?? 2;
|
|
123
|
+
if (sa !== sb)
|
|
124
|
+
return sa - sb;
|
|
99
125
|
const ra = ea?.errorRate ?? 0;
|
|
100
126
|
const rb = eb?.errorRate ?? 0;
|
|
101
127
|
if (ra !== rb)
|
|
@@ -156,8 +182,10 @@ export function rankAvailableProviders(configManager) {
|
|
|
156
182
|
// providers join routing the moment they appear in config. Nothing is
|
|
157
183
|
// hardcoded to the 6 built-ins anymore.
|
|
158
184
|
let configuredIds = [];
|
|
185
|
+
let providerConfig = {};
|
|
159
186
|
try {
|
|
160
|
-
|
|
187
|
+
providerConfig = configManager.getAll?.()?.providers ?? {};
|
|
188
|
+
configuredIds = Object.keys(providerConfig);
|
|
161
189
|
}
|
|
162
190
|
catch {
|
|
163
191
|
// Best-effort.
|
|
@@ -165,6 +193,11 @@ export function rankAvailableProviders(configManager) {
|
|
|
165
193
|
const candidates = [...new Set([...CATALOG_PROVIDER_IDS, ...configuredIds])].filter((p) => {
|
|
166
194
|
if (blocked.has(p))
|
|
167
195
|
return false;
|
|
196
|
+
// The dashboard's per-provider On/Off switch. Off removes the provider from
|
|
197
|
+
// the AUTO pool only; credentials stay on disk, and an explicit `--provider`
|
|
198
|
+
// pin is a user decision the router does not second-guess.
|
|
199
|
+
if (providerConfig[p]?.enabled === false)
|
|
200
|
+
return false;
|
|
168
201
|
// Keyless runners BEYOND `local` (nuvira, lmstudio, vllm) only join when the
|
|
169
202
|
// registry has VERIFIED them or the user explicitly configured them — a
|
|
170
203
|
// not-running localhost endpoint must never out-rank running local on a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../src/learning/model-selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"model-selection.js","sourceRoot":"","sources":["../../src/learning/model-selection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PROJECT DOCUMENTATION (software deliverables).
|
|
3
|
+
*
|
|
4
|
+
* The gap this closes: a software build produced CODE and stopped. The
|
|
5
|
+
* documents a real project ships — a README, a changelog that grows with each
|
|
6
|
+
* change, a short architecture note with a diagram, and (for a library/service)
|
|
7
|
+
* usage + API docs — were only produced when the user named them, which is
|
|
8
|
+
* exactly backwards: a user should not have to ask a "world-class developer" to
|
|
9
|
+
* write down what it built.
|
|
10
|
+
*
|
|
11
|
+
* Two rules keep this from becoming noise:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Software only.** This module is consulted ONLY for a `code` deliverable
|
|
14
|
+
* that is not authored (`deliverable-class.ts` already separates a poem
|
|
15
|
+
* from a program). Nobody wants a README and an ARCHITECTURE.md for
|
|
16
|
+
* "write me a poem about rain" — the classifier decides, and this guidance
|
|
17
|
+
* is never appended to an authored ask.
|
|
18
|
+
* 2. **Proportionate.** A README and a CHANGELOG are expected of every
|
|
19
|
+
* software deliverable; the heavier documents (architecture, API reference,
|
|
20
|
+
* contributing guide) are asked for only when the shape warrants them —
|
|
21
|
+
* a multi-component or library/service build, or an explicit request for
|
|
22
|
+
* docs. A one-file script still gets a README; it is not asked to invent an
|
|
23
|
+
* architecture diagram.
|
|
24
|
+
*
|
|
25
|
+
* It also encodes the maintenance rule the user cares about: an EXISTING
|
|
26
|
+
* document is UPDATED in place (CHANGELOG gets a new entry at the top), never
|
|
27
|
+
* shadowed by a second file — a project with two changelogs is worse than one
|
|
28
|
+
* with none.
|
|
29
|
+
*
|
|
30
|
+
* Pure and side-effect free: every input is data, so it is unit-testable and can
|
|
31
|
+
* be appended to any prompt without touching the filesystem.
|
|
32
|
+
*/
|
|
33
|
+
/** The canonical documents a software project ships, in priority order. */
|
|
34
|
+
export interface ProjectDocArtifact {
|
|
35
|
+
/** Project-relative path the document lives at. */
|
|
36
|
+
path: string;
|
|
37
|
+
/** What it is FOR — handed to the model so the document has a job. */
|
|
38
|
+
purpose: string;
|
|
39
|
+
/** Required of every software deliverable (README, CHANGELOG). */
|
|
40
|
+
always: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare const PROJECT_DOC_ARTIFACTS: readonly ProjectDocArtifact[];
|
|
43
|
+
/** What we know about the deliverable, from the goal + project assessment. */
|
|
44
|
+
export interface ProjectDocShape {
|
|
45
|
+
/**
|
|
46
|
+
* True when the workspace has no project yet (a scaffold). A greenfield build
|
|
47
|
+
* gets the full proportionate set rather than only the always-on pair.
|
|
48
|
+
*/
|
|
49
|
+
greenfield?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* A library, package, SDK or service — a thing other code CONSUMES — rather
|
|
52
|
+
* than an end-user app. Its public surface must be documented.
|
|
53
|
+
*/
|
|
54
|
+
isLibraryOrService?: boolean;
|
|
55
|
+
/** The project already exposes tests (or the agent is expected to write them). */
|
|
56
|
+
hasTests?: boolean;
|
|
57
|
+
/** Names the user explicitly asked for docs ("with documentation", "API docs"). */
|
|
58
|
+
docsRequested?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Documents that ALREADY exist in the workspace (project-relative paths).
|
|
61
|
+
* These are UPDATED in place, never duplicated.
|
|
62
|
+
*/
|
|
63
|
+
existingDocs?: readonly string[];
|
|
64
|
+
}
|
|
65
|
+
/** The always-on pair, plus the heavier docs a bigger build warrants. */
|
|
66
|
+
export declare function requiredProjectDocs(shape?: ProjectDocShape): string[];
|
|
67
|
+
/**
|
|
68
|
+
* Does the goal name something other code CONSUMES (a library, package, SDK,
|
|
69
|
+
* CLI, service, plugin) rather than an end-user app? A consumed surface has a
|
|
70
|
+
* public API worth documenting; an app does not need an API reference.
|
|
71
|
+
*/
|
|
72
|
+
export declare function looksLikeLibraryOrService(goal: string): boolean;
|
|
73
|
+
/** The required docs that do NOT yet exist on disk (the ones to CREATE). */
|
|
74
|
+
export declare function missingProjectDocs(shape?: ProjectDocShape): string[];
|
|
75
|
+
/** The required docs that already exist (the ones to UPDATE, not recreate). */
|
|
76
|
+
export declare function existingProjectDocs(shape?: ProjectDocShape): string[];
|
|
77
|
+
/**
|
|
78
|
+
* The instruction appended to the reasoner/planner prompt for a SOFTWARE
|
|
79
|
+
* deliverable. Returns `''` for a non-software (authored) ask, so callers can
|
|
80
|
+
* append it unconditionally without a poem ever being asked for a CHANGELOG.
|
|
81
|
+
*/
|
|
82
|
+
export declare function softwareProjectGuidance(verdictClass: string, authored: boolean, shape?: ProjectDocShape): string;
|
|
83
|
+
//# sourceMappingURL=project-docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-docs.d.ts","sourceRoot":"","sources":["../../src/learning/project-docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAqC9D,CAAC;AAEF,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,KAAK,GAAE,eAAoB,GAAG,MAAM,EAAE,CAOzE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAU/D;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,eAAoB,GAAG,MAAM,EAAE,CAGxE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,KAAK,GAAE,eAAoB,GAAG,MAAM,EAAE,CAGzE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,OAAO,EACjB,KAAK,GAAE,eAAoB,GAC1B,MAAM,CAmCR"}
|