Skip to content

[Reasoning retention 1/2] Reconcile complete streamed reasoning items #152

Description

@franciscojavierarceo

Parent: #151

Goal

Make the streaming path produce the same complete typed reasoning items as the non-streaming path, without changing the database schema or persistence unit.

Scope

Event normalization

  • Give response.reasoning_text.delta/done and response.reasoning_summary_text.delta/done distinct normalized payloads.
  • Preserve the item ID and any index needed to update the correct in-flight field.
  • Keep reasoning text and reasoning summaries semantically separate throughout normalization and accumulation.

Streaming accumulator

  • Track independent fallback state for reasoning content and summary.
  • Parse reasoning items from response.output_item.done.item.
  • Reconcile a valid completed item with matching in-flight state by item ID.
  • Treat raw field presence as significant:
    • completed fields that are present—including empty arrays or null—are authoritative;
    • delta-derived state is used only when the corresponding completed field is omitted.
  • Preserve id, all typed content entries, all summary entries, encrypted_content, and status.
  • If output_item.added is absent, retain the completed item at its output_index.
  • If the completed item is malformed, retain valid delta-derived state.
  • Emit at most one reasoning item per ID and preserve ordering relative to messages and tool calls.
  • Follow the existing complete_custom_tool_call reconciliation structure where practical.

Storage contract

  • Keep ReasoningOutput as the persistence unit.
  • Add no reasoning-text table, column, migration, or alternate flattened representation.
  • Verify a complete reasoning item survives storage serialization and deserialization with its private item-kind marker removed from the reconstructed typed item.

Test plan

Add focused tests to the existing accumulator, normalizer, and storage test modules:

  • streamed reasoning-text deltas followed by a complete reasoning item;
  • streamed summary deltas preserved separately from reasoning text;
  • encrypted_content and status copied from output_item.done;
  • completed content/summary overriding incomplete delta-derived fields;
  • delta fallback when completed content or summary is omitted;
  • completed reasoning without a preceding output_item.added;
  • no duplicate when deltas and a completed item are both present;
  • malformed completed item retaining valid accumulated reasoning;
  • original output_index ordering when an added event is omitted;
  • complete typed storage serialization/deserialization round trip.

Use literal hand-checked fixtures. Do not hand-author or update captured replay cassettes for these unit-level cases.

Likely files

  • crates/agentic-server-core/src/events/types.rs
  • crates/agentic-server-core/src/events/normalize.rs
  • crates/agentic-server-core/src/executor/accumulator.rs
  • crates/agentic-server-core/src/types/io/output.rs only if a focused typed helper is needed
  • crates/agentic-server-core/src/storage/types/item.rs
  • crates/agentic-server-core/src/storage/models/item.rs
  • existing event-normalizer and accumulator tests

Acceptance criteria

  • Streamed and non-streamed versions of the same upstream reasoning item are wire-equivalent after structured serialization.
  • Summary events never enter reasoning content, and reasoning-text events never enter summary.
  • A valid completed item is authoritative without causing duplicates.
  • Missing or malformed completion data falls back safely to valid accumulated state.
  • Ordering is preserved even when output_item.added is omitted.
  • Complete reasoning items survive the existing typed JSON storage round trip.
  • No migration or separate reasoning-text persistence is introduced.

Verification

cargo test -p agentic-server-core executor::accumulator
cargo test -p agentic-server-core --test event_normalizer_test
cargo test -p agentic-server-core storage
cargo test -p agentic-server-core
cargo clippy -p agentic-server-core --all-targets -- -D warnings
cargo fmt -- --check

Report the exact commands and results.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions