Skip to content

feat: Phase 2 — validated streaming #1013

Description

@planetf1

Context

mellea/stdlib/streaming.py (landing in PR #942, closing #901) provides Phase 1 streaming validation — a call-site ChunkingStrategy with three built-in chunkers (SentenceChunker, WordChunker, ParagraphChunker) and an orchestrator (stream_with_chunking). This is a scoped pragmatic choice. Phase 2 refines that foundation and extends it, broken into the sub-issues below.

Consolidated design summary

Motivation

Phase 1 collapses two semantic concerns onto the call site: how to chunk the stream (a property of the output type) and how to validate chunks (a property of the requirement). These are independent and belong in different owners.

  • Type semantics. What counts as a complete chunk of this kind of output? JSON value, prose sentence, code statement, audio segment, image region. Invariant across requirements.
  • Constraint semantics. What makes a particular output acceptable? Max three sentences, matches schema X, no hallucinated entities. Invariant across outputs of the same type.

Under Phase 1, both are author-written at the call site. Phase 2 separates them: chunking becomes a per-requirement concern, and the streaming parsed representation becomes its own capability.

Motivating output types (all in scope)

Phase 1 chunkers cover prose only (sentence/word/paragraph, all operating on accumulated_text: str). Phase 2 must support at least these output types, each with genuinely different chunk semantics:

  • Prose — sentence, word, paragraph boundaries. Already covered by Phase 1 chunkers; Phase 2 should subsume them.
  • Structured text — JSON values, YAML documents, code statements/blocks. Chunk boundary is "one complete parseable unit."
  • Multi-modal streams — audio (silence-delimited segments, fixed windows, VAD-detected utterances), image (region or tile boundaries), potentially video. Chunk boundary is inherently non-string.

Multi-modal is first-class motivation for this work, not deferred scope. Epic #891 explicitly names the audio case ("Audio that goes wrong in the first few seconds can't be caught until the full clip is done"), and the ChunkingStrategy.split(accumulated_text: str) -> list[str] signature in Phase 1 forecloses on multi-modal by design — that foreclosure is what this issue exists to address.

Sub-issues

Phase 2 is broken into four sub-issues (an earlier version of this issue proposed moving chunking onto the MOT; the direction has since changed — chunking is handled per-Requirement, and stream_parsed_repr is a separate concern from chunking):

#1440 blocks the rest; #1441, #403, and #1442 depend only on it and can proceed in parallel.

Open design questions (for comments)

  1. Signature and generator shape. Is stream_parsed_repr an async generator on the MOT? Does it share a queue with the raw astream(), or run in parallel? For multi-modal, does the signature accept bytes / frames / tensors rather than str?
  2. Chunking boundary authority. Which component decides what a "complete chunk" is — the MOT's parser, a pluggable chunk-boundary predicate, or both? Answer likely differs between text and multi-modal.
  3. Backpressure. If parsed chunks are slower to produce than raw tokens/frames, where does the buffering live?
  4. Backwards compatibility. How to migrate from the Phase 1 call sites?
  5. Typed output. Does stream_parsed_repr yield values of type S (the MOT's parsed_repr type parameter), or a richer container that carries partial-parse state? Multi-modal MOTs may need the latter.
  6. Error handling. What happens if the MOT's parser fails on a partial stream — surface immediately, wait for more data, or fall back to raw chunking?
  7. Testability. Each MOT type's stream_parsed_repr needs verification against its non-streaming parsed_repr. Shape of the shared test harness? Multi-modal test fixtures are their own problem.
  8. Agent authoring. If we want new MOT types to be agent-writable (see PR feat(stdlib): add stream_with_chunking() with per-chunk validation (#901) #942 discussion), what contracts are needed on the MOT base class? Clear APIs and guidelines are the substrate; a skill can sit on top where the framework supports one.

Broader scope (to discuss)

The PR #942 thread raised a parallel observation. Both stream_validate authoring and (future) stream_parsed_repr authoring have deterministic checks against a non-streaming counterpart (validate() and parsed_repr respectively), which makes them plausible candidates for agent-friendly extension patterns — potentially skills in frameworks that support them. Worth discussing whether this issue should cover just stream_parsed_repr or also the broader agent-authoring story, or whether the latter warrants its own separate issue.

Dependencies

References

Metadata

Metadata

Assignees

Labels

area/samplingSamplingStrategy, SamplingResult, ModelOption, generation optionsarea/stdlibCore abstractions: Context, MOT, SamplingStrategy, formatters, serializationarea/streamingStreaming chunks, events, per-chunk validationenhancementNew feature or requestepicHigh level Epicp1High: important bugs (workaround exists) or high-value core features. Do soon, not on fire.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions