Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hive-runtime/src/claude.rs
atlas c2bdf30e05 hive-agent: export ACP-reported cost and context fill over OTLP
An ACP agent's `usage_update` carries `cost.{amount,currency}`, the
session's running total (opencode sums every assistant message in the
session). hive-runtime now reads it and turns the running total into
what each report added: a new session counts from zero, a session loaded
into a freshly started agent only baselines on its first report, and a
falling total adds nothing. The spend is held on the runtime until
`Runtime::take_reported_cost` drains it; claude's runtime reports none,
since the claude binary already exports `claude_code.cost.usage`.

hive-agent's existing turn-metrics meter records three new instruments:

- `hyperhive.agent.cost.usage` (counter, `model` + `currency`), ACP only;
- `hyperhive.agent.context.used` / `.size` (gauges, no attributes), for
  every backend: the two numbers the web UI's ctx% divides.

The `hyperhive · agents` dashboard gets ACP cost panels on its cost tab
and a context-fill panel on its health tab.

Refs #4845
2026-09-30 22:24:06 +02:00

54 lines
1.5 KiB
Rust

//! The claude backend: a pass-through to `hive_claude`.
use std::path::PathBuf;
use hive_claude::{CompactionPolicy, Config, InfiniteSession, Progress, SessionStore, Sink};
use crate::{Canceller, Choices, ReportedCost, Result, Runtime};
/// `claude --print` turns on a titled [`InfiniteSession`], which owns
/// resume-or-create and compaction.
pub struct ClaudeRuntime<P: CompactionPolicy> {
session: InfiniteSession<P>,
store: SessionStore,
title: String,
}
impl<P: CompactionPolicy> ClaudeRuntime<P> {
/// A runtime for the session titled `title`, found through `store` and
/// compacted per `policy`.
pub fn new(title: impl Into<String>, store: SessionStore, policy: P) -> Self {
let title = title.into();
Self {
session: InfiniteSession::new(title.clone(), store.clone(), policy),
store,
title,
}
}
}
impl<P: CompactionPolicy> Runtime for ClaudeRuntime<P> {
async fn run(&self, config: &Config, prompt: &str, sink: &impl Sink) -> Result<Progress> {
Ok(self.session.run(config, prompt, sink).await?)
}
async fn compact(&self, config: &Config, sink: &impl Sink) -> Result<()> {
Ok(self.session.compact(config, sink).await?)
}
fn archive(&self) -> Result<Option<PathBuf>> {
Ok(self.store.archive_by_title(&self.title)?)
}
fn canceller(&self) -> Option<Canceller> {
None
}
fn choices(&self) -> Option<Choices> {
None
}
fn take_reported_cost(&self) -> Vec<ReportedCost> {
Vec::new()
}
}