refactor(core): remove provider module, migrate to LLMProvider, add client mode handling, improve serialization error handling, update workspace edition, and clean up conditionals and imports

This commit is contained in:
2025-10-12 12:38:55 +02:00
parent c2f5ccea3b
commit 7851af14a9
63 changed files with 2221 additions and 1236 deletions

View File

@@ -1,24 +1,25 @@
use super::protocol::methods;
use super::protocol::{
RequestId, RpcErrorResponse, RpcNotification, RpcRequest, RpcResponse, PROTOCOL_VERSION,
PROTOCOL_VERSION, RequestId, RpcErrorResponse, RpcNotification, RpcRequest, RpcResponse,
};
use super::{McpClient, McpToolCall, McpToolDescriptor, McpToolResponse};
use crate::consent::{ConsentManager, ConsentScope};
use crate::tools::{Tool, WebScrapeTool, WebSearchTool};
use crate::types::ModelInfo;
use crate::types::{ChatResponse, Message, Role};
use crate::{provider::chat_via_stream, Error, LLMProvider, Result};
use futures::{future::BoxFuture, stream, StreamExt};
use crate::{Error, LlmProvider, Result, mode::Mode, send_via_stream};
use anyhow::anyhow;
use futures::{StreamExt, future::BoxFuture, stream};
use reqwest::Client as HttpClient;
use serde_json::json;
use std::path::Path;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
use tokio::sync::Mutex;
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream, connect_async};
use tungstenite::protocol::Message as WsMessage;
/// Client that talks to the external `owlen-mcp-server` over STDIO, HTTP, or WebSocket.
@@ -203,10 +204,10 @@ impl RemoteMcpClient {
.await
.map_err(|e| Error::Network(e.to_string()))?;
// Try to parse as success then error.
if let Ok(r) = serde_json::from_str::<RpcResponse>(&text) {
if r.id == id {
return Ok(r.result);
}
if let Ok(r) = serde_json::from_str::<RpcResponse>(&text)
&& r.id == id
{
return Ok(r.result);
}
let err_resp: RpcErrorResponse =
serde_json::from_str(&text).map_err(Error::Serialization)?;
@@ -249,10 +250,10 @@ impl RemoteMcpClient {
};
// Try to parse as success then error.
if let Ok(r) = serde_json::from_str::<RpcResponse>(&response_text) {
if r.id == id {
return Ok(r.result);
}
if let Ok(r) = serde_json::from_str::<RpcResponse>(&response_text)
&& r.id == id
{
return Ok(r.result);
}
let err_resp: RpcErrorResponse =
serde_json::from_str(&response_text).map_err(Error::Serialization)?;
@@ -416,7 +417,9 @@ impl McpClient for RemoteMcpClient {
// Autogrant consent for the web_search tool (permanent for this process).
let consent_manager = std::sync::Arc::new(std::sync::Mutex::new(ConsentManager::new()));
{
let mut cm = consent_manager.lock().unwrap();
let mut cm = consent_manager
.lock()
.map_err(|_| Error::Provider(anyhow!("Consent manager mutex poisoned")))?;
cm.grant_consent_with_scope(
"web_search",
Vec::new(),
@@ -459,17 +462,22 @@ impl McpClient for RemoteMcpClient {
let response: McpToolResponse = serde_json::from_value(result)?;
Ok(response)
}
async fn set_mode(&self, _mode: Mode) -> Result<()> {
// Remote servers manage their own mode settings; treat as best-effort no-op.
Ok(())
}
}
// ---------------------------------------------------------------------------
// Provider implementation forwards chat requests to the generate_text tool.
// ---------------------------------------------------------------------------
impl LLMProvider for RemoteMcpClient {
impl LlmProvider for RemoteMcpClient {
type Stream = stream::Iter<std::vec::IntoIter<Result<ChatResponse>>>;
type ListModelsFuture<'a> = BoxFuture<'a, Result<Vec<ModelInfo>>>;
type ChatFuture<'a> = BoxFuture<'a, Result<ChatResponse>>;
type ChatStreamFuture<'a> = BoxFuture<'a, Result<Self::Stream>>;
type SendPromptFuture<'a> = BoxFuture<'a, Result<ChatResponse>>;
type StreamPromptFuture<'a> = BoxFuture<'a, Result<Self::Stream>>;
type HealthCheckFuture<'a> = BoxFuture<'a, Result<()>>;
fn name(&self) -> &str {
@@ -484,11 +492,11 @@ impl LLMProvider for RemoteMcpClient {
})
}
fn chat(&self, request: crate::types::ChatRequest) -> Self::ChatFuture<'_> {
Box::pin(chat_via_stream(self, request))
fn send_prompt(&self, request: crate::types::ChatRequest) -> Self::SendPromptFuture<'_> {
Box::pin(send_via_stream(self, request))
}
fn chat_stream(&self, request: crate::types::ChatRequest) -> Self::ChatStreamFuture<'_> {
fn stream_prompt(&self, request: crate::types::ChatRequest) -> Self::StreamPromptFuture<'_> {
Box::pin(async move {
let args = serde_json::json!({
"messages": request.messages,