types.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from __future__ import annotations
  2. from enum import StrEnum
  3. from typing import Any, Literal
  4. from pydantic import BaseModel, Field
  5. class Role(StrEnum):
  6. SYSTEM = "system"
  7. USER = "user"
  8. ASSISTANT = "assistant"
  9. TOOL = "tool"
  10. class Message(BaseModel):
  11. """A single message in the conversation."""
  12. role: Role
  13. content: str | None = None
  14. tool_calls: list[ToolCall] | None = None
  15. tool_call_id: str | None = None
  16. name: str | None = None
  17. # Model reasoning / chain-of-thought text (OpenRouter); not sent back in API history.
  18. reasoning: str | None = None
  19. def to_api_dict(self) -> dict[str, Any]:
  20. """Convert to OpenAI-compatible API format."""
  21. data: dict[str, Any] = {"role": self.role.value}
  22. if self.content is not None:
  23. data["content"] = self.content
  24. if self.tool_calls:
  25. data["tool_calls"] = [tc.to_api_dict() for tc in self.tool_calls]
  26. if self.tool_call_id:
  27. data["tool_call_id"] = self.tool_call_id
  28. if self.name:
  29. data["name"] = self.name
  30. return data
  31. class ToolCall(BaseModel):
  32. """A tool invocation requested by the model."""
  33. id: str
  34. name: str
  35. arguments: str # JSON string
  36. def to_api_dict(self) -> dict[str, Any]:
  37. return {
  38. "id": self.id,
  39. "type": "function",
  40. "function": {
  41. "name": self.name,
  42. "arguments": self.arguments,
  43. },
  44. }
  45. class ToolDefinition(BaseModel):
  46. """OpenAI-compatible tool schema."""
  47. name: str
  48. description: str
  49. parameters: dict[str, Any] = Field(default_factory=lambda: {
  50. "type": "object",
  51. "properties": {},
  52. "required": [],
  53. })
  54. def to_api_dict(self) -> dict[str, Any]:
  55. return {
  56. "type": "function",
  57. "function": {
  58. "name": self.name,
  59. "description": self.description,
  60. "parameters": self.parameters,
  61. },
  62. }
  63. class ToolResult(BaseModel):
  64. """Result of executing a tool."""
  65. tool_call_id: str
  66. name: str
  67. content: str
  68. is_error: bool = False
  69. class SkillInfo(BaseModel):
  70. """Metadata and content for a loaded skill."""
  71. name: str
  72. description: str
  73. content: str
  74. path: str
  75. class AgentEventType(StrEnum):
  76. """Events emitted during agent execution."""
  77. THINKING = "thinking"
  78. TOOL_CALL = "tool_call"
  79. TOOL_RESULT = "tool_result"
  80. MESSAGE = "message"
  81. SKILL_LOADED = "skill_loaded"
  82. DONE = "done"
  83. ERROR = "error"
  84. class AgentEvent(BaseModel):
  85. """A streaming event from the agent loop."""
  86. type: AgentEventType
  87. data: dict[str, Any] = Field(default_factory=dict)
  88. class AgentResult(BaseModel):
  89. """Final result of an agent run."""
  90. content: str
  91. messages: list[Message]
  92. iterations: int
  93. tool_calls_made: int
  94. skills_used: list[str] = Field(default_factory=list)