Skip to content

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

Closed

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.

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    needs:complianceThis means the issue will auto-close after 2 hours.
    and removed
    needs:complianceThis means the issue will auto-close after 2 hours.
    on Apr 26, 2026
  2. github-actions commented on Apr 26, 2026

    @github-actions
    Contributor

    Thanks for updating the issue! It now includes a clear description, source-level evidence, reproduction context, and expected behavior. The compliance flag has been removed.

  3. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  4. truenorth-lj commented on May 8, 2026

    @truenorth-lj

    Hi @hancengiz — thanks for the source-level analysis here, this lined up cleanly with what we needed. The fix is ending up as a two-PR stack:

    The split was so the wire contract could land first before the producer side; happy to combine them if maintainers prefer. Credit to you for catching this — end_turn for an internally-failed turn is exactly the bug we were seeing on real ACP clients too.

  5. axel7083 commented on Jun 26, 2026

    @axel7083

    Looking at https://agentclientprotocol.com/protocol/v1/overview#error-handling opencode should not return end_turn, this is leading to a pretty weird UI, where the user may think the model just did not responded..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions