pi-para 0.6.5 → 0.6.7
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 +22 -0
- package/CONFIGURATION.md +1 -1
- package/README.md +1 -1
- package/SETUP.md +2 -2
- package/STRUCTURE.md +1 -1
- package/dist/cli.d.ts +23 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +71 -83
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +2 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +12 -5
- package/dist/commands.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2 -1
- package/dist/context.js.map +1 -1
- package/dist/credentials.d.ts +2 -2
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +6 -14
- package/dist/credentials.js.map +1 -1
- package/dist/doctor.js +19 -18
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -10
- package/dist/index.js.map +1 -1
- package/dist/model-resolver.d.ts +13 -6
- package/dist/model-resolver.d.ts.map +1 -1
- package/dist/model-resolver.js +35 -19
- package/dist/model-resolver.js.map +1 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +9 -3
- package/dist/scheduler/index.js.map +1 -1
- package/dist/store.d.ts +11 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +48 -16
- package/dist/store.js.map +1 -1
- package/dist/wiki-tool-guidance.js +2 -2
- package/dist/wiki-tool-guidance.js.map +1 -1
- package/package.json +9 -9
- package/src/cli.ts +69 -81
- package/src/commands.ts +15 -6
- package/src/context.ts +2 -1
- package/src/credentials.ts +7 -14
- package/src/doctor.ts +18 -16
- package/src/index.ts +11 -10
- package/src/model-resolver.ts +45 -20
- package/src/scheduler/index.ts +9 -3
- package/src/store.ts +52 -15
- package/src/wiki-tool-guidance.ts +2 -2
package/src/store.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* re-indexing after wiki changes, and embedding lifecycle.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
9
|
import { readFileSync, existsSync } from "node:fs";
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
11
|
import { join } from "node:path";
|
|
@@ -73,6 +74,51 @@ const RAW_CONTEXT = "Immutable source material: articles, documents, notes. Not
|
|
|
73
74
|
|
|
74
75
|
const pendingEmbeds = new WeakMap<QMDStore, Promise<void>>();
|
|
75
76
|
|
|
77
|
+
export type QmdEmbedOperationResult<T> =
|
|
78
|
+
| { ok: true; value: T; diagnostics: string[] }
|
|
79
|
+
| { ok: false; error: unknown; diagnostics: string[] };
|
|
80
|
+
|
|
81
|
+
// qmd-engine's API adapter logs recoverable provider failures directly to
|
|
82
|
+
// console.error before returning null. Capture only those known messages so
|
|
83
|
+
// best-effort vector search and scheduler retries do not flash raw errors in
|
|
84
|
+
// the Pi UI. Other console errors continue to pass through unchanged.
|
|
85
|
+
const qmdEmbedDiagnosticContext = new AsyncLocalStorage<string[]>();
|
|
86
|
+
let qmdEmbedCaptureCount = 0;
|
|
87
|
+
let qmdEmbedOriginalConsoleError: typeof console.error | null = null;
|
|
88
|
+
const qmdEmbedConsoleInterceptor = (...args: unknown[]): void => {
|
|
89
|
+
const sink = qmdEmbedDiagnosticContext.getStore();
|
|
90
|
+
const first = String(args[0] ?? "");
|
|
91
|
+
if (sink && /^embed(?:Batch)? error:/i.test(first)) {
|
|
92
|
+
sink.push(args.map((arg) => arg instanceof Error ? arg.message : String(arg)).join(" "));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
qmdEmbedOriginalConsoleError?.(...args);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** Run a QMD embedding operation without leaking its recoverable raw stderr. */
|
|
99
|
+
export async function captureQmdEmbedErrors<T>(operation: () => Promise<T>): Promise<QmdEmbedOperationResult<T>> {
|
|
100
|
+
const diagnostics: string[] = [];
|
|
101
|
+
if (qmdEmbedCaptureCount++ === 0) {
|
|
102
|
+
qmdEmbedOriginalConsoleError = console.error;
|
|
103
|
+
console.error = qmdEmbedConsoleInterceptor;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
return await qmdEmbedDiagnosticContext.run(diagnostics, async () => {
|
|
107
|
+
try {
|
|
108
|
+
return { ok: true, value: await operation(), diagnostics };
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return { ok: false, error, diagnostics };
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} finally {
|
|
114
|
+
qmdEmbedCaptureCount--;
|
|
115
|
+
if (qmdEmbedCaptureCount === 0) {
|
|
116
|
+
if (console.error === qmdEmbedConsoleInterceptor && qmdEmbedOriginalConsoleError) console.error = qmdEmbedOriginalConsoleError;
|
|
117
|
+
qmdEmbedOriginalConsoleError = null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
76
122
|
// -- Inert-provider tracking ---------------------------------------------------
|
|
77
123
|
|
|
78
124
|
/** Stores opened with the NO_LOCAL_PROVIDERS shim (no real API provider). */
|
|
@@ -184,22 +230,10 @@ export async function openStore(wikiDir: string, opts: OpenStoreOptions = {}): P
|
|
|
184
230
|
if (opts.backgroundEmbed !== false && opts.paraConfig?.qmd.embedEnabled !== false) {
|
|
185
231
|
// Schedule embedding in background (non-blocking).
|
|
186
232
|
// BM25 search works immediately; hybrid search improves once embed completes.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const embedPromise = store.embed().then(() => {
|
|
190
|
-
pendingEmbeds.delete(store);
|
|
191
|
-
}).catch(() => {
|
|
192
|
-
// Embedding failures are non-fatal — hybrid search degrades to BM25
|
|
233
|
+
const embedPromise = captureQmdEmbedErrors(() => store.embed()).then(() => {
|
|
234
|
+
// Embedding failures are non-fatal — hybrid search degrades to BM25.
|
|
193
235
|
pendingEmbeds.delete(store);
|
|
194
|
-
}).finally(() => {
|
|
195
|
-
console.error = origError;
|
|
196
236
|
});
|
|
197
|
-
// Temporarily suppress embed error noise during background embed
|
|
198
|
-
console.error = (...args: unknown[]) => {
|
|
199
|
-
const msg = String(args[0] ?? "");
|
|
200
|
-
if (msg.includes("embed error") || msg.includes("fetch failed")) return;
|
|
201
|
-
origError(...args);
|
|
202
|
-
};
|
|
203
237
|
pendingEmbeds.set(store, embedPromise);
|
|
204
238
|
}
|
|
205
239
|
|
|
@@ -317,7 +351,10 @@ async function mergeLexAndVectorResults(
|
|
|
317
351
|
const llm = (store.internal as unknown as { llm?: unknown }).llm;
|
|
318
352
|
const embedModel = (llm as { embedModelName?: string } | undefined)?.embedModelName;
|
|
319
353
|
if (status.hasVectorIndex && llm && embedModel) {
|
|
320
|
-
|
|
354
|
+
const vectorAttempt = await captureQmdEmbedErrors(
|
|
355
|
+
() => store.internal.searchVec(query, embedModel, limit, "wiki", llm as any) as Promise<RawQmdSearchResult[]>,
|
|
356
|
+
);
|
|
357
|
+
if (vectorAttempt.ok) vecResults = vectorAttempt.value;
|
|
321
358
|
}
|
|
322
359
|
} catch {
|
|
323
360
|
// Semantic search is best-effort; lexical BM25 remains the reliable fallback.
|
|
@@ -39,7 +39,7 @@ const TOOL_SPECIFIC_GUIDELINES: Record<WikiToolName, readonly string[]> = {
|
|
|
39
39
|
"After ingesting, synthesize durable knowledge with wiki_write/wiki_edit when the source contains reusable facts.",
|
|
40
40
|
],
|
|
41
41
|
wiki_query: [
|
|
42
|
-
"
|
|
42
|
+
"Call wiki_query FIRST — before other tools — for any non-trivial planning, implementation, debugging, architecture, or review request; the wiki may hold prior decisions, root causes, and conventions.",
|
|
43
43
|
"Use global=true only when the answer should search across project scopes.",
|
|
44
44
|
],
|
|
45
45
|
wiki_edit: [
|
|
@@ -76,7 +76,7 @@ export function buildWikiToolGuidanceSection(): string {
|
|
|
76
76
|
return [
|
|
77
77
|
"## pi-para Wiki Tool Guidance",
|
|
78
78
|
"",
|
|
79
|
-
"-
|
|
79
|
+
"- Start non-trivial work with wiki_query using keywords from the request; past architecture, debugging, conventions, domain facts, or prior discussion may already be documented.",
|
|
80
80
|
"- Treat AGING/STALE/VERY STALE code/config/API claims as untrusted until verified against source; fix wrong pages with wiki_edit.",
|
|
81
81
|
"- Persist major decisions/debugging/conventions without being asked. Use wiki_edit for surgical fixes; wiki_write create/append for new/additive knowledge; replace only for deliberate full rewrites.",
|
|
82
82
|
"- Prefer resources/, kebab-case scope/tags, [[wikilinks]], and no secrets.",
|