From 0cfbae5f8fc3423d77795a2b0864570e7634df11 Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Fri, 31 Jul 2026 23:54:52 +0530 Subject: [PATCH 01/25] Format files with Black to pass CI checks --- src/api/main.py | 2 +- src/api/routes/chat.py | 4 +- src/db/models.py | 5 +- src/llm/local_weight_engine.py | 98 ++++++++++++++++++---------------- 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/api/main.py b/src/api/main.py index f88fc83e..cca20708 100644 --- a/src/api/main.py +++ b/src/api/main.py @@ -175,7 +175,7 @@ def create_app() -> FastAPI: app.add_middleware(SecurityHeadersMiddleware) app.add_middleware(RequestSizeLimitMiddleware, max_size=10 * 1024 * 1024) app.add_middleware(TimeoutMiddleware, timeout=60.0) - + # Add CORS middleware app.add_middleware( CORSMiddleware, diff --git a/src/api/routes/chat.py b/src/api/routes/chat.py index c4144f09..4f1a33ab 100644 --- a/src/api/routes/chat.py +++ b/src/api/routes/chat.py @@ -132,7 +132,9 @@ async def chat( @router.post("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/chat/stream") @limiter.limit("20/minute") async def chat_stream( - request: StreamChatRequest, request_obj: Request, current_user: TokenData = Depends(get_current_user) + request: StreamChatRequest, + request_obj: Request, + current_user: TokenData = Depends(get_current_user), ): """Handle streaming chat requests.""" try: diff --git a/src/db/models.py b/src/db/models.py index 57d159b4..37f4479e 100644 --- a/src/db/models.py +++ b/src/db/models.py @@ -2538,14 +2538,13 @@ class SubOrchestrator(Base): # Relationships director: Mapped[DirectorAgent] = relationship(back_populates="sub_orchestrators") current_task: Mapped[SwarmSubTask | None] = relationship( - "SwarmSubTask", - foreign_keys=[current_task_id] + "SwarmSubTask", foreign_keys=[current_task_id] ) assigned_tasks: Mapped[List["SwarmSubTask"]] = relationship( "SwarmSubTask", foreign_keys="[assigned_orchestrator_id]", back_populates="assigned_orchestrator", - cascade="all, delete-orphan" + cascade="all, delete-orphan", ) def __repr__(self) -> str: diff --git a/src/llm/local_weight_engine.py b/src/llm/local_weight_engine.py index dc616e4d..b71eb977 100644 --- a/src/llm/local_weight_engine.py +++ b/src/llm/local_weight_engine.py @@ -28,6 +28,7 @@ @dataclass class ModelLoadConfig: """Configuration for loading a local model""" + model_name_or_path: str device: str = "auto" # "auto", "mps", "cuda", "cpu" torch_dtype: str = "bfloat16" # "bfloat16", "float16", "float32" @@ -41,13 +42,14 @@ class ModelLoadConfig: @dataclass class LoRAConfig: """Configuration for LoRA adapter""" + r: int = 8 lora_alpha: int = 16 target_modules: List[str] = None lora_dropout: float = 0.05 bias: str = "none" task_type: str = "CAUSAL_LM" - + def __post_init__(self): if self.target_modules is None: self.target_modules = ["q_proj", "v_proj", "k_proj", "o_proj"] @@ -56,7 +58,7 @@ def __post_init__(self): class LocalWeightEngine: """ Native PyTorch engine for loading local LLM weights and performing direct inference/fine-tuning. - + Supports: - Qwen2.5-0.5B, Llama-3.2-1B, Phi-3.5-mini, and other HF models - Automatic device selection (MPS for Apple Silicon, CUDA, CPU) @@ -64,7 +66,7 @@ class LocalWeightEngine: - LoRA/PEFT adapters for parameter-efficient fine-tuning - Direct weight manipulation without external API calls """ - + def __init__(self): self._model: Optional[AutoModelForCausalLM] = None self._tokenizer: Optional[AutoTokenizer] = None @@ -73,7 +75,7 @@ def __init__(self): self._model_name: str = "" self._peft_config: Optional[LoRAConfig] = None self._is_peft_model: bool = False - + def _resolve_device(self, device: str) -> torch.device: """Resolve device string to torch.device""" if device == "auto": @@ -84,7 +86,7 @@ def _resolve_device(self, device: str) -> torch.device: else: return torch.device("cpu") return torch.device(device) - + def _resolve_dtype(self, dtype_str: str) -> torch.dtype: """Resolve dtype string to torch.dtype""" dtype_map = { @@ -93,20 +95,22 @@ def _resolve_dtype(self, dtype_str: str) -> torch.dtype: "float32": torch.float32, } return dtype_map.get(dtype_str, torch.bfloat16) - + def load_model(self, config: ModelLoadConfig) -> None: """ Load model and tokenizer directly into PyTorch memory. - + Args: config: ModelLoadConfig with model path and loading options """ self._model_name = config.model_name_or_path self._device = self._resolve_device(config.device) torch_dtype = self._resolve_dtype(config.torch_dtype) - - logger.info(f"Loading model: {config.model_name_or_path} on {self._device} with {config.torch_dtype}") - + + logger.info( + f"Loading model: {config.model_name_or_path} on {self._device} with {config.torch_dtype}" + ) + # Load tokenizer self._tokenizer = AutoTokenizer.from_pretrained( config.model_name_or_path, @@ -114,7 +118,7 @@ def load_model(self, config: ModelLoadConfig) -> None: ) if self._tokenizer.pad_token is None: self._tokenizer.pad_token = self._tokenizer.eos_token - + # Configure quantization if requested quantization_config = config.quantization_config if config.use_4bit and quantization_config is None: @@ -128,7 +132,7 @@ def load_model(self, config: ModelLoadConfig) -> None: quantization_config = BitsAndBytesConfig( load_in_8bit=True, ) - + # Load model self._model = AutoModelForCausalLM.from_pretrained( config.model_name_or_path, @@ -138,11 +142,11 @@ def load_model(self, config: ModelLoadConfig) -> None: quantization_config=quantization_config, trust_remote_code=config.trust_remote_code, ) - + # Move to device if not using device_map if str(self._device) == "cpu" or config.device != "auto": self._model = self._model.to(self._device) - + # Load generation config try: self._generation_config = GenerationConfig.from_pretrained(config.model_name_or_path) @@ -157,22 +161,22 @@ def load_model(self, config: ModelLoadConfig) -> None: pad_token_id=self._tokenizer.pad_token_id, eos_token_id=self._tokenizer.eos_token_id, ) - + self._model.eval() logger.info(f"Model loaded successfully on {self._model.device}") - + def attach_lora(self, lora_config: LoRAConfig) -> None: """ Attach LoRA adapter for parameter-efficient fine-tuning. - + Args: lora_config: LoRAConfig with adapter parameters """ if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") - + self._peft_config = lora_config - + peft_config = LoraConfig( r=lora_config.r, lora_alpha=lora_config.lora_alpha, @@ -181,41 +185,41 @@ def attach_lora(self, lora_config: LoRAConfig) -> None: bias=lora_config.bias, task_type=TaskType.CAUSAL_LM, ) - + self._model = get_peft_model(self._model, peft_config) self._is_peft_model = True self._model.print_trainable_parameters() logger.info("LoRA adapter attached successfully") - + def load_lora_adapter(self, adapter_path: str) -> None: """ Load a saved LoRA adapter from disk. - + Args: adapter_path: Path to the saved adapter directory or .safetensors file """ if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") - + self._model = PeftModel.from_pretrained(self._model, adapter_path) self._is_peft_model = True logger.info(f"Loaded LoRA adapter from {adapter_path}") - + def save_lora_adapter(self, save_path: str) -> None: """ Save the current LoRA adapter to disk. - + Args: save_path: Directory path to save adapter """ if not self._is_peft_model: raise RuntimeError("No LoRA adapter attached. Call attach_lora() first.") - + os.makedirs(save_path, exist_ok=True) self._model.save_pretrained(save_path) self._tokenizer.save_pretrained(save_path) logger.info(f"Saved LoRA adapter to {save_path}") - + def generate( self, prompt: str, @@ -229,7 +233,7 @@ def generate( ) -> str: """ Generate text directly from the loaded model. - + Args: prompt: Input prompt string max_new_tokens: Maximum new tokens to generate @@ -238,16 +242,16 @@ def generate( top_k: Top-k sampling parameter repetition_penalty: Repetition penalty do_sample: Whether to use sampling - + Returns: Generated text string """ if self._model is None or self._tokenizer is None: raise RuntimeError("Model not loaded. Call load_model() first.") - + # Tokenize prompt inputs = self._tokenizer(prompt, return_tensors="pt").to(self._device) - + # Prepare generation config gen_config = self._generation_config gen_config.max_new_tokens = max_new_tokens @@ -258,28 +262,28 @@ def generate( gen_config.do_sample = do_sample and temperature > 0 gen_config.pad_token_id = self._tokenizer.pad_token_id gen_config.eos_token_id = self._tokenizer.eos_token_id - + # Generate with torch.no_grad(): outputs = self._model.generate( **inputs, generation_config=gen_config, ) - + # Decode only new tokens - new_tokens = outputs[0][inputs["input_ids"].shape[1]:] + new_tokens = outputs[0][inputs["input_ids"].shape[1] :] generated_text = self._tokenizer.decode(new_tokens, skip_special_tokens=True) - + return generated_text - + def get_model_info(self) -> Dict[str, Any]: """Get information about the loaded model""" if self._model is None: return {"status": "not_loaded"} - + total_params = sum(p.numel() for p in self._model.parameters()) trainable_params = sum(p.numel() for p in self._model.parameters() if p.requires_grad) - + return { "model_name": self._model_name, "device": str(self._model.device), @@ -289,43 +293,43 @@ def get_model_info(self) -> Dict[str, Any]: "is_peft_model": self._is_peft_model, "peft_config": self._peft_config.__dict__ if self._peft_config else None, } - + def enable_training_mode(self) -> None: """Enable training mode (for fine-tuning)""" if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") self._model.train() - + def enable_eval_mode(self) -> None: """Enable evaluation mode (for inference)""" if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") self._model.eval() - + def get_trainable_parameters(self): """Get trainable parameters for optimizer""" if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") return [p for p in self._model.parameters() if p.requires_grad] - + def forward(self, input_ids: torch.Tensor, labels: torch.Tensor = None, **kwargs): """Direct forward pass for training""" if self._model is None: raise RuntimeError("Model not loaded. Call load_model() first.") return self._model(input_ids=input_ids, labels=labels, **kwargs) - + @property def model(self) -> Optional[AutoModelForCausalLM]: return self._model - + @property def tokenizer(self) -> Optional[AutoTokenizer]: return self._tokenizer - + @property def device(self) -> torch.device: return self._device - + def unload(self) -> None: """Unload model and free memory""" if self._model is not None: @@ -341,4 +345,4 @@ def unload(self) -> None: torch.cuda.empty_cache() elif torch.backends.mps.is_available(): torch.mps.empty_cache() - logger.info("Model unloaded, memory freed") \ No newline at end of file + logger.info("Model unloaded, memory freed") From fee6ff8cbeed75944c8a31bde6c4e02c5ec16c50 Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:03:49 +0530 Subject: [PATCH 02/25] chore: remove tracked pycache compiled files from repository --- src/__pycache__/main.cpython-314.pyc | Bin 3392 -> 0 bytes .../__pycache__/free_api_client.cpython-314.pyc | Bin 28130 -> 0 bytes .../learning_chatbot.cpython-314.pyc | Bin 30402 -> 0 bytes .../__pycache__/web_crawler.cpython-314.pyc | Bin 22727 -> 0 bytes .../knowledge_integrator.cpython-314.pyc | Bin 49031 -> 0 bytes .../continuous_learner.cpython-314.pyc | Bin 37856 -> 0 bytes src/llm/__pycache__/__init__.cpython-314.pyc | Bin 980 -> 0 bytes .../conversation_manager.cpython-314.pyc | Bin 25115 -> 0 bytes .../__pycache__/deepseek_client.cpython-314.pyc | Bin 19422 -> 0 bytes src/llm/__pycache__/rag_service.cpython-314.pyc | Bin 18473 -> 0 bytes .../content_processor.cpython-314.pyc | Bin 31910 -> 0 bytes 11 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/__pycache__/main.cpython-314.pyc delete mode 100644 src/api/__pycache__/free_api_client.cpython-314.pyc delete mode 100644 src/chatbot/__pycache__/learning_chatbot.cpython-314.pyc delete mode 100644 src/crawler/__pycache__/web_crawler.cpython-314.pyc delete mode 100644 src/knowledge/__pycache__/knowledge_integrator.cpython-314.pyc delete mode 100644 src/learning/__pycache__/continuous_learner.cpython-314.pyc delete mode 100644 src/llm/__pycache__/__init__.cpython-314.pyc delete mode 100644 src/llm/__pycache__/conversation_manager.cpython-314.pyc delete mode 100644 src/llm/__pycache__/deepseek_client.cpython-314.pyc delete mode 100644 src/llm/__pycache__/rag_service.cpython-314.pyc delete mode 100644 src/processor/__pycache__/content_processor.cpython-314.pyc diff --git a/src/__pycache__/main.cpython-314.pyc b/src/__pycache__/main.cpython-314.pyc deleted file mode 100644 index 72adbb7d50bf02abd8fd64aa98811eff4bb1622d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3392 zcmZ`*Uu+Y}8K3p;+8cXq$N57@2=O}q4a6KY1zITW9Z5(U;CzOnJ~*s4_Qot-dwsKG zNZj^ht`FRCmB_UZy@z{9rAoAKRI1eX9>;S`(mI+;Ris`Y`j#9>t<*~GH*2qBjxf^B zeEZG!&3yBHzxlp78VdRmwEz7$b?cOb(BIjQ+q@0pc?XA31*H%{H&BY3;|S-B9^!FE zp71bw=7d?1h*7j4#?XRy5_DKghU#N$zaNiC3w*MpRjN)WyIZdsJ2c(C1=MyG;*P-eu*uwV;XV@n1`t)BbRA}#yJ@T9q|YW z&lB|^b44!Q^hL7a*d_yr7`l#PR>+z| zxw9rmpUTlSsivH$DkmPz{aN|WhJ1dTO~jtcvEK|mJo4)!8}h`C$anbv<@1T&=dc0F zu+D8hAb!TsdQbQA6FRW71*BaR5L?8Y~W(oIw+_rWaSq={5lr^sFBk}ZgH z%}8-@NA|&|3nb@xIDbUk~zY36&UfpnKk?~TAcu=nRu zz&+^Fdn0fmL4LiZgwqXA6+P+0?(FrZ4MqMCy3Qw~?#$lkM&KeO<697eWv;?s68#XT z*POUnMxy8tN-OS4$w8Oe8)N7O=X&AQ_2**<`Ou|P@JR|v54(C^l>HvdS5b6r|425A z3`p=vH_5r`Fursq@JsznKEzJ-nl;;8JEQ0@cwz{po8<@WIm7HJ3ZQ$mWt#?>@?R5J zyi>kZ;B>R>rH{Fi$%ISojjf)k?^qPRE3kc2BBKn>Kxg^G$l$)o8(ds2_d8{*HKFNF z87s0fR&KjWpysivRrV;i%ONOhxAY8Auw{{ND{+B#=e1=uV-+$bj6qS&VC{}+({^W6 zu|{;&H1Y)(+NUr>e12 z>&of%_A{Hpw_xd>k*$Hz+Q7N$z`3p7SgrSDwfE#!-(an8vf4MJUOFWOO9 zSqpE3-l$yM5!%JBXQA#|Xt)|0-UyA>q|tS0^qCZT5cn{#-Zix;P49S7xO2Os_g53Y zm{{XBItFX<;8S^UH;CHCc4ZVC`uCTC{uhWB<6ExU=%zHb#a11vhK4pmBQ+fv|xbYEJHJP6zm{AWi5$^Y6* z;M(`!Iy=+L{poz?l#D)$a8r`-S;ujpA9LK4UwG{CG1||uUOql^fPZ|Jn>z1(eC`0y zpLg(}`+2v-=mC!P(PJ|a{zX1sfPY357(I}g7 zQO86YuiH9)0k7;9)b9v;J2-g53fqQ;`gqjPu@jr;>0`y0CamDkUCzv>&~x^}K{NRU4$Z}PocLg3!~`|}?Qzx4h^=-K6w I(C1k7f85s6Z2$lO diff --git a/src/api/__pycache__/free_api_client.cpython-314.pyc b/src/api/__pycache__/free_api_client.cpython-314.pyc deleted file mode 100644 index e5487badcf39c793db7fa7dd920ca0f9090cff8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28130 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 diff --git a/src/chatbot/__pycache__/learning_chatbot.cpython-314.pyc b/src/chatbot/__pycache__/learning_chatbot.cpython-314.pyc deleted file mode 100644 index 3ca4f3e6cd2c5e914faa8c3d76782fc517064cbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30402 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�Mndj5aN;^K0(p%C2NxrGml9x%_v>`G3R}pG5 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 diff --git a/src/knowledge/__pycache__/knowledge_integrator.cpython-314.pyc b/src/knowledge/__pycache__/knowledge_integrator.cpython-314.pyc deleted file mode 100644 index 50983b5bb7c75f9dae3ad61851c4b398cd22b931..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49031 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 Qi@Tm>Jy;}M_wWe+KRmh0F8}}l diff --git a/src/learning/__pycache__/continuous_learner.cpython-314.pyc b/src/learning/__pycache__/continuous_learner.cpython-314.pyc deleted file mode 100644 index d6492705d786570b629c144c17b8dced76f0df9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37856 zcmdVD3shX!nI?Kpy{H#d0REwPvkB zl6z!#yl(FI?^Ea0gM;KwdS=!fiCz2b_c>?pZ~y*5Fq&s2$LSbp!gae!vhm4CI7!28>~&o6>3r zO#`N|X}}ydvwPj3WxyJ?4&;V&**!m)7tUj4*}^vVYY*G;s~^lCCFa8 z4o=NZ&xTU52TzB>fm7zk{8RoDfsiMBGT<3cC7YBBnF-DWCWBJ}&+%zNN+gxqY#wgZ zi@N>6P*~LU2gk#rwrA?JXncGo9Gsr=Pm0=ufpDWnG*0-#fpG9tKs1p%5tt175o|)R ze|*v(3W)}PXae~gc~Ljw51(w*ismN*$NB{SOOpXXH2V%7l>HXw@dZM&la$=DCpZ~M z#^E;asp;86v&WPWjcBLm4orndgz51>C^RjI_M|s3k&HsV!l9{YR5fuTFo@JA1b=v1 zKydCJArR;p8SI-3qKNV2cVj=vZ^_+%4!3^v>SwqxkDjeLS{Bw8bJOVGVck)4Sbvlc z8+@8@j!zpl`gCEFPaih>3}K5eCv5c@!@2m&!=DX*cKqf0OeI{nV3ga$`^+WWq%mCR zvxFU^T)4<*#CNuedGg0a^N$BlL~5nqSu`4NoqeP6)gLkV_gaoSv58&r?h{{sldd0i z2b<7UgZ4Z)XAbb(@OZN4D$j^q#{2&bw`aIfZiEGAI>#~YU0gH9+T;8vH>E@(wfv5h zFpg7F8(3b;H6OW z@t_bm<_`se(=6$W8(SzCeJL0SH9r@co{E^7TV`h_r~MP5h`qUm20+X6a@T9rM{4C# zj|T!1q2^=9#)BxSdG>i$P>T=>HNSjnGEyTaqk!?LDOMZ&ErE$3b%JL2BaLz*sVpHd z8x9Caj%P^vTf);b!)Rc{B_|CB#!rq5vs2?ISvtzu5~-A9UwY}K=9ln@6RAj4)M$v< z15=229xyQx^fylnCnDz58;j(JFwCEyelZ{%pPYV)@Z<~K|PUTh9eM~cJK zFZqRu5WSSpI0oE!fZ~BLCe$*AGb0EDqwVKQ_X@Dc(%hN#=siPa%tyhR4NmeiOTV_^ZIdFHg3J2o~m z9SV;Hr-I?JG0~Md_L?(d+fZug44gCEvc>lL&ewL{uvFdC7%KDT`oBE9V&|;(gry>8 zskmXOy{E~kM(~oga-|?W{Eoe4*}iv0ua#rXEY=gVcy3r4mTNag+xny4-ITNHj>VR+ zxMCL94U2c#Q$5#z%UW?)%UNshqYWGz$@2K39!}%oz5yX!JdNd}nr&a=xCw;1xC8u2 zzJ)u;Kh1S&e0&`eCjFW;zc%UTkw%y1*Qcd1r1^8w{KlkTgL1V^WvC!|p)Auw;>-_; zvpgiu`jEI>io+Ps`vu{NSaiz&@)$n;_^cpcWRI~9hOQ)aG=OSgY%+K%7#8y<{K3i7 zQoI~=DmXRv!mNKX7(P7~8lM&dVj%?yfyuy&esthuV1W?uPma;thmM3%_#);;+sSG4 z$Bhm8A&>WN5#5w=r7lWVPB$*DxHP77 z->smVO0LLBH*UJ|a(2i0zJGI?0%|Fsj&nHQ)P8L{RbEd44QT<56tIpfDSva**Mc!! z-QD#R(8Lv%oDY4i5e>Pw0Rcia9-~n&y-4;-+1q4qn7z_s(Kt3X<;V9K6U}2|r=}-n z0VHGew&?RFV{Bt%K=@FYXrZZTMCXhFiN?pqgj$p@P`?uD$!Q>`k(_nptS6_5oVC8G z;6bdIpZ0Bz1B6jS5k4QjRd9UF9}Ww_W5Dnbf{{}Bz~h0*$+5A^ywHj=7_{wTpIRuU z8p&Z_@)$h$l4rQT)3w~Gs)_1Kmt7T6onyJ8Dyl15F>oG)6)jhJqq-8@xvQhP;^lJp zna7vQ+-HUn;_{psTz1!-c}#Mu>nL+&^_l(mbd~y=2d#L|U*y=EW|fYkKINhwNZ0)@ zz{#MN4yI8{9H=EOY`|X*{*3rD;m-`}$pY%hir-wH4%AT|qmJ~9I=^z~y-Fa5FIRfz`oHox;d~8y z+3Gm|9c23rah~P^8RyBbhVwk|T$6?8GVW`UN5*{}(&@9(G2F*DGYeicRxAhulqT6c zEn#e6Ld*}%juX{>e0EaC<$Ri_38(P^DGI4<3I#RhpO`>^eF8LAa2yZ^vSE653I)mE zeJq4LppZgh0T_?4G}WU&FmM)&{2)@m3T0xt(2Mpp8iWn_5r~%+a>!{WhdQ><0;f?U zY$QJ$gcO##rhqH0ddGRwxh|$_l_A+xML5YIxtPl@I)CtMrkKuiuLS9((c6Q@ zG!_Wd^Mx(sY$d0ioNeUnCT9;hd&wCfXONtIWCoIj;FPLJA;csP5GMG;o@rtHWB>#VjaTzafny#< zdSOsDv8)*Egw{0JS(txn!lR6M50Oj6uM^i}&cH$%grIJ@`yM#zSm-1C;#x?4qLEO@ z0C)jY-N>^!?BRpDa@7-O4D9DoZO8%VlQY}{&Y|CWmz+0$oBc@8O-+<9YAXJ$_Ya{@ zp5dObr&#GD6vr-Ebd=5v`-tsUQuv5b*2(GF9YGem*quSXJ7SZ4X{9QR@{vN7Sg`ui zb)-c0rRBBCVMmC%Vpm!$L=4h(gy>LqrN!Fiux79(Q~C1U5hASEm6ld%*%6|%*fl~V zR@UXy%3?S-gp2sZx=6(!*tj6b^~h>LS3uY^97+469yVnJ1oSXD&qQOfZ~(P1tP=G^ zn1w`hFf;~^nWSxEt}@Mlg?(PMpfe}uGC{Nu6U%ybKoIEFi&n<1%0cu7M4Qa6%Axco z#Oyh5S`g?Rhz?~KFfKw8TL}(U&~Zqv#)vx}XR<5Nt~Bi=$f0TBw5SaQ!eX9(JRE!x zd;L~gp^)bVL_|4J0bo;gH)wXRNLB0wxB8R9avF(AdU{{K73b%wiB z?E13hc2V`e9h=jA*$jdbKQ<7abGjvC86z#p=LEUQes8<#zwsFPN^iS2#N93Ab=|IN zjaO|VZ{=-od)&L7yj8c|P2YHx#iN*Z7FKb)Vg0|;Q&{=WjCrqHUb93Un{OGnq^Kpd ziCr{IzDPrkI!ZO?MoS?pN=Byt)F*EyK#jS$Bg(KHQHEA3wU5v2c0MgSv=W_`mxze0 z%co1_J)#W75oOq=l2=hnb5r-SPaY<6IjCEy2RW31C8y^&Ifpy_xs*JqbUwXYrZk+k zXoEaNKeZrSh49*hCKdB@WT_QJ;`A+d??~(rC>Q%}R(?sjZnXfrB#lJ-PAsP<9ps@haQ1|QIbKSSC z1+NdkHXJSAwq)J@k+tAXStSjN+j5`XvSi%)v4N|sO;l{WQL*ugBhlI)YweG>?ul3I zrS455$CR5e*2avrOU8Pov$x(dwtX5RoIl%J-0S2s7#pR}ult;R{sg8L7o^#cjMCJC zQl$&MNf`%n7{@6i1;nt6`lw18wNaDmh2?AH+KVb)_MicWy6U#Z#DU}5Oq}C|3 zlal?{YYpR9e&g0CwAydj8seMM-;F}$jVLr+s)qE*&!-2yW`Oi23CSKAl2hPMNFEwb zW#>48HY)c%ai2u+e~xdVGJ(rbB)`QPPS}M48?|hp3Mb(g3nAi_CAuXBq<3G>#ZJ{!k8FtG>b<0PSj&fQ8+EJ7VA*7m=g+& zPftyRM9su>n)Fy@PB<>f5}%`7>pp)k`xZUGAHYGM0*ztHe?9Ma^Uj6ec;);niIOd` zk}YxL)`W3q%(ydQ?1>qBZd?04)@n@VkIh+W+hQecapR_hu`_1ulycm*?ovjngj@>h}VpKNqPEd6kPRPbX?=P-IEy36BdFnj6?fDuBf@G@WN3h6Boc@WBZv%zFabf)N9~y5k0=N~qVV0R#`rXccq`YY zk!!#_@~GBy$!S?@@N5!cl*18eRDssa@ZJ2-SE*g(3-TG{j5bohWHWMK_YfgG9C0$@ z11xU}XDOn?(`b|kmsikcu(GpLV>4KGB|4i?FZ$4AATT4EcE3CxV9Fm7F|G%zJ1tz6 z*hrBNgoqlf^GJO*NJXj8&I)NWMpgegQiTLKjC{!}czycy>AC3@jVZU`XLe`8?!966 zF4^nQiAyTqIQ9FdF80QY>l60+8}@n#M{Si@oyu?ca8bS~MuZWmXiXGGp#uIQ2Wvk=WAXA64W{2w&;*ti89-;=9b(Cf%=(jj;umnXl? z((BSLl(qJjXs=oL-aNxKtDgM%2Bf)GqDSmCmlpmEI)>Og)}#LtFGcFnY4ep9u~}C- zW66kQmHvDjGb|WXg?*FfG7#C^g{BEyqY0W0)}^qDvW zB+<<1yY(bNlYCi7Vu-Z(Knrc4)$J5&92cffd7!rCVQL#5lG&0($^&JpP^41f_KAwh z%n4>6VmOr&p$alH834QA;fdHiLFlc8WU+8yB2u9M*XkmHUe+{z>PbAVK%x`TF3ID@ zQtBl|68MZ!^WjJ$G$;eet4*XRK&wxpLy@=z#uOMBF@X}6D&m68OU5lLx^mObJGR1v%^kD3Z`kT@*KGKsu5-F2yXQ_x zd7`9V`X4W;zvFF4c(=#A+vDEOL}lkW3xp80jS270n0IH~yDL$-iv_vY-K=b9zV$7M zb=|Rb-B&H~b^8|24edx8JXxX;!7e;ps$G1No-8K>(c{b|w-?AQqR)DkN?s&$Rp$7*gxxj=cDfy3-E1)d#b4q%K$mQ9Eq`~n& z=6VkM_J^cpJ795{g2h=S0f@~hAO@R7&{R$vl31rm8lU`aiefu)3%FXL9MR>4ZCp$g^sGo%as08R!_wk{dlR&=?h z&O4+`EW1?{5T>sB)h0As85_MZ+bz855<8@sLPuIEJ<#o+T=*x|-8%}tK z0ewuAmJNK%c1IHSb}ZTZe+Fz~V7KMZ#^=3%8ocuK)!e9a_?GqYyZM}>706b#<0J3z zNA})Nz>Z0P)~Nv6mMi`%2cxCi6V{F!)(!?}ou7qH<5|uY_qFkF7WVPnclqA!x<9eN z_kjZr$k^Ua-9ny|{B?Zq4&6dM^LO*T-MVXBJHoHEYmocecAos5%-zA}QWgW=JJSm}m% zX-lH8<)0ak(x|m~acjcf8nw477`6G&4$eFN^r2!K6cAGe7A&iY)r!_=rHBC zeS#$e38*?0pxS)pz?Hse>9&M*`wi=M22>rNg$VS|7WZ2TsLBCUefb1bMAW1ux*{MWz)iJ?`s9ZEb7Mwoda`okR$+@h%{PfL+?aaSgVy4I!o>a)aX2_uc zBq%WZQd_IAb9)YQ+>B-|S%WG$mrk5zEZ2dX=T*r$g*aoxm?Ak#wNOPUY9mWVcUnSyQB!!m`VpNTgz;*=N~nUB07L)l{ABiH5JV)A=~dD8Uil^O(ukA zDMAbFMu`IQQ;sjeflf2i&^S-=M&h*zq@Y#8$eyD#D1ch0(O zFHe#-T}$?jjL@lx*=rzVi`nZh8E@HJv3ywCj7<>s@~E-wu8s2y@dOu+3R*}Ut9Kp$c4g02&0q07n+^YIBYX?Z1_Ul_ z#(JY>VXLLLUVn`*@2%Efb5Z!UYCVP2YvKRr8|lJ3XpHbja2`FdT^R$rmRjmj2X?S=3(pl0F$RU z?j^KX*gUGkm}HlvTQCI52C$TqRTXYiVz?Ros6HzfR!Y`@lr&8hl>0d$1=-9zsj;*u}=D2@x~i9=?DCUOxbR^&bArNueMAoGx9kue<@g$4sH$ zA>@CE*w2vm4C-P(L*}!y1q4I4fy%`K0(`6Z${kG71hF0@eN47DGkXkL*G$AGDRxdw zPt}J#Lg0m2?8x%?XR*H&QYz?WLs@fJ)RE{bQnV)!rbS*EE~WA!<}`7kTcXrtVkoUf zk|r|g9wZFV;5kl3jWHn_1dfp4$wm~gl7XL9>9QL3>LnDc`!X*@# zq5`u>IcRZ6l013>8D-B=6AThJE#}BITa$Ros*re6>gSRGFDb$MUCLRnLIkoW&XPqk z#IOK16hI~ta2LN!V!HLx|9HuICZ^jK^KMIc55&9&;@*Ra%7aWE*RUy3zb#h3?N)uq z`Nz-g`Dsbz`InaK*C*-+V)X+*ERNSdb;0`6^7=QsmRwHbLbZ5fa9kq7f zv6W%A_~l9tk4OJ3^e*1uS#5s@|F50>ChnVjU!C!7Eqvdq>}%35aC~2bae-%kZ!v{* z_Y~o0(E-wrTXge%>vW4A9r?W)6tY;ylOKd6(yU|tCPTl$wAjY?ZOL2QWG4Sk4czM- z<+`q;T-Oa$<8_mzzg>IX;p}hIUPms3x9KUQotl?1$xuIF z(E@|94C>RiX=ik!yid0c1knVx41jOfjG*%D%clpX0t@LvKEoQRa?(?wZ0#E9j94g2 zmNuh%?EggzOsoZ4sRcgMsD}12OhCd&?eUq?-}sF7vH#0wPNu+4AEdV=?~0S@&FSgU zS}V%1WQI}O9{Xd|o6G9O42N>^)@ZFQ{i%HRHB#lLr)txo{0Pb~VC6fcmZ`qkf>b`_ zc@}vJS)TQ*O^!8cD@^6W6BezJsyHK6Nt+%uw4eqjtD%wAP`XCmvW&dtYov0er=q7G z)hcr*`WxPAMGcoys~^>^QH~xIhKjt&SLt)hJw=Ufk*Op(%_w@D&*Q7|RkxG;3s(&X zHicL;b}3R6eM)sejqUN(s4UM_u;n>CkB|9M^K_#((ui3Fx+P(nl$9AaJniWtp2f!| zCE6B8dq%lPzP!(yX7df0+creZ%_jm_Ou~}ZglJNBc#HaQFbu;C-$vub9Iz+?w8%v* zaUQzork@W$H6BbZ)B$E_CpqnwjA&tjLe#%7I~@*)d^N+Ph_0Ff4MZ2fEQ7&6@nUd1 zAR3uQIyTfs%sr%=4j)$hjGl%=r)L5k9#I#@ugEuw2JDA?G3bw&56ois2uKP<8ed5I zBPLJJROqFEfWSO#%%vUS*mOl9!y-Q>@}8s#gkN-nubK&Baqd6iX@u{SLue@)PX)q$ z+KVpcX72E{NOSxcwIfm~(I%Mg=`|B~m-ePXn&gOD2)P-XFXjk=nMpqcL#&c7QcZqx zz62+^IG93f(Hh2!l_?mhag33p4pdi11cW5hejoQ@vkLV<#0lEPHp^wvItZ`&AP48+V(4<`Sz=wH#;AX zc8o-84xHQn2^G@5lwZAEReiDjz0P+!FP)yRj@RsnR_~mjxZ3`M&V|k&z8rn(>3H9f zXzw#o_tEoK%Cc=Kzh>E8_x3AqzH({X6<^%FO$zT=%CB9nT7PNp_l7PH&6}_G#+&v= z*AM*A7(MW0;=qyEfg{mp#-o7~@dGELBf)6!xv2a3v=UWvnxej^6250*zGtFGr=l}L z+!u--2uIzs=d3?3bbnM*4#gCQd)ZMUzn=O_TfevS^3M61`A~d)Ut;}WZ2e$-{ZPDk z|FYA&TmLJMu5ubMB6mhM=x?)*t%32CdC zoc|ailJso<*4-W4_0FAeKkTsVY0&5pO~0;HK$AT35JRFK2b=LiVW6Z%&*@h3u}JunsBL@Hxc$=*eT=iU^_ev6Z{CT71j>DM?|Ckx_t^BC?{aY7319B}_G#u_-Ft|> zX1(Wc;E{XJKT!Y*T4V+mF-9RAY)k(7G;LZbgy__y56V2vL}jQ_3n_&q2rKd0C1Isc zzlJC_Ng<%o%BA#Js6=PPBu5#A$*buL}1bBPAY&WdOvqc&{$gLQ+{d9qxk}AAWOw9b9)e4Sbkya1#B>=SuQ9e-^KcO#;P*^oH>YR%IGe$27 z>kZml_9j@)aJnAka1JjD0esj?=JKE^?C^e6-1k5$1tTV=M1B@}77aezQ`P6?7iysH zU|jHO$zSj8%h6vm@O@h2wVVd>w^$H#lX?z`v;F5x%JB$)98Bt1>NO4bz^t zm}e$`sfOHg6Jj%Hv;PTrgzYPYB*NFp`4$`i6b(oQMFOqoKY9}WJ;EdEE)0(xdJk=7 z_as4Rh5SGA#vUKLx$jvPu^N%+x!9EaYzmPSH8E*1pc%v&jmpECSxqxHtJ%{;Q!v2(?wotah=E_yH0VjQrf@S}rV_8-%7ob<2IN)@A;vs`=cD%eJC~ zttMuxxfp)$m3LlA)c42m-`0;Yo?AG#=befbEoUlS;gB9EP*b0%-WIFgmZ%<%RS!oW zAB$H%n{YiFHI|}S?-r@pn#~t-mTkoeTV2dncgg#`^_SNt)(yt+-!@3aI_CDqYBr~p z3-v5d)ad^7UIl7_Vrqq-|MZ>#{!c^O(fYHt-e&%MeQ&kyuMBV&v>x08VtVU!3tl7n zo9cTTb=RB*ax2XUxz?zMn*kOy>CoS=rIvs}&tQQ*6Z{MjJ|7soLts#bYzz!4^jNNh z^Fe>C=fKS_AG>)709-{)Ns=TB0BEOiIqXR$C+B&ZoS}G5s{N=e`%(h{B4g>A*v90W zpF5wLq;FKKM)qWEy}`Se_avj0skKd6x~j5eB7=kovDHtKhi6@#yc$Vzly6GYSe?~O zDP&pN8ee`^QMiR20__NW+N>*c-EZhGll+NBev1-p(pOpI3lwD)h}#Su-E2}wbww7> z3ORZ9b%b~mcBM+pdU}Q6qZR@L7xA|lvQ_Gt>`IfZDrzAkkkDseKAnnem1nY5l#JC0 zY=TJ1R+;=j9~l}TRz&wi zDh|Si<_t*@Q%Ph~RuF7X2@@m?^HbX!gaL~B3OSg%Go_V;8e;Boh$OA<9oSZ|PO zP1~`+Ry-v-@ynE}PK8dCZTX~asbDCR2dI&d-h+MXD>^6kD!3}=9{X{5)481G(#ms& z<-(FgVNL+;b@3C8ZMRGaLPbrS+y`^G!#~ZAaM~L+6L0)!kQf zevrG6JO66b^Y|^t2rO#3HasZi9919Li;00PNffM)6|7GbbjAug=O2p~>`PepMXmb~ z2QGErYq+huVXgaa&81WEbzL{D*mh6{tA~{*`MXXomlR)Qh2BT)P&kfvc-FGJlK)Ci zN&g0Jp_cD&G%VCv$lumegP+A>4WbvFmE_;b_pjG2wr_<0dOd|-Z{*3pp1B(=yUVrL zw>ftgYd^Fb5c^@V9w8r=YvIqBYyM{wrqrQ?zlZZ^V)QD_Kai$K^Unr7c7AZ=Uf%q^ z<>vaX6?PLla5y%4{N{lZQk*m)(PSxK1PQpe-q!&}&#VD)04EhX^9a2RcBMGXEO0^- zlPOduA(X3tx15sW(#r)!iCuY&4n|8~*pvy%L!cQ)wV(>^5@>@GRJ7@`TB1C&I*6ks zBrV9g(psYE+hvujle4T@uFAx=Y6?@{WZEuS1+3*7I4-qYSG~3=1#JX(NAPR zY8Rdl78^!2c4gn9JejLLtunoU3|Wf=!9<^Zskcv!8^F6rdqYjio4}XVf%Q?Y&tGCw zTAS5#O(`{k%+k}lU@{N`_!Sl9pi#q!Q)!0ck>46bnjWe5wQw^zqxxi7#?hRSawW0i z8HG_#c~KNku7pF?>*YG!$z>f;CTNtS*b7S~mls%luy^5u!SD8D|Mq1VnOx)PF{FgPC#|n48>oE7v`}TdlG*}VZ%#vzKOP~HKkLds5i_YW$XGK00uSRyzU7WUC@x)3 zDvEY;Z+MJv=34YK7QBaba;ntt$cB_(_KjNPyx6p$^nUgHa>}C<+rA3&9(|Q<=uoN2 zXZ1lx3X(>JIQ3aT#NjW=BWr__kA1bIUo&G4a*er>vcqf>r?Q`b>`WzX$g;^$ZaU2g zoA7rZd`6O)ImGS3w|*giL{5|T`!aV%kI@1Wocasdi6tUZ*o7o8-W#PKji_nfDDvYW zDmuBUBbvHs4gTdBVW-%pLNulCI88GiBIo(fG))ph5djsg7>u|Z5Ko%rb z1fV5=OCq~z7oDhLEh=NrGNY=VKo2;>-7#8UH@{|veX$$H+V2)#dM4i3dDDphwaaph z_lD8?UF`?C@ur~w zjR?HmuWXa}j92c1 zd!_a5SKoRSo>=9+Wve66vg@l8Z*95|`9}9r@%pRBRxAdmdCrQX3dpWpMa)={FnVJ~ z@5Lk7`iRG|+UCLun>S|j#x1p%v`d!t%kp;cdGCB})VqrgA*jOBTbn+;caY~c?B_qd zzm=;Uh1@HTa}V)M17N{w8fvpHlo{auFh6&w-SDFp$Iy;~40NTr;EP0=r)0&%-b$C6 zYC6_m2$gWTAwa?mLg1ElJxp0kb#t&<87cxDd1h8EBaI%Do3nO$+Q#Q|1elG}t=+k??XN@1&rpv#lCg-tSB6mch`NHDP~ zmTeC%RyNb6#X}@vOp`7!;e>r0O3hQVGh@?}6AY}xylEJWIR%TX5IIZ)UWOe;%yqz3 zWi#$r(qL&y{2=@*ypHraQurnUR7DCZ`||!fO*VwPG$Sfj5Xjo%iq2wczf({wbMalV zg06T0RE~E>tvfUL`;J&aN4x;+dso!jm5gbL6|}?)S`*gR8`f5=DCKrz8(i)Va@s!m znaxRt2ig@Kp4KZ>SD?eQC1Krq!@8Aie{26NbPUZpTMP;Bn-x7fxc|WSwCnz&3cdv= z-?Lq}P+CI%jeHNb>$d91zeR(@3++7lw==hsxjQVq>$TU6&fYrhHID&luGQ%&WW5&t zjB!T2lZ~@BpuQxMh1I0wNTOX&@~E0Y?|IZ3v7DBSo~rS-K3zr$3crRnBrl}|{Sjr{ zpe$t!$mvqn`an}FyyA#G6)*czT%+2~FL@+_YSkQ3s70t3<;Z*rR-<`l8Ast5XS7EY zVWk>xRK-0}b5xTOLHdmCNgRQt7Zd%HSBgRNy5x4M@j0NwvqrMdRKwBckosgc75gvi zl#L)BxoibFbZPaea2P&|$~Ilo3>g?ey*}p45`tPI?%iy_rs(D5fb~H9NhXdXMe^1S zc__29kQf~%=E$S_0NTnHoke>R0LY?@MC9==(cvb94=}xwGZ8rM$6^zXXxcBIP$t(X z<-~3hR2`|7KuHQC?2?<|NhSwC6$sSJ1R^UXx{#4+tSt_V0oEYN+`pY}3*m^mY3vh$ zrYp{K5_J=^r)DITdOwvx12_d#$?bWfHCZ8!519;zmgMs>8*s-*%CRitLnEtyw- z6#0#E7`&m6P&t9xiZ0*O$KNh@M?LNF@@;ebfl&F*w~8<7-ZQ^rj+cTcDZQ{cQNA%& zjxBl4x9ToB-Yb8nJYKe8+3tDQdoi4-?}*iR#H%}(?bYuNy!ZIG9*=vsB)r`*Z+G0= z11h0BZ*J&gJ6BMAZt`MZBEMlNzu{8PZO~Sx-#1-YeeK+m9uq0N{2&zFg-qJpA zz4F^p=bl^Ey;y%QXhgnWDgsZmSGLKrW8Oax69zpAYwrzfFN4NDZ1Nxy{Vc4Y@L%e+ z_0@6L3M=~x_19WG@Gs_T5WZMw>8mj2* z_WgrbjDLb9HQY)%%Uj zco;O3AdE&#*5$ML^gMQ9_;L`h0@yNSO+YZj7?pL_fx3zXyp}R6zb=&<+s@ zH{!@@EN<0=U2SzFD;?AY}r7jXVnMr`mN?*~^kH!oxlh^;(IE z%(@;~tBN3RjaqSFg<3Bf@nltr+eg-_($Y0*#i1CgwN|gLwMEwg1qhJH|2JEUvq$Ro zCbueJ0S=fPz-Ge`OxveWAL{p@D{+Ke@}w^k>x7tDL(!3G24CW|N$+7CGmdg*%&=&q zqNj2C69Sp_{~Ss3AYiY9q-ue!21n3Xu~0$i!13cjcAVX5(V9HZW{i}w(2%5d{^?*~ zGUFJVWI)zwG{OHt@{5AB$?7m_l7tw~l8?<@q~ayoNdHn&yON%gsdqRiG}%tfhteZR z%{5V!l$7Klq84go0+W#t>`H5Z`^iUw*))ldSV$R_XHC9h6?0@N$r$==1hBC=3-g5Q zt#Ky%yrSo!)yd1tJ=bE$ks^oggj5&goUM8&39#im5XK&)aQUa@c4 zUUz9C(Y!a-yf@K&Al7^!-h438aBw9@=g9*%o?E?auaxFY*z<{by1pN}y7>nk3mu8R zXJdWOMvslhyC-gXAX9K-0xf%|EK#*1R<+~0_Gv*RlQL`gfqn@fJJyl<xwE|+_VE0*7JhfP z=i0_TJ8m+jHCkC>(;9uYE}qHpvX1hOKcdg2$&Ut{ zbg9b)(&WktH-qhIP~?^;#iYbQnE>VTunME(z?7g(pAwkfn2IbQrK+$h$LBFnmQe@W znxCfbA-5~tK$%a6Y0;4Oj49cF`Z|H~tQqSBsZdkOkQtp}G^$luA|094w;4P*_3wY4l?36JRKaI(GUOw_LV%hTa_Q+)_?>)u zm34$|G;oQCV(SQXzSyn<^R4f_`khzfyAFIR@OUDb--7YrHC}3mXOFbmE!`aFSE#|H zI-F%xNyw*{wu>ALcS-L=f}0Dtl?*8<8xh2kHJ(JI9gta;G1o}SpozXzx?HHZ>-z_< zI{xER^Fvo>qmIXxjKeFsLQ~#ybzP#mEmqxjWpf-#gRX6Jk1+#qov}L7`>5NO@IddQ zVp*0Yk=R=nBq@h1T==ae>n>u=$}ViiO!Kbx;$v}7+p@jp-GkA_j(9D&uc~)9MeDc4 zYqm3QjJ@`FoiASFTRQyY(o@*3HWhzrI{JbTKODMQ69Q*O+r|vJdDxU+vHc^@zK^Us zKl!+r?I6>e@>a1}OV-{y;03oV+e_Xmyl~(f#W;D^k@pXrHa8F3%8=u;P!MnXY)!wD z|Bj=tl>1Av!1N!T@GZcg5)3don7@e(FfDB8sYS$M0gu#VZwY?bTY?LFOK?jq{YBbE zZ(YA#dmRQYi?r7*dZfH=*OR|U3xCE8_Rqzb2}EN&dTQ#W9`3@^enQNck(e-!;a~icsM(xsYBnWx zIY4#d24n-eu# zV>Mgjl~_b^eD(N+LvKI*=F{=wMo^sdhY~w{_#fTjQ^-*tEHApZV-OO#W-ysSLq3HK zL#Y7Pdm3{E<+U)iYvCz+(r3tFFO4Qc>A^?I_ar%o$RW~R_yU~a#tMNrRn_Ae$0_1@ za%RYRjvN}qLYSPF$%&Bj8acm9&imy20Xct2jv5$$lOjkcCG?OpK+Z5Z9Td??P8S@; z8SIkQ8y}}Yasm|b*KpXWj(0U$z43t=N8!rQ)1hX{pz{g`F=?d*8eNcu?fh)8# z@BvCJVSA(=c(5;lZBBU51O??4(o%k~lQhL76|s9qd7HldUUi`!_JY?z-m*eMmj?}? zMHxZ*pbaSSKL`rg*JDpauUNS-_}RsFsiq$$>En}!NovA6Izkc$NJ4^ugBWp!Ee@5W z^K0#seAvK_lFVU8NgCNvk`NGw&7)ixhe=|%S;hSQNjax{9EuPe23SQlEBEYdTg+?z z6B%+&>C_1_zCD8ztpuE77YMB)JkWk4(;Yv90iM1&%SU(k#?nRmZBs_%N!zwjvuC(b zi{)rKi3N-F$wTn+h?^q(k&DUPs!mNBi@V`(Z?5^39wU^%H?f|7o23NLnfnoi4=6 zRUahd};>n=y`<-Qg6`$3;{FFgn~UcP7{1K-1XKMD`AY$I|^+OIm3 zgCz@WlOZi{EV3wNsx88#7DSFH>@tlgdUt8q@E1&0sP;nxD$Efk)DBO0Op5~f2Ip(pcOsAW|b z&d^rzaoO4`Qc*f84+6?`@dZ1ZMr>OBIbmv#_1-i}IH{}hEPY%_SLLGrlKDHQ*jGFx z7*X;t%s61xThjALTQ;ENqK>phlAGzE!Gb3r%Y4q{b~@#dMY#=XgGG*GU5#dqGbw$I z(wMPy*;;UJaM@aX!MJQKJa-trw~TMwzHW;<8^1d^A6RPYzv=9UbfMh*F{d|K*or@? zTfA<2%?9&M^M~eaw~W21ktTmz>R4Z-4ocHSas!8ICsim5bZ3}b0bHParX3%bb`YY{ zS>;Md(-U1^g&U_yk1m<6L5WIksw26r-^n;N)~i?#QxIwR5SC;P(HA;_QiPLmMBA7W z%}yK<4pV$K&0&LZ42#lAQn6}vr^!lkjCu;Sm>3E=_OI*puDLEcd99?J@a#5@_N#2Y zQQ3OMn`qk;YugiV8;Dm9GK`bAD(Cc=GM8(W5Agq>U|IH`{$kZ7sLJPH47Yk3wf!&h z3r`A2@I=|yYLy2`$$+u_MzH%Nh+>!8ngT=sdg>s|)Fxm#>yVlf<;=az?}&*f`5oEE znnL-~7o8?w_P4`BqDwIOv*USq7dF=21KVQ;*f!&%)}{?A{RbvmA?oQ_A-)7i~E8~DGl_2hF42An6O zTgcIo-=ahCf{iDCeo@al?LwWFLK=DUuOoj34$^C8Bl8Lx|G7ryU($>J{3j$a(+SGQ zL~Y3n8owdhqxl3(Mx`Tf+U`Y2d{7UeAiLBSk1*nKvPyb>d5kMv7bwpRZ)K#)ma)0H z$6zokv!v97M}`)UDDpI<%P^a!J_RBbPjto5tfaY__8gAn1Eu|BofDNM%^Uh#+K9!5 z#wdn{qPL)|&ubrHr`B*N%Sa`Yb!oe`L)WR~8TeAtF38(Dvuf$5cL@CjWeH7f;mntl zUCSe%IsG&$ZKlymHndsGcJo6+t6Rx1+ZZV%TPi6cfE`FBkfjoVnA~AT2?$5wjd|M5d|x8xEF5_vx5}$Yq^$tsRA_*-pie-p$ftzkXt>&xkwPUl_skOTSdo?i z4^F$9e0_3maz#^&qpRHYZ@>EWSL5!D=d5>Jp11eCweMX2a!JjleK+gdZwB7M|FOGi4`feV0-;G`04@O50 zMGqgjIr7ZX&Z9S5j$Y`$SQd9R-7VrO>OZbjIaI5jvz6a1;Hox#0-KK>I_{IIbydH; z|IPi;^+P}G`QfH$ z-NiVEt6$G8n5+8=Gz%N7JdUF9QE9Fy#)uTT(`IG&eML#^SgD14>fx7=j5P-5A*bNyh@=K ze((*9eqi$s^&J>p_yyX>2`}IVy1g`GuFaPdWD6(AA)6?yTRen?K0s;6A$Bj+jFK4( z{gH0xJ)Krx^T148#XZJT+;bZA`}liylfLLdajCvxg@eQBH&#Gnqp*z{#yWZq9r6uE z5t`AbX}6)YlmkL7-6SL-y+p#&5D+b-tuj984?#pM5ZfRLZW^hDuTTOV8vr>o{xB@Q z9b;-WVo69CZ%(d|Hm4niE}5Vp9A@SRL}z-sj8oBRwMQ&ZkIp_Josdj)Qwn7T76y|f zvu8?(kWY2d!h={%NtJDrDW9_AQ9fOrH6BLPn#mkq+EMD#0qeA2x}TkuE`4!7RZvXM zPI8#=gMB{6c2rXsafG6=>(n$IGQCsyZM-`C=R)6rgMq^H5RLG<`(}=}{g})9Dc5?F zYyBzL@Kdhw$DHNI90Dyr;haC`_QtrqKjAk1gxmU4Zulo$?@zeaJ0^R=RCdEuc41rG z+thUZU_C95148^8 z{scc{rJgt=0aaCw%-V7P04w>^H#0jsGydjrx8o2z-~WoYKWl{iFh+IkCAs>H1eW7hKwb4(&phuE84Z zL67#KPX{odLm1L^Sf?AXK{sJ@n~ceR>x$5FEIcoKR+it!KN#XR8)5sL)I z&dAc;=R#z2ADxTYM6&N6q;ZCI zkEK}pn^TeJIE`*&{!HXqn&d(|@6My(j0LA0v|IA>SLnN;01*J=7d(<2-(kmPf4S}} z5u`Exmay`@81 zu8I-#dUZt_)v9;@cQ7*+my)q>fR3dYDeqa8+BsoMu|9CPp(foJvj;-)&{TwDpJYe5neglc7CyO`3xy->@N^;;nU2JhgwiTf z^6Z4V`iUr?oZ-%}FGiCm*l;KrIv(O9ES5p5Y$zT^@?_+6lI0>vE*d!%igj5>ym~>u zA8HEbg9*H0C?@C!qZ3Ji>5HH7>I5^i6iG&>BZ39fa3q!tc^SciH<*ZpcwR6}MkBGX zU<~nLsOO~x{b(q80)9;gB0LZGhOB)mk__^ZWHK6`;wQ2LNl|*~t9k-7)l$dXXq1jH+6{qH`ETDpKb>lDX)|AG@R=? z>*0cQ039P;V<4|r+f%f>LkbLo1 z)H&+Dk+RsoxA(q@qUrl)%3krkefKSxw^9|A7q4rC%*S7vBzM$X!xf2Q>zzwMPsS&SJFb9M2&@^_+8VpXuM;yaEbobJR$0FmRq#*9MoGx1AmO?+xs=x?eZ`vT>8I%)75YN@1Ax@N>L)NhimnFu{_VJNd; zS<>upCS|~Vq0A=HS)|%_Qd%aJTBXu*Qd%LE+N4qkDRoMvcE5+T>msFG#WI8LQs2VWv9RH~=9BqLHku&QLl z6p<0?kA;;!7Eu@+dS-t#8Of6gUDhFx3b9Cz97%vcf+-k@PeeMiqM}nHLB!@!Ab|+c z@H2e3`1fEPB!&5zA9)t?A6m_~x=|+TIOOPpDSSMbKp~>zur1CF3FMK>iPKhO6ym&X z!WwLWLDH~-H9*DVl>g!^^@wsB0`z^7UNOI4`CgfrC)0HT+m;VxSI`4HnW<-~ahYpV zvV2eI#^_1tK_fMeJtfDOZWMW4&f(W}+OkD5dPvYm9C4-QG3yu=SLz;v*&CO!5j9>W z*B+zg+N0%iS@w6-na#^NKLh{tTcjuRfQ%Wfl&@ufU4LrUawdFTpVVEoez7590mdx`?a6?b>Dqba1H3b#VQlC|NUf(rmzGrj&p!bs+_oa@z^=lXE*QUF6 z->KidSkpJR_g-!D%l6Ew_Bs8Mxh3OWi@)s;LDH4Y9rsC_ zX>;q6xpx^a-!(TZm>ZVNO`n;|U$vdLrE7+6*WR|ItNgz+9}>R=Wwt|KlrLdB%p&*_ zph!GM)!&O$)`Bxkna46EMaeTJL66a+rfj*KlV>1&Rk~4>hB=2{nfWk>3sb0OB~Ylo zIJqhL9uDd-Gpp;OW_5dj>g0xF8g4YAdm3hwg=(e}`UHGEWBP3{8e!m0jgPytUVggA z_RUa|!dQ~RRFcA6lEPAw!m6U6M-|Q^k0HECDGSd^k0Nr&IkMONwl)}J5Bw#VC~7?$ zhLz8l&67+MCnD1!@#CK5K^Nj@6Nwov8LEKMx3a2Z!0+n|_}D;S|9&4kyoVh*7+`(R z4j&2}VzDC6c4)}4W;DzOe9s2hQUCCPKL2y<)4u0A^N8T~(U?egcx3pQ!#>jT$l?9_ z^J!0n_!EGA6QBjXIKxS;V@C>;PtF4JLJ&xr&u=b^tHt}vEou7bRnAiIAbooe^s&H? z0A?Z=>d>%PuVBKV2u8!H)rmLwXi3>-X*P`F$e;K4l(8!(R5_2s`N8?}G_D z(06E{Z_uZ_MVy$~cN%)-E4&0*kbT|pSHDDr&0#gs@aZ67H$jnaz z#*UE|aEj#gQl3+(qa_-VCjvqo1FH=vFigZ|_=wlQJq4mg&|`JZhgpW3c@dk7%}&R89&t%Keng@&upKE{2UO#rpeqe} zLpuI{LjoA9qUP0?e(=(z+BCH zv!!ggMk-3zZd)>M&#Yei^Wc@>((28Nt}P3zH(#1~?c~MHuWg3xoGI6fhF_dj94XIJHBK-s+^o!GQX&t zB$mu4@0sn0=Uy($K*oCB`ilKuKR-xQm0NicSO@Gs^oD! zKsF11d^aRSkFy)x_bEuO@XPq~n+@dW@3$@lj{L(@B)<@zA`~K`Rbx`bm*1x-^MiB1 zb6Y77qFTs_$GC!O3*p!n1^>u6DWM<7(Iv+y4rtCn5HYcUYcDAE4P%C4I4fanpvH`a zkd~i1(s!h7+#$DH$R?WY?drA1c;3>qUR0L$AzXVPE5hms*uIitJ zFTU{O7haDoy4vPUpA_X;I$DxHChZc7n zPCLdP8kn;3WiwUgeD&$`PrrO1Q(1q{?s#?I`F%gy|Ha&(nE4ZrHoS9v75%;RN3K3o z{}a>=w-ZioJmKo!$=uk#8LM{ z<6eE1bEwVBMGQrRhrm})@g0y59%4lv0?GS_mhtD8&;BO-(T2ZgKHU0u@jIIikW2Z7 zA%%H-H_JSrLGk!nDlw|O#Z+Pj7ywgHDFzj61FiaWnPO^hLO-U*d5uSS3#zkzdJNoY z>cRHwphTk%qXK+P<1Fw)JI5Gxt!_O$K~Yt)je=(=L4$4qf=G>pTT+ItAV^*{hL zycIADc8~wy0g1gF83M2_@)!0gwwFVz7@1!}MGm(iU-$@o_>W^55`>wFM?@AO0vBEt>+h~(p!dZx7`l?LwnkPG#xyio(SIw zM$)yD2xgojgIG3DRdo{Icty=O+Mr|SditNDKj?GxcThLfg@X*v>#+ z!#nV^V&Lz=vyhbJ9a$(sfJt!gP@uMHfROa7y+{sutzKHn;NKqsgNz&PY3h? zI-moTQ3SCRzdDYNEOLyZzbxlyp#sbfT4se)FzXrt19mGm$_+*pOEr$7>mcWlp91XV z=z|~!^ja4%z`ufRgO3^Y6*v;+@n$hcQKKz#F8hlN*G>VGMN7NdvS@}8#V;%8$o2)< z=lCl5vXKe{SZ<^e7S;Xahn9)p*KY_|v^M>Kan!3Kkh0nPoPdalgr(OKrDbLeY`a9? zWJ-efOsRF&0pdz#Lu@?qqDK8?0dhexpNLFEC!-UDU3XbiZ)@x(sP?HLBj|{V`b)I@ zPEt?OcfpIT#))uE(N{Y`QN%VARLTByJ4o1pN#AOk6O8 zXQvaqh+!+R`VLHXVuFxXu=q|-L`VpTV2EH(1T$ECV#h-h-||{TxJ&RYc{<{Mu27FR z3^IrFDvN&wyZX97M|k8V5+H`*5`7|-66Dp;t{G6hNm+p}Ku9=l10XOIfDc_%L-X6= zcVBqxg`dV2>(|azd{SQXYU~HGAI9gH;!3{0RgsR%ItCcFm8xEqscOhnxieL@7Y|%G z@cKa|^GQ|R#eF~Ccj@%I-@WwRtLqo5x|YjKPS-AJv@{cxtzvs|u7*e@R1 zD2MwY#aLXQ0IJ`Aet)`Q>viXKChgw2WPd6HnEk-{11}%U*qvW4n}F&|=)WwU|HPyH zUkm-wn!XK#4(evZDolHwP&Dtb`7F$QgV(2LZs`q>zhz;3cIuYhbn63dW|C9pMpCHdNe;0D-s$QOG<1MR;4BO z4WQytbt4knN2AEb^bhXFWdk`iQWdUc6Umw>SM{=mWUYAu+(ydnl+}5^46~vLmzX`= z0Ax4(eIG^mKYtS<+)&EgAT#QO@y`_DrZH1d5pD(%Zhnji2QNE_Lk2`v5g}euOzT%H zrVIB&SN#5v>6%V<4LIZ=kRTLK;t78S zf?1~5i1HfRM*fklDHV`5We~8Pm17|lTwt~OiLp}ZqAbnj`_CMI0c_jW)LVJ*L5)wc z=6F<8a~>07ZQzkeG4@bpq5o#kN$ONy-wuxsq7PNw5k8OTkT0M@N~k60k%(F}c#sNR zd|%H^!vyBykccs)#PcJrQk+3o^Qcj#2>i)2)8W9$S!eInO(h&YRc!)cW-I>6I z81#@a6EFl2DRO*viohW*jHMAwCL!_KL)B^iSUQG zD`fm*g9npCQVQDyRRly{ZIba$J5}R;yXxKgx9We|xLDmjXI(ko>9n}-i3UOi?|3p* zZJDY%f_fy#Qxxg2k~?Errze2PReiDPLeuM>%iU?m`iEsE07I@U7^-Q?RJ${Eo=kmH z771AlwdHer9|F>;L{xKW*VQMkHl{c2`S7Lmo+D}ZvrG2pz$RG&3H4lSxmKBWZ(6c% zUMUjV2uP^kIM_zr>{tx{X!G1_eBB6YTiR?zvnAN%&z&-jb?h%a?#5BREOcMy;OT!xr%oKh-kP>*a z6VVMM1l-_>k#g0)+4e@$vI)=3l+|^i^Nz)H-vXy1e!<6+4+X!Bfn<|R5b`zZYgs%Q zuxH{R<{YwwOXwTGHkkm)*hMFdW4bjGT^Lkx2*NQyK%L6k2z16m*3mI_K#;zWWpvD- z3awKDa8!suKZ?Vhb11z8d?fd5stS8X?6gIU9uO`EFL|tBUr^y!+j6_WPym!gg7qBK zo>O2>umA=_<5|uzuHddQi`K>q=Nb!dDHI0unu#i#c%WQk1(wGm4CW08io}pja*Q_0 zx$G~Pk8*0utsa1&cfUc#P;#kE0Fr1u?aA!!!ZfKe( zZWi)Xf@zwc3PQvPcLFOA9ESH-P?%zfa-e%fJ<7tWfdW>jTq+`C-ag+hL(4G z-|YQeL+5LzjHB*i#f6HWnKEwnvh$t#Ok>;SzIXP0(%gQxdE;-JH(on({h41qzu3Gx zvt`%ylfO=Vka|1t?(=Uwf7Nu2{)Kg^X~T!yLyMus^)HmcS$UtK8lMD%R%1t|vgWmu zZ*0y$sB+62lYsO-X=uCK(DU1do@;H_LceNXY}l4xlIdQ5t>-_U`VXf>Fnf96D*fJ` zCHLCv2qV!}20*fkg(s42T3xZhS zkGCVyZMy-=Z#x+%xn1QNYG-b@Gf@6#;zEsJCE+!Q4K+d}7Z(b43|^OcMxO6VV4`3o z)8UlI*Buq<9-T zAR@(pPG!RZ)P}AW2oZ<-lU2m0wFm1;{6 zU@s$3sxYQ}Ke;UldzrxPQ2-&1E7G|XMj3a>Esr8Q&N%=jJqDpbxdwscAdM34uiV=5 z2oj{Bdp!06oL$rzHfDr3pg6>`4XJzU_mM=dOFl&(s2JZtp z(I?Ek=0M4NigX%mQlgFqn;23bTlYqi2ujEzTKU_PJXLDR!FIsH*d&{czw~}}`>OqkqVdfBIyCiNG2Mocx!4g4-));iCr*= zG_R-ohYt(~3fQ0ss7b9U3R>iMht?w(w;3i|AqXP|fDxo}21yjS!hIW05u|Y6fkZHI z08=?IITC1-gHN+jQ}z z3oreyw&OKMg)JH{J@ZaYrqOemerHb>TO7LX{MFcE^UlnM&DT!;dh-XHC2YZ5?fZps zsj2(A7F*PL(UMes*WS2bZ(OoB->YmW2nK2tFwp;D&xZg8_AJ@=W-6;+9#+EI2pp)< z!U24H=lV>(R{A4r|GGgNb#uEDPUdYkpOu-far+F+d^e5xb$VYJHNO$B-ZB`V{2eIyAt6yKcp^rvV9rdztG8ed0#(Y-$L?4f?%UurKUxJv zCd_&Jga4!e08|0Q<7=6UP^g>a7P7yxNJ)r79mhN80HN+0V>U2ZbB-j|(HNU^$gP1` z|1qf8DAo%I|8YgsmlW#``39qkfR{@s>hWT|R4nh~1UHmxFk=oJP@u)A0t|9`qp6(( z2P9XfTneU`pNOUyBJN8@0%r|DDskT^-+xpw=g1`xky1+Bm$+v^abL7fj=1+)i2zj# zcK$J8DgTrwroOrnBCiQz70}#0k3=*LNb5w3n*_4KE@W{=UQ?1>We@JzgC3uJCl42b zcOwU>;2s6JCIKGBs$(S*6~7=cdPOTyiwRO>p&T+j?uVFUHUBcr5Q&<96i9gF28y>u z6sRujw?@h5h4w9?Lu*CwvF{AzO1^HhFG5jkozwu6ptBsw~gqg5>> zWT!f^q@?WJ3uAn)$LFR$=znTZN8RjkLVjKc(GbjhnR{?2Gv7{QevRIzr{>p^t2-gG zg1JRAP;yJ}^3^c6Y8a@ck({XD5y{yJnUazdcm>9nRnQGqKXj z@Ovl{y-=Bm#8oH~AtA~zo`@n5bEpX4w?Hmm3C1TNGEnzT$-ou3OA4#L5a6vV6$B#7 zzCwzud<|R^Dmhxp{0x05AoY$>xVH_|RU8vAPSPRYM^X?KDFqT^kSK_TaV3tkkP7OD z$V;t)2qx>IiYPH{8+svHvv_~}u&fD8+d!#NA4}BAkteTO50ijHty!CxsK2^;NU8zD zg|JDI%~AaV+-!u6PQvo(i3!mDV4+MWyC)RmBkWA_M1*@W%15lJ@8t=B6$b>6d!oQm zM^P3OKx#XB-u+T-qP|9iQ?5J_9}J#xkGJCSQU$*=G4OBz{M9QW@fa|t=( zQppj?&0hPq`Ca>4_MevDty{NHw{Ed+{k4N>$6&6Hl)s##r3ipu#?Qf^$6syUUE&%udMPaN7pfFgI3p z474&g?fQWysGANKl;3PMK>5uz43<3M8raF)+{r+>hUM#_MZ)siAybm&)9M95Q&5BO zdF}$_O7r*shWs6EScJcOkiSFno62SU`KXGVi5wkxw{jo?CLH~5q53!C0RQ?+eqjF$ zwVSy3P8VQmWk%78k#k7ASXYeaOT1XoWE5VkR~an}@N(eA5WlY8BLtG}nN#;2jahE(;gv>@^KR4OH_tluQHco6seE8Ws zz9{V#uwo71G5$aqt;42$u!UcKNckS{s13lRD7XTW#76xDuRfNEN=ux`=a<7j@ncb~ ze5@p0h-lcSP%z5703rEY{~a_)SY}memZ=GCg0NlU2(uZ%SOr1X%3{YA^G7uzmSe3; z@yFfJUEq(6^ankCn{m-KWIx($8_+X1=#Ktg=7v{4V4`k3>4Neby#^@1sb`?%rpYzn zW^TF}DA%w@{d1jafPMgwaHSzdPurh4335sGlhIO;FT)D{z^bwX*tk(Mt&Ny1Y1`e-nLN? zA*}YZ{H4)SPGO2qjiP+G4k8=P{6v42#$eu7lqr$AZA&l%wgR{YiU@wDfO(( zx;1(~I};0oV7?PP4F+7w~OO%OR0Vg% zWOo)YrKD^Fu}CNmfv>X(Hs!*;Ym@>$wOYi*6G(=P8|ds}*d$`$Ol4uuf-i$?j8O>nc@z0$}TEEw)CHe6Fu$a6SFes=nF* zJ9T4+6Had0ZG-j9&DxH^YUXCIez1v}XIxM|Uu}T$`FaLRnp}h3;I3exTq8adbiElG zFD5?FkOF@??NWRcD%{&p71rQmQ(`D8vhmVryBy>L-w32ct~8-sf#gcnm5KK^Tt4w$ zGdazdFUa8u+(w7NHv+dyZaPO+r(58@IY-X6b46SS+E~N{16;pQd+M0fqMOv^w5K0~ z4Y0Su2ONf08>u4$ovOYZfX%WK23R->TRo2H{pzSz!!c!ri{A(`x4@EJKWv{mimx{3 z=!W>)6~q}TrXIz-Z!EEiq&Z;JDhS=8H{X&l_8J2v@98IW8aYy;jz*4HQw@?cKf4-} z?3@dB?Fl~BD%tM`4jvu}bUfiL5FwaqDo7)14MJrS_9u?zu)T7zP$6mw!R>L^Nx38l zyRT~M5I40@Chs~)wna@_bM1TVAf&L^F0g&Ii?YLTa$fw z$%n~%nEYEv1bgVzl+sI)-J`(KtYxsEznXMLXewkBQ7#jf@UKuE`FRPJU8gKn5I0WB zw08Ww`%3p>>xOH6cUm{6?H=5WK-yVp`;vV}2AFs7&ER5F*VU7EntJ9&;QAnagib&A z{L;Ylmv;TGp*Q^(A&4q7QqK1Dn(Y|}d$}v)*zm#O>pO2d7dJhfakO96-|gsI=;+Hh zJeR9}-gu>P*=DRNU#=?em2;e_T%n9cijK#C}{WCT*Ck!elijy_nz*S=d(=m{U|_#p?(=H`H%L~VCW&%o=5#OC^^fh={y>wK`#9Z3MV3sNH@KWWJm;4 zh(8mbh|UNm-1QY8nW#7)hX)Xh$ukKo0XZe^VwK&CM)Y#wha%YU6DGTGM|chu8M56s zhhh$Qz)hZrMURtxXSo0t)xsX=U9bmwS2z+$@R7*3U8j?IHlo_KLN=yL&IL@I)>Ii zuu^oz@2PU~-}Wihxkz<>N_Binty`eh{UcTPd&>4dsI~t{b>6c$?po@9YpK7qbB;{EuPJT0 diff --git a/src/llm/__pycache__/deepseek_client.cpython-314.pyc b/src/llm/__pycache__/deepseek_client.cpython-314.pyc deleted file mode 100644 index a753d5de555ae8397aafab157ca28fe4e5069e92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19422 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 ZNbiKnrgx?i0D9!)bacf73PaMZ{|EHfZUz7V diff --git a/src/llm/__pycache__/rag_service.cpython-314.pyc b/src/llm/__pycache__/rag_service.cpython-314.pyc deleted file mode 100644 index 9a0c739c787024af3e247accdc9ca912168f3c19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18473 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 ImRJM-4-{}RtN;K2 From 2eb4e30de7e08bad7565829a74306564e27816ed Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:03:53 +0530 Subject: [PATCH 03/25] chore: add .venv_local and .saropa to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e04c4f8f..68bfa28f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ # Python venv/ .venv/ +.venv_local/ +.saropa/ __pycache__/ *.py[cod] *.pyo From 6f28b135b2547511c6a02c77dc2ff9fdac24b676 Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:03:58 +0530 Subject: [PATCH 04/25] refactor(frontend): clean up preconnect and dns-prefetch links in layout --- frontend/src/app/layout.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 55858b95..4ff5c713 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -101,9 +101,6 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`} > - - -
From 8e82b31f83c417932653f2abed7ffc24d964f5ec Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:04:01 +0530 Subject: [PATCH 05/25] fix(cli): handle empty checkpoint files gracefully in execution loop harness --- src/cli/execution_loop_harness.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cli/execution_loop_harness.py b/src/cli/execution_loop_harness.py index 32927bec..a14e5521 100644 --- a/src/cli/execution_loop_harness.py +++ b/src/cli/execution_loop_harness.py @@ -77,8 +77,13 @@ def list(self, objective_id: str) -> list[dict[str, Any]]: def _read_document(self) -> dict[str, Any]: if not self.path.exists(): return {"version": 1, "objectives": {}} + if self.path.stat().st_size == 0: + return {"version": 1, "objectives": {}} with self.path.open(encoding="utf-8") as checkpoint_file: - document = json.load(checkpoint_file) + content = checkpoint_file.read().strip() + if not content: + return {"version": 1, "objectives": {}} + document = json.loads(content) if document.get("version") != 1 or not isinstance(document.get("objectives"), dict): raise click.ClickException(f"Invalid checkpoint store: {self.path}") return document From c1a591440a97c6f2280fb464ca4c1a4cd01e2c72 Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:04:02 +0530 Subject: [PATCH 06/25] feat(safety): add parameter boundary validation for weight fine-tuning actions --- src/safety/action_validator.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/safety/action_validator.py b/src/safety/action_validator.py index f38a4440..e4ec10ae 100644 --- a/src/safety/action_validator.py +++ b/src/safety/action_validator.py @@ -3,7 +3,7 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Any +from typing import Any, Dict, Optional @dataclass @@ -27,6 +27,8 @@ class ActionValidator: "research", "memory_consolidation", "execute_task", + "weight_fine_tune", # Allow fine-tuning with boundary checks + "adapter_load", # Allow adapter loading with boundary checks } BLOCKED_ACTION_TYPES = { "delete_file", @@ -38,6 +40,11 @@ class ActionValidator: } BLOCKED_TERMS = ("rm -rf", "sudo", "chmod 777", "mkfs", ":(){") + # Parameter boundaries for weight fine-tuning + MAX_EPOCHS = 10 + MAX_LEARNING_RATE = 1e-3 + MAX_BATCH_SIZE = 32 + def validate_action(self, action: Any) -> ValidationResult: if action is None: return ValidationResult(False, "Action is empty") @@ -63,6 +70,31 @@ def validate_action(self, action: Any) -> ValidationResult: if any(term in normalized_payload for term in self.BLOCKED_TERMS): return ValidationResult(False, "Action contains a blocked operation") + # Parameter boundary checks for weight fine-tuning + if normalized_type == "weight_fine_tune" and isinstance(action, dict): + warnings = [] + if "epochs" in action and action["epochs"] > self.MAX_EPOCHS: + return ValidationResult( + False, + f"Epochs {action['epochs']} exceeds maximum allowed {self.MAX_EPOCHS}" + ) + if "learning_rate" in action and action["learning_rate"] > self.MAX_LEARNING_RATE: + return ValidationResult( + False, + f"Learning rate {action['learning_rate']} exceeds maximum allowed {self.MAX_LEARNING_RATE}" + ) + if "batch_size" in action and action["batch_size"] > self.MAX_BATCH_SIZE: + return ValidationResult( + False, + f"Batch size {action['batch_size']} exceeds maximum allowed {self.MAX_BATCH_SIZE}" + ) + if warnings: + return ValidationResult( + True, + "Action allowed with parameter warnings", + warnings + ) + if normalized_type and normalized_type not in self.SAFE_ACTION_TYPES: return ValidationResult( True, From c1b135d6fa41b1c7cce0b70c2c76e767464180be Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:04:04 +0530 Subject: [PATCH 07/25] feat(swarm): integrate message router, consensus evaluator, and load balancer into swarm coordinator --- src/swarm/swarm_coordinator.py | 387 +++++++++++++++++++++++++++++++-- 1 file changed, 373 insertions(+), 14 deletions(-) diff --git a/src/swarm/swarm_coordinator.py b/src/swarm/swarm_coordinator.py index 46c31cd4..7ef2cf55 100644 --- a/src/swarm/swarm_coordinator.py +++ b/src/swarm/swarm_coordinator.py @@ -1,14 +1,18 @@ """Swarm Coordinator for Swarm Orchestration (Phase 8). Central coordinator for managing the entire swarm of agents. +Enhanced with in-process message queues, consensus evaluation, and load balancing. """ from __future__ import annotations import asyncio from datetime import datetime, timezone -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Callable from uuid import UUID, uuid4 +from dataclasses import dataclass, field +from enum import Enum +from collections import deque from pydantic import BaseModel, Field @@ -18,6 +22,281 @@ logger = get_logger(__name__) +class MessageType(str, Enum): + """Types of messages in the swarm communication system""" + TASK_ASSIGNMENT = "task_assignment" + TASK_RESULT = "task_result" + CONSENSUS_VOTE = "consensus_vote" + CONSENSUS_RESULT = "consensus_result" + HEARTBEAT = "heartbeat" + STATUS_UPDATE = "status_update" + LOAD_REPORT = "load_report" + SCALING_SIGNAL = "scaling_signal" + + +@dataclass +class SwarmMessage: + """Message for inter-agent communication""" + msg_type: MessageType + sender_id: UUID + recipient_id: Optional[UUID] # None for broadcast + payload: Dict[str, Any] + timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) + correlation_id: Optional[UUID] = None + reply_to: Optional[UUID] = None + + +class InProcessMessageRouter: + """In-memory async message router for swarm communication""" + + def __init__(self): + self._queues: Dict[UUID, asyncio.Queue] = {} + self._subscriptions: Dict[MessageType, List[UUID]] = {} + self._broadcast_queue: asyncio.Queue = asyncio.Queue() + self._running = False + self._router_task: Optional[asyncio.Task] = None + + def register_agent(self, agent_id: UUID) -> asyncio.Queue: + """Register an agent and return its message queue""" + queue = asyncio.Queue() + self._queues[agent_id] = queue + return queue + + def unregister_agent(self, agent_id: UUID) -> None: + """Unregister an agent""" + if agent_id in self._queues: + del self._queues[agent_id] + # Remove from subscriptions + for msg_type, subscribers in self._subscriptions.items(): + if agent_id in subscribers: + subscribers.remove(agent_id) + + def subscribe(self, agent_id: UUID, msg_type: MessageType) -> None: + """Subscribe agent to a message type""" + if msg_type not in self._subscriptions: + self._subscriptions[msg_type] = [] + if agent_id not in self._subscriptions[msg_type]: + self._subscriptions[msg_type].append(agent_id) + + def unsubscribe(self, agent_id: UUID, msg_type: MessageType) -> None: + """Unsubscribe agent from a message type""" + if msg_type in self._subscriptions: + if agent_id in self._subscriptions[msg_type]: + self._subscriptions[msg_type].remove(agent_id) + + async def send(self, message: SwarmMessage) -> None: + """Send a message to a specific recipient or broadcast""" + if message.recipient_id is not None: + # Direct message + if message.recipient_id in self._queues: + await self._queues[message.recipient_id].put(message) + else: + logger.warning(f"Recipient {message.recipient_id} not registered") + else: + # Broadcast + await self._broadcast_queue.put(message) + + async def start(self) -> None: + """Start the router""" + self._running = True + self._router_task = asyncio.create_task(self._route_loop()) + logger.info("InProcessMessageRouter started") + + async def stop(self) -> None: + """Stop the router""" + self._running = False + if self._router_task: + self._router_task.cancel() + try: + await self._router_task + except asyncio.CancelledError: + pass + logger.info("InProcessMessageRouter stopped") + + async def _route_loop(self) -> None: + """Main routing loop""" + while self._running: + try: + # Process broadcast queue + try: + message = await asyncio.wait_for(self._broadcast_queue.get(), timeout=0.1) + for agent_id, queue in self._queues.items(): + if message.sender_id != agent_id: # Don't send to sender + await queue.put(message) + except asyncio.TimeoutError: + pass + + # Process direct messages (they're already in queues) + await asyncio.sleep(0.01) + + except asyncio.CancelledError: + break + except Exception as e: + logger.error(f"Error in router loop: {e}") + await asyncio.sleep(0.1) + + async def receive(self, agent_id: UUID, timeout: float = 1.0) -> Optional[SwarmMessage]: + """Receive a message for an agent""" + if agent_id not in self._queues: + return None + try: + return await asyncio.wait_for(self._queues[agent_id].get(), timeout=timeout) + except asyncio.TimeoutError: + return None + + +class ConsensusEvaluator: + """Consensus evaluation for multi-agent agreement""" + + def __init__(self, min_agreement: float = 0.66): + self.min_agreement = min_agreement + self._votes: Dict[UUID, Dict[UUID, Any]] = {} # proposal_id -> {voter_id: vote} + self._vote_weights: Dict[UUID, float] = {} # voter_id -> weight + + def register_voter(self, voter_id: UUID, weight: float = 1.0) -> None: + """Register a voter with optional weight""" + self._vote_weights[voter_id] = weight + + def unregister_voter(self, voter_id: UUID) -> None: + """Unregister a voter""" + if voter_id in self._vote_weights: + del self._vote_weights[voter_id] + + def submit_vote(self, proposal_id: UUID, voter_id: UUID, vote: Any) -> None: + """Submit a vote for a proposal""" + if proposal_id not in self._votes: + self._votes[proposal_id] = {} + self._votes[proposal_id][voter_id] = vote + + def evaluate(self, proposal_id: UUID) -> Dict[str, Any]: + """Evaluate consensus for a proposal""" + if proposal_id not in self._votes: + return {"consensus": False, "reason": "No votes submitted"} + + votes = self._votes[proposal_id] + if not votes: + return {"consensus": False, "reason": "No votes"} + + # Count votes by value + vote_counts: Dict[Any, float] = {} + total_weight = 0.0 + + for voter_id, vote in votes.items(): + weight = self._vote_weights.get(voter_id, 1.0) + vote_str = str(vote) + vote_counts[vote_str] = vote_counts.get(vote_str, 0.0) + weight + total_weight += weight + + # Find majority + max_votes = max(vote_counts.values()) if vote_counts else 0 + agreement_ratio = max_votes / total_weight if total_weight > 0 else 0 + + consensus_reached = agreement_ratio >= self.min_agreement + + # Get winning vote + winning_vote = max(vote_counts, key=vote_counts.get) if vote_counts else None + + return { + "consensus": consensus_reached, + "agreement_ratio": agreement_ratio, + "winning_vote": winning_vote, + "vote_distribution": vote_counts, + "total_voters": len(votes), + "required_ratio": self.min_agreement, + } + + def clear_proposal(self, proposal_id: UUID) -> None: + """Clear votes for a proposal""" + if proposal_id in self._votes: + del self._votes[proposal_id] + + +class LoadBalancer: + """Load balancer for distributing tasks across agents""" + + def __init__(self): + self._agent_loads: Dict[UUID, float] = {} + self._agent_capabilities: Dict[UUID, List[str]] = {} + self._agent_status: Dict[UUID, str] = {} # idle, busy, offline + self._task_history: Dict[UUID, List[Dict]] = {} + + def register_agent(self, agent_id: UUID, capabilities: List[str] = None, max_load: float = 1.0) -> None: + """Register an agent with capabilities""" + self._agent_loads[agent_id] = 0.0 + self._agent_capabilities[agent_id] = capabilities or [] + self._agent_status[agent_id] = "idle" + self._task_history[agent_id] = [] + + def unregister_agent(self, agent_id: UUID) -> None: + """Unregister an agent""" + for d in [self._agent_loads, self._agent_capabilities, self._agent_status, self._task_history]: + if agent_id in d: + del d[agent_id] + + def update_load(self, agent_id: UUID, load: float) -> None: + """Update agent load (0.0 to 1.0)""" + if agent_id in self._agent_loads: + self._agent_loads[agent_id] = max(0.0, min(1.0, load)) + self._agent_status[agent_id] = "busy" if load > 0.1 else "idle" + + def update_status(self, agent_id: UUID, status: str) -> None: + """Update agent status""" + if agent_id in self._agent_status: + self._agent_status[agent_id] = status + + def record_task_completion(self, agent_id: UUID, task_info: Dict[str, Any]) -> None: + """Record task completion for learning""" + if agent_id in self._task_history: + self._task_history[agent_id].append({ + **task_info, + "timestamp": datetime.now(timezone.utc).isoformat(), + }) + # Keep last 100 tasks + if len(self._task_history[agent_id]) > 100: + self._task_history[agent_id] = self._task_history[agent_id][-100:] + + def select_agent(self, required_capabilities: List[str] = None, strategy: str = "least_loaded") -> Optional[UUID]: + """Select best agent for a task""" + # Filter by capabilities + candidates = [] + for agent_id, capabilities in self._agent_capabilities.items(): + if self._agent_status.get(agent_id) == "offline": + continue + if required_capabilities: + if not all(cap in capabilities for cap in required_capabilities): + continue + candidates.append(agent_id) + + if not candidates: + return None + + if strategy == "least_loaded": + return min(candidates, key=lambda a: self._agent_loads.get(a, 1.0)) + elif strategy == "most_capable": + return max(candidates, key=lambda a: len(self._agent_capabilities.get(a, []))) + elif strategy == "round_robin": + # Simple round-robin based on task count + return min(candidates, key=lambda a: len(self._task_history.get(a, []))) + + return candidates[0] + + def get_load_report(self) -> Dict[str, Any]: + """Get current load report""" + return { + "agent_loads": {str(k): v for k, v in self._agent_loads.items()}, + "agent_status": {str(k): v for k, v in self._agent_status.items()}, + "total_agents": len(self._agent_loads), + "busy_agents": sum(1 for s in self._agent_status.values() if s == "busy"), + "idle_agents": sum(1 for s in self._agent_status.values() if s == "idle"), + } + + +# Global instances for swarm communication +message_router = InProcessMessageRouter() +consensus_evaluator = ConsensusEvaluator() +load_balancer = LoadBalancer() + + class SwarmMetrics(BaseModel): """Metrics for the entire swarm.""" @@ -33,8 +312,11 @@ class SwarmMetrics(BaseModel): class SwarmCoordinator: - """Central coordinator for managing multiple director agents.""" - + """Central coordinator for managing multiple director agents. + + Enhanced with in-process message queues, consensus evaluation, and load balancing. + """ + def __init__(self, num_directors: int = 5, sub_orchestrators_per_director: int = 10): """Initialize swarm coordinator.""" self.num_directors = num_directors @@ -43,6 +325,9 @@ def __init__(self, num_directors: int = 5, sub_orchestrators_per_director: int = self.directors: Dict[UUID, DirectorAgent] = {} self._running = False self._monitor_task: Optional[asyncio.Task] = None + self._message_router = message_router + self._consensus = consensus_evaluator + self._load_balancer = load_balancer logger.info( f"SwarmCoordinator initialized with {num_directors} directors, " @@ -54,11 +339,20 @@ async def initialize(self) -> None: logger.info("Initializing SwarmCoordinator") self._running = True + # Start message router + await self._message_router.start() + # Initialize director agents for i in range(self.num_directors): director = DirectorAgent(max_sub_orchestrators=self.sub_orchestrators_per_director) await director.initialize() - self.directors[uuid4()] = director + director_id = uuid4() + self.directors[director_id] = director + + # Register with communication infrastructure + self._message_router.register_agent(director_id) + self._load_balancer.register_agent(director_id, ["director", "coordination"]) + self._consensus.register_voter(director_id, weight=1.0) # Start monitoring task self._monitor_task = asyncio.create_task(self._monitor_loop()) @@ -77,6 +371,9 @@ async def shutdown(self) -> None: except asyncio.CancelledError: pass + # Stop message router + await self._message_router.stop() + # Shutdown all directors for director in self.directors.values(): await director.shutdown() @@ -101,14 +398,25 @@ async def submit_goal(self, goal: SwarmGoal) -> UUID: except RuntimeError: pass # Runtime not initialized yet (startup) - # Find director with least load - director = await self._get_least_loaded_director() - - if not director: - raise RuntimeError("No available directors") + # Use load balancer to find best director + director_id = self._load_balancer.select_agent( + required_capabilities=["director"], + strategy="least_loaded" + ) + + if not director_id or director_id not in self.directors: + # Fallback to original method + director = await self._get_least_loaded_director() + if not director: + raise RuntimeError("No available directors") + else: + director = self.directors[director_id] goal_id = await director.submit_goal(goal) - logger.info(f"Goal {goal_id} assigned to director") + logger.info(f"Goal {goal_id} assigned to director {director_id}") + + # Update load balancer + self._load_balancer.update_load(director_id, 0.5) return goal_id @@ -120,9 +428,9 @@ async def _get_least_loaded_director(self) -> Optional[DirectorAgent]: min_load = float("inf") least_loaded = None - for director in self.directors.values(): + for director_id, director in self.directors.items(): status = await director.monitor_swarm() - load = status.get("busy_sub_orchestrators", 0) + load = status.get("busy_sub_orchestrators", 0) / max(1, status.get("total_sub_orchestrators", 1)) if load < min_load: min_load = load @@ -139,6 +447,41 @@ async def get_goal_status(self, goal_id: UUID) -> Optional[Dict[str, Any]]: return None + async def request_consensus(self, proposal: Dict[str, Any], voters: List[UUID] = None) -> Dict[str, Any]: + """Request consensus from directors on a proposal""" + proposal_id = uuid4() + + # Default to all directors if no voters specified + if voters is None: + voters = list(self.directors.keys()) + + # Broadcast consensus request + message = SwarmMessage( + msg_type=MessageType.CONSENSUS_VOTE, + sender_id=uuid4(), # coordinator ID + recipient_id=None, # broadcast + payload={ + "proposal_id": str(proposal_id), + "proposal": proposal, + "voters": [str(v) for v in voters], + }, + ) + await self._message_router.send(message) + + # Collect votes (simplified - in real implementation would wait for responses) + # For now, simulate voting + for voter_id in voters: + if voter_id in self.directors: + # Simulate vote based on proposal + vote = {"agree": True, "confidence": 0.8} + self._consensus.submit_vote(proposal_id, voter_id, vote) + + # Evaluate consensus + result = self._consensus.evaluate(proposal_id) + self._consensus.clear_proposal(proposal_id) + + return result + async def get_swarm_metrics(self) -> SwarmMetrics: """Get comprehensive metrics for the entire swarm.""" total_sub_orchestrators = 0 @@ -175,7 +518,7 @@ async def get_swarm_metrics(self) -> SwarmMetrics: active_goals=active_goals, completed_goals=completed_goals, failed_goals=failed_goals, - average_task_duration=0.0, # Would be calculated from task history + average_task_duration=0.0, total_tasks_completed=total_tasks_completed, swarm_utilization=swarm_utilization, ) @@ -194,6 +537,10 @@ async def _monitor_loop(self) -> None: f"{metrics.swarm_utilization:.2%} utilization" ) + # Get load balancer report + load_report = self._load_balancer.get_load_report() + logger.debug(f"Load report: {load_report}") + # Auto-scale if needed await self._auto_scale(metrics) @@ -230,7 +577,14 @@ async def scale_directors(self, target_count: int) -> bool: for i in range(target_count - current_count): director = DirectorAgent(max_sub_orchestrators=self.sub_orchestrators_per_director) await director.initialize() - self.directors[uuid4()] = director + director_id = uuid4() + self.directors[director_id] = director + + # Register with communication infrastructure + self._message_router.register_agent(director_id) + self._load_balancer.register_agent(director_id, ["director", "coordination"]) + self._consensus.register_voter(director_id, weight=1.0) + logger.info(f"Scaled directors from {current_count} to {target_count}") elif target_count < current_count: # Scale down (remove idle directors) @@ -248,6 +602,11 @@ async def scale_directors(self, target_count: int) -> bool: director_id = idle_directors[i] await self.directors[director_id].shutdown() del self.directors[director_id] + + # Unregister from communication infrastructure + self._message_router.unregister_agent(director_id) + self._load_balancer.unregister_agent(director_id) + self._consensus.unregister_voter(director_id) logger.info(f"Scaled directors from {current_count} to {target_count}") From fb3837d13dc7806de65c77bde4eacf40f852750f Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:04:05 +0530 Subject: [PATCH 08/25] test(unit): update local weight engine unit tests for parameter iterator mocking --- tests/unit/test_local_weight_engine.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_local_weight_engine.py b/tests/unit/test_local_weight_engine.py index f9ac7042..8c8b79b1 100644 --- a/tests/unit/test_local_weight_engine.py +++ b/tests/unit/test_local_weight_engine.py @@ -208,14 +208,16 @@ def test_get_model_info_loaded(self): """Test get_model_info when model loaded""" engine = LocalWeightEngine() engine._model = Mock() - # Mock parameters() to return an iterator - mock_params = [Mock(numel=Mock(return_value=100)), Mock(numel=Mock(return_value=50))] - engine._model.parameters.return_value = iter(mock_params) - # Mock next() on the model for dtype + # Mock parameters() to return a fresh iterator each time mock_param = Mock() + mock_param.numel.return_value = 100 + mock_param.requires_grad = True mock_param.dtype = torch.float32 - engine._model.__iter__ = Mock(return_value=iter([mock_param])) - engine._model.__next__ = Mock(return_value=mock_param) + + def params_iterator(): + return iter([mock_param]) + + engine._model.parameters.side_effect = params_iterator engine._model.device = torch.device("cpu") engine._model_name = "test-model" engine._is_peft_model = False @@ -225,6 +227,8 @@ def test_get_model_info_loaded(self): assert info["model_name"] == "test-model" assert info["device"] == "cpu" assert info["is_peft_model"] is False + assert info["total_parameters"] == 100 + assert info["trainable_parameters"] == 100 def test_enable_training_mode(self): """Test enabling training mode""" From 740d44423bbca1b455fadf3d588b959c9aac0f4a Mon Sep 17 00:00:00 2001 From: genius-0963 Date: Sat, 1 Aug 2026 22:04:07 +0530 Subject: [PATCH 09/25] feat(frontend): add Swarm Agents dashboard page --- frontend/src/app/agents/page.tsx | 889 +++++++++++++++++++++++++++++++ 1 file changed, 889 insertions(+) create mode 100644 frontend/src/app/agents/page.tsx diff --git a/frontend/src/app/agents/page.tsx b/frontend/src/app/agents/page.tsx new file mode 100644 index 00000000..0603020d --- /dev/null +++ b/frontend/src/app/agents/page.tsx @@ -0,0 +1,889 @@ +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { + Brain, + Search, + Code, + CheckSquare, + Shield, + Zap, + Pause, + Play, + RotateCcw, + MessageSquare, + X, + Activity, + Wifi, + WifiOff, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Separator } from "@/components/ui/separator"; +import { Slider } from "@/components/ui/slider"; +import { Label } from "@/components/ui/label"; + +interface AgentNode { + id: string; + role: string; + name: string; + icon: React.ReactNode; + color: string; + status: "idle" | "active" | "completed" | "error"; + progress: number; + lastThought: string; + thoughts: string[]; +} + +interface AgentEvent { + type: string; + payload: any; + timestamp: string; +} + +interface WebSocketMessage { + event_type: string; + payload: any; + timestamp: string; + correlation_id?: string; +} + +const AGENT_ROLES: AgentNode[] = [ + { + id: "planner", + role: "planner", + name: "Planner", + icon: , + color: "bg-blue-500", + status: "idle", + progress: 0, + lastThought: "", + thoughts: [], + }, + { + id: "researcher", + role: "researcher", + name: "Researcher", + icon: , + color: "bg-green-500", + status: "idle", + progress: 0, + lastThought: "", + thoughts: [], + }, + { + id: "coder", + role: "coder", + name: "Coder", + icon: , + color: "bg-purple-500", + status: "idle", + progress: 0, + lastThought: "", + thoughts: [], + }, + { + id: "evaluator", + role: "evaluator", + name: "Evaluator", + icon: , + color: "bg-orange-500", + status: "idle", + progress: 0, + lastThought: "", + thoughts: [], + }, + { + id: "safety_gate", + role: "safety_gate", + name: "Safety Gate", + icon: , + color: "bg-red-500", + status: "idle", + progress: 0, + lastThought: "", + thoughts: [], + }, +]; + +const AGENT_CONNECTIONS = [ + { from: "planner", to: "researcher" }, + { from: "researcher", to: "coder" }, + { from: "coder", to: "evaluator" }, + { from: "evaluator", to: "safety_gate" }, +]; + +export default function AgentsPage() { + const [ws, setWs] = useState(null); + const canvasRef = useRef(null); + + const [connected, setConnected] = useState(false); + const [agents, setAgents] = useState(AGENT_ROLES); + const [objective, setObjective] = useState(""); + const [isRunning, setIsRunning] = useState(false); + const [events, setEvents] = useState([]); + const [fineTuneEvents, setFineTuneEvents] = useState([]); + const [selectedAgent, setSelectedAgent] = useState(null); + const [showFineTune, setShowFineTune] = useState(false); + const [modelName, setModelName] = useState("Qwen2.5-0.5B"); + const [adapterPath, setAdapterPath] = useState(""); + const [autoFineTune, setAutoFineTune] = useState(true); + const eventsEndRef = useRef(null); + const fineTuneEndRef = useRef(null); + + // Draw agent graph on canvas + useEffect(() => { + if (canvasRef.current) { + drawAgentGraph(canvasRef.current, agents); + } + }, [agents]); + + useEffect(() => { + const websocket = new WebSocket("ws://127.0.0.1:8765"); + + websocket.onopen = () => { + setConnected(true); + setWs(websocket); // set the websocket state when the connection opens + console.log("Connected to agent bridge"); + + // Subscribe to all event types + websocket.send(JSON.stringify({ + subscribe: [ + "agent_thought", + "agent_step", + "fine_tune_epoch", + "fine_tune_loss", + "swarm_status", + "objective_started", + "objective_completed", + "objective_failed", + "checkpoint_created", + "consensus_request", + "consensus_result", + "error" + ] + })); + }; + + websocket.onmessage = (event) => { + try { + const message: WebSocketMessage = JSON.parse(event.data); + handleMessage(message); + } catch (e) { + console.error("Failed to parse message:", e); + } + }; + + websocket.onclose = () => { + setConnected(false); + setWs(null); // clear the websocket state when the connection closes + console.log("Disconnected from agent bridge"); + }; + + websocket.onerror = (error) => { + console.error("WebSocket error:", error); + }; + + return () => { + websocket.close(); + }; + }, []); // Empty deps because we only want to run once + + const handleMessage = (message: WebSocketMessage) => { + const { event_type, payload } = message; + + switch (event_type) { + case "agent_thought": + updateAgentThought(payload); + break; + case "agent_step": + updateAgentStep(payload); + break; + case "fine_tune_epoch": + addFineTuneEvent(payload); + break; + case "fine_tune_loss": + updateFineTuneLoss(payload); + break; + case "swarm_status": + // Handle swarm status updates + break; + case "objective_started": + setIsRunning(true); + resetAgents(); + addEvent({ type: "objective_started", payload, timestamp: new Date().toISOString() }); + break; + case "objective_completed": + setIsRunning(false); + addEvent({ type: "objective_completed", payload, timestamp: new Date().toISOString() }); + break; + case "objective_failed": + setIsRunning(false); + addEvent({ type: "objective_failed", payload, timestamp: new Date().toISOString() }); + break; + case "error": + addEvent({ type: "error", payload, timestamp: new Date().toISOString() }); + break; + default: + // Handle response messages + if (payload?.response) { + handleResponse(payload); + } + } + }; + + const updateAgentThought = (payload: any) => { + const { agent, thought, step } = payload; + setAgents(prev => prev.map(a => { + if (a.id === agent) { + const newThoughts = [...a.thoughts, thought]; + return { + ...a, + lastThought: thought, + thoughts: newThoughts.slice(-10), // Keep last 10 thoughts + status: "active" as const, + progress: step || a.progress, + }; + } + return a; + })); + addEvent({ type: "agent_thought", payload, timestamp: new Date().toISOString() }); + }; + + const updateAgentStep = (payload: any) => { + const { agent, status, progress } = payload; + setAgents(prev => prev.map(a => + a.id === agent ? { ...a, status, progress: progress || a.progress } : a + )); + }; + + const addFineTuneEvent = (payload: any) => { + setFineTuneEvents(prev => [...prev.slice(-50), { ...payload, timestamp: new Date().toISOString() }]); + }; + + const updateFineTuneLoss = (payload: any) => { + setFineTuneEvents(prev => prev.map(e => + e.epoch === payload.epoch ? { ...e, ...payload } : e + )); + }; + + const addEvent = (event: AgentEvent) => { + setEvents(prev => [...prev.slice(-100), event]); + // Auto-scroll + setTimeout(() => eventsEndRef.current?.scrollIntoView({ behavior: "smooth" }), 0); + }; + + const handleResponse = (payload: any) => { + // Handle command responses + console.log("Response:", payload); + }; + + const resetAgents = () => { + setAgents(AGENT_ROLES.map(a => ({ ...a, status: "idle" as const, progress: 0, lastThought: "", thoughts: [] }))); + setFineTuneEvents([]); + }; + + const sendCommand = (commandType: string, payload: any) => { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ + command_type: commandType, + payload, + request_id: crypto.randomUUID(), + timestamp: new Date().toISOString(), + })); + } + }; + + const handleSubmitObjective = () => { + if (!objective.trim()) return; + sendCommand("submit_objective", { objective }); + }; + + const handleTriggerFineTune = () => { + if (!adapterPath.trim()) return; + sendCommand("trigger_finetune", { adapter_path: adapterPath }); + }; + + const handlePauseHarness = () => { + sendCommand("pause_harness", {}); + }; + + const handleResumeHarness = () => { + sendCommand("resume_harness", {}); + }; + + const handleSwitchModel = () => { + sendCommand("switch_model", { model: modelName }); + }; + + const getStatusColor = (status: string) => { + switch (status) { + case "active": return "bg-green-500 animate-pulse"; + case "completed": return "bg-blue-500"; + case "error": return "bg-red-500"; + default: return "bg-gray-400"; + } + }; + + const getAgentById = (id: string) => agents.find(a => a.id === id); + + return ( +
+ {/* Sidebar - Agent Graph */} +
+ + + + + + Agent Swarm + + + {connected ? : } + {connected ? "Connected" : "Disconnected"} + + + + +
+ {/* Agent Graph Canvas */} + +
+
+
+ + {/* Controls */} + +
+ Controls + + +
+ +