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/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;
@@ -166086,6 +166104,161 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
166086
166104
  },
166087
166105
  };
166088
166106
  };
166107
+
166108
+ /**
166109
+ * OpenCode v2 compatibility layer. Keep this beside the v1 export so one
166110
+ * generated file can be loaded by both host generations during migration.
166111
+ */
166112
+ const v2HookCommand = ${hookCommand};
166113
+
166114
+ function v2ReportHookFailure(eventName, detail) {
166115
+ if (process.env.MEMORIX_HOOK_DEBUG !== '1') return;
166116
+ console.error('[memorix-plugin] v2 hook delivery failed:', eventName, detail);
166117
+ }
166118
+
166119
+ function v2EventData(event) {
166120
+ return event && typeof event.data === 'object' && event.data !== null ? event.data : {};
166121
+ }
166122
+
166123
+ function v2SessionId(event) {
166124
+ const data = v2EventData(event);
166125
+ const value = data.sessionID ?? data.sessionId ?? data.session_id
166126
+ ?? event?.sessionID ?? event?.sessionId;
166127
+ return typeof value === 'string' ? value : '';
166128
+ }
166129
+
166130
+ function v2RunHook(payload, directory, sessionId) {
166131
+ const nextPayload = { agent: 'opencode', cwd: directory, ...payload };
166132
+ if (sessionId) nextPayload.session_id = sessionId;
166133
+ const eventName = nextPayload.hook_event_name || 'unknown';
166134
+ try {
166135
+ const result = spawnSync(v2HookCommand, ['hook'], {
166136
+ input: JSON.stringify(nextPayload),
166137
+ timeout: 10_000,
166138
+ encoding: 'utf-8',
166139
+ stdio: ['pipe', 'pipe', 'pipe'],
166140
+ shell: process.platform === 'win32',
166141
+ windowsHide: true,
166142
+ });
166143
+ if (result.status !== 0) {
166144
+ v2ReportHookFailure(eventName, {
166145
+ exit: result.status,
166146
+ stderr: (result.stderr || '').slice(0, 200),
166147
+ error: result.error?.message,
166148
+ });
166149
+ }
166150
+ } catch (error) {
166151
+ v2ReportHookFailure(eventName, error?.message ?? error);
166152
+ }
166153
+ }
166154
+
166155
+ function v2SessionState(states, sessionId) {
166156
+ const key = sessionId || '__unknown__';
166157
+ let state = states.get(key);
166158
+ if (!state) {
166159
+ state = { pendingText: '', lastDeliveredKey: '' };
166160
+ states.set(key, state);
166161
+ }
166162
+ return state;
166163
+ }
166164
+
166165
+ function v2FlushAssistant(state, directory, sessionId) {
166166
+ const text = state.pendingText.trim();
166167
+ if (!text || text === state.lastDeliveredKey) return;
166168
+ v2RunHook({ hook_event_name: 'message.updated', ai_response: text }, directory, sessionId);
166169
+ state.lastDeliveredKey = text;
166170
+ state.pendingText = '';
166171
+ }
166172
+
166173
+ function v2FilePath(file) {
166174
+ if (typeof file === 'string') return file;
166175
+ if (!file || typeof file !== 'object') return '';
166176
+ return file.path ?? file.file ?? file.name ?? '';
166177
+ }
166178
+
166179
+ function v2HandleEvent(event, directory, states) {
166180
+ if (!event || typeof event !== 'object') return;
166181
+ const type = typeof event.type === 'string' ? event.type : '';
166182
+ const data = v2EventData(event);
166183
+ const sessionId = v2SessionId(event);
166184
+ const state = v2SessionState(states, sessionId);
166185
+ const run = (payload) => v2RunHook(payload, directory, sessionId);
166186
+
166187
+ switch (type) {
166188
+ case 'session.created':
166189
+ run({ hook_event_name: 'session.created' });
166190
+ break;
166191
+ case 'session.text.delta':
166192
+ state.pendingText += typeof data.delta === 'string' ? data.delta : (typeof data.text === 'string' ? data.text : '');
166193
+ break;
166194
+ case 'session.message.updated':
166195
+ case 'message.updated':
166196
+ if (data.role === 'assistant' && typeof data.text === 'string') state.pendingText = data.text;
166197
+ break;
166198
+ case 'session.step.ended': {
166199
+ const files = Array.isArray(data.files) ? data.files : [];
166200
+ for (const file of files) {
166201
+ const filePath = v2FilePath(file);
166202
+ if (filePath) run({ hook_event_name: 'file.edited', file_path: filePath });
166203
+ }
166204
+ if (typeof data.text === 'string') state.pendingText += data.text;
166205
+ break;
166206
+ }
166207
+ case 'session.idle':
166208
+ v2FlushAssistant(state, directory, sessionId);
166209
+ run({ hook_event_name: 'session.idle' });
166210
+ break;
166211
+ case 'session.compacted':
166212
+ run({ hook_event_name: 'session.compacted' });
166213
+ break;
166214
+ default:
166215
+ break;
166216
+ }
166217
+ }
166218
+
166219
+ function setup(ctx) {
166220
+ const directory = ctx?.location?.directory || ctx?.location?.worktree || process.cwd();
166221
+ const controller = new AbortController();
166222
+ const states = new Map();
166223
+
166224
+ if (ctx?.tool?.hook) {
166225
+ try {
166226
+ Promise.resolve(ctx.tool.hook('execute.after', async (event) => {
166227
+ const sessionId = v2SessionId(event);
166228
+ const data = event && typeof event.input === 'object' ? event.input : {};
166229
+ const tool = event?.tool ?? event?.name ?? '';
166230
+ v2RunHook({
166231
+ hook_event_name: 'tool.execute.after',
166232
+ tool_name: tool,
166233
+ tool_input: data,
166234
+ }, directory, sessionId);
166235
+ if (tool === 'shell') {
166236
+ v2RunHook({
166237
+ hook_event_name: 'command.executed',
166238
+ command: data.command ?? data.cmd ?? '',
166239
+ }, directory, sessionId);
166240
+ }
166241
+ })).catch((error) => v2ReportHookFailure('execute.after', error?.message ?? error));
166242
+ } catch (error) {
166243
+ v2ReportHookFailure('execute.after', error?.message ?? error);
166244
+ }
166245
+ }
166246
+
166247
+ if (ctx?.event?.subscribe) {
166248
+ void (async () => {
166249
+ try {
166250
+ const stream = ctx.event.subscribe({ signal: controller.signal });
166251
+ for await (const event of stream) v2HandleEvent(event, directory, states);
166252
+ } catch (error) {
166253
+ if (!controller.signal.aborted) v2ReportHookFailure('event.subscribe', error?.message ?? error);
166254
+ }
166255
+ })();
166256
+ }
166257
+
166258
+ return () => controller.abort();
166259
+ }
166260
+
166261
+ export default { id: 'memorix', setup };
166089
166262
  `;
166090
166263
  }
166091
166264
  async function installOpenCodeSkills(projectRoot, global2 = false) {
@@ -166911,7 +167084,7 @@ var init_installers = __esm({
166911
167084
  "use strict";
166912
167085
  init_esm_shims();
166913
167086
  init_official_skills();
166914
- OPENCODE_PLUGIN_VERSION = 7;
167087
+ OPENCODE_PLUGIN_VERSION = 8;
166915
167088
  AGENT_SKILL_DIRS = {
166916
167089
  cursor: { project: path34.join(".cursor", "skills"), global: path34.join(".cursor", "skills") },
166917
167090
  windsurf: { project: path34.join(".windsurf", "skills"), global: path34.join(".windsurf", "skills") },
@@ -170816,7 +170989,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
170816
170989
  function getMcpServerInfo() {
170817
170990
  return {
170818
170991
  name: "memorix",
170819
- version: true ? "1.9.7" : "1.0.1"
170992
+ version: true ? "1.9.9" : "1.0.1"
170820
170993
  };
170821
170994
  }
170822
170995
  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.
@@ -13,7 +13,7 @@ Memorix is a TypeScript project built around:
13
13
 
14
14
  ## Current Development Baseline
15
15
 
16
- The current release line is **1.9.7** and package metadata is kept synchronized
16
+ The current release line is **1.9.9** and package metadata is kept synchronized
17
17
  with the root package and MCP Registry manifest.
18
18
 
19
19
  Contributors should assume the following areas are part of the current release line:
@@ -55,7 +55,7 @@ Generated guidance also has scope:
55
55
  | Cursor | `memorix setup --agent cursor --global` | Cursor MCP and rules config | Cursor MCP config, `.cursor/rules/memorix.mdc`, skills, and hook guidance | Reload Cursor after setup so it can pick up project config changes. |
56
56
  | Grok Build | `memorix setup --agent grok --global` | `~/.grok/hooks/memorix.json` + `~/.grok/AGENTS.md` | Lifecycle hooks on SessionStart, SessionEnd, UserPromptSubmit, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, Stop, and StopFailure, plus Grok project/global guidance | Uses Grok's own JSON hook directory. MCP stays host-owned unless you pass `--mcp http`, which writes `[mcp_servers.memorix]` with `url = "http://localhost:3211/mcp"` in Grok `config.toml`. Global hooks are trusted; project hooks require Grok `/hooks-trust`. Set `GROK_HOME` to use a custom Grok home. The command is `memorix hook --agent grok`. |
57
57
  | Gemini CLI | `memorix setup --agent gemini-cli --global` | Gemini CLI extension | Extension under `~/.gemini/extensions/memorix` with MCP, `GEMINI.md` context, hooks, commands, and skills | Antigravity CLI has an official Gemini CLI migration path, but Gemini CLI remains an active standalone Google CLI target. |
58
- | OpenCode | `memorix setup --agent opencode --global` | OpenCode local plugin file | Global setup writes `~/.config/opencode/plugins/memorix.js`, `~/.config/opencode/opencode.json`, skills, and `AGENTS.md` guidance; repo-local setup writes the `.opencode/` equivalents. | OpenCode loads local plugin and skill files from its config scope. |
58
+ | OpenCode | `memorix setup --agent opencode --global` | OpenCode local plugin file | Global setup writes `~/.config/opencode/plugins/memorix.js`, `~/.config/opencode/opencode.json`, skills, and `AGENTS.md` guidance; repo-local setup writes the `.opencode/` equivalents. | The generated plugin keeps the v1 named export and also exposes the v2 default `id`/`setup` contract. v2 event subscriptions use the host session ID when forwarding hooks. |
59
59
  | OpenClaw | `memorix setup --agent openclaw --global` | OpenClaw compatible bundle | `~/.openclaw/extensions/memorix` with `.mcp.json`, skills, and OpenClaw `HOOK.md`/`handler.ts` hook pack | Setup attempts `openclaw plugins install <path> --force` and `openclaw hooks enable memorix` when OpenClaw is available. |
60
60
  | Hermes Agent | `memorix setup --agent hermes --global` | Hermes plugin | Hermes home (`%LOCALAPPDATA%\hermes` on native Windows, `~/.hermes` elsewhere, or `HERMES_HOME`), plugin enablement in `config.yaml`, and `mcp_servers.memorix` | The plugin registers hooks, a slash command, a CLI command, and skills through Hermes' plugin context. Existing YAML keys are preserved. |
61
61
  | Oh-my-Pi | `memorix setup --agent omp --global` | Oh-my-Pi `omp.extensions` package | `.omp/packages/memorix` or `~/.omp/agent/packages/memorix`, plus `.omp/mcp.json` or `~/.omp/agent/mcp.json` | Setup attempts `omp plugin link <path>`. This target uses Oh-my-Pi's package/extension manifest, not Pi's legacy package manifest. |
package/docs/README.md CHANGED
@@ -126,7 +126,7 @@ Historical/deep-reference documents may describe older designs. If they conflict
126
126
 
127
127
  ## Current Product Line
128
128
 
129
- The current product line is **1.9.7**. Multi-device store sync is opt-in and
129
+ The current product line is **1.9.9**. Multi-device store sync is opt-in and
130
130
  keeps local SQLite canonical; existing users do not upload anything until they
131
131
  configure a relay provider explicitly.
132
132
  The authoritative acceptance contract for the current implementation is
package/docs/SETUP.md CHANGED
@@ -502,7 +502,7 @@ OpenCode can also use a local Memorix plugin generated by setup:
502
502
  memorix setup --agent opencode --global
503
503
  ```
