@gamaze/hicortex 0.3.11 → 0.3.13

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 CHANGED
@@ -23,6 +23,12 @@ export interface LlmConfig {
23
23
  model: string;
24
24
  reflectModel: string;
25
25
  provider: string;
26
+ /** Optional separate model for distillation (defaults to model if unset). */
27
+ distillModel?: string;
28
+ /** Optional separate endpoint for reflect-tier LLM (e.g. remote Ollama with larger model). */
29
+ reflectBaseUrl?: string;
30
+ reflectApiKey?: string;
31
+ reflectProvider?: string;
26
32
  }
27
33
  /**
28
34
  * Resolve LLM configuration from plugin config, OpenClaw config, env vars, or Ollama fallback.
@@ -70,12 +76,17 @@ export declare class LlmClient {
70
76
  completeFast(prompt: string, maxTokens?: number): Promise<string>;
71
77
  /**
72
78
  * Reflect-tier completion (nightly reflection, needs reasoning).
79
+ * Routes to reflectBaseUrl/reflectProvider if configured (e.g. remote Ollama with larger model).
73
80
  */
74
81
  completeReflect(prompt: string, maxTokens?: number): Promise<string>;
75
82
  /**
76
83
  * Distillation-tier completion (session knowledge extraction).
77
84
  */
78
85
  completeDistill(prompt: string, maxTokens?: number): Promise<string>;
86
+ /**
87
+ * Complete with overridden baseUrl/apiKey/provider (used for reflect tier with separate endpoint).
88
+ */
89
+ private completeWithOverride;
79
90
  private complete;
80
91
  /**
81
92
  * Claude CLI: shell out to `claude -p` for subscription users.
package/dist/llm.js CHANGED
@@ -422,15 +422,40 @@ class LlmClient {
422
422
  }
423
423
  /**
424
424
  * Reflect-tier completion (nightly reflection, needs reasoning).
425
+ * Routes to reflectBaseUrl/reflectProvider if configured (e.g. remote Ollama with larger model).
425
426
  */
426
427
  async completeReflect(prompt, maxTokens = 8192) {
428
+ if (this.config.reflectBaseUrl) {
429
+ return this.completeWithOverride(this.config.reflectBaseUrl, this.config.reflectApiKey ?? this.config.apiKey, this.config.reflectProvider ?? this.config.provider, this.config.reflectModel, prompt, maxTokens, 900_000);
430
+ }
427
431
  return this.complete(this.config.reflectModel, prompt, maxTokens, 900_000);
428
432
  }
429
433
  /**
430
434
  * Distillation-tier completion (session knowledge extraction).
431
435
  */
432
436
  async completeDistill(prompt, maxTokens = 2048) {
433
- return this.complete(this.config.model, prompt, maxTokens, 900_000);
437
+ return this.complete(this.config.distillModel ?? this.config.model, prompt, maxTokens, 900_000);
438
+ }
439
+ /**
440
+ * Complete with overridden baseUrl/apiKey/provider (used for reflect tier with separate endpoint).
441
+ */
442
+ async completeWithOverride(baseUrl, apiKey, provider, model, prompt, maxTokens, timeoutMs) {
443
+ if (this.isRateLimited) {
444
+ throw new RateLimitError(this.rateLimitedUntil - Date.now());
445
+ }
446
+ // Temporarily swap config for this call
447
+ const saved = { baseUrl: this.config.baseUrl, apiKey: this.config.apiKey, provider: this.config.provider };
448
+ this.config.baseUrl = baseUrl;
449
+ this.config.apiKey = apiKey;
450
+ this.config.provider = provider;
451
+ try {
452
+ return await this.complete(model, prompt, maxTokens, timeoutMs);
453
+ }
454
+ finally {
455
+ this.config.baseUrl = saved.baseUrl;
456
+ this.config.apiKey = saved.apiKey;
457
+ this.config.provider = saved.provider;
458
+ }
434
459
  }
