1use std::sync::Arc;
6
7use sokuto_core::contract::calibration::CalibrationConfig;
8use sokuto_core::gating::GatingConfig;
9use sokuto_runtime::dag::InProcessDagExecutor;
10use sokuto_runtime::engine::{
11 CoarseToFineConfig, DualSessionEngine, InferenceEngine, StateCacheManager,
12};
13use sokuto_runtime::hierarchical::HierarchicalRouterConfig;
14use sokuto_runtime::hierarchical::mapping::HierarchicalMapping;
15use sokuto_runtime::tokenizer::JevTokenizer;
16
17use crate::guardrails::{GuardrailConfig, GuardrailPipeline};
18
19pub const DEFAULT_MAX_QUESTIONS_PER_REQUEST: usize = 128;
21
22pub const DEFAULT_CHUNK_SIZE: usize = 16;
24
25#[derive(Clone)]
27pub struct AppState {
28 pub engine: Arc<InferenceEngine>,
30 pub tokenizer: Arc<JevTokenizer>,
32 pub calib_config: Arc<CalibrationConfig>,
34 pub coarse_config: CoarseToFineConfig,
36 pub max_questions_per_request: usize,
38 pub chunk_size: usize,
40 pub guardrail_pipeline: GuardrailPipeline,
42 pub gating_config: GatingConfig,
44 pub dag_executor: Arc<InProcessDagExecutor>,
46 pub hierarchical_mapping: Option<Arc<HierarchicalMapping>>,
48 pub hierarchical_config: HierarchicalRouterConfig,
50 pub auto_hierarchical: bool,
52 pub dual_engine: Option<Arc<DualSessionEngine>>,
54 pub cache_manager: Option<Arc<StateCacheManager>>,
56}
57
58impl AppState {
59 pub fn new(
66 engine: Arc<InferenceEngine>,
67 tokenizer: Arc<JevTokenizer>,
68 calib_config: Arc<CalibrationConfig>,
69 ) -> Self {
70 let mut guardrail_config = GuardrailConfig::default();
71 guardrail_config.limits.max_questions = DEFAULT_MAX_QUESTIONS_PER_REQUEST;
72 let guardrail_pipeline = GuardrailPipeline::new(guardrail_config);
73
74 let auto_hierarchical = std::env::var("SOKUTO_AUTO_HIERARCHICAL")
75 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
76 .unwrap_or(false);
77
78 let dag_executor = Arc::new(InProcessDagExecutor::new(
79 Arc::clone(&engine),
80 Arc::clone(&tokenizer),
81 (*calib_config).clone(),
82 ));
83
84 Self {
85 engine,
86 tokenizer,
87 calib_config,
88 coarse_config: CoarseToFineConfig::default(),
89 max_questions_per_request: DEFAULT_MAX_QUESTIONS_PER_REQUEST,
90 chunk_size: DEFAULT_CHUNK_SIZE,
91 guardrail_pipeline,
92 gating_config: GatingConfig {
93 enabled: false,
94 ..Default::default()
95 },
96 dag_executor,
97 hierarchical_mapping: None,
98 hierarchical_config: HierarchicalRouterConfig::default(),
99 auto_hierarchical,
100 dual_engine: None,
101 cache_manager: None,
102 }
103 }
104
105 pub fn with_options(
107 engine: Arc<InferenceEngine>,
108 tokenizer: Arc<JevTokenizer>,
109 calib_config: Arc<CalibrationConfig>,
110 coarse_config: CoarseToFineConfig,
111 max_questions_per_request: usize,
112 chunk_size: usize,
113 ) -> Self {
114 let mut guardrail_config = GuardrailConfig::default();
115 guardrail_config.limits.max_questions = max_questions_per_request;
116 let guardrail_pipeline = GuardrailPipeline::new(guardrail_config);
117
118 let auto_hierarchical = std::env::var("SOKUTO_AUTO_HIERARCHICAL")
119 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
120 .unwrap_or(false);
121
122 let dag_executor = Arc::new(InProcessDagExecutor::new(
123 Arc::clone(&engine),
124 Arc::clone(&tokenizer),
125 (*calib_config).clone(),
126 ));
127
128 Self {
129 engine,
130 tokenizer,
131 calib_config,
132 coarse_config,
133 max_questions_per_request,
134 chunk_size: chunk_size.max(1),
135 guardrail_pipeline,
136 gating_config: GatingConfig {
137 enabled: false,
138 ..Default::default()
139 },
140 dag_executor,
141 hierarchical_mapping: None,
142 hierarchical_config: HierarchicalRouterConfig::default(),
143 auto_hierarchical,
144 dual_engine: None,
145 cache_manager: None,
146 }
147 }
148
149 pub fn with_guardrails(
151 engine: Arc<InferenceEngine>,
152 tokenizer: Arc<JevTokenizer>,
153 calib_config: Arc<CalibrationConfig>,
154 coarse_config: CoarseToFineConfig,
155 max_questions_per_request: usize,
156 chunk_size: usize,
157 guardrail_config: GuardrailConfig,
158 ) -> Self {
159 let auto_hierarchical = std::env::var("SOKUTO_AUTO_HIERARCHICAL")
160 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
161 .unwrap_or(false);
162
163 let dag_executor = Arc::new(InProcessDagExecutor::new(
164 Arc::clone(&engine),
165 Arc::clone(&tokenizer),
166 (*calib_config).clone(),
167 ));
168
169 Self {
170 engine,
171 tokenizer,
172 calib_config,
173 coarse_config,
174 max_questions_per_request,
175 chunk_size: chunk_size.max(1),
176 guardrail_pipeline: GuardrailPipeline::new(guardrail_config),
177 gating_config: GatingConfig {
178 enabled: false,
179 ..Default::default()
180 },
181 dag_executor,
182 hierarchical_mapping: None,
183 hierarchical_config: HierarchicalRouterConfig::default(),
184 auto_hierarchical,
185 dual_engine: None,
186 cache_manager: None,
187 }
188 }
189
190 pub fn with_dual_engine(
192 mut self,
193 dual_engine: Arc<DualSessionEngine>,
194 cache_manager: Arc<StateCacheManager>,
195 ) -> Self {
196 self.dual_engine = Some(dual_engine);
197 self.cache_manager = Some(cache_manager);
198 self
199 }
200
201 pub fn with_gating_config(mut self, gating_config: GatingConfig) -> Self {
203 self.gating_config = gating_config;
204 self
205 }
206
207 pub fn with_hierarchical_mapping(mut self, mapping: Arc<HierarchicalMapping>) -> Self {
209 self.hierarchical_mapping = Some(mapping);
210 self
211 }
212
213 pub fn with_hierarchical_config(mut self, config: HierarchicalRouterConfig) -> Self {
215 self.hierarchical_config = config;
216 self
217 }
218
219 pub fn with_auto_hierarchical(mut self, enabled: bool) -> Self {
221 self.auto_hierarchical = enabled;
222 self
223 }
224
225 pub fn with_dag_executor(mut self, executor: Arc<InProcessDagExecutor>) -> Self {
227 self.dag_executor = executor;
228 self
229 }
230
231 pub fn load_hierarchical_mapping_from_dir<P: AsRef<std::path::Path>>(mut self, dir: P) -> Self {
233 let mapping_path = dir.as_ref().join("hierarchical_mapping.json");
234 if mapping_path.exists()
235 && let Ok(content) = std::fs::read_to_string(&mapping_path)
236 {
237 if let Ok(mapping) = serde_json::from_str::<HierarchicalMapping>(&content) {
238 if mapping.validate().is_ok() {
239 tracing::info!("粗密階層マッピングをロードしました: {}", mapping.name);
240 self.hierarchical_mapping = Some(Arc::new(mapping));
241 } else {
242 tracing::warn!("階層マッピングの検証に失敗しました: {:?}", mapping_path);
243 }
244 } else {
245 tracing::warn!(
246 "階層マッピング JSON のパースに失敗しました: {:?}",
247 mapping_path
248 );
249 }
250 }
251
252 self
253 }
254
255 pub fn is_ready(&self) -> bool {
257 self.engine.pool_size() > 0 && self.tokenizer.max_sequence_length() > 0
258 }
259}