MoonshotAI / MoonshotAI/kimi-cli

[Bug] Background subagent keeps making LLM calls after TaskStop/timeout marks it terminal

Open
#2,615 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
11.4k
Forks
1.3k
Avg merge
9h 47m
Merged PRs (30d)
2

Description

TL;DR

A background subagent can continue making LLM requests after its task and subagent metadata have already been marked timed_out or killed. The task disappears from active-task tracking, so the continued quota consumption is invisible and TaskStop can no longer stop it; terminating the entire Kimi CLI process was the only effective workaround.

Problem description

This is a task-lifecycle inconsistency with direct quota impact. A background agent reached its configured 900-second timeout and a subsequent stop request marked the related task/subagent as terminal. Despite those terminal states, the underlying subagent continued its model/tool loop for about 26 more minutes.

Because the task was no longer considered active, the UI and task manager gave no indication that model calls were continuing. The affected CLI process retained an established HTTPS connection, and the subagent wire/context files continued growing until the parent Kimi CLI process was terminated.

Current behavior

  • A background agent timeout records status="failed", timed_out=true, and a terminal finished_at.
  • A stop request records status="killed" for the task/subagent.
  • The underlying subagent can nevertheless continue emitting StepBegin, completing LLM steps, invoking tools, and updating its wire/context files.
  • Once persisted state is terminal, another TaskStop returns without reaching the still-running nested task.
  • The hidden activity stops only when the entire Kimi CLI process exits.

Expected behavior

When a background subagent times out or is stopped, no model request, tool invocation, or session-file write belonging to that execution should continue after shutdown completes. A terminal task status should accurately mean that the underlying execution has terminated, and the task should remain controllable while any execution associated with it is still alive.

Impact

  • Invisible subscription quota consumption after the user has been told the task stopped.
  • No in-product way to discover or stop the detached execution.
  • Potentially large impact for long-context agents and parallel subagent workflows.

In the observed incident, after the related task/subagent metadata had reached terminal states by 01:31:01 UTC, the same session logged another 137 completed LLM steps, approximately 15,431,930 input tokens, and 105,982 output tokens through 01:57:51 UTC. These are CLI-reported token counts; provider-side metering may account for caching differently.

Environment

  • kimi-cli: 1.49.0
  • Build commit: 4a550effdfcb29a25a5d325bf935296cc50cd417
  • Python: 3.13
  • OS: Linux
  • Surface: interactive Kimi Code CLI launched from a VS Code terminal
  • Subscription/provider: Kimi Code managed provider

Trigger / reproduction

  1. Start a background coder subagent with a finite timeout (the observed case used 900 seconds).
  2. Let the task reach its timeout, or invoke TaskStop while the subagent is actively waiting on/running an LLM step.
  3. Confirm that task runtime and subagent metadata report timed_out, failed, or killed.
  4. Continue observing the Kimi log and the subagent's wire.jsonl/context.jsonl mtimes.
  5. Observe additional StepBegin and LLM step completed events after the terminal timestamp.
  6. Invoke stop again and observe that terminal-state handling does not reach the continuing execution.
  7. Terminate the parent Kimi CLI process; file growth and network activity then stop.

Sanitized evidence timeline

UTC time Observation
01:30:00 Background agent task recorded timed_out=true after 900 seconds
01:31:01 Related task/subagent recorded killed
01:54:42 Further LLM step completed despite terminal state
01:56:15 Another 92.9-second LLM step completed (input=148792)
01:57:16 Another LLM step completed (input=155242)
01:57:51 Last observed LLM step completed (input=158137)
01:57:56 Parent Kimi CLI process terminated; log/wire growth and HTTPS activity stopped

No credentials, prompts, project paths, or private source content are included in this report.

Code-path evidence

The observed behavior aligns with the following lifecycle boundary at the reported build:

Location Current behavior
src/kimi_cli/soul/__init__.py:209-218 Creates the nested soul_task, then awaits asyncio.wait(...) before entering the lifecycle try/finally below
src/kimi_cli/soul/__init__.py:220-247 Cancellation and wire/UI cleanup begin only after the preceding await returns
src/kimi_cli/background/agent_runner.py:74-100 Outer timeout/cancellation records terminal task and subagent states
src/kimi_cli/background/agent_runner.py:115-132 Removes the outer task from _live_agent_tasks during cleanup
src/kimi_cli/background/manager.py:371-390 kill() returns immediately for persisted terminal states and otherwise cancels only the tracked outer task

If outer cancellation lands while run_soul() is suspended at the pre-try asyncio.wait(...), the nested soul_task is not covered by the cleanup block. The outer runner can then record a terminal state and unregister itself while the nested task remains scheduled. This is consistent with the terminal metadata plus continued wire/log writes observed above.

Acceptance criteria

  • After either timeout or TaskStop, no LLM step or tool call from that background execution completes beyond a bounded shutdown grace period.
  • Subagent wire/context files stop changing once the task reports a terminal state.
  • A task is not removed from active control while execution associated with it is still running.
  • Repeated stop attempts are not required to terminate a background subagent.
  • Regression coverage exercises cancellation while the subagent is suspended in its initial run wait for both timeout and explicit TaskStop paths.

Related issues checked

  • #2232 concerns adjusting background-task timeout duration, not post-timeout execution.
  • #2578 concerns checkpointing/resume after quota errors or timeout, not an execution continuing after terminal state.
  • #2438 concerns subagent observability, but does not report a terminal task continuing model calls.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read the lifecycle around src/kimi_cli/soul/init.py:209-247, then trace cancellation and cleanup through src/kimi_cli/background/agent_runner.py:74-132 and src/kimi_cli/background/manager.py:371-390. Reproduce timeout and TaskStop cancellation while the initial run wait is suspended, then add regression coverage showing that nested execution, LLM/tool activity, file updates, and active control all stop within the shutdown grace period.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.