1 line
42 KiB
JSON
1 line
42 KiB
JSON
{"repo": "chiruu12/hive", "files": {"docs/agent-guide.md": {"eb61d7793c9cb8cd8af1cf6be9c63127dd363954": {"t": 1785674610.1454635, "n": 20149, "h": "00323c42acb620e5", "c": "# hive-agent SDK Reference (for AI Coding Assistants)\n\n## Package\n\n| Field | Value |\n|-------|-------|\n| Package | `hive-agent` |\n| Install | `pip install hive-agent` / `uv add hive-agent` |\n| Python | `>=3.11` |\n| Import | `from hive import ...` |\n\n## Exports\n\n### Top-level (`from hive import ...`)\n\n```\nAgent, AgentProfile, AgentState, AgentStatus, collect_tools, CommsToolkit,\nConversationMemory, create_runtime_provider, DaemonAgentAdapter, EventLog,\nEventType, ExecutionContext, ExistenceLoop, GenerateResult, GoalOutcome,\nHive, HiveConfig, HiveDaemon, HiveEvent, HiveStore, initialize_hive,\nload_config, make_tool, MCPToolkit, MemoryToolkit, Message, PersistentMemory,\nRole, Step, StressorType, StructuredGenerateResult, StructuredTaskResult,\nSufferingState, Task, TaskResult, TaskStatus, Tool, ToolCall, ToolResult,\nToolkit, tool, Workflow, WorldState, WorldToolkit\n```\n\n### Runtime (`from hive.runtime import ...`)\n\n```\nAgent, collect_tools, CommsToolkit,\nConversationMemory, DaemonAgentAdapter, DaemonDelegationToolkit,\nDelegationToolkit, FileToolkit, GenerateResult, GitToolkit, GoalOutcome,\nmake_tool, MemoryToolkit, Message, PersistentMemory,\nPluginLoader, Role, BaseProvider, ShellToolkit, Step,\nStructuredGenerateResult, StructuredTaskResult, Task, TaskResult, TaskStatus,\nTool, ToolCall, ToolResult, Toolkit, tool, Workflow, WorldToolkit\n```\n\n### Models (`from hive.models.* import ...`)\n\n```\nBaseProvider # from hive.models.base\nAnthropic # from hive.models.anthropic\nOpenAI # from hive.models.openai\nGroq # from hive.models.groq\nFireworks # from hive.models.fireworks\nOllama # from hive.models.ollama\nLMStudio # from hive.models.lmstudio\ncreate_runtime_provider # from hive.models.factory (also from hive)\n```\n\n---\n\n## Agent\n\n### Constructor\n\n```python\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic # or any provider\n\nagent = Agent(\n name: str, # required\n model: BaseProvider, # required\n system_prompt: str = \"\",\n toolkits: list[Toolkit] | None = None,\n tools: list[Tool] | None = None,\n memory: PersistentMemory | None = None,\n max_steps: int = 25,\n temperature: float = 0.0,\n max_cost_usd: float = 0.0, # 0 = no limit\n max_tokens: int = 0, # 0 = default 4096\n)\n```\n\n### Methods\n\n| Method | Signature | Returns | Description |\n|--------|-----------|---------|-------------|\n| `run` | `async (task: Task)` | `TaskResult` | Full ReAct loop with tools |\n| `run_structured` | `async (task: Task, output_type: type[T])` | `StructuredTaskResult[T]` | One-shot structured output via task |\n| `run_once` | `async (message: str, context: str \\| None = None)` | `str` | Single turn, at most one tool round |\n| `run_once_structured` | `async (message: str, output_type: type[T], context: str \\| None = None)` | `T` | Single turn, returns parsed model |\n| `run_once_sync` | `(message: str, context: str \\| None = None)` | `str` | Sync wrapper for `run_once` |\n| `run_once_structured_sync` | `(message: str, output_type: type[T], context: str \\| None = None)` | `T` | Sync wrapper for `run_once_structured` |\n| `get_tools` | `()` | `list[Tool]` | All tools from toolkits + extra tools |\n\n### Minimal Example\n\n```python\nimport asyncio\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\n\nagent = Agent(\n name=\"helper\",\n model=Anthropic.lite(),\n system_prompt=\"You are a helpful assistant.\",\n)\n\nresult = asyncio.run(agent.run(Task(instruction=\"What is 2+2?\")))\nprint(result.output)\n```\n\n### Sync One-Shot Example\n\n```python\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\n\nagent = Agent(name=\"q\", model=Anthropic.lite())\nanswer = agent.run_once_sync(\"What is the capital of France?\")\nprint(answer)\n```\n\n---\n\n## Task / TaskResult\n\n```python\nfrom hive import Task, TaskResult, TaskStatus, StructuredTaskResult\n\n# Task\nTask(\n instruction: str, # required\n id: str = \"task-{auto_hex}\",\n context: dict[str, Any] = {},\n max_steps: int = 25,\n)\n\n# TaskResult fields\nTaskResult(\n task_id: str,\n status: TaskStatus, # COMPLETED | FAILED | MAX_STEPS | PENDING | RUNNING\n output: str = \"\",\n steps_taken: int = 0,\n tool_calls_made: int = 0,\n error: str | None = None,\n duration_seconds: float = 0.0,\n)\n\n# StructuredTaskResult adds:\nStructuredTaskResult[T](\n ...TaskResult fields...,\n parsed: T, # validated Pydantic model instance\n)\n```\n\n---\n\n## Message\n\n```python\nfrom hive import Message, Role\n\n# Static constructors (preferred)\nMessage.system(\"You are a coder.\")\nMessage.user(\"Write hello world.\")\nMessage.assistant(\"Here it is.\", tool_calls=[...])\nMessage.tool_result(tool_call_id=\"id\", content=\"output\", is_error=False, name=\"tool_name\")\n\n# Role enum: SYSTEM | USER | ASSISTANT | TOOL\n\n# Fields (frozen dataclass)\n# .role: Role\n# .content: str\n# .tool_calls: tuple[ToolCall, ...]\n# .tool_call_id: str\n# .name: str\n# .is_error: bool\n```\n\n---\n\n## Tool System\n\n### Pattern 1: `@tool` on Toolkit Methods\n\n```python\nfrom hive import Agent, Toolkit, tool\nfrom hive.models.anthropic import Anthropic\n\nclass SearchToolkit(Toolkit):\n @tool()\n def search(self, query: str, max_results: int = 5) -> str:\n \"\"\"Search a knowledge base.\n\n Args:\n query: The search query string.\n max_results: Maximum number of results to return.\n \"\"\"\n return f\"Found {max_results} results for: {query}\"\n\nagent = Agent(\n name=\"researcher\",\n model=Anthropic.lite(),\n toolkits=[SearchToolkit()],\n)\n```\n\n### Pattern 2: Standalone Functions with `make_tool`\n\n```python\nfrom hive import tool, make_tool\n\n@tool()\ndef calculate(expression: str) -> str:\n \"\"\"Evaluate a math expression.\n\n Args:\n expression: A Python math expression to evaluate.\n \"\"\"\n return str(eval(expression))\n\nt = make_tool(calculate) # -> Tool\n```\n\n### Pattern 3: Batch with `collect_tools`\n\n```python\nfrom hive import tool, collect_tools\n\n@tool()\ndef add(a: int, b: int) -> str:\n \"\"\"Add two numbers.\n\n Args:\n a: First number.\n b: Second number.\n \"\"\"\n return str(a + b)\n\n@tool()\ndef multiply(a: int, b: int) -> str:\n \"\"\"Multiply two numbers.\n\n Args:\n a: First number.\n b: Second number.\n \"\"\"\n return str(a * b)\n\ntools = collect_tools(add, multiply) # -> list[Tool]\n```\n\n### Pattern 4: Async Tool\n\n```python\nfrom hive import Toolkit, tool\n\nclass APIToolkit(Toolkit):\n @tool()\n async def fetch_data(self, url: str) -> str:\n \"\"\"Fetch data from a URL.\n\n Args:\n url: The URL to fetch.\n \"\"\"\n import httpx\n async with httpx.AsyncClient() as client:\n resp = await client.get(url)\n return resp.text[:5000]\n```\n\n### Tool Decorator Options\n\n```python\n@tool() # name = function name, description = docstring\n@tool(name=\"custom_name\") # override tool name\n@tool(description=\"Custom desc\") # override description\n@tool(name=\"foo\", description=\"d\") # override both\n```\n\n### Supported Parameter Types\n\n| Python Type | JSON Schema Type |\n|-------------|-----------------|\n| `str` | `\"string\"` |\n| `int` | `\"integer\"` |\n| `float` | `\"number\"` |\n| `bool` | `\"boolean\"` |\n| `dict` | `\"object\"` |\n| `list[str]` | `\"array\"` with `\"items\": {\"type\": \"string\"}` |\n| `dict[str, int]` | `\"object\"` with `\"additionalProperties\"` |\n| `Literal[\"a\", \"b\"]` | `\"string\"` with `\"enum\": [\"a\", \"b\"]` |\n| `str \\| None` | `\"string\"` (optional) |\n| `BaseModel` subclass | inlined object schema |\n| `@dataclass` | inlined object schema |\n| unannotated | `\"string\"` (with warning) |\n\n---\n\n## Built-in Toolkits\n\n### FileToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.file import FileToolkit\n\nft = FileToolkit(workspace=Path(\"/tmp/work\"))\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `file_read` | `path: str, offset: int = 0, limit: int = 500` | Read file lines |\n| `file_write` | `path: str, content: str` | Write file (creates dirs) |\n| `file_edit` | `path: str, old_text: str, new_text: str` | Replace exact string (must be unique) |\n| `list_dir` | `path: str = \".\", max_depth: int = 2` | List directory tree |\n\n### ShellToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.shell import ShellToolkit\n\nst = ShellToolkit(workspace=Path(\"/tmp/work\"), timeout=30, restrict=True)\n# restrict=True: command allowlist (python, git, npm, curl, etc.)\n# restrict=False: full shell access\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `shell_exec` | `command: str` | Execute shell command (async) |\n\n### GitToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.git import GitToolkit\n\ngt = GitToolkit(workspace=Path(\"/tmp/work\"))\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `git_status` | (none) | `git status --short` |\n| `git_diff` | `staged: bool = False` | Show diff |\n| `git_log` | `count: int = 10` | Show recent commits |\n| `git_add` | `path: str = \".\"` | Stage files |\n| `git_commit` | `message: str` | Create commit |\n| `git_init` | (none) | Init repo |\n\n### DelegationToolkit\n\n```python\nfrom hive.tools.delegation import DelegationToolkit\n\ndelegation = DelegationToolkit(agents={\"researcher\": agent_a, \"coder\": agent_b})\nleader = Agent(name=\"lead\", model=provider, toolkits=[delegation])\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `delegate_task` | `agent_name: str, task: str` | Run task on named agent (async) |\n| `list_agents` | (none) | List available agent names |\n\n---\n\n## Providers\n\n### Tier Presets (Recommended)\n\nEach provider class has `.lite()`, `.standard()`, `.pro()` classmethods:\n\n```python\nfrom hive.models.anthropic import Anthropic\nfrom hive.models.openai import OpenAI\nfrom hive.models.groq import Groq\nfrom hive.models.fireworks import Fireworks\nfrom hive.models.ollama import Ollama\nfrom hive.models.lmstudio import LMStudio\n\nprovider = Anthropic.lite() # Claude Haiku (fast, cheap)\nprovider = Anthropic.standard() # Claude Sonnet (balanced)\nprovider = Anthropic.pro() # Claude Opus (most capable)\nprovider = OpenAI.lite() # GPT-5.4 Nano\nprovider = Groq.lite() # Llama on Groq\nprovider = Ollama.lite() # Local model\n```\n\n### Factory (String-Based Routing)\n\n```python\nfrom hive import create_runtime_provider\n\nprovider = create_runtime_provider(\"claude-haiku-4-5\")\n```\n\n`create_runtime_provider` is located in `hive.models.factory` and re-exported from `hive`.\n\n### Routing Table\n\n| Model String | Provider | Env Var Required |\n|-------------|----------|-----------------|\n| `claude-haiku-4-5` | `Anthropic` | `ANTHROPIC_API_KEY` |\n| `claude-sonnet-4-6` | `Anthropic` | `ANTHROPIC_API_KEY` |\n| `gpt-5.4-nano` | `OpenAI` | `OPENAI_API_KEY` |\n| `gpt-5.4-mini` | `OpenAI` | `OPENAI_API_KEY` |\n| `fireworks:deepseek-v4-pro` | `Fireworks` | `FIREWORKS_API_KEY` |\n| `groq:llama-3.3-70b-versatile` | `Groq` | `GROQ_API_KEY` |\n| `ollama:llama3.2` | `Ollama` (localhost:11434) | none |\n| `lmstudio:loaded-model` | `LMStudio` (localhost:1234) | none |\n\n### Direct Construction\n\n```python\nfrom hive.models.anthropic import Anthropic\nfrom hive.models.openai import OpenAI\nfrom hive.models.ollama import Ollama\n\n# Anthropic\np = Anthropic(model=\"claude-haiku-4-5\", api_key=\"sk-ant-...\")\n\n# OpenAI\np = OpenAI(model=\"gpt-5.4-nano\", api_key=\"sk-...\")\n\n# Custom base URL (Fireworks, Together, etc.)\np = OpenAI(\n model=\"accounts/fireworks/models/deepseek-v3\",\n api_key=\"fw-...\",\n base_url=\"https://api.fireworks.ai/inference/v1\",\n)\n\n# Local (Ollama)\np = Ollama(model=\"llama3.2\")\n```\n\n---\n\n## Structured Output\n\n### One-Shot (Returns Model Directly)\n\n```python\nfrom pydantic import BaseModel\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\n\nclass Sentiment(BaseModel):\n label: str\n confidence: float\n\nagent = Agent(name=\"s\", model=Anthropic.lite())\nresult = agent.run_once_structured_sync(\"Analyze: 'I love this!'\", output_type=Sentiment)\n# result is a Sentiment instance\nprint(result.label, result.confidence)\n```\n\n### Task-Based (Returns StructuredTaskResult)\n\n```python\nimport asyncio\nfrom pydantic import BaseModel\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\n\nclass Plan(BaseModel):\n steps: list[str]\n estimated_hours: float\n\nagent = Agent(name=\"planner\", model=Anthropic.lite())\n\nresult = asyncio.run(\n agent.run_structured(\n Task(instruction=\"Plan a blog migration\"),\n output_type=Plan,\n )\n)\nprint(result.status) # TaskStatus.COMPLETED\nprint(result.parsed.steps) # [\"Step 1...\", ...]\nprint(result.parsed.estimated_hours)\n```\n\n---\n\n## MCP Integration\n\n```python\nimport asyncio\nfrom hive import Agent, Task, MCPToolkit\nfrom hive.models.anthropic import Anthropic\n\nasync def main():\n async with await MCPToolkit.from_stdio(\n \"npx\", [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"]\n ) as mcp:\n agent = Agent(\n name=\"fs-agent\",\n model=Anthropic.lite(),\n toolkits=[mcp],\n )\n result = await agent.run(Task(instruction=\"List all .txt files in /tmp\"))\n print(result.output)\n\nasyncio.run(main())\n```\n\n### MCPToolkit.from_stdio\n\n```python\nMCPToolkit.from_stdio(\n command: str, # executable (e.g. \"npx\", \"python\")\n args: list[str] | None = None, # command arguments\n env: dict[str, str] | None = None, # environment variables\n cwd: str | Path | None = None, # working directory\n) -> MCPToolkit\n```\n\n### MCPToolkit.from_config\n\n```python\nMCPToolkit.from_config({\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"],\n \"env\": {\"NODE_ENV\": \"production\"},\n \"cwd\": \"/opt/servers\",\n})\n```\n\n---\n\n## Workflow\n\n```python\nimport asyncio\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\nfrom hive.runtime import Workflow, Step\n\nlite = Anthropic.lite()\nresearcher = Agent(name=\"researcher\", model=lite)\nwriter = Agent(name=\"writer\", model=lite)\n\nworkflow = Workflow(\n name=\"blog-pipeline\",\n steps=[\n Step(\n name=\"research\",\n agent=researcher,\n instruction=\"Research the topic: {topic}\",\n output_key=\"research\",\n ),\n Step(\n name=\"write\",\n agent=writer,\n instruction=\"Write a blog post using this research:\\n{research}\",\n output_key=\"draft\",\n ),\n ],\n)\n\nctx = asyncio.run(workflow.run({\"topic\": \"async Python\"}))\nprint(ctx[\"draft\"])\n```\n\n### Step with Custom Function\n\n```python\nfrom hive.runtime import Step\n\nasync def transform(context: dict) -> str:\n return context[\"raw_data\"].upper()\n\nstep = Step(name=\"transform\", fn=transform, output_key=\"transformed\")\n```\n\n---\n\n## PersistentMemory\n\n```python\nfrom pathlib import Path\nfrom hive import Agent, PersistentMemory\nfrom hive.models.anthropic import Anthropic\n\nmemory = PersistentMemory(agent_name=\"coder\", hive_dir=Path(\".hive\"))\n\nagent = Agent(\n name=\"coder\",\n model=Anthropic.lite(),\n memory=memory,\n)\n# Agent auto-recalls relevant memories at task start\n# Store/recall manually:\n# await memory.store(\"learned X about the codebase\")\n# entries = await memory.recall(\"database schema\", limit=5)\n```\n\n---\n\n## Hive Facade (Daemon Mode)\n\n```python\nfrom pathlib import Path\nfrom hive import Hive\n\nh = Hive(path=Path(\".\"))\nh.init() # create .hive/ directory structure\nagent_id = h.spawn(\"coder\") # spawn from preset profile\nh.spawn(\"coder\", model=\"gpt-5.4-nano\") # override model\nh.start(cycles=10, heartbeat=10) # run 10 daemon cycles (blocking)\nh.status() # -> list[dict] with agent_id, name, role, status, goal\nh.nudge(\"coder\", \"write tests next\") # send message to agent\nh.kill(\"coder\") # terminate agent\nh.stop() # signal daemon to stop\n```\n\n---\n\n## Environment Variables\n\n| Variable | Provider | Required For |\n|----------|----------|-------------|\n| `ANTHROPIC_API_KEY` | Anthropic | `claude-*` models |\n| `OPENAI_API_KEY` | OpenAI | `gpt-*` models |\n| `FIREWORKS_API_KEY` | Fireworks | `fireworks:*` models |\n| `GROQ_API_KEY` | Groq | `groq:*` models |\n| (none) | Ollama | `ollama:*` (local) |\n| (none) | LM Studio | `lmstudio:*` (local) |\n\n---\n\n## Common Recipes\n\n### Agent with Tools (Full ReAct Loop)\n\n```python\nimport asyncio\nfrom pathlib import Path\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.file import FileToolkit\nfrom hive.tools.shell import ShellToolkit\n\nagent = Agent(\n name=\"dev\",\n model=Anthropic.standard(),\n system_prompt=\"You are a senior developer.\",\n toolkits=[\n FileToolkit(workspace=Path(\"./project\")),\n ShellToolkit(workspace=Path(\"./project\"), restrict=False),\n ],\n max_steps=15,\n max_cost_usd=0.50,\n)\n\nresult = asyncio.run(agent.run(Task(instruction=\"Add type hints to all functions in main.py\")))\nprint(result.status, result.steps_taken, result.tool_calls_made)\n```\n\n### Multi-Agent Delegation\n\n```python\nimport asyncio\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.delegation import DelegationToolkit\nfrom hive.tools.file import FileToolkit\nfrom hive.tools.shell import ShellToolkit\nfrom pathlib import Path\n\nws = Path(\"./project\")\n\nresearcher = Agent(\n name=\"researcher\",\n model=Anthropic.lite(),\n toolkits=[ShellToolkit(workspace=ws)],\n)\ncoder = Agent(\n name=\"coder\",\n model=Anthropic.standard(),\n toolkits=[FileToolkit(workspace=ws), ShellToolkit(workspace=ws)],\n)\n\nlead = Agent(\n name=\"lead\",\n model=Anthropic.standard(),\n toolkits=[DelegationToolkit(agents={\"researcher\": researcher, \"coder\": coder})],\n system_prompt=\"You are a tech lead. Delegate research and coding tasks.\",\n)\n\nresult = asyncio.run(lead.run(Task(instruction=\"Add a /health endpoint to the API\")))\n```\n\n### Mixed Toolkits + Standalone Tools\n\n```python\nfrom hive import Agent, Toolkit, tool, make_tool\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.file import FileToolkit\nfrom pathlib import Path\n\n@tool()\ndef timestamp() -> str:\n \"\"\"Return the current UTC timestamp.\"\"\"\n from datetime import datetime, timezone\n return datetime.now(timezone.utc).isoformat()\n\nagent = Agent(\n name=\"mixed\",\n model=Anthropic.lite(),\n toolkits=[FileToolkit(workspace=Path(\"/tmp/work\"))],\n tools=[make_tool(timestamp)],\n)\n```\n\n---\n\n## Gotchas\n\n1. `@tool()` needs parentheses -- it is a decorator factory, not a decorator\n2. `run()` and `run_once()` are async -- use `asyncio.run()` or the `_sync` variants\n3. Tool functions MUST have type annotations -- untyped params default to `str`\n4. Docstrings with an `Args:` section are how parameter descriptions reach the LLM\n5. `Toolkit.get_tools()` skips methods starting with `_`\n6. `ShellToolkit(restrict=True)` uses a command allowlist -- pass `restrict=False` for full access\n7. `FileToolkit` blocks path traversal outside its `workspace` directory\n8. `max_cost_usd=0` means unlimited -- set a budget for production use\n9. `run_once` does at most one tool-use round then a final generation\n10. `run` does the full multi-step ReAct loop -- use for complex multi-tool tasks\n11. Local models (`ollama:*`, `lmstudio:*`) may not support native structured output -- fallback is automatic\n12. `.env` files are NOT auto-loaded into `os.environ` -- set env vars explicitly or use `dotenv`\n13. `run_once_sync` / `run_once_structured_sync` create a new event loop -- do not call from within an existing async context (it uses a thread pool as a workaround, but prefer async when possible)\n14. `collect_tools()` applies `@tool()` automatically if the function is not already decorated\n15. Tool return values are stringified -- return `str` for predictable LLM input; `dict`/`list` are JSON-serialized\n"}}, "docs/api/sdk-reference.md": {"eb61d7793c9cb8cd8af1cf6be9c63127dd363954": {"t": 1785674611.6240737, "n": 20452, "h": "660652200c8041aa", "c": "# hive-agent SDK Reference (for AI Coding Assistants)\n\n## Package\n\n| Field | Value |\n|-------|-------|\n| Package | `hive-agent` |\n| Install | `pip install hive-agent` / `uv add hive-agent` |\n| Python | `>=3.11` |\n| Import | `from hive import ...` |\n\n## Exports\n\n### Top-level (`from hive import ...`)\n\n```\nAgent, AgentProfile, AgentState, AgentStatus, collect_tools, CommsToolkit,\nConversationMemory, create_runtime_provider, DaemonAgentAdapter, EventLog,\nEventType, ExecutionContext, ExistenceLoop, GenerateResult, GoalOutcome,\nHive, HiveConfig, HiveDaemon, HiveEvent, HiveStore, initialize_hive,\nload_config, make_tool, MCPToolkit, MemoryToolkit, Message, PersistentMemory,\nRole, Step, StressorType, StructuredGenerateResult, StructuredTaskResult,\nSufferingState, Task, TaskResult, TaskStatus, Tool, ToolCall, ToolResult,\nToolkit, tool, Workflow, WorldState, WorldToolkit\n```\n\n### Runtime (`from hive.runtime import ...`)\n\n```\nAgent, collect_tools, CommsToolkit,\nConversationMemory, DaemonAgentAdapter, DaemonDelegationToolkit,\nDelegationToolkit, FileToolkit, GenerateResult, GitToolkit, GoalOutcome,\nmake_tool, MemoryToolkit, Message, PersistentMemory,\nPluginLoader, Role, BaseProvider, ShellToolkit, Step,\nStructuredGenerateResult, StructuredTaskResult, Task, TaskResult, TaskStatus,\nTool, ToolCall, ToolResult, Toolkit, tool, Workflow, WorldToolkit\n```\n\n### Models (`from hive.models.* import ...`)\n\n```\nBaseProvider # from hive.models.base\nAnthropic # from hive.models.anthropic\nOpenAI # from hive.models.openai\nGroq # from hive.models.groq\nFireworks # from hive.models.fireworks\nOllama # from hive.models.ollama\nLMStudio # from hive.models.lmstudio\ncreate_runtime_provider # from hive.models.factory (also from hive)\n```\n\n---\n\n## Agent\n\n### Constructor\n\n```python\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic # or any provider\n\nagent = Agent(\n name: str, # required\n model: BaseProvider, # required\n system_prompt: str = \"\",\n toolkits: list[Toolkit] | None = None,\n tools: list[Tool] | None = None,\n memory: PersistentMemory | None = None,\n max_steps: int = 25,\n temperature: float = 0.0,\n max_cost_usd: float = 0.0, # 0 = no limit\n max_tokens: int = 0, # 0 = default 4096\n)\n```\n\n### Methods\n\n| Method | Signature | Returns | Description |\n|--------|-----------|---------|-------------|\n| `run` | `async (task: Task)` | `TaskResult` | Full ReAct loop with tools |\n| `run_structured` | `async (task: Task, output_type: type[T])` | `StructuredTaskResult[T]` | One-shot structured output via task |\n| `run_once` | `async (message: str, context: str \\| None = None)` | `str` | Single turn, at most one tool round |\n| `run_once_structured` | `async (message: str, output_type: type[T], context: str \\| None = None)` | `T` | Single turn, returns parsed model |\n| `run_once_sync` | `(message: str, context: str \\| None = None)` | `str` | Sync wrapper for `run_once` |\n| `run_once_structured_sync` | `(message: str, output_type: type[T], context: str \\| None = None)` | `T` | Sync wrapper for `run_once_structured` |\n| `get_tools` | `()` | `list[Tool]` | All tools from toolkits + extra tools |\n\n### Minimal Example\n\n```python\nimport asyncio\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\n\nagent = Agent(\n name=\"helper\",\n model=Anthropic.lite(),\n system_prompt=\"You are a helpful assistant.\",\n)\n\nresult = asyncio.run(agent.run(Task(instruction=\"What is 2+2?\")))\nprint(result.output)\n```\n\n### Sync One-Shot Example\n\n```python\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\n\nagent = Agent(name=\"q\", model=Anthropic.lite())\nanswer = agent.run_once_sync(\"What is the capital of France?\")\nprint(answer)\n```\n\n---\n\n## Task / TaskResult\n\n```python\nfrom hive import Task, TaskResult, TaskStatus, StructuredTaskResult\n\n# Task\nTask(\n instruction: str, # required\n id: str = \"task-{auto_hex}\",\n context: dict[str, Any] = {},\n max_steps: int = 25,\n)\n\n# TaskResult fields\nTaskResult(\n task_id: str,\n status: TaskStatus, # COMPLETED | FAILED | MAX_STEPS | PENDING | RUNNING\n output: str = \"\",\n steps_taken: int = 0,\n tool_calls_made: int = 0,\n error: str | None = None,\n duration_seconds: float = 0.0,\n)\n\n# StructuredTaskResult adds:\nStructuredTaskResult[T](\n ...TaskResult fields...,\n parsed: T | None, # validated model on COMPLETED; None on FAILED\n)\n```\n\n---\n\n## Message\n\n```python\nfrom hive import Message, Role\n\n# Static constructors (preferred)\nMessage.system(\"You are a coder.\")\nMessage.user(\"Write hello world.\")\nMessage.assistant(\"Here it is.\", tool_calls=[...])\nMessage.tool_result(tool_call_id=\"id\", content=\"output\", is_error=False, name=\"tool_name\")\n\n# Role enum: SYSTEM | USER | ASSISTANT | TOOL\n\n# Fields (frozen dataclass)\n# .role: Role\n# .content: str\n# .tool_calls: tuple[ToolCall, ...]\n# .tool_call_id: str\n# .name: str\n# .is_error: bool\n```\n\n---\n\n## Tool System\n\n### Pattern 1: `@tool` on Toolkit Methods\n\n```python\nfrom hive import Agent, Toolkit, tool\nfrom hive.models.anthropic import Anthropic\n\nclass SearchToolkit(Toolkit):\n @tool()\n def search(self, query: str, max_results: int = 5) -> str:\n \"\"\"Search a knowledge base.\n\n Args:\n query: The search query string.\n max_results: Maximum number of results to return.\n \"\"\"\n return f\"Found {max_results} results for: {query}\"\n\nagent = Agent(\n name=\"researcher\",\n model=Anthropic.lite(),\n toolkits=[SearchToolkit()],\n)\n```\n\n### Pattern 2: Standalone Functions with `make_tool`\n\n```python\nfrom hive import tool, make_tool\n\n@tool()\ndef calculate(expression: str) -> str:\n \"\"\"Evaluate a math expression.\n\n Args:\n expression: A Python math expression to evaluate.\n \"\"\"\n return str(eval(expression))\n\nt = make_tool(calculate) # -> Tool\n```\n\n### Pattern 3: Batch with `collect_tools`\n\n```python\nfrom hive import tool, collect_tools\n\n@tool()\ndef add(a: int, b: int) -> str:\n \"\"\"Add two numbers.\n\n Args:\n a: First number.\n b: Second number.\n \"\"\"\n return str(a + b)\n\n@tool()\ndef multiply(a: int, b: int) -> str:\n \"\"\"Multiply two numbers.\n\n Args:\n a: First number.\n b: Second number.\n \"\"\"\n return str(a * b)\n\ntools = collect_tools(add, multiply) # -> list[Tool]\n```\n\n### Pattern 4: Async Tool\n\n```python\nfrom hive import Toolkit, tool\n\nclass APIToolkit(Toolkit):\n @tool()\n async def fetch_data(self, url: str) -> str:\n \"\"\"Fetch data from a URL.\n\n Args:\n url: The URL to fetch.\n \"\"\"\n import httpx\n async with httpx.AsyncClient() as client:\n resp = await client.get(url)\n return resp.text[:5000]\n```\n\n### Tool Decorator Options\n\n```python\n@tool() # name = function name, description = docstring\n@tool(name=\"custom_name\") # override tool name\n@tool(description=\"Custom desc\") # override description\n@tool(name=\"foo\", description=\"d\") # override both\n```\n\n### Supported Parameter Types\n\n| Python Type | JSON Schema Type |\n|-------------|-----------------|\n| `str` | `\"string\"` |\n| `int` | `\"integer\"` |\n| `float` | `\"number\"` |\n| `bool` | `\"boolean\"` |\n| `dict` | `\"object\"` |\n| `list[str]` | `\"array\"` with `\"items\": {\"type\": \"string\"}` |\n| `dict[str, int]` | `\"object\"` with `\"additionalProperties\"` |\n| `Literal[\"a\", \"b\"]` | `\"string\"` with `\"enum\": [\"a\", \"b\"]` |\n| `str \\| None` | `\"string\"` (optional) |\n| `BaseModel` subclass | inlined object schema |\n| `@dataclass` | inlined object schema |\n| unannotated | `\"string\"` (with warning) |\n\n---\n\n## Built-in Toolkits\n\n### FileToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.file import FileToolkit\n\nft = FileToolkit(workspace=Path(\"/tmp/work\"))\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `file_read` | `path: str, offset: int = 0, limit: int = 500` | Read file lines |\n| `file_write` | `path: str, content: str` | Write file (creates dirs) |\n| `file_edit` | `path: str, old_text: str, new_text: str` | Replace exact string (must be unique) |\n| `list_dir` | `path: str = \".\", max_depth: int = 2` | List directory tree |\n\n### ShellToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.shell import ShellToolkit\n\nst = ShellToolkit(workspace=Path(\"/tmp/work\"), timeout=30, restrict=True)\n# restrict=True: command allowlist (python, git, npm, curl, etc.)\n# restrict=False: full shell access\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `shell_exec` | `command: str` | Execute shell command (async) |\n\n### GitToolkit\n\n```python\nfrom pathlib import Path\nfrom hive.tools.git import GitToolkit\n\ngt = GitToolkit(workspace=Path(\"/tmp/work\"))\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `git_status` | (none) | `git status --short` |\n| `git_diff` | `staged: bool = False` | Show diff |\n| `git_log` | `count: int = 10` | Show recent commits |\n| `git_add` | `path: str = \".\"` | Stage files |\n| `git_commit` | `message: str` | Create commit |\n| `git_init` | (none) | Init repo |\n\n### DelegationToolkit\n\n```python\nfrom hive.tools.delegation import DelegationToolkit\n\ndelegation = DelegationToolkit(agents={\"researcher\": agent_a, \"coder\": agent_b})\nleader = Agent(name=\"lead\", model=provider, toolkits=[delegation])\n```\n\n| Tool | Parameters | Description |\n|------|-----------|-------------|\n| `delegate_task` | `agent_name: str, task: str` | Run task on named agent (async) |\n| `list_agents` | (none) | List available agent names |\n\n---\n\n## Providers\n\n### Tier Presets (Recommended)\n\nEach provider class has `.lite()`, `.standard()`, `.pro()` classmethods:\n\n```python\nfrom hive.models.anthropic import Anthropic\nfrom hive.models.openai import OpenAI\nfrom hive.models.groq import Groq\nfrom hive.models.fireworks import Fireworks\nfrom hive.models.ollama import Ollama\nfrom hive.models.lmstudio import LMStudio\n\nprovider = Anthropic.lite() # Claude Haiku (fast, cheap)\nprovider = Anthropic.standard() # Claude Sonnet (balanced)\nprovider = Anthropic.pro() # Claude Opus (most capable)\nprovider = OpenAI.lite() # GPT-5.4 Nano\nprovider = Groq.lite() # Llama on Groq\nprovider = Ollama.lite() # Local model\n```\n\n### Factory (String-Based Routing)\n\n```python\nfrom hive import create_runtime_provider\n\nprovider = create_runtime_provider(\"claude-haiku-4-5\")\n```\n\n`create_runtime_provider` is located in `hive.models.factory` and re-exported from `hive`.\n\n### Routing Table\n\n| Model String | Provider | Env Var Required |\n|-------------|----------|-----------------|\n| `claude-haiku-4-5` | `Anthropic` | `ANTHROPIC_API_KEY` |\n| `claude-sonnet-4-6` | `Anthropic` | `ANTHROPIC_API_KEY` |\n| `gpt-5.4-nano` | `OpenAI` | `OPENAI_API_KEY` |\n| `gpt-5.4-mini` | `OpenAI` | `OPENAI_API_KEY` |\n| `fireworks:deepseek-v4-pro` | `Fireworks` | `FIREWORKS_API_KEY` |\n| `groq:llama-3.3-70b-versatile` | `Groq` | `GROQ_API_KEY` |\n| `ollama:llama3.2` | `Ollama` (localhost:11434) | none |\n| `lmstudio:loaded-model` | `LMStudio` (localhost:1234) | none |\n\n### Direct Construction\n\n```python\nfrom hive.models.anthropic import Anthropic\nfrom hive.models.openai import OpenAI\nfrom hive.models.ollama import Ollama\n\n# Anthropic\np = Anthropic(model=\"claude-haiku-4-5\", api_key=\"sk-ant-...\")\n\n# OpenAI\np = OpenAI(model=\"gpt-5.4-nano\", api_key=\"sk-...\")\n\n# Custom base URL (Fireworks, Together, etc.)\np = OpenAI(\n model=\"accounts/fireworks/models/deepseek-v3\",\n api_key=\"fw-...\",\n base_url=\"https://api.fireworks.ai/inference/v1\",\n)\n\n# Local (Ollama)\np = Ollama(model=\"llama3.2\")\n```\n\n---\n\n## Structured Output\n\n### One-Shot (Returns Model Directly)\n\n```python\nfrom pydantic import BaseModel\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\n\nclass Sentiment(BaseModel):\n label: str\n confidence: float\n\nagent = Agent(name=\"s\", model=Anthropic.lite())\nresult = agent.run_once_structured_sync(\"Analyze: 'I love this!'\", output_type=Sentiment)\n# result is a Sentiment instance\nprint(result.label, result.confidence)\n```\n\n### Task-Based (Returns StructuredTaskResult)\n\n```python\nimport asyncio\nfrom pydantic import BaseModel\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\n\nclass Plan(BaseModel):\n steps: list[str]\n estimated_hours: float\n\nagent = Agent(name=\"planner\", model=Anthropic.lite())\n\nresult = asyncio.run(\n agent.run_structured(\n Task(instruction=\"Plan a blog migration\"),\n output_type=Plan,\n )\n)\nprint(result.status) # TaskStatus.COMPLETED\nprint(result.parsed.steps) # [\"Step 1...\", ...]\nprint(result.parsed.estimated_hours)\n```\n\n---\n\n## MCP Integration\n\n```python\nimport asyncio\nfrom hive import Agent, Task, MCPToolkit\nfrom hive.models.anthropic import Anthropic\n\nasync def main():\n async with await MCPToolkit.from_stdio(\n \"npx\", [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"]\n ) as mcp:\n agent = Agent(\n name=\"fs-agent\",\n model=Anthropic.lite(),\n toolkits=[mcp],\n )\n result = await agent.run(Task(instruction=\"List all .txt files in /tmp\"))\n print(result.output)\n\nasyncio.run(main())\n```\n\n### MCPToolkit.from_stdio\n\n```python\nMCPToolkit.from_stdio(\n command: str, # executable (e.g. \"npx\", \"python\")\n args: list[str] | None = None, # command arguments\n env: dict[str, str] | None = None, # environment variables\n cwd: str | Path | None = None, # working directory\n) -> MCPToolkit\n```\n\n### MCPToolkit.from_config\n\n```python\nMCPToolkit.from_config({\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"],\n \"env\": {\"NODE_ENV\": \"production\"},\n \"cwd\": \"/opt/servers\",\n})\n```\n\n---\n\n## Workflow\n\n```python\nimport asyncio\nfrom hive import Agent\nfrom hive.models.anthropic import Anthropic\nfrom hive.runtime import Workflow, Step\n\nlite = Anthropic.lite()\nresearcher = Agent(name=\"researcher\", model=lite)\nwriter = Agent(name=\"writer\", model=lite)\n\nworkflow = Workflow(\n name=\"blog-pipeline\",\n steps=[\n Step(\n name=\"research\",\n agent=researcher,\n instruction=\"Research the topic: {topic}\",\n output_key=\"research\",\n ),\n Step(\n name=\"write\",\n agent=writer,\n instruction=\"Write a blog post using this research:\\n{research}\",\n output_key=\"draft\",\n ),\n ],\n)\n\nctx = asyncio.run(workflow.run({\"topic\": \"async Python\"}))\nprint(ctx[\"draft\"])\n```\n\n### Step with Custom Function\n\n```python\nfrom hive.runtime import Step\n\nasync def transform(context: dict) -> str:\n return context[\"raw_data\"].upper()\n\nstep = Step(name=\"transform\", fn=transform, output_key=\"transformed\")\n```\n\n---\n\n## PersistentMemory\n\n```python\nfrom pathlib import Path\nfrom hive import Agent, PersistentMemory\nfrom hive.models.anthropic import Anthropic\n\nmemory = PersistentMemory(agent_name=\"coder\", hive_dir=Path(\".hive\"))\n\nagent = Agent(\n name=\"coder\",\n model=Anthropic.lite(),\n memory=memory,\n)\n# Agent auto-recalls relevant memories at task start\n# Store/recall manually:\n# await memory.store(\"learned X about the codebase\")\n# entries = await memory.recall(\"database schema\", limit=5)\n```\n\n---\n\n## Hive Facade (Daemon Mode)\n\n```python\nfrom pathlib import Path\nfrom hive import Hive\n\nh = Hive(path=Path(\".\"))\nh.init() # optional -- .hive/ is created lazily on first use\nagent_id = h.spawn(\"coder\") # spawn from preset profile\nh.spawn(\"coder\", model=\"gpt-5.4-nano\") # override model\nh.start(cycles=10, heartbeat=10) # run 10 daemon cycles (blocking)\nh.status() # -> list[dict] with agent_id, name, role, status, goal\nh.nudge(\"coder\", \"write tests next\") # send message to agent\nh.kill(\"coder\") # terminate agent\nh.stop() # signal daemon to stop\n```\n\n`Hive` is also a context manager -- `init()` is optional, and the daemon is\nstopped on exit:\n\n```python\nwith Hive(Path(\".\")) as h: # sync\n h.spawn(\"coder\")\n\nasync with Hive(Path(\".\")) as h: # async (native init, no thread hop)\n h.spawn(\"coder\")\n```\n\n---\n\n## Environment Variables\n\n| Variable | Provider | Required For |\n|----------|----------|-------------|\n| `ANTHROPIC_API_KEY` | Anthropic | `claude-*` models |\n| `OPENAI_API_KEY` | OpenAI | `gpt-*` models |\n| `FIREWORKS_API_KEY` | Fireworks | `fireworks:*` models |\n| `GROQ_API_KEY` | Groq | `groq:*` models |\n| (none) | Ollama | `ollama:*` (local) |\n| (none) | LM Studio | `lmstudio:*` (local) |\n\n---\n\n## Common Recipes\n\n### Agent with Tools (Full ReAct Loop)\n\n```python\nimport asyncio\nfrom pathlib import Path\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.file import FileToolkit\nfrom hive.tools.shell import ShellToolkit\n\nagent = Agent(\n name=\"dev\",\n model=Anthropic.standard(),\n system_prompt=\"You are a senior developer.\",\n toolkits=[\n FileToolkit(workspace=Path(\"./project\")),\n ShellToolkit(workspace=Path(\"./project\"), restrict=False),\n ],\n max_steps=15,\n max_cost_usd=0.50,\n)\n\nresult = asyncio.run(agent.run(Task(instruction=\"Add type hints to all functions in main.py\")))\nprint(result.status, result.steps_taken, result.tool_calls_made)\n```\n\n### Multi-Agent Delegation\n\n```python\nimport asyncio\nfrom hive import Agent, Task\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.delegation import DelegationToolkit\nfrom hive.tools.file import FileToolkit\nfrom hive.tools.shell import ShellToolkit\nfrom pathlib import Path\n\nws = Path(\"./project\")\n\nresearcher = Agent(\n name=\"researcher\",\n model=Anthropic.lite(),\n toolkits=[ShellToolkit(workspace=ws)],\n)\ncoder = Agent(\n name=\"coder\",\n model=Anthropic.standard(),\n toolkits=[FileToolkit(workspace=ws), ShellToolkit(workspace=ws)],\n)\n\nlead = Agent(\n name=\"lead\",\n model=Anthropic.standard(),\n toolkits=[DelegationToolkit(agents={\"researcher\": researcher, \"coder\": coder})],\n system_prompt=\"You are a tech lead. Delegate research and coding tasks.\",\n)\n\nresult = asyncio.run(lead.run(Task(instruction=\"Add a /health endpoint to the API\")))\n```\n\n### Mixed Toolkits + Standalone Tools\n\n```python\nfrom hive import Agent, Toolkit, tool, make_tool\nfrom hive.models.anthropic import Anthropic\nfrom hive.tools.file import FileToolkit\nfrom pathlib import Path\n\n@tool()\ndef timestamp() -> str:\n \"\"\"Return the current UTC timestamp.\"\"\"\n from datetime import datetime, timezone\n return datetime.now(timezone.utc).isoformat()\n\nagent = Agent(\n name=\"mixed\",\n model=Anthropic.lite(),\n toolkits=[FileToolkit(workspace=Path(\"/tmp/work\"))],\n tools=[make_tool(timestamp)],\n)\n```\n\n---\n\n## Gotchas\n\n1. `@tool()` needs parentheses -- it is a decorator factory, not a decorator\n2. `run()` and `run_once()` are async -- use `asyncio.run()` or the `_sync` variants\n3. Tool functions MUST have type annotations -- untyped params default to `str`\n4. Docstrings with an `Args:` section are how parameter descriptions reach the LLM\n5. `Toolkit.get_tools()` skips methods starting with `_`\n6. `ShellToolkit(restrict=True)` uses a command allowlist -- pass `restrict=False` for full access\n7. `FileToolkit` blocks path traversal outside its `workspace` directory\n8. `max_cost_usd=0` means unlimited -- set a budget for production use\n9. `run_once` does at most one tool-use round then a final generation\n10. `run` does the full multi-step ReAct loop -- use for complex multi-tool tasks\n11. Local models (`ollama:*`, `lmstudio:*`) may not support native structured output -- fallback is automatic\n12. `.env` files are NOT auto-loaded into `os.environ` -- set env vars explicitly or use `dotenv`\n13. `run_once_sync` / `run_once_structured_sync` create a new event loop -- do not call from within an existing async context (it uses a thread pool as a workaround, but prefer async when possible)\n14. `collect_tools()` applies `@tool()` automatically if the function is not already decorated\n15. Tool return values are stringified -- return `str` for predictable LLM input; `dict`/`list` are JSON-serialized\n"}}}} |