@prometheus-ai/memory 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +107 -0
  2. package/dist/types/cli.d.ts +35 -0
  3. package/dist/types/config.d.ts +77 -0
  4. package/dist/types/core/aaak.d.ts +55 -0
  5. package/dist/types/core/annotations.d.ts +75 -0
  6. package/dist/types/core/banks.d.ts +33 -0
  7. package/dist/types/core/beam/consolidate.d.ts +32 -0
  8. package/dist/types/core/beam/helpers.d.ts +76 -0
  9. package/dist/types/core/beam/index.d.ts +59 -0
  10. package/dist/types/core/beam/recall.d.ts +32 -0
  11. package/dist/types/core/beam/schema.d.ts +2 -0
  12. package/dist/types/core/beam/store.d.ts +35 -0
  13. package/dist/types/core/beam/types.d.ts +233 -0
  14. package/dist/types/core/binary-vectors.d.ts +54 -0
  15. package/dist/types/core/chat-normalize.d.ts +13 -0
  16. package/dist/types/core/content-sanitizer.d.ts +18 -0
  17. package/dist/types/core/cost-log.d.ts +13 -0
  18. package/dist/types/core/embeddings.d.ts +44 -0
  19. package/dist/types/core/entities.d.ts +7 -0
  20. package/dist/types/core/episodic-graph.d.ts +89 -0
  21. package/dist/types/core/extraction/client.d.ts +31 -0
  22. package/dist/types/core/extraction/diagnostics.d.ts +51 -0
  23. package/dist/types/core/extraction/prompts.d.ts +2 -0
  24. package/dist/types/core/extraction.d.ts +6 -0
  25. package/dist/types/core/index.d.ts +4 -0
  26. package/dist/types/core/llm-backends.d.ts +21 -0
  27. package/dist/types/core/local-llm.d.ts +15 -0
  28. package/dist/types/core/memory.d.ts +160 -0
  29. package/dist/types/core/migrations/e6-triplestore-split.d.ts +17 -0
  30. package/dist/types/core/migrations/index.d.ts +1 -0
  31. package/dist/types/core/mmr.d.ts +8 -0
  32. package/dist/types/core/orchestrator.d.ts +20 -0
  33. package/dist/types/core/patterns.d.ts +61 -0
  34. package/dist/types/core/plugins.d.ts +109 -0
  35. package/dist/types/core/polyphonic-recall.d.ts +66 -0
  36. package/dist/types/core/query-cache.d.ts +46 -0
  37. package/dist/types/core/query-intent.d.ts +20 -0
  38. package/dist/types/core/recall-diagnostics.d.ts +48 -0
  39. package/dist/types/core/runtime-options.d.ts +68 -0
  40. package/dist/types/core/shmr.d.ts +56 -0
  41. package/dist/types/core/streaming.d.ts +136 -0
  42. package/dist/types/core/synonyms.d.ts +46 -0
  43. package/dist/types/core/temporal-parser.d.ts +16 -0
  44. package/dist/types/core/token-counter.d.ts +8 -0
  45. package/dist/types/core/triples.d.ts +63 -0
  46. package/dist/types/core/typed-memory.d.ts +39 -0
  47. package/dist/types/core/vector-math.d.ts +1 -0
  48. package/dist/types/core/veracity-consolidation.d.ts +60 -0
  49. package/dist/types/core/weibull.d.ts +96 -0
  50. package/dist/types/db.d.ts +16 -0
  51. package/dist/types/diagnose.d.ts +24 -0
  52. package/dist/types/dr/index.d.ts +1 -0
  53. package/dist/types/dr/recovery.d.ts +68 -0
  54. package/dist/types/index.d.ts +5 -0
  55. package/dist/types/mcp-server.d.ts +40 -0
  56. package/dist/types/mcp-tools.d.ts +484 -0
  57. package/dist/types/migrations/e6-triplestore-split.d.ts +1 -0
  58. package/dist/types/migrations/index.d.ts +1 -0
  59. package/dist/types/types.d.ts +145 -0
  60. package/dist/types/util/datetime.d.ts +8 -0
  61. package/dist/types/util/env.d.ts +10 -0
  62. package/dist/types/util/ids.d.ts +3 -0
  63. package/dist/types/util/lru.d.ts +12 -0
  64. package/dist/types/util/regex.d.ts +10 -0
  65. package/package.json +85 -0
  66. package/src/cli.ts +398 -0
  67. package/src/config.ts +326 -0
  68. package/src/core/aaak.ts +142 -0
  69. package/src/core/annotations.ts +457 -0
  70. package/src/core/banks.ts +133 -0
  71. package/src/core/beam/consolidate.ts +965 -0
  72. package/src/core/beam/helpers.ts +977 -0
  73. package/src/core/beam/index.ts +353 -0
  74. package/src/core/beam/recall.ts +1100 -0
  75. package/src/core/beam/schema.ts +423 -0
  76. package/src/core/beam/store.ts +829 -0
  77. package/src/core/beam/types.ts +268 -0
  78. package/src/core/binary-vectors.ts +317 -0
  79. package/src/core/chat-normalize.ts +160 -0
  80. package/src/core/content-sanitizer.ts +136 -0
  81. package/src/core/cost-log.ts +103 -0
  82. package/src/core/embeddings.ts +423 -0
  83. package/src/core/entities.ts +259 -0
  84. package/src/core/episodic-graph.ts +708 -0
  85. package/src/core/extraction/client.ts +162 -0
  86. package/src/core/extraction/diagnostics.ts +193 -0
  87. package/src/core/extraction/prompts.ts +31 -0
  88. package/src/core/extraction.ts +335 -0
  89. package/src/core/index.ts +30 -0
  90. package/src/core/llm-backends.ts +51 -0
  91. package/src/core/local-llm.ts +436 -0
  92. package/src/core/memory.ts +630 -0
  93. package/src/core/migrations/e6-triplestore-split.ts +211 -0
  94. package/src/core/migrations/index.ts +1 -0
  95. package/src/core/mmr.ts +71 -0
  96. package/src/core/orchestrator.ts +62 -0
  97. package/src/core/patterns.ts +484 -0
  98. package/src/core/plugins.ts +375 -0
  99. package/src/core/polyphonic-recall.ts +563 -0
  100. package/src/core/query-cache.ts +354 -0
  101. package/src/core/query-intent.ts +139 -0
  102. package/src/core/recall-diagnostics.ts +157 -0
  103. package/src/core/runtime-options.ts +119 -0
  104. package/src/core/shmr.ts +460 -0
  105. package/src/core/streaming.ts +419 -0
  106. package/src/core/synonyms.ts +197 -0
  107. package/src/core/temporal-parser.ts +363 -0
  108. package/src/core/token-counter.ts +30 -0
  109. package/src/core/triples.ts +454 -0
  110. package/src/core/typed-memory.ts +407 -0
  111. package/src/core/vector-math.ts +23 -0
  112. package/src/core/veracity-consolidation.ts +477 -0
  113. package/src/core/weibull.ts +124 -0
  114. package/src/db.ts +128 -0
  115. package/src/diagnose.ts +174 -0
  116. package/src/dr/index.ts +1 -0
  117. package/src/dr/recovery.ts +405 -0
  118. package/src/index.ts +33 -0
  119. package/src/mcp-server.ts +155 -0
  120. package/src/mcp-tools.ts +970 -0
  121. package/src/migrations/e6-triplestore-split.ts +1 -0
  122. package/src/migrations/index.ts +1 -0
  123. package/src/types.ts +157 -0
  124. package/src/util/datetime.ts +69 -0
  125. package/src/util/env.ts +65 -0
  126. package/src/util/ids.ts +19 -0
  127. package/src/util/lru.ts +48 -0
  128. package/src/util/regex.ts +165 -0
