@oh-my-pi/pi-mnemopi 18.14.2 → 18.16.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.
@@ -5,6 +5,8 @@ export declare function envOptionalString(name: string, env?: Env): string | und
5
5
  export declare function envTruthy(name: string, env?: Env): boolean;
6
6
  export declare function envDisabled(name: string, env?: Env): boolean;
7
7
  export declare function envBool(name: string, defaultValue: boolean, env?: Env): boolean;
8
+ /** Unset or blank → `defaultValue`; otherwise true only for `1`/`true`/`yes`/`on`, so a malformed value disables. */
9
+ export declare function envFlag(name: string, defaultValue: boolean, env?: Env): boolean;
8
10
  export declare function envInt(name: string, defaultValue: number, env?: Env): number;
9
11
  export declare function envFloat(name: string, defaultValue: number, env?: Env): number;
10
12
  export declare function envOneOf<T extends string>(name: string, allowed: readonly T[], defaultValue: T, env?: Env): T;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-mnemopi",
4
- "version": "18.14.2",
4
+ "version": "18.16.0",
5
5
  "description": "Local SQLite memory engine for omp agents",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": {
@@ -42,10 +42,10 @@
42
42
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
43
43
  },
44
44
  "dependencies": {
45
- "@oh-my-pi/pi-ai": "18.14.2",
46
- "@oh-my-pi/pi-catalog": "18.14.2",
47
- "@oh-my-pi/pi-natives": "18.14.2",
48
- "@oh-my-pi/pi-utils": "18.14.2"
45
+ "@oh-my-pi/pi-ai": "18.16.0",
46
+ "@oh-my-pi/pi-catalog": "18.16.0",
47
+ "@oh-my-pi/pi-natives": "18.16.0",
48
+ "@oh-my-pi/pi-utils": "18.16.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "fastembed": "3.0.0",
@@ -1,4 +1,4 @@
1
- import { withLoopPhase } from "@oh-my-pi/pi-utils";
1
+ import { isRecord, withLoopPhase } from "@oh-my-pi/pi-utils";
2
2
  import { getDiagnostics, safeForLog } from "./extraction/diagnostics";
3
3
  import { callHostLlm, getHostLlmBackend } from "./llm-backends";
4
4
  import {
@@ -12,29 +12,14 @@ import {
12
12
  } from "./local-llm";
13
13
  import { getMnemopiRuntimeOptions } from "./runtime-options";
14
14
  import { clipToWindow, DEFAULT_INPUT_CHARS } from "./text-window";
15
-
16
- const TRUE_VALUES: Record<string, true> = { "1": true, true: true, yes: true, on: true };
17
-
18
- function env(name: string): string {
19
- return process.env[name] ?? "";
20
- }
21
-
22
- function envBool(name: string, defaultValue: boolean): boolean {
23
- const value = env(name).trim().toLowerCase();
24
- return value === "" ? defaultValue : TRUE_VALUES[value] === true;
25
- }
26
-
27
- function envInt(name: string, defaultValue: number): number {
28
- const parsed = Number.parseInt(env(name), 10);
29
- return Number.isFinite(parsed) ? parsed : defaultValue;
30
- }
15
+ import { envFlag, envInt, envString } from "../util/env";
31
16
 
32
17
  function llmEnabled(): boolean {
33
- return envBool("MNEMOPI_LLM_ENABLED", true);
18
+ return envFlag("MNEMOPI_LLM_ENABLED", true);
34
19
  }
35
20
 
36
21
  function hostLlmEnabled(): boolean {
37
- return envBool("MNEMOPI_HOST_LLM_ENABLED", false);
22
+ return envFlag("MNEMOPI_HOST_LLM_ENABLED", false);
38
23
  }
39
24
 
40
25
  function llmMaxTokens(): number {
@@ -42,7 +27,7 @@ function llmMaxTokens(): number {
42
27
  }
43
28
 
44
29
  export const EXTRACTION_PROMPT_TEMPLATE =
45
- env("MNEMOPI_EXTRACTION_PROMPT") ||
30
+ envString("MNEMOPI_EXTRACTION_PROMPT") ||
46
31
  `You are an expert structured memory extractor for Mnemopi v3.0+ MEMORIA tables.
47
32
  The user message below may be in English, German, Russian, or another language.
48
33
  First detect the language, then extract ONLY high-signal, long-term relevant items.
@@ -159,10 +144,6 @@ function normalizeFactArray(items: unknown, options: FactArrayOptions): string[]
159
144
  return out;
160
145
  }
161
146
 
162
- function isRecord(value: unknown): value is Record<string, unknown> {
163
- return value !== null && typeof value === "object" && !Array.isArray(value);
164
- }
165
-
166
147
  function triplePart(value: unknown): string {
167
148
  return typeof value === "string" ? normalizeFact(value) : "";
168
149
  }
@@ -341,8 +322,8 @@ async function tryHostExtraction(prompt: string): Promise<[boolean, string | nul
341
322
  maxTokens: llmMaxTokens(),
342
323
  temperature: 0,
343
324
  timeout: 15,
344
- provider: env("MNEMOPI_HOST_LLM_PROVIDER").trim() || null,
345
- model: env("MNEMOPI_HOST_LLM_MODEL").trim() || null,
325
+ provider: envString("MNEMOPI_HOST_LLM_PROVIDER").trim() || null,
326
+ model: envString("MNEMOPI_HOST_LLM_MODEL").trim() || null,
346
327
  });
347
328
  const text = typeof raw === "string" ? raw.trim() : "";
348
329
  return [true, text === "" ? null : text];
@@ -11,6 +11,7 @@ import {
11
11
  import { ProviderHttpError } from "@oh-my-pi/pi-ai/error";
12
12
  import { fetchWithRetry } from "@oh-my-pi/pi-utils";
13
13
  import { type CompleteOptions, callHostLlm, getHostLlmBackend } from "./llm-backends";
14
+ import { envFlag, envInt, envString } from "../util/env";
14
15
  import {
15
16
  getMnemopiRuntimeOptions,
16
17
  isPiAiModel,
@@ -29,12 +30,6 @@ export const DEFAULT_MODEL_REPO =
29
30
  export const DEFAULT_MODEL_FILE =
30
31
  ENV_MODEL_REPO !== "" && ENV_MODEL_FILE !== "" ? ENV_MODEL_FILE : "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf";
31
32
 
32
- const TRUE_VALUES: Record<string, true> = { "1": true, true: true, yes: true, on: true };
33
-
34
- function env(name: string): string {
35
- return process.env[name] ?? "";
36
- }
37
-
38
33
  function activeLlmOptions() {
39
34
  return getMnemopiRuntimeOptions()?.llm;
40
35
  }
@@ -48,16 +43,6 @@ function activePiAiModel(): Model<Api> | undefined {
48
43
  return isPiAiModel(model) ? model : undefined;
49
44
  }
50
45
 
51
- function envBool(name: string, defaultValue: boolean): boolean {
52
- const value = env(name).trim().toLowerCase();
53
- return value === "" ? defaultValue : TRUE_VALUES[value] === true;
54
- }
55
-
56
- function envInt(name: string, defaultValue: number): number {
57
- const parsed = Number.parseInt(env(name), 10);
58
- return Number.isFinite(parsed) ? parsed : defaultValue;
59
- }
60
-
61
46
  function stripTrailingSlash(value: string): string {
62
47
  let end = value.length;
63
48
  while (end > 0 && value.charCodeAt(end - 1) === 47) {
@@ -74,7 +59,7 @@ function llmEnabled(): boolean {
74
59
  if (activeCustomCompletion() !== undefined || activePiAiModel() !== undefined) {
75
60
  return true;
76
61
  }
77
- return envBool("MNEMOPI_LLM_ENABLED", true);
62
+ return envFlag("MNEMOPI_LLM_ENABLED", true);
78
63
  }
79
64
 
80
65
  function llmMaxTokens(): number {
@@ -97,7 +82,7 @@ function hostLlmEnabled(): boolean {
97
82
  if (active?.baseUrl !== undefined || (typeof active?.model === "string" && active.model !== "")) {
98
83
  return false;
99
84
  }
100
- return envBool("MNEMOPI_HOST_LLM_ENABLED", false);
85
+ return envFlag("MNEMOPI_HOST_LLM_ENABLED", false);
101
86
  }
102
87
 
103
88
  function hostLlmContextTokens(): number {
@@ -109,7 +94,7 @@ function llmBaseUrl(): string {
109
94
  if (active?.baseUrl !== undefined) {
110
95
  return stripTrailingSlash(active.baseUrl);
111
96
  }
112
- return stripTrailingSlash(env("MNEMOPI_LLM_BASE_URL"));
97
+ return stripTrailingSlash(envString("MNEMOPI_LLM_BASE_URL"));
113
98
  }
114
99
 
115
100
  function llmModelName(): string {
@@ -117,7 +102,7 @@ function llmModelName(): string {
117
102
  if (typeof model === "string") {
118
103
  return model;
119
104
  }
120
- return env("MNEMOPI_LLM_MODEL") || "local";
105
+ return envString("MNEMOPI_LLM_MODEL") || "local";
121
106
  }
122
107
 
123
108
  function llmApiKey(): ApiKey {
@@ -125,11 +110,11 @@ function llmApiKey(): ApiKey {
125
110
  if (active?.apiKey !== undefined) {
126
111
  return active.apiKey;
127
112
  }
128
- return env("MNEMOPI_LLM_API_KEY");
113
+ return envString("MNEMOPI_LLM_API_KEY");
129
114
  }
130
115
 
131
116
  function sleepPrompt(): string {
132
- return env("MNEMOPI_SLEEP_PROMPT").trim();
117
+ return envString("MNEMOPI_SLEEP_PROMPT").trim();
133
118
  }
134
119
 
135
120
  function memoryLines(memories: readonly string[]): string {
@@ -248,8 +233,8 @@ async function tryHostLlm(prompt: string, maxTokens: number, temperature: number
248
233
  maxTokens,
249
234
  temperature,
250
235
  timeout: 15,
251
- provider: env("MNEMOPI_HOST_LLM_PROVIDER").trim() || null,
252
- model: env("MNEMOPI_HOST_LLM_MODEL").trim() || null,
236
+ provider: envString("MNEMOPI_HOST_LLM_PROVIDER").trim() || null,
237
+ model: envString("MNEMOPI_HOST_LLM_MODEL").trim() || null,
253
238
  });
254
239
  const text = typeof raw === "string" ? raw.trim() : "";
255
240
  return [true, text === "" ? null : text];
@@ -418,7 +403,7 @@ async function summarizeChunk(
418
403
  return null;
419
404
  }
420
405
 
421
- if (llmEnabled() && llmBaseUrl() !== "" && !envBool("MNEMOPI_FORCE_LOCAL", false)) {
406
+ if (llmEnabled() && llmBaseUrl() !== "" && !envFlag("MNEMOPI_FORCE_LOCAL", false)) {
422
407
  const raw = await callRemoteLlm(prompt, 0.3, options);
423
408
  if (raw !== null) {
424
409
  const cleaned = cleanOutput(raw);
@@ -475,7 +460,7 @@ export async function complete(
475
460
  if (attempted) {
476
461
  return hostText;
477
462
  }
478
- if (llmEnabled() && llmBaseUrl() !== "" && !envBool("MNEMOPI_FORCE_LOCAL", false)) {
463
+ if (llmEnabled() && llmBaseUrl() !== "" && !envFlag("MNEMOPI_FORCE_LOCAL", false)) {
479
464
  const remote = await callRemoteLlm(prompt, temperature, options);
480
465
  return remote === null ? null : cleanOutput(remote) || null;
481
466
  }
package/src/util/env.ts CHANGED
@@ -36,6 +36,13 @@ export function envBool(name: string, defaultValue: boolean, env: Env = process.
36
36
  return defaultValue;
37
37
  }
38
38
 
39
+ /** Unset or blank → `defaultValue`; otherwise true only for `1`/`true`/`yes`/`on`, so a malformed value disables. */
40
+ export function envFlag(name: string, defaultValue: boolean, env: Env = process.env): boolean {
41
+ const value = env[name]?.trim().toLowerCase();
42
+ if (!value) return defaultValue;
43
+ return TRUE_VALUES[value] === true;
44
+ }
45
+
39
46
  export function envInt(name: string, defaultValue: number, env: Env = process.env): number {
40
47
  const raw = env[name]?.trim();
41
48
  if (!raw) return defaultValue;