Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/builder/__tests__/ai-agent-action-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from "@/features/ai-agents/schemas/action"

describe("AI agent action schemas", () => {
test("defaults rich response on create", () => {
test("defaults optional toggles on create", () => {
const result = createAIAgentRequest.safeParse({
name: "Support",
prompt: "Answer customer questions.",
Expand All @@ -18,10 +18,13 @@ describe("AI agent action schemas", () => {
})

expect(result.success).toBe(true)
expect(result.data).toMatchObject({ isRichResponse: false })
expect(result.data).toMatchObject({
disableSummary: false,
isRichResponse: false,
})
})

test("does not default rich response on partial update", () => {
test("does not default optional toggles on partial update", () => {
const result = updateAIAgentRequest.safeParse({ isDefault: true })

expect(result.success).toBe(true)
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,10 @@
"description": "إرجاع JSON منظم يحتوي على رسائل وإجراءات بدلًا من بث نص عادي.",
"label": "رد منسّق"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "تُعيّن اللغة الافتراضية لجهات الاتصال عندما تكون لغتها غير معروفة.",
"label": "اللغة",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Return structured JSON med beskeder og actions instead af plain tekst streaming.",
"label": "Rich Svar"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Kontakter er tildelt den standard sprog når den kontakt sprog er unknown.",
"label": "Sprog",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Strukturiertes JSON mit Nachrichten und Aktionen anstelle eines einfachen Textstreams zurückgeben.",
"label": "Strukturierte Antwort"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Kontakten wird die Standardsprache zugewiesen, wenn ihre Sprache unbekannt ist.",
"label": "Sprache",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,10 @@
"description": "Return structured JSON with messages and actions instead of plain text streaming.",
"label": "Rich Response"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Contacts are assigned the default language when the contact language is unknown.",
"label": "Language",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,10 @@
"description": "Devuelve JSON estructurado con mensajes y acciones en lugar de transmitir texto sin formato.",
"label": "Respuesta enriquecida"
},
"disableSummary": {
"description": "Usa solo los mensajes recientes de la conversación, sin el resumen acumulado. Las conversaciones largas pueden perder el contexto anterior a los últimos mensajes.",
"label": "Deshabilitar resumen de conversación"
},
"language": {
"description": "A los contactos se les asigna el idioma predeterminado cuando se desconoce su idioma.",
"label": "Idioma",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Palauta jäsennelty JSON, joka sisältää viestit ja toiminnot, pelkän tekstin suoratoiston sijaan.",
"label": "Monipuolinen vastaus"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Yhteystiedoille määritetään oletuskieli, kun yhteystiedon kieltä ei tunneta.",
"label": "Kieli",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Renvoyer un JSON structuré avec des messages et des actions au lieu d’un flux de texte brut.",
"label": "Réponse enrichie"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "La langue par défaut est attribuée aux contacts dont la langue est inconnue.",
"label": "Langue",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -3667,6 +3667,10 @@
"description": "החזרת JSON מובנה עם הודעות ופעולות במקום הזרמת טקסט רגיל.",
"label": "תגובה עשירה"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "לאנשי קשר מוקצית שפת ברירת המחדל כאשר שפת איש הקשר אינה ידועה.",
"label": "שפה",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Return structured JSON dengan pesans dan actions instead dari plain teks streaming.",
"label": "Respons Kaya"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Kontak diberi bahasa default saat bahasa kontak tidak diketahui.",
"label": "Bahasa",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@
"description": "Restituisce JSON strutturato con messaggi e azioni invece di testo semplice in streaming.",
"label": "Risposta avanzata"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Ai contatti viene assegnata la lingua predefinita quando la loro lingua è sconosciuta.",
"label": "Lingua",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "プレーンテキストのストリーミングではなく、メッセージとアクションを含む構造化JSONを返します。",
"label": "リッチレスポンス"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "連絡先の言語が不明な場合、デフォルト言語が連絡先に割り当てられます。",
"label": "言語",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,10 @@
"description": "Retourneer gestructureerde JSON met berichten en acties in plaats van streaming in platte tekst.",
"label": "Verrijkt antwoord"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Contacten krijgen de standaardtaal toegewezen wanneer hun taal onbekend is.",
"label": "Taal",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Retorne JSON estruturado com mensagens e ações em vez de streaming de texto simples.",
"label": "Resposta avançada"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Os contatos recebem o idioma padrão quando o idioma do contato é desconhecido.",
"label": "Idioma",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,10 @@
"description": "Devolver JSON estruturado com mensagens e ações em vez de transmissão de texto simples.",
"label": "Resposta avançada"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "É atribuído o idioma predefinido aos contactos quando o respetivo idioma é desconhecido.",
"label": "Idioma",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/ro.json
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,10 @@
"description": "Returnează JSON structurat cu mesaje și acțiuni în locul unui flux de text simplu.",
"label": "Răspuns complex"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Contactelor li se atribuie limba implicită atunci când limba contactului este necunoscută.",
"label": "Limbă",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,10 @@
"description": "Returnera strukturerad JSON med meddelanden och åtgärder i stället för direktuppspelad oformaterad text.",
"label": "Strukturerat svar"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"jsonPath": {
"placeholder": "Ange JSON-sökväg",
"targetThisRow": "Fyll den här raden från JSON"
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,10 @@
"description": "Düz metin akışı yerine mesajlar ve eylemler içeren yapılandırılmış JSON döndürün.",
"label": "Zengin Yanıt"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "Kişinin dili bilinmediğinde kişilere varsayılan dil atanır.",
"label": "Dil",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,10 @@
"description": "Trả về JSON có cấu trúc gồm tin nhắn và hành động thay vì stream văn bản thuần.",
"label": "Rich Response"
},
"disableSummary": {
"description": "Chỉ dùng các tin nhắn gần đây trong cuộc trò chuyện, không dùng bản tóm tắt tích lũy. Cuộc trò chuyện dài có thể mất ngữ cảnh cũ hơn các tin nhắn mới nhất.",
"label": "Tắt tóm tắt cuộc trò chuyện"
},
"language": {
"description": "Liên hệ được gán ngôn ngữ mặc định khi ngôn ngữ liên hệ không xác định.",
"label": "Ngôn ngữ",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,10 @@
"description": "传回包含消息与操作的结构化 JSON,而不是纯文本流。",
"label": "丰富回应"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"javascriptCode": {
"description": "使用纯 JavaScript 并返回一个值。网络、文件、API 和外部库均不可用。可通过 `input` 对象访问联系人和系统数据。",
"label": "JavaScript 代码",
Expand Down
4 changes: 4 additions & 0 deletions apps/builder/messages/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@
"description": "傳回包含訊息與操作的結構化 JSON,而不是純文字流。",
"label": "豐富回應"
},
"disableSummary": {
"description": "Use only recent conversation messages, without the accumulated summary. Long conversations may lose context older than the latest messages.",
"label": "Disable conversation summary"
},
"language": {
"description": "聯絡人將套用此預設語言。",
"label": "語言",
Expand Down
10 changes: 10 additions & 0 deletions apps/builder/src/features/ai-agents/create-ai-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export function CreateAIAgentDialog({
prompt: "",
isDefault: false,
isRichResponse: false,
disableSummary: false,
messages: [],
models: [
...aiChatProviders.map((provider) => ({
Expand Down Expand Up @@ -334,6 +335,15 @@ export function CreateAIAgentDialog({

<AIToolMultiSelect name="tools" />
<WebSearchAuthorizedDomainsField />
<div>
<div className="flex items-center gap-3">
<Label>{t("fields.disableSummary.label")}</Label>
<SwitchField formItemClassName="w-auto" name="disableSummary" />
</div>
<p className="wrap-break-words mt-1.5 text-muted-foreground text-sm">
{t("fields.disableSummary.description")}
</p>
</div>
<div>
<div className="flex items-center gap-3">
<Label>{t("fields.isRichResponse.label")}</Label>
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/src/features/ai-agents/schemas/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ export const createAIAgentRequest = z.object({
webSearchAuthorizedDomains: webSearchAuthorizedDomainsSchema.default([]),
isDefault: z.boolean(),
isRichResponse: z.boolean().default(false),
disableSummary: z.boolean().default(false),
})
export type CreateAIAgentRequest = z.infer<typeof createAIAgentRequest>

export const updateAIAgentRequest = createAIAgentRequest
.extend({
webSearchAuthorizedDomains: webSearchAuthorizedDomainsSchema,
isRichResponse: z.boolean(),
disableSummary: z.boolean(),
})
.partial()
export type UpdateAIAgentRequest = z.infer<typeof updateAIAgentRequest>
10 changes: 10 additions & 0 deletions apps/builder/src/features/ai-agents/update-ai-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export function UpdateAIAgentDialog({
setValue("messages", agent.messages as UpdateAIAgentRequest["messages"])
setValue("tools", agent.tools)
setValue("isRichResponse", agent.isRichResponse)
setValue("disableSummary", agent.disableSummary)
setValue(
"webSearchAuthorizedDomains",
agent.webSearchAuthorizedDomains.map((domain) => ({ value: domain })),
Expand Down Expand Up @@ -341,6 +342,15 @@ export function UpdateAIAgentDialog({

<AIToolMultiSelect name="tools" />
<WebSearchAuthorizedDomainsField />
<div>
<div className="flex items-center gap-3">
<Label>{t("fields.disableSummary.label")}</Label>
<SwitchField formItemClassName="w-auto" name="disableSummary" />
</div>
<p className="wrap-break-words mt-1.5 text-muted-foreground text-sm">
{t("fields.disableSummary.description")}
</p>
</div>
<div>
<div className="flex items-center gap-3">
<Label>{t("fields.isRichResponse.label")}</Label>
Expand Down
16 changes: 16 additions & 0 deletions apps/worker/__tests__/ai-agent-runner-openai-compatible.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function makeAIAgent(overrides?: Partial<AIAgentModel>): AIAgentModel {
messages: [],
isDefault: false,
isRichResponse: false,
disableSummary: false,
tools: [],
webSearchAuthorizedDomains: [],
models: [{ provider: "openai", model: "gpt-5.4-mini" }],
Expand Down Expand Up @@ -181,6 +182,21 @@ describe("AI agent runner OpenAI-compatible providers", () => {
})
})

test("omits conversation summary from the system prompt when disabled", async () => {
await runAIAgentRunner({
aiAgent: makeAIAgent({ disableSummary: true }),
conversation: makeConversation(),
messages: [] as ModelMessage[],
summary: "Old lead data",
})

expect(streamText).toHaveBeenCalledWith(
expect.objectContaining({
system: "You are helpful.",
}),
)
})

test("runs a preferred OpenAI-compatible model without native provider filtering", async () => {
const result = await runAIAgentRunner({
aiAgent: makeAIAgent({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function makeAgent(): AIAgentModel {
messages: [],
isDefault: false,
isRichResponse: false,
disableSummary: false,
tools: [],
webSearchAuthorizedDomains: [],
models: [{ provider: "openai", model: "gpt-5.4-mini" }],
Expand Down
16 changes: 16 additions & 0 deletions apps/worker/__tests__/automated-response-default-reply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ function makeAIAgent(overrides?: Partial<AIAgentModel>): AIAgentModel {
messages: [],
isDefault: false,
isRichResponse: false,
disableSummary: false,
tools: ["sys:some_tool"],
webSearchAuthorizedDomains: [],
models: [{ provider: "openai", model: "gpt-4o" }] as AIAgentModel["models"],
Expand Down Expand Up @@ -548,6 +549,21 @@ describe("replyByAI — default reply flow fallback", () => {
})
})

test("omits conversation summary from the system prompt when disabled", async () => {
await replyByAI({
...baseProps,
aiAgent: makeAIAgent({ disableSummary: true }),
defaultReplyFlowId: null,
summary: "Old lead data",
})

expect(streamText).toHaveBeenCalledWith(
expect.objectContaining({
system: "You are a helpful assistant.",
}),
)
})

test("triggers the default reply flow instead of the canned fallback text when configured and valid", async () => {
findByFlowMock.mockResolvedValueOnce({
id: "flow-1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ function makeAIAgent(overrides?: Partial<AIAgentModel>): AIAgentModel {
messages: [],
isDefault: false,
isRichResponse: true,
disableSummary: false,
tools: [],
webSearchAuthorizedDomains: [],
models: [{ provider: "openai", model: "gpt-4o" }] as AIAgentModel["models"],
Expand Down
Loading