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:
@@ -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 {
|
||||
// Auto‑grant 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,
|
||||
|
||||
Reference in New Issue
Block a user