Skip to content

Comments

feat: stream tool activity to Telegram in real time#113

Open
williamlmao wants to merge 1 commit intoTinyAGI:mainfrom
williamlmao:feat/telegram-activity-streaming
Open

feat: stream tool activity to Telegram in real time#113
williamlmao wants to merge 1 commit intoTinyAGI:mainfrom
williamlmao:feat/telegram-activity-streaming

Conversation

@williamlmao
Copy link

Summary

  • When an agent uses tools (Read, Write, Bash, Grep, etc.), Telegram users now see live updates like "Read /src/index.ts" and "Ran npm test" as the agent works, instead of waiting silently for the final response
  • Claude CLI is invoked with --output-format stream-json and stdout is parsed line-by-line in real time to detect tool_use events
  • Activity summaries are sent as partial responses to the Telegram outgoing queue, which the Telegram client delivers immediately while keeping the conversation pending until the final response arrives

Changes

src/lib/invoke.ts (main change)

  • Added runClaudeCommand() which spawns the Claude CLI and streams JSONL events in real time
  • Added summarizeToolUse() to turn raw tool calls into readable strings (e.g. Read /src/index.ts, Ran npm test, Searched for "handleClick")
  • Added processClaudeEvent() to parse streaming events and detect tool_use/tool_result blocks
  • invokeAgent() now accepts an onActivity callback, returns AgentInvokeResult (text + sessionId) instead of a plain string
  • Session ID extraction from streaming events for conversation continuity

src/queue-processor.ts

  • Added writeResponse() helper that supports partial, updateType, and sessionId fields
  • Added activityEmitterForAgent() — creates a callback that writes partial activity responses to the outgoing queue when tools fire
  • Activity streaming is enabled for Telegram channel messages (streamActivitiesEnabled = channel === 'telegram')

src/channels/telegram-client.ts

  • ResponseData interface extended with sessionId, partial, updateType
  • Outgoing queue files are now sorted for consistent ordering
  • Partial (activity) responses are sent immediately but do not clear pending state — only the final response does
  • Session ID appended to final responses

src/lib/types.ts

  • ResponseData: added sessionId?, partial?, updateType? fields
  • ChainStep: added sessionId? field

Test plan

  • Send a message to the Telegram bot that triggers tool use (e.g. ask the agent to read a file or run a command)
  • Verify that activity messages appear in Telegram as tools are called (e.g. "Read /path/to/file")
  • Verify the final response still arrives normally after activities
  • Verify non-Telegram channels (Discord, WhatsApp) continue to work without activity streaming
  • Verify team chain conversations still work with activity streaming enabled

🤖 Generated with Claude Code

When an agent uses tools (Read, Write, Bash, Grep, etc.), Telegram users
now see live updates like "Read /src/index.ts" and "Ran npm test" as the
agent works, instead of waiting silently for the final response.

How it works:
- invoke.ts: Claude CLI now runs with --output-format stream-json and
  streams stdout line-by-line. Each tool_use event is parsed into a
  human-readable summary via summarizeToolUse(), and an onActivity
  callback fires immediately.
- queue-processor.ts: For Telegram messages, an activity emitter writes
  partial responses (partial: true, updateType: 'activity') to the
  outgoing queue as tools are called.
- telegram-client.ts: Partial responses are sent immediately but keep
  the message in pending state. Only the final response clears pending.
- types.ts: ResponseData gains sessionId, partial, and updateType fields.

Also extracts Claude session IDs from streaming events for conversation
continuity tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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