Metadata-Version: 2.4
Name: gradient-adk
Version: 0.2.5
Summary: Gradient AI Platform Agent Development Kit
License-Expression: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.104.0
Requires-Dist: uvicorn[standard]>=0.24.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: typing-extensions>=4.8.0
Requires-Dist: typer>=0.12.0
Requires-Dist: PyYAML>=6.0
Requires-Dist: aiohttp>=3.8.0
Requires-Dist: pytest>=8.4.2
Requires-Dist: pytest-asyncio>=0.21.0
Requires-Dist: structlog>=24.1.0
Requires-Dist: pytest-cov>=7.0.0
Requires-Dist: httpx>=0.26.0
Requires-Dist: requests>=2.32.5
Requires-Dist: pytest-mock>=3.15.1
Requires-Dist: langgraph>=1.0.0
Requires-Dist: gradient>=3.10.1
Dynamic: license-file

![Header image for the DigitalOcean Gradient AI Agentic Cloud](https://doimages.nyc3.cdn.digitaloceanspaces.com/do_gradient_ai_agentic_cloud.svg)

# DigitalOcean Gradient™ Agent Development Kit (ADK)

<!-- prettier-ignore -->
[![PyPI version](https://img.shields.io/pypi/v/gradient-adk.svg?label=pypi%20(stable))](https://pypi.org/project/gradient-adk/)
[![Docs](https://img.shields.io/badge/Docs-8A2BE2)](https://docs.digitalocean.com/products/gradient-ai-platform/)

The Gradient™ Agent Development Kit (ADK) is a comprehensive toolkit for building, testing, deploying, and evaluating AI agents on DigitalOcean's Gradient™ AI Platform. It provides both a **CLI** for development workflows and a **runtime environment** for hosting agents with automatic trace capture.

## Features

### 🛠️ CLI (Command Line Interface)
- **Local Development**: Run and test your agents locally with hot-reload support
- **Seamless Deployment**: Deploy agents to DigitalOcean with a single command
- **Evaluation Framework**: Run comprehensive evaluations with custom metrics and datasets
- **Observability**: View traces and runtime logs directly from the CLI

### 🚀 Runtime Environment
- **Framework Agnostic**: Works with any Python framework for building AI agents
- **Automatic LangGraph Integration**: Built-in trace capture for LangGraph nodes and state transitions
- **Custom Decorators**: Capture traces from any framework using `@trace` decorators
- **Streaming Support**: Full support for streaming responses with trace capture
- **Production Ready**: Designed for seamless deployment to DigitalOcean infrastructure

## Installation

```bash
pip install gradient-adk
```

## Quick Start

> **🎥 Watch the [Getting Started Video](https://www.youtube.com/watch?v=23xiqgrGciE)** for a complete walkthrough

### 1. Initialize a New Agent Project

```bash
gradient agent init
```

This creates a new agent project with:
- `main.py` - Agent entrypoint with example code
- `agents/` - Directory for agent implementations
- `tools/` - Directory for custom tools
- `config.yaml` - Agent configuration
- `requirements.txt` - Python dependencies

### 2. Run Locally

```bash
gradient agent run
```

Your agent will be available at `http://localhost:8080` with automatic trace capture enabled.

### 3. Deploy to DigitalOcean

```bash
export DIGITALOCEAN_API_TOKEN=your_token_here
gradient agent deploy
```

### 4. Evaluate Your Agent

```bash
gradient agent evaluate \
  --test-case-name "my-evaluation" \
  --dataset-file evaluation_dataset.csv \
  --categories correctness,context_quality
```

## Usage Examples

### Using LangGraph (Automatic Trace Capture)

LangGraph agents automatically capture traces for all nodes and state transitions:

```python
from gradient_adk import entrypoint
from langgraph.graph import StateGraph
from typing import TypedDict

class State(TypedDict):
    input: str
    output: str

async def llm_call(state: State) -> State:
    # This node execution is automatically traced
    response = await llm.ainvoke(state["input"])
    state["output"] = response
    return state

@entrypoint
async def main(input: dict, context: dict):
    graph = StateGraph(State)
    graph.add_node("llm_call", llm_call)
    graph.set_entry_point("llm_call")
    
    graph = graph.compile()
    result = await graph.ainvoke({"input": input.get("query")})
    return result["output"]
```

### Using Custom Decorators (Any Framework)

For frameworks beyond LangGraph, use trace decorators to capture custom spans:

```python
from gradient_adk import entrypoint, trace_llm, trace_tool, trace_retriever

@trace_retriever("vector_search")
async def search_knowledge_base(query: str):
    # Retriever spans capture search/lookup operations
    results = await vector_db.search(query)
    return results

@trace_llm("generate_response")
async def generate_response(prompt: str):
    # LLM spans capture model calls with token usage
    response = await llm.generate(prompt)
    return response

@trace_tool("calculate")
async def calculate(x: int, y: int):
    # Tool spans capture function execution
    return x + y

@entrypoint
async def main(input: dict, context: dict):
    docs = await search_knowledge_base(input["query"])
    result = await calculate(5, 10)
    response = await generate_response(f"Context: {docs}")
    return response
```

### Streaming Responses

The runtime supports streaming responses with automatic trace capture:

```python
from gradient_adk import entrypoint

@entrypoint
async def main(input: dict, context: dict):
    # Stream text chunks
    async def generate_chunks():
        async for chunk in llm.stream(input["query"]):
            yield chunk
```

## CLI Commands

### Agent Management

```bash
# Initialize new project
gradient agent init

# Configure existing project
gradient agent configure

# Run locally with hot-reload
gradient agent run --dev

# Deploy to DigitalOcean
gradient agent deploy

# View runtime logs
gradient agent logs

# Open traces UI
gradient agent traces
```

### Evaluation

You can evaluate your deployed agent with a number of useful evaluation metrics. See the [DigitalOcean docs](https://docs.digitalocean.com/products/gradient-ai-platform/how-to/create-evaluation-datasets/#evaluation-datasets-for-agents-built-with-agent-development-kit) for details on what belongs in a dataset.

```bash
# Run evaluation (interactive)
gradient agent evaluate

# Run evaluation (non-interactive)
gradient agent evaluate \
  --test-case-name "my-test" \
  --dataset-file data.csv \
  --categories correctness,safety_and_security \
  --star-metric-name "Correctness (general hallucinations)" \
  --success-threshold 80.0
```


## Tracing

The ADK provides comprehensive tracing capabilities to capture and analyze your agent's execution. You can use **decorators** for wrapping functions or **programmatic functions** for manual span creation.

### What Gets Traced Automatically
- **LangGraph Nodes**: All node executions, state transitions, and edges (including LLM calls, tool calls, and DigitalOcean Knowledge Base calls)
- **HTTP Requests**: Request/response payloads for LLM API calls
- **Errors**: Full exception details and stack traces
- **Streaming Responses**: Individual chunks and aggregated outputs

### Tracing Decorators

Use decorators to automatically trace function executions:

```python
from gradient_adk import entrypoint, trace_llm, trace_tool, trace_retriever

@trace_llm("model_call")
async def call_model(prompt: str):
    """LLM spans capture model calls with token usage."""
    response = await llm.generate(prompt)
    return response

@trace_tool("calculator")
async def calculate(x: int, y: int):
    """Tool spans capture function/tool execution."""
    return x + y

@trace_retriever("vector_search")
async def search_docs(query: str):
    """Retriever spans capture search/lookup operations."""
    results = await vector_db.search(query)
    return results

@entrypoint
async def main(input: dict, context: dict):
    docs = await search_docs(input["query"])
    result = await calculate(5, 10)
    response = await call_model(f"Context: {docs}")
    return response
```

### Programmatic Span Functions

For more control over span creation, use the programmatic functions. These are useful when you can't use decorators or need to add spans for code you don't control:

```python
from gradient_adk import entrypoint, add_llm_span, add_tool_span, add_agent_span

@entrypoint
async def main(input: dict, context: dict):
    # Add an LLM span with detailed metadata
    response = await external_llm_call(input["query"])
    add_llm_span(
        name="external_llm_call",
        input={"messages": [{"role": "user", "content": input["query"]}]},
        output={"response": response},
        model="gpt-4",
        num_input_tokens=100,
        num_output_tokens=50,
        temperature=0.7,
    )

    # Add a tool span
    tool_result = await run_tool(input["data"])
    add_tool_span(
        name="data_processor",
        input={"data": input["data"]},
        output={"result": tool_result},
        tool_call_id="call_abc123",
        metadata={"tool_version": "1.0"},
    )

    # Add an agent span for sub-agent calls
    agent_result = await call_sub_agent(input["task"])
    add_agent_span(
        name="research_agent",
        input={"task": input["task"]},
        output={"result": agent_result},
        metadata={"agent_type": "research"},
        tags=["sub-agent", "research"],
    )

    return {"response": response, "tool_result": tool_result, "agent_result": agent_result}
```

#### Available Span Functions

| Function | Description | Key Optional Fields |
|----------|-------------|---------------------|
| `add_llm_span()` | Record LLM/model calls | `model`, `temperature`, `num_input_tokens`, `num_output_tokens`, `total_tokens`, `tools`, `time_to_first_token_ns` |
| `add_tool_span()` | Record tool/function executions | `tool_call_id` |
| `add_agent_span()` | Record agent/sub-agent executions | — |

**Common optional fields for all span functions:** `duration_ns`, `metadata`, `tags`, `status_code`

### Viewing Traces

Traces are:
- Automatically sent to DigitalOcean's Gradient Platform
- Available in real-time through the web console
- Accessible via `gradient agent traces` command

## Environment Variables

```bash
# Required for deployment and evaluations
export DIGITALOCEAN_API_TOKEN=your_do_api_token

# Required for Gradient serverless inference (if using)
export GRADIENT_MODEL_ACCESS_KEY=your_gradient_key

# Optional: Enable verbose trace logging
export GRADIENT_VERBOSE=1
```

## Project Structure

```
my-agent/
├── main.py              # Agent entrypoint with @entrypoint decorator
├── .gradient/agent.yml  # Agent configuration (auto-generated)
├── requirements.txt     # Python dependencies
├── .env                 # Environment variables (not committed)
├── agents/              # Agent implementations
│   └── my_agent.py
└── tools/               # Custom tools
    └── my_tool.py
```

## Framework Compatibility

The Gradient ADK is designed to work with any Python-based AI agent framework:

- ✅ **LangGraph** - Automatic trace capture (zero configuration)
- ✅ **LangChain** - Use trace decorators (`@trace_llm`, `@trace_tool`, `@trace_retriever`) for custom spans
- ✅ **CrewAI** - Use trace decorators for agent and task execution
- ✅ **Custom Frameworks** - Use trace decorators for any function

## Support

- **Templates/Examples**: [https://github.com/digitalocean/gradient-adk-templates](https://github.com/digitalocean/gradient-adk-templates)
- **Gradient Platform**: [https://www.digitalocean.com/products/gradient/platform](https://www.digitalocean.com/products/gradient/platform)
- **Documentation**: [https://docs.digitalocean.com/products/gradient-ai-platform/](https://docs.digitalocean.com/products/gradient-ai-platform/)
- **API Reference**: [https://docs.digitalocean.com/reference/api](https://docs.digitalocean.com/reference/api)
- **Community**: [DigitalOcean Community Forums](https://www.digitalocean.com/community)

## License

Licensed under the Apache License 2.0. See [LICENSE](./LICENSE)
