Skip to main content

oxicode_sdk/
url_resolver.rs

1//! Adapter bridging the SDK's `InternalUrlRouter` port to oxicode-agent's
2//! `UrlResolver` capability.
3//!
4//! When wired into `AgentConfig.url_resolver`, this enables the `read`,
5//! `grep`, and `find` tools to resolve internal protocol URLs (`issue://`,
6//! `pr://`, `memory://`, `skill://`, etc.) through the SDK's port system.
7
8use std::future::Future;
9use std::pin::Pin;
10use std::sync::Arc;
11
12use oxicode_agent::tools::{ResolvedContent, UrlResolver};
13
14use crate::ports::{InternalUrlRouter, ResolveContext};
15
16/// Adapter wrapping the SDK's `InternalUrlRouter` port.
17///
18/// Constructed by the composition root (oxicode-cli's `App::from_oxicode`) and
19/// injected into `AgentConfig.url_resolver` so the agent's `read`/`grep`/
20/// `find` tools can dispatch internal URLs.
21pub struct SdkUrlResolver {
22    router: Arc<dyn InternalUrlRouter>,
23}
24
25impl SdkUrlResolver {
26    /// Create a new adapter wrapping the SDK's URL router port.
27    pub fn new(router: Arc<dyn InternalUrlRouter>) -> Self {
28        Self { router }
29    }
30}
31
32impl std::fmt::Debug for SdkUrlResolver {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("SdkUrlResolver")
35            .field("schemes", &self.router.registered_schemes())
36            .finish()
37    }
38}
39
40impl UrlResolver for SdkUrlResolver {
41    fn can_resolve(&self, input: &str) -> bool {
42        let registered = self.router.registered_schemes();
43        registered
44            .iter()
45            .any(|scheme| input.starts_with(&format!("{}://", scheme)))
46    }
47
48    fn resolve<'a>(
49        &'a self,
50        uri: &'a str,
51    ) -> Pin<Box<dyn Future<Output = Result<ResolvedContent, String>> + Send + 'a>> {
52        Box::pin(async move {
53            let ctx = ResolveContext::default();
54            let resolved = self
55                .router
56                .resolve(uri, &ctx)
57                .await
58                .map_err(|e| e.to_string())?;
59            Ok(ResolvedContent {
60                content: resolved.content,
61                content_type: resolved.content_type,
62                immutable: resolved.immutable,
63            })
64        })
65    }
66}