@agentmemory/agentmemory 0.9.16 → 0.9.17

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/index.mjs CHANGED
@@ -68,6 +68,12 @@ function hasRealValue(v) {
68
68
  }
69
69
  function detectProvider(env) {
70
70
  const maxTokens = parseInt(env["MAX_TOKENS"] || "4096", 10);
71
+ if (hasRealValue(env["OPENAI_API_KEY"]) && env["OPENAI_API_KEY_FOR_LLM"] !== "false") return {
72
+ provider: "openai",
73
+ model: env["OPENAI_MODEL"] || "gpt-4o-mini",
74
+ maxTokens,
75
+ baseURL: env["OPENAI_BASE_URL"]
76
+ };
71
77
  if (hasRealValue(env["MINIMAX_API_KEY"])) return {
72
78
  provider: "minimax",
73
79
  model: env["MINIMAX_MODEL"] || "MiniMax-M2.7",
@@ -93,7 +99,7 @@ function detectProvider(env) {
93
99
  maxTokens
94
100
  };
95
101
  if (!(env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true")) {
96
- process.stderr.write("[agentmemory] No LLM provider key found (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, MINIMAX_API_KEY). LLM-backed compression and summarization are DISABLED — using no-op provider. This is the safe default: the agent-sdk fallback used to spawn Claude Agent SDK child sessions which inherit Claude Code's plugin hooks and cause infinite Stop-hook recursion (#149 follow-up). To opt in to the agent-sdk fallback anyway, set both AGENTMEMORY_AUTO_COMPRESS=true AND AGENTMEMORY_ALLOW_AGENT_SDK=true — but be aware it will burn your Claude Pro allocation and may still recurse if you use it from inside Claude Code itself.\n");
102
+ process.stderr.write("[agentmemory] No LLM provider key found (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, MINIMAX_API_KEY, OPENAI_API_KEY). LLM-backed compression and summarization are DISABLED — using no-op provider. This is the safe default: the agent-sdk fallback used to spawn Claude Agent SDK child sessions which inherit Claude Code's plugin hooks and cause infinite Stop-hook recursion (#149 follow-up). To opt in to the agent-sdk fallback anyway, set both AGENTMEMORY_AUTO_COMPRESS=true AND AGENTMEMORY_ALLOW_AGENT_SDK=true — but be aware it will burn your Claude Pro allocation and may still recurse if you use it from inside Claude Code itself.\n");
97
103
  return {
98
104
  provider: "noop",
99
105
  model: "noop",
@@ -133,7 +139,7 @@ function getEnvVar(key) {
133
139
  }
134
140
  function detectLlmProviderKind() {
135
141
  const env = getMergedEnv();
136
- if (hasRealValue(env["ANTHROPIC_API_KEY"]) || hasRealValue(env["GEMINI_API_KEY"]) || hasRealValue(env["GOOGLE_API_KEY"]) || hasRealValue(env["OPENROUTER_API_KEY"]) || hasRealValue(env["MINIMAX_API_KEY"])) return "llm";
142
+ if (hasRealValue(env["ANTHROPIC_API_KEY"]) || hasRealValue(env["GEMINI_API_KEY"]) || hasRealValue(env["GOOGLE_API_KEY"]) || hasRealValue(env["OPENROUTER_API_KEY"]) || hasRealValue(env["MINIMAX_API_KEY"]) || hasRealValue(env["OPENAI_API_KEY"]) && env["OPENAI_API_KEY_FOR_LLM"] !== "false") return "llm";
137
143
  return "noop";
138
144
  }
139
145
  function loadEmbeddingConfig() {
@@ -215,7 +221,8 @@ const VALID_PROVIDERS = new Set([
215
221
  "gemini",
216
222
  "openrouter",
217
223
  "agent-sdk",
218
- "minimax"
224
+ "minimax",
225
+ "openai"
219
226
  ]);
220
227
  function loadFallbackConfig() {
221
228
  const env = getMergedEnv();
@@ -398,6 +405,137 @@ var NoopProvider = class {
398
405
  }
399
406
  };
400
407
 
408
+ //#endregion
409
+ //#region src/providers/openai.ts
410
+ const DEFAULT_BASE_URL$1 = "https://api.openai.com";
411
+ const DEFAULT_TIMEOUT_MS = 6e4;
412
+ const DEFAULT_AZURE_API_VERSION = "2024-08-01-preview";
413
+ /**
414
+ * OpenAI-compatible LLM provider.
415
+ *
416
+ * Uses raw fetch (no SDK) to support any OpenAI-compatible endpoint:
417
+ * - OpenAI official
418
+ * - Azure OpenAI (auto-detected from .openai.azure.com host)
419
+ * - DeepSeek
420
+ * - 硅基流动 (SiliconFlow)
421
+ * - vLLM / LM Studio / Ollama (with OpenAI compatibility layer)
422
+ * - Any other proxy implementing /v1/chat/completions
423
+ *
424
+ * Required env vars:
425
+ * OPENAI_API_KEY — API key
426
+ *
427
+ * Optional:
428
+ * OPENAI_BASE_URL — base URL without path (default: https://api.openai.com).
429
+ * Azure: https://<resource>.openai.azure.com/openai/deployments/<deployment>
430
+ * OPENAI_MODEL — model name (default: gpt-4o-mini)
431
+ * OPENAI_API_VERSION — Azure api-version query param (default: 2024-08-01-preview)
432
+ * OPENAI_TIMEOUT_MS — outbound fetch timeout in ms (default: 60000)
433
+ * MAX_TOKENS — max output tokens (default: from config or 4096)
434
+ * OPENAI_REASONING_EFFORT — "low" | "medium" | "high" | "none"
435
+ * Passthrough for reasoning models (e.g. Ollama Cloud
436
+ * thinking models). Set to "none" to ensure
437
+ * message.content is populated instead of only
438
+ * message.reasoning.
439
+ */
440
+ var OpenAIProvider = class {
441
+ name = "openai";
442
+ apiKey;
443
+ model;
444
+ maxTokens;
445
+ baseUrl;
446
+ reasoningEffort;
447
+ timeoutMs;
448
+ isAzure;
449
+ azureApiVersion;
450
+ constructor(apiKey, model, maxTokens, baseURL) {
451
+ this.apiKey = apiKey;
452
+ this.model = model;
453
+ this.maxTokens = maxTokens;
454
+ this.baseUrl = (baseURL || getEnvVar("OPENAI_BASE_URL") || DEFAULT_BASE_URL$1).replace(/\/+$/, "");
455
+ this.reasoningEffort = getEnvVar("OPENAI_REASONING_EFFORT") || void 0;
456
+ this.timeoutMs = parseTimeout(getEnvVar("OPENAI_TIMEOUT_MS"));
457
+ this.azureApiVersion = getEnvVar("OPENAI_API_VERSION") || DEFAULT_AZURE_API_VERSION;
458
+ this.isAzure = detectAzure(this.baseUrl);
459
+ }
460
+ async compress(systemPrompt, userPrompt) {
461
+ return this.call(systemPrompt, userPrompt);
462
+ }
463
+ async summarize(systemPrompt, userPrompt) {
464
+ return this.call(systemPrompt, userPrompt);
465
+ }
466
+ buildUrl() {
467
+ if (this.isAzure) {
468
+ const sep = this.baseUrl.includes("?") ? "&" : "?";
469
+ return `${this.baseUrl}/chat/completions${sep}api-version=${encodeURIComponent(this.azureApiVersion)}`;
470
+ }
471
+ return `${this.baseUrl}/v1/chat/completions`;
472
+ }
473
+ buildHeaders() {
474
+ if (this.isAzure) return {
475
+ "Content-Type": "application/json",
476
+ "api-key": this.apiKey
477
+ };
478
+ return {
479
+ "Content-Type": "application/json",
480
+ Authorization: `Bearer ${this.apiKey}`
481
+ };
482
+ }
483
+ async call(systemPrompt, userPrompt) {
484
+ const url = this.buildUrl();
485
+ const body = {
486
+ model: this.model,
487
+ max_tokens: this.maxTokens,
488
+ messages: [{
489
+ role: "system",
490
+ content: systemPrompt
491
+ }, {
492
+ role: "user",
493
+ content: userPrompt
494
+ }]
495
+ };
496
+ if (this.reasoningEffort) body.reasoning_effort = this.reasoningEffort;
497
+ const ac = new AbortController();
498
+ const t = setTimeout(() => ac.abort(), this.timeoutMs);
499
+ let response;
500
+ try {
501
+ response = await fetch(url, {
502
+ method: "POST",
503
+ headers: this.buildHeaders(),
504
+ body: JSON.stringify(body),
505
+ signal: ac.signal
506
+ });
507
+ } catch (err) {
508
+ if (ac.signal.aborted || err instanceof Error && err.name === "AbortError") throw new Error(`OpenAI API request timed out after ${this.timeoutMs}ms — set OPENAI_TIMEOUT_MS to raise the bound or check the provider status.`);
509
+ throw err;
510
+ } finally {
511
+ clearTimeout(t);
512
+ }
513
+ if (!response.ok) {
514
+ const text = await response.text();
515
+ throw new Error(`OpenAI API error (${response.status}): ${text}`);
516
+ }
517
+ const data = await response.json();
518
+ const message = data.choices?.[0]?.message;
519
+ const content = message?.content;
520
+ if (content) return content;
521
+ const reasoning = message?.reasoning;
522
+ if (reasoning) return reasoning;
523
+ throw new Error(`OpenAI returned unexpected response: ${JSON.stringify(data).slice(0, 200)}`);
524
+ }
525
+ };
526
+ function parseTimeout(raw) {
527
+ if (!raw) return DEFAULT_TIMEOUT_MS;
528
+ const n = parseInt(raw, 10);
529
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_TIMEOUT_MS;
530
+ }
531
+ function detectAzure(baseUrl) {
532
+ try {
533
+ return new URL(baseUrl).hostname.endsWith(".openai.azure.com");
534
+ } catch {
535
+ return false;
536
+ }
537
+ }
538
+
401
539
  //#endregion
402
540
  //#region src/providers/openrouter.ts
403
541
  var OpenRouterProvider = class {
@@ -983,6 +1121,11 @@ function createBaseProvider(config) {
983
1121
  return new OpenRouterProvider(geminiKey, config.model, config.maxTokens, "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions");
984
1122
  }
985
1123
  case "openrouter": return new OpenRouterProvider(requireEnvVar("OPENROUTER_API_KEY"), config.model, config.maxTokens, "https://openrouter.ai/api/v1/chat/completions");
1124
+ case "openai": {
1125
+ const openaiKey = getEnvVar("OPENAI_API_KEY");
1126
+ if (!openaiKey) throw new Error("OPENAI_API_KEY is required for the openai provider");
1127
+ return new OpenAIProvider(openaiKey, config.model, config.maxTokens, config.baseURL);
1128
+ }
986
1129
  case "noop": return new NoopProvider();
987
1130
  default: return new AgentSDKProvider();
988
1131
  }
@@ -5967,7 +6110,7 @@ function registerAutoForgetFunction(sdk, kv) {
5967
6110
 
5968
6111
  //#endregion
5969
6112
  //#region src/version.ts
5970
- const VERSION = "0.9.16";
6113
+ const VERSION = "0.9.17";
5971
6114
 
5972
6115
  //#endregion
5973
6116
  //#region src/functions/export-import.ts
@@ -6101,7 +6244,8 @@ function registerExportImportFunction(sdk, kv) {
6101
6244
  "0.9.13",
6102
6245
  "0.9.14",
6103
6246
  "0.9.15",
6104
- "0.9.16"
6247
+ "0.9.16",
6248
+ "0.9.17"
6105
6249
  ]).has(importData.version)) return {
6106
6250
  success: false,
6107
6251
  error: `Unsupported export version: ${importData.version}`
@@ -19676,6 +19820,11 @@ async function main() {
19676
19820
  serviceName: OTEL_CONFIG.serviceName,
19677
19821
  serviceVersion: OTEL_CONFIG.serviceVersion,
19678
19822
  metricsExportIntervalMs: OTEL_CONFIG.metricsExportIntervalMs
19823
+ },
19824
+ telemetry: {
19825
+ project_name: "agentmemory",
19826
+ language: "node",
19827
+ framework: "iii-sdk"
19679
19828
  }
19680
19829
  });
19681
19830
  const kv = new StateKV(sdk);
@@ -19835,7 +19984,7 @@ async function main() {
19835
19984
  console.warn(`[agentmemory] Failed to backfill memories into BM25:`, err);
19836
19985
  }
19837
19986
  bootLog(`Ready. ${embeddingProvider ? "Triple-stream (BM25+Vector+Graph)" : "BM25+Graph"} search active.`);
19838
- bootLog(`REST API: 107 endpoints at http://localhost:${config.restPort}/agentmemory/*`);
19987
+ bootLog(`REST API: 121 endpoints at http://localhost:${config.restPort}/agentmemory/*`);
19839
19988
  bootLog(`MCP surface (opt-in via \`npx @agentmemory/mcp\`): ${getAllTools().length} tools · 6 resources · 3 prompts`);
19840
19989
  const viewerServer = startViewerServer(config.restPort + 2, kv, sdk, secret, config.restPort);
19841
19990
  const autoForgetIntervalMs = parseInt(process.env.AUTO_FORGET_INTERVAL_MS || "3600000", 10);