Add provider gateway and collaboration records
This commit is contained in:
1 parent
fcf6d90731
commit
c694b7fc2c
12 files changed
+556
-9
No files matched your search
@@ -1,8 +1,11 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import type { SaveProviderCredentialInput } from "../../shared/commands";
|
||||
import { createHash } from "node:crypto";
|
||||
import type { CreateProviderResponseInput, SaveProviderCredentialInput } from "../../shared/commands";
|
||||
import { PROVIDER_AUTH_TYPE, PROVIDER_REQUEST_STATE } from "../../shared/domain";
|
||||
import { createId } from "../../shared/ids";
|
||||
import { AuditService } from "./audit-service";
|
||||
import { SecretVault } from "./secret-vault";
|
||||
import { providerAdapters } from "./provider-adapters";
|
||||
|
||||
function displayHint(secret: string): string {
|
||||
const clean = secret.trim();
|
||||
@@ -50,4 +53,94 @@ export class ProviderService {
|
||||
payload: { providerKey: provider.provider_key, authType: provider.auth_type },
|
||||
});
|
||||
}
|
||||
|
||||
async createResponse(input: CreateProviderResponseInput): Promise<void> {
|
||||
const prompt = input.prompt.trim();
|
||||
if (!prompt) throw new Error("Prompt is required.");
|
||||
const provider = this.db.prepare(`
|
||||
select id, provider_key, auth_type, model, credential_id, enabled
|
||||
from providers
|
||||
where id = ? and org_id = ?
|
||||
`).get(input.providerId, input.orgId) as ProviderRow | undefined;
|
||||
if (!provider) throw new Error("Provider was not found.");
|
||||
if (provider.enabled !== 1) throw new Error("Provider credential is required.");
|
||||
if (provider.auth_type !== PROVIDER_AUTH_TYPE.API_KEY) {
|
||||
throw new Error("Provider response execution requires an API key adapter.");
|
||||
}
|
||||
if (!provider.credential_id) throw new Error("Provider credential is required.");
|
||||
if (!provider.model) throw new Error("Provider model is required.");
|
||||
const adapter = providerAdapters[provider.provider_key];
|
||||
if (!adapter) throw new Error(`Provider adapter is unavailable for ${provider.provider_key}.`);
|
||||
|
||||
const credential = this.db.prepare(`
|
||||
select ciphertext
|
||||
from credentials
|
||||
where id = ? and org_id = ? and provider_key = ?
|
||||
`).get(provider.credential_id, input.orgId, provider.provider_key) as { ciphertext: Uint8Array } | undefined;
|
||||
if (!credential) throw new Error("Provider credential was not found.");
|
||||
|
||||
const requestId = createId("preq");
|
||||
const now = new Date().toISOString();
|
||||
this.db.prepare(`
|
||||
insert into provider_requests(
|
||||
id, org_id, provider_id, provider_key, model, prompt_sha256,
|
||||
response_text, raw_response_json, state, error_message, created_at, completed_at
|
||||
)
|
||||
values (?, ?, ?, ?, ?, ?, null, null, ?, null, ?, null)
|
||||
`).run(
|
||||
requestId,
|
||||
input.orgId,
|
||||
provider.id,
|
||||
provider.provider_key,
|
||||
provider.model,
|
||||
hashPrompt(prompt),
|
||||
PROVIDER_REQUEST_STATE.PENDING,
|
||||
now,
|
||||
);
|
||||
|
||||
try {
|
||||
const apiKey = this.vault.decryptSecret(Buffer.from(credential.ciphertext));
|
||||
const result = await adapter.createResponse({
|
||||
apiKey,
|
||||
model: provider.model,
|
||||
prompt,
|
||||
instructions: input.instructions?.trim() || null,
|
||||
});
|
||||
this.db.prepare(`
|
||||
update provider_requests
|
||||
set state = ?, response_text = ?, raw_response_json = ?, completed_at = ?
|
||||
where id = ? and org_id = ?
|
||||
`).run(PROVIDER_REQUEST_STATE.SUCCEEDED, result.text, result.rawResponseJson, new Date().toISOString(), requestId, input.orgId);
|
||||
this.audit.record({
|
||||
orgId: input.orgId,
|
||||
entityType: "provider_request",
|
||||
entityId: requestId,
|
||||
actorType: "system",
|
||||
actorId: null,
|
||||
action: "response_created",
|
||||
payload: { providerKey: provider.provider_key, model: provider.model },
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.db.prepare(`
|
||||
update provider_requests
|
||||
set state = ?, error_message = ?, completed_at = ?
|
||||
where id = ? and org_id = ?
|
||||
`).run(PROVIDER_REQUEST_STATE.FAILED, message, new Date().toISOString(), requestId, input.orgId);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ProviderRow {
|
||||
id: string;
|
||||
provider_key: string;
|
||||
auth_type: string;
|
||||
model: string | null;
|
||||
credential_id: string | null;
|
||||
enabled: number;
|
||||
}
|
||||
|
||||
function hashPrompt(prompt: string): string {
|
||||
return createHash("sha256").update(prompt).digest("hex");
|
||||
}
|
||||
Reference in new issue
Block a user