feat: Add OpenAI-compatible provider nodes

- Support multiple OpenAI-compatible providers with custom prefix/baseUrl
- Add provider nodes CRUD (create/read/update/delete)
- URL building: baseUrl + /chat/completions or /responses
- Model import from /models endpoint
- API key validation via /models
- Usage type safety across all translators
- OAuth token auto-refresh for expired tokens
This commit is contained in:
decolua
2026-02-02 19:45:12 +07:00
parent 1b14c9d66b
commit 0a28f9f924
25 changed files with 1276 additions and 151 deletions
+98 -1
View File
@@ -42,6 +42,7 @@ if (!isCloud && !fs.existsSync(DATA_DIR)) {
// Default data structure
const defaultData = {
providerConnections: [],
providerNodes: [],
modelAliases: {},
combos: [],
apiKeys: [],
@@ -116,6 +117,103 @@ export async function getProviderConnections(filter = {}) {
return connections;
}
// ============ Provider Nodes ============
/**
* Get provider nodes
*/
export async function getProviderNodes(filter = {}) {
const db = await getDb();
let nodes = db.data.providerNodes || [];
if (filter.type) {
nodes = nodes.filter((node) => node.type === filter.type);
}
return nodes;
}
/**
* Get provider node by ID
*/
export async function getProviderNodeById(id) {
const db = await getDb();
return db.data.providerNodes.find((node) => node.id === id) || null;
}
/**
* Create provider node
*/
export async function createProviderNode(data) {
const db = await getDb();
const now = new Date().toISOString();
const node = {
id: data.id || uuidv4(),
type: data.type,
name: data.name,
prefix: data.prefix,
apiType: data.apiType,
baseUrl: data.baseUrl,
createdAt: now,
updatedAt: now,
};
db.data.providerNodes.push(node);
await db.write();
return node;
}
/**
* Update provider node
*/
export async function updateProviderNode(id, data) {
const db = await getDb();
const index = db.data.providerNodes.findIndex((node) => node.id === id);
if (index === -1) return null;
db.data.providerNodes[index] = {
...db.data.providerNodes[index],
...data,
updatedAt: new Date().toISOString(),
};
await db.write();
return db.data.providerNodes[index];
}
/**
* Delete provider node
*/
export async function deleteProviderNode(id) {
const db = await getDb();
const index = db.data.providerNodes.findIndex((node) => node.id === id);
if (index === -1) return null;
const [removed] = db.data.providerNodes.splice(index, 1);
await db.write();
return removed;
}
/**
* Delete all provider connections by provider ID
*/
export async function deleteProviderConnectionsByProvider(providerId) {
const db = await getDb();
const beforeCount = db.data.providerConnections.length;
db.data.providerConnections = db.data.providerConnections.filter(
(connection) => connection.provider !== providerId
);
const deletedCount = beforeCount - db.data.providerConnections.length;
await db.write();
return deletedCount;
}
/**
* Get provider connection by ID
*/
@@ -699,4 +797,3 @@ export async function resetAllPricing() {
await db.write();
return db.data.pricing;
}