memorix 1.9.8 → 1.9.10

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 (38) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +2 -0
  3. package/README.zh-CN.md +2 -0
  4. package/dist/cli/index.js +125 -31
  5. package/dist/index.js +117 -31
  6. package/dist/maintenance-runner.js +22 -5
  7. package/dist/media-audio-runner.js +22 -5
  8. package/dist/media-video-runner.js +22 -5
  9. package/dist/memcode-runtime/CHANGELOG.md +17 -0
  10. package/dist/sdk.js +116 -30
  11. package/dist/vector-backfill-runner.js +22 -5
  12. package/docs/CONFIGURATION.md +22 -0
  13. package/docs/DEVELOPMENT.md +1 -1
  14. package/docs/INTEGRATIONS.md +1 -1
  15. package/docs/README.md +1 -1
  16. package/docs/SETUP.md +1 -1
  17. package/package.json +1 -1
  18. package/plugins/antigravity/memorix/plugin.json +1 -1
  19. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  20. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  21. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  22. package/plugins/copilot/memorix/plugin.json +1 -1
  23. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  24. package/plugins/hermes/memorix/plugin.yaml +1 -1
  25. package/plugins/omp/memorix/package.json +1 -1
  26. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  27. package/plugins/pi/memorix/package.json +1 -1
  28. package/server.json +2 -2
  29. package/src/cli/commands/init.ts +7 -1
  30. package/src/cli/tui/ConfigureView.tsx +2 -0
  31. package/src/config/dotenv-loader.ts +1 -0
  32. package/src/config/resolved-config.ts +19 -5
  33. package/src/config/yaml-loader.ts +2 -2
  34. package/src/config.ts +5 -1
  35. package/src/dashboard/server.ts +3 -0
  36. package/src/hooks/installers/index.ts +89 -21
  37. package/src/llm/provider.ts +2 -1
  38. package/src/multimodal/image-loader.ts +2 -2
@@ -2089,6 +2089,7 @@ function getResolvedConfig(options = {}) {
2089
2089
  const legacy = loadFileConfig(homeDir);
2090
2090
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
2091
2091
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2092
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
2092
2093
  const memoryLlmProvider = first(
2093
2094
  process.env.MEMORIX_LLM_PROVIDER,
2094
2095
  toml.memory?.llm?.provider,
@@ -2109,16 +2110,18 @@ function getResolvedConfig(options = {}) {
2109
2110
  );
2110
2111
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2111
2112
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
2113
+ const isRequesty = memoryLlmProvider === "requesty";
2114
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
2112
2115
  const memoryLlmApiKey = first(
2113
2116
  process.env.MEMORIX_LLM_API_KEY,
2114
2117
  process.env.MEMORIX_API_KEY,
2115
2118
  toml.memory?.llm?.api_key,
2116
2119
  yaml.llm?.apiKey,
2117
2120
  legacy.llm?.apiKey,
2118
- // Never borrow another provider's credentials for the Atlas Cloud preset.
2119
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2120
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2121
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
2121
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
2122
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
2123
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
2124
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
2122
2125
  );
2123
2126
  const resolved = {
2124
2127
  agent: {
@@ -2167,7 +2170,7 @@ function getResolvedConfig(options = {}) {
2167
2170
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
2168
2171
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
2169
2172
  baseUrl: embeddingBaseUrl,
2170
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
2173
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
2171
2174
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
2172
2175
  },
2173
2176
  rerank: resolveRerankLane({
@@ -2298,6 +2301,7 @@ function getEnvSourceNames() {
2298
2301
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2299
2302
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2300
2303
  "OPENROUTER_API_KEY",
2304
+ "REQUESTY_API_KEY",
2301
2305
  "ATLASCLOUD_API_KEY"
2302
2306
  ].filter((name) => process.env[name]);
2303
2307
  }
@@ -2310,6 +2314,15 @@ function isOpenRouterUrl(value) {
2310
2314
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
2311
2315
  }
2312
2316
  }
2317
+ function isRequestyUrl(value) {
2318
+ if (!value) return false;
2319
+ try {
2320
+ const url = new URL(value);
2321
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
2322
+ } catch {
2323
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
2324
+ }
2325
+ }
2313
2326
  function isOpenRouterMemoryLane(provider2, baseUrl) {
2314
2327
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
2315
2328
  }
@@ -2464,6 +2477,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
2464
2477
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
2465
2478
  return "qwen/qwen3-embedding-8b";
2466
2479
  }
2480
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
2481
+ return "openai/text-embedding-3-small";
2482
+ }
2467
2483
  } catch {
2468
2484
  }
2469
2485
  return "text-embedding-3-small";
@@ -3129,6 +3145,7 @@ var init_provider = __esm({
3129
3145
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
3130
3146
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
3131
3147
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
3148
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
3132
3149
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
3133
3150
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
3134
3151
  };
@@ -3372,6 +3372,7 @@ function getResolvedConfig(options = {}) {
3372
3372
  const legacy = loadFileConfig(homeDir);
3373
3373
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3374
3374
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3375
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
3375
3376
  const memoryLlmProvider = first(
3376
3377
  process.env.MEMORIX_LLM_PROVIDER,
3377
3378
  toml.memory?.llm?.provider,
@@ -3392,16 +3393,18 @@ function getResolvedConfig(options = {}) {
3392
3393
  );
3393
3394
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3394
3395
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
3396
+ const isRequesty = memoryLlmProvider === "requesty";
3397
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
3395
3398
  const memoryLlmApiKey = first(
3396
3399
  process.env.MEMORIX_LLM_API_KEY,
3397
3400
  process.env.MEMORIX_API_KEY,
3398
3401
  toml.memory?.llm?.api_key,
3399
3402
  yaml.llm?.apiKey,
3400
3403
  legacy.llm?.apiKey,
3401
- // Never borrow another provider's credentials for the Atlas Cloud preset.
3402
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3403
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3404
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3404
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
3405
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
3406
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
3407
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
3405
3408
  );
3406
3409
  const resolved = {
3407
3410
  agent: {
@@ -3450,7 +3453,7 @@ function getResolvedConfig(options = {}) {
3450
3453
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
3451
3454
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
3452
3455
  baseUrl: embeddingBaseUrl,
3453
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
3456
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
3454
3457
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
3455
3458
  },
3456
3459
  rerank: resolveRerankLane({
@@ -3581,6 +3584,7 @@ function getEnvSourceNames() {
3581
3584
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
3582
3585
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
3583
3586
  "OPENROUTER_API_KEY",
3587
+ "REQUESTY_API_KEY",
3584
3588
  "ATLASCLOUD_API_KEY"
3585
3589
  ].filter((name) => process.env[name]);
3586
3590
  }
@@ -3593,6 +3597,15 @@ function isOpenRouterUrl(value) {
3593
3597
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
3594
3598
  }
3595
3599
  }
3600
+ function isRequestyUrl(value) {
3601
+ if (!value) return false;
3602
+ try {
3603
+ const url = new URL(value);
3604
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
3605
+ } catch {
3606
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
3607
+ }
3608
+ }
3596
3609
  function isOpenRouterMemoryLane(provider2, baseUrl) {
3597
3610
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
3598
3611
  }
@@ -3747,6 +3760,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
3747
3760
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
3748
3761
  return "qwen/qwen3-embedding-8b";
3749
3762
  }
3763
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
3764
+ return "openai/text-embedding-3-small";
3765
+ }
3750
3766
  } catch {
3751
3767
  }
3752
3768
  return "text-embedding-3-small";
@@ -6561,6 +6577,7 @@ var init_provider2 = __esm({
6561
6577
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
6562
6578
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
6563
6579
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
6580
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
6564
6581
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
6565
6582
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
6566
6583
  };
@@ -2384,6 +2384,7 @@ function getResolvedConfig(options = {}) {
2384
2384
  const legacy = loadFileConfig(homeDir);
2385
2385
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
2386
2386
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2387
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
2387
2388
  const memoryLlmProvider = first(
2388
2389
  process.env.MEMORIX_LLM_PROVIDER,
2389
2390
  toml.memory?.llm?.provider,
@@ -2404,16 +2405,18 @@ function getResolvedConfig(options = {}) {
2404
2405
  );
2405
2406
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2406
2407
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
2408
+ const isRequesty = memoryLlmProvider === "requesty";
2409
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
2407
2410
  const memoryLlmApiKey = first(
2408
2411
  process.env.MEMORIX_LLM_API_KEY,
2409
2412
  process.env.MEMORIX_API_KEY,
2410
2413
  toml.memory?.llm?.api_key,
2411
2414
  yaml.llm?.apiKey,
2412
2415
  legacy.llm?.apiKey,
2413
- // Never borrow another provider's credentials for the Atlas Cloud preset.
2414
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2415
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2416
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
2416
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
2417
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
2418
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
2419
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
2417
2420
  );
2418
2421
  const resolved = {
2419
2422
  agent: {
@@ -2462,7 +2465,7 @@ function getResolvedConfig(options = {}) {
2462
2465
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
2463
2466
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
2464
2467
  baseUrl: embeddingBaseUrl,
2465
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
2468
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
2466
2469
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
2467
2470
  },
2468
2471
  rerank: resolveRerankLane({
@@ -2593,6 +2596,7 @@ function getEnvSourceNames() {
2593
2596
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2594
2597
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2595
2598
  "OPENROUTER_API_KEY",
2599
+ "REQUESTY_API_KEY",
2596
2600
  "ATLASCLOUD_API_KEY"
2597
2601
  ].filter((name) => process.env[name]);
2598
2602
  }
@@ -2605,6 +2609,15 @@ function isOpenRouterUrl(value) {
2605
2609
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
2606
2610
  }
2607
2611
  }
2612
+ function isRequestyUrl(value) {
2613
+ if (!value) return false;
2614
+ try {
2615
+ const url = new URL(value);
2616
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
2617
+ } catch {
2618
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
2619
+ }
2620
+ }
2608
2621
  function isOpenRouterMemoryLane(provider2, baseUrl) {
2609
2622
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
2610
2623
  }
@@ -2759,6 +2772,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
2759
2772
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
2760
2773
  return "qwen/qwen3-embedding-8b";
2761
2774
  }
2775
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
2776
+ return "openai/text-embedding-3-small";
2777
+ }
2762
2778
  } catch {
2763
2779
  }
2764
2780
  return "text-embedding-3-small";
@@ -5573,6 +5589,7 @@ var init_provider2 = __esm({
5573
5589
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
5574
5590
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
5575
5591
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
5592
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
5576
5593
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
5577
5594
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
5578
5595
  };
@@ -6,6 +6,23 @@ All notable changes to this project will be documented in this file.
6
6
 
7
7
  No unreleased changes.
8
8
 
9
+ ## [1.9.10] - 2026-10-08
10
+
11
+ ### Fixed
12
+ - **OpenCode 1.x regression** -- generated plugins now include the v1
13
+ `server` field alongside the v2 `setup` contract, so OpenCode 1.x can load
14
+ the legacy named export. Lifecycle, file, command, message, and compaction
15
+ events are also forwarded through the v1 generic `event` hook, with a longer
16
+ Windows hook timeout to reduce stale Bun timer failures.
17
+
18
+ ## [1.9.9] - 2026-10-02
19
+
20
+ ### Added
21
+ - **Requesty memory preset** -- `memorix init` and the configuration TUI can
22
+ select Requesty for optional background memory LLM work through its
23
+ OpenAI-compatible endpoint, with provider-specific key isolation.
24
+ `REQUESTY_API_KEY` is also accepted for Requesty embedding endpoints.
25
+
9
26
  ## [1.9.8] - 2026-10-02
10
27
 
11
28
  ### Fixed
package/dist/sdk.js CHANGED
@@ -3847,6 +3847,7 @@ function getResolvedConfig(options = {}) {
3847
3847
  const legacy = loadFileConfig(homeDir);
3848
3848
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3849
3849
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3850
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
3850
3851
  const memoryLlmProvider = first(
3851
3852
  process.env.MEMORIX_LLM_PROVIDER,
3852
3853
  toml.memory?.llm?.provider,
@@ -3867,16 +3868,18 @@ function getResolvedConfig(options = {}) {
3867
3868
  );
3868
3869
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3869
3870
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
3871
+ const isRequesty = memoryLlmProvider === "requesty";
3872
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
3870
3873
  const memoryLlmApiKey = first(
3871
3874
  process.env.MEMORIX_LLM_API_KEY,
3872
3875
  process.env.MEMORIX_API_KEY,
3873
3876
  toml.memory?.llm?.api_key,
3874
3877
  yaml.llm?.apiKey,
3875
3878
  legacy.llm?.apiKey,
3876
- // Never borrow another provider's credentials for the Atlas Cloud preset.
3877
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3878
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3879
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3879
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
3880
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
3881
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
3882
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
3880
3883
  );
3881
3884
  const resolved = {
3882
3885
  agent: {
@@ -3925,7 +3928,7 @@ function getResolvedConfig(options = {}) {
3925
3928
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
3926
3929
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
3927
3930
  baseUrl: embeddingBaseUrl,
3928
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
3931
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
3929
3932
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
3930
3933
  },
3931
3934
  rerank: resolveRerankLane({
@@ -4056,6 +4059,7 @@ function getEnvSourceNames() {
4056
4059
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
4057
4060
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
4058
4061
  "OPENROUTER_API_KEY",
4062
+ "REQUESTY_API_KEY",
4059
4063
  "ATLASCLOUD_API_KEY"
4060
4064
  ].filter((name) => process.env[name]);
4061
4065
  }
@@ -4068,6 +4072,15 @@ function isOpenRouterUrl(value) {
4068
4072
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
4069
4073
  }
4070
4074
  }
4075
+ function isRequestyUrl(value) {
4076
+ if (!value) return false;
4077
+ try {
4078
+ const url = new URL(value);
4079
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
4080
+ } catch {
4081
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
4082
+ }
4083
+ }
4071
4084
  function isOpenRouterMemoryLane(provider2, baseUrl) {
4072
4085
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
4073
4086
  }
@@ -4222,6 +4235,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
4222
4235
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
4223
4236
  return "qwen/qwen3-embedding-8b";
4224
4237
  }
4238
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
4239
+ return "openai/text-embedding-3-small";
4240
+ }
4225
4241
  } catch {
4226
4242
  }
4227
4243
  return "text-embedding-3-small";
@@ -7036,6 +7052,7 @@ var init_provider2 = __esm({
7036
7052
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
7037
7053
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
7038
7054
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
7055
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
7039
7056
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
7040
7057
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
7041
7058
  };
@@ -163566,7 +163583,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
163566
163583
  "MEMORIX_API_KEY",
163567
163584
  "OPENAI_API_KEY",
163568
163585
  "ANTHROPIC_API_KEY",
163569
- ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
163586
+ ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : [],
163587
+ ...resolved.memory.llm.provider === "requesty" ? ["REQUESTY_API_KEY"] : []
163570
163588
  ];
163571
163589
  if (llmKey) {
163572
163590
  const src = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
@@ -165151,7 +165169,7 @@ async function analyzeImage(input) {
165151
165169
  const config = getLLMConfig();
165152
165170
  if (!OPENAI_COMPATIBLE_PROVIDERS.has(config.provider)) {
165153
165171
  throw new Error(
165154
- `Image analysis requires an OpenAI-compatible provider (openai, openrouter, or custom). Current provider "${config.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
165172
+ `Image analysis requires an OpenAI-compatible provider (openai, openrouter, requesty, or custom). Current provider "${config.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
165155
165173
  );
165156
165174
  }
165157
165175
  const bytes = decodeBase64ImagePayload(input.base64, MAX_VISION_IMAGE_BYTES);
@@ -165190,7 +165208,7 @@ var init_image_loader = __esm({
165190
165208
  init_provider2();
165191
165209
  init_secret_filter();
165192
165210
  init_image_payload();
165193
- OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "custom"]);
165211
+ OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "requesty", "custom"]);
165194
165212
  MAX_VISION_PROMPT_CHARS = 12e3;
165195
165213
  MAX_VISION_DESCRIPTION_CHARS = 12e3;
165196
165214
  MAX_VISION_LABELS = 50;
@@ -165905,6 +165923,8 @@ function generateOpenCodePlugin() {
165905
165923
  */
165906
165924
  import { spawnSync } from 'node:child_process';
165907
165925
 
165926
+ const HOOK_TIMEOUT_MS = 30_000;
165927
+
165908
165928
  export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
165909
165929
  // Generate a stable session ID for this plugin lifetime
165910
165930
  const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
@@ -165930,14 +165950,14 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
165930
165950
  * - spawnSync is simpler: no stream lifecycle, no writer.close() bugs
165931
165951
  * - stdin pipe via input option is reliable cross-platform
165932
165952
  */
165933
- function runHook(payload) {
165934
- payload.session_id = sessionId;
165953
+ function runHook(payload, activeSessionId = sessionId) {
165954
+ payload.session_id = activeSessionId;
165935
165955
  const data = JSON.stringify(payload);
165936
165956
  const eventName = payload.hook_event_name || 'unknown';
165937
165957
  try {
165938
165958
  const result = spawnSync(hookCommand, ['hook'], {
165939
165959
  input: data,
165940
- timeout: 10_000,
165960
+ timeout: HOOK_TIMEOUT_MS,
165941
165961
  encoding: 'utf-8',
165942
165962
  stdio: ['pipe', 'pipe', 'pipe'],
165943
165963
  shell: process.platform === 'win32',
@@ -165982,7 +166002,87 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
165982
166002
  .trim();
165983
166003
  }
165984
166004
 
166005
+ function flushAssistantResponse(activeSessionId = sessionId) {
166006
+ if (!pendingAssistantResponse?.text) return;
166007
+ const deliveryKey = pendingAssistantResponse.id
166008
+ ? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
166009
+ : pendingAssistantResponse.text;
166010
+ if (deliveryKey === lastDeliveredAssistantKey) return;
166011
+ runHook({
166012
+ agent: 'opencode',
166013
+ hook_event_name: 'message.updated',
166014
+ ai_response: pendingAssistantResponse.text,
166015
+ message_id: pendingAssistantResponse.id,
166016
+ cwd: directory,
166017
+ }, activeSessionId);
166018
+ lastDeliveredAssistantKey = deliveryKey;
166019
+ }
166020
+
166021
+ function eventSessionId(event) {
166022
+ const properties = event?.properties ?? {};
166023
+ const value = properties.sessionID ?? properties.sessionId ?? properties.info?.id;
166024
+ return typeof value === 'string' && value ? value : sessionId;
166025
+ }
166026
+
166027
+ async function handleEvent({ event }) {
166028
+ const properties = event?.properties ?? {};
166029
+ const activeSessionId = eventSessionId(event);
166030
+ switch (event?.type) {
166031
+ case 'session.created':
166032
+ runHook({
166033
+ agent: 'opencode',
166034
+ hook_event_name: 'session.created',
166035
+ cwd: directory,
166036
+ }, activeSessionId);
166037
+ break;
166038
+ case 'session.idle':
166039
+ flushAssistantResponse(activeSessionId);
166040
+ runHook({
166041
+ agent: 'opencode',
166042
+ hook_event_name: 'session.idle',
166043
+ cwd: directory,
166044
+ }, activeSessionId);
166045
+ break;
166046
+ case 'file.edited':
166047
+ runHook({
166048
+ agent: 'opencode',
166049
+ hook_event_name: 'file.edited',
166050
+ file_path: properties.file ?? properties.path ?? '',
166051
+ cwd: directory,
166052
+ }, activeSessionId);
166053
+ break;
166054
+ case 'command.executed':
166055
+ runHook({
166056
+ agent: 'opencode',
166057
+ hook_event_name: 'command.executed',
166058
+ command: properties.name ?? properties.command ?? '',
166059
+ cwd: directory,
166060
+ }, activeSessionId);
166061
+ break;
166062
+ case 'message.updated': {
166063
+ const message = properties.info ?? properties.message ?? properties;
166064
+ if (message?.role !== 'assistant') break;
166065
+ const text = extractMessageText(message);
166066
+ if (!text) break;
166067
+ pendingAssistantResponse = { id: message.id, text };
166068
+ break;
166069
+ }
166070
+ case 'session.compacted':
166071
+ runHook({
166072
+ agent: 'opencode',
166073
+ hook_event_name: 'session.compacted',
166074
+ cwd: directory,
166075
+ }, activeSessionId);
166076
+ break;
166077
+ default:
166078
+ break;
166079
+ }
166080
+ }
166081
+
165985
166082
  return {
166083
+ // OpenCode 1.x delivers lifecycle/file/command/message events through this
166084
+ // generic hook. The named keys below remain for older compatible hosts.
166085
+ event: handleEvent,
165986
166086
  /** Session created \u2014 record session start */
165987
166087
  'session.created': async ({ session }) => {
165988
166088
  runHook({
@@ -165994,21 +166094,7 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
165994
166094
 
165995
166095
  /** Session idle \u2014 record session end */
165996
166096
  'session.idle': async ({ session }) => {
165997
- if (pendingAssistantResponse?.text) {
165998
- const deliveryKey = pendingAssistantResponse.id
165999
- ? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
166000
- : pendingAssistantResponse.text;
166001
- if (deliveryKey !== lastDeliveredAssistantKey) {
166002
- runHook({
166003
- agent: 'opencode',
166004
- hook_event_name: 'message.updated',
166005
- ai_response: pendingAssistantResponse.text,
166006
- message_id: pendingAssistantResponse.id,
166007
- cwd: directory,
166008
- });
166009
- lastDeliveredAssistantKey = deliveryKey;
166010
- }
166011
- }
166097
+ flushAssistantResponse();
166012
166098
  runHook({
166013
166099
  agent: 'opencode',
166014
166100
  hook_event_name: 'session.idle',
@@ -166116,7 +166202,7 @@ function v2RunHook(payload, directory, sessionId) {
166116
166202
  try {
166117
166203
  const result = spawnSync(v2HookCommand, ['hook'], {
166118
166204
  input: JSON.stringify(nextPayload),
166119
- timeout: 10_000,
166205
+ timeout: HOOK_TIMEOUT_MS,
166120
166206
  encoding: 'utf-8',
166121
166207
  stdio: ['pipe', 'pipe', 'pipe'],
166122
166208
  shell: process.platform === 'win32',
@@ -166240,7 +166326,7 @@ function setup(ctx) {
166240
166326
  return () => controller.abort();
166241
166327
  }
166242
166328
 
166243
- export default { id: 'memorix', setup };
166329
+ export default { id: 'memorix', server: MemorixPlugin, setup };
166244
166330
  `;
166245
166331
  }
166246
166332
  async function installOpenCodeSkills(projectRoot, global2 = false) {
@@ -167066,7 +167152,7 @@ var init_installers = __esm({
167066
167152
  "use strict";
167067
167153
  init_esm_shims();
167068
167154
  init_official_skills();
167069
- OPENCODE_PLUGIN_VERSION = 8;
167155
+ OPENCODE_PLUGIN_VERSION = 9;
167070
167156
  AGENT_SKILL_DIRS = {
167071
167157
  cursor: { project: path34.join(".cursor", "skills"), global: path34.join(".cursor", "skills") },
167072
167158
  windsurf: { project: path34.join(".windsurf", "skills"), global: path34.join(".windsurf", "skills") },
@@ -170971,7 +171057,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
170971
171057
  function getMcpServerInfo() {
170972
171058
  return {
170973
171059
  name: "memorix",
170974
- version: true ? "1.9.8" : "1.0.1"
171060
+ version: true ? "1.9.10" : "1.0.1"
170975
171061
  };
170976
171062
  }
170977
171063
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -2384,6 +2384,7 @@ function getResolvedConfig(options = {}) {
2384
2384
  const legacy = loadFileConfig(homeDir);
2385
2385
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
2386
2386
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2387
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
2387
2388
  const memoryLlmProvider = first(
2388
2389
  process.env.MEMORIX_LLM_PROVIDER,
2389
2390
  toml.memory?.llm?.provider,
@@ -2404,16 +2405,18 @@ function getResolvedConfig(options = {}) {
2404
2405
  );
2405
2406
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2406
2407
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
2408
+ const isRequesty = memoryLlmProvider === "requesty";
2409
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
2407
2410
  const memoryLlmApiKey = first(
2408
2411
  process.env.MEMORIX_LLM_API_KEY,
2409
2412
  process.env.MEMORIX_API_KEY,
2410
2413
  toml.memory?.llm?.api_key,
2411
2414
  yaml.llm?.apiKey,
2412
2415
  legacy.llm?.apiKey,
2413
- // Never borrow another provider's credentials for the Atlas Cloud preset.
2414
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2415
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2416
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
2416
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
2417
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
2418
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
2419
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
2417
2420
  );
2418
2421
  const resolved = {
2419
2422
  agent: {
@@ -2462,7 +2465,7 @@ function getResolvedConfig(options = {}) {
2462
2465
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
2463
2466
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
2464
2467
  baseUrl: embeddingBaseUrl,
2465
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
2468
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
2466
2469
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
2467
2470
  },
2468
2471
  rerank: resolveRerankLane({
@@ -2593,6 +2596,7 @@ function getEnvSourceNames() {
2593
2596
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2594
2597
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2595
2598
  "OPENROUTER_API_KEY",
2599
+ "REQUESTY_API_KEY",
2596
2600
  "ATLASCLOUD_API_KEY"
2597
2601
  ].filter((name) => process.env[name]);
2598
2602
  }
@@ -2605,6 +2609,15 @@ function isOpenRouterUrl(value) {
2605
2609
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
2606
2610
  }
2607
2611
  }
2612
+ function isRequestyUrl(value) {
2613
+ if (!value) return false;
2614
+ try {
2615
+ const url = new URL(value);
2616
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
2617
+ } catch {
2618
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
2619
+ }
2620
+ }
2608
2621
  function isOpenRouterMemoryLane(provider2, baseUrl) {
2609
2622
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
2610
2623
  }
@@ -2759,6 +2772,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
2759
2772
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
2760
2773
  return "qwen/qwen3-embedding-8b";
2761
2774
  }
2775
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
2776
+ return "openai/text-embedding-3-small";
2777
+ }
2762
2778
  } catch {
2763
2779
  }
2764
2780
  return "text-embedding-3-small";
@@ -5573,6 +5589,7 @@ var init_provider2 = __esm({
5573
5589
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
5574
5590
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
5575
5591
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
5592
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
5576
5593
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
5577
5594
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
5578
5595
  };
@@ -178,6 +178,23 @@ This is opt-in background memory processing and may incur API charges. Setting
178
178
  `ATLASCLOUD_API_KEY` alone does not enable it. Embeddings and memcode's model
179
179
  registry are unchanged.
180
180
 
181
+ Requesty is available as a memory LLM preset in `memorix init` and the
182
+ configuration TUI:
183
+
184
+ ```toml
185
+ [memory.llm]
186
+ provider = "requesty"
187
+ model = "openai/gpt-4o-mini"
188
+ ```
189
+
190
+ The preset uses `https://router.requesty.ai/v1` and the existing
191
+ OpenAI-compatible chat completion transport. Set `REQUESTY_API_KEY` or
192
+ `MEMORIX_LLM_API_KEY`; the preset does not fall back to OpenAI, Anthropic, or
193
+ OpenRouter environment keys. Model IDs use the `vendor/model` form, for example
194
+ `anthropic/claude-sonnet-4-5`. To keep traffic in the EU, set
195
+ `base_url = "https://router.eu.requesty.ai/v1"`. Get a key at
196
+ https://app.requesty.ai/api-keys.
197
+
181
198
  OrcaRouter works through the generic OpenAI-compatible gateway path. Keep the
182
199
  provider label as `openai`, set its base URL, and use an explicit model ID:
183
200
 
@@ -247,6 +264,11 @@ OpenAI-only default. The equivalent env-var form is
247
264
  `MEMORIX_EMBEDDING=api`, `MEMORIX_EMBEDDING_BASE_URL=https://openrouter.ai/api/v1`,
248
265
  `MEMORIX_EMBEDDING_MODEL=qwen/qwen3-embedding-8b`.
249
266
 
267
+ Requesty embeddings work the same way with
268
+ `base_url = "https://router.requesty.ai/v1"`. Memorix then accepts
269
+ `REQUESTY_API_KEY` for the embedding endpoint and, when no `model` is
270
+ configured, defaults to `openai/text-embedding-3-small`.
271
+
250
272
  ### Large-store retrieval
251
273
 
252
274
  Memorix does not cap the number of durable observations to make search fast.