UNPKG

@unified-llm/core

Version:

Unified LLM interface (in-memory).

248 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.clientRepository = exports.ClientRepository = void 0; const drizzle_orm_1 = require("drizzle-orm"); const connection_1 = require("./connection"); const schema_1 = require("./schema"); const crypto_1 = require("crypto"); class ClientRepository { async getDb() { return await (0, connection_1.getDatabase)(); } async isDisabled() { return (await this.getDb()) === null; } /* ──────────────────────────────── CRUD ──────────────────────────────── */ /** Save or update LLM client configuration. */ async save(config) { var _a, _b, _c, _d, _e, _f, _g; if (await this.isDisabled()) { // 永続化オフ時はメモリ上で完結 const now = new Date(); return { id: config.id || `asst_${(0, crypto_1.randomUUID)()}`, createdAt: now, updatedAt: now, isActive: (_a = config.isActive) !== null && _a !== void 0 ? _a : true, name: config.name, provider: config.provider, description: (_b = config.description) !== null && _b !== void 0 ? _b : null, model: (_c = config.model) !== null && _c !== void 0 ? _c : null, systemPrompt: (_d = config.systemPrompt) !== null && _d !== void 0 ? _d : null, instructions: (_e = config.instructions) !== null && _e !== void 0 ? _e : null, apiKey: (_f = config.apiKey) !== null && _f !== void 0 ? _f : null, generationConfig: config.generationConfig ? JSON.stringify(config.generationConfig) : null, tools: config.tools ? JSON.stringify(config.tools) : null, argumentMap: config.argumentMap ? JSON.stringify(config.argumentMap) : null, tags: config.tags ? JSON.stringify(config.tags) : null, metadata: config.metadata ? JSON.stringify(config.metadata) : null, }; } const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); const now = new Date(); const id = config.id || `asst_${(0, crypto_1.randomUUID)()}`; const newClient = { id, name: config.name, description: config.description, provider: config.provider, model: config.model, systemPrompt: config.systemPrompt, instructions: config.instructions, apiKey: config.apiKey, generationConfig: config.generationConfig ? JSON.stringify(config.generationConfig) : null, tools: config.tools ? JSON.stringify(config.tools) : null, argumentMap: config.argumentMap ? JSON.stringify(config.argumentMap) : null, tags: config.tags ? JSON.stringify(config.tags) : null, isActive: (_g = config.isActive) !== null && _g !== void 0 ? _g : true, createdAt: now, updatedAt: now, metadata: config.metadata ? JSON.stringify(config.metadata) : null, }; const existing = await this.findById(id); if (existing) { await db .update(schema_1.llmClients) .set({ ...newClient, createdAt: existing.createdAt }) .where((0, drizzle_orm_1.eq)(schema_1.llmClients.id, id)) .run(); } else { await db.insert(schema_1.llmClients).values(newClient).run(); } return (await this.findById(id)); } /** Retrieve by ID */ async findById(id) { var _a; if (await this.isDisabled()) return null; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); const result = await db .select() .from(schema_1.llmClients) .where((0, drizzle_orm_1.eq)(schema_1.llmClients.id, id)) .limit(1); return (_a = result[0]) !== null && _a !== void 0 ? _a : null; } /** 名前検索 */ async findByName(name) { if (await this.isDisabled()) return []; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); return await db .select() .from(schema_1.llmClients) .where((0, drizzle_orm_1.like)(schema_1.llmClients.name, `%${name}%`)) .orderBy((0, drizzle_orm_1.desc)(schema_1.llmClients.updatedAt)); } /** プロバイダー検索 */ async findByProvider(provider) { if (await this.isDisabled()) return []; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); return await db .select() .from(schema_1.llmClients) .where((0, drizzle_orm_1.eq)(schema_1.llmClients.provider, provider)) .orderBy((0, drizzle_orm_1.desc)(schema_1.llmClients.updatedAt)); } /** タグ検索 */ async findByTags(tags) { if (await this.isDisabled()) return []; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); const all = await db.select().from(schema_1.llmClients); return all .filter((c) => { if (!c.tags) return false; const arr = JSON.parse(c.tags); return tags.some((t) => arr.includes(t)); }) .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()); } /** 一覧取得(非アクティブ含むか) */ async findAll(includeInactive = false) { if (await this.isDisabled()) return []; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); const q = db.select().from(schema_1.llmClients); if (!includeInactive) q.where((0, drizzle_orm_1.eq)(schema_1.llmClients.isActive, true)); return await q.orderBy((0, drizzle_orm_1.desc)(schema_1.llmClients.updatedAt)); } /** 論理削除 */ async delete(id) { var _a; if (await this.isDisabled()) return false; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); const res = await db .update(schema_1.llmClients) .set({ isActive: false, updatedAt: new Date() }) .where((0, drizzle_orm_1.eq)(schema_1.llmClients.id, id)) .run(); const affected = typeof res.rowsAffected === 'bigint' ? Number(res.rowsAffected) : (_a = res.rowsAffected) !== null && _a !== void 0 ? _a : 0; return affected > 0; } /** 物理削除 */ async hardDelete(id) { var _a; if (await this.isDisabled()) return false; const db = await this.getDb(); if (!db) throw new Error('Database connection is not available'); // 参照削除 → messages の client_id を null → 本体削除 await db.delete(schema_1.threadParticipants).where((0, drizzle_orm_1.eq)(schema_1.threadParticipants.clientId, id)).run(); await db .update(schema_1.messages) .set({ clientId: null }) .where((0, drizzle_orm_1.eq)(schema_1.messages.clientId, id)) .run(); const res = await db.delete(schema_1.llmClients).where((0, drizzle_orm_1.eq)(schema_1.llmClients.id, id)).run(); const affected = typeof res.rowsAffected === 'bigint' ? Number(res.rowsAffected) : (_a = res.rowsAffected) !== null && _a !== void 0 ? _a : 0; return affected > 0; } /* ──────────────────────────────── Utility ──────────────────────────────── */ static toConfig(stored) { var _a, _b, _c, _d, _e, _f; return { id: stored.id, name: stored.name, description: (_a = stored.description) !== null && _a !== void 0 ? _a : undefined, provider: stored.provider, model: (_b = stored.model) !== null && _b !== void 0 ? _b : undefined, systemPrompt: (_c = stored.systemPrompt) !== null && _c !== void 0 ? _c : undefined, instructions: (_d = stored.instructions) !== null && _d !== void 0 ? _d : undefined, apiKey: (_e = stored.apiKey) !== null && _e !== void 0 ? _e : undefined, generationConfig: stored.generationConfig ? JSON.parse(stored.generationConfig) : undefined, tools: stored.tools ? JSON.parse(stored.tools) : undefined, argumentMap: stored.argumentMap ? JSON.parse(stored.argumentMap) : undefined, tags: stored.tags ? JSON.parse(stored.tags) : undefined, isActive: (_f = stored.isActive) !== null && _f !== void 0 ? _f : undefined, metadata: stored.metadata ? JSON.parse(stored.metadata) : undefined, }; } static validateConfig(config) { var _a; const errors = []; if (!((_a = config.name) === null || _a === void 0 ? void 0 : _a.trim())) errors.push('Name is required'); if (!config.provider) { errors.push('Provider is required'); } else if (!['openai', 'anthropic', 'google', 'deepseek'].includes(config.provider)) { errors.push('Provider must be one of: openai, anthropic, google, deepseek'); } const gen = config.generationConfig; if (gen) { if (gen.temperature !== undefined && (gen.temperature < 0 || gen.temperature > 2)) errors.push('Temperature must be between 0 and 2'); if (gen.max_tokens !== undefined && gen.max_tokens <= 0) errors.push('Max tokens must be greater than 0'); if (gen.top_p !== undefined && (gen.top_p < 0 || gen.top_p > 1)) errors.push('Top P must be between 0 and 1'); } return { valid: errors.length === 0, errors }; } } exports.ClientRepository = ClientRepository; /* シングルトン */ exports.clientRepository = new ClientRepository(); //# sourceMappingURL=client-repository.js.map