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