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.
- package/CHANGELOG.md +15 -0
- package/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/cli/index.js +192 -11
- package/dist/index.js +184 -11
- package/dist/maintenance-runner.js +22 -5
- package/dist/media-audio-runner.js +22 -5
- package/dist/media-video-runner.js +22 -5
- package/dist/memcode-runtime/CHANGELOG.md +15 -0
- package/dist/sdk.js +183 -10
- package/dist/vector-backfill-runner.js +22 -5
- package/docs/CONFIGURATION.md +22 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/README.md +1 -1
- package/docs/SETUP.md +1 -1
- package/package.json +1 -1
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/init.ts +7 -1
- package/src/cli/tui/ConfigureView.tsx +2 -0
- package/src/config/dotenv-loader.ts +1 -0
- package/src/config/resolved-config.ts +19 -5
- package/src/config/yaml-loader.ts +2 -2
- package/src/config.ts +5 -1
- package/src/dashboard/server.ts +3 -0
- package/src/hooks/installers/index.ts +160 -3
- package/src/llm/provider.ts +2 -1
- 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
|
|
3877
|
-
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
3878
|
-
|
|
3879
|
-
|
|
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 =
|
|
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.
|
|
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
|
|
2414
|
-
isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
|
|
2415
|
-
|
|
2416
|
-
|
|
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
|
};
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -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.
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -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.
|
|
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:
|
package/docs/INTEGRATIONS.md
CHANGED
|
@@ -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. |
|
|
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.
|
|
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.
|
|
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,
|
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.
|
|
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.
|
|
25
|
+
"version": "1.9.9",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"packageArguments": [
|
|
28
28
|
{
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -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
|