swadhinbiswas Allow configuring local AI endpoint and key · 2/19/2026
37142e2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import type { APIRoute } from "astro";
import { getDatabase, schema } from "@/db";
import { eq } from "drizzle-orm";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import {
buildStoredAIConfig,
mergeAIConfig,
parseAIConfigFromStorage,
sanitizeAIConfigForClient,
} from "@/lib/ai-config";
export const POST: APIRoute = async ({ request, locals }) => {
const user = locals.user;
if (!user) {
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
}
try {
const data = await request.json();
const { provider, apiKeys, model } = data;
// Basic validation
if (!["openai", "groq", "bytez", "openrouter", "together", "google", "external_agent", "local", "anthropic"].includes(provider)) {
return new Response(JSON.stringify({ error: "Invalid provider" }), { status: 400 });
}
const db = getDatabase() as NodePgDatabase<typeof schema>;
const currentUser = await db.query.users.findFirst({
where: eq(schema.users.id, user.id),
columns: { aiConfig: true },
});
const existing = parseAIConfigFromStorage(currentUser?.aiConfig);
const merged = mergeAIConfig(existing, {
provider,
model: model || existing.model,
apiKeys: {
openai: typeof apiKeys?.openai === "string" && apiKeys.openai.trim() !== "" ? apiKeys.openai.trim() : undefined,
anthropic: typeof apiKeys?.anthropic === "string" && apiKeys.anthropic.trim() !== "" ? apiKeys.anthropic.trim() : undefined,
groq: typeof apiKeys?.groq === "string" && apiKeys.groq.trim() !== "" ? apiKeys.groq.trim() : undefined,
bytez: typeof apiKeys?.bytez === "string" && apiKeys.bytez.trim() !== "" ? apiKeys.bytez.trim() : undefined,
openrouter: typeof apiKeys?.openrouter === "string" && apiKeys.openrouter.trim() !== "" ? apiKeys.openrouter.trim() : undefined,
together: typeof apiKeys?.together === "string" && apiKeys.together.trim() !== "" ? apiKeys.together.trim() : undefined,
google: typeof apiKeys?.google === "string" && apiKeys.google.trim() !== "" ? apiKeys.google.trim() : undefined,
local: typeof apiKeys?.local === "string" && apiKeys.local.trim() !== "" ? apiKeys.local.trim() : undefined,
externalAgent: typeof apiKeys?.externalAgent === "string" && apiKeys.externalAgent.trim() !== "" ? apiKeys.externalAgent.trim() : undefined,
},
localBaseUrl:
typeof data?.localBaseUrl === "string" && data.localBaseUrl.trim() !== ""
? data.localBaseUrl.trim()
: undefined,
externalAgentWebhookUrl:
typeof data?.externalAgentWebhookUrl === "string" && data.externalAgentWebhookUrl.trim() !== ""
? data.externalAgentWebhookUrl.trim()
: undefined,
});
await db.update(schema.users)
.set({
aiConfig: buildStoredAIConfig(merged),
updatedAt: new Date()
})
.where(eq(schema.users.id, user.id));
return new Response(JSON.stringify({ success: true }), { status: 200 });
} catch (e: any) {
return new Response(JSON.stringify({ error: e.message }), { status: 500 });
}
};
export const GET: APIRoute = async ({ locals }) => {
const user = locals.user;
if (!user) {
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
}
let config = null;
try {
if (user.aiConfig) {
config = sanitizeAIConfigForClient(parseAIConfigFromStorage(user.aiConfig));
}
} catch (e) { }
return new Response(JSON.stringify({ config }), { status: 200 });
}