hive-runtime: report an empty ACP end_turn as a turn error (#4819)
opencode answers `end_turn` even when its provider rejected the request with a non-retryable error (401, 400), and forwards nothing over ACP, so the turn looked like an empty success. A turn that ends with `end_turn`, no event, no `usage_update` and no `usage` in the prompt response now fails with `AcpError::EmptyEndTurn`. A turn that really produced nothing and reported no usage is reported the same way; that false positive is accepted. The test agent's plain `end_turn` replies now carry a response `usage`, so its ordinary turns stay successes; a response `usage` feeds only cost telemetry, not the compaction watermark. A new `blank` mode keeps the empty reply for the error case.
This commit is contained in:
parent
c01ddd8238
commit
f9c6a56ab9
2 changed files with 55 additions and 6 deletions
|
|
@ -21,6 +21,7 @@ pub(super) struct StreamMapper {
|
|||
thought: String,
|
||||
tools: HashMap<String, ToolCall>,
|
||||
usage: Option<(u64, u64)>,
|
||||
emitted: bool,
|
||||
}
|
||||
|
||||
struct ToolCall {
|
||||
|
|
@ -39,6 +40,7 @@ impl StreamMapper {
|
|||
thought: String::new(),
|
||||
tools: HashMap::new(),
|
||||
usage: None,
|
||||
emitted: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +71,7 @@ impl StreamMapper {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.emitted |= !out.is_empty();
|
||||
out
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +85,20 @@ impl StreamMapper {
|
|||
for (id, tool) in pending {
|
||||
out.push(tool_use(&id, &tool.name, &tool.input));
|
||||
}
|
||||
self.emitted |= !out.is_empty();
|
||||
out
|
||||
}
|
||||
|
||||
/// Whether the turn has emitted any event.
|
||||
pub(super) fn has_content(&self) -> bool {
|
||||
self.emitted
|
||||
}
|
||||
|
||||
/// Whether the turn has had a `usage_update`.
|
||||
pub(super) fn has_usage_update(&self) -> bool {
|
||||
self.usage.is_some()
|
||||
}
|
||||
|
||||
/// The turn's telemetry: context from the last `usage_update`, cost from
|
||||
/// the `session/prompt` response's `usage` when the agent sends one.
|
||||
pub(super) fn telemetry(&self, response: &Value, model: Option<&str>) -> Telemetry {
|
||||
|
|
|
|||
Loading…
Reference in a new issue