Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.0] - 2026-09-05

### Added
- Steering input for streaming runs: a message typed while the agent is working can now reach the running turn instead of waiting for it to finish (`serdes-ai-agent`):
- New `SteeringQueue`, cheaply cloneable, constructible standalone, with `steer(text: String)` to enqueue from any task and `pending_len()` to read how many texts are queued but not yet delivered. Internally a tokio unbounded mpsc; the run claims the single receiver for its lifetime.
- `RunOptions::steering(queue)` attaches a queue to a run, mirroring `message_history`. Clone the queue beforehand wherever user input arrives.
- Queued texts are drained FIFO at the tool-call boundary only: after the step's tool returns are appended to the history and before the loop issues the next model request. Each drained text is appended as its own `ModelRequest` carrying a user prompt part, and one `AgentStreamEvent::SteeringDelivered { step, text }` is emitted per text after that step's `ToolExecuted` events and before the next `RequestStart`, so consumers can persist the user message in transcript order. Both `AgentStream::new` and `AgentStream::new_with_cancel` drain.
- Nothing is drained before the first model request, and a run that never crosses a tool-call boundary (text-only completion, error, cancellation) delivers nothing: leftovers stay queued and a later run created from the same queue delivers them at its first tool-call boundary.

### Breaking
- `AgentStreamEvent` gains `SteeringDelivered { step, text }`. The enum is not `#[non_exhaustive]`, so downstream `match` sites that list every variant without a wildcard need the new arm. Adding a public type and variant is a minor-version bump for this 0.x workspace: `0.4.0` across all crates.

## [0.3.0] - 2026-08-24

Combined release integrating PRs #51, #52, #53, #54 and #55. Streaming is now a
Expand Down
34 changes: 17 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 16 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ members = [
]

[workspace.package]
version = "0.3.0"
version = "0.4.0"
edition = "2021"
license = "MIT"
authors = ["serdes-ai contributors"]
Expand Down Expand Up @@ -93,21 +93,21 @@ pretty_assertions = "1.4"
regex = "1.12"

# Internal crates
serdes-ai-core = { path = "serdes-ai-core", version = "0.3.0" }
serdes-ai-agent = { path = "serdes-ai-agent", version = "0.3.0" }
serdes-ai-models = { path = "serdes-ai-models", version = "0.3.0" }
serdes-ai-providers = { path = "serdes-ai-providers", version = "0.3.0" }
serdes-ai-tools = { path = "serdes-ai-tools", version = "0.3.0" }
serdes-ai-toolsets = { path = "serdes-ai-toolsets", version = "0.3.0" }
serdes-ai-output = { path = "serdes-ai-output", version = "0.3.0" }
serdes-ai-streaming = { path = "serdes-ai-streaming", version = "0.3.0" }
serdes-ai-mcp = { path = "serdes-ai-mcp", version = "0.3.0" }
serdes-ai-embeddings = { path = "serdes-ai-embeddings", version = "0.3.0" }
serdes-ai-retries = { path = "serdes-ai-retries", version = "0.3.0" }
serdes-ai-graph = { path = "serdes-ai-graph", version = "0.3.0" }
serdes-ai-evals = { path = "serdes-ai-evals", version = "0.3.0" }
serdes-ai-macros = { path = "serdes-ai-macros", version = "0.3.0" }
serdes-ai-a2a = { path = "serdes-ai-a2a", version = "0.3.0" }
serdes-ai-core = { path = "serdes-ai-core", version = "0.4.0" }
serdes-ai-agent = { path = "serdes-ai-agent", version = "0.4.0" }
serdes-ai-models = { path = "serdes-ai-models", version = "0.4.0" }
serdes-ai-providers = { path = "serdes-ai-providers", version = "0.4.0" }
serdes-ai-tools = { path = "serdes-ai-tools", version = "0.4.0" }
serdes-ai-toolsets = { path = "serdes-ai-toolsets", version = "0.4.0" }
serdes-ai-output = { path = "serdes-ai-output", version = "0.4.0" }
serdes-ai-streaming = { path = "serdes-ai-streaming", version = "0.4.0" }
serdes-ai-mcp = { path = "serdes-ai-mcp", version = "0.4.0" }
serdes-ai-embeddings = { path = "serdes-ai-embeddings", version = "0.4.0" }
serdes-ai-retries = { path = "serdes-ai-retries", version = "0.4.0" }
serdes-ai-graph = { path = "serdes-ai-graph", version = "0.4.0" }
serdes-ai-evals = { path = "serdes-ai-evals", version = "0.4.0" }
serdes-ai-macros = { path = "serdes-ai-macros", version = "0.4.0" }
serdes-ai-a2a = { path = "serdes-ai-a2a", version = "0.4.0" }

[profile.dev]
split-debuginfo = "unpacked"
Expand Down
4 changes: 3 additions & 1 deletion serdes-ai-agent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub mod history;
pub mod instructions;
pub mod output;
pub mod run;
pub mod steering;
pub mod stream;

// Re-exports
Expand All @@ -105,6 +106,7 @@ pub use output::{
pub use run::{
AgentRun, AgentRunResult, CompressionStrategy, ContextCompression, RunOptions, StepResult,
};
pub use steering::SteeringQueue;
pub use stream::{AgentStream, AgentStreamEvent};

// Re-export CancellationToken for convenience
Expand All @@ -116,7 +118,7 @@ pub mod prelude {
agent, agent_with_deps, Agent, AgentBuilder, AgentRun, AgentRunError, AgentRunResult,
AgentStream, AgentStreamEvent, CancellationToken, CompressionStrategy, ContextCompression,
EndStrategy, OutputMode, OutputSchema, OutputValidator, RunContext, RunOptions, RunUsage,
StepResult, UsageLimits,
SteeringQueue, StepResult, UsageLimits,
};
}

Expand Down
12 changes: 12 additions & 0 deletions serdes-ai-agent/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::agent::{Agent, EndStrategy};
use crate::context::{generate_run_id, RunContext, RunUsage, UsageLimits};
use crate::errors::{AgentRunError, OutputParseError, OutputValidationError};
use crate::steering::SteeringQueue;
use chrono::Utc;
use serde_json::Value as JsonValue;
use serdes_ai_core::messages::{RetryPromptPart, ToolCallArgs, ToolReturnPart, UserContent};
Expand Down Expand Up @@ -54,6 +55,8 @@ pub struct RunOptions {
pub model_settings: Option<ModelSettings>,
/// Message history to continue from.
pub message_history: Option<Vec<ModelRequest>>,
/// Steering input queue for this run.
pub steering: Option<SteeringQueue>,
/// Usage limits for this run.
pub usage_limits: Option<crate::context::UsageLimits>,
/// Custom metadata.
Expand All @@ -80,6 +83,15 @@ impl RunOptions {
self
}

/// Attach a steering input queue.
///
/// Queued texts are delivered to the model at tool-call boundaries only;
/// see [`SteeringQueue`] for the exact delivery rules.
pub fn steering(mut self, queue: SteeringQueue) -> Self {
self.steering = Some(queue);
self
}

/// Set metadata.
pub fn metadata(mut self, metadata: JsonValue) -> Self {
self.metadata = Some(metadata);
Expand Down
Loading