Initial commit: Memind H5 portal with MindSpace, Plaza, and agent jobs.
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
createLlmProviderService,
|
||||
CUSTOM_PROVIDER_ID,
|
||||
decryptSecret,
|
||||
encryptSecret,
|
||||
LLM_PROVIDER_CATALOG,
|
||||
LOCAL_LLM_FALLBACK,
|
||||
maskApiKey,
|
||||
normalizeApiUrl,
|
||||
parseModelList,
|
||||
resolveChatCompletionsUrl,
|
||||
testLocalLlmConnection,
|
||||
testRelayConnection,
|
||||
syncProfileToGoosed,
|
||||
} from './llm-providers.mjs';
|
||||
|
||||
test('encryptSecret round-trips with derived key', () => {
|
||||
const encrypted = encryptSecret('sk-test-key-12345678', 'unit-test-secret');
|
||||
const plain = decryptSecret(encrypted, 'unit-test-secret');
|
||||
assert.equal(plain, 'sk-test-key-12345678');
|
||||
});
|
||||
|
||||
test('parseModelList accepts comma and newline separated values', () => {
|
||||
assert.deepEqual(parseModelList('qwen2.5:3b, llama3.2:1b\nmistral'), [
|
||||
'qwen2.5:3b',
|
||||
'llama3.2:1b',
|
||||
'mistral',
|
||||
]);
|
||||
});
|
||||
|
||||
test('normalizeApiUrl adds http scheme', () => {
|
||||
assert.equal(
|
||||
normalizeApiUrl('127.0.0.1:18300/relay/buyer/v1/chat/completions'),
|
||||
'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
);
|
||||
});
|
||||
|
||||
test('maskApiKey hides middle segment', () => {
|
||||
const masked = maskApiKey('sk-1234567890abcdef');
|
||||
assert.ok(masked.startsWith('sk-1'));
|
||||
assert.ok(masked.endsWith('cdef'));
|
||||
assert.ok(masked.includes('*'));
|
||||
});
|
||||
|
||||
test('createKey selects first profile and syncs to goosed', async () => {
|
||||
const rows = [];
|
||||
let selectedId = null;
|
||||
const syncCalls = [];
|
||||
|
||||
const pool = {
|
||||
async query(sql, params = []) {
|
||||
if (sql.includes('COUNT(*) AS total FROM h5_llm_provider_keys')) {
|
||||
return [[{ total: rows.length }]];
|
||||
}
|
||||
if (sql.includes('UPDATE h5_llm_provider_keys SET is_selected = 0')) {
|
||||
for (const row of rows) row.is_selected = 0;
|
||||
return [[]];
|
||||
}
|
||||
if (sql.includes('INSERT INTO h5_llm_provider_keys')) {
|
||||
const encrypted = {
|
||||
ciphertext: params[9],
|
||||
iv: params[10],
|
||||
tag: params[11],
|
||||
};
|
||||
const row = {
|
||||
id: params[0],
|
||||
provider_id: params[1],
|
||||
provider_kind: params[2],
|
||||
api_url: params[3],
|
||||
base_path: params[4],
|
||||
models_json: params[5],
|
||||
goosed_provider_id: null,
|
||||
engine: params[6],
|
||||
relay_provider: params[7],
|
||||
name: params[8],
|
||||
api_key_ciphertext: encrypted.ciphertext,
|
||||
api_key_iv: encrypted.iv,
|
||||
api_key_tag: encrypted.tag,
|
||||
default_model: params[12],
|
||||
status: 'active',
|
||||
is_selected: params[13],
|
||||
created_at: params[14],
|
||||
updated_at: params[15],
|
||||
};
|
||||
rows.push(row);
|
||||
if (row.is_selected) selectedId = row.id;
|
||||
return [[]];
|
||||
}
|
||||
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
|
||||
return [[rows.find((row) => row.id === params[0]) ?? null].filter(Boolean)];
|
||||
}
|
||||
if (sql.includes('ORDER BY is_selected DESC')) {
|
||||
return [rows];
|
||||
}
|
||||
if (sql.includes('SELECT id FROM h5_llm_provider_keys WHERE name = ?')) {
|
||||
return [[rows.find((row) => row.name === params[0])].filter(Boolean)];
|
||||
}
|
||||
if (sql.includes('SET goosed_provider_id = ?')) {
|
||||
const target = rows.find((row) => row.id === params[3]);
|
||||
if (target) {
|
||||
target.goosed_provider_id = params[0];
|
||||
target.provider_id = params[1];
|
||||
}
|
||||
return [[]];
|
||||
}
|
||||
throw new Error(`Unexpected SQL: ${sql}`);
|
||||
},
|
||||
};
|
||||
|
||||
const mockFetch = async (url, init) => {
|
||||
syncCalls.push({ url: String(url), body: init?.body ? JSON.parse(init.body) : null });
|
||||
if (String(url).includes('/config/custom-providers') && init?.method === 'POST') {
|
||||
return { ok: true, json: async () => ({ provider_name: 'relay_ollama' }) };
|
||||
}
|
||||
return { ok: true, text: async () => '' };
|
||||
};
|
||||
|
||||
const service = createLlmProviderService(pool, {
|
||||
apiTarget: 'https://127.0.0.1:18006',
|
||||
apiSecret: 'secret',
|
||||
encryptionKey: 'unit-test-secret',
|
||||
apiFetchImpl: mockFetch,
|
||||
});
|
||||
const result = await service.createKey({
|
||||
providerId: 'custom_deepseek',
|
||||
name: 'DeepSeek 主账号',
|
||||
apiKey: 'sk-deepseek-test',
|
||||
defaultModel: 'deepseek-chat',
|
||||
});
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.key.isSelected, true);
|
||||
assert.equal(rows.length, 1);
|
||||
assert.equal(selectedId, rows[0].id);
|
||||
assert.equal(syncCalls.filter((item) => item.body?.key === 'DEEPSEEK_API_KEY').length, 1);
|
||||
});
|
||||
|
||||
test('create custom relay profile registers goosed custom provider', async () => {
|
||||
const rows = [];
|
||||
const mockFetch = async (url, init) => {
|
||||
if (String(url).includes('/config/custom-providers') && init?.method === 'POST') {
|
||||
const body = JSON.parse(init.body);
|
||||
assert.equal(body.api_url, 'http://127.0.0.1:18300/relay/buyer/v1/chat/completions');
|
||||
assert.deepEqual(body.models, ['qwen2.5:3b', 'llama3.2:1b']);
|
||||
assert.equal(body.headers['X-Provider'], 'ollama');
|
||||
return { ok: true, json: async () => ({ provider_name: 'relay_buyer' }) };
|
||||
}
|
||||
return { ok: true, text: async () => '' };
|
||||
};
|
||||
|
||||
const pool = {
|
||||
async query(sql, params = []) {
|
||||
if (sql.includes('COUNT(*) AS total FROM h5_llm_provider_keys')) return [[{ total: 0 }]];
|
||||
if (sql.includes('UPDATE h5_llm_provider_keys SET is_selected = 0')) return [[]];
|
||||
if (sql.includes('INSERT INTO h5_llm_provider_keys')) {
|
||||
rows.push({
|
||||
id: params[0],
|
||||
provider_id: params[1],
|
||||
provider_kind: params[2],
|
||||
api_url: params[3],
|
||||
base_path: params[4],
|
||||
models_json: params[5],
|
||||
goosed_provider_id: null,
|
||||
engine: params[6],
|
||||
relay_provider: params[7],
|
||||
name: params[8],
|
||||
api_key_ciphertext: params[9],
|
||||
api_key_iv: params[10],
|
||||
api_key_tag: params[11],
|
||||
default_model: params[12],
|
||||
status: 'active',
|
||||
is_selected: params[13],
|
||||
created_at: params[14],
|
||||
updated_at: params[15],
|
||||
});
|
||||
return [[]];
|
||||
}
|
||||
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
|
||||
return [[rows.find((row) => row.id === params[0]) ?? null].filter(Boolean)];
|
||||
}
|
||||
if (sql.includes('SELECT id FROM h5_llm_provider_keys WHERE name = ?')) return [[]];
|
||||
if (sql.includes('SET goosed_provider_id = ?')) {
|
||||
rows[0].goosed_provider_id = params[0];
|
||||
rows[0].provider_id = params[1];
|
||||
return [[]];
|
||||
}
|
||||
throw new Error(`Unexpected SQL: ${sql}`);
|
||||
},
|
||||
};
|
||||
|
||||
const service = createLlmProviderService(pool, {
|
||||
apiTarget: 'https://127.0.0.1:18006',
|
||||
apiSecret: 'secret',
|
||||
encryptionKey: 'unit-test-secret',
|
||||
apiFetchImpl: mockFetch,
|
||||
});
|
||||
const result = await service.createKey({
|
||||
providerId: CUSTOM_PROVIDER_ID,
|
||||
name: 'Relay Ollama',
|
||||
apiKey: 'UqyHPKSSEZq0-oPnl8sru-7hZcJ2anPUL1yAVk866Vo',
|
||||
apiUrl: 'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
models: ['qwen2.5:3b', 'llama3.2:1b'],
|
||||
defaultModel: 'qwen2.5:3b',
|
||||
relayProvider: 'ollama',
|
||||
});
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.key.providerKind, 'custom');
|
||||
assert.equal(rows[0].provider_kind, 'custom');
|
||||
});
|
||||
|
||||
test('selectKey rejects disabled profile', async () => {
|
||||
const row = {
|
||||
id: 'key-1',
|
||||
provider_id: 'custom_deepseek',
|
||||
provider_kind: 'builtin',
|
||||
name: 'disabled',
|
||||
api_key_ciphertext: encryptSecret('sk-x', 'unit-test-secret').ciphertext,
|
||||
api_key_iv: encryptSecret('sk-x', 'unit-test-secret').iv,
|
||||
api_key_tag: encryptSecret('sk-x', 'unit-test-secret').tag,
|
||||
default_model: 'deepseek-chat',
|
||||
status: 'disabled',
|
||||
is_selected: 0,
|
||||
created_at: 1,
|
||||
updated_at: 1,
|
||||
};
|
||||
const pool = {
|
||||
async query(sql, params = []) {
|
||||
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
|
||||
return [[row]];
|
||||
}
|
||||
throw new Error(`Unexpected SQL: ${sql}`);
|
||||
},
|
||||
};
|
||||
const service = createLlmProviderService(pool, {
|
||||
apiTarget: 'https://127.0.0.1:18006',
|
||||
apiSecret: 'secret',
|
||||
encryptionKey: 'unit-test-secret',
|
||||
});
|
||||
const result = await service.selectKey('key-1');
|
||||
assert.equal(result.ok, false);
|
||||
assert.match(result.message, /禁用/);
|
||||
});
|
||||
|
||||
test('catalog includes custom provider template', () => {
|
||||
const custom = LLM_PROVIDER_CATALOG.find((item) => item.id === CUSTOM_PROVIDER_ID);
|
||||
assert.ok(custom);
|
||||
assert.equal(custom.kind, 'custom');
|
||||
});
|
||||
|
||||
test('resolveChatCompletionsUrl keeps full completions path', () => {
|
||||
assert.equal(
|
||||
resolveChatCompletionsUrl('http://127.0.0.1:18300/relay/buyer/v1/chat/completions'),
|
||||
'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
);
|
||||
});
|
||||
|
||||
test('testRelayConnection surfaces 401 as token error', async () => {
|
||||
const mockFetch = async () => ({
|
||||
ok: false,
|
||||
status: 401,
|
||||
text: async () => '{}',
|
||||
});
|
||||
const result = await testRelayConnection(
|
||||
{
|
||||
apiUrl: 'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
apiKey: 'bad-token',
|
||||
model: 'qwen2.5:3b',
|
||||
relayProvider: 'ollama',
|
||||
},
|
||||
mockFetch,
|
||||
);
|
||||
assert.equal(result.ok, false);
|
||||
assert.match(result.message ?? '', /401/);
|
||||
assert.match(result.message ?? '', /Token/);
|
||||
});
|
||||
|
||||
test('testRelayConnection parses OpenAI-style response', async () => {
|
||||
const mockFetch = async () => ({
|
||||
ok: true,
|
||||
text: async () =>
|
||||
JSON.stringify({
|
||||
choices: [{ message: { content: 'Hi there' } }],
|
||||
}),
|
||||
});
|
||||
const result = await testRelayConnection(
|
||||
{
|
||||
apiUrl: 'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
apiKey: 'token',
|
||||
model: 'qwen2.5:3b',
|
||||
relayProvider: 'ollama',
|
||||
},
|
||||
mockFetch,
|
||||
);
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.reply, 'Hi there');
|
||||
});
|
||||
|
||||
test('syncProfileToGoosed writes provider, model and secret keys for builtin', async () => {
|
||||
const writes = [];
|
||||
const mockFetch = async (_url, init) => {
|
||||
writes.push(JSON.parse(init.body));
|
||||
return { ok: true, text: async () => '' };
|
||||
};
|
||||
await syncProfileToGoosed(
|
||||
'https://127.0.0.1:18006',
|
||||
'secret',
|
||||
{
|
||||
providerKind: 'builtin',
|
||||
providerId: 'custom_deepseek',
|
||||
defaultModel: 'deepseek-chat',
|
||||
apiKey: 'sk-test',
|
||||
},
|
||||
mockFetch,
|
||||
);
|
||||
assert.deepEqual(
|
||||
writes.map((item) => item.key),
|
||||
['DEEPSEEK_API_KEY', 'GOOSE_PROVIDER', 'GOOSE_MODEL', 'TKMIND_PROVIDER', 'TKMIND_MODEL'],
|
||||
);
|
||||
});
|
||||
|
||||
test('syncProfileToGoosed tolerates missing /config/upsert endpoint', async () => {
|
||||
const mockFetch = async (_url, init) => {
|
||||
if (String(_url).includes('/config/custom-providers')) {
|
||||
return {
|
||||
ok: true,
|
||||
json: async () => ({ provider_name: 'custom_local_ollama_7b' }),
|
||||
};
|
||||
}
|
||||
if (String(_url).includes('/config/upsert')) {
|
||||
return { ok: false, status: 404, text: async () => '' };
|
||||
}
|
||||
return { ok: true, text: async () => '' };
|
||||
};
|
||||
const providerId = await syncProfileToGoosed(
|
||||
'https://127.0.0.1:18006',
|
||||
'secret',
|
||||
{
|
||||
providerKind: 'custom',
|
||||
providerId: CUSTOM_PROVIDER_ID,
|
||||
name: 'Local Ollama 7B',
|
||||
apiUrl: LOCAL_LLM_FALLBACK.apiUrl,
|
||||
apiKey: LOCAL_LLM_FALLBACK.apiKey,
|
||||
models: [LOCAL_LLM_FALLBACK.model],
|
||||
defaultModel: LOCAL_LLM_FALLBACK.model,
|
||||
engine: 'openai',
|
||||
},
|
||||
mockFetch,
|
||||
);
|
||||
assert.equal(providerId, 'custom_local_ollama_7b');
|
||||
});
|
||||
|
||||
test('LOCAL_LLM_FALLBACK defaults to local ollama 7b', () => {
|
||||
assert.equal(LOCAL_LLM_FALLBACK.model, 'qwen2.5-coder:7b');
|
||||
assert.match(LOCAL_LLM_FALLBACK.apiUrl, /11434/);
|
||||
assert.equal(LOCAL_LLM_FALLBACK.enabled, true);
|
||||
});
|
||||
|
||||
test('syncSelectedToGoosed does not auto-fallback to local when selected relay is down', async () => {
|
||||
const encrypted = encryptSecret('token', 'unit-test-secret');
|
||||
const row = {
|
||||
id: 'key-relay',
|
||||
provider_id: '__custom__',
|
||||
provider_kind: 'custom',
|
||||
name: 'Relay Buyer Ollama',
|
||||
api_url: 'http://127.0.0.1:18300/relay/buyer/v1/chat/completions',
|
||||
base_path: null,
|
||||
models_json: JSON.stringify(['qwen2.5:3b']),
|
||||
goosed_provider_id: null,
|
||||
engine: 'openai',
|
||||
relay_provider: 'ollama',
|
||||
api_key_ciphertext: encrypted.ciphertext,
|
||||
api_key_iv: encrypted.iv,
|
||||
api_key_tag: encrypted.tag,
|
||||
default_model: 'qwen2.5:3b',
|
||||
status: 'active',
|
||||
is_selected: 1,
|
||||
created_at: 1,
|
||||
updated_at: 1,
|
||||
};
|
||||
const pool = {
|
||||
async query(sql) {
|
||||
if (sql.includes('is_selected = 1')) return [[row]];
|
||||
throw new Error(`Unexpected SQL: ${sql}`);
|
||||
},
|
||||
};
|
||||
const mockFetch = async () => {
|
||||
throw Object.assign(new Error('connect ECONNREFUSED'), { code: 'ECONNREFUSED' });
|
||||
};
|
||||
const service = createLlmProviderService(pool, {
|
||||
apiTarget: 'https://127.0.0.1:18006',
|
||||
apiSecret: 'secret',
|
||||
encryptionKey: 'unit-test-secret',
|
||||
apiFetchImpl: mockFetch,
|
||||
});
|
||||
const result = await service.syncSelectedToGoosed();
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(result.synced, false);
|
||||
assert.ok(result.message);
|
||||
});
|
||||
Reference in New Issue
Block a user