-
Clone the repository
git clone https://github.com/NASA-IMPACT/akd-ext.git cd akd-ext -
Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh -
Install dependencies
uv sync --extra dev
-
Install pre-commit hooks
uv run pre-commit install
uv run pytestuv run pre-commit run --all-filesTools follow the akd-core pattern. See akd_ext/tools/dummy.py as a reference:
from akd._base import InputSchema, OutputSchema
from akd.tools import BaseTool
from pydantic import Field
class MyInputSchema(InputSchema):
"""Input schema for MyTool."""
query: str = Field(..., description="Description of the input")
class MyOutputSchema(OutputSchema):
"""Output schema for MyTool."""
result: str = Field(..., description="Description of the output")
class MyTool(BaseTool[MyInputSchema, MyOutputSchema]):
"""Description of what this tool does."""
input_schema = MyInputSchema
output_schema = MyOutputSchema
async def _arun(self, params: MyInputSchema) -> MyOutputSchema:
# Implementation here
return MyOutputSchema(result=params.query)Each tool has these auto-generated attributes:
.name- Derived from class name (e.g.,"MyTool").description- Generated from class docstring + input/output schema field names and descriptions
Customize tools via BaseToolConfig:
from akd.tools import BaseToolConfig
# Override name
tool = MyTool(config=BaseToolConfig(name="custom_name"))
# Create custom config class for additional options
class MyToolConfig(BaseToolConfig):
custom_option: str = "default_value"
tool = MyTool(config=MyToolConfig(name="custom", custom_option="foo"))See akd_ext/tools/dummy.py for a complete reference implementation.
- Python 3.12+ is strictly required
- We use Ruff for linting and formatting
- Line length: 120 characters
- Pre-commit hooks will auto-fix most issues
Use modern Python 3.12+ type hint syntax:
# Good
def foo(x: int | None = None) -> list[str]:
...
# Bad (old style)
from typing import Optional, Union, List
def foo(x: Optional[int] = None) -> List[str]:
...| Old Style | Modern Style |
|---|---|
Optional[X] |
X | None |
Union[X, Y] |
X | Y |
List[X] |
list[X] |
Dict[K, V] |
dict[K, V] |
Tuple[X, Y] |
tuple[X, Y] |
Set[X] |
set[X] |
Agents accept both AKD tools (BaseTool subclasses — auto-converted to OpenAI FunctionTool) and OpenAI-native tools (HostedMCPTool, FunctionTool, etc.) via the config tools list.
from akd.tools.human import HumanTool
from akd_ext.agents import CMRCareAgent, CMRCareConfig
from akd_ext.agents.cmr_care import get_default_cmr_tools
agent = CMRCareAgent(config=CMRCareConfig(
system_prompt="...(include guidance to ask for clarification when needed)...",
tools=get_default_cmr_tools() + [HumanTool()],
))HumanTool() enables human-in-the-loop — when the LLM calls ask_human, the stream pauses with a HUMAN_INPUT_REQUIRED event and resumes when the caller provides a response via RunContext. See docs/specs/HUMAN-IN-THE-LOOP.md for the full protocol.
Reference implementation: akd_ext/agents/cmr_care.py (CMRCareAgent).
- Create a feature branch from
develop - Make your changes
- Ensure tests pass:
uv run pytest - Ensure linting passes:
uv run pre-commit run --all-files - Submit a PR against
develop