504
504
 
505
- This writes the OpenCode plugin, skills, MCP config, and `AGENTS.md` guidance in the selected scope.
505
+ This writes the OpenCode plugin, skills, MCP config, and `AGENTS.md` guidance in the selected scope. The generated plugin exports both the legacy v1 hook function and the v2 default `id`/`setup` contract, so OpenCode v1 and v2 can load the same file during the migration window.
506
506
 
507
507
  Antigravity setup installs a native plugin at `~/.gemini/config/plugins/memorix` for global setup or `.agents/plugins/memorix` for workspace setup. The plugin includes stdio MCP, official hooks, rules, and skills:
508
508
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memorix",
3
3
  "mcpName": "io.github.AVIDS2/memorix",
4
- "version": "1.9.7",
4
+ "version": "1.9.9",
5
5
  "description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7"
3
+ "version": "1.9.9"
4
4
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memorix",
4
- "version": "1.9.7",
4
+ "version": "1.9.9",
5
5
  "description": "Shared workspace memory for Claude Code and other AI coding agents.",
6
6
  "author": {
7
7
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Local-first project memory for CodeBuddy Code and other coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Shared workspace memory for Codex and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Shared local workspace memory for GitHub Copilot CLI and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "mcpServers": {
5
5
  "memorix": {
6
6
  "command": "memorix",
@@ -1,5 +1,5 @@
1
1
  name: memorix
2
- version: "1.9.7"
2
+ version: "1.9.9"
3
3
  description: Shared workspace memory bridge for Hermes Agent.
4
4
  author: AVIDS2
5
5
  license: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix-omp-package",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Memorix shared workspace memory package for Oh-my-Pi.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Shared workspace memory for OpenClaw and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix-pi-package",
3
- "version": "1.9.7",
3
+ "version": "1.9.9",
4
4
  "description": "Memorix shared workspace memory package for Pi coding agent.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
package/server.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "url": "https://github.com/AVIDS2/memorix",
8
8
  "source": "github"
9
9
  },
10
- "version": "1.9.7",
10
+ "version": "1.9.9",
11
11
  "websiteUrl": "https://mem.rglens.com",
12
12
  "icons": [
13
13
  {
@@ -22,7 +22,7 @@
22
22
  {
23
23
  "registryType": "npm",
24
24
  "identifier": "memorix",
25
- "version": "1.9.7",
25
+ "version": "1.9.9",
26
26
  "runtimeHint": "npx",
27
27
  "packageArguments": [
28
28
  {
@@ -21,7 +21,7 @@ import {
21
21
  type InitScope,
22
22
  } from './init-shared.js';
23
23
 
24
- type InitLlmProvider = 'none' | 'openai' | 'anthropic' | 'openrouter' | 'atlascloud' | 'custom';
24
+ type InitLlmProvider = 'none' | 'openai' | 'anthropic' | 'openrouter' | 'requesty' | 'atlascloud' | 'custom';
25
25
  type InitEmbeddingProvider = 'off' | 'api' | 'fastembed';
26
26
  type InitInjectMode = 'minimal' | 'full' | 'silent';
27
27
 
@@ -103,6 +103,7 @@ export default defineCommand({
103
103
  { value: 'openai', label: 'OpenAI', hint: 'gpt-4o-mini' },
104
104
  { value: 'anthropic', label: 'Anthropic', hint: 'claude-3-haiku' },
105
105
  { value: 'openrouter', label: 'OpenRouter', hint: 'multi-provider' },
106
+ { value: 'requesty', label: 'Requesty', hint: 'multi-provider' },
106
107
  { value: 'atlascloud', label: 'Atlas Cloud', hint: 'DeepSeek V3.2' },
107
108
  { value: 'custom', label: 'Custom', hint: 'OpenAI-compatible endpoint' },
108
109
  ],
@@ -169,6 +170,8 @@ export default defineCommand({
169
170
  envLines.push('MEMORIX_LLM_API_KEY=sk-ant-your-key-here');
170
171
  } else if (llmProvider === 'openrouter') {
171
172
  envLines.push('MEMORIX_LLM_API_KEY=sk-or-your-key-here');
173
+ } else if (llmProvider === 'requesty') {
174
+ envLines.push('MEMORIX_LLM_API_KEY=rqsty-your-key-here');
172
175
  }
173
176
  if (llmProvider === 'custom') {
174
177
  envLines.push('# MEMORIX_LLM_BASE_URL=http://localhost:11434/v1');
@@ -197,6 +200,7 @@ export default defineCommand({
197
200
  envLines.push('# OPENAI_API_KEY=sk-...');
198
201
  envLines.push('# ANTHROPIC_API_KEY=sk-ant-...');
199
202
  envLines.push('# OPENROUTER_API_KEY=sk-or-...');
203
+ envLines.push('# REQUESTY_API_KEY=rqsty-...');
200
204
  envLines.push('');
201
205
 
202
206
  mkdirSync(targetDir, { recursive: true });
@@ -293,6 +297,8 @@ export function buildInitTomlConfig(options: {
293
297
  lines.push('model = "claude-3-haiku-20240307"');
294
298
  } else if (options.llmProvider === 'openrouter') {
295
299
  lines.push('# model = "openai/gpt-4o-mini"');
300
+ } else if (options.llmProvider === 'requesty') {
301
+ lines.push('# model = "openai/gpt-4o-mini"');
296
302
  } else if (options.llmProvider === 'atlascloud') {
297
303
  lines.push('model = "deepseek-ai/deepseek-v3.2"');
298
304
  }
@@ -166,6 +166,7 @@ export function ConfigureView({ onBack }: ConfigureViewProps): React.ReactElemen
166
166
  { key: 'openai', label: 'OpenAI', hint: 'gpt-4o-mini' },
167
167
  { key: 'anthropic', label: 'Anthropic', hint: 'claude-3-haiku' },
168
168
  { key: 'openrouter', label: 'OpenRouter', hint: 'multi-provider' },
169
+ { key: 'requesty', label: 'Requesty', hint: 'multi-provider' },
169
170
  { key: 'atlascloud', label: 'Atlas Cloud', hint: 'DeepSeek V3.2' },
170
171
  { key: 'custom', label: 'Custom endpoint', hint: 'OpenAI-compatible' },
171
172
  { key: 'disable', label: 'Disable LLM', hint: 'free heuristic mode', color: COLORS.warning },
@@ -447,6 +448,7 @@ export function ConfigureView({ onBack }: ConfigureViewProps): React.ReactElemen
447
448
  function getDefaultModel(provider: string): string {
448
449
  if (provider === 'anthropic') return 'claude-3-haiku-20240307';
449
450
  if (provider === 'openrouter') return 'openai/gpt-4o-mini';
451
+ if (provider === 'requesty') return 'openai/gpt-4o-mini';
450
452
  if (provider === 'atlascloud') return 'deepseek-ai/deepseek-v3.2';
451
453
  return 'gpt-4o-mini';
452
454
  }
@@ -143,6 +143,7 @@ export function getLoadedEnvValue(key: string): string | undefined {
143
143
  // OPENAI_API_KEY — OpenAI compatibility fallback
144
144
  // ANTHROPIC_API_KEY — Anthropic compatibility fallback
145
145
  // OPENROUTER_API_KEY — OpenRouter compatibility fallback
146
+ // REQUESTY_API_KEY - Requesty memory preset and embedding endpoint key
146
147
  // MINIMAX_API_KEY — MiniMax global image/video generation key
147
148
  // MINIMAX_CN_API_KEY — MiniMax China-region image/video generation key
148
149
  // MINIMAX_REGION — MiniMax region: global or cn