userQuestions: single global provider without timeout hangs non-web channels (WeChat/Telegram gateways) forever #2544
Replies: 1 comment
|
Verified every claim against master (47f9438) — your analysis is accurate, and this is the interaction-seam sibling of an unbounded-wait family I've been tracking (#1607, 1. All three claims confirm at source. The provider registers unconditionally ( 2. Precision on the approval contrast — it's fail-closed fallthrough, not a timeout. The approval seam doesn't have a "default-deny timeout" either; it has an answerer chain with a fail-closed default: when no handler claims the request the chain calls 3. The key design point: distinguish "no listener" from "listener hasn't answered". A hard 4. Your suggestion 3 (question event) matches the in-repo precedent exactly. 5. Family note. This is the second confirmed instance of the "promise that never settles while the listener is absent" class: #1607 ( Your scoped-shadowing workaround is a nice illustration that the architecture is right even where the capability is missing — worth keeping in the thread as the community reference implementation. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
ask_user_questionhangs indefinitely when the agent is driven from a non-web channel (e.g. a WeChat/Telegram gateway) because:dsh-host-apiproxyregisters the onlyuserQuestionsprovider unconditionally at startup (registerProviderrejects a second one withDUPLICATE_PROVIDER).ask()pushes the question into the browser RPC queue with no timeout and no offline detection — if no browser is connected, the queue is never consumed and the tool call never settles.Repro
dsh web(host only, no browser connected).ask_user_question→ tool hangs until the agent turn is manually cancelled.Workaround we shipped
We built a WeChat gateway plugin (dsh-chatnode-wechat) that works around this by scoped-shadowing
ask_user_question(registering a same-name tool on the agent's scoped ctx — documented indocs/subsystems/tools.md: "Scoped tools shadow globals") and broadcasting the question to both the web UI (viactx.userQuestions.ask()) and the WeChat text channel, first answer wins, WeChat lane times out after 10 minutes. It works, but it is a large workaround for what looks like a core capability gap.Suggested improvements (any subset would help)
userQuestionsprovider (e.g. matched byrequest.agent) instead of a global singleton.ask()is invoked (likeapproval/requestalready does), so external channels can forward the question to the user and answer it — this is the patternapproval/requestestablishes anduserQuestionscurrently lacks.Context
docs/subsystems/user-questions.md("Only one provider may be active in a context")approval/request→ forward → reply → resolve, with a default-deny timeout.userQuestionshas no equivalent event or timeout.Thanks for the great plugin architecture — the scoped-shadow escape hatch made the workaround possible without touching core.
All reactions