From 0b8a7b3809777dba157c3e68498a9701b874e68a Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Thu, 25 Jun 2026 15:34:04 +0200 Subject: [PATCH] feat: add Opus/Sonnet model selector to "Genera preventivo" page Adds a "Modello AI" toggle (Opus default, Sonnet option) styled like the existing Soggetto toggle. The server action validates the keyword and maps it to the real model id; the agent receives the resolved id and uses it in the Anthropic messages.create call. The proposals DB record stores the actual model used. Co-Authored-By: Claude Opus 4.8 --- src/app/admin/preventivi/actions.ts | 17 ++++++++-- .../preventivi/genera/GeneraProposalForm.tsx | 34 ++++++++++++++++++- src/lib/proposal/agent.ts | 3 +- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/app/admin/preventivi/actions.ts b/src/app/admin/preventivi/actions.ts index 952931b..11a30f7 100644 --- a/src/app/admin/preventivi/actions.ts +++ b/src/app/admin/preventivi/actions.ts @@ -62,7 +62,17 @@ export async function generateProposalDraft(formData: FormData) { .orderBy(desc(clientTranscripts.call_date)); } - const MODEL = "claude-opus-4-8"; + const MODEL_IDS = { + opus: "claude-opus-4-8", + sonnet: "claude-sonnet-4-6", + } as const; + + const modelKey = (() => { + const raw = formData.get("model"); + if (raw === "opus" || raw === "sonnet") return raw; + return "opus" as const; + })(); + const resolvedModel = MODEL_IDS[modelKey]; // Chiama agente AI const { content: aiContent } = await generateProposalContent({ @@ -70,6 +80,7 @@ export async function generateProposalDraft(formData: FormData) { client, transcripts, offer, + model: resolvedModel, }); // Assembla contenuto completo @@ -78,7 +89,7 @@ export async function generateProposalDraft(formData: FormData) { client, offer, aiContent, - model: MODEL, + model: resolvedModel, }); // Salva nel DB @@ -94,7 +105,7 @@ export async function generateProposalDraft(formData: FormData) { offer_macro_id: offerMacroId, title, content: assembled as unknown as Record, - model: MODEL, + model: resolvedModel, state: "draft", }); diff --git a/src/app/admin/preventivi/genera/GeneraProposalForm.tsx b/src/app/admin/preventivi/genera/GeneraProposalForm.tsx index a2497e5..ddaa754 100644 --- a/src/app/admin/preventivi/genera/GeneraProposalForm.tsx +++ b/src/app/admin/preventivi/genera/GeneraProposalForm.tsx @@ -16,6 +16,7 @@ export function GeneraProposalForm({ leads, clients, offers, action, preselected const [subjectType, setSubjectType] = useState<"lead" | "client">( preselectedLeadId ? "lead" : "lead" ); + const [model, setModel] = useState<"opus" | "sonnet">("opus"); const [isPending, startTransition] = useTransition(); const [error, setError] = useState(null); @@ -25,6 +26,8 @@ export function GeneraProposalForm({ leads, clients, offers, action, preselected const form = e.currentTarget; const formData = new FormData(form); + formData.append("model", model); + startTransition(async () => { try { await action(formData); @@ -65,6 +68,35 @@ export function GeneraProposalForm({ leads, clients, offers, action, preselected + {/* Modello AI */} +
+ +
+ + +
+
+ {/* Select lead o cliente */} {subjectType === "lead" ? (
@@ -135,7 +167,7 @@ export function GeneraProposalForm({ leads, clients, offers, action, preselected {/* Info generazione */}
- L'AI (Claude Opus) legge i transcript del soggetto selezionato e genera una bozza + L'AI (Claude {model === "opus" ? "Opus" : "Sonnet"}) legge i transcript del soggetto selezionato e genera una bozza personalizzata. La generazione richiede 30–60 secondi.
diff --git a/src/lib/proposal/agent.ts b/src/lib/proposal/agent.ts index 8b336d1..e72c06b 100644 --- a/src/lib/proposal/agent.ts +++ b/src/lib/proposal/agent.ts @@ -11,6 +11,7 @@ type AgentInput = { client?: Pick; transcripts: Pick[]; offer: OfferEditorData; + model?: string; }; function buildSystemPrompt(): string { @@ -128,7 +129,7 @@ export async function generateProposalContent( const client = new Anthropic({ apiKey }); const message = await client.messages.create({ - model: MODEL, + model: input.model ?? MODEL, max_tokens: 8192, system: buildSystemPrompt(), messages: [{ role: "user", content: buildUserPrompt(input) }],