435
460
  async complete(model, prompt, maxTokens, timeoutMs) {
436
461
  if (this.isRateLimited) {
@@ -192,15 +192,40 @@ async function startServer(options = {}) {
192
192
  llmConfig = (0, llm_js_1.resolveLlmConfigForCC)();
193
193
  }
194
194
  }
195
+ else if (savedConfig?.llmBackend === "ollama" && savedConfig?.llmBaseUrl) {
196
+ // Ollama: no API key needed, construct config directly
197
+ llmConfig = {
198
+ baseUrl: savedConfig.llmBaseUrl,
199
+ apiKey: "",
200
+ model: savedConfig.llmModel ?? "qwen3.5:4b",
201
+ reflectModel: savedConfig.reflectModel ?? savedConfig.llmModel ?? "qwen3.5:4b",
202
+ provider: "ollama",
203
+ };
204
+ }
195
205
  else {
196
206
  llmConfig = (0, llm_js_1.resolveLlmConfigForCC)({
197
207
  llmBaseUrl: savedConfig?.llmBaseUrl,
198
208
  llmApiKey: savedConfig?.llmApiKey,
199
209
  llmModel: savedConfig?.llmModel,
210
+ reflectModel: savedConfig?.reflectModel,
200
211
  });
201
212
  }
213
+ // Apply optional distillModel (e.g. larger local model for session extraction)
214
+ if (savedConfig?.distillModel) {
215
+ llmConfig.distillModel = savedConfig.distillModel;
216
+ }
217
+ // Apply separate reflect endpoint if configured (e.g. remote Ollama with larger model)
218
+ if (savedConfig?.reflectBaseUrl) {
219
+ llmConfig.reflectBaseUrl = savedConfig.reflectBaseUrl;
220
+ llmConfig.reflectApiKey = savedConfig.reflectApiKey ?? llmConfig.apiKey;
221
+ llmConfig.reflectProvider = savedConfig.reflectProvider ?? llmConfig.provider;
222
+ }
202
223
  llm = new llm_js_1.LlmClient(llmConfig);
203
- console.log(`[hicortex] LLM: ${llmConfig.provider}/${llmConfig.model} (reflect: ${llmConfig.reflectModel})`);
224
+ const distillInfo = llmConfig.distillModel ? `, distill: ${llmConfig.distillModel}` : "";
225
+ const reflectInfo = llmConfig.reflectBaseUrl
226
+ ? `${llmConfig.reflectProvider}/${llmConfig.reflectModel}@${llmConfig.reflectBaseUrl}`
227
+ : llmConfig.reflectModel;
228
+ console.log(`[hicortex] LLM fast: ${llmConfig.provider}/${llmConfig.model}${distillInfo}, reflect: ${reflectInfo}`);
204
229
  // License: read from options, config file, or env var
205
230
  const licenseKey = options.licenseKey
206
231
  ?? savedConfig?.licenseKey
@@ -220,9 +245,46 @@ async function startServer(options = {}) {
220
245
  const stats = (0, db_js_1.getStats)(db, dbPath);
221
246
  console.log(`[hicortex] Ready: ${stats.memories} memories, ${stats.links} links, ` +
222
247
  `${Math.round(stats.db_size_bytes / 1024)} KB`);
248
+ // Auth token: from options, config file, or env var
249
+ const authToken = savedConfig?.authToken
250
+ ?? process.env.HICORTEX_AUTH_TOKEN
251
+ ?? "";
223
252
  // Express app
224
253
  const app = (0, express_1.default)();
225
254
  app.use(express_1.default.json());
255
+ // Optional bearer token auth (skip for /health and localhost when no token)
256
+ if (authToken) {
257
+ console.log(`[hicortex] Bearer token auth enabled`);
258
+ app.use((req, res, next) => {
259
+ // Always allow health endpoint
260
+ if (req.path === "/health")
261
+ return next();
262
+ // Allow localhost without auth
263
+ const ip = req.ip ?? req.socket.remoteAddress ?? "";
264
+ if (ip === "127.0.0.1" || ip === "::1" || ip === "::ffff:127.0.0.1")
265
+ return next();
266
+ // Check bearer token
267
+ const auth = req.headers.authorization;
268
+ if (auth === `Bearer ${authToken}`)
269
+ return next();
270
+ res.status(401).json({ error: "Unauthorized" });
271
+ });
272
+ }
273
+ // CORS: allow Claude Desktop (https://claude.ai) and other browser-based MCP clients
274
+ app.use((req, res, next) => {
275
+ const origin = req.headers.origin;
276
+ if (origin) {
277
+ res.setHeader("Access-Control-Allow-Origin", origin);
278
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
279
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
280
+ res.setHeader("Access-Control-Allow-Credentials", "true");
281
+ }
282
+ if (req.method === "OPTIONS") {
283
+ res.status(204).end();
284
+ return;
285
+ }
286
+ next();
287
+ });
226
288
  // SSE transport management — each connection gets its own McpServer instance
227
289
  const transports = new Map();
228
290
  // Health endpoint
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamaze/hicortex",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "description": "Human-like memory for self-improving AI agents. Automatic capturing, nightly reflection, and cross-agent learning. Works with Claude Code and OpenClaw.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {