Skip to content

Comments

feat: interactive questions via Telegram inline keyboards#67

Open
salemsayed wants to merge 1 commit intoTinyAGI:mainfrom
salemsayed:feat/interactive-questions
Open

feat: interactive questions via Telegram inline keyboards#67
salemsayed wants to merge 1 commit intoTinyAGI:mainfrom
salemsayed:feat/interactive-questions

Conversation

@salemsayed
Copy link
Contributor

Summary

  • Implements a question bridge that forwards Claude's clarifying questions to Telegram as inline keyboard buttons, enabling bidirectional interactive conversations in non-interactive (-p) mode
  • When Claude needs user input, it outputs structured [QUESTION] tags instead of using the disabled AskUserQuestion tool. The queue processor detects these, forwards to Telegram, waits for the user's button tap, then continues the conversation via --resume
  • Supports single-select, multi-select (with toggle + Done), and free-text "Other" responses

How it works

User sends message → Claude responds with [QUESTION] tag
  → Queue processor writes to queue/questions/
  → Telegram client renders inline keyboard
  → User taps button → answer written to queue/answers/
  → Queue processor reads answer, continues with --resume <sessionId>
  → Loop repeats until Claude stops asking questions

Screenshot

Telegram inline keyboard

Files changed

File Change
src/lib/question-bridge.ts New — parseQuestions, emitQuestion, pollForAnswer, writeAnswer, QUESTION_PROMPT
src/lib/types.ts Added QuestionData, AnswerData, InvokeResult interfaces
src/lib/config.ts Added QUEUE_QUESTIONS, QUEUE_ANSWERS paths
src/lib/invoke.ts Returns InvokeResult, adds --disallowed-tools, --append-system-prompt, --output-format json, --resume support
src/queue-processor.ts Question detection loop after invokeAgent(), heartbeat TTL refresh
src/channels/telegram-client.ts Inline keyboard builder, callback_query handler, questions queue watcher, free-text mode, multi-select

Key design decisions

  • File-based IPC (not sockets) — matches tinyclaw's existing queue architecture
  • wx flag on answer writes prevents duplicate answers from double-taps
  • Session ID capture via --output-format json on first call, then --resume <sessionId> for continuations
  • Heartbeat files refresh pending message TTL during long question loops (prevents 10-min timeout)
  • Graceful degradation — if Claude doesn't use [QUESTION] tags, response flows through as normal text
  • Telegram-only — interactive mode only activates for the Telegram channel (which supports inline keyboards)

Test plan

  • Build compiles cleanly (npm run build:main)
  • Claude outputs [QUESTION] tags with the stronger system prompt
  • Inline keyboard renders in Telegram with tappable buttons
  • Button tap writes answer and continues conversation
  • Multi-turn question loops work (tested 4+ rounds)
  • "Other" button triggers free-text mode
  • Duplicate tap protection (wx flag)
  • Timeout fallback (5-min per question)
  • Multi-select toggle + Done

🤖 Generated with Claude Code

- Add question-bridge module for Claude's AskUserQuestion → Telegram inline
  keyboard flow with poll-based answer retrieval
- Add configurable timeout (max_response_time) to agent invocations with
  SIGTERM→SIGKILL escalation to prevent hung sessions
- Strip CLAUDECODE env var from spawned processes to avoid nested session errors
- Deliver partial text before [QUESTION] tags as separate messages
- Add heartbeat handler to refresh pending message TTL during long processing
- Add proactive/agent-initiated messaging via senderId for direct delivery
- Improve error handling with 4xx permanent error detection in telegram client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@salemsayed salemsayed force-pushed the feat/interactive-questions branch from e40cad2 to c09142a Compare February 15, 2026 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant