fix(02): revise plans based on checker feedback
Address 3 blockers and 1 warning: - Clarify on_tool_use responsibility split (subprocess passes raw data, bot.py formats) - Make verify step 6 concrete with code inspection pattern - Add explicit subprocess auto-start pseudo-code with double-start guard - Reframe must_haves truth from implementation detail to capability Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
36fabb41a6
commit
92318e79ab
2 changed files with 26 additions and 5 deletions
|
|
@ -12,7 +12,7 @@ autonomous: true
|
|||
must_haves:
|
||||
truths:
|
||||
- "Persistent Claude Code subprocess accepts multiple messages without respawning"
|
||||
- "Stream-json events from Claude include tool_use events parseable for progress notifications"
|
||||
- "Subprocess emits tool_use events (tool_name + tool_input dict) that bot.py can consume for progress notifications"
|
||||
- "Long messages are split at smart boundaries without breaking MarkdownV2 code blocks"
|
||||
- "MarkdownV2 special characters are properly escaped before sending to Telegram"
|
||||
- "Typing indicator can be maintained for arbitrarily long operations via re-send loop"
|
||||
|
|
@ -86,6 +86,7 @@ Refactor ClaudeSubprocess to maintain a single long-lived process per session us
|
|||
3. **Add on_tool_use callback:** New callback `on_tool_use(tool_name: str, tool_input: dict)` for progress notifications.
|
||||
In `_handle_stdout_line()`, parse `content_block_start` events with `type: "tool_use"` to extract tool name and input.
|
||||
Stream-json emits these as separate events during assistant turns.
|
||||
**Responsibility split:** `claude_subprocess.py` extracts `tool_name` (e.g. "Read", "Bash", "Edit") and passes the raw `tool_input` dict (e.g. `{"file_path": "/foo/bar"}`, `{"command": "ls -la"}`) directly to the callback. It does NOT format human-readable descriptions -- that is bot.py's job in Plan 02 (Part B, item 5). This keeps the subprocess layer format-agnostic.
|
||||
|
||||
4. **Update _handle_stdout_line():** Handle the stream-json event types from persistent mode:
|
||||
- `assistant`: Extract text blocks, call on_output with final text
|
||||
|
|
@ -127,7 +128,7 @@ Refactor ClaudeSubprocess to maintain a single long-lived process per session us
|
|||
3. Verify on_tool_use callback parameter exists in __init__
|
||||
4. Verify --input-format stream-json appears in the command construction
|
||||
5. Verify stdin.write + drain pattern in send_message
|
||||
6. Verify stdout reader does NOT exit on result events (stays alive for persistent process)
|
||||
6. Verify `_read_stdout()` loop continues after result events: inspect code to confirm the loop only exits on empty readline (i.e. `line = await self._process.stdout.readline(); if not line: break`), NOT on receiving a result event. Result events should set `_busy = False` and call `on_complete` but NOT break the reader loop.
|
||||
</verify>
|
||||
<done>
|
||||
ClaudeSubprocess maintains a persistent process that accepts NDJSON messages on stdin, emits stream-json events on stdout, routes tool_use events to on_tool_use callback, and tracks busy state via result events instead of process completion. No fresh process spawned per turn.
|
||||
|
|
|
|||
|
|
@ -150,9 +150,29 @@ Overhaul the message handler to use typing indicators and message batching:
|
|||
- On message: `await batcher.add_message(text)` instead of direct `subprocess.send_message()`
|
||||
- Typing indicator starts immediately on first message, stops on Claude response
|
||||
|
||||
3. Subprocess auto-start:
|
||||
- When no subprocess exists for active session, create ClaudeSubprocess and call `await subprocess.start()`
|
||||
- Pass all 5 callbacks (on_output, on_error, on_complete, on_status, on_tool_use)
|
||||
3. Subprocess auto-start (integrate into existing handle_message after session lookup, before batcher):
|
||||
```python
|
||||
# In handle_message(), after resolving active session:
|
||||
session_id = session_manager.get_active_session(user_id)
|
||||
|
||||
# Get or create subprocess for this session (avoid double-start)
|
||||
if session_id not in self.subprocesses or not self.subprocesses[session_id].is_alive:
|
||||
callbacks = make_callbacks(bot, chat_id, stop_typing_event)
|
||||
subprocess = ClaudeSubprocess(
|
||||
session_dir=session_dir,
|
||||
on_output=callbacks['on_output'],
|
||||
on_error=callbacks['on_error'],
|
||||
on_complete=callbacks['on_complete'],
|
||||
on_status=callbacks['on_status'],
|
||||
on_tool_use=callbacks['on_tool_use'],
|
||||
)
|
||||
await subprocess.start()
|
||||
self.subprocesses[session_id] = subprocess
|
||||
else:
|
||||
subprocess = self.subprocesses[session_id]
|
||||
```
|
||||
- The `is_alive` check prevents double-start: only creates and starts if no subprocess exists for session or previous one died
|
||||
- `self.subprocesses` is a dict[str, ClaudeSubprocess] stored on the handler/application context (same pattern as existing subprocess tracking in bot.py)
|
||||
|
||||
**Part D: Update handle_photo() and handle_document()**
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue