Repository navigation
Fix phone agent duplicate responses on reconnect - #105
Merged
Merged
Conversation
Replace fixed 6-second replay suppression timeout with turn-count-based detection. Tracks conversation turn count before disconnect, unmutes when Gemini replays all previous turns. Fallback timeout scales with conversation length (max of 10s or 2s per turn). Root cause: for longer calls (>3 turns), the 6s timeout expired before Gemini finished replaying the conversation history, causing duplicate audio. Call log scanner found 217 duplicate response instances across 57/158 calls. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liususan091219
added a commit
that referenced
this pull request
Apr 5, 2026
Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR #67 - Apr 2-3: 13-29% after PR #105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liususan091219
added a commit
that referenced
this pull request
Apr 6, 2026
Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR #67 - Apr 2-3: 13-29% after PR #105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sonichi
pushed a commit
that referenced
this pull request
Apr 7, 2026
* Add 3 new call log scanner detectors from transcript analysis New patterns detected across 263 calls: - reconnect_leak: 37 calls with "I'm back" after Gemini reconnect - repeated_summon: 3 calls where user asked to summon 3+ times - repeated_tab_switch: 7 calls where tab switching failed repeatedly Added 6 tests (20 total, was 14). Scanner now has 8 detectors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add --summary flag to call scanner for quality trend tracking Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR #67 - Apr 2-3: 13-29% after PR #105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add 3 new call detectors: recording confusion, scroll frustration, STT retry Analyzed all 266 calls to find missing patterns: - recording_confusion: 28 calls where user expected recording to start/stop - scroll_frustration: 4 calls with 3+ scroll requests (tool unresponsive) - stt_retry: 23 calls where caller rephrased (word overlap 30-90%) Quality trend shows issue rate dropped from 80-100% (Mar 28) to 25-32% (Apr 5). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix recording_confusion false positives — exclude IVR lines Tightened recording_confusion detector to exclude IVR "You have not entered any numbers" and similar menu prompts. Also removed overly broad "you have not" pattern that matched non-recording IVR messages. Result: 28 → 8 detections (20 false positives removed). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove tests/ from tracked files — should be gitignored Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sonichi
pushed a commit
that referenced
this pull request
Apr 7, 2026
* Pass previous description to Gemini for natural continuation Screen descriptions now flow naturally instead of every sentence starting with "The screen displays...". When a previous description exists, the prompt says "Continue naturally — do NOT start with The screen displays or repeat the previous description." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Revert "Pass previous description to Gemini for natural continuation" This reverts commit 1105ed89e6cc41a0de777bc3b1dff9d157589d23. * Make task watcher persistent (loop instead of one-shot) watch-tasks.sh now loops continuously instead of exiting after detecting one batch of tasks. This eliminates the recurring issue where the watcher dies between task detections, causing delayed task pickup (e.g. the Discord video send delay). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add proactive Discord DM support to bridge The bridge now scans results/proactive-*.txt and sends them to the owner's DM channel. Previously only task replies were sent back — proactive messages (like sending a video unprompted) were silently dropped because they had no matching pending_replies entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix 3 CodeQL security alerts - browser-tools.ts: Fix command injection in typeText — write AppleScript to temp file instead of inline shell interpolation - conversation-server.ts: Sanitize DTMF digits in TwiML Play (strip non-digit chars to prevent XML injection) - conversation-server.ts: Improve phone number masking in startup log (show only first 2 + last 2 digits) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Harden path traversal guards in dashboard and agent-api - dashboard.py: Add resolve() + is_relative_to() for notes read and delete endpoints (supplements existing regex guard) - agent-api.py: Remove unused mimetypes import (replaced by SAFE_TYPES allowlist in previous security fix) Addresses CodeQL alerts #28-31 (dashboard) and cleans up #19-23 (agent-api already has guards, but adding belt-and-suspenders). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add 3 new call log scanner detectors from transcript analysis New patterns detected across 263 calls: - reconnect_leak: 37 calls with "I'm back" after Gemini reconnect - repeated_summon: 3 calls where user asked to summon 3+ times - repeated_tab_switch: 7 calls where tab switching failed repeatedly Added 6 tests (20 total, was 14). Scanner now has 8 detectors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Expand security tests for CodeQL fixes (33 assertions, was 17) New test coverage for: - Dashboard note slug validation (7 tests: traversal, slash, null byte, injection) - Dashboard note path resolution via is_relative_to (2 tests) - DTMF digit sanitization for TwiML injection (5 tests) - TypeText AppleScript injection prevention (2 tests) Total test suite: 120 assertions across 4 suites, all passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add test runner script (4 suites, 120 assertions) bash tests/run-all.sh runs all test suites: - Phone access control (49 assertions) - Browser tools / STT corrections (18 assertions) - Security sanitization (33 assertions) - Call log scanner (20 assertions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix migration script: auto-detect memory dir + don't exit on optional paths - Memory dir now auto-detected from repo path slug (falls back to default ~/Desktop/sutando path) - Session dir also auto-detected - Replaced set -e with set -uo pipefail — many migration paths legitimately don't exist and shouldn't abort the script - Tested: successfully bundles .env, 22 memory files, claude config, session history, flywheel data into 3.2MB tarball Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add --summary flag to call scanner for quality trend tracking Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR #67 - Apr 2-3: 13-29% after PR #105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add migration script tests (14 assertions, 5 suites total) Tests cover: - REPO_SLUG generation (no slashes, starts with dash) - Memory dir auto-detection from repo path - Session dir detection - Bundle creation (env, memory, MEMORY.md) - Script syntax validation (no set -e) Total: 134 assertions across 5 suites, all passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add ngrok tunnel to health check (13 checks total) Verifies the ngrok HTTPS tunnel is active — required for inbound phone calls via Twilio. Shows tunnel URL in health output. Only checked when Twilio is configured in .env. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add Twilio webhook URL verification script Checks if Twilio's phone number webhook matches the current ngrok tunnel. Stale webhooks are a common failure mode — inbound calls silently fail. Supports --fix flag to auto-update Twilio. Usage: bash src/check-webhook.sh [--fix] Exit: 0=match, 1=mismatch, 2=error Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add Twilio webhook verification to health check (15 checks) Runs check-webhook.sh as part of the health check — warns if Twilio's voice URL doesn't match the current ngrok tunnel. Stale webhooks cause inbound calls to silently fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix Python 3.9 compat in github-webhook.py Remove str | None return type annotation (requires Python 3.10+). Susan runs Python 3.9 — this would crash on import. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address review: fix 2 blockers + 2 yellow items (Wenjix review) Blocker 1: check-webhook.sh Python injection — pass phone number via env var instead of interpolating into Python source string. Blocker 2: phone mask padEnd alignment — wrap entire masked string in parens before padEnd. Show last 4 digits (standard compromise). Yellow: discord-bridge proactive files — rename to .failed on send failure instead of deleting (preserves message for inspection). Yellow: typeText tmp file — add random suffix to prevent race, use try/finally to ensure cleanup on execSync failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove test files from PR (tests/ is gitignored, should stay local) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove non-security changes from PR Revert infra/tooling files to main — this PR should only contain security fixes with CodeQL citations. Non-security changes (webhook script, scanner detectors, health checks, migration, watcher, Discord DM, Python 3.9 fix) moved to local infra branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add CodeQL citation comments to all security fixes Each fix now has an inline code comment citing the specific CodeQL alert number and what vulnerability it addresses. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liususan091219
pushed a commit
to liususan091219/sutando-fork
that referenced
this pull request
May 28, 2026
Replace fixed 6-second replay suppression timeout with turn-count-based detection. Tracks conversation turn count before disconnect, unmutes when Gemini replays all previous turns. Fallback timeout scales with conversation length (max of 10s or 2s per turn). Root cause: for longer calls (>3 turns), the 6s timeout expired before Gemini finished replaying the conversation history, causing duplicate audio. Call log scanner found 217 duplicate response instances across 57/158 calls. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liususan091219
added a commit
to liususan091219/sutando-fork
that referenced
this pull request
May 28, 2026
* Add 3 new call log scanner detectors from transcript analysis New patterns detected across 263 calls: - reconnect_leak: 37 calls with "I'm back" after Gemini reconnect - repeated_summon: 3 calls where user asked to summon 3+ times - repeated_tab_switch: 7 calls where tab switching failed repeatedly Added 6 tests (20 total, was 14). Scanner now has 8 detectors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add --summary flag to call scanner for quality trend tracking Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR sonichi#67 - Apr 2-3: 13-29% after PR sonichi#105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add 3 new call detectors: recording confusion, scroll frustration, STT retry Analyzed all 266 calls to find missing patterns: - recording_confusion: 28 calls where user expected recording to start/stop - scroll_frustration: 4 calls with 3+ scroll requests (tool unresponsive) - stt_retry: 23 calls where caller rephrased (word overlap 30-90%) Quality trend shows issue rate dropped from 80-100% (Mar 28) to 25-32% (Apr 5). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix recording_confusion false positives — exclude IVR lines Tightened recording_confusion detector to exclude IVR "You have not entered any numbers" and similar menu prompts. Also removed overly broad "you have not" pattern that matched non-recording IVR messages. Result: 28 → 8 detections (20 false positives removed). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove tests/ from tracked files — should be gitignored Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
liususan091219
added a commit
to liususan091219/sutando-fork
that referenced
this pull request
May 28, 2026
* Pass previous description to Gemini for natural continuation Screen descriptions now flow naturally instead of every sentence starting with "The screen displays...". When a previous description exists, the prompt says "Continue naturally — do NOT start with The screen displays or repeat the previous description." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Revert "Pass previous description to Gemini for natural continuation" This reverts commit 1105ed89e6cc41a0de777bc3b1dff9d157589d23. * Make task watcher persistent (loop instead of one-shot) watch-tasks.sh now loops continuously instead of exiting after detecting one batch of tasks. This eliminates the recurring issue where the watcher dies between task detections, causing delayed task pickup (e.g. the Discord video send delay). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add proactive Discord DM support to bridge The bridge now scans results/proactive-*.txt and sends them to the owner's DM channel. Previously only task replies were sent back — proactive messages (like sending a video unprompted) were silently dropped because they had no matching pending_replies entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix 3 CodeQL security alerts - browser-tools.ts: Fix command injection in typeText — write AppleScript to temp file instead of inline shell interpolation - conversation-server.ts: Sanitize DTMF digits in TwiML Play (strip non-digit chars to prevent XML injection) - conversation-server.ts: Improve phone number masking in startup log (show only first 2 + last 2 digits) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Harden path traversal guards in dashboard and agent-api - dashboard.py: Add resolve() + is_relative_to() for notes read and delete endpoints (supplements existing regex guard) - agent-api.py: Remove unused mimetypes import (replaced by SAFE_TYPES allowlist in previous security fix) Addresses CodeQL alerts sonichi#28-31 (dashboard) and cleans up sonichi#19-23 (agent-api already has guards, but adding belt-and-suspenders). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add 3 new call log scanner detectors from transcript analysis New patterns detected across 263 calls: - reconnect_leak: 37 calls with "I'm back" after Gemini reconnect - repeated_summon: 3 calls where user asked to summon 3+ times - repeated_tab_switch: 7 calls where tab switching failed repeatedly Added 6 tests (20 total, was 14). Scanner now has 8 detectors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Expand security tests for CodeQL fixes (33 assertions, was 17) New test coverage for: - Dashboard note slug validation (7 tests: traversal, slash, null byte, injection) - Dashboard note path resolution via is_relative_to (2 tests) - DTMF digit sanitization for TwiML injection (5 tests) - TypeText AppleScript injection prevention (2 tests) Total test suite: 120 assertions across 4 suites, all passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add test runner script (4 suites, 120 assertions) bash tests/run-all.sh runs all test suites: - Phone access control (49 assertions) - Browser tools / STT corrections (18 assertions) - Security sanitization (33 assertions) - Call log scanner (20 assertions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix migration script: auto-detect memory dir + don't exit on optional paths - Memory dir now auto-detected from repo path slug (falls back to default ~/Desktop/sutando path) - Session dir also auto-detected - Replaced set -e with set -uo pipefail — many migration paths legitimately don't exist and shouldn't abort the script - Tested: successfully bundles .env, 22 memory files, claude config, session history, flywheel data into 3.2MB tarball Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add --summary flag to call scanner for quality trend tracking Shows daily breakdown: total calls, clean vs issues, issue rate, top patterns per day. Clear improvement trend visible: - Mar 28-30: 80-100% issue rate (duplicates) - Mar 31: 45% after PR sonichi#67 - Apr 2-3: 13-29% after PR sonichi#105 - Apr 4: 21% (remaining: confusion + tab switching) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add migration script tests (14 assertions, 5 suites total) Tests cover: - REPO_SLUG generation (no slashes, starts with dash) - Memory dir auto-detection from repo path - Session dir detection - Bundle creation (env, memory, MEMORY.md) - Script syntax validation (no set -e) Total: 134 assertions across 5 suites, all passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add ngrok tunnel to health check (13 checks total) Verifies the ngrok HTTPS tunnel is active — required for inbound phone calls via Twilio. Shows tunnel URL in health output. Only checked when Twilio is configured in .env. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add Twilio webhook URL verification script Checks if Twilio's phone number webhook matches the current ngrok tunnel. Stale webhooks are a common failure mode — inbound calls silently fail. Supports --fix flag to auto-update Twilio. Usage: bash src/check-webhook.sh [--fix] Exit: 0=match, 1=mismatch, 2=error Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add Twilio webhook verification to health check (15 checks) Runs check-webhook.sh as part of the health check — warns if Twilio's voice URL doesn't match the current ngrok tunnel. Stale webhooks cause inbound calls to silently fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix Python 3.9 compat in github-webhook.py Remove str | None return type annotation (requires Python 3.10+). Susan runs Python 3.9 — this would crash on import. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address review: fix 2 blockers + 2 yellow items (Wenjix review) Blocker 1: check-webhook.sh Python injection — pass phone number via env var instead of interpolating into Python source string. Blocker 2: phone mask padEnd alignment — wrap entire masked string in parens before padEnd. Show last 4 digits (standard compromise). Yellow: discord-bridge proactive files — rename to .failed on send failure instead of deleting (preserves message for inspection). Yellow: typeText tmp file — add random suffix to prevent race, use try/finally to ensure cleanup on execSync failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove test files from PR (tests/ is gitignored, should stay local) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove non-security changes from PR Revert infra/tooling files to main — this PR should only contain security fixes with CodeQL citations. Non-security changes (webhook script, scanner detectors, health checks, migration, watcher, Discord DM, Python 3.9 fix) moved to local infra branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add CodeQL citation comments to all security fixes Each fix now has an inline code comment citing the specific CodeQL alert number and what vulnerability it addresses. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bassilkhilo-ag2
approved these changes
Jun 5, 2026
bassilkhilo-ag2
left a comment
Collaborator
There was a problem hiding this comment.
LGTM — workspace-path fix looks correct.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Root cause
For longer calls (>3 turns), the fixed 6s timeout expired before Gemini finished replaying conversation history, causing duplicate audio output.
Call log scanner (PR #104) found 217 duplicate response instances across 57/158 calls — this was the #1 detected issue.
Test plan
[Phone] replay completelog message appears on reconnect🤖 Generated with Claude Code