From 783d1ff2a3be412ac4f300f39a856bd32e9a4d75 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 13 Sep 2026 04:44:51 +0000 Subject: [PATCH] fix(kickoff): ask for time before phone collect Do not treat "at " as time_text. Book intake asks for party+time when both are missing, and a party-only follow-up asks for time instead of the restaurant number. Co-authored-by: natecl --- .cursor/skills/verify-call-agent/SKILL.md | 2 +- .../verify-call-agent/features/README.md | 2 +- .../features/linq-inbound.md | 2 +- .../features/linq-to-call.md | 6 +- .../features/verify-linq-call.md | 9 +- .../verify-call-agent/scripts/verify_stub.sh | 2 +- README.md | 2 +- call_agent/kickoff.py | 80 ++++++++----- call_agent/verify_linq_call.py | 68 ++++++++++- docs/FEATURE_MAP.md | 10 +- docs/linq.md | 4 +- tests/test_cli.py | 5 +- tests/test_kickoff.py | 113 ++++++++++++++++++ 13 files changed, 256 insertions(+), 49 deletions(-) diff --git a/.cursor/skills/verify-call-agent/SKILL.md b/.cursor/skills/verify-call-agent/SKILL.md index f557ac4..f816564 100644 --- a/.cursor/skills/verify-call-agent/SKILL.md +++ b/.cursor/skills/verify-call-agent/SKILL.md @@ -66,7 +66,7 @@ The script writes to `artifacts/verify-call-agent//` in the repo (the `a - `book-artifacts//`. A retain run's booking artifacts, copied from the scratch artifacts dir. - `verify-book.txt`. The seven-line checklist and `7/7 passed`. - `verify-message.txt`. The six-line MessagingPort checklist and `6/6 passed`. -- `verify-linq-call.txt`. The thirteen-line linq-to-call checklist and `13/13 passed`. +- `verify-linq-call.txt`. The fourteen-line linq-to-call checklist and `14/14 passed`. - `verify-webhooks.txt`. The Worker inbox five-line checklist and `5/5 passed`. - `verify-persistence.txt`. The four-line checklist, `sqlite ledger + local artifacts`, and `4/4 passed`. The partial-R2 refusal is in `transcript.txt`. diff --git a/.cursor/skills/verify-call-agent/features/README.md b/.cursor/skills/verify-call-agent/features/README.md index 9687c5f..b42f82f 100644 --- a/.cursor/skills/verify-call-agent/features/README.md +++ b/.cursor/skills/verify-call-agent/features/README.md @@ -47,7 +47,7 @@ Each feature file starts with an H1 title and one paragraph describing the user- - [Always-on webhooks versus local tunnel](./webhooks.md) covers the Worker prod path at `https://call-agent-webhooks.usetreena.workers.dev/linq/webhook`, the laptop tunnel, `PUBLIC_WEBHOOK_URL`, and the Linq hook. - [Linq inbound (closed alpha)](./linq-inbound.md) covers the iMessage L1 ingress hook. SMS stays off. - [Linq to call (closed alpha)](./linq-to-call.md) covers iMessage natural collect + confirm-before-dial → Fly `run_call` → result on the same chat. -- [Verify linq-to-call](./verify-linq-call.md) covers the thirteen-check stub lever for that path. +- [Verify linq-to-call](./verify-linq-call.md) covers the fourteen-check stub lever for that path. - [Verify webhooks](./verify-webhooks.md) covers the always-on Worker lever in stub mode and against a deployed URL. - [Verify persistence](./verify-persistence.md) covers the Neon and R2 port lever, the SQLite and local fallback, and the misconfig exit. - [Default wipe at hangup](./privacy-wipe.md) covers write-then-delete after hangup unless retention is on. The privacy page stays not shipped. diff --git a/.cursor/skills/verify-call-agent/features/linq-inbound.md b/.cursor/skills/verify-call-agent/features/linq-inbound.md index 23010f2..ed7580f 100644 --- a/.cursor/skills/verify-call-agent/features/linq-inbound.md +++ b/.cursor/skills/verify-call-agent/features/linq-inbound.md @@ -29,7 +29,7 @@ Preconditions: - **Stub hook.** Run `.venv/bin/call-agent verify-webhooks`. Exit code `0`. The `linq_hook` line is `[PASS]`. Stub POST is 501 `missing_app_base_url`. Stub GET ping is 200 `provider:linq`. - **Stub reply.** Run `.venv/bin/call-agent verify-message`. Exit code `0`. The `inbound_reply` line is `[PASS]` and names the inbound text. -- **Stub kickoff.** Run `.venv/bin/call-agent verify-linq-call`. Exit code `0`. Thirteen `[PASS]` lines and `13/13 passed`. +- **Stub kickoff.** Run `.venv/bin/call-agent verify-linq-call`. Exit code `0`. Fourteen `[PASS]` lines and `14/14 passed`. - **Live register URL.** The string `https://call-agent-webhooks.usetreena.workers.dev/linq/webhook` is in `README.md`, `workers/webhooks/README.md`, and `docs/FEATURE_MAP.md`. - **Proof.** Save `verify-webhooks` stdout as `verify-webhooks.txt`, `verify-message` stdout as `verify-message.txt`, and `verify-linq-call` stdout as `verify-linq-call.txt`. diff --git a/.cursor/skills/verify-call-agent/features/linq-to-call.md b/.cursor/skills/verify-call-agent/features/linq-to-call.md index 7831832..09cfceb 100644 --- a/.cursor/skills/verify-call-agent/features/linq-to-call.md +++ b/.cursor/skills/verify-call-agent/features/linq-to-call.md @@ -1,10 +1,11 @@ # Linq to call (closed alpha) -Closed alpha testers text Treena on iMessage. A natural book ask on that chat collects party and time, then the restaurant phone number, then confirm/approve, then kicks off the same general `run_call` path FastAPI already uses for CLI book and quick-ask. Caller name, kickoff `user_id`, and Telnyx from-DID come from the `users` row for the inbound phone, not from the chat. The Worker forwards Linq POST to Fly. Collect and confirm reply 200. Approve returns 202, texts `Okay, I'm going to call them now.`, places the call, hangs up, and texts the result on the same Linq chat. The first message never dials. It does not pause the live call for mid-call chat. qa owns live prove. +Closed alpha testers text Treena on iMessage. A natural book ask on that chat collects party and time, then the restaurant phone number, then confirm/approve, then kicks off the same general `run_call` path FastAPI already uses for CLI book and quick-ask. If time is missing, Treena asks for time (or party+time) before the phone number. Caller name, kickoff `user_id`, and Telnyx from-DID come from the `users` row for the inbound phone, not from the chat. The Worker forwards Linq POST to Fly. Collect and confirm reply 200. Approve returns 202, texts `Okay, I'm going to call them now.`, places the call, hangs up, and texts the result on the same Linq chat. The first message never dials. It does not pause the live call for mid-call chat. qa owns live prove. ## Sub-features - `parse-book` Natural book intent with party and time, and no restaurant number, becomes a pending collect. A complete first message `book <+E164> party at