update readme
This commit is contained in:
@@ -35,7 +35,7 @@ CODEX_API_KEY="<YOUR_CODEX_API_KEY>"
|
||||
### 2. Install dependencies
|
||||
|
||||
```bash
|
||||
pip install modaic dspy python-dotenv
|
||||
uv add modaic dspy
|
||||
```
|
||||
|
||||
### 3. Use the agent
|
||||
@@ -44,9 +44,6 @@ pip install modaic dspy python-dotenv
|
||||
from modaic import AutoAgent
|
||||
import dspy
|
||||
from pydantic import BaseModel
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
class Dependencies(BaseModel):
|
||||
dependencies: list[str]
|
||||
|
||||
20
main.py
20
main.py
@@ -1,17 +1,19 @@
|
||||
from dotenv import load_dotenv
|
||||
from src.index import CodexAgent, CodexAgentConfig
|
||||
|
||||
load_dotenv()
|
||||
|
||||
codex_agent = CodexAgent(CodexAgentConfig())
|
||||
|
||||
|
||||
def main():
|
||||
codex_agent.push_to_hub("darinkishore/codex-agent", with_code=True, commit_message="add thread id property")
|
||||
#result = codex_agent(message="What files are in this directory?")
|
||||
#print(result.answer) # String response
|
||||
#print(result.trace) # Execution items (commands, files, etc.)
|
||||
#print(result.usage) # Token counts
|
||||
codex_agent.push_to_hub(
|
||||
"darinkishore/codex-agent",
|
||||
with_code=True,
|
||||
commit_message="update readme",
|
||||
)
|
||||
# result = codex_agent(message="What files are in this directory?")
|
||||
# print(result.answer) # String response
|
||||
# print(result.trace) # Execution items (commands, files, etc.)
|
||||
# print(result.usage) # Token counts
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -17,6 +17,8 @@ class Codex:
|
||||
thread_options = options or ThreadOptions()
|
||||
return Thread(self._exec, self._options, thread_options)
|
||||
|
||||
def resume_thread(self, thread_id: str, options: Optional[ThreadOptions] = None) -> Thread:
|
||||
def resume_thread(
|
||||
self, thread_id: str, options: Optional[ThreadOptions] = None
|
||||
) -> Thread:
|
||||
thread_options = options or ThreadOptions()
|
||||
return Thread(self._exec, self._options, thread_options, thread_id)
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Mapping, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover - typing only
|
||||
from pydantic import BaseModel as PydanticBaseModel
|
||||
|
||||
SchemaInput = Mapping[str, object] | type[PydanticBaseModel] | PydanticBaseModel
|
||||
else:
|
||||
SchemaInput = Mapping[str, object]
|
||||
|
||||
@@ -100,7 +100,9 @@ def _parse_usage(payload: object) -> Usage:
|
||||
data = _ensure_dict(payload)
|
||||
return Usage(
|
||||
input_tokens=_ensure_int(data.get("input_tokens"), "input_tokens"),
|
||||
cached_input_tokens=_ensure_int(data.get("cached_input_tokens"), "cached_input_tokens"),
|
||||
cached_input_tokens=_ensure_int(
|
||||
data.get("cached_input_tokens"), "cached_input_tokens"
|
||||
),
|
||||
output_tokens=_ensure_int(data.get("output_tokens"), "output_tokens"),
|
||||
)
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ class SpawnError(CodexError):
|
||||
def __init__(self, command: Sequence[str] | None, error: OSError) -> None:
|
||||
self.command = list(command) if command else None
|
||||
self.original_error = error
|
||||
super().__init__(f"Failed to spawn codex exec: {_format_command(self.command)}: {error}")
|
||||
super().__init__(
|
||||
f"Failed to spawn codex exec: {_format_command(self.command)}: {error}"
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
||||
@@ -82,6 +82,7 @@ class CodexExec:
|
||||
|
||||
stderr_thread: Thread | None = None
|
||||
if process.stderr:
|
||||
|
||||
def _drain_stderr(pipe: io.TextIOBase, buffer: list[str]) -> None:
|
||||
while True:
|
||||
try:
|
||||
|
||||
@@ -171,12 +171,16 @@ def parse_thread_item(payload: object) -> ThreadItem:
|
||||
|
||||
if type_name == "command_execution":
|
||||
command = _ensure_str(payload.get("command"), "command")
|
||||
aggregated_output = _ensure_str(payload.get("aggregated_output"), "aggregated_output")
|
||||
aggregated_output = _ensure_str(
|
||||
payload.get("aggregated_output"), "aggregated_output"
|
||||
)
|
||||
status_str = _ensure_str(payload.get("status"), "status")
|
||||
try:
|
||||
status = CommandExecutionStatus(status_str)
|
||||
except ValueError as exc:
|
||||
raise CodexError(f"Unsupported command execution status: {status_str}") from exc
|
||||
raise CodexError(
|
||||
f"Unsupported command execution status: {status_str}"
|
||||
) from exc
|
||||
exit_code = payload.get("exit_code")
|
||||
exit_value = int(exit_code) if isinstance(exit_code, int) else None
|
||||
return CommandExecutionItem(
|
||||
|
||||
@@ -23,7 +23,11 @@ def _get_pydantic_base_model() -> Type[Any] | None: # pragma: no cover - import
|
||||
|
||||
def _is_pydantic_model(value: object) -> bool:
|
||||
base_model = _get_pydantic_base_model()
|
||||
return isinstance(value, type) and base_model is not None and issubclass(value, base_model)
|
||||
return (
|
||||
isinstance(value, type)
|
||||
and base_model is not None
|
||||
and issubclass(value, base_model)
|
||||
)
|
||||
|
||||
|
||||
def _is_pydantic_instance(value: object) -> bool:
|
||||
|
||||
@@ -53,11 +53,15 @@ class Thread:
|
||||
def id(self) -> Optional[str]:
|
||||
return self._id
|
||||
|
||||
def run_streamed(self, prompt: str, turn_options: Optional[TurnOptions] = None) -> ThreadStream:
|
||||
def run_streamed(
|
||||
self, prompt: str, turn_options: Optional[TurnOptions] = None
|
||||
) -> ThreadStream:
|
||||
events = self._stream_events(prompt, turn_options)
|
||||
return ThreadStream(events=events)
|
||||
|
||||
def run(self, prompt: str, turn_options: Optional[TurnOptions] = None) -> ThreadRunResult:
|
||||
def run(
|
||||
self, prompt: str, turn_options: Optional[TurnOptions] = None
|
||||
) -> ThreadRunResult:
|
||||
final_response = ""
|
||||
items: list[ThreadItem] = []
|
||||
usage: Optional[Usage] = None
|
||||
|
||||
@@ -170,7 +170,9 @@ class CodexModule(dspy.Module):
|
||||
if not _is_str_type(self.output_type):
|
||||
# Parse as Pydantic model
|
||||
try:
|
||||
parsed_output = self.output_type.model_validate_json(result.final_response)
|
||||
parsed_output = self.output_type.model_validate_json(
|
||||
result.final_response
|
||||
)
|
||||
except Exception as e:
|
||||
# Provide helpful error with response preview
|
||||
response_preview = result.final_response[:500]
|
||||
|
||||
10
src/index.py
10
src/index.py
@@ -6,6 +6,7 @@ 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 = "."
|
||||
@@ -16,8 +17,9 @@ class CodexAgentConfig(PrecompiledConfig):
|
||||
base_url: Optional[str] = None
|
||||
codex_path_override: Optional[str] = "/opt/homebrew/bin/codex"
|
||||
|
||||
|
||||
class CodexAgent(PrecompiledAgent):
|
||||
config : CodexAgentConfig
|
||||
config: CodexAgentConfig
|
||||
|
||||
def __init__(self, config: CodexAgentConfig, **kwargs):
|
||||
super().__init__(config, **kwargs)
|
||||
@@ -30,9 +32,9 @@ class CodexAgent(PrecompiledAgent):
|
||||
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
|
||||
codex_path_override=config.codex_path_override,
|
||||
)
|
||||
|
||||
|
||||
def forward(self, **kwargs) -> Prediction:
|
||||
return self.codex_module(**kwargs)
|
||||
|
||||
@@ -46,4 +48,4 @@ class CodexAgent(PrecompiledAgent):
|
||||
Returns:
|
||||
Thread ID string, or None if no forward() calls have been made yet
|
||||
"""
|
||||
return self.codex_module.thread.id
|
||||
return self.codex_module.thread.id
|
||||
|
||||
Reference in New Issue
Block a user