Conversation
|
Code review note: one issue before merge. The PR did come from Orion's branch ( Blocking issue: Please tighten the fallback regex so it only suppresses known progress-only lines, e.g. exact/punctuation-only Everything else looks sound: subscribing to |
Mirrors CI's three checks (ruff check, ruff format --check, pytest) so lint-only failures like PR #70's channel.py format miss get caught locally before push. Pytest runs at pre-push stage to keep everyday commits fast. Setup now: pip install pre-commit pre-commit install --install-hooks # installs both pre-commit and pre-push Verified: ruff check, ruff format, pytest tests/ all pass via `pre-commit run --all-files` and `... --hook-stage pre-push`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…unks
Restores two behaviors from the original TypeScript ax-channel bridge
that regressed when it was ported to Python `axctl channel`:
1. Subscribe to `message_updated` SSE events in addition to `message` /
`mention`. Hermes-runtime sentinels seed a placeholder message
("Working…") on reply start and overwrite the same message_id
in place as the final reply streams in. Without `message_updated`
the bridge saw only the placeholder creation and never the real
text, so sessions had to manually fetch replies via API.
2. Filter progress/chunk payloads so every "Working…" / "Received" /
streaming placeholder stops waking the Claude Code session. Two
signals used in order:
- Structured: `metadata.streaming_reply.final` is explicitly `false`
(runtime tells us this is a placeholder it will overwrite).
- Defensive: first-line content matches known progress patterns,
anchored with `\Z` so the entire line must be progress-only —
"Working…" is dropped but "Working-state cleanup proposal" is
delivered normally. Covers: Working, Received, Thinking,
Processing (with only trailing whitespace / dots / ellipses) and
"No response after <N>[smh] ..." (runtime-emitted timeout form).
Seen-dedup semantics:
- New messages: skip if id already delivered (unchanged).
- message_updated: skip if id already delivered, otherwise deliver the
final payload (so placeholder -> final round-trips work).
- Skipped progress chunks are NOT added to seen_ids, so the subsequent
final update for the same id still delivers.
Also fixes the leading-mention strip regex to handle hyphens in agent
handles (e.g. `peer-agent`); the previous `^@\w+` stopped at the first
hyphen and left stray text that defeated the progress filter.
Tests (tests/test_channel.py):
- test_channel_skips_streaming_reply_non_final — structured filter
- test_channel_skips_working_progress_message — Working / Received /
Thinking / No-response-after-5m all dropped
- test_channel_delivers_prompts_that_merely_start_with_progress_words —
"Working-state cleanup proposal" lands (regression for over-broad
regex caught in review)
- test_channel_delivers_processing_webhook_errors_prompt
- test_channel_delivers_thinking_through_issue_prompt
- test_channel_delivers_message_updated_final — placeholder -> final
round-trip
- test_channel_skips_message_updated_for_already_delivered — dup final
updates don't re-wake
Verified: pytest tests/test_channel.py -> 20 passed.
ruff check + ruff format --check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7961b23 to
542c040
Compare
Summary
Restores two ax-channel bridge behaviors that regressed when the TypeScript bridge was ported to Python
axctl channel.Root cause
messageandmentionSSE events;message_updatedwas dropped. Hermes-runtime sentinels seed a placeholder message ("Working…") on reply start and overwrite the samemessage_idin place as the real reply streams in. Withoutmessage_updated, the bridge saw the placeholder creation and nothing else."Working…"/"Received"/ streaming placeholder woke the Claude Code session.Net effect: sessions got constant chatter from sentinels but never saw the actual replies without manually fetching via
GET /api/v1/messages/{id}.Fix
message_updatedin addition tomessage/mention.message_updatedto bypass seen-dedup only when the id has NOT been delivered yet (so final streaming updates supersede the placeholder but can't re-wake after delivery).metadata.streaming_reply.finalis explicitlyfalse(structured runtime signal).\Z: drop payloads whose first line (after stripping any leading@mention) is entirely progress-only —Working…/Received/Thinking.../Processing…with only trailing whitespace / dots / ellipses, orNo response after <N>[smh] .... Prompts that merely start with those words like"Working-state cleanup proposal"are NOT dropped.seen_idsso the subsequent final update for the same id still delivers.Tests
Seven targeted tests in
tests/test_channel.py:test_channel_skips_streaming_reply_non_final— structuredmetadata.streaming_reply.final=falsefilter.test_channel_skips_working_progress_message— defensive regex catchesWorking…/Received/Thinking.../No response after 5m ....test_channel_delivers_prompts_that_merely_start_with_progress_words—"Working-state cleanup proposal"still lands (regression for over-broad regex caught in review).test_channel_delivers_processing_webhook_errors_prompttest_channel_delivers_thinking_through_issue_prompttest_channel_delivers_message_updated_final— placeholder → final update round-trip delivers the real content.test_channel_skips_message_updated_for_already_delivered— duplicate finals don't re-wake.All 20 channel tests pass.
ruff checkandruff format --checkclean. Full test suite: 224 passed.Test plan