fix(agent): propagate LLM stop reason through lifecycle events#24867
Merged
visionik merged 1 commit intoopenclaw:mainfrom Mar 3, 2026
Merged
fix(agent): propagate LLM stop reason through lifecycle events#24867visionik merged 1 commit intoopenclaw:mainfrom
visionik merged 1 commit intoopenclaw:mainfrom
Conversation
Contributor
kevinWangSheng
left a comment
There was a problem hiding this comment.
Review Summary
Good change in concept - propagating stopReason helps downstream consumers detect truncated responses.
Issue found
check job failed: https://github.com/openclaw/openclaw/actions/runs/22329117075/job/64607637997
Please fix the failing check and I'll be happy to approve.
Code review notes
- The implementation is clean and follows existing patterns
- Adding
stopReasonto lifecycle events is backward compatible - Good logging for non-
end_turncases
Status: Request changes until CI passes.
Complete the stop reason propagation chain so ACP clients can distinguish end_turn from max_tokens: - server-chat.ts: emitChatFinal accepts optional stopReason param, includes it in the final payload, reads it from lifecycle event data - translator.ts: read stopReason from the final payload instead of hardcoding end_turn Chain: LLM API → run.ts (meta.stopReason) → agent.ts (lifecycle event) → server-chat.ts (final payload) → ACP translator (PromptResponse)
83b30ee to
333c160
Compare
Contributor
Author
|
@kevinWangSheng thank you for the comment. Passed all tests and I just merged. Happy to have your input on any of my future PR's! |
kevinWangSheng
pushed a commit
to kevinWangSheng/openclaw
that referenced
this pull request
Mar 3, 2026
…openclaw#24867) Complete the stop reason propagation chain so ACP clients can distinguish end_turn from max_tokens: - server-chat.ts: emitChatFinal accepts optional stopReason param, includes it in the final payload, reads it from lifecycle event data - translator.ts: read stopReason from the final payload instead of hardcoding end_turn Chain: LLM API → run.ts (meta.stopReason) → agent.ts (lifecycle event) → server-chat.ts (final payload) → ACP translator (PromptResponse)
yumesha
pushed a commit
to yumesha/openclaw
that referenced
this pull request
Mar 3, 2026
…openclaw#24867) Complete the stop reason propagation chain so ACP clients can distinguish end_turn from max_tokens: - server-chat.ts: emitChatFinal accepts optional stopReason param, includes it in the final payload, reads it from lifecycle event data - translator.ts: read stopReason from the final payload instead of hardcoding end_turn Chain: LLM API → run.ts (meta.stopReason) → agent.ts (lifecycle event) → server-chat.ts (final payload) → ACP translator (PromptResponse)
mrosmarin
added a commit
to mrosmarin/openclaw
that referenced
this pull request
Mar 3, 2026
* main: (134 commits) fix(telegram): warn when accounts.default is missing in multi-account setup (openclaw#32544) agents: propagate config for embedded skill loading Gateway: fix stale self version in status output (openclaw#32655) feat(mattermost): add native slash command support (refresh) (openclaw#32467) Diffs: Migrate tool usage guidance from before_prompt_build to a plugin skill (openclaw#32630) bug: Workaround for QMD upstream bug (openclaw#27028) fix: improve compaction summary instructions to preserve active work (openclaw#8903) chore: Updated Brave documentation (openclaw#26860) security(line): synthesize strict LINE auth boundary hardening test(e2e): isolate module mocks across harnesses fix(telegram): debounce forwarded media-only bursts test(live): harden gateway model profile probes fix(ci): handle disabled systemd units in docker doctor flow fix(test): stabilize appcast version assertion fix(line): synthesize media/auth/routing webhook regressions (openclaw#32546) thanks @Takhoffman fix(gateway+acp): thread stopReason through final event to ACP bridge (openclaw#24867) docs(changelog): reattribute duplicated PR credits fix: scope extension runtime deps to plugin manifests ci: enable stale workflow chore(release): bump to 2026.3.3 and seed changelog ...
dawi369
pushed a commit
to dawi369/davis
that referenced
this pull request
Mar 3, 2026
…openclaw#24867) Complete the stop reason propagation chain so ACP clients can distinguish end_turn from max_tokens: - server-chat.ts: emitChatFinal accepts optional stopReason param, includes it in the final payload, reads it from lifecycle event data - translator.ts: read stopReason from the final payload instead of hardcoding end_turn Chain: LLM API → run.ts (meta.stopReason) → agent.ts (lifecycle event) → server-chat.ts (final payload) → ACP translator (PromptResponse)
MillionthOdin16
added a commit
to MillionthOdin16/openclaw
that referenced
this pull request
Mar 3, 2026
Problem
The LLM stop reason (
end_turn,max_tokens, etc.) is lost between the agent runner and the gateway event stream. Downstream consumers like the ACP bridge, TUI, and WebSocket clients cannot distinguish a complete response from one truncated bymax_tokens.The stop reason is dropped at two points:
pi-embedded-runner/run.tsonly setsmeta.stopReasonfortool_calls, discarding the actual LLM stop reason fromlastAssistant.stopReasoncommands/agent.tsemits the lifecyclephase: "end"event without includingstopReasonFix
run.ts: PropagatelastAssistant.stopReasonintoresult.meta.stopReasonwhen there are no client tool callsagent.ts: IncludestopReasonin the lifecycle end event data and log non-end_turnstop reasons to stderrContext
Related to #24856 (flush throttled delta before final). Together these two PRs improve streaming reliability for gateway clients:
stopReasonChanges
2 files, 10 lines added, 1 removed.
Greptile Summary
Propagates LLM stop reason (
end_turn,max_tokens, etc.) from the agent runner to lifecycle events and downstream consumers.Changes:
run.ts:1138-1140- propagateslastAssistant.stopReasonwhen no client tool calls presentagent.ts:600-612- includesstopReasonin lifecycle end event and logs non-end_turnreasons to stderrThis allows downstream consumers (ACP bridge, TUI, WebSocket clients) to distinguish complete responses from ones truncated by token limits.
Confidence Score: 5/5
stopReasonfield is optional and doesn't break existing consumers. The implementation correctly propagates the stop reason from the LLM through the execution flow. Type safety is maintained with appropriate casts, and the change aligns with existing patterns in the codebase.Last reviewed commit: e8f66e8
(4/5) You can add custom instructions or style guidelines for the agent here!