feat: 中断 router 分发(✖ on thinking chip)#107
Merged
Merged
Conversation
Adds a stable, observable mechanism to cancel an in-flight agent turn:
- New STATUS_PHASES value 'cancelled'; chips can transition from
thinking|running → cancelled via the new endpoint.
- POST /api/threads/<tid>/posts/<chip_id>/cancel
* idempotent (already-cancelled → 200; terminal phases → 409 already_completed)
* patches chip phase to 'cancelled'
* marks chip in post_router._cancelled_chips so a late agent reply
is silently dropped at the router boundary (router is single
source of truth for what lands in the thread)
* best-effort SIGTERMs the bound subprocess group for both native
openclaw agent and ACP CLI employees
* posts a __router__ audit line so the thread explains itself
- agent_runtime.cancel_chip_subprocess + acp_runtime.cancel_acp_chip_subprocess
expose chip_id → pgid maps for the endpoint to nudge the right group.
- Worker (post_router._route_to_agent) checks is_cancelled() in two
spots: on AgentError (so a SIGTERM-induced non-zero exit becomes
'cancelled' instead of 'failed') and after a successful reply (late
cancel drops the reply).
- ACP runtime switched from subprocess.run → Popen+communicate so the
cancel path can SIGTERM the pgid; old timeout/failure semantics preserved.
UI (per @designer spec):
- ✖ button on thinking/running chips. Default opacity .45, hover full
opacity + --danger color, 28×28 hit area (visual 16×16 with transparent
padding), no confirm dialog. Touch (hover:none) keeps opacity 1.
- 'cancelled' phase renders as a low-key ⛔ pill, --text-soft only.
- Optimistic UI: click flips chip to 'cancelled' instantly with a brief
strike-through animation; SSE/refresh reconciles. 409 path rolls back.
- All colors via CSS tokens (--danger / --text-soft); no hex (PR #105
activity-chip lesson).
Tests:
- 3 new tests in tests/test_status_chip.py covering the happy path,
idempotency, and terminal-phase rejection.
- tests/test_acp_runtime.py updated to fake Popen instead of run.
🤖 bot-review (comment-only · phase 1)Diff: Red-line checks:
Needs human review — these paths are not eligible for future auto-approve:
Phase 2: auto-approve + auto-merge fire only when red-lines are clean, author is internal, and no needs-human path is touched. Block with |
Two fixes from blind read-through (light OK, dark weak): 1. asc-cancelling strike-through invisible in dark. Old: text-decoration: line-through; opacity: .7 on already --text-soft text — the strike was lighter than the text. Lost the 'click landed' feedback that the optimistic 0ms morph depends on. New: animation pulls .asc-phase color up to var(--text) + 2px strike-thickness for ~600ms, then eases back to --text-soft so the final cancelled pill still rests at low-key gravity. 2. asc-cancel:hover background looked 'swallowed' in dark. Old: --danger-soft (#3A1818) is too close to the deep bg; the red circle had hue but no punch. New: --danger-soft-strong token (rgba(.., .22) in dark, .16 in light) used only by the hover circle. Light/dark each get their own value so the red 'lifts' off the surface uniformly. Both fixes go through tokens — zero hex literals in component CSS.
SymbolStar
added a commit
that referenced
this pull request
Jun 26, 2026
main 上残留的 ruff lint 失败(PR #107 引入),在本 PR 里顺手清掉,让 CI 绿。
github-actions Bot
pushed a commit
that referenced
this pull request
Jun 26, 2026
* fix(branding): dock F 再缩一档 (0.82 → 0.78) Scott 反馈 macOS dock 里 F 仍偏大。把 inner content scale 从 0.82 降到 0.78(约 -5%),translate 同步重算保持视觉居中。 dock 圆角遮罩下留白更舒服,缩到 32/48 也仍有识别度。 - logo-forge-f.svg / -inverse.svg: scale 0.82 → 0.78 - regen 32/48/256 PNGs * chore(lint): ruff I001 auto-fix on acp_runtime + test_status_chip main 上残留的 ruff lint 失败(PR #107 引入),在本 PR 里顺手清掉,让 CI 绿。
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.
背景
Scott 在 thread feature-中断 router 得分发 提的需求:思考中能 ✖ 取消。@designer 给了 UI spec。
后端
cancelled,新 endpointPOST /api/threads/<tid>/posts/<chip>/cancel_cancelled_chips,worker 落回复前 check,late reply 直接丢弃,hung agent 永远污染不了 threadalready_completed)__router__post(⛔ 的本轮回复已被中断)subprocess.run换成Popen + communicate,这样能 SIGTERM pgidUI(按 @designer 的 spec)
--danger色 + 圆形 hover 背景hover: none) opacity 1 常驻cancelled(带 strike-through 过渡),不等 APIcancelled用--text-soft⛔ pill,禁止 hex(参考 PR fix(web/style): activity-chip hover/disabled use theme vars (dark mode) #105)测试
3 个新 endpoint 测试(成功 / 幂等 / 409 terminal)+ ACP runtime 测试 migrate 到 Popen。
pytest tests/全绿(556 tests)。cc @designer 完了麻烦盲读验收一次(dark/light × 1280/1024)。