Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(chat): raise maxSteps 20→100 on user-facing chat surfaces

merged#2487CedarCopilot

CedarCopilot wants to merge 0 commits into staging from fix/chat-maxsteps-100

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 14, 2026, 6:08 PM
  2. Merged
    Aug 14, 2026, 6:56 PM
  3. Live on prod
    Aug 14, 2026, 6:56 PM
  4. Observed 2 days
    Aug 14, 2026, 6:56 PM
  5. Pipelines steady after this deploy
    Aug 14, 2026, 6:56 PM
  6. Unobserved

    Live on prod, no production signal yet

    Aug 17, 2026, 3:59 PM

Behaviors Libra is checking

User-facing chat agents can execute up to 100 steps instead of stopping after 20 across frontend, Slack, iMessage, and SMS conversations.Not checked
prod, checked Aug 17, 2026, 3:59 PM

Libra has verdicts on 0 of 1 tracked behaviors on prod; 1 is still being checked. Libra checks hourly for 3 days after each deploy.

What

Raises the chat agent's tool-loop step cap from 20 → 100 on the four surfaces the user interacts with directly:

SurfaceFile
Frontend (in-app chat)chat-workflow.ts
Slackslack-bot-chat.ts
iMessageimessage-bot-chat.ts
SMSsms-bot-chat.ts

Background/automation paths (orchestrator dispatch, operation registry, execute-orchestrator, etc.) are intentionally left at their existing caps , this only touches direct-user chat.

Why

Investigating why the Slack bot sometimes replies "I did not generate a response." The message is a fallback that fires only when the agent finishes with empty text. Prod telemetry (last 14 days):

  • 7 of 153 Slack replies went out empty ({"text":""}, no buttons, no thread replies).
  • Every one traced to a Chat Agent (Understudy) generate() that ended on finish_reason: "tool-calls" , i.e. it hit maxSteps: 20 while still mid tool-loop (8k,24k output tokens).

The prompts force multiple silent lookups (find-crm-conversationsget-conversation → write) before any output and only ever emit text inside a final <final_answer> block, so a run that exhausts the step budget has no assistant text anywhere → extractFinalAgentText returns "" → the fallback string. Raising the ceiling gives these runs room to reach their final answer.

The frontend never hit the cap in the measured window (0/238 exhaustions; it also streams, so it wouldn't blank out) , but it's raised too for consistency across direct-user surfaces.

Follow-ups (not in this PR)

This raises the ceiling but does not remove the failure mode , a run that still exhausts 100 steps hits the same blank-message fallback on the headless generate() path. Recommended next steps:

  1. Forced-final-answer retry: when a run ends on finish_reason: "tool-calls" / empty text, do one more "wrap up now" generate step instead of giving up.
  2. Graceful empty-text fallback + fix the latent responseText = structured?.text ?? rawText (?? preserves "") so a threadReplies-only response isn't blanked.
  3. Cost/latency watch: a genuinely stuck loop can now run ~5× longer / ~5× tokens before terminating; the retry above also caps that downside.

🤖 Generated with Claude Code

Greptile Summary

Raises the Mastra agent tool-loop limit from 20 to 100 for the four direct-user chat surfaces so multi-step requests have more opportunity to produce a final response.

  • Updates headless Slack, SMS, and iMessage agent generation limits.
  • Updates the legacy in-app streaming chat path to the same limit.
  • Leaves background and automation agent limits unchanged.

Confidence Score: 5/5

The PR appears safe to merge, with the explicitly acknowledged increase in worst-case agent cost and latency remaining the primary operational tradeoff.

The changes only raise existing step limits on direct-user chat invocations, and the review found no concrete new timeout, retry, delivery, security, or correctness failure.

Important Files Changed

FilenameOverview
apps/server/src/mastra/routeHandlers/imessage/imessage-bot-chat.tsRaises the iMessage chat agent generation limit from 20 to 100 steps without changing routing or response handling.
apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.tsRaises the Slack chat agent generation limit from 20 to 100 steps to reduce empty responses from unfinished tool loops.
apps/server/src/mastra/routeHandlers/sms/sms-bot-chat.tsRaises the SMS chat agent generation limit from 20 to 100 steps without changing surrounding behavior.
apps/server/src/mastra/workflows/chat/chat-workflow.tsApplies the same 100-step limit to the legacy streamed in-app Mastra chat path.

Reviews (1): Last reviewed commit: ["fix(chat): raise maxSteps 20→100 on user..."](https://github.com/cedarcopilot/cedar

Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/routeHandlers/imessage/imessage-bot-chat.tsno production surface mapped
  • apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.tsno production surface mapped
  • apps/server/src/mastra/routeHandlers/sms/sms-bot-chat.tsno production surface mapped
  • apps/server/src/mastra/workflows/chat/chat-workflow.tsno production surface mapped