ai-chatbot/lib/ai/runtime/agent-model-slots.ts
Your Name 9ecd91376d
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: strengthen agent runtime boundaries
2026-03-16 11:45:00 +08:00

109 lines
3.0 KiB
TypeScript

import "server-only";
import {
getAiModelById,
getAiProviderById,
getEnabledAiModelsWithProvider,
} from "@/lib/db/queries";
export type AgentModelSlotName = "planner" | "analyzer" | "reply" | "execution";
export interface AgentModelSlotDescriptor {
modelId: string;
displayName?: string;
providerId?: string;
providerType?: string;
providerKey?: string;
}
export interface AgentModelSlot extends AgentModelSlotDescriptor {
slot: AgentModelSlotName;
source: string;
reason?: string;
locked?: boolean;
}
export interface AgentModelSlots {
planner?: AgentModelSlot;
analyzer?: AgentModelSlot;
reply?: AgentModelSlot;
execution?: AgentModelSlot;
}
function buildProviderKey(params: {
providerId?: string;
providerType?: string;
modelId: string;
}) {
if (params.providerId) return params.providerId;
if (params.providerType) return `${params.providerType}:${params.modelId}`;
return `model:${params.modelId}`;
}
export async function resolveAgentModelSlotDescriptor(modelId: string) {
const normalizedModelId = String(modelId || "").trim();
if (!normalizedModelId) return null;
const isUuid =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(normalizedModelId);
if (isUuid) {
const model = await getAiModelById({ id: normalizedModelId }).catch(() => null);
if (!model) {
return {
modelId: normalizedModelId,
providerKey: `model:${normalizedModelId}`,
} satisfies AgentModelSlotDescriptor;
}
const provider = await getAiProviderById({ id: model.providerId }).catch(() => null);
return {
modelId: model.id,
displayName: model.displayName || model.modelId,
providerId: model.providerId,
providerType: provider?.type || undefined,
providerKey: buildProviderKey({
providerId: model.providerId,
providerType: provider?.type || undefined,
modelId: model.id,
}),
} satisfies AgentModelSlotDescriptor;
}
const enabledModels = await getEnabledAiModelsWithProvider(false).catch(() => []);
const matched = enabledModels.find(
({ model }) => model.id === normalizedModelId || model.modelId === normalizedModelId,
);
if (!matched) {
return {
modelId: normalizedModelId,
providerKey: `model:${normalizedModelId}`,
} satisfies AgentModelSlotDescriptor;
}
return {
modelId: matched.model.id,
displayName: matched.model.displayName || matched.model.modelId,
providerId: matched.model.providerId,
providerType: matched.provider?.type || undefined,
providerKey: buildProviderKey({
providerId: matched.model.providerId,
providerType: matched.provider?.type || undefined,
modelId: matched.model.id,
}),
} satisfies AgentModelSlotDescriptor;
}
export function upsertAgentModelSlot(
slots: AgentModelSlots,
slot: AgentModelSlotName,
value: Omit<AgentModelSlot, "slot">,
) {
return {
...slots,
[slot]: {
slot,
...value,
},
} satisfies AgentModelSlots;
}