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/dist/index.js CHANGED
@@ -3818,6 +3818,7 @@ function getResolvedConfig(options = {}) {
3818
3818
  const legacy = loadFileConfig(homeDir);
3819
3819
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3820
3820
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3821
+ const requestyEmbeddingApiKey = isRequestyUrl(embeddingBaseUrl) ? process.env.REQUESTY_API_KEY : void 0;
3821
3822
  const memoryLlmProvider = first(
3822
3823
  process.env.MEMORIX_LLM_PROVIDER,
3823
3824
  toml.memory?.llm?.provider,
@@ -3838,16 +3839,18 @@ function getResolvedConfig(options = {}) {
3838
3839
  );
3839
3840
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3840
3841
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
3842
+ const isRequesty = memoryLlmProvider === "requesty";
3843
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty;
3841
3844
  const memoryLlmApiKey = first(
3842
3845
  process.env.MEMORIX_LLM_API_KEY,
3843
3846
  process.env.MEMORIX_API_KEY,
3844
3847
  toml.memory?.llm?.api_key,
3845
3848
  yaml.llm?.apiKey,
3846
3849
  legacy.llm?.apiKey,
3847
- // Never borrow another provider's credentials for the Atlas Cloud preset.
3848
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3849
- isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3850
- isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3850
+ // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
3851
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
3852
+ usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
3853
+ usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
3851
3854
  );
3852
3855
  const resolved = {
3853
3856
  agent: {
@@ -3896,7 +3899,7 @@ function getResolvedConfig(options = {}) {
3896
3899
  provider: first(process.env.MEMORIX_EMBEDDING, toml.embedding?.provider, yaml.embedding?.provider, legacy.embedding, "off"),
3897
3900
  model: first(process.env.MEMORIX_EMBEDDING_MODEL, toml.embedding?.model, yaml.embedding?.model, legacy.embeddingApi?.model),
3898
3901
  baseUrl: embeddingBaseUrl,
3899
- apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
3902
+ apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey, requestyEmbeddingApiKey),
3900
3903
  dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
3901
3904
  },
3902
3905
  rerank: resolveRerankLane({
@@ -4027,6 +4030,7 @@ function getEnvSourceNames() {
4027
4030
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
4028
4031
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
4029
4032
  "OPENROUTER_API_KEY",
4033
+ "REQUESTY_API_KEY",
4030
4034
  "ATLASCLOUD_API_KEY"
4031
4035
  ].filter((name) => process.env[name]);
4032
4036
  }
@@ -4039,6 +4043,15 @@ function isOpenRouterUrl(value) {
4039
4043
  return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
4040
4044
  }
4041
4045
  }
4046
+ function isRequestyUrl(value) {
4047
+ if (!value) return false;
4048
+ try {
4049
+ const url = new URL(value);
4050
+ return url.hostname.toLowerCase() === "requesty.ai" || url.hostname.toLowerCase().endsWith(".requesty.ai");
4051
+ } catch {
4052
+ return /(^|\.)requesty\.ai(?::|\/|$)/i.test(value);
4053
+ }
4054
+ }
4042
4055
  function isOpenRouterMemoryLane(provider2, baseUrl) {
4043
4056
  return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
4044
4057
  }
@@ -4193,6 +4206,9 @@ function defaultEmbeddingModelFor(baseUrl, explicitModel) {
4193
4206
  if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
4194
4207
  return "qwen/qwen3-embedding-8b";
4195
4208
  }
4209
+ if (url && (url.hostname === "requesty.ai" || url.hostname.endsWith(".requesty.ai"))) {
4210
+ return "openai/text-embedding-3-small";
4211
+ }
4196
4212
  } catch {
4197
4213
  }
4198
4214
  return "text-embedding-3-small";
@@ -7007,6 +7023,7 @@ var init_provider2 = __esm({
7007
7023
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
7008
7024
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
7009
7025
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
7026
+ requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
7010
7027
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
7011
7028
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
7012
7029
  };
@@ -160104,7 +160121,7 @@ var init_request_context = __esm({
160104
160121
  function getMcpServerInfo() {
160105
160122
  return {
160106
160123
  name: "memorix",
160107
- version: true ? "1.9.7" : "1.0.1"
160124
+ version: true ? "1.9.9" : "1.0.1"
160108
160125
  };
160109
160126
  }
160110
160127
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -167573,7 +167590,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
167573
167590
  "MEMORIX_API_KEY",
167574
167591
  "OPENAI_API_KEY",
167575
167592
  "ANTHROPIC_API_KEY",
167576
- ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : []
167593
+ ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : [],
167594
+ ...resolved.memory.llm.provider === "requesty" ? ["REQUESTY_API_KEY"] : []
167577
167595
  ];
167578
167596
  if (llmKey) {
167579
167597
  const src = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
@@ -169158,7 +169176,7 @@ async function analyzeImage(input) {
169158
169176
  const config = getLLMConfig();
169159
169177
  if (!OPENAI_COMPATIBLE_PROVIDERS.has(config.provider)) {
169160
169178
  throw new Error(
169161
- `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.`
169179
+ `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.`
169162
169180
  );
169163
169181
  }
169164
169182
  const bytes = decodeBase64ImagePayload(input.base64, MAX_VISION_IMAGE_BYTES);
@@ -169197,7 +169215,7 @@ var init_image_loader = __esm({
169197
169215
  init_provider2();
169198
169216
  init_secret_filter();
169199
169217
  init_image_payload();
169200
- OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "custom"]);
169218
+ OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "requesty", "custom"]);
169201
169219
  MAX_VISION_PROMPT_CHARS = 12e3;
169202
169220
  MAX_VISION_DESCRIPTION_CHARS = 12e3;
169203
169221
  MAX_VISION_LABELS = 50;
@@ -170093,6 +170111,161 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
170093
170111
  },
170094
170112
  };
170095
170113
  };
170114
+
170115
+ /**
170116
+ * OpenCode v2 compatibility layer. Keep this beside the v1 export so one
170117
+ * generated file can be loaded by both host generations during migration.
170118
+ */
170119
+ const v2HookCommand = ${hookCommand};
170120
+
170121
+ function v2ReportHookFailure(eventName, detail) {
170122
+ if (process.env.MEMORIX_HOOK_DEBUG !== '1') return;
170123
+ console.error('[memorix-plugin] v2 hook delivery failed:', eventName, detail);
170124
+ }
170125
+
170126
+ function v2EventData(event) {
170127
+ return event && typeof event.data === 'object' && event.data !== null ? event.data : {};
170128
+ }
170129
+
170130
+ function v2SessionId(event) {
170131
+ const data = v2EventData(event);
170132
+ const value = data.sessionID ?? data.sessionId ?? data.session_id
170133
+ ?? event?.sessionID ?? event?.sessionId;
170134
+ return typeof value === 'string' ? value : '';
170135
+ }
170136
+
170137
+ function v2RunHook(payload, directory, sessionId) {
170138
+ const nextPayload = { agent: 'opencode', cwd: directory, ...payload };
170139
+ if (sessionId) nextPayload.session_id = sessionId;
170140
+ const eventName = nextPayload.hook_event_name || 'unknown';
170141
+ try {
170142
+ const result = spawnSync(v2HookCommand, ['hook'], {
170143
+ input: JSON.stringify(nextPayload),
170144
+ timeout: 10_000,
170145
+ encoding: 'utf-8',
170146
+ stdio: ['pipe', 'pipe', 'pipe'],
170147
+ shell: process.platform === 'win32',
170148
+ windowsHide: true,
170149
+ });
170150
+ if (result.status !== 0) {
170151
+ v2ReportHookFailure(eventName, {
170152
+ exit: result.status,
170153
+ stderr: (result.stderr || '').slice(0, 200),
170154
+ error: result.error?.message,
170155
+ });
170156
+ }
170157
+ } catch (error) {
170158
+ v2ReportHookFailure(eventName, error?.message ?? error);
170159
+ }
170160
+ }
170161
+
170162
+ function v2SessionState(states, sessionId) {
170163
+ const key = sessionId || '__unknown__';
170164
+ let state = states.get(key);
170165
+ if (!state) {
170166
+ state = { pendingText: '', lastDeliveredKey: '' };
170167
+ states.set(key, state);
170168
+ }
170169
+ return state;
170170
+ }
170171
+
170172
+ function v2FlushAssistant(state, directory, sessionId) {
170173
+ const text = state.pendingText.trim();
170174
+ if (!text || text === state.lastDeliveredKey) return;
170175
+ v2RunHook({ hook_event_name: 'message.updated', ai_response: text }, directory, sessionId);
170176
+ state.lastDeliveredKey = text;
170177
+ state.pendingText = '';
170178
+ }
170179
+
170180
+ function v2FilePath(file) {
170181
+ if (typeof file === 'string') return file;
170182
+ if (!file || typeof file !== 'object') return '';
170183
+ return file.path ?? file.file ?? file.name ?? '';
170184
+ }
170185
+
170186
+ function v2HandleEvent(event, directory, states) {
170187
+ if (!event || typeof event !== 'object') return;
170188
+ const type = typeof event.type === 'string' ? event.type : '';
170189
+ const data = v2EventData(event);
170190
+ const sessionId = v2SessionId(event);
170191
+ const state = v2SessionState(states, sessionId);
170192
+ const run = (payload) => v2RunHook(payload, directory, sessionId);
170193
+
170194
+ switch (type) {
170195
+ case 'session.created':
170196
+ run({ hook_event_name: 'session.created' });
170197
+ break;
170198
+ case 'session.text.delta':
170199
+ state.pendingText += typeof data.delta === 'string' ? data.delta : (typeof data.text === 'string' ? data.text : '');
170200
+ break;
170201
+ case 'session.message.updated':
170202
+ case 'message.updated':
170203
+ if (data.role === 'assistant' && typeof data.text === 'string') state.pendingText = data.text;
170204
+ break;
170205
+ case 'session.step.ended': {
170206
+ const files = Array.isArray(data.files) ? data.files : [];
170207
+ for (const file of files) {
170208
+ const filePath = v2FilePath(file);
170209
+ if (filePath) run({ hook_event_name: 'file.edited', file_path: filePath });
170210
+ }
170211
+ if (typeof data.text === 'string') state.pendingText += data.text;
170212
+ break;
170213
+ }
170214
+ case 'session.idle':
170215
+ v2FlushAssistant(state, directory, sessionId);
170216
+ run({ hook_event_name: 'session.idle' });
170217
+ break;
170218
+ case 'session.compacted':
170219
+ run({ hook_event_name: 'session.compacted' });
170220
+ break;
170221
+ default:
170222
+ break;
170223
+ }
170224
+ }
170225
+
170226
+ function setup(ctx) {
170227
+ const directory = ctx?.location?.directory || ctx?.location?.worktree || process.cwd();
170228
+ const controller = new AbortController();
170229
+ const states = new Map();
170230
+
170231
+ if (ctx?.tool?.hook) {
170232
+ try {
170233
+ Promise.resolve(ctx.tool.hook('execute.after', async (event) => {
170234
+ const sessionId = v2SessionId(event);
170235
+ const data = event && typeof event.input === 'object' ? event.input : {};
170236
+ const tool = event?.tool ?? event?.name ?? '';
170237
+ v2RunHook({
170238
+ hook_event_name: 'tool.execute.after',
170239
+ tool_name: tool,
170240
+ tool_input: data,
170241
+ }, directory, sessionId);
170242
+ if (tool === 'shell') {
170243
+ v2RunHook({
170244
+ hook_event_name: 'command.executed',
170245
+ command: data.command ?? data.cmd ?? '',
170246
+ }, directory, sessionId);
170247
+ }
170248
+ })).catch((error) => v2ReportHookFailure('execute.after', error?.message ?? error));
170249
+ } catch (error) {
170250
+ v2ReportHookFailure('execute.after', error?.message ?? error);
170251
+ }
170252
+ }
170253
+
170254
+ if (ctx?.event?.subscribe) {
170255
+ void (async () => {
170256
+ try {
170257
+ const stream = ctx.event.subscribe({ signal: controller.signal });
170258
+ for await (const event of stream) v2HandleEvent(event, directory, states);
170259
+ } catch (error) {
170260
+ if (!controller.signal.aborted) v2ReportHookFailure('event.subscribe', error?.message ?? error);
170261
+ }
170262
+ })();
170263
+ }
170264
+
170265
+ return () => controller.abort();
170266
+ }
170267
+
170268
+ export default { id: 'memorix', setup };
170096
170269
  `;
170097
170270
  }
170098
170271
  async function installOpenCodeSkills(projectRoot, global2 = false) {
@@ -170918,7 +171091,7 @@ var init_installers = __esm({
170918
171091
  "use strict";
170919
171092
  init_esm_shims();
170920
171093
  init_official_skills();
170921
- OPENCODE_PLUGIN_VERSION = 7;
171094
+ OPENCODE_PLUGIN_VERSION = 8;
170922
171095
  AGENT_SKILL_DIRS = {
170923
171096
  cursor: { project: path34.join(".cursor", "skills"), global: path34.join(".cursor", "skills") },
170924
171097
  windsurf: { project: path34.join(".windsurf", "skills"), global: path34.join(".windsurf", "skills") },
@@ -176442,7 +176615,7 @@ var init_serve_shared = __esm({
176442
176615
 
176443
176616
  // src/cli/version.ts
176444
176617
  function getCliVersion() {
176445
- return true ? "1.9.7" : pkg.version;
176618
+ return true ? "1.9.9" : pkg.version;
176446
176619
  }
176447
176620
  var init_version3 = __esm({
176448
176621
  "src/cli/version.ts"() {
@@ -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,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