From a9778d0f9340adabde4b972a30d7e876c4a5fd56 Mon Sep 17 00:00:00 2001 From: Farouk Adeleke Date: Thu, 27 Nov 2025 04:40:00 -0500 Subject: [PATCH] update readme --- agent.json | 2 +- auto_classes.json | 4 ++-- main.py | 4 ++-- src/codex_dspy/agent.py | 47 +++++++++++++++++++------------------ src/index.py | 51 ----------------------------------------- 5 files changed, 30 insertions(+), 78 deletions(-) delete mode 100644 src/index.py diff --git a/agent.json b/agent.json index e0eb7e1..ac56cba 100644 --- a/agent.json +++ b/agent.json @@ -2,7 +2,7 @@ "metadata": { "dependency_versions": { "python": "3.13", - "dspy": "3.0.4b1", + "dspy": "3.0.4", "cloudpickle": "3.1" } } diff --git a/auto_classes.json b/auto_classes.json index 09cafe7..3f0970b 100644 --- a/auto_classes.json +++ b/auto_classes.json @@ -1,4 +1,4 @@ { - "AutoConfig": "src.index.CodexAgentConfig", - "AutoAgent": "src.index.CodexAgent" + "AutoConfig": "src.codex_dspy.agent.CodexAgentConfig", + "AutoAgent": "src.codex_dspy.agent.CodexModule" } \ No newline at end of file diff --git a/main.py b/main.py index 707ab2b..e1d0ff9 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ -from src.index import CodexAgent, CodexAgentConfig +from src.codex_dspy.agent import CodexModule, CodexAgentConfig -codex_agent = CodexAgent(CodexAgentConfig()) +codex_agent = CodexModule(CodexAgentConfig()) def main(): diff --git a/src/codex_dspy/agent.py b/src/codex_dspy/agent.py index 6ac445f..89be8f1 100644 --- a/src/codex_dspy/agent.py +++ b/src/codex_dspy/agent.py @@ -12,7 +12,7 @@ from pydantic import BaseModel import dspy from dspy.primitives.prediction import Prediction from dspy.signatures.signature import Signature, ensure_signature - +from modaic import PrecompiledAgent, PrecompiledConfig from ..codex import Codex, CodexOptions, SandboxMode, ThreadOptions, TurnOptions @@ -38,7 +38,18 @@ def _is_str_type(annotation: Any) -> bool: return False -class CodexModule(dspy.Module): +class CodexAgentConfig(PrecompiledConfig): + signature: str | type[Signature] = "message:str -> answer:str" + working_directory: str = "." + model: Optional[str] = "gpt-4o" + sandbox_mode: Optional[SandboxMode] = None + skip_git_repo_check: bool = False + api_key: Optional[str] = None + base_url: Optional[str] = None + codex_path_override: Optional[str] = "/opt/homebrew/bin/codex" + + +class CodexModule(PrecompiledAgent): """DSPy module for Codex SDK integration. Creates a stateful agent where each instance maintains one conversation thread. @@ -72,21 +83,13 @@ class CodexModule(dspy.Module): >>> print(result.report.severity) # typed access """ - def __init__( - self, - signature: str | type[Signature], - working_directory: str, - model: Optional[str] = None, - sandbox_mode: Optional[SandboxMode] = None, - skip_git_repo_check: bool = False, - api_key: Optional[str] = None, - base_url: Optional[str] = None, - codex_path_override: Optional[str] = None, - ): - super().__init__() + config: CodexAgentConfig + + def __init__(self, config: CodexAgentConfig, **kwargs): + super().__init__(config, **kwargs) # Ensure signature is valid - self.signature = ensure_signature(signature) + self.signature = ensure_signature(config.signature) # Validate: exactly 1 input field, 1 output field if len(self.signature.input_fields) != 1: @@ -112,19 +115,19 @@ class CodexModule(dspy.Module): # Create Codex client self.client = Codex( options=CodexOptions( - api_key=api_key, - base_url=base_url, - codex_path_override=codex_path_override, + api_key=config.api_key, + base_url=config.base_url, + codex_path_override=config.codex_path_override, ) ) # Start thread (1 agent instance = 1 stateful thread) self.thread = self.client.start_thread( options=ThreadOptions( - working_directory=working_directory, - model=model, - sandbox_mode=sandbox_mode, - skip_git_repo_check=skip_git_repo_check, + working_directory=config.working_directory, + model=config.model, + sandbox_mode=config.sandbox_mode, + skip_git_repo_check=config.skip_git_repo_check, ) ) diff --git a/src/index.py b/src/index.py deleted file mode 100644 index 5226f3b..0000000 --- a/src/index.py +++ /dev/null @@ -1,51 +0,0 @@ -import dspy -from modaic import PrecompiledAgent, PrecompiledConfig -from .codex_dspy import CodexModule -from .codex import Codex, CodexOptions, SandboxMode, ThreadOptions, TurnOptions -from dspy.signatures.signature import Signature -from dspy.primitives.prediction import Prediction -from typing import Optional - - -class CodexAgentConfig(PrecompiledConfig): - signature: str | type[Signature] = "message:str -> answer:str" - working_directory: str = "." - model: Optional[str] = "gpt-4o" - sandbox_mode: Optional[SandboxMode] = None - skip_git_repo_check: bool = False - api_key: Optional[str] = None - base_url: Optional[str] = None - codex_path_override: Optional[str] = "/opt/homebrew/bin/codex" - - -class CodexAgent(PrecompiledAgent): - config: CodexAgentConfig - - def __init__(self, config: CodexAgentConfig, **kwargs): - super().__init__(config, **kwargs) - - self.codex_module = CodexModule( - signature=config.signature, - working_directory=config.working_directory, - model=config.model, - sandbox_mode=config.sandbox_mode, - skip_git_repo_check=config.skip_git_repo_check, - api_key=config.api_key, - base_url=config.base_url, - codex_path_override=config.codex_path_override, - ) - - def forward(self, **kwargs) -> Prediction: - return self.codex_module(**kwargs) - - @property - def thread_id(self) -> Optional[str]: - """Get thread ID for this agent instance. - - The thread ID is assigned after the first forward() call. - Useful for debugging and visibility into the conversation state. - - Returns: - Thread ID string, or None if no forward() calls have been made yet - """ - return self.codex_module.thread.id