@gamaze/hicortex 0.16.5 → 0.16.6
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/llm.d.ts +13 -0
- package/dist/llm.js +42 -0
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
package/dist/llm.d.ts
CHANGED
|
@@ -31,6 +31,10 @@ export interface LlmConfig {
|
|
|
31
31
|
enableThinking?: boolean;
|
|
32
32
|
/** Context window for the ollama fast tier (completeOllama). Falls back to 2048. */
|
|
33
33
|
numCtx?: number;
|
|
34
|
+
/** Flush ollama memory every N ollama calls (0 = off). See HicortexConfig.ollamaFlushEvery. */
|
|
35
|
+
ollamaFlushEvery?: number;
|
|
36
|
+
/** Ms to wait after an ollama flush for the runner to release. */
|
|
37
|
+
ollamaFlushWaitMs?: number;
|
|
34
38
|
/** Optional separate endpoint for reflect-tier LLM (e.g. remote Ollama with larger model). */
|
|
35
39
|
reflectBaseUrl?: string;
|
|
36
40
|
reflectApiKey?: string;
|
|
@@ -212,6 +216,7 @@ export declare class RateLimitError extends Error {
|
|
|
212
216
|
}
|
|
213
217
|
export declare class LlmClient {
|
|
214
218
|
private config;
|
|
219
|
+
private ollamaCallCount;
|
|
215
220
|
constructor(config: LlmConfig);
|
|
216
221
|
/** Endpoint identity for shared rate-limit state (provider + base URL). */
|
|
217
222
|
private get endpointKey();
|
|
@@ -261,6 +266,14 @@ export declare class LlmClient {
|
|
|
261
266
|
* Ollama: use /api/generate with think:false (important for qwen3.5 models).
|
|
262
267
|
*/
|
|
263
268
|
private completeOllama;
|
|
269
|
+
/**
|
|
270
|
+
* Flush ollama's accumulated memory: unload the model (keep_alive:0) so the
|
|
271
|
+
* runner exits + releases its per-request RSS growth, then wait for the release
|
|
272
|
+
* before the next call reloads fresh. The runner takes >90 s to exit after
|
|
273
|
+
* keep_alive:0 (measured), so the wait is generous (ollamaFlushWaitMs, default
|
|
274
|
+
* 180 s). Best-effort — a flush failure just means no release this cycle.
|
|
275
|
+
*/
|
|
276
|
+
private flushOllama;
|
|
264
277
|
/**
|
|
265
278
|
* Anthropic Messages API (/v1/messages).
|
|
266
279
|
* Auth via x-api-key header.
|
package/dist/llm.js
CHANGED
|
@@ -211,6 +211,12 @@ function applyTierTuningOverlay(llmConfig, savedConfig) {
|
|
|
211
211
|
if (savedConfig.numCtx !== undefined) {
|
|
212
212
|
llmConfig.numCtx = (0, config_read_js_1.readPositiveConfig)(savedConfig, "numCtx", 2048);
|
|
213
213
|
}
|
|
214
|
+
if (savedConfig.ollamaFlushEvery !== undefined) {
|
|
215
|
+
llmConfig.ollamaFlushEvery = (0, config_read_js_1.readPositiveConfig)(savedConfig, "ollamaFlushEvery", 0);
|
|
216
|
+
}
|
|
217
|
+
if (savedConfig.ollamaFlushWaitMs !== undefined) {
|
|
218
|
+
llmConfig.ollamaFlushWaitMs = (0, config_read_js_1.readPositiveConfig)(savedConfig, "ollamaFlushWaitMs", 180000);
|
|
219
|
+
}
|
|
214
220
|
}
|
|
215
221
|
/**
|
|
216
222
|
* Resolve an LlmConfig from a saved ~/.hicortex/config.json object.
|
|
@@ -511,6 +517,7 @@ exports.RateLimitError = RateLimitError;
|
|
|
511
517
|
const rateLimitedUntilByEndpoint = new Map();
|
|
512
518
|
class LlmClient {
|
|
513
519
|
config;
|
|
520
|
+
ollamaCallCount = 0;
|
|
514
521
|
constructor(config) {
|
|
515
522
|
this.config = config;
|
|
516
523
|
}
|
|
@@ -739,8 +746,43 @@ class LlmClient {
|
|
|
739
746
|
catch { /* skip malformed lines */ }
|
|
740
747
|
}
|
|
741
748
|
}
|
|
749
|
+
// Flush ollama's accumulated memory every N calls. ollama's runner RSS grows
|
|
750
|
+
// ~171 MB/call and isn't freed between requests — on RAM-constrained boxes
|
|
751
|
+
// this swap-thrashes long consolidations. After the Nth call, unload the
|
|
752
|
+
// model (keep_alive:0) + wait for the runner to exit + release, so the next
|
|
753
|
+
// call reloads fresh (low RSS) instead of accumulating to thrash. Opt-in via
|
|
754
|
+
// ollamaFlushEvery (0 = off).
|
|
755
|
+
const flushEvery = this.config.ollamaFlushEvery ?? 0;
|
|
756
|
+
if (flushEvery > 0) {
|
|
757
|
+
this.ollamaCallCount++;
|
|
758
|
+
if (this.ollamaCallCount >= flushEvery) {
|
|
759
|
+
await this.flushOllama(model);
|
|
760
|
+
this.ollamaCallCount = 0;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
742
763
|
return result.trim();
|
|
743
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Flush ollama's accumulated memory: unload the model (keep_alive:0) so the
|
|
767
|
+
* runner exits + releases its per-request RSS growth, then wait for the release
|
|
768
|
+
* before the next call reloads fresh. The runner takes >90 s to exit after
|
|
769
|
+
* keep_alive:0 (measured), so the wait is generous (ollamaFlushWaitMs, default
|
|
770
|
+
* 180 s). Best-effort — a flush failure just means no release this cycle.
|
|
771
|
+
*/
|
|
772
|
+
async flushOllama(model) {
|
|
773
|
+
const url = `${this.config.baseUrl.replace(/\/$/, "")}/api/generate`;
|
|
774
|
+
try {
|
|
775
|
+
await fetch(url, {
|
|
776
|
+
method: "POST",
|
|
777
|
+
headers: { "Content-Type": "application/json" },
|
|
778
|
+
body: JSON.stringify({ model, keep_alive: 0 }),
|
|
779
|
+
signal: AbortSignal.timeout(60_000),
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
catch { /* best-effort flush */ }
|
|
783
|
+
const waitMs = this.config.ollamaFlushWaitMs ?? 180_000;
|
|
784
|
+
await new Promise((r) => setTimeout(r, waitMs));
|
|
785
|
+
}
|
|
744
786
|
/**
|
|
745
787
|
* Anthropic Messages API (/v1/messages).
|
|
746
788
|
* Auth via x-api-key header.
|
package/dist/types.d.ts
CHANGED
|
@@ -313,6 +313,23 @@ export interface HicortexConfig {
|
|
|
313
313
|
* scoring prompt actually needs more.
|
|
314
314
|
*/
|
|
315
315
|
numCtx?: number;
|
|
316
|
+
/**
|
|
317
|
+
* Flush ollama's accumulated memory every N ollama calls — workaround for
|
|
318
|
+
* ollama's per-request memory growth (the runner's RSS climbs ~171 MB/call and
|
|
319
|
+
* isn't freed between requests), which swap-thrashes RAM-constrained boxes
|
|
320
|
+
* during long consolidations. Default 0 (off). When >0, every Nth ollama call
|
|
321
|
+
* triggers a `keep_alive:0` unload + an `ollamaFlushWaitMs` pause for the
|
|
322
|
+
* runner to exit + release, then the next call reloads fresh. N=15 caps a
|
|
323
|
+
* cycle at ~2.5 GB. Opt-in — set e.g. 15 on constrained boxes.
|
|
324
|
+
*/
|
|
325
|
+
ollamaFlushEvery?: number;
|
|
326
|
+
/**
|
|
327
|
+
* Milliseconds to wait after an ollama flush (`keep_alive:0`) for the runner
|
|
328
|
+
* to exit + release its accumulated memory before the next call reloads.
|
|
329
|
+
* Default 180000 (3 min — the runner takes >90 s to exit after keep_alive:0;
|
|
330
|
+
* doubled for margin). Only relevant when `ollamaFlushEvery` > 0.
|
|
331
|
+
*/
|
|
332
|
+
ollamaFlushWaitMs?: number;
|
|
316
333
|
}
|
|
317
334
|
/** A config-owned life-sphere domain (see HicortexConfig.domains). */
|
|
318
335
|
export interface DomainDef {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.6",
|
|
4
4
|
"description": "Self-learning memory for AI agents — experience captured automatically, distilled into lessons overnight, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|