feat(runtime): expose typing-indicator control for runtime-token agents#298
Closed
feat(runtime): expose typing-indicator control for runtime-token agents#298
Conversation
Adds POST /api/agents/runtime/pods/:podId/typing — runtime-token agents
can now emit agent_typing_start / agent_typing_stop, getting the same
conversational chrome as native cloud agents.
Body: { action: 'start' | 'stop' } (defaults to 'start')
Why this exists
---------------
Internal callers (nativeRuntimeService, agentEventService) auto-emit
typing_start when they enter the agent loop and typing_stop on message
land. agentMessageService emits typing_stop when an external agent's
POST /messages lands — but never typing_start. Net effect: external
agent messages appear in chat instantly with no '…' pre-roll, while
native ones get the expected conversational fade-in.
This route closes that gap. CLI wrappers (ADR-005), webhook bots
(ADR-006), and demo drivers can now POST {action:'start'} ~1s before
their content message and the message lands with proper chat chrome.
Safety
------
- 30s auto-clear in agentTypingService prevents stuck indicators if a
caller forgets stop or crashes between start and message land
- Existing agentMessageService.postMessage emits typing_stop on land,
so callers can fire-and-forget the start (the message itself stops
the indicator)
- Same auth (agentRuntimeAuth) + pod authorization as POST /messages
- Same rate-limit (phase4RateLimit)
Identity
--------
displayName + avatar resolved via AgentIdentityService.getOrCreateAgentUser
the same way agentEventService does — User.botMetadata.displayName wins
over installation.displayName, falls back to agentName.
Driver pattern
--------------
send_with_typing(podId, agent, msg) {
POST /pods/$podId/typing {action: 'start'}
sleep 1.2s
POST /pods/$podId/messages {content: msg} // auto-emits typing_stop
}
samxu01
added a commit
that referenced
this pull request
May 4, 2026
…ts (#298) Adds POST /api/agents/runtime/pods/:podId/typing — runtime-token agents get the same conversational chrome as native cloud agents. Body: { action: 'start' | 'stop' } agentMessageService.postMessage already emits typing_stop on message land, so the pattern is: POST /typing {start} → sleep ~1.2s → POST /messages. 30s auto-clear in agentTypingService prevents stuck indicators if a caller crashes between start and message land. Same auth + pod authorization + rate limit as POST /messages. Identity resolution mirrors agentEventService — User.botMetadata.displayName + User.profilePicture for the typing payload. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
POST /api/agents/runtime/pods/:podId/typing— runtime-token agents (CLI wrappers, webhook bots, external SDK clients) can now emitagent_typing_start/agent_typing_stopover Socket.io, getting the same conversational chrome as native cloud agents.Body:
{ action: 'start' | 'stop' }(defaults to'start')Why this exists
nativeRuntimeServiceandagentEventServicealready emit typing_start when they enter the agent loop, and the existingPOST /messageshandler emits typing_stop on message land viaagentMessageService.postMessage. But there's no symmetric typing_start hook for external agents — so their messages appear instantly with no '…' pre-roll while native ones get the expected fade-in.This route closes that gap. With it, an external agent (CLI-wrapped or webhook) can:
```
POST /pods//typing {action: 'start'} # show the typing indicator
sleep 1.2s
POST /pods//messages {content: '...'} # auto-emits typing_stop on land
```
Safety
agentRuntimeAuth) and pod authorization (ensurePodMatch) as the existingPOST /messageshandler.phase4RateLimit).agentTypingServiceprevents stuck indicators if a caller forgets to call stop or crashes between start and message land.agentMessageService.postMessageemits typing_stop on every message land — so the typical pattern is fire-and-forget the start; the message itself stops the indicator.Identity resolution
displayName + avatar are resolved via
AgentIdentityService.getOrCreateAgentUser— same chainagentEventServiceuses.User.botMetadata.displayNamewins overinstallation.displayName, falls back toagentName. avatar comes fromUser.profilePicture.Test plan
tsc --noEmitcleancurl -X POST .../pods/<id>/typingfrom a CLI-wrapped agent emitsagent_typing_startover WS; subsequentPOST /messagesclears it🤖 Generated with Claude Code