types.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. def to_api_dict(self) -> dict[str, Any]:
  18. """Convert to OpenAI-compatible API format."""
  19. data: dict[str, Any] = {"role": self.role.value}
  20. if self.content is not None:
  21. data["content"] = self.content
  22. if self.tool_calls:
  23. data["tool_calls"] = [tc.to_api_dict() for tc in self.tool_calls]
  24. if self.tool_call_id:
  25. data["tool_call_id"] = self.tool_call_id
  26. if self.name:
  27. data["name"] = self.name
  28. return data
  29. class ToolCall(BaseModel):
  30. """A tool invocation requested by the model."""
  31. id: str
  32. name: str
  33. arguments: str # JSON string
  34. def to_api_dict(self) -> dict[str, Any]:
  35. return {
  36. "id": self.id,
  37. "type": "function",
  38. "function": {
  39. "name": self.name,
  40. "arguments": self.arguments,
  41. },
  42. }
  43. class ToolDefinition(BaseModel):
  44. """OpenAI-compatible tool schema."""
  45. name: str
  46. description: str
  47. parameters: dict[str, Any] = Field(default_factory=lambda: {
  48. "type": "object",
  49. "properties": {},
  50. "required": [],
  51. })
  52. def to_api_dict(self) -> dict[str, Any]:
  53. return {
  54. "type": "function",
  55. "function": {
  56. "name": self.name,
  57. "description": self.description,
  58. "parameters": self.parameters,
  59. },
  60. }
  61. class ToolResult(BaseModel):
  62. """Result of executing a tool."""
  63. tool_call_id: str
  64. name: str
  65. content: str
  66. is_error: bool = False
  67. class SkillInfo(BaseModel):
  68. """Metadata and content for a loaded skill."""
  69. name: str
  70. description: str
  71. content: str
  72. path: str
  73. class AgentEventType(StrEnum):
  74. """Events emitted during agent execution."""
  75. THINKING = "thinking"
  76. TOOL_CALL = "tool_call"
  77. TOOL_RESULT = "tool_result"
  78. MESSAGE = "message"
  79. SKILL_LOADED = "skill_loaded"
  80. DONE = "done"
  81. ERROR = "error"
  82. class AgentEvent(BaseModel):
  83. """A streaming event from the agent loop."""
  84. type: AgentEventType
  85. data: dict[str, Any] = Field(default_factory=dict)
  86. class AgentResult(BaseModel):
  87. """Final result of an agent run."""
  88. content: str
  89. messages: list[Message]
  90. iterations: int
  91. tool_calls_made: int
  92. skills_used: list[str] = Field(default_factory=list)