@@ -0,0 +1,436 @@
1
+ import { type Api, type AssistantMessage, completeSimple, type Model } from "@prometheus-ai/ai";
2
+ import { callHostLlm, getHostLlmBackend } from "./llm-backends";
3
+ import {
4
+ getMnemopiRuntimeOptions,
5
+ isPiAiModel,
6
+ type MnemopiLlmCompleteOptions,
7
+ type MnemopiLlmCompletion,
8
+ } from "./runtime-options";
9
+
10
+ const ENV_MODEL_REPO = process.env.PROMETHEUS_MEMORY_LLM_REPO ?? "";
11
+ const ENV_MODEL_FILE = process.env.PROMETHEUS_MEMORY_LLM_FILE ?? "";
12
+ export const DEFAULT_MODEL_REPO =
13
+ ENV_MODEL_REPO !== "" && ENV_MODEL_FILE !== "" ? ENV_MODEL_REPO : "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF";
14
+ export const DEFAULT_MODEL_FILE =
15
+ ENV_MODEL_REPO !== "" && ENV_MODEL_FILE !== "" ? ENV_MODEL_FILE : "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf";
16
+
17
+ const TRUE_VALUES: Record<string, true> = { "1": true, true: true, yes: true, on: true };
18
+
19
+ function env(name: string): string {
20
+ return process.env[name] ?? "";
21
+ }
22
+
23
+ function activeLlmOptions() {
24
+ return getMnemopiRuntimeOptions()?.llm;
25
+ }
26
+
27
+ function activeCustomCompletion(): MnemopiLlmCompletion | undefined {
28
+ return activeLlmOptions()?.complete;
29
+ }
30
+
31
+ function activePiAiModel(): Model<Api> | undefined {
32
+ const model = activeLlmOptions()?.model;
33
+ return isPiAiModel(model) ? model : undefined;
34
+ }
35
+
36
+ function envBool(name: string, defaultValue: boolean): boolean {
37
+ const value = env(name).trim().toLowerCase();
38
+ return value === "" ? defaultValue : TRUE_VALUES[value] === true;
39
+ }
40
+
41
+ function envInt(name: string, defaultValue: number): number {
42
+ const parsed = Number.parseInt(env(name), 10);
43
+ return Number.isFinite(parsed) ? parsed : defaultValue;
44
+ }
45
+
46
+ function stripTrailingSlash(value: string): string {
47
+ let end = value.length;
48
+ while (end > 0 && value.charCodeAt(end - 1) === 47) {
49
+ end -= 1;
50
+ }
51
+ return end === value.length ? value : value.slice(0, end);
52
+ }
53
+
54
+ function llmEnabled(): boolean {
55
+ const active = activeLlmOptions();
56
+ if (active?.enabled !== undefined) {
57
+ return active.enabled;
58
+ }
59
+ if (activeCustomCompletion() !== undefined || activePiAiModel() !== undefined) {
60
+ return true;
61
+ }
62
+ return envBool("PROMETHEUS_MEMORY_LLM_ENABLED", true);
63
+ }
64
+
65
+ function llmMaxTokens(): number {
66
+ const active = activeLlmOptions();
67
+ if (active?.maxTokens !== undefined) {
68
+ return active.maxTokens;
69
+ }
70
+ return envInt("PROMETHEUS_MEMORY_LLM_MAX_TOKENS", 2048);
71
+ }
72
+
73
+ function llmContextTokens(): number {
74
+ return envInt("PROMETHEUS_MEMORY_LLM_N_CTX", 2048);
75
+ }
76
+
77
+ function hostLlmEnabled(): boolean {
78
+ if (activeCustomCompletion() !== undefined || activePiAiModel() !== undefined) {
79
+ return false;
80
+ }
81
+ const active = activeLlmOptions();
82
+ if (active?.baseUrl !== undefined || (typeof active?.model === "string" && active.model !== "")) {
83
+ return false;
84
+ }
85
+ return envBool("PROMETHEUS_MEMORY_HOST_LLM_ENABLED", false);
86
+ }
87
+
88
+ function hostLlmContextTokens(): number {
89
+ return envInt("PROMETHEUS_MEMORY_HOST_LLM_N_CTX", 32000);
90
+ }
91
+
92
+ function llmBaseUrl(): string {
93
+ const active = activeLlmOptions();
94
+ if (active?.baseUrl !== undefined) {
95
+ return stripTrailingSlash(active.baseUrl);
96
+ }
97
+ return stripTrailingSlash(env("PROMETHEUS_MEMORY_LLM_BASE_URL"));
98
+ }
99
+
100
+ function llmModelName(): string {
101
+ const model = activeLlmOptions()?.model;
102
+ if (typeof model === "string") {
103
+ return model;
104
+ }
105
+ return env("PROMETHEUS_MEMORY_LLM_MODEL") || "local";
106
+ }
107
+
108
+ function llmApiKey(): string {
109
+ const active = activeLlmOptions();
110
+ if (active?.apiKey !== undefined) {
111
+ return active.apiKey;
112
+ }
113
+ return env("PROMETHEUS_MEMORY_LLM_API_KEY");
114
+ }
115
+
116
+ function sleepPrompt(): string {
117
+ return env("PROMETHEUS_MEMORY_SLEEP_PROMPT").trim();
118
+ }
119
+
120
+ function memoryLines(memories: readonly string[]): string {
121
+ return memories
122
+ .filter(Boolean)
123
+ .map(memory => `- ${memory}`)
124
+ .join("\n");
125
+ }
126
+
127
+ function formatSleepPrompt(memories: readonly string[], source = ""): string | null {
128
+ const override = getMnemopiRuntimeOptions()?.llm?.consolidationPrompt;
129
+ const template = override !== undefined && override !== "" ? override : sleepPrompt();
130
+ if (template === "") {
131
+ return null;
132
+ }
133
+
134
+ let rendered = template;
135
+ rendered = rendered.split("{source}").join(source);
136
+ rendered = rendered.split("{memories}").join(memoryLines(memories));
137
+ rendered = rendered.split("{memory_count}").join(String(memories.filter(Boolean).length));
138
+ return rendered;
139
+ }
140
+
141
+ export function buildPrompt(memories: readonly string[], source = ""): string {
142
+ const custom = formatSleepPrompt(memories, source);
143
+ if (custom !== null) {
144
+ return custom;
145
+ }
146
+
147
+ let header =
148
+ "Summarize the following memories into 1-3 concise sentences. Preserve facts, names, preferences, and decisions. Discard fluff.";
149
+ if (source !== "") {
150
+ header += ` Source: ${source}.`;
151
+ }
152
+ return `/no_think\n${header}\n\n${memoryLines(memories)}\n\nSummary:`;
153
+ }
154
+
155
+ export async function callConfiguredCompletion(
156
+ prompt: string,
157
+ temperature: number,
158
+ opts: MnemopiLlmCompleteOptions = {},
159
+ ): Promise<string | null> {
160
+ const completion = activeCustomCompletion();
161
+ if (completion !== undefined) {
162
+ const raw = await completion(prompt, {
163
+ maxTokens: opts.maxTokens ?? llmMaxTokens(),
164
+ temperature,
165
+ timeout: opts.timeout,
166
+ provider: opts.provider,
167
+ model: opts.model,
168
+ });
169
+ return typeof raw === "string" ? raw : null;
170
+ }
171
+ const model = activePiAiModel();
172
+ if (model === undefined) {
173
+ return null;
174
+ }
175
+ try {
176
+ const message = await completeSimple(
177
+ model,
178
+ {
179
+ messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
180
+ },
181
+ {
182
+ apiKey: llmApiKey() || undefined,
183
+ maxTokens: opts.maxTokens ?? llmMaxTokens(),
184
+ temperature,
185
+ },
186
+ );
187
+ return assistantText(message).trim() || null;
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+
193
+ function assistantText(message: AssistantMessage): string {
194
+ return message.content
195
+ .filter((block): block is Extract<AssistantMessage["content"][number], { type: "text" }> => block.type === "text")
196
+ .map(block => block.text)
197
+ .join("\n");
198
+ }
199
+
200
+ export function buildHostPrompt(memories: readonly string[], source = ""): string {
201
+ const custom = formatSleepPrompt(memories, source);
202
+ if (custom !== null) {
203
+ return custom;
204
+ }
205
+
206
+ let header =
207
+ "Summarize the following memories into 1-3 concise sentences. Preserve facts, names, preferences, and decisions. Discard fluff.";
208
+ if (source !== "") {
209
+ header += ` Source: ${source}.`;
210
+ }
211
+ return `${header}\n\n${memoryLines(memories)}`;
212
+ }
213
+
214
+ function hostBackendWillHandleCall(): boolean {
215
+ return llmEnabled() && hostLlmEnabled() && getHostLlmBackend() !== null;
216
+ }
217
+
218
+ export function configuredLlmWillHandleCall(): boolean {
219
+ return llmEnabled() && (activeCustomCompletion() !== undefined || activePiAiModel() !== undefined);
220
+ }
221
+
222
+ async function tryHostLlm(prompt: string, maxTokens: number, temperature: number): Promise<[boolean, string | null]> {
223
+ if (!hostBackendWillHandleCall()) {
224
+ return [false, null];
225
+ }
226
+
227
+ const raw = await callHostLlm(prompt, {
228
+ maxTokens,
229
+ temperature,
230
+ timeout: 15,
231
+ provider: env("PROMETHEUS_MEMORY_HOST_LLM_PROVIDER").trim() || null,
232
+ model: env("PROMETHEUS_MEMORY_HOST_LLM_MODEL").trim() || null,
233
+ });
234
+ const text = typeof raw === "string" ? raw.trim() : "";
235
+ return [true, text === "" ? null : text];
236
+ }
237
+
238
+ export function cleanOutput(text: string): string {
239
+ return text
240
+ .replaceAll("<|assistant|>", "")
241
+ .replaceAll("<|user|>", "")
242
+ .replaceAll("</s>", "")
243
+ .trim()
244
+ .replace(/^(Summarize the following memories.*?[.!?:]\s*)/is, "")
245
+ .replace(/^(Preserve facts.*?[.!?:]\s*)/is, "")
246
+ .replace(/^Source:.*?\n/im, "")
247
+ .replace(/^\s*[-*]\s.*\n/gm, "")
248
+ .trim();
249
+ }
250
+
251
+ function estimateTokens(text: string): number {
252
+ return Math.max(1, Math.floor(text.length / 4));
253
+ }
254
+
255
+ function promptTokenBudget(): number {
256
+ const overhead = 80;
257
+ const nCtx = hostBackendWillHandleCall() ? hostLlmContextTokens() : llmContextTokens();
258
+ const outputReserve = Math.min(llmMaxTokens(), Math.max(128, Math.floor(nCtx / 4)));
259
+ const safetyMargin = Math.floor(nCtx * 0.2);
260
+ return Math.max(64, nCtx - overhead - outputReserve - safetyMargin);
261
+ }
262
+
263
+ export function chunkMemoriesByBudget(memories: readonly string[], source = ""): string[][] {
264
+ if (memories.length === 0) {
265
+ return [];
266
+ }
267
+
268
+ const budget = promptTokenBudget();
269
+ const chunks: string[][] = [];
270
+ let currentChunk: string[] = [];
271
+ let currentTokens = 0;
272
+
273
+ let header =
274
+ "Summarize the following memories into 1-3 concise sentences. Preserve facts, names, preferences, and decisions. Discard fluff.";
275
+ if (source !== "") {
276
+ header += ` Source: ${source}.`;
277
+ }
278
+ const headerTokens = estimateTokens(`${header}\n\n`);
279
+ const formatOverhead = estimateTokens("- \n");
280
+ const available = budget - headerTokens;
281
+
282
+ for (const memory of memories) {
283
+ const memTokens = estimateTokens(memory) + formatOverhead;
284
+ if (memTokens > budget) {
285
+ continue;
286
+ }
287
+ if (currentTokens + memTokens > available && currentChunk.length > 0) {
288
+ chunks.push(currentChunk);
289
+ currentChunk = [];
290
+ currentTokens = 0;
291
+ }
292
+ currentChunk.push(memory);
293
+ currentTokens += memTokens;
294
+ }
295
+
296
+ if (currentChunk.length > 0) {
297
+ chunks.push(currentChunk);
298
+ }
299
+ return chunks;
300
+ }
301
+
302
+ export function llmAvailable(): boolean {
303
+ if (configuredLlmWillHandleCall()) {
304
+ return true;
305
+ }
306
+ if (hostBackendWillHandleCall()) {
307
+ return true;
308
+ }
309
+ return llmEnabled() && llmBaseUrl() !== "";
310
+ }
311
+
312
+ export async function callRemoteLlm(prompt: string, temperature = 0.3): Promise<string | null> {
313
+ const baseUrl = llmBaseUrl();
314
+ if (baseUrl === "") {
315
+ return null;
316
+ }
317
+
318
+ const headers: Record<string, string> = { "Content-Type": "application/json" };
319
+ const apiKey = llmApiKey();
320
+ if (apiKey !== "") {
321
+ headers.Authorization = `Bearer ${apiKey}`;
322
+ }
323
+
324
+ try {
325
+ const response = await fetch(`${baseUrl}/chat/completions`, {
326
+ method: "POST",
327
+ headers,
328
+ body: JSON.stringify({
329
+ model: llmModelName(),
330
+ messages: [{ role: "user", content: prompt }],
331
+ max_tokens: llmMaxTokens(),
332
+ temperature,
333
+ stop: ["</s>", "<|user|>"],
334
+ }),
335
+ signal: AbortSignal.timeout(60000),
336
+ });
337
+ if (!response.ok) {
338
+ return null;
339
+ }
340
+ const data = (await response.json()) as {
341
+ choices?: Array<{ message?: { content?: unknown } }>;
342
+ };
343
+ const content = data.choices?.[0]?.message?.content;
344
+ return typeof content === "string" ? content : null;
345
+ } catch {
346
+ return null;
347
+ }
348
+ }
349
+
350
+ export function localGgufAvailable(): false {
351
+ return false;
352
+ }
353
+
354
+ export async function callLocalLlm(_prompt: string): Promise<string | null> {
355
+ return null;
356
+ }
357
+
358
+ async function summarizeChunk(memories: readonly string[], source = ""): Promise<string | null> {
359
+ const hostPrompt = buildHostPrompt(memories, source);
360
+ const prompt = buildPrompt(memories, source);
361
+ if (configuredLlmWillHandleCall()) {
362
+ const raw = await callConfiguredCompletion(hostPrompt, 0.3, { maxTokens: llmMaxTokens() });
363
+ if (raw === null) {
364
+ return null;
365
+ }
366
+ const cleaned = cleanOutput(raw);
367
+ return cleaned === "" ? null : cleaned;
368
+ }
369
+ const [attempted, hostText] = await tryHostLlm(hostPrompt, llmMaxTokens(), 0.3);
370
+ if (attempted) {
371
+ if (hostText !== null) {
372
+ return hostText;
373
+ }
374
+ const raw = await callLocalLlm(prompt);
375
+ if (raw !== null) {
376
+ const cleaned = cleanOutput(raw);
377
+ return cleaned === "" ? null : cleaned;
378
+ }
379
+ return null;
380
+ }
381
+
382
+ if (llmEnabled() && llmBaseUrl() !== "" && !envBool("PROMETHEUS_MEMORY_FORCE_LOCAL", false)) {
383
+ const raw = await callRemoteLlm(prompt);
384
+ if (raw !== null) {
385
+ const cleaned = cleanOutput(raw);
386
+ return cleaned === "" ? null : cleaned;
387
+ }
388
+ }
389
+
390
+ const raw = await callLocalLlm(prompt);
391
+ if (raw !== null) {
392
+ const cleaned = cleanOutput(raw);
393
+ return cleaned === "" ? null : cleaned;
394
+ }
395
+ return null;
396
+ }
397
+
398
+ export async function summarizeMemories(memories: readonly string[], source = ""): Promise<string | null> {
399
+ if (memories.length === 0) {
400
+ return null;
401
+ }
402
+
403
+ const chunks = chunkMemoriesByBudget(memories, source);
404
+ const chunkSummaries: string[] = [];
405
+ for (const chunk of chunks) {
406
+ const summary = await summarizeChunk(chunk, source);
407
+ if (summary !== null) {
408
+ chunkSummaries.push(summary);
409
+ }
410
+ }
411
+
412
+ if (chunkSummaries.length === 0) {
413
+ return null;
414
+ }
415
+ if (chunkSummaries.length > 1) {
416
+ const final = await summarizeChunk(chunkSummaries, `${source} [chunked ${chunks.length} parts]`);
417
+ return final ?? chunkSummaries[0] ?? null;
418
+ }
419
+ return chunkSummaries[0] ?? null;
420
+ }
421
+
422
+ export async function complete(prompt: string, temperature = 0.3): Promise<string | null> {
423
+ if (configuredLlmWillHandleCall()) {
424
+ const raw = await callConfiguredCompletion(prompt, temperature, { maxTokens: llmMaxTokens() });
425
+ return raw === null ? null : cleanOutput(raw) || null;
426
+ }
427
+ const [attempted, hostText] = await tryHostLlm(prompt, llmMaxTokens(), temperature);
428
+ if (attempted) {
429
+ return hostText;
430
+ }
431
+ if (llmEnabled() && llmBaseUrl() !== "" && !envBool("PROMETHEUS_MEMORY_FORCE_LOCAL", false)) {
432
+ const remote = await callRemoteLlm(prompt, temperature);
433
+ return remote === null ? null : cleanOutput(remote) || null;
434
+ }
435
+ return callLocalLlm(prompt);
436
+ }