Skip to content

ACP adapter returns end_turn even when assistant message has internal error #24494

@hancengiz

Description

@hancengiz

Summary

The ACP adapter appears to return a successful stopReason: "end_turn" even when the underlying assistant message contains an internal error.

This was observed while testing with Fabriqa / Fabriqa.ai acting as the ACP client. Fabriqa finalized the turn from the ACP end_turn result, so provider/session errors that remained internal appeared as a blank assistant response.

This is problematic for ACP clients because end_turn means the agent completed the turn normally. If the model/provider/session processor failed, the client needs a protocol-visible failure, not only an internal session.error event or stderr/log output.

Why this matters

ACP clients communicate with the agent over JSON-RPC. Stderr/logs are diagnostic only and should not be required for correctness.

If a session/prompt turn fails due to provider/model/session error, the ACP adapter should surface that through the ACP/JSON-RPC channel. Returning successful end_turn with no useful assistant content causes clients to finalize blank or misleading assistant messages.

ACP references:

Source-level evidence

In packages/opencode/src/session/processor.ts, failures are captured on the assistant message:

ctx.assistantMessage.error = error
yield* bus.publish(Session.Event.Error, {
  sessionID: ctx.assistantMessage.sessionID,
  error: ctx.assistantMessage.error,
})

But in packages/opencode/src/acp/agent.ts, the ACP session/prompt path does not appear to inspect that error:

const response = await this.sdk.session.prompt(...)
const msg = response.data?.info

await sendUsageUpdate(...)

return {
  stopReason: "end_turn" as const,
  usage: msg ? buildUsage(msg) : undefined,
  _meta: {},
}

So an assistant message with msg.error can still be mapped to a successful ACP end_turn.

Expected behavior

If response.data?.info.error is present, the ACP adapter should not return a normal successful end_turn.

It should either:

  1. return a JSON-RPC error response to the session/prompt request, or
  2. send a user-visible ACP update explaining the error before ending the turn.

Additionally, the adapter should guarantee that all pending session/update notifications are flushed before returning the session/prompt response. This is related to the existing ordering issue where end_turn can arrive before remaining agent_message_chunk notifications:

#17505

Impact

Clients such as Fabriqa, agent-shell, or other ACP hosts may finalize the turn as successful before receiving the actual content or before learning that the turn failed. In the provider-error case, this can produce a blank assistant response with no visible error.

P.S. This report and issue is AI generated but not AI slop. It was manually reviewed by a human over long turns and checked against local logs/source to ensure this is a valid issue.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions