apps/cli: Route studio_mobile_* bot replies to studio-mobile-client endpoint (PoC)#3493
apps/cli: Route studio_mobile_* bot replies to studio-mobile-client endpoint (PoC)#3493gcsecsey wants to merge 5 commits into
Conversation
…ndpoint When the polled message comes from a bot whose name starts with studio_mobile_, the remote-session controller now POSTs the reply to /wpcom/v2/studio-mobile-client/respond with an agent_message envelope alongside the existing chat_id and bot routing keys. Other bots keep hitting /local-agent-respond unchanged.
…i-mobile-respond-routing
📊 Performance Test ResultsComparing eeb277f vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
…ing fork Move machine_id into the remote-session config schema with a sanitized os.hostname() default and a STUDIO_REMOTE_MACHINE_ID env override. Removes the MobileTarget struct, the empty-suffix throw in the NDJSON reader path, and the silent base_url misroute when /telegram-bot is missing.
…pond router The mobile and Telegram message shapes were both living inside telegram-client.ts alongside the dispatch logic, which made the file the de-facto home for the entire wire protocol. Move the studio-mobile shape into its own studio-mobile-client.ts, the Telegram-only code stays in telegram-client.ts, and introduce respond-router.ts as the dispatcher (fork + retry loop). Shared HTTP primitives (errors, URL helpers, backoff) move to remote-http.ts; the Telegram-flavored error class names become Remote*Error to reflect that they're transport-layer concerns shared by both clients.
|
@claude please review these changes |
|
Claude finished @gcsecsey's task in 4m 38s —— View job Code Review
SummaryClean, well-scoped refactor. The previous "fork inside
The split is justified by the actual axes of change (transport vs. wire-format vs. retry policy), not premature abstraction, and the public The FindingsPosted two minor inline nits on
A couple of other observations that didn't need inline comments:
Nothing blocking. The bigger architectural question — whether studio-mobile should ever ride the Telegram poll loop, or get its own inbound channel as Phase 2 of the SPEC implies — is correctly out-of-scope for this PoC routing change. |
| if ( ! text ) { | ||
| throw new Error( 'Studio mobile respond requires `text` (photos are not supported yet)' ); | ||
| } |
There was a problem hiding this comment.
Minor — this branch is unreachable in practice. flattenPhotoToText always returns a non-empty string (defaults to the 📷 (image omitted) placeholder), and when photo is absent the empty-text case is already filtered at respond-router.ts:85-87 before this function is called. The guard only fires if someone calls buildMobileRespondBody directly with { text: undefined, photo: undefined }. Either fine to keep as defense-in-depth, or you could drop it and rely on the router-level precondition.
| if ( text && trimmedCaption ) { | ||
| return `${ text }\n\n${ trimmedCaption }`; | ||
| } | ||
| return text || trimmedCaption || '📷 (image omitted)'; |
There was a problem hiding this comment.
Nit: this '📷 (image omitted)' placeholder lands directly in the mobile chat as user-visible text. The rest of the file (and surrounding poll-loop strings like 🟢 Local agent attached.) doesn't use __() either, so this is consistent, but if/when this surface gets localized it's worth running these through @wordpress/i18n.
…respond-routing # Conflicts: # apps/cli/remote-session/telegram-client.ts # apps/cli/remote-session/tests/telegram-client.test.ts
Related issues
How AI was used in this PR
Used Claude Code to implement the flow described in the SPEC. Reviewed the diff manually, and tested end-to-end against a local daemon talking to mobile app through wpcom.
Proposed Changes
The Studio CLI's remote-session loop currently posts every reply to
/wpcom/v2/telegram-bot/local-agent-respondregardless of which client originated the message. That endpoint only knows how to forward to Telegram, so replies destined for the studio-mobile PoC client (polled withbot: "studio_mobile_<machine_id>") get rejected withrest_missing_callback_param. The wpcom side now exposes a parallel/wpcom/v2/studio-mobile-client/respondendpoint that accepts anagent_messageenvelope; this PR teaches the CLI to use it.respondMessage(): when the effectivebotstarts withstudio_mobile_, hit/wpcom/v2/studio-mobile-client/respond(derived by swapping the trailingtelegram-botsegment inbase_urlso dev hosts still resolve). Other bots keep using/local-agent-respondunchanged.{ chat_id, bot, machine_id, envelope: { type: "agent_message", id, text } }.chat_idandbotare the queue routing keys today;machine_idis forward-compat for when wpcom switches the queue key in Phase 2 of the SPEC;envelope.textis what the server reads instead of the old top-leveltextfield. Telegram path is unchanged.media.shareevent lands on astudio_mobile_*bot the photo bytes are dropped and the caption (or a placeholder) is promoted to the envelope text, with a warning logged. Telegram still gets the multipartsendPhotopath.Testing Instructions
npm run cli:build.export STUDIO_ENABLE_REMOTE_SESSION=truenode apps/cli/dist/cli/main.mjs code remote-session stop.node apps/cli/dist/cli/main.mjs code remote-session start.~/.studio/remote-session.logshould show a successfulPosting replyfollowed by noRespond 4xx.studio_mobile_*bot suffix). The reply should land in the mobile app, and the log should again show a successfulPosting replywith no 4xx.npm test -- apps/cli/remote-sessionto exercise the unit tests covering the routing and body shape.Pre-merge Checklist