sqlite_graphrag/extract/llm_embedding/
builder.rs1use super::binary::resolve_real_binary;
4use super::models::{claude_embed_model, codex_embed_model, opencode_embed_model};
5use super::types::EmbeddingFlavour;
6use super::LlmEmbedding;
7use crate::errors::AppError;
8
9#[derive(Clone, Debug)]
16pub struct LlmEmbeddingBuilder {
17 pub(crate) flavour: EmbeddingFlavour,
19 pub(crate) binary_override: Option<std::path::PathBuf>,
21 pub(crate) model_override: Option<String>,
23 pub(crate) timeout_override: Option<std::time::Duration>,
25}
26
27impl LlmEmbeddingBuilder {
28 pub fn claude_default() -> Self {
33 Self {
34 flavour: EmbeddingFlavour::Claude,
35 binary_override: None,
36 model_override: None,
37 timeout_override: None,
38 }
39 }
40
41 pub fn codex_default() -> Self {
44 Self {
45 flavour: EmbeddingFlavour::Codex,
46 binary_override: None,
47 model_override: None,
48 timeout_override: None,
49 }
50 }
51
52 pub fn opencode_default() -> Self {
55 Self {
56 flavour: EmbeddingFlavour::Opencode,
57 binary_override: None,
58 model_override: None,
59 timeout_override: None,
60 }
61 }
62 pub fn override_binary(mut self, binary: std::path::PathBuf) -> Self {
64 self.binary_override = Some(binary);
65 self
66 }
67
68 pub fn override_model(mut self, model: String) -> Self {
70 self.model_override = Some(model);
71 self
72 }
73
74 pub fn override_timeout(mut self, secs: u64) -> Self {
77 let clamped = secs.clamp(1, 3_600);
78 self.timeout_override = Some(std::time::Duration::from_secs(clamped));
79 self
80 }
81
82 pub fn build(self) -> Result<LlmEmbedding, AppError> {
85 LlmEmbedding::oauth_only_enforce()?;
86 let binary = match self.binary_override {
87 Some(path) => resolve_real_binary(&path),
88 None => {
89 let (xdg_bin, which_name) = match self.flavour {
91 EmbeddingFlavour::Codex => (
92 crate::runtime_config::codex_binary(),
93 "codex",
94 ),
95 EmbeddingFlavour::Claude => (
96 crate::runtime_config::claude_binary(),
97 "claude",
98 ),
99 EmbeddingFlavour::Opencode => (
100 crate::runtime_config::opencode_binary(),
101 "opencode",
102 ),
103 };
104 let path = xdg_bin
105 .map(std::path::PathBuf::from)
106 .or_else(|| which::which(which_name).ok())
107 .ok_or_else(|| {
108 AppError::Embedding(
109 crate::i18n::validation::embedding_binary_not_found_on_path(which_name),
110 )
111 })?;
112 resolve_real_binary(&path)
113 }
114 };
115 let model = match self.model_override {
116 Some(m) => m,
117 None => match self.flavour {
118 EmbeddingFlavour::Codex => codex_embed_model(),
119 EmbeddingFlavour::Claude => claude_embed_model(),
120 EmbeddingFlavour::Opencode => opencode_embed_model(),
121 },
122 };
123 Ok(LlmEmbedding::from_parts(
124 self.flavour,
125 binary,
126 model,
127 self.timeout_override,
128 ))
129 }
130}