fix(background): stream agent task output in real-time and remove completion watcher#1576
fix(background): stream agent task output in real-time and remove completion watcher#1576
Conversation
… for real-time updates
There was a problem hiding this comment.
Pull request overview
This PR fixes live visibility of background agent task output by streaming subagent transcript writes into the task’s output.log in real time (instead of copying after completion), and routes output readers through BackgroundTaskManager APIs.
Changes:
- Tee subagent transcript writes to the background task
output.logduring execution (removes the post-completion copy step). - Add/consume
BackgroundTaskManager.resolve_output_path()and switch UI/notifications/tools to use manager output APIs for reading. - Update background tool tests to reflect that running agent tasks now populate
output.loglive.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/tools/test_background_tools.py | Updates expectations/docstring for live agent task output now being in output.log. |
| src/kimi_cli/ui/shell/task_browser.py | Reads output path via BackgroundTaskManager instead of the store directly. |
| src/kimi_cli/tools/background/init.py | Removes subagent-output fallback logic; reads output through manager APIs and uses canonical task output path. |
| src/kimi_cli/subagents/output.py | Extends SubagentOutputWriter to tee writes to additional output files. |
| src/kimi_cli/notifications/llm.py | Switches task notification tailing to BackgroundTaskManager.tail_output(). |
| src/kimi_cli/background/manager.py | Introduces resolve_output_path() and exposes read/tail output APIs used by consumers. |
| src/kimi_cli/background/agent_runner.py | Uses SubagentOutputWriter.extra_paths to stream into output.log; removes completion-time copy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| output_path = manager.resolve_output_path(task_id) | ||
| try: | ||
| output_size = output_path.stat().st_size | ||
| output_size = output_path.stat().st_size if output_path.exists() else 0 | ||
| except OSError: | ||
| output_size = 0 | ||
| preview_offset = max(0, output_size - TASK_OUTPUT_PREVIEW_BYTES) | ||
| chunk = self._runtime.background_tasks.store.read_output( | ||
| chunk = manager.read_output( | ||
| task_id, | ||
| preview_offset, | ||
| TASK_OUTPUT_PREVIEW_BYTES, | ||
| status=status, | ||
| path_override=output_path, | ||
| offset=preview_offset, | ||
| max_bytes=TASK_OUTPUT_PREVIEW_BYTES, | ||
| ) | ||
| preview_bytes = chunk.next_offset - chunk.offset | ||
| preview_text = chunk.text.rstrip("\n") | ||
| preview_truncated = preview_offset > 0 | ||
| return ( | ||
| preview_text, | ||
| output_available, | ||
| chunk.text.rstrip("\n"), | ||
| output_size > 0, | ||
| output_size, |
There was a problem hiding this comment.
full_output_available is derived from output_size > 0, which makes the tool report that no output is available even when output.log exists but is currently empty (common for running tasks) and can also become stale if the file grows between the stat and the read. Consider basing full_output_available on output_path.exists() (and optionally keeping a separate has_output_bytes/output_size_bytes signal) so the ReadFile hint and metadata remain accurate.
| @pytest.mark.asyncio | ||
| async def test_task_output_reads_live_subagent_output_while_running(runtime, task_output_tool): | ||
| """While an agent task is running, TaskOutput should read from the subagent's | ||
| live output file, not the empty task output.log.""" | ||
| """While an agent task is running, TaskOutput should read real-time output | ||
| from task output.log (tee'd by the agent runner).""" |
There was a problem hiding this comment.
The test name still says it reads “live subagent output”, but the updated docstring/fixture data indicate it now reads real-time output from the task’s output.log. Renaming the test (and the nearby section header, if kept) would reduce confusion about the current expected behavior.
Signed-off-by: Kai <me@kaiyi.cool>
Summary
output.login real-timevia
SubagentOutputWriter.extra_paths, replacing thepost-completion file copy. This fixes
/taskbrowser andTaskOutputtool showing empty output for running agent tasks.notifications) to read through
BackgroundTaskManagerAPIsinstead of accessing the store directly.
Checklist
make gen-changelogto update the changelog.make gen-docsto update the user documentation.