memorix 1.9.7 → 1.9.9

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 +15 -0
  2. package/README.md +2 -0
  3. package/README.zh-CN.md +2 -0
  4. package/dist/cli/index.js +192 -11
  5. package/dist/index.js +184 -11
  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 +15 -0
  10. package/dist/sdk.js +183 -10
  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 +160 -3
  37. package/src/llm/provider.ts +2 -1
  38. package/src/multimodal/image-loader.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ All notable changes to this project will be documented in this file.
6
6
 
7
7
  No unreleased changes.
8
8
 
9
+ ## [1.9.9] - 2026-10-02
10
+
11
+ ### Added
12
+ - **Requesty memory preset** -- `memorix init` and the configuration TUI can
13
+ select Requesty for optional background memory LLM work through its
14
+ OpenAI-compatible endpoint, with provider-specific key isolation.
15
+ `REQUESTY_API_KEY` is also accepted for Requesty embedding endpoints.
16
+
17
+ ## [1.9.8] - 2026-10-02
18
+
19
+ ### Fixed
20
+ - **OpenCode v2 plugin compatibility** -- generated plugins retain the v1
21
+ named export while also exposing the v2 default `id`/`setup` contract,
22
+ including event subscriptions, tool hooks, cleanup, and host session IDs.
23
+
9
24
  ## [1.9.7] - 2026-09-28
10
25
 
11
26
  ### Fixed
package/README.md CHANGED
@@ -533,6 +533,8 @@ OpenAI-compatible `https://api.atlascloud.ai/v1` endpoint and reads
533
533
 
534
534
  For OpenRouter embeddings, use `provider = "api"`, `base_url = "https://openrouter.ai/api/v1"`, and `model = "qwen/qwen3-embedding-8b"`. Memorix accepts `OPENROUTER_API_KEY` for that embedding endpoint; `MEMORIX_EMBEDDING_API_KEY` remains the explicit override.
535
535
 
536
+ For Requesty, choose Requesty in `memorix init` or set `provider = "requesty"` in `[memory.llm]` (endpoint `https://router.requesty.ai/v1`, key from `REQUESTY_API_KEY` or `MEMORIX_LLM_API_KEY`). Requesty embeddings use `provider = "api"`, `base_url = "https://router.requesty.ai/v1"`, and `model = "openai/text-embedding-3-small"` with `REQUESTY_API_KEY`.
537
+
536
538
  For controlled MiniMax media generation, set `MINIMAX_API_KEY` (global) or
537
539
  `MINIMAX_CN_API_KEY` (China region) in your environment or `.env`. The media
538
540
  library never stores that key, a signed output URL, or base64 payloads. CLI
package/README.zh-CN.md CHANGED
@@ -506,6 +506,8 @@ OpenAI-compatible 的 `https://api.atlascloud.ai/v1` endpoint,并读取
506
506
 
507
507
  如果使用 OpenRouter embedding,可以设置 `provider = "api"`、`base_url = "https://openrouter.ai/api/v1"`、`model = "qwen/qwen3-embedding-8b"`。这个 endpoint 下 Memorix 会读取官方 `OPENROUTER_API_KEY`;需要单独覆盖 embedding key 时仍可用 `MEMORIX_EMBEDDING_API_KEY`。
508
508
 
509
+ 使用 Requesty 时,可在 `memorix init` 中选择 Requesty,或在 `[memory.llm]` 中设置 `provider = "requesty"`(endpoint 为 `https://router.requesty.ai/v1`,key 读取 `REQUESTY_API_KEY` 或 `MEMORIX_LLM_API_KEY`)。Requesty embedding 使用 `provider = "api"`、`base_url = "https://router.requesty.ai/v1"`、`model = "openai/text-embedding-3-small"`,并读取 `REQUESTY_API_KEY`。
510
+
509
511
  受控 MiniMax 媒体生成可在环境变量或 `.env` 中设置全局 `MINIMAX_API_KEY`,或中国区 `MINIMAX_CN_API_KEY`。媒体库不会保存该 key、临时签名 URL 或 base64 负载。CLI 生成本身就是显式操作;若要让 MCP 中的 Agent 发起生成,还必须明确设置 `MEMORIX_MCP_MEDIA_GENERATION=1`。
510
512
 
511
513
  <h2 id="docker"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-docker.svg"><img src="assets/tags/section-docker.svg" alt="Docker" height="32" /></picture></h2>
