{"record":{"id":"3af61ece05324333","repo":"Budibase/budibase","slug":"invalid-tool-call-summary-response","errorCode":null,"errorMessage":"Invalid tool call summary response","messagePattern":"Invalid tool call summary response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/server/src/sdk/workspace/ai/agentRequests/helpers.ts","lineNumber":237,"sourceCode":"  const result = await generateText({\n    model: llm.chat,\n    providerOptions: llm.providerOptions?.(false),\n    headers: {\n      \"x-litellm-tags\": \"bb-agent-request-tool-call-summary\",\n    },\n    instructions:\n      'Summarize a single tool call for a UI timeline entry, in plain user-friendly language, not technical jargon - describe what the action did and its outcome, e.g. \"Searched tickets for email server errors\" or \"Failed to update the customer\\'s address\". Return plain text only. Use at most 6 to 7 words, no quotes, no punctuation unless necessary.',\n    prompt: JSON.stringify({\n      tool: readableName || toolName,\n      status,\n      input,\n      output,\n    }),\n  })\n\n  const summary = normalizeTitle(result.text || \"\")\n  if (!summary) {\n    throw new Error(\"Invalid tool call summary response\")\n  }\n\n  return summary\n}\n\nexport async function generateInteractionSummary({\n  latestPrompt,\n  agentId,\n  sessionId,\n}: {\n  latestPrompt: string\n  agentId: string\n  sessionId: string\n}): Promise<string> {\n  const agent = await sdk.ai.agents.getOrThrow(agentId)\n  const llm = await sdk.ai.llm.createLLM(\n    agent.aiconfig,\n    sessionId,","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/agentRequests/helpers.ts#L219-L255","documentation":"generateToolCallSummary asks the LLM for a short plain-text summary of a single tool call and normalizes it. If the normalized summary is empty (empty text, or only quotes/whitespace), it throws Error(\"Invalid tool call summary response\"). Called from recordToolCall when recording each tool call on an agent request timeline.","triggerScenarios":"The LLM returns an empty, filtered, or whitespace-only completion when summarizing a tool call (e.g. very large/empty tool output, provider outage yielding empty body).","commonSituations":"Content filters suppressing output for sensitive tool input/output; provider misconfiguration in the agent's aiconfig; oversized prompts leading to empty completions.","solutions":["Catch the error and fall back to a static summary built from the tool name and status (e.g. \"Ran readableName — success\")","Check LiteLLM/provider logs for empty or filtered completions and fix the aiconfig","Truncate very large tool input/output before prompting to avoid degenerate completions"],"exampleFix":"// before\nconst summary = await generateToolCallSummary({ toolName, status, ... })\n// after\nlet summary\ntry {\n  summary = await generateToolCallSummary({ toolName, status, ... })\n} catch {\n  summary = `${readableName || toolName} ${status === \"success\" ? \"completed\" : \"failed\"}`\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let summary\ntry {\n  summary = await generateToolCallSummary({ toolName, status, input, output, agentId, sessionId })\n} catch (err) {\n  if (err instanceof Error && err.message === \"Invalid tool call summary response\") {\n    summary = `${readableName || toolName} ${status}`\n  } else {\n    throw err\n  }\n}","preventionTips":["Truncate large tool input/output before summarizing","Check provider/content-filter logs when summaries come back empty","Always keep a static fallback summary so tool-call recording never fails on the LLM"],"tags":["llm","empty-response","tool-calls","agent-requests"],"backgroundTag":"llm-empty-response","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}