Skip to content

Commit 0b3bbfe

Browse files
authored
fix(gateway+acp): thread stopReason through final event to ACP bridge (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)
1 parent b34530a commit 0b3bbfe

File tree

2 files changed

+9
-1
lines changed

2 files changed

+9
-1
lines changed

src/acp/translator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,9 @@ export class AcpGatewayAgent implements Agent {
423423
}
424424

425425
if (state === "final") {
426-
this.finishPrompt(pending.sessionId, pending, "end_turn");
426+
const rawStopReason = payload.stopReason as string | undefined;
427+
const stopReason: StopReason = rawStopReason === "max_tokens" ? "max_tokens" : "end_turn";
428+
this.finishPrompt(pending.sessionId, pending, stopReason);
427429
return;
428430
}
429431
if (state === "aborted") {

src/gateway/server-chat.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ export function createAgentEventHandler({
346346
seq: number,
347347
jobState: "done" | "error",
348348
error?: unknown,
349+
stopReason?: string,
349350
) => {
350351
const bufferedText = stripInlineDirectiveTagsForDisplay(
351352
chatRunState.buffers.get(clientRunId) ?? "",
@@ -399,6 +400,7 @@ export function createAgentEventHandler({
399400
sessionKey,
400401
seq,
401402
state: "final" as const,
403+
...(stopReason && { stopReason }),
402404
message:
403405
text && !shouldSuppressSilent
404406
? {
@@ -512,6 +514,8 @@ export function createAgentEventHandler({
512514
if (!isAborted && evt.stream === "assistant" && typeof evt.data?.text === "string") {
513515
emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, evt.data.text);
514516
} else if (!isAborted && (lifecyclePhase === "end" || lifecyclePhase === "error")) {
517+
const evtStopReason =
518+
typeof evt.data?.stopReason === "string" ? evt.data.stopReason : undefined;
515519
if (chatLink) {
516520
const finished = chatRunState.registry.shift(evt.runId);
517521
if (!finished) {
@@ -525,6 +529,7 @@ export function createAgentEventHandler({
525529
evt.seq,
526530
lifecyclePhase === "error" ? "error" : "done",
527531
evt.data?.error,
532+
evtStopReason,
528533
);
529534
} else {
530535
emitChatFinal(
@@ -534,6 +539,7 @@ export function createAgentEventHandler({
534539
evt.seq,
535540
lifecyclePhase === "error" ? "error" : "done",
536541
evt.data?.error,
542+
evtStopReason,
537543
);
538544
}
539545
} else if (isAborted && (lifecyclePhase === "end" || lifecyclePhase === "error")) {

0 commit comments

Comments
 (0)