Skip to main content

GeneratedOutput

Struct GeneratedOutput 

Source
pub struct GeneratedOutput {
    pub reasoning_chars: u64,
    pub answer_chars: u64,
    pub llm_calls: usize,
    pub max_tool_calls_in_batch: usize,
    pub system_warnings: u32,
}
Expand description

The shape of what a run generated, as opposed to how much.

§Why this exists

Until this struct, the eval counted output and threw it away: 7 of the 9 AgentEvent variants — TextDelta and ReasoningDelta among them — fell through the benchmark’s event loop untouched. A run was therefore knowable only as a token total and a wall time.

That is not enough to read a run. On 2026-08-29 five runs generated ~32,900 completion tokens apiece against ~510 for the same task without the pipeline, took ~950s, and passed. Nothing recorded anywhere could say whether that was a small reasoning model thinking at length or a generation fault, and the two call for opposite responses. This struct is the difference between those two readings.

Every field is taken from events the loop already emitted, so nothing here changes what the eval sends, executes or scores.

Fields§

§reasoning_chars: u64

Characters the model emitted as reasoning (chain-of-thought).

§This is only meaningful when the upstream separates reasoning

It counts AgentEvent::ReasoningDelta, which exists only when llama-server was launched with --reasoning-format deepseek and so splits thinking into its own reasoning_content SSE field. Without that flag a reasoning model’s thinking arrives inline as <think>…</think>, the normalizer strips the tags, and every one of those characters is counted as Self::answer_chars instead.

So reasoning_chars: 0 beside a large answer_chars is ambiguous: it means either the model did not think, or it thought and nobody could tell. Resolve it by checking whether the model carries the reasoning capability tag, not by assuming.

§answer_chars: u64

Characters the model emitted as ordinary answer text, summed across every turn — not just the final one.

Counted from AgentEvent::TextDelta rather than from FinalAnswer, which carries the same text already accumulated and would double it.

§llm_calls: usize

How many requests the run actually sent to the model.

Distinct from TuneTaskResult::iterations, which counts only tool-executing turns — a run that ends by answering in text made one more request than it reports iterations. Dividing tokens by iterations therefore overstates per-request generation, by 50% on a two-iteration run, which is exactly the arithmetic a reader performs when asking whether a token cap was in force.

Derived from the event stream (one per IterationComplete, plus one for a FinalAnswer), so a run a guard aborted mid-turn under-counts by the aborting request. Read it as a floor on those runs.

§max_tool_calls_in_batch: usize

The largest single batch of tool calls any one turn executed.

The fingerprint of a constrained-decoding runaway. gglib’s generated grammar admits root ::= sp call (sp call)* sp — unbounded repetition — so a model that never emits an end-of-generation token can keep producing syntactically valid calls until it hits a token cap or the context limit. Scoring cannot reveal this: extra unrequested calls cost nothing, so a batch of hundreds containing the right call still scores 1.0 and the task still reads as passed.

§It saturates at 64

The collector drops tool-call fragments past MAX_TOOL_CALL_INDEX (64), so this is a floor, and a reading of exactly 64 means “at least 64” — the true batch went into CollectedResponse::tool_calls_truncated and from there into a SystemWarning message this eval keeps no text of. Measured 2026-08-29: a reading of 64 was kept=64 dropped=542606 calls in one response, for a task whose expected output is one call. An earlier run logged dropped=1237. Read a 64 as “consult the daemon log”, never as a batch size.

§system_warnings: u32

How many recoverable conditions the loop reported during this run.

Counts AgentEvent::SystemWarning, whose main source is the loop recovering from a model that requested more parallel tool calls than the configured limit. That recovery costs a whole extra request and was previously invisible to the eval: the warning was emitted, discarded, and the run reported as though nothing had happened.

Warnings, not incidents. One over-wide batch raises two — the collector’s slot limit and then the parallel-tool limit — so this over-states how many times the model ran away, by up to a factor of two. It is a “something went wrong here” flag; the log holds the account.

Trait Implementations§

Source§

impl Clone for GeneratedOutput

Source§

fn clone(&self) -> GeneratedOutput

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for GeneratedOutput

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for GeneratedOutput

Source§

fn default() -> GeneratedOutput

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for GeneratedOutput

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for GeneratedOutput

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,