Skip to content

feat(gastown): parse H1 headers from agent output as automatic status updates#1374

Merged
jrf0110 merged 2 commits intoconvoy/parse-agent-status-from-h1-headers-repla/52d188d7/headfrom
convoy/parse-agent-status-from-h1-headers-repla/52d188d7/gt/maple/f0ad7dff
Mar 23, 2026
Merged

feat(gastown): parse H1 headers from agent output as automatic status updates#1374
jrf0110 merged 2 commits intoconvoy/parse-agent-status-from-h1-headers-repla/52d188d7/headfrom
convoy/parse-agent-status-from-h1-headers-repla/52d188d7/gt/maple/f0ad7dff

Conversation

@jrf0110
Copy link
Contributor

@jrf0110 jrf0110 commented Mar 21, 2026

Summary

Parse markdown H1 headers from message.part.updated / message_part.updated events in broadcastEvent() and post them to the agent status API. This provides dashboard visibility into what agents are doing without requiring explicit gt_status tool calls — agents just write naturally with H1 headers at phase transitions.

Key implementation details:

  • Uses last H1 match when multiple exist in a single text part (most current status)
  • Deduplicates via module-level lastStatusForAgent Map to avoid redundant API calls
  • Truncates status text to 120 characters
  • Cleans up lastStatusForAgent entries at all agent exit paths: exitAgent(), stream error handler, stopAgent(), and stopAll()
  • Auth follows the same container-token/session-token pattern as event persistence

Refs: #1307

Verification

  • Typecheck passes (reported by author)
  • Lint passes (reported by author)
  • Format passes (reported by author)
  • Code review: correctness, security, cleanup paths all verified

Visual Changes

N/A

Reviewer Notes

  • The auth token resolution + header construction (lines 173-186) duplicates the pattern from the event persistence block above (lines 117-131). This is a minor code smell but acceptable given the localized scope. A future cleanup could extract a shared helper.
  • The agents.get(agentId) call at line 173 (agentMeta) is redundant since agent was already fetched at line 114 and is still in scope. Not a bug, but a minor inefficiency.
  • The H1 regex (?:^|\n)# (.+) could theoretically match code comments (e.g., Python #) in code blocks, but false positives would just produce a slightly wrong status update — low severity and self-correcting.
  • No new tests added; the container's process-manager.ts has no existing test infrastructure to extend.

… updates

Parse markdown H1 headers from message.part.updated events in
broadcastEvent() and post them to the agent status API. This provides
dashboard visibility into agent activity without requiring agents to
call gt_status explicitly.

- Uses last H1 match (most current) when multiple exist in one text part
- Deduplicates via lastStatusForAgent Map to avoid redundant API calls
- Truncates status to 120 characters
- Cleans up lastStatusForAgent on agent exit/stop/failure/shutdown

Refs: #1307
@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 21, 2026

Code Review Summary

Status: 1 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
cloudflare-gastown/container/src/process-manager.ts 169 Requiring a trailing newline fixes partial-stream spam, but it also drops valid H1 headings that end the text part without a final newline.
Other Observations (not in diff)

None.

Files Reviewed (1 files)
  • cloudflare-gastown/container/src/process-manager.ts - 1 issue

Reviewed by gpt-5.4-20260305 · 306,482 tokens

…rtial matches

The H1 regex was matching incomplete headings during streaming, causing
dozens of /status writes per heading as each token delta produced a
different partial match. Adding a trailing newline requirement ensures
status is only posted once the heading line is fully streamed.
// Require a trailing newline so we only match completed headings; without it,
// every streaming delta would match the partial heading being typed and spam
// the /status endpoint with incremental fragments.
const matches = [...part.text.matchAll(/(?:^|\n)# (.+)\n/g)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: This skips headings that end the text part

Requiring \n means # Done only matches if another line arrives afterward. Since this branch only runs on message.part.updated, an H1 that is the final line of the streamed text never reaches /status, so the dashboard can miss the agent's latest phase. Consider flushing the final heading on a completion event (or another signal that the text part is finished) instead of making newline the only terminator.

@jrf0110 jrf0110 merged commit efbf99a into convoy/parse-agent-status-from-h1-headers-repla/52d188d7/head Mar 23, 2026
2 checks passed
@jrf0110 jrf0110 deleted the convoy/parse-agent-status-from-h1-headers-repla/52d188d7/gt/maple/f0ad7dff branch March 23, 2026 15:44
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