@daniel156161/prism 0.2.81 → 0.2.83
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/prism-extensions/integrations/ai-memory-errors.d.ts +13 -0
- package/dist/prism-extensions/integrations/ai-memory-errors.js +54 -0
- package/dist/prism-extensions/integrations/ai-memory-errors.js.map +1 -1
- package/dist/prism-extensions/integrations/ai-memory-http.d.ts +29 -0
- package/dist/prism-extensions/integrations/ai-memory-http.js +102 -0
- package/dist/prism-extensions/integrations/ai-memory-http.js.map +1 -0
- package/dist/prism-extensions/integrations/ai-memory-system.d.ts +3 -0
- package/dist/prism-extensions/integrations/ai-memory-system.js +63 -132
- package/dist/prism-extensions/integrations/ai-memory-system.js.map +1 -1
- package/dist/prism-extensions/integrations/ai-memory-write-preview.d.ts +36 -0
- package/dist/prism-extensions/integrations/ai-memory-write-preview.js +67 -0
- package/dist/prism-extensions/integrations/ai-memory-write-preview.js.map +1 -0
- package/dist/prism-extensions/ui/collapsed-text-rendering.d.ts +4 -2
- package/dist/prism-extensions/ui/collapsed-text-rendering.js +12 -7
- package/dist/prism-extensions/ui/collapsed-text-rendering.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2365 -2
- package/package.json +4 -3
- package/src/prism-extensions/integrations/ai-memory-errors.ts +59 -0
- package/src/prism-extensions/integrations/ai-memory-http.ts +123 -0
- package/src/prism-extensions/integrations/ai-memory-system.ts +74 -139
- package/src/prism-extensions/integrations/ai-memory-write-preview.ts +83 -0
- package/src/prism-extensions/ui/collapsed-text-rendering.ts +14 -8
|
@@ -12,5 +12,18 @@ export type AiMemoryRequestContext = {
|
|
|
12
12
|
query?: string;
|
|
13
13
|
filters?: Record<string, unknown>;
|
|
14
14
|
};
|
|
15
|
+
export type AiMemoryTransportContext = AiMemoryRequestContext & {
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
timeoutMs: number;
|
|
18
|
+
};
|
|
15
19
|
export declare function formatApiFailure(status: number, text: string, context: AiMemoryRequestContext): string;
|
|
20
|
+
/**
|
|
21
|
+
* A request that never reached the API (timeout, refused connection, DNS) must
|
|
22
|
+
* still explain itself. `fetch` alone only reports "fetch failed" or "The
|
|
23
|
+
* operation was aborted due to timeout", which is useless while debugging why a
|
|
24
|
+
* memory write did not land.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatTransportFailure(error: unknown, context: AiMemoryTransportContext): string;
|
|
27
|
+
/** A 2xx response with a body that is not JSON, e.g. an HTML proxy page. */
|
|
28
|
+
export declare function formatInvalidJsonFailure(error: unknown, text: string, context: AiMemoryTransportContext): string;
|
|
16
29
|
export declare function formatDegradedNotice(degraded: any): string;
|
|
@@ -41,6 +41,60 @@ export function formatApiFailure(status, text, context) {
|
|
|
41
41
|
parts.push(`filters=${JSON.stringify(context.filters)}`);
|
|
42
42
|
return parts.join(" | ");
|
|
43
43
|
}
|
|
44
|
+
function errorCode(error) {
|
|
45
|
+
const candidates = [error, error?.cause];
|
|
46
|
+
for (const candidate of candidates) {
|
|
47
|
+
const code = candidate?.code ?? candidate?.errno;
|
|
48
|
+
if (typeof code === "string" && code.trim())
|
|
49
|
+
return code.trim();
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function errorMessage(error) {
|
|
54
|
+
if (error instanceof Error) {
|
|
55
|
+
const cause = error.cause;
|
|
56
|
+
const causeMessage = cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "";
|
|
57
|
+
return causeMessage && causeMessage !== error.message ? `${error.message}: ${causeMessage}` : error.message;
|
|
58
|
+
}
|
|
59
|
+
return String(error);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A request that never reached the API (timeout, refused connection, DNS) must
|
|
63
|
+
* still explain itself. `fetch` alone only reports "fetch failed" or "The
|
|
64
|
+
* operation was aborted due to timeout", which is useless while debugging why a
|
|
65
|
+
* memory write did not land.
|
|
66
|
+
*/
|
|
67
|
+
export function formatTransportFailure(error, context) {
|
|
68
|
+
const name = error?.name;
|
|
69
|
+
const code = errorCode(error);
|
|
70
|
+
const timedOut = name === "TimeoutError" || name === "AbortError";
|
|
71
|
+
const reason = timedOut
|
|
72
|
+
? `request timed out after ${context.timeoutMs}ms`
|
|
73
|
+
: `request failed before a response arrived: ${errorMessage(error)}`;
|
|
74
|
+
const parts = [`AI Memory ${context.method} ${context.path} failed: ${reason}`];
|
|
75
|
+
if (code)
|
|
76
|
+
parts.push(`code=${code}`);
|
|
77
|
+
parts.push(`base_url=${context.baseUrl}`);
|
|
78
|
+
if (code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EAI_AGAIN") {
|
|
79
|
+
parts.push(`hint=Is the AI Memory System API running and reachable at ${context.baseUrl}?`);
|
|
80
|
+
}
|
|
81
|
+
else if (timedOut) {
|
|
82
|
+
parts.push("hint=Raise PRISM_AI_MEMORY_TIMEOUT_MS or check the API load; nothing was confirmed as written.");
|
|
83
|
+
}
|
|
84
|
+
if (context.query)
|
|
85
|
+
parts.push(`query=${JSON.stringify(context.query)}`);
|
|
86
|
+
if (context.filters && Object.keys(context.filters).length > 0)
|
|
87
|
+
parts.push(`filters=${JSON.stringify(context.filters)}`);
|
|
88
|
+
return parts.join(" | ");
|
|
89
|
+
}
|
|
90
|
+
/** A 2xx response with a body that is not JSON, e.g. an HTML proxy page. */
|
|
91
|
+
export function formatInvalidJsonFailure(error, text, context) {
|
|
92
|
+
const snippet = String(text ?? "").replace(/\s+/g, " ").trim().slice(0, 300);
|
|
93
|
+
const parts = [`AI Memory ${context.method} ${context.path} failed: response was not valid JSON: ${errorMessage(error)}`];
|
|
94
|
+
parts.push(`base_url=${context.baseUrl}`);
|
|
95
|
+
parts.push(`body=${snippet || "(empty)"}`);
|
|
96
|
+
return parts.join(" | ");
|
|
97
|
+
}
|
|
44
98
|
export function formatDegradedNotice(degraded) {
|
|
45
99
|
const stages = Array.isArray(degraded?.stages) ? degraded.stages : [];
|
|
46
100
|
if (stages.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-memory-errors.js","sourceRoot":"","sources":["../../../src/prism-extensions/integrations/ai-memory-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"ai-memory-errors.js","sourceRoot":"","sources":["../../../src/prism-extensions/integrations/ai-memory-errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP transport for the AI Memory System integration.
|
|
3
|
+
*
|
|
4
|
+
* Every request funnels through `requestJson` so that transport failures
|
|
5
|
+
* (timeout, refused connection, unreadable or non-JSON body) end up as
|
|
6
|
+
* descriptive errors instead of a bare "fetch failed" / "The operation was
|
|
7
|
+
* aborted". The tool call is still reported as an error to the model, but the
|
|
8
|
+
* message now explains *why* it failed and which route/base URL was involved.
|
|
9
|
+
*/
|
|
10
|
+
export declare function configuredAiMemoryBaseUrl(env?: NodeJS.ProcessEnv): string | undefined;
|
|
11
|
+
export declare function aiMemoryBaseUrl(env?: NodeJS.ProcessEnv): string;
|
|
12
|
+
export declare function aiMemoryRequestTimeoutMs(env?: NodeJS.ProcessEnv): number;
|
|
13
|
+
export declare function aiMemoryStatusTimeoutMs(env?: NodeJS.ProcessEnv): number;
|
|
14
|
+
export declare function aiMemoryInjectTimeoutMs(env?: NodeJS.ProcessEnv): number;
|
|
15
|
+
export declare function aiMemoryInjectCacheTtlMs(env?: NodeJS.ProcessEnv): number;
|
|
16
|
+
export type AiMemoryRequest = {
|
|
17
|
+
method: string;
|
|
18
|
+
path: string;
|
|
19
|
+
body?: unknown;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
query?: string;
|
|
22
|
+
filters?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
export declare function requestJson<T>(request: AiMemoryRequest): Promise<T>;
|
|
25
|
+
export declare function postJson<T>(path: string, body: unknown, timeoutMs?: number): Promise<T>;
|
|
26
|
+
export declare function putJson<T>(path: string, body: unknown, timeoutMs?: number): Promise<T>;
|
|
27
|
+
export declare function deleteJson<T>(path: string, body: unknown, timeoutMs?: number): Promise<T>;
|
|
28
|
+
export declare function methodJson<T>(method: string, path: string, timeoutMs?: number, body?: unknown): Promise<T>;
|
|
29
|
+
export declare function getJson<T>(path: string, timeoutMs?: number): Promise<T>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP transport for the AI Memory System integration.
|
|
3
|
+
*
|
|
4
|
+
* Every request funnels through `requestJson` so that transport failures
|
|
5
|
+
* (timeout, refused connection, unreadable or non-JSON body) end up as
|
|
6
|
+
* descriptive errors instead of a bare "fetch failed" / "The operation was
|
|
7
|
+
* aborted". The tool call is still reported as an error to the model, but the
|
|
8
|
+
* message now explains *why* it failed and which route/base URL was involved.
|
|
9
|
+
*/
|
|
10
|
+
import { readSettings } from "../core/shared-config.js";
|
|
11
|
+
import { formatApiFailure, formatInvalidJsonFailure, formatTransportFailure } from "./ai-memory-errors.js";
|
|
12
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
13
|
+
const DEFAULT_STATUS_TIMEOUT_MS = 1_500;
|
|
14
|
+
const DEFAULT_INJECT_TIMEOUT_MS = 1_200;
|
|
15
|
+
const DEFAULT_INJECT_CACHE_TTL_MS = 60_000;
|
|
16
|
+
export function configuredAiMemoryBaseUrl(env = process.env) {
|
|
17
|
+
const raw = env.PRISM_AI_MEMORY_BASE_URL ?? env.AI_MEMORY_BASE_URL ?? readSettings(undefined, env)?.aiMemory?.baseUrl ?? readSettings(undefined, env)?.aiMemoryBaseUrl;
|
|
18
|
+
if (typeof raw !== "string")
|
|
19
|
+
return undefined;
|
|
20
|
+
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
21
|
+
return trimmed || undefined;
|
|
22
|
+
}
|
|
23
|
+
export function aiMemoryBaseUrl(env = process.env) {
|
|
24
|
+
const baseUrl = configuredAiMemoryBaseUrl(env);
|
|
25
|
+
if (!baseUrl)
|
|
26
|
+
throw new Error("AI Memory base URL is not configured. Set PRISM_AI_MEMORY_BASE_URL or aiMemory.baseUrl.");
|
|
27
|
+
return baseUrl;
|
|
28
|
+
}
|
|
29
|
+
function positiveIntegerSetting(value, fallback) {
|
|
30
|
+
const parsed = Number(value);
|
|
31
|
+
if (!Number.isFinite(parsed))
|
|
32
|
+
return fallback;
|
|
33
|
+
return Math.max(1, Math.trunc(parsed));
|
|
34
|
+
}
|
|
35
|
+
export function aiMemoryRequestTimeoutMs(env = process.env) {
|
|
36
|
+
return positiveIntegerSetting(env.PRISM_AI_MEMORY_TIMEOUT_MS ?? env.PI_AI_MEMORY_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
37
|
+
}
|
|
38
|
+
export function aiMemoryStatusTimeoutMs(env = process.env) {
|
|
39
|
+
return positiveIntegerSetting(env.PRISM_AI_MEMORY_STATUS_TIMEOUT_MS ?? env.PI_AI_MEMORY_STATUS_TIMEOUT_MS, DEFAULT_STATUS_TIMEOUT_MS);
|
|
40
|
+
}
|
|
41
|
+
export function aiMemoryInjectTimeoutMs(env = process.env) {
|
|
42
|
+
return positiveIntegerSetting(env.PRISM_AI_MEMORY_INJECT_TIMEOUT_MS ?? env.PI_AI_MEMORY_INJECT_TIMEOUT_MS, DEFAULT_INJECT_TIMEOUT_MS);
|
|
43
|
+
}
|
|
44
|
+
export function aiMemoryInjectCacheTtlMs(env = process.env) {
|
|
45
|
+
return positiveIntegerSetting(env.PRISM_AI_MEMORY_INJECT_CACHE_TTL_MS ?? env.PI_AI_MEMORY_INJECT_CACHE_TTL_MS, DEFAULT_INJECT_CACHE_TTL_MS);
|
|
46
|
+
}
|
|
47
|
+
function requestContext(request) {
|
|
48
|
+
const payload = request.body;
|
|
49
|
+
return {
|
|
50
|
+
method: request.method,
|
|
51
|
+
path: request.path,
|
|
52
|
+
query: request.query ?? (typeof payload?.query === "string" ? payload.query : undefined),
|
|
53
|
+
filters: request.filters ?? payload?.filters,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export async function requestJson(request) {
|
|
57
|
+
const baseUrl = aiMemoryBaseUrl();
|
|
58
|
+
const timeoutMs = request.timeoutMs ?? aiMemoryRequestTimeoutMs();
|
|
59
|
+
const context = requestContext(request);
|
|
60
|
+
const transport = { ...context, baseUrl, timeoutMs };
|
|
61
|
+
let response;
|
|
62
|
+
let text;
|
|
63
|
+
try {
|
|
64
|
+
response = await fetch(`${baseUrl}${request.path}`, {
|
|
65
|
+
method: request.method,
|
|
66
|
+
headers: {
|
|
67
|
+
accept: "application/json",
|
|
68
|
+
...(request.body === undefined ? {} : { "content-type": "application/json; charset=utf-8" }),
|
|
69
|
+
},
|
|
70
|
+
body: request.body === undefined ? undefined : JSON.stringify(request.body),
|
|
71
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
72
|
+
});
|
|
73
|
+
text = await response.text();
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw new Error(formatTransportFailure(error, transport));
|
|
77
|
+
}
|
|
78
|
+
if (!response.ok)
|
|
79
|
+
throw new Error(formatApiFailure(response.status, text, context));
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(text);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new Error(formatInvalidJsonFailure(error, text, transport));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function postJson(path, body, timeoutMs) {
|
|
88
|
+
return requestJson({ method: "POST", path, body, timeoutMs });
|
|
89
|
+
}
|
|
90
|
+
export function putJson(path, body, timeoutMs) {
|
|
91
|
+
return requestJson({ method: "PUT", path, body, timeoutMs });
|
|
92
|
+
}
|
|
93
|
+
export function deleteJson(path, body, timeoutMs) {
|
|
94
|
+
return requestJson({ method: "DELETE", path, body, timeoutMs });
|
|
95
|
+
}
|
|
96
|
+
export function methodJson(method, path, timeoutMs, body) {
|
|
97
|
+
return requestJson({ method, path, body, timeoutMs });
|
|
98
|
+
}
|
|
99
|
+
export function getJson(path, timeoutMs = aiMemoryStatusTimeoutMs()) {
|
|
100
|
+
return requestJson({ method: "GET", path, timeoutMs });
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=ai-memory-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-memory-http.js","sourceRoot":"","sources":["../../../src/prism-extensions/integrations/ai-memory-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
type ExtensionAPI = any;
|
|
2
2
|
import { type ThemeLike } from "../ui/tool-call-rendering.js";
|
|
3
|
+
/** Test hook: drop injection caches and one-shot failure notices. */
|
|
4
|
+
export declare function resetAiMemoryCaches(): void;
|
|
3
5
|
export declare function shouldEnableAiMemory(env?: NodeJS.ProcessEnv): boolean;
|
|
4
6
|
export declare function shouldInjectAiMemoryCandidates(env?: NodeJS.ProcessEnv): boolean;
|
|
7
|
+
export declare function shouldInjectAiMemoryAlwaysContext(env?: NodeJS.ProcessEnv): boolean;
|
|
5
8
|
export declare function formatSearchResponse(data: any): string;
|
|
6
9
|
export declare function formatAiMemoryCandidate(row: any): string;
|
|
7
10
|
export declare function buildAiMemoryContextMessage(results: any[]): any | undefined;
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { readSettings } from "../core/shared-config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { formatDegradedNotice } from "./ai-memory-errors.js";
|
|
4
|
+
import { aiMemoryBaseUrl, configuredAiMemoryBaseUrl, aiMemoryInjectCacheTtlMs, aiMemoryInjectTimeoutMs, aiMemoryRequestTimeoutMs, aiMemoryStatusTimeoutMs, deleteJson, getJson, methodJson, postJson, putJson, } from "./ai-memory-http.js";
|
|
5
|
+
import { isAiMemoryWriteTool, renderAiMemoryWriteResult } from "./ai-memory-write-preview.js";
|
|
4
6
|
import { renderCollapsibleTextResult } from "../ui/collapsed-text-rendering.js";
|
|
5
7
|
import { obsidianOpenUrl } from "./obsidian-memory.js";
|
|
6
8
|
import { ansiHyperlink, formatBracketedToolCall, renderSingleLineToolCall } from "../ui/tool-call-rendering.js";
|
|
7
|
-
const DEFAULT_BASE_URL = "http://127.0.0.1:8765";
|
|
8
9
|
const DEFAULT_LIMIT = 8;
|
|
9
10
|
const DEFAULT_CONTEXT_LIMIT = 5;
|
|
10
11
|
const DEFAULT_CONTEXT_SCORE_THRESHOLD = 0.15;
|
|
11
|
-
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
12
|
-
const DEFAULT_STATUS_TIMEOUT_MS = 1_500;
|
|
13
|
-
const DEFAULT_INJECT_TIMEOUT_MS = 1_200;
|
|
14
|
-
const DEFAULT_INJECT_CACHE_TTL_MS = 60_000;
|
|
15
12
|
const DEFAULT_ALWAYS_CONTEXT_CACHE_TTL_MS = 60_000;
|
|
16
13
|
const injectCache = new Map();
|
|
17
14
|
const alwaysContextCache = { expiresAt: 0, content: "" };
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const reportedBackgroundFailures = new Set();
|
|
16
|
+
/** Test hook: drop injection caches and one-shot failure notices. */
|
|
17
|
+
export function resetAiMemoryCaches() {
|
|
18
|
+
injectCache.clear();
|
|
19
|
+
alwaysContextCache.expiresAt = 0;
|
|
20
|
+
alwaysContextCache.content = "";
|
|
21
|
+
reportedBackgroundFailures.clear();
|
|
20
22
|
}
|
|
21
23
|
function clampLimit(value, fallback = DEFAULT_LIMIT) {
|
|
22
24
|
const parsed = Number(value);
|
|
@@ -48,7 +50,7 @@ export function shouldEnableAiMemory(env = process.env) {
|
|
|
48
50
|
return envValue;
|
|
49
51
|
const settings = readSettings(undefined, env);
|
|
50
52
|
const settingsValue = booleanSetting(settings?.aiMemory?.enabled ?? settings?.aiMemoryEnabled);
|
|
51
|
-
return settingsValue ??
|
|
53
|
+
return settingsValue ?? configuredAiMemoryBaseUrl(env) !== undefined;
|
|
52
54
|
}
|
|
53
55
|
export function shouldInjectAiMemoryCandidates(env = process.env) {
|
|
54
56
|
const envValue = booleanSetting(env.PRISM_AI_MEMORY_INJECT_CANDIDATES ?? env.PI_AI_MEMORY_INJECT_CANDIDATES);
|
|
@@ -56,7 +58,15 @@ export function shouldInjectAiMemoryCandidates(env = process.env) {
|
|
|
56
58
|
return envValue;
|
|
57
59
|
const settings = readSettings(undefined, env);
|
|
58
60
|
const settingsValue = booleanSetting(settings?.aiMemory?.injectCandidates ?? settings?.aiMemoryInjectCandidates);
|
|
59
|
-
return settingsValue ??
|
|
61
|
+
return settingsValue ?? configuredAiMemoryBaseUrl(env) !== undefined;
|
|
62
|
+
}
|
|
63
|
+
export function shouldInjectAiMemoryAlwaysContext(env = process.env) {
|
|
64
|
+
const envValue = booleanSetting(env.PRISM_AI_MEMORY_INJECT_ALWAYS_CONTEXT ?? env.PI_AI_MEMORY_INJECT_ALWAYS_CONTEXT);
|
|
65
|
+
if (envValue !== undefined)
|
|
66
|
+
return envValue;
|
|
67
|
+
const settings = readSettings(undefined, env);
|
|
68
|
+
const settingsValue = booleanSetting(settings?.aiMemory?.injectAlwaysContext ?? settings?.aiMemoryInjectAlwaysContext);
|
|
69
|
+
return settingsValue ?? configuredAiMemoryBaseUrl(env) !== undefined;
|
|
60
70
|
}
|
|
61
71
|
function aiMemoryContextLimit(env = process.env) {
|
|
62
72
|
return clampLimit(env.PRISM_AI_MEMORY_CONTEXT_LIMIT ?? env.PI_AI_MEMORY_CONTEXT_LIMIT, DEFAULT_CONTEXT_LIMIT);
|
|
@@ -65,24 +75,6 @@ function aiMemoryContextScoreThreshold(env = process.env) {
|
|
|
65
75
|
const parsed = Number(env.PRISM_AI_MEMORY_CONTEXT_SCORE_THRESHOLD ?? env.PI_AI_MEMORY_CONTEXT_SCORE_THRESHOLD);
|
|
66
76
|
return Number.isFinite(parsed) ? Math.max(0, parsed) : DEFAULT_CONTEXT_SCORE_THRESHOLD;
|
|
67
77
|
}
|
|
68
|
-
function positiveIntegerSetting(value, fallback) {
|
|
69
|
-
const parsed = Number(value);
|
|
70
|
-
if (!Number.isFinite(parsed))
|
|
71
|
-
return fallback;
|
|
72
|
-
return Math.max(1, Math.trunc(parsed));
|
|
73
|
-
}
|
|
74
|
-
function aiMemoryRequestTimeoutMs(env = process.env) {
|
|
75
|
-
return positiveIntegerSetting(env.PRISM_AI_MEMORY_TIMEOUT_MS ?? env.PI_AI_MEMORY_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
76
|
-
}
|
|
77
|
-
function aiMemoryStatusTimeoutMs(env = process.env) {
|
|
78
|
-
return positiveIntegerSetting(env.PRISM_AI_MEMORY_STATUS_TIMEOUT_MS ?? env.PI_AI_MEMORY_STATUS_TIMEOUT_MS, DEFAULT_STATUS_TIMEOUT_MS);
|
|
79
|
-
}
|
|
80
|
-
function aiMemoryInjectTimeoutMs(env = process.env) {
|
|
81
|
-
return positiveIntegerSetting(env.PRISM_AI_MEMORY_INJECT_TIMEOUT_MS ?? env.PI_AI_MEMORY_INJECT_TIMEOUT_MS, DEFAULT_INJECT_TIMEOUT_MS);
|
|
82
|
-
}
|
|
83
|
-
function aiMemoryInjectCacheTtlMs(env = process.env) {
|
|
84
|
-
return positiveIntegerSetting(env.PRISM_AI_MEMORY_INJECT_CACHE_TTL_MS ?? env.PI_AI_MEMORY_INJECT_CACHE_TTL_MS, DEFAULT_INJECT_CACHE_TTL_MS);
|
|
85
|
-
}
|
|
86
78
|
function cleanFilters(params) {
|
|
87
79
|
const filters = {};
|
|
88
80
|
for (const key of ["source", "project", "type", "status", "tag", "path"]) {
|
|
@@ -92,76 +84,6 @@ function cleanFilters(params) {
|
|
|
92
84
|
}
|
|
93
85
|
return filters;
|
|
94
86
|
}
|
|
95
|
-
async function postJson(path, body, timeoutMs = aiMemoryRequestTimeoutMs()) {
|
|
96
|
-
const baseUrl = aiMemoryBaseUrl();
|
|
97
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
98
|
-
method: "POST",
|
|
99
|
-
headers: { "content-type": "application/json; charset=utf-8", accept: "application/json" },
|
|
100
|
-
body: JSON.stringify(body),
|
|
101
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
102
|
-
});
|
|
103
|
-
const text = await response.text();
|
|
104
|
-
if (!response.ok) {
|
|
105
|
-
const payload = body;
|
|
106
|
-
throw new Error(formatApiFailure(response.status, text, {
|
|
107
|
-
method: "POST",
|
|
108
|
-
path,
|
|
109
|
-
query: typeof payload?.query === "string" ? payload.query : undefined,
|
|
110
|
-
filters: payload?.filters,
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
113
|
-
return JSON.parse(text);
|
|
114
|
-
}
|
|
115
|
-
async function putJson(path, body, timeoutMs = aiMemoryRequestTimeoutMs()) {
|
|
116
|
-
const baseUrl = aiMemoryBaseUrl();
|
|
117
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
118
|
-
method: "PUT",
|
|
119
|
-
headers: { "content-type": "application/json; charset=utf-8", accept: "application/json" },
|
|
120
|
-
body: JSON.stringify(body),
|
|
121
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
122
|
-
});
|
|
123
|
-
const text = await response.text();
|
|
124
|
-
if (!response.ok)
|
|
125
|
-
throw new Error(formatApiFailure(response.status, text, { method: "PUT", path }));
|
|
126
|
-
return JSON.parse(text);
|
|
127
|
-
}
|
|
128
|
-
async function deleteJson(path, body, timeoutMs = aiMemoryRequestTimeoutMs()) {
|
|
129
|
-
const baseUrl = aiMemoryBaseUrl();
|
|
130
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
131
|
-
method: "DELETE",
|
|
132
|
-
headers: { "content-type": "application/json; charset=utf-8", accept: "application/json" },
|
|
133
|
-
body: JSON.stringify(body),
|
|
134
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
135
|
-
});
|
|
136
|
-
const text = await response.text();
|
|
137
|
-
if (!response.ok)
|
|
138
|
-
throw new Error(formatApiFailure(response.status, text, { method: "DELETE", path }));
|
|
139
|
-
return JSON.parse(text);
|
|
140
|
-
}
|
|
141
|
-
async function methodJson(method, path, timeoutMs = aiMemoryRequestTimeoutMs(), body) {
|
|
142
|
-
const baseUrl = aiMemoryBaseUrl();
|
|
143
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
144
|
-
method,
|
|
145
|
-
headers: { accept: "application/json", ...(body === undefined ? {} : { "content-type": "application/json; charset=utf-8" }) },
|
|
146
|
-
body: body === undefined ? undefined : JSON.stringify(body),
|
|
147
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
148
|
-
});
|
|
149
|
-
const text = await response.text();
|
|
150
|
-
if (!response.ok)
|
|
151
|
-
throw new Error(formatApiFailure(response.status, text, { method, path }));
|
|
152
|
-
return JSON.parse(text);
|
|
153
|
-
}
|
|
154
|
-
async function getJson(path, timeoutMs = aiMemoryStatusTimeoutMs()) {
|
|
155
|
-
const baseUrl = aiMemoryBaseUrl();
|
|
156
|
-
const response = await fetch(`${baseUrl}${path}`, {
|
|
157
|
-
headers: { accept: "application/json" },
|
|
158
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
159
|
-
});
|
|
160
|
-
const text = await response.text();
|
|
161
|
-
if (!response.ok)
|
|
162
|
-
throw new Error(formatApiFailure(response.status, text, { method: "GET", path }));
|
|
163
|
-
return JSON.parse(text);
|
|
164
|
-
}
|
|
165
87
|
function formatSearchResults(results) {
|
|
166
88
|
if (!Array.isArray(results) || results.length === 0)
|
|
167
89
|
return "No AI Memory results found. Is the index built?";
|
|
@@ -271,12 +193,24 @@ export function formatAiMemoryToolCall(toolName, args, theme) {
|
|
|
271
193
|
const label = toolName.replace(/^ai_memory_/, "ai memory ").replace(/_/g, " ");
|
|
272
194
|
const rawValue = args?.query || args?.id || args?.path || args?.session || "";
|
|
273
195
|
const value = typeof rawValue === "string" && rawValue.trim() ? rawValue.trim() : "...";
|
|
274
|
-
const linksToVaultNote =
|
|
196
|
+
const linksToVaultNote = isAiMemoryWriteTool(toolName) || toolName === "ai_memory_vault_delete";
|
|
275
197
|
if (linksToVaultNote && value !== "...") {
|
|
276
198
|
return `${theme.fg("toolTitle", theme.bold(label))} ${theme.fg("accent", ansiHyperlink(obsidianOpenUrl(value), value))}`;
|
|
277
199
|
}
|
|
278
200
|
return formatBracketedToolCall(label, value, theme);
|
|
279
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Surface background (non-tool) failures once per distinct reason. The dedupe key
|
|
204
|
+
* ignores the per-turn query so a broken API does not warn on every prompt.
|
|
205
|
+
*/
|
|
206
|
+
function reportBackgroundFailure(ctx, label, error) {
|
|
207
|
+
const message = `AI Memory ${label} failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
208
|
+
const key = `${label}|${message.split(" | query=")[0]}`;
|
|
209
|
+
if (reportedBackgroundFailures.has(key))
|
|
210
|
+
return;
|
|
211
|
+
reportedBackgroundFailures.add(key);
|
|
212
|
+
ctx?.ui?.notify?.(message, "warning");
|
|
213
|
+
}
|
|
280
214
|
function formatVaultWriteResult(action, params, responsePath) {
|
|
281
215
|
const path = String(responsePath ?? params.path ?? "");
|
|
282
216
|
const frontmatter = params.frontmatter === undefined ? "" : String(params.frontmatter).trim();
|
|
@@ -535,8 +469,8 @@ export default function aiMemorySystemExtension(pi) {
|
|
|
535
469
|
renderCall(args, theme, context) {
|
|
536
470
|
return renderSingleLineToolCall(formatAiMemoryToolCall("ai_memory_vault_write", args, theme), context);
|
|
537
471
|
},
|
|
538
|
-
renderResult(result, options, theme) {
|
|
539
|
-
return
|
|
472
|
+
renderResult(result, options, theme, context) {
|
|
473
|
+
return renderAiMemoryWriteResult("ai_memory_vault_write", result, options, theme, context);
|
|
540
474
|
},
|
|
541
475
|
});
|
|
542
476
|
pi.registerTool({
|
|
@@ -562,8 +496,8 @@ export default function aiMemorySystemExtension(pi) {
|
|
|
562
496
|
renderCall(args, theme, context) {
|
|
563
497
|
return renderSingleLineToolCall(formatAiMemoryToolCall("ai_memory_vault_edit", args, theme), context);
|
|
564
498
|
},
|
|
565
|
-
renderResult(result, options, theme) {
|
|
566
|
-
return
|
|
499
|
+
renderResult(result, options, theme, context) {
|
|
500
|
+
return renderAiMemoryWriteResult("ai_memory_vault_edit", result, options, theme, context);
|
|
567
501
|
},
|
|
568
502
|
});
|
|
569
503
|
pi.registerTool({
|
|
@@ -606,39 +540,36 @@ export default function aiMemorySystemExtension(pi) {
|
|
|
606
540
|
.then((active) => ctx.ui.setStatus?.("ai-memory", active === true ? "🧠 local" : undefined))
|
|
607
541
|
.catch(() => ctx.ui.setStatus?.("ai-memory", undefined));
|
|
608
542
|
});
|
|
609
|
-
pi.on?.("before_agent_start", async (event) => {
|
|
543
|
+
pi.on?.("before_agent_start", async (event, ctx) => {
|
|
544
|
+
const patch = {};
|
|
610
545
|
// Always-loaded durable context (mapped from 00 Kontext) is injected as a
|
|
611
|
-
// system-prompt chunk so it remains in the cached prefix.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
return { systemPrompt: `${prev}${prev ? "\n\n" : ""}${block}` };
|
|
546
|
+
// system-prompt chunk so it remains in the cached prefix. It is opt-in so a
|
|
547
|
+
// missing local AI Memory daemon does not produce startup/per-turn warnings.
|
|
548
|
+
if (shouldInjectAiMemoryAlwaysContext()) {
|
|
549
|
+
try {
|
|
550
|
+
const alwaysBlock = buildAlwaysContextMessage(await loadAlwaysContext())?.content?.trim();
|
|
551
|
+
if (alwaysBlock) {
|
|
552
|
+
const prev = String(event?.systemPrompt ?? "");
|
|
553
|
+
patch.systemPrompt = `${prev}${prev ? "\n\n" : ""}${alwaysBlock}`;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
reportBackgroundFailure(ctx, "always-context injection", error);
|
|
558
|
+
}
|
|
625
559
|
}
|
|
626
|
-
// Query-specific candidates
|
|
627
|
-
if (!shouldInjectAiMemoryCandidates())
|
|
628
|
-
return;
|
|
560
|
+
// Query-specific candidates (independent of the always-context block).
|
|
629
561
|
const query = String(event?.prompt ?? "").trim();
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
// remains available and will surface API errors when the model calls it.
|
|
640
|
-
return undefined;
|
|
562
|
+
if (shouldInjectAiMemoryCandidates() && query) {
|
|
563
|
+
try {
|
|
564
|
+
const message = buildAiMemoryContextMessage(await loadAiMemoryInjectResults(query));
|
|
565
|
+
if (message)
|
|
566
|
+
patch.message = message;
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
reportBackgroundFailure(ctx, "candidate injection", error);
|
|
570
|
+
}
|
|
641
571
|
}
|
|
572
|
+
return patch.systemPrompt === undefined && patch.message === undefined ? undefined : patch;
|
|
642
573
|
});
|
|
643
574
|
}
|
|
644
575
|
//# sourceMappingURL=ai-memory-system.js.map
|