Some chat templates write the opening think tag into the prompt
(Spark-X2.5, Qwen3 thinking variants, DeepSeek-R1-0528 served without a
reasoning parser), so the model streams only …SAY:. ReplyParser had no
opening tag to match, settled on plain mode at the first non-format
characters, and spoke every reasoning sentence — to the person on the
phone, in the user's voice — plus the stray tags.
Implements the reporter's recommended parser-side fix (FenjuFu,
option 1):
- _body now drops everything up to a closing tag found anywhere, or up
to a line-start SAY: when no closing tag comes either. Both searches
are stable on the append-only raw text, so _emitted stays aligned.
- _decide_mode no longer settles plain early: the system prompt
requires replies to start with SAY: or {, so a body with neither is
held while it streams (it may be prefilled thinking) and only
finish() speaks it as plain text. Format-following replies keep
first-sentence streaming.
Regression tests fail before the parser change; the reporter's exact
repro now returns only the SAY: text in both variants.
* feat(integrations): guided Twilio setup and responsive integration pages
- Twilio detail page is a step-by-step checklist (account, tunnel, phone
number, voice and behavior) with live status, per-step saves, exact
cloudflared/ngrok commands for the OS and gateway port, copyable webhook
URL, readiness rail, test card with explicit disabled reasons, recent calls
and a "How it works" security explainer. Calls backend endpoints
(/calls/settings, /calls/readiness) and the /calls route are feature-detected.
- Detail pages: per-integration taglines from the registry, own category
labels (no borrowed "Dubbing" key), one docs link, full-width scroller with
a two-column container-query layout and sticky rail.
- Select triggers always label their value (no raw __default__, auto, *, or
locale codes); a source-scan test guards the class.
- Catalog and featured logos open the in-app page, never a vendor website.
- Gateway state exposes preferred_port so the tunnel command is exact before
calls are turned on.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(changelog): reference #2304
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(integrations): exact tunnel port and honest webhook status
- preferred_port uses the same free-port probe as gateway start, so a taken
base port no longer yields a tunnel command for the wrong service.
- The phone-number step is Done only after a call that passed the signature
check; rejected or busy attempts do not count.
- Docs: Learn more applies to pages with a built-in setup.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(changelog): list the #2304 docs update
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(i18n): phone step completes on a signed call; merge changelog Docs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(calls): phone call agent backend — outbound/inbound calls in your voice
Adds a task-driven call agent on top of the Twilio integration: outbound
calls via Twilio REST with signed status callbacks, a provider-agnostic
conversation loop (energy VAD -> capture ASR -> streamed LLM turn -> streaming
TTS, barge-in via clear), persisted call sessions (alembic 0012), the /calls
local API with SSE events, take-over/say/hangup, and inbound agent mode.
Owner safeguards: editable AI disclosure on by default, outbound voices gated
to verified-own or designed profiles (403), one explicit request per call with
max 1-2 concurrent, recording only when enabled and disclosed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(changelog): reference #2306
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(changelog): add Unreleased highlights
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(calls): address review — affirmative recording notice, one agent-call limit, wider number guard
- Recording needs an affirmative notice; negated disclosures never record (greptile)
- max_concurrent now limits agent calls in both directions (greptile)
- Sensitive-number guard also catches comma and Unicode-dash separators (greptile)
- Constant upsert SQL, https-only urlopen guard, no BaseException catch (code scanning)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(calls): always finalize a connected call; allow brief numbers in any phone style
- Finalize agent calls in a shielded finally so a failed/cancelled stream frees its slot (coderabbit)
- Guard allows numbers from the brief written with parentheses or a country code (coderabbit)
- Docs: the no-LLM fallback needs a configured greeting (coderabbit)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(calls): wait on record changes instead of sleeping; assert the injected stream failure
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>