Skip to main content

skilllite_agent/
dependency_resolver.rs

1//! LLM-based dependency resolution for skilllite-agent.
2//!
3//! This module extends skilllite-core's dependency_resolver with LLM-based package extraction.
4//! Implements the LlmProvider trait to enable async resolution.
5
6#[cfg(feature = "async-resolve")]
7use skilllite_core::skill::dependency_resolver::{
8    resolve_packages as core_resolve_packages, LlmProvider,
9};
10
11use crate::llm::LlmClient;
12use std::path::Path;
13
14#[cfg(feature = "async-resolve")]
15mod llm_resolver {
16    use super::*;
17    use crate::types::ChatMessage;
18    use async_trait::async_trait;
19
20    /// Implement LlmProvider for skilllite-agent's LlmClient.
21    #[async_trait]
22    impl LlmProvider for LlmClient {
23        async fn extract_packages(&self, model: &str, prompt: &str) -> Option<String> {
24            let messages = vec![ChatMessage::user(prompt)];
25            let resp = self
26                .chat_completion(model, &messages, None, Some(0.0))
27                .await
28                .ok()?;
29            let text = resp.choices.first()?.message.content.as_ref()?.clone();
30            Some(text)
31        }
32    }
33
34    /// Full async resolution: Lock → LLM → Whitelist.
35    pub async fn resolve_packages(
36        skill_dir: &Path,
37        compatibility: Option<&str>,
38        language: &str,
39        llm_client: Option<&LlmClient>,
40        model: Option<&str>,
41        allow_unknown: bool,
42    ) -> anyhow::Result<skilllite_core::skill::dependency_resolver::ResolvedDependencies> {
43        core_resolve_packages(
44            skill_dir,
45            compatibility,
46            language,
47            llm_client,
48            model,
49            allow_unknown,
50        )
51        .await
52    }
53}
54
55#[cfg(not(feature = "async-resolve"))]
56mod llm_resolver {
57    use super::*;
58
59    /// Stub for non-async builds.
60    pub async fn resolve_packages(
61        _skill_dir: &Path,
62        _compatibility: Option<&str>,
63        _language: &str,
64        _llm_client: Option<&LlmClient>,
65        _model: Option<&str>,
66        _allow_unknown: bool,
67    ) -> anyhow::Result<skilllite_core::skill::dependency_resolver::ResolvedDependencies> {
68        anyhow::bail!("async-resolve feature not enabled")
69    }
70}
71
72pub use llm_resolver::resolve_packages;