feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
use crate::error::ApiError;
|
2026-04-01 04:10:46 +00:00
|
|
|
use crate::providers::anthropic::{self, AnthropicClient, AuthSource};
|
|
|
|
|
use crate::providers::openai_compat::{self, OpenAiCompatClient, OpenAiCompatConfig};
|
|
|
|
|
use crate::providers::{self, Provider, ProviderKind};
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
use crate::types::{MessageRequest, MessageResponse, StreamEvent};
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
async fn send_via_provider<P: Provider>(
|
|
|
|
|
provider: &P,
|
|
|
|
|
request: &MessageRequest,
|
|
|
|
|
) -> Result<MessageResponse, ApiError> {
|
|
|
|
|
provider.send_message(request).await
|
2026-03-31 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
async fn stream_via_provider<P: Provider>(
|
|
|
|
|
provider: &P,
|
|
|
|
|
request: &MessageRequest,
|
|
|
|
|
) -> Result<P::Stream, ApiError> {
|
|
|
|
|
provider.stream_message(request).await
|
2026-03-31 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2026-04-01 04:10:46 +00:00
|
|
|
pub enum ProviderClient {
|
|
|
|
|
Anthropic(AnthropicClient),
|
|
|
|
|
Xai(OpenAiCompatClient),
|
|
|
|
|
OpenAi(OpenAiCompatClient),
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
impl ProviderClient {
|
|
|
|
|
pub fn from_model(model: &str) -> Result<Self, ApiError> {
|
|
|
|
|
Self::from_model_with_anthropic_auth(model, None)
|
2026-03-31 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
pub fn from_model_with_anthropic_auth(
|
|
|
|
|
model: &str,
|
|
|
|
|
anthropic_auth: Option<AuthSource>,
|
|
|
|
|
) -> Result<Self, ApiError> {
|
|
|
|
|
let resolved_model = providers::resolve_model_alias(model);
|
|
|
|
|
match providers::detect_provider_kind(&resolved_model) {
|
2026-04-01 05:45:27 +00:00
|
|
|
ProviderKind::Anthropic => Ok(Self::Anthropic(match anthropic_auth {
|
|
|
|
|
Some(auth) => AnthropicClient::from_auth(auth),
|
|
|
|
|
None => AnthropicClient::from_env()?,
|
|
|
|
|
})),
|
2026-04-01 04:10:46 +00:00
|
|
|
ProviderKind::Xai => Ok(Self::Xai(OpenAiCompatClient::from_env(
|
|
|
|
|
OpenAiCompatConfig::xai(),
|
|
|
|
|
)?)),
|
|
|
|
|
ProviderKind::OpenAi => Ok(Self::OpenAi(OpenAiCompatClient::from_env(
|
|
|
|
|
OpenAiCompatConfig::openai(),
|
|
|
|
|
)?)),
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[must_use]
|
2026-04-01 04:10:46 +00:00
|
|
|
pub const fn provider_kind(&self) -> ProviderKind {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Anthropic(_) => ProviderKind::Anthropic,
|
|
|
|
|
Self::Xai(_) => ProviderKind::Xai,
|
|
|
|
|
Self::OpenAi(_) => ProviderKind::OpenAi,
|
2026-03-31 19:47:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
pub async fn send_message(
|
|
|
|
|
&self,
|
|
|
|
|
request: &MessageRequest,
|
|
|
|
|
) -> Result<MessageResponse, ApiError> {
|
2026-04-01 04:10:46 +00:00
|
|
|
match self {
|
|
|
|
|
Self::Anthropic(client) => send_via_provider(client, request).await,
|
|
|
|
|
Self::Xai(client) | Self::OpenAi(client) => send_via_provider(client, request).await,
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
}
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn stream_message(
|
|
|
|
|
&self,
|
|
|
|
|
request: &MessageRequest,
|
|
|
|
|
) -> Result<MessageStream, ApiError> {
|
2026-04-01 04:10:46 +00:00
|
|
|
match self {
|
|
|
|
|
Self::Anthropic(client) => stream_via_provider(client, request)
|
|
|
|
|
.await
|
|
|
|
|
.map(MessageStream::Anthropic),
|
|
|
|
|
Self::Xai(client) | Self::OpenAi(client) => stream_via_provider(client, request)
|
|
|
|
|
.await
|
|
|
|
|
.map(MessageStream::OpenAiCompat),
|
2026-03-31 23:38:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
#[derive(Debug)]
|
2026-04-01 04:10:46 +00:00
|
|
|
pub enum MessageStream {
|
|
|
|
|
Anthropic(anthropic::MessageStream),
|
|
|
|
|
OpenAiCompat(openai_compat::MessageStream),
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MessageStream {
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
#[must_use]
|
|
|
|
|
pub fn request_id(&self) -> Option<&str> {
|
2026-04-01 04:10:46 +00:00
|
|
|
match self {
|
|
|
|
|
Self::Anthropic(stream) => stream.request_id(),
|
|
|
|
|
Self::OpenAiCompat(stream) => stream.request_id(),
|
|
|
|
|
}
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
pub async fn next_event(&mut self) -> Result<Option<StreamEvent>, ApiError> {
|
2026-04-01 04:10:46 +00:00
|
|
|
match self {
|
|
|
|
|
Self::Anthropic(stream) => stream.next_event().await,
|
|
|
|
|
Self::OpenAiCompat(stream) => stream.next_event().await,
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
pub use anthropic::{
|
|
|
|
|
oauth_token_is_expired, resolve_saved_oauth_token, resolve_startup_auth_source, OAuthTokenSet,
|
|
|
|
|
};
|
|
|
|
|
#[must_use]
|
|
|
|
|
pub fn read_base_url() -> String {
|
|
|
|
|
anthropic::read_base_url()
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-01 04:10:46 +00:00
|
|
|
#[must_use]
|
|
|
|
|
pub fn read_xai_base_url() -> String {
|
|
|
|
|
openai_compat::read_base_url(OpenAiCompatConfig::xai())
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2026-04-01 04:10:46 +00:00
|
|
|
use crate::providers::{detect_provider_kind, resolve_model_alias, ProviderKind};
|
2026-03-31 23:38:05 +00:00
|
|
|
|
|
|
|
|
#[test]
|
2026-04-01 04:10:46 +00:00
|
|
|
fn resolves_existing_and_grok_aliases() {
|
|
|
|
|
assert_eq!(resolve_model_alias("opus"), "claude-opus-4-6");
|
|
|
|
|
assert_eq!(resolve_model_alias("grok"), "grok-3");
|
|
|
|
|
assert_eq!(resolve_model_alias("grok-mini"), "grok-3-mini");
|
2026-03-31 23:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2026-04-01 04:10:46 +00:00
|
|
|
fn provider_detection_prefers_model_family() {
|
|
|
|
|
assert_eq!(detect_provider_kind("grok-3"), ProviderKind::Xai);
|
2026-03-31 19:47:02 +00:00
|
|
|
assert_eq!(
|
2026-04-01 04:10:46 +00:00
|
|
|
detect_provider_kind("claude-sonnet-4-6"),
|
|
|
|
|
ProviderKind::Anthropic
|
2026-03-31 19:47:02 +00:00
|
|
|
);
|
|
|
|
|
}
|
feat: Rust port of Claw Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- claw-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|