package/dist/cli/index.js CHANGED
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
3232
3232
 
3233
3233
  // src/cli/version.ts
3234
3234
  function getCliVersion() {
3235
- return true ? "1.9.7" : pkg.version;
3235
+ return true ? "1.9.9" : pkg.version;
3236
3236
  }
3237
3237
  var init_version = __esm({
3238
3238
  "src/cli/version.ts"() {
@@ -22122,6 +22122,7 @@ function getResolvedConfig(options = {}) {
22122
22122
  const legacy = loadFileConfig(homeDir);
22123
22123
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
22124
22124
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
22125
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
22125
22126
  const memoryLlmProvider = first(
22126
22127
  process.env.MEMORIX_LLM_PROVIDER,
22127
22128
  toml.memory?.llm?.provider,
@@ -22142,16 +22143,18 @@ function getResolvedConfig(options = {}) {
22142
22143
  );
22143
22144
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
22144
22145
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
22146
+ const isRequesty = memoryLlmProvider === "requesty";
22147
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
22145
22148
  const memoryLlmApiKey = first(
22146
22149
  process.env.MEMORIX_LLM_API_KEY,
22147
22150
  process.env.MEMORIX_API_KEY,
22148
22151
  toml.memory?.llm?.api_key,
22149
22152
  yaml.llm?.apiKey,
22150
22153
  legacy.llm?.apiKey,
22151
- // Never borrow another provider's credentials for the Atlas Cloud preset.
22152
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
22153
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
22154
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
22154
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
22155
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
22156
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
22157
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
22155
22158
  );
22156
22159
  const resolved = {
22157
22160
  agent: {
@@ -22200,7 +22203,7 @@ function getResolvedConfig(options = {}) {
22200
22203
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
22201
22204
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
22202
22205
  baseUrl: embeddingBaseUrl,
22203
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
22206
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
22204
22207
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
22205
22208
  },
22206
22209
  rerank: resolveRerankLane({
@@ -22331,6 +22334,7 @@ function getEnvSourceNames() {
22331
22334
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
22332
22335
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
22333
22336
  "OPENROUTER_API_KEY",
22337
+ "REQUESTY_API_KEY",
22334
22338
  "ATLASCLOUD_API_KEY"
22335
22339
  ].filter((name) => process.env[name]);
22336
22340
  }
@@ -22343,6 +22347,15 @@ function isOpenRouterUrl(value) {
22343
22347
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
22344
22348
  }
22345
22349
  }
22350
+ function isRequestyUrl(value) {
22351
+ if (!value) return false;
22352
+ try {
22353
+ const url2 = new URL(value);
22354
+ return url2.hostname.toLowerCase() === "requesty.ai" || url2.hostname.toLowerCase().endsWith(".requesty.ai");
22355
+ } catch {
22356
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
22357
+ }
22358
+ }
22346
22359
  function isOpenRouterMemoryLane(provider2, baseUrl) {
22347
22360
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
22348
22361
  }
@@ -22497,6 +22510,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
22497
22510
  if (url2 && (url2.hostname === "openrouter.ai" || url2.hostname.endsWith(".openrouter.ai"))) {
22498
22511
  return "qwen/qwen3-embedding-8b";
22499
22512
  }
22513
+ if (url2 && (url2.hostname === "requesty.ai" || url2.hostname.endsWith(".requesty.ai"))) {
22514
+ return "openai/text-embedding-3-small";
22515
+ }
22500
22516
  } catch {
22501
22517
  }
22502
22518
  return "text-embedding-3-small";
@@ -25311,6 +25327,7 @@ var init_provider2 = __esm({
25311
25327
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
25312
25328
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
25313
25329
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
25330
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
25314
25331
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
25315
25332
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
25316
25333
  };
@@ -193093,6 +193110,8 @@ function buildInitTomlConfig(options) {
193093
193110
  lines.push('model = "claude-3-haiku-20240307"');
193094
193111
  } else if (options.llmProvider === "openrouter") {
193095
193112
  lines.push('# model = "openai/gpt-4o-mini"');
193113
+ } else if (options.llmProvider === "requesty") {
193114
+ lines.push('# model = "openai/gpt-4o-mini"');
193096
193115
  } else if (options.llmProvider === "atlascloud") {
193097
193116
  lines.push('model = "deepseek-ai/deepseek-v3.2"');
193098
193117
  }
@@ -193227,6 +193246,7 @@ var init_init = __esm({
193227
193246
  { value: "openai", label: "OpenAI", hint: "gpt-4o-mini" },
193228
193247
  { value: "anthropic", label: "Anthropic", hint: "claude-3-haiku" },
193229
193248
  { value: "openrouter", label: "OpenRouter", hint: "multi-provider" },
193249
+ { value: "requesty", label: "Requesty", hint: "multi-provider" },
193230
193250
  { value: "atlascloud", label: "Atlas Cloud", hint: "DeepSeek V3.2" },
193231
193251
  { value: "custom", label: "Custom", hint: "OpenAI-compatible endpoint" }
193232
193252
  ]
@@ -193287,6 +193307,8 @@ var init_init = __esm({
193287
193307
  envLines.push("MEMORIX_LLM_API_KEY=sk-ant-your-key-here");
193288
193308
  } else if (llmProvider === "openrouter") {
193289
193309
  envLines.push("MEMORIX_LLM_API_KEY=sk-or-your-key-here");
193310
+ } else if (llmProvider === "requesty") {
193311
+ envLines.push("MEMORIX_LLM_API_KEY=rqsty-your-key-here");
193290
193312
  }
193291
193313
  if (llmProvider === "custom") {
193292
193314
  envLines.push("# MEMORIX_LLM_BASE_URL=http://localhost:11434/v1");
@@ -193313,6 +193335,7 @@ var init_init = __esm({
193313
193335
  envLines.push("# OPENAI_API_KEY=sk-...");
193314
193336
  envLines.push("# ANTHROPIC_API_KEY=sk-ant-...");
193315
193337
  envLines.push("# OPENROUTER_API_KEY=sk-or-...");
193338
+ envLines.push("# REQUESTY_API_KEY=rqsty-...");
193316
193339
  envLines.push("");
193317
193340
  mkdirSync3(targetDir, { recursive: true });
193318
193341
  writeFileSync3(targetPath, tomlContent, "utf-8");
@@ -195667,6 +195690,161 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
195667
195690
  },
195668
195691
  };
195669
195692
  };
195693
+
195694
+ /**
195695
+ * OpenCode v2 compatibility layer. Keep this beside the v1 export so one
195696
+ * generated file can be loaded by both host generations during migration.
195697
+ */
195698
+ const v2HookCommand = ${hookCommand};
195699
+
195700
+ function v2ReportHookFailure(eventName, detail) {
195701
+ if (process.env.MEMORIX_HOOK_DEBUG !== '1') return;
195702
+ console.error('[memorix-plugin] v2 hook delivery failed:', eventName, detail);
195703
+ }
195704
+
195705
+ function v2EventData(event) {
195706
+ return event && typeof event.data === 'object' && event.data !== null ? event.data : {};
195707
+ }
195708
+
195709
+ function v2SessionId(event) {
195710
+ const data = v2EventData(event);
195711
+ const value = data.sessionID ?? data.sessionId ?? data.session_id
195712
+ ?? event?.sessionID ?? event?.sessionId;
195713
+ return typeof value === 'string' ? value : '';
195714
+ }
195715
+
195716
+ function v2RunHook(payload, directory, sessionId) {
195717
+ const nextPayload = { agent: 'opencode', cwd: directory, ...payload };
195718
+ if (sessionId) nextPayload.session_id = sessionId;
195719
+ const eventName = nextPayload.hook_event_name || 'unknown';
195720
+ try {
195721
+ const result = spawnSync(v2HookCommand, ['hook'], {
195722
+ input: JSON.stringify(nextPayload),
195723
+ timeout: 10_000,
195724
+ encoding: 'utf-8',
195725
+ stdio: ['pipe', 'pipe', 'pipe'],
195726
+ shell: process.platform === 'win32',
195727
+ windowsHide: true,
195728
+ });
195729
+ if (result.status !== 0) {
195730
+ v2ReportHookFailure(eventName, {
195731
+ exit: result.status,
195732
+ stderr: (result.stderr || '').slice(0, 200),
195733
+ error: result.error?.message,
195734
+ });
195735
+ }
195736
+ } catch (error) {
195737
+ v2ReportHookFailure(eventName, error?.message ?? error);
195738
+ }
195739
+ }
195740
+
195741
+ function v2SessionState(states, sessionId) {
195742
+ const key = sessionId || '__unknown__';
195743
+ let state = states.get(key);
195744
+ if (!state) {
195745
+ state = { pendingText: '', lastDeliveredKey: '' };
195746
+ states.set(key, state);
195747
+ }
195748
+ return state;
195749
+ }
195750
+
195751
+ function v2FlushAssistant(state, directory, sessionId) {
195752
+ const text = state.pendingText.trim();
195753
+ if (!text || text === state.lastDeliveredKey) return;
195754
+ v2RunHook({ hook_event_name: 'message.updated', ai_response: text }, directory, sessionId);
195755
+ state.lastDeliveredKey = text;
195756
+ state.pendingText = '';
195757
+ }
195758
+
195759
+ function v2FilePath(file) {
195760
+ if (typeof file === 'string') return file;
195761
+ if (!file || typeof file !== 'object') return '';
195762
+ return file.path ?? file.file ?? file.name ?? '';
195763
+ }
195764
+
195765
+ function v2HandleEvent(event, directory, states) {
195766
+ if (!event || typeof event !== 'object') return;
195767
+ const type = typeof event.type === 'string' ? event.type : '';
195768
+ const data = v2EventData(event);
195769
+ const sessionId = v2SessionId(event);
195770
+ const state = v2SessionState(states, sessionId);
195771
+ const run = (payload) => v2RunHook(payload, directory, sessionId);
195772
+
195773
+ switch (type) {
195774
+ case 'session.created':
195775
+ run({ hook_event_name: 'session.created' });
195776
+ break;
195777
+ case 'session.text.delta':
195778
+ state.pendingText += typeof data.delta === 'string' ? data.delta : (typeof data.text === 'string' ? data.text : '');
195779
+ break;
195780
+ case 'session.message.updated':
195781
+ case 'message.updated':
195782
+ if (data.role === 'assistant' && typeof data.text === 'string') state.pendingText = data.text;
195783
+ break;
195784
+ case 'session.step.ended': {
195785
+ const files = Array.isArray(data.files) ? data.files : [];
195786
+ for (const file of files) {
195787
+ const filePath = v2FilePath(file);
195788
+ if (filePath) run({ hook_event_name: 'file.edited', file_path: filePath });
195789
+ }
195790
+ if (typeof data.text === 'string') state.pendingText += data.text;
195791
+ break;
195792
+ }
195793
+ case 'session.idle':
195794
+ v2FlushAssistant(state, directory, sessionId);
195795
+ run({ hook_event_name: 'session.idle' });
195796
+ break;
195797
+ case 'session.compacted':
195798
+ run({ hook_event_name: 'session.compacted' });
195799
+ break;
195800
+ default:
195801
+ break;
195802
+ }
195803
+ }
195804
+
195805
+ function setup(ctx) {
195806
+ const directory = ctx?.location?.directory || ctx?.location?.worktree || process.cwd();
195807
+ const controller = new AbortController();
195808
+ const states = new Map();
195809
+
195810
+ if (ctx?.tool?.hook) {
195811
+ try {
195812
+ Promise.resolve(ctx.tool.hook('execute.after', async (event) => {
195813
+ const sessionId = v2SessionId(event);
195814
+ const data = event && typeof event.input === 'object' ? event.input : {};
195815
+ const tool = event?.tool ?? event?.name ?? '';
195816
+ v2RunHook({
195817
+ hook_event_name: 'tool.execute.after',
195818
+ tool_name: tool,
195819
+ tool_input: data,
195820
+ }, directory, sessionId);
195821
+ if (tool === 'shell') {
195822
+ v2RunHook({
195823
+ hook_event_name: 'command.executed',
195824
+ command: data.command ?? data.cmd ?? '',
195825
+ }, directory, sessionId);
195826
+ }
195827
+ })).catch((error) => v2ReportHookFailure('execute.after', error?.message ?? error));
195828
+ } catch (error) {
195829
+ v2ReportHookFailure('execute.after', error?.message ?? error);
195830
+ }
195831
+ }
195832
+
195833
+ if (ctx?.event?.subscribe) {
195834
+ void (async () => {
195835
+ try {
195836
+ const stream = ctx.event.subscribe({ signal: controller.signal });
195837
+ for await (const event of stream) v2HandleEvent(event, directory, states);
195838
+ } catch (error) {
195839
+ if (!controller.signal.aborted) v2ReportHookFailure('event.subscribe', error?.message ?? error);
195840
+ }
195841
+ })();
195842
+ }
195843
+
195844
+ return () => controller.abort();
195845
+ }
195846
+
195847
+ export default { id: 'memorix', setup };
195670
195848
  `;
195671
195849
  }
195672
195850
  async function installOpenCodeSkills(projectRoot, global2 = false) {
@@ -196492,7 +196670,7 @@ var init_installers = __esm({
196492
196670
  "use strict";
196493
196671
  init_esm_shims();
196494
196672
  init_official_skills();
196495
- OPENCODE_PLUGIN_VERSION = 7;
196673
+ OPENCODE_PLUGIN_VERSION = 8;
196496
196674
  AGENT_SKILL_DIRS = {
196497
196675
  cursor: { project: path31.join(".cursor", "skills"), global: path31.join(".cursor", "skills") },
196498
196676
  windsurf: { project: path31.join(".windsurf", "skills"), global: path31.join(".windsurf", "skills") },
@@ -209019,7 +209197,7 @@ var init_tool_profile = __esm({
209019
209197
  function getMcpServerInfo() {
209020
209198
  return {
209021
209199
  name: "memorix",
209022
- version: true ? "1.9.7" : "1.0.1"
209200
+ version: true ? "1.9.9" : "1.0.1"
209023
209201
  };
209024
209202
  }
209025
209203
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -224951,7 +225129,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
224951
225129
  "MEMORIX_API_KEY",
224952
225130
  "OPENAI_API_KEY",
224953
225131
  "ANTHROPIC_API_KEY",
224954
- ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
225132
+ ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : [],
225133
+ ...resolved.memory.llm.provider === "requesty" ? ["REQUESTY_API_KEY"] : []
224955
225134
  ];
224956
225135
  if (llmKey) {
224957
225136
  const src2 = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
@@ -265342,7 +265521,7 @@ async function analyzeImage(input) {
265342
265521
  const config2 = getLLMConfig();
265343
265522
  if (!OPENAI_COMPATIBLE_PROVIDERS.has(config2.provider)) {
265344
265523
  throw new Error(
265345
- `Image analysis requires an OpenAI-compatible provider (openai, openrouter, or custom). Current provider "${config2.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
265524
+ `Image analysis requires an OpenAI-compatible provider (openai, openrouter, requesty, or custom). Current provider "${config2.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
265346
265525
  );
265347
265526
  }
265348
265527
  const bytes = decodeBase64ImagePayload(input.base64, MAX_VISION_IMAGE_BYTES);
@@ -265381,7 +265560,7 @@ var init_image_loader = __esm({
265381
265560
  init_provider2();
265382
265561
  init_secret_filter();
265383
265562
  init_image_payload();
265384
- OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "custom"]);
265563
+ OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "requesty", "custom"]);
265385
265564
  MAX_VISION_PROMPT_CHARS = 12e3;
265386
265565
  MAX_VISION_DESCRIPTION_CHARS = 12e3;
265387
265566
  MAX_VISION_LABELS = 50;
@@ -289527,6 +289706,7 @@ function ConfigureView({ onBack }) {
289527
289706
  { key: "openai", label: "OpenAI", hint: "gpt-4o-mini" },
289528
289707
  { key: "anthropic", label: "Anthropic", hint: "claude-3-haiku" },
289529
289708
  { key: "openrouter", label: "OpenRouter", hint: "multi-provider" },
289709
+ { key: "requesty", label: "Requesty", hint: "multi-provider" },
289530
289710
  { key: "atlascloud", label: "Atlas Cloud", hint: "DeepSeek V3.2" },
289531
289711
  { key: "custom", label: "Custom endpoint", hint: "OpenAI-compatible" },
289532
289712
  { key: "disable", label: "Disable LLM", hint: "free heuristic mode", color: COLORS.warning },
@@ -289820,6 +290000,7 @@ function ConfigureView({ onBack }) {
289820
290000
  function getDefaultModel(provider2) {
289821
290001
  if (provider2 === "anthropic") return "claude-3-haiku-20240307";
289822
290002
  if (provider2 === "openrouter") return "openai/gpt-4o-mini";
290003
+ if (provider2 === "requesty") return "openai/gpt-4o-mini";
289823
290004
  if (provider2 === "atlascloud") return "deepseek-ai/deepseek-v3.2";
289824
290005
  return "gpt-4o-mini";
289825
290006
  }