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
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,10 @@ Everything flows through a fixed-shape chain enforced at construction time:
request-side component* → LLMBackend → response-side component* → TranslationEngine
```

The chain executor is `Switchyard` (`switchyard/lib/switchyard.py`). `LLMBackend` remains the
shared role class re-exported from `switchyard/lib/roles.py`; request-side and response-side
processors are plain async components with `process(...)` methods.
The chain executor is `Switchyard` (`switchyard/lib/switchyard.py`). `LLMBackend` is the shared
Python role class re-exported from `switchyard/lib/roles.py`; native implementations register with
it, and request-side and response-side processors are plain async components with `process(...)`
methods.
Direct Rust bindings for migrated concrete processors/backends are exposed from
`switchyard_rust.components` and implemented under `crates/switchyard-py/src/component_bindings/`.

Expand All @@ -163,7 +164,7 @@ Direct Rust bindings for migrated concrete processors/backends are exposed from
switchyard/
├── __init__.py # Public API — all exports live here
├── lib/ # Core library
│ ├── roles.py # Rust-owned LLMBackend re-export and translation aliases
│ ├── roles.py # Python LLMBackend re-export and translation aliases
│ ├── switchyard.py # Switchyard — chain executor
│ ├── proxy_context.py # ProxyContext — per-request state carrier
│ ├── profiles/ # Profile configs/runtimes for pre-built routing behavior
Expand Down Expand Up @@ -372,7 +373,7 @@ uvicorn.run(build_switchyard_app(switchyard), port=4000)

### Ask first
- Modifying `pyproject.toml` dependencies.
- Changes to the chain shape or Rust-owned role classes in `switchyard/lib/roles.py`.
- Changes to the chain shape or public role classes in `switchyard/lib/roles.py`.
- Adding new HTTP endpoints.
- Removing or renaming any public API currently in `switchyard/__init__.__all__`.

Expand Down
51 changes: 2 additions & 49 deletions Cargo.lock

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

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ members = [
"crates/libsy",
"crates/libsy-llm-client",
"crates/switchyard-components",
"crates/switchyard-core",
"crates/switchyard-py",
"crates/protocol",
"crates/switchyard-server",
Expand All @@ -32,7 +31,7 @@ rand = "0.8"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-webpki-roots", "stream"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
switchyard-core = { path = "crates/switchyard-core", version = "0.1.0" }
switchyard-components = { path = "crates/switchyard-components", version = "0.1.0" }
switchyard-libsy = { path = "crates/libsy", version = "0.1.0" }
switchyard-llm-client = { path = "crates/libsy-llm-client", version = "0.1.0" }
switchyard-protocol = { path = "crates/protocol", version = "0.1.0" }
Expand Down
3 changes: 2 additions & 1 deletion crates/switchyard-components/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@ rust-version.workspace = true
[dependencies]
async-stream.workspace = true
async-trait.workspace = true
futures-core = "0.3"
futures-util.workspace = true
parking_lot.workspace = true
rand.workspace = true
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
switchyard-core.workspace = true
switchyard-libsy.workspace = true
switchyard-protocol.workspace = true
switchyard-translation.workspace = true
tokio.workspace = true
thiserror.workspace = true
tracing.workspace = true

[dev-dependencies]
Expand Down
12 changes: 6 additions & 6 deletions crates/switchyard-components/src/backends/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ use std::env;
use std::fmt;
use std::sync::Arc;

use async_stream::try_stream;
use async_trait::async_trait;
use futures_util::StreamExt;
use serde_json::{json, Map, Value};
use switchyard_core::{
use crate::{
merge_target_extra_body, BackendFormat, BoxResponseStream, ChatRequest, ChatRequestType,
ChatResponse, LlmBackend, LlmTarget, LlmTargetId, ProxyContext, Result, StreamEvent,
SwitchyardError,
};
use async_stream::try_stream;
use async_trait::async_trait;
use futures_util::StreamExt;
use serde_json::{json, Map, Value};
use switchyard_translation::{
normalize_anthropic_tool_use_ids, TranslationEngine, TranslationPolicy, WireFormat,
};
Expand Down Expand Up @@ -546,9 +546,9 @@ fn anthropic_sse_stream(response: reqwest::Response) -> BoxResponseStream {

#[cfg(test)]
mod tests {
use crate::{EndpointConfig, LlmTargetId, ModelId};
use parking_lot::Mutex;
use serde_json::json;
use switchyard_core::{EndpointConfig, LlmTargetId, ModelId};

use super::*;

Expand Down
2 changes: 1 addition & 1 deletion crates/switchyard-components/src/backends/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
use std::sync::{Arc, OnceLock};
use std::time::Duration;

use crate::{ChatRequestType, Result, SwitchyardError};
use serde_json::{Map, Value};
use switchyard_core::{ChatRequestType, Result, SwitchyardError};
use switchyard_translation::{TranslationEngine, WireFormat};

pub(crate) enum ParsedSseFrame {
Expand Down
4 changes: 2 additions & 2 deletions crates/switchyard-components/src/backends/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use std::collections::HashSet;
use std::fmt;
use std::sync::Arc;

use async_trait::async_trait;
use switchyard_core::{
use crate::{
ChatRequest, ChatRequestType, ChatResponse, LlmBackend, LlmTarget, LlmTargetId, ProxyContext,
Result, SwitchyardError,
};
use async_trait::async_trait;

use super::{BackendSelection, BackendSelectionReason};

Expand Down
12 changes: 6 additions & 6 deletions crates/switchyard-components/src/backends/openai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ use std::env;
use std::fmt;
use std::sync::Arc;

use async_stream::try_stream;
use async_trait::async_trait;
use futures_util::StreamExt;
use serde_json::{Map, Value};
use switchyard_core::{
use crate::{
merge_target_extra_body, BackendFormat, BoxResponseStream, ChatRequest, ChatRequestType,
ChatResponse, EndpointConfig, LlmBackend, LlmTarget, LlmTargetId, ModelId, ProxyContext,
Result, StreamEvent, SwitchyardError,
};
use async_stream::try_stream;
use async_trait::async_trait;
use futures_util::StreamExt;
use serde_json::{Map, Value};
use switchyard_translation::{TranslationEngine, TranslationPolicy, WireFormat};

use super::common::{
Expand Down Expand Up @@ -580,9 +580,9 @@ fn openai_sse_stream(response: reqwest::Response) -> BoxResponseStream {

#[cfg(test)]
mod tests {
use crate::{EndpointConfig, LlmTargetId, ModelId};
use parking_lot::Mutex;
use serde_json::json;
use switchyard_core::{EndpointConfig, LlmTargetId, ModelId};

use super::*;

Expand Down
2 changes: 1 addition & 1 deletion crates/switchyard-components/src/backends/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

//! Backend execution metadata for observability components.

use crate::{LlmTargetId, ModelId};
use serde::{Deserialize, Serialize};
use switchyard_core::{LlmTargetId, ModelId};

/// How a backend resolved the final upstream target/model for a request.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
Expand Down
4 changes: 1 addition & 3 deletions crates/switchyard-components/src/backends/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ use std::fmt;
use std::sync::Arc;
use std::time::Instant;

use crate::{ChatRequest, ChatRequestType, ChatResponse, LlmBackend, ProxyContext, Result};
use async_trait::async_trait;
use switchyard_core::{
ChatRequest, ChatRequestType, ChatResponse, LlmBackend, ProxyContext, Result,
};

use crate::stats::{
selected_stats_model, selected_stats_tier, StatsAccumulator, StatsBackendLatency,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! LLM target configuration shared by routing and factory code.
//! LLM target configuration shared by compatibility routing and factory code.

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::ids::{LlmTargetId, ModelId};
use super::ids::{LlmTargetId, ModelId};

/// Wire format expected by an LLM target.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Per-request context and typed extension storage for chain components.
//! Per-request context and typed extension storage for compatibility components.

use std::any::{Any, TypeId};
use std::collections::{HashMap, HashSet};
use std::fmt;

use crate::ids::{LlmTargetId, RequestId};
use crate::types::ChatRequestType;
use super::ids::{LlmTargetId, RequestId};
use super::types::ChatRequestType;

/// Mutable state shared across processors and the backend for one request.
#[derive(Default)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Error types used by the Rust core contracts.
//! Errors shared by compatibility backends and Python bindings.

use thiserror::Error;

use crate::ids::{InvalidId, ModelId};
use crate::types::ChatRequestType;
use super::ids::{InvalidId, ModelId};
use super::types::ChatRequestType;

/// Result alias for core Switchyard operations.
pub type Result<T> = std::result::Result<T, SwitchyardError>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Non-empty string identifiers used across core routing and component wiring.
//! Non-empty string identifiers used by compatibility component wiring.

use std::fmt;
use std::str::FromStr;
Expand Down Expand Up @@ -106,10 +106,6 @@ macro_rules! string_id {
};
}

string_id!(BackendId);
string_id!(ComponentId);
string_id!(EndpointId);
string_id!(LlmTargetId);
string_id!(ModelId);
string_id!(ProfileId);
string_id!(RequestId);
18 changes: 18 additions & 0 deletions crates/switchyard-components/src/contracts/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Contracts retained by the compatibility component and Python layers.

mod backend;
mod context;
mod error;
mod ids;
mod roles;
mod types;

pub use backend::*;
pub use context::*;
pub use error::*;
pub use ids::*;
pub use roles::*;
pub use types::*;
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

//! Backend trait shared by Rust-owned LLM callers.
//! Backend trait shared by compatibility LLM callers.

use async_trait::async_trait;

use crate::context::ProxyContext;
use crate::error::Result;
use crate::types::{ChatRequest, ChatRequestType, ChatResponse};
use super::context::ProxyContext;
use super::error::Result;
use super::types::{ChatRequest, ChatRequestType, ChatResponse};

/// Backend abstraction responsible for making the LLM call.
#[async_trait]
Expand Down
Loading
Loading