iloveeyjafjalla opened a new issue, #6847:
URL: https://github.com/apache/rocketmq-dashboard/issues/6847

   ## Summary
   
   An AI turn that runs on the **qoder** engine never finishes successfully. 
The answer streams into the console, and the run row is written as `FAILED` / 
`StopReason.PROVIDER_ERROR` / `llm.provider.no_result` (`agent stream ended 
without a result frame`).
   
   ## Why
   
   `decide()` in `AiRunExecutor` fails a run whose agent stream closed without 
delivering a result frame, and scopes that rule with `!isHttpEngine(engine)`, 
which covers every CLI engine:
   
   - 
`server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiRunExecutor.java:508`
   
   Only claude-code produces such a frame:
   
   - `ClaudeCodeAgentProvider` is the only provider that overrides 
`streamEvents` 
(`server/src/main/java/org/apache/rocketmq/studio/ops/ai/ClaudeCodeAgentProvider.java:191`),
 and `ClaudeCodeStreamParser.java:628` is the only place an 
`AgentEvent.ResultMeta` is created at all.
   - `QoderAgentProvider` implements neither `stream` nor `streamEvents`, so it 
inherits the default adapter, which adapts the completion into `TextDelta` and 
emits nothing else 
(`server/src/main/java/org/apache/rocketmq/studio/ops/ai/AgentProvider.java:74-78`).
   
   `outcome.subtype` therefore stays empty for **every** finished qoder turn, 
and the no-result branch fires on all of them. The engine's own gates already 
decide whether a text-only turn succeeded: `CliAgentProvider.complete()` throws 
`llm.provider.cli_error` on a non-zero exit and `llm.provider.empty_completion` 
on blank output, so for that provider shape a missing result frame carries no 
information about the process.
   
   ## Impact
   
   The shipped server image is affected: `server/Dockerfile:81` installs 
`@qoder-ai/qodercli` on `PATH`, `qoderAvailable` is part of the capability 
response (`docs/api-spec.md:2837`), and the engine is selectable in AI settings 
(`web/src/pages/settings/AiAssistantTab.tsx:69`) and in the composer 
(`web/src/pages/ai/components/Composer.tsx:87`).
   
   Every finished qoder turn renders the failed marker in the answer bubble 
(`web/src/pages/ai/components/AssistantBubble.tsx:96`) and flags the 
conversation with an error state 
(`web/src/pages/ai/components/ConversationListModal.tsx:144`), although the 
answer is complete. The same applies to any future engine that inherits the 
default text-only adapter.
   
   ## Reproduction
   
   Deterministic, no CLI required:
   
   ```
   mvn -B -ntp -Dtest=AiRunServiceTest -Dsurefire.failIfNoSpecifiedTests=false 
test
   ```
   
   `AiRunServiceTest.aTextOnlyEngineTurnMustCompleteWithoutAResultFrameTest` 
runs a turn with the engine set to `qoder` whose stream carries the completion 
as one text delta (the shape of a real qoder turn):
   
   ```
   expected: "COMPLETED"
    but was: "FAILED"
   ```
   
   
`AiRunServiceTest.admissionShouldQueueTheRunWithASnapshotOfTheEngineAndModelTest`
 (also engine `qoder`) fails the same way.
   
   End to end: install the image, pick **Qoder CLI** in the composer, send a 
message — the answer appears and the turn lands in `FAILED`.
   
   ## Expected
   
   A finished turn on an engine whose stream carries no result frame is 
`COMPLETED` (no stop reason, no error code), and the no-result branch stays 
scoped to the engines whose stream actually carries a terminal frame, so a 
claude-code run that ends without one is still a failure.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to