Skip to content
Merged
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
94 changes: 47 additions & 47 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ homepage = "https://github.com/danielkov/agentkit"
license = "MIT"
repository = "https://github.com/danielkov/agentkit"
rust-version = "1.92"
version = "0.10.0"
version = "0.10.1"

[workspace.dependencies]
async-trait = "0.1.89"
Expand Down
2 changes: 1 addition & 1 deletion book/src/acp.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ On the umbrella crate, ACP is behind the `acp` feature (implies `loop`):

```toml
[dependencies]
agentkit = { version = "0.10.0", features = ["acp"] }
agentkit = { version = "0.10.1", features = ["acp"] }
```

The `agentkit-acp` crate itself has a default `stdio` feature (pulls in `agent-client-protocol-tokio` for `serve_stdio`) and an `unstable-acp` feature that forwards to the upstream SDK's unstable protocol surface.
Expand Down
16 changes: 8 additions & 8 deletions book/src/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ The umbrella crate `agentkit` re-exports subcrates behind feature flags.
**Minimal orchestration:**

```toml
agentkit = { version = "0.10.0", features = ["core", "capabilities", "tools", "loop"] }
agentkit = { version = "0.10.1", features = ["core", "capabilities", "tools", "loop"] }
```

**Coding agent:**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "context", "tools",
"loop", "tool-fs", "tool-shell", "reporting",
] }
Expand All @@ -51,7 +51,7 @@ agentkit = { version = "0.10.0", features = [
**MCP-enabled agent:**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "context", "tools",
"loop", "tool-fs", "tool-shell", "reporting", "mcp",
] }
Expand All @@ -60,7 +60,7 @@ agentkit = { version = "0.10.0", features = [
**ACP-exposed agent (editor-addressable over the Agent Client Protocol):**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "context", "tools",
"loop", "tool-fs", "tool-shell", "reporting", "acp",
] }
Expand All @@ -69,7 +69,7 @@ agentkit = { version = "0.10.0", features = [
**OpenRouter-backed example host (streaming, prompt caching):**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "tools", "loop",
"reporting", "provider-openrouter",
] }
Expand All @@ -78,7 +78,7 @@ agentkit = { version = "0.10.0", features = [
**OpenAI-compatible provider host (streaming):**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "tools", "loop",
"reporting", "provider-groq",
] }
Expand All @@ -90,7 +90,7 @@ or `provider-openai` as needed.
**Anthropic Messages API host (streaming, extended thinking, server tools):**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "tools", "loop",
"reporting", "provider-anthropic",
] }
Expand All @@ -99,7 +99,7 @@ agentkit = { version = "0.10.0", features = [
**Cerebras Inference host (streaming, reasoning, rate-limit snapshot):**

```toml
agentkit = { version = "0.10.0", features = [
agentkit = { version = "0.10.1", features = [
"core", "capabilities", "tools", "loop",
"reporting", "provider-cerebras",
] }
Expand Down
6 changes: 3 additions & 3 deletions book/src/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Or add it to your `Cargo.toml`:

```toml
[dependencies]
agentkit = "0.10.0"
agentkit = "0.10.1"
```

## Minimal dependency set
Expand All @@ -25,14 +25,14 @@ To keep your build lean, disable defaults and pick only what you need:

```toml
[dependencies]
agentkit = { version = "0.10.0", default-features = false, features = ["core", "loop"] }
agentkit = { version = "0.10.1", default-features = false, features = ["core", "loop"] }
```

Provider adapters and MCP integration are opt-in features:

```toml
[dependencies]
agentkit = { version = "0.10.0", features = ["provider-anthropic", "mcp", "tool-fs", "tool-shell"] }
agentkit = { version = "0.10.1", features = ["provider-anthropic", "mcp", "tool-fs", "tool-shell"] }
```

See the [Feature flags reference](./feature-flags.md) for the full list.
Expand Down
6 changes: 3 additions & 3 deletions crates/agentkit-acp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ unstable-acp = ["agent-client-protocol/unstable"]
[dependencies]
agent-client-protocol = "1.0.1"
agent-client-protocol-tokio = { version = "0.11.1", optional = true }
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.0", path = "../agentkit-loop" }
agentkit-tools-core = { version = "0.10.0", path = "../agentkit-tools-core" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.1", path = "../agentkit-loop" }
agentkit-tools-core = { version = "0.10.1", path = "../agentkit-tools-core" }
async-trait.workspace = true
base64.workspace = true
serde.workspace = true
Expand Down
8 changes: 4 additions & 4 deletions crates/agentkit-adapter-completions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ rust-version.workspace = true
version.workspace = true

[dependencies]
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-http = { version = "0.10.0", path = "../agentkit-http" }
agentkit-loop = { version = "0.10.0", path = "../agentkit-loop" }
agentkit-tools-core = { version = "0.10.0", path = "../agentkit-tools-core" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
agentkit-http = { version = "0.10.1", path = "../agentkit-http" }
agentkit-loop = { version = "0.10.1", path = "../agentkit-loop" }
agentkit-tools-core = { version = "0.10.1", path = "../agentkit-tools-core" }
async-trait.workspace = true
base64.workspace = true
futures-util.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/agentkit-capabilities/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license.workspace = true
rust-version.workspace = true

[dependencies]
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
async-trait.workspace = true
serde.workspace = true
serde_json.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions crates/agentkit-compaction/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ license.workspace = true
rust-version.workspace = true

[dependencies]
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.0", path = "../agentkit-loop" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.1", path = "../agentkit-loop" }
async-trait.workspace = true
serde.workspace = true
thiserror.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/agentkit-context/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license.workspace = true
rust-version.workspace = true

[dependencies]
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
async-fs = "2.2.0"
async-trait.workspace = true
serde_json.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/agentkit-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ feature, which is **enabled by default**. Disable it to compile trait-only
when you want to bring your own backend:

```toml
agentkit-http = { version = "0.10.0", default-features = false }
agentkit-http = { version = "0.10.1", default-features = false }
```

A second optional feature, `reqwest-middleware-client`, layers
Expand Down
16 changes: 8 additions & 8 deletions crates/agentkit-integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ path = "src/lib.rs"
doctest = false

[dependencies]
agentkit-capabilities = { version = "0.10.0", path = "../agentkit-capabilities" }
agentkit-core = { version = "0.10.0", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.0", path = "../agentkit-loop" }
agentkit-mcp = { version = "0.10.0", path = "../agentkit-mcp" }
agentkit-task-manager = { version = "0.10.0", path = "../agentkit-task-manager" }
agentkit-tool-compose = { version = "0.10.0", path = "../agentkit-tool-compose" }
agentkit-tools-core = { version = "0.10.0", path = "../agentkit-tools-core", features = ["schemars"] }
agentkit-tools-derive = { version = "0.10.0", path = "../agentkit-tools-derive" }
agentkit-capabilities = { version = "0.10.1", path = "../agentkit-capabilities" }
agentkit-core = { version = "0.10.1", path = "../agentkit-core" }
agentkit-loop = { version = "0.10.1", path = "../agentkit-loop" }
agentkit-mcp = { version = "0.10.1", path = "../agentkit-mcp" }
agentkit-task-manager = { version = "0.10.1", path = "../agentkit-task-manager" }
agentkit-tool-compose = { version = "0.10.1", path = "../agentkit-tool-compose" }
agentkit-tools-core = { version = "0.10.1", path = "../agentkit-tools-core", features = ["schemars"] }
agentkit-tools-derive = { version = "0.10.1", path = "../agentkit-tools-derive" }
async-trait.workspace = true
schemars = { workspace = true, features = ["derive"] }
axum = { version = "0.8", default-features = false, features = ["http1", "tokio"] }
Expand Down
13 changes: 13 additions & 0 deletions crates/agentkit-integration-tests/src/http_mcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,19 @@ impl HttpServerHandle {
tools.len() != before
}

/// Kills the server immediately, freeing the port. Subsequent client
/// requests — including the session `DELETE` a graceful close issues —
/// fail at the transport level. Useful for exercising close/disconnect
/// error paths against a server that has gone away.
pub fn shutdown(&mut self) {
if let Some(tx) = self.shutdown_tx.take() {
let _ = tx.send(());
}
if let Some(handle) = self.join.take() {
handle.abort();
}
}

/// Emits `notifications/tools/list_changed` on the live MCP session.
/// Returns an error if the client hasn't completed the handshake yet
/// (no peer has been stashed) or the underlying notify fails.
Expand Down
103 changes: 92 additions & 11 deletions crates/agentkit-integration-tests/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

use agentkit_core::{Item, TurnCancellation};
use agentkit_core::{Item, MetadataMap, Part, ToolOutput, TurnCancellation};
use agentkit_loop::{
LoopError, ModelAdapter, ModelSession, ModelTurn, ModelTurnEvent, SessionConfig, TurnRequest,
};
Expand Down Expand Up @@ -288,22 +288,103 @@ pub fn assert_recording(observed: &SessionRecording, path: impl AsRef<Path>) {
/// Strips non-deterministic fields the loop populates so snapshot comparisons
/// stay stable. Currently zeroes [`Item::created_at`] across every Item.
fn normalise_recording(recording: &mut SessionRecording) {
for item in &mut recording.initial_items {
item.created_at = None;
}
recording.initial_items.iter_mut().for_each(normalise_item);
for turn in &mut recording.turns {
for item in &mut turn.input {
item.created_at = None;
turn.input.iter_mut().for_each(normalise_item);
for spec in &mut turn.tools {
canonicalise_json(&mut spec.input_schema);
if let Some(schema) = &mut spec.output_schema {
canonicalise_json(schema);
}
canonicalise_metadata(&mut spec.metadata);
}
for event in &mut turn.events {
if let ModelTurnEvent::Finished(result) = event {
for item in &mut result.output_items {
item.created_at = None;
match event {
ModelTurnEvent::ToolCall(part) => {
canonicalise_json(&mut part.input);
canonicalise_metadata(&mut part.metadata);
}
ModelTurnEvent::Finished(result) => {
result.output_items.iter_mut().for_each(normalise_item);
canonicalise_metadata(&mut result.metadata);
}
ModelTurnEvent::Delta(_) | ModelTurnEvent::Usage(_) => {}
}
}
}
for item in &mut recording.final_transcript {
item.created_at = None;
recording
.final_transcript
.iter_mut()
.for_each(normalise_item);
}

fn normalise_item(item: &mut Item) {
item.created_at = None;
item.parts.iter_mut().for_each(canonicalise_part);
canonicalise_metadata(&mut item.metadata);
}

fn canonicalise_part(part: &mut Part) {
match part {
Part::Text(part) => canonicalise_metadata(&mut part.metadata),
Part::Media(part) => canonicalise_metadata(&mut part.metadata),
Part::File(part) => canonicalise_metadata(&mut part.metadata),
Part::Reasoning(part) => canonicalise_metadata(&mut part.metadata),
Part::Structured(part) => {
canonicalise_json(&mut part.value);
if let Some(schema) = &mut part.schema {
canonicalise_json(schema);
}
canonicalise_metadata(&mut part.metadata);
}
Part::ToolCall(part) => {
canonicalise_json(&mut part.input);
canonicalise_metadata(&mut part.metadata);
}
Part::ToolResult(part) => {
canonicalise_output(&mut part.output);
canonicalise_metadata(&mut part.metadata);
}
Part::Custom(part) => {
if let Some(value) = &mut part.value {
canonicalise_json(value);
}
canonicalise_metadata(&mut part.metadata);
}
}
}

fn canonicalise_output(output: &mut ToolOutput) {
match output {
ToolOutput::Text(_) => {}
ToolOutput::Structured(value) => canonicalise_json(value),
ToolOutput::Parts(parts) => parts.iter_mut().for_each(canonicalise_part),
ToolOutput::Files(files) => files
.iter_mut()
.for_each(|file| canonicalise_metadata(&mut file.metadata)),
}
}

fn canonicalise_metadata(metadata: &mut MetadataMap) {
metadata.values_mut().for_each(canonicalise_json);
}

/// Recursively sorts JSON object keys so recordings compare identically
/// whether or not some crate in the build graph enables serde_json's
/// `preserve_order` feature (agent-client-protocol does, so workspace-wide
/// builds serialize maps in insertion order while narrower builds sort them).
fn canonicalise_json(value: &mut serde_json::Value) {
match value {
serde_json::Value::Object(map) => {
let mut entries: Vec<(String, serde_json::Value)> =
std::mem::take(map).into_iter().collect();
entries.sort_by(|left, right| left.0.cmp(&right.0));
for (_, nested) in &mut entries {
canonicalise_json(nested);
}
map.extend(entries);
}
serde_json::Value::Array(values) => values.iter_mut().for_each(canonicalise_json),
_ => {}
}
}
Loading
Loading