@eleboucher/pi-memini 0.7.2 → 0.7.4

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 (2) hide show
  1. package/dist/index.js +95 -48
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28,9 +28,72 @@ function validateNamespace(ns) {
28
28
  return null;
29
29
  }
30
30
 
31
+ // ../../../packages/memini-client/src/capture.ts
32
+ var TRUNCATION_MARKER = "\n[...truncated]";
33
+ function truncateForCapture(s, max) {
34
+ if (typeof max !== "number" || !Number.isFinite(max) || max <= 0) return s;
35
+ const cap = Math.floor(max);
36
+ if (s.length <= cap) return s;
37
+ let i = 0;
38
+ for (let n = 0; i < s.length && n < cap; n++) {
39
+ i += s.codePointAt(i) > 65535 ? 2 : 1;
40
+ }
41
+ if (i >= s.length) return s;
42
+ return s.slice(0, i) + TRUNCATION_MARKER;
43
+ }
44
+ function buildTurnCapture(userText, assistantText, userMax, assistantMax) {
45
+ return `${truncateForCapture(userText, userMax)}
46
+
47
+ ${truncateForCapture(assistantText, assistantMax)}`;
48
+ }
49
+
31
50
  // ../../../packages/memini-client/src/session.ts
32
51
  var SESSION_CWD_TTL_MS = 6 * 60 * 60 * 1e3;
33
52
 
53
+ // ../../../packages/memini-client/src/bootstrap.ts
54
+ var DEFAULT_TIMEOUT_MS = 3e4;
55
+ var MIN_TIMEOUT_MS = 100;
56
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
57
+ function envTimeoutMs(raw, fallback = DEFAULT_TIMEOUT_MS) {
58
+ if (raw == null || raw.trim() === "") return fallback;
59
+ const n = Number(raw.trim());
60
+ if (!Number.isFinite(n)) return fallback;
61
+ return Math.max(MIN_TIMEOUT_MS, Math.trunc(n));
62
+ }
63
+ function envEnabled(raw, defaultOn) {
64
+ if (raw == null || raw === "") return defaultOn;
65
+ return !/^(0|false|no|off)$/i.test(raw.trim());
66
+ }
67
+ function readBootstrap(env = process.env) {
68
+ return {
69
+ baseUrl: env["MEMINI_BASE_URL"] || "http://localhost:8080",
70
+ apiKey: env["MEMINI_API_KEY"] || "",
71
+ requireHttps: envEnabled(env["MEMINI_REQUIRE_HTTPS"], false),
72
+ debug: envEnabled(env["MEMINI_DEBUG"], false),
73
+ agent: env["MEMINI_AGENT"] || "",
74
+ namespaceEnv: (env["MEMINI_NAMESPACE"] || "").trim(),
75
+ namespacePrefixEnv: (env["MEMINI_NAMESPACE_PREFIX"] || "").trim(),
76
+ homeEnv: (env["MEMINI_HOME"] || "").trim(),
77
+ timeoutMs: envTimeoutMs(env["MEMINI_TIMEOUT_MS"])
78
+ };
79
+ }
80
+ function isPlaintextBearerUnsafe(baseUrl, secret) {
81
+ if (!secret) return false;
82
+ try {
83
+ const u = new URL(baseUrl);
84
+ return u.protocol === "http:" && !LOOPBACK_HOSTS.has(u.hostname.replace(/^\[|\]$/g, "").toLowerCase());
85
+ } catch {
86
+ return false;
87
+ }
88
+ }
89
+ function assertBearerTransportSafe(baseUrl, secret, env = process.env) {
90
+ if (!isPlaintextBearerUnsafe(baseUrl, secret)) return;
91
+ if (!envEnabled(env["MEMINI_REQUIRE_HTTPS"], false)) return;
92
+ throw new Error(
93
+ `memini: a bearer token is configured for plaintext HTTP to ${baseUrl}. The token and memory payloads can be observed on the network; use HTTPS or an SSH tunnel.`
94
+ );
95
+ }
96
+
34
97
  // ../../../packages/memini-client/src/settings.ts
35
98
  var BEHAVIOR_KNOBS = [
36
99
  { envName: "MEMINI_CAPTURE_TURNS", wireKey: "capture_turns", kind: "bool", default: true },
@@ -51,7 +114,7 @@ var BEHAVIOR_KNOBS = [
51
114
  envName: "MEMINI_INJECT_PRETOOL_TOOLS",
52
115
  wireKey: "inject_pretool_tools",
53
116
  kind: "list",
54
- default: ["Read", "Write", "Edit", "Glob", "Grep"]
117
+ default: ["Read", "Write", "Edit", "MultiEdit", "Glob", "Grep"]
55
118
  },
56
119
  { envName: "MEMINI_INJECT_DEDUPE", wireKey: "inject_dedupe", kind: "bool", default: true },
57
120
  { envName: "MEMINI_INJECT_LABELS", wireKey: "inject_labels", kind: "list", default: [] },
@@ -60,11 +123,30 @@ var BEHAVIOR_KNOBS = [
60
123
  { envName: "MEMINI_RECALL_LIMIT", wireKey: "recall_limit", kind: "int", default: 3 },
61
124
  { envName: "MEMINI_INJECT_RECALL_MAX_TOK", wireKey: "inject_recall_max_tok", kind: "int", default: 0 },
62
125
  { envName: "MEMINI_INJECT_RECALL_MIN_SCORE", wireKey: "inject_recall_min_score", kind: "float", default: 0 },
63
- { envName: "MEMINI_MIN_CAPTURE_CHARS", wireKey: "min_capture_chars", kind: "int", default: 0 }
126
+ { envName: "MEMINI_MIN_CAPTURE_CHARS", wireKey: "min_capture_chars", kind: "int", default: 0 },
127
+ { envName: "MEMINI_CAPTURE_USER_MAX_CHARS", wireKey: "capture_user_max_chars", kind: "int", default: 1e3 },
128
+ {
129
+ envName: "MEMINI_CAPTURE_ASSISTANT_MAX_CHARS",
130
+ wireKey: "capture_assistant_max_chars",
131
+ kind: "int",
132
+ default: 3e3
133
+ },
134
+ // Also read at the transport layer (bootstrap.ts's timeoutMs), because a
135
+ // request timeout has to exist before the handshake that fetches settings.
136
+ // Both spellings share DEFAULT_TIMEOUT_MS/MIN_TIMEOUT_MS, so there is exactly
137
+ // one number: raising it here (server-side) or in the env both work.
138
+ {
139
+ envName: "MEMINI_TIMEOUT_MS",
140
+ wireKey: "request_timeout_ms",
141
+ kind: "int",
142
+ default: DEFAULT_TIMEOUT_MS,
143
+ min: MIN_TIMEOUT_MS
144
+ }
64
145
  ];
65
- function parseIntKnob(raw, fallback) {
146
+ function parseIntKnob(raw, fallback, min = 0) {
66
147
  const n = Number.parseInt(raw, 10);
67
- return Number.isFinite(n) && n >= 0 ? n : fallback;
148
+ if (!Number.isFinite(n) || n < 0) return fallback;
149
+ return Math.max(min, n);
68
150
  }
69
151
  function parseFloatKnob(raw, fallback) {
70
152
  const n = Number.parseFloat(raw);
@@ -82,7 +164,7 @@ function effectiveSetting(knob2, server, env = process.env) {
82
164
  value = !/^(0|false|no|off)$/i.test(raw.trim());
83
165
  break;
84
166
  case "int":
85
- value = parseIntKnob(raw, knob2.default);
167
+ value = parseIntKnob(raw, knob2.default, knob2.min);
86
168
  break;
87
169
  case "float":
88
170
  value = parseFloatKnob(raw, knob2.default);
@@ -99,41 +181,6 @@ function effectiveSetting(knob2, server, env = process.env) {
99
181
  return { value: knob2.default, source: "default" };
100
182
  }
101
183
 
102
- // ../../../packages/memini-client/src/bootstrap.ts
103
- var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
104
- function envEnabled(raw, defaultOn) {
105
- if (raw == null || raw === "") return defaultOn;
106
- return !/^(0|false|no|off)$/i.test(raw.trim());
107
- }
108
- function readBootstrap(env = process.env) {
109
- return {
110
- baseUrl: env["MEMINI_BASE_URL"] || "http://localhost:8080",
111
- apiKey: env["MEMINI_API_KEY"] || "",
112
- requireHttps: envEnabled(env["MEMINI_REQUIRE_HTTPS"], false),
113
- debug: envEnabled(env["MEMINI_DEBUG"], false),
114
- agent: env["MEMINI_AGENT"] || "",
115
- namespaceEnv: (env["MEMINI_NAMESPACE"] || "").trim(),
116
- namespacePrefixEnv: (env["MEMINI_NAMESPACE_PREFIX"] || "").trim(),
117
- homeEnv: (env["MEMINI_HOME"] || "").trim()
118
- };
119
- }
120
- function isPlaintextBearerUnsafe(baseUrl, secret) {
121
- if (!secret) return false;
122
- try {
123
- const u = new URL(baseUrl);
124
- return u.protocol === "http:" && !LOOPBACK_HOSTS.has(u.hostname.replace(/^\[|\]$/g, "").toLowerCase());
125
- } catch {
126
- return false;
127
- }
128
- }
129
- function assertBearerTransportSafe(baseUrl, secret, env = process.env) {
130
- if (!isPlaintextBearerUnsafe(baseUrl, secret)) return;
131
- if (!envEnabled(env["MEMINI_REQUIRE_HTTPS"], false)) return;
132
- throw new Error(
133
- `memini: a bearer token is configured for plaintext HTTP to ${baseUrl}. The token and memory payloads can be observed on the network; use HTTPS or an SSH tunnel.`
134
- );
135
- }
136
-
137
184
  // ../../../packages/memini-client/src/facts.ts
138
185
  import { execFileSync } from "node:child_process";
139
186
  import path from "node:path";
@@ -270,7 +317,7 @@ async function performHandshake(boot, facts, opts = {}) {
270
317
  }
271
318
 
272
319
  // src/index.ts
273
- var DEFAULT_TIMEOUT_MS = 3e4;
320
+ var DEFAULT_TIMEOUT_MS2 = 3e4;
274
321
  var DEFAULT_RECALL_LIMIT = 3;
275
322
  var STATUS_TIMEOUT_MS = 4e3;
276
323
  var HANDSHAKE_TIMEOUT_MS = 2500;
@@ -350,7 +397,7 @@ function resolveStaticConfig(env = process.env) {
350
397
  const homeEnv = (e.MEMINI_HOME || "").trim();
351
398
  return {
352
399
  home: homeEnv || void 0,
353
- timeout_ms: Number(e.MEMINI_TIMEOUT_MS || DEFAULT_TIMEOUT_MS),
400
+ timeout_ms: Number(e.MEMINI_TIMEOUT_MS || DEFAULT_TIMEOUT_MS2),
354
401
  fallback_on_error: envBool(e.MEMINI_FALLBACK, true)
355
402
  };
356
403
  }
@@ -370,7 +417,9 @@ function resolveLiveConfig(boot, facts, hs, env = process.env) {
370
417
  capture: effectiveSetting(knob("capture"), server, env).value,
371
418
  recall_limit: effectiveSetting(knob("recall_limit"), server, env).value,
372
419
  recall_max_tokens: effectiveSetting(knob("inject_recall_max_tok"), server, env).value,
373
- recall_min_score: effectiveSetting(knob("inject_recall_min_score"), server, env).value
420
+ recall_min_score: effectiveSetting(knob("inject_recall_min_score"), server, env).value,
421
+ capture_user_max_chars: effectiveSetting(knob("capture_user_max_chars"), server, env).value,
422
+ capture_assistant_max_chars: effectiveSetting(knob("capture_assistant_max_chars"), server, env).value
374
423
  };
375
424
  }
376
425
  async function sessionLive(ctx, env = process.env) {
@@ -538,10 +587,8 @@ function extractLastAssistantText(messages) {
538
587
  }
539
588
  return "";
540
589
  }
541
- function buildTurnContent(userText, assistantText) {
542
- return `${String(userText).slice(0, 1e3)}
543
-
544
- ${String(assistantText).slice(0, 3e3)}`;
590
+ function buildTurnContent(userText, assistantText, userMax, assistantMax) {
591
+ return buildTurnCapture(String(userText), String(assistantText), userMax, assistantMax);
545
592
  }
546
593
  function pinKeyFacts(facts) {
547
594
  const out = {};
@@ -1004,7 +1051,7 @@ function meminiExtension(pi) {
1004
1051
  const stored = await client.postJson(
1005
1052
  "/v1/memories",
1006
1053
  {
1007
- content: buildTurnContent(userText, assistantText),
1054
+ content: buildTurnContent(userText, assistantText, live.capture_user_max_chars, live.capture_assistant_max_chars),
1008
1055
  tags: ["pi"],
1009
1056
  metadata
1010
1057
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eleboucher/pi-memini",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Shared cross-session memory for the Pi coding agent, backed by a memini service.",
5
5
  "files": [
6
6
  "dist"