-
Notifications
You must be signed in to change notification settings - Fork 973
fix(soul): keep agent loop alive while background tasks are running #1802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
aa8cb76
47cb48e
0f06bef
21097db
a6a4e5d
8e09783
6072f8d
a3885c2
60870da
91220f8
1077e9c
3874c64
e0b5814
1a44ccc
a45e8e8
742088e
ce1020b
a2da914
3586234
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,6 +96,64 @@ def _handler(): | |
| runtime.session.wire_file if runtime else None, | ||
| runtime, | ||
| ) | ||
|
|
||
| # In one-shot text mode the process exits after this | ||
| # function returns, which would kill still-running | ||
| # background agents. Poll until they finish, calling | ||
| # reconcile() each iteration (the notification pump | ||
| # inside run_soul is no longer running, so we must | ||
| # drive reconcile ourselves to recover lost workers | ||
| # and publish terminal notifications). Only re-enter | ||
| # the soul when there are pending LLM notifications. | ||
| # | ||
| # stream-json mode is multi-turn: background tasks | ||
| # from one command must not block the next command. | ||
| if runtime and runtime.role == "root" and self.input_format == "text": | ||
| manager = runtime.background_tasks | ||
| notifications = runtime.notifications | ||
| while not cancel_event.is_set(): | ||
| # Drive reconcile() ourselves: the notification | ||
| # pump inside run_soul is no longer running, so | ||
| # we must recover lost workers and publish | ||
| # terminal notifications here. | ||
| manager.reconcile() | ||
| if notifications.has_pending_for_sink("llm"): | ||
| # Re-enter soul so the LLM can process the | ||
| # completion notification. Do this even if | ||
| # other tasks are still active — progress on | ||
| # completed tasks should not wait on siblings. | ||
| bg_prompt = ( | ||
| "<system-reminder>" | ||
| "Background tasks have completed." | ||
| " Process their results." | ||
| "</system-reminder>" | ||
| ) | ||
| await run_soul( | ||
| self.soul, | ||
| bg_prompt, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This branch re-enters Useful? React with 👍 / 👎. |
||
| partial(visualize, self.output_format, self.final_only), | ||
| cancel_event, | ||
| runtime.session.wire_file, | ||
| runtime, | ||
| ) | ||
| continue | ||
|
devin-ai-integration[bot] marked this conversation as resolved.
Outdated
|
||
| if not manager.has_active_tasks(): | ||
| # Re-check once after noticing no active | ||
| # tasks: a worker may have finished between | ||
| # the reconcile above and this snapshot, | ||
| # leaving a terminal state on disk that we | ||
| # haven't published yet. Without this | ||
| # second reconcile+pending check, that | ||
| # final completion notification would be | ||
| # lost when the process exits. | ||
| manager.reconcile() | ||
| if notifications.has_pending_for_sink("llm"): | ||
| continue | ||
| break | ||
| # Still waiting for tasks to finish. | ||
| await asyncio.sleep(1.0) | ||
| if cancel_event.is_set(): | ||
| raise RunCancelled | ||
| else: | ||
| logger.info("Empty command, skipping") | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new post-
run_soulwait loop runs for every root/text print turn, but it ignoresruntime.config.background.keep_alive_on_exit. That flag is already honored byKimiCLI.shutdown_background_tasks(src/kimi_cli/app.py), which means exiting would not kill active tasks in this mode; with the current condition, one-shot--printcan still block until all background tasks finish (or forever for long-lived jobs), which defeats the configured keep-alive behavior.Useful? React with 👍 / 👎.