Metadata-Version: 2.4
Name: agentic-ai-sdk
Version: 1.0.1
Summary: SDK for building AI agent 2.0.
Author: Frank Lin
License-Expression: MIT
License-File: LICENSE
Keywords: agent,agentic,ai,framework,llm,sdk
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: <3.13,>=3.12
Requires-Dist: agent-framework-openai<2,>=1.8.2
Requires-Dist: agent-framework<2,>=1.9.0
Requires-Dist: httpx[http2]<1,>=0.27.0
Requires-Dist: pydantic<3,>=2.7.0
Requires-Dist: pyyaml<7,>=6.0.0
Provides-Extra: ag-ui
Requires-Dist: ag-ui-protocol<0.2,>=0.1.16; extra == 'ag-ui'
Requires-Dist: agent-framework-ag-ui==1.0.0rc5; extra == 'ag-ui'
Provides-Extra: all
Requires-Dist: ag-ui-protocol<0.2,>=0.1.16; extra == 'all'
Requires-Dist: agent-framework-ag-ui==1.0.0rc5; extra == 'all'
Requires-Dist: alembic>=1.13; extra == 'all'
Requires-Dist: apscheduler>=4.0.0a5; extra == 'all'
Requires-Dist: asyncpg>=0.29.0; extra == 'all'
Requires-Dist: azure-cosmos<4.16,>=4.9.0; extra == 'all'
Requires-Dist: azure-identity>=1.15.0; extra == 'all'
Requires-Dist: croniter>=2.0; extra == 'all'
Requires-Dist: httpx>=0.27.0; extra == 'all'
Requires-Dist: opentelemetry-api<2,>=1.20.0; extra == 'all'
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2,>=1.20.0; extra == 'all'
Requires-Dist: opentelemetry-sdk<2,>=1.20.0; extra == 'all'
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'all'
Requires-Dist: tiktoken>=0.7; extra == 'all'
Provides-Extra: azure-auth
Requires-Dist: azure-identity>=1.15.0; extra == 'azure-auth'
Provides-Extra: cosmos
Requires-Dist: azure-cosmos<4.16,>=4.9.0; extra == 'cosmos'
Provides-Extra: dev
Requires-Dist: opentelemetry-api<2,>=1.20.0; extra == 'dev'
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2,>=1.20.0; extra == 'dev'
Requires-Dist: opentelemetry-sdk<2,>=1.20.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=8.3.0; extra == 'dev'
Provides-Extra: mcp-client
Requires-Dist: httpx>=0.27.0; extra == 'mcp-client'
Provides-Extra: observability
Requires-Dist: opentelemetry-api<2,>=1.20.0; extra == 'observability'
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2,>=1.20.0; extra == 'observability'
Requires-Dist: opentelemetry-sdk<2,>=1.20.0; extra == 'observability'
Provides-Extra: scheduler
Requires-Dist: alembic>=1.13; extra == 'scheduler'
Requires-Dist: apscheduler>=4.0.0a5; extra == 'scheduler'
Requires-Dist: asyncpg>=0.29.0; extra == 'scheduler'
Requires-Dist: croniter>=2.0; extra == 'scheduler'
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'scheduler'
Provides-Extra: token-estimation
Requires-Dist: tiktoken>=0.7; extra == 'token-estimation'
Description-Content-Type: text/markdown

# Agentic AI SDK

A production-ready SDK for building AI agents with planning, workspace management, artifact persistence, and observability. Built on top of Microsoft Agent Framework.

## Overview

Agentic AI SDK supports three development modes:

| Mode | Use Case | Requirements |
|------|----------|--------------|
| **Declarative Assembly** | Assemble existing Tools via YAML (no code) | Docker or Python + SDK |
| **Tool Development** | Extend with new Python tools | Python 3.10+ |
| **Pro-Code Agent** | Full programmatic control | Python + SDK APIs |

## Installation

```bash
# Basic installation
pip install agentic-ai-sdk

# With AG-UI protocol support (for web UI integration)
pip install agentic-ai-sdk[ag-ui]

# With observability (OpenTelemetry)
pip install agentic-ai-sdk[observability]

# All features
pip install agentic-ai-sdk[all]
```

## Quick Start

### Option 1: Docker Launch (Recommended, Zero Dependencies)

```bash
# Start Agent service with a single command
docker run -p 8000:8000 \
  -v $(pwd)/env.yaml:/app/env.yaml \
  -v $(pwd)/agent_teams:/app/agent_teams \
  agentic-analyst:latest

# Start frontend Web UI
docker run -p 3000:3000 \
  -e AGENT_BACKEND_URL=http://host.docker.internal:8000/ \
  agentic-ai-web-default:latest

# Access: http://localhost:3000/agentic-ai
```

### Option 2: CLI Launch (For Developers)

```bash
# Interactive terminal mode
agentic-ai run --agent my_agent --config env.yaml

# AG-UI server mode (for frontend integration)
agentic-ai serve --port 8000
```

### Option 3: Programmatic Usage

```python
from agentic_ai import (
    build_agent,
    create_workspace,
    create_llm_factory_from_list,
)
from agent_framework import AIFunction

# Define tools
@AIFunction
def get_weather(city: str) -> str:
    """Get weather for a city."""
    return f"The weather in {city} is sunny, 22°C."

# Create LLM factory
llm_factory = create_llm_factory_from_list([{
    "name": "default",
    "provider": "azure_openai",
    "model": "gpt-4o",
    "endpoint": "https://your-endpoint.openai.azure.com",
    "api_key_env": "AZURE_OPENAI_API_KEY",
}])

# Build agent
workspace = create_workspace(".ws/my_agent")
session = build_agent(
    chat_client=llm_factory.get_client("default"),
    workspace=workspace,
    agent_id="my_agent",
    tools=[get_weather],
    instructions="You are a helpful assistant.",
    planning_enabled=True,
)

# Run agent
response = await session.run("What's the weather in Beijing?")
print(response.text)
```

## Project Structure

```
my-agent-project/
├── env.yaml                    # Platform config (auth, storage, observability)
├── agent_teams/
│   └── default/                # A team (add more dirs for multi-tenant)
│       ├── agent_team.env.yaml # Per-team data source creds, UI, MCP
│       ├── agents.yaml         # Agent configuration
│       ├── tools.yaml          # Tool configuration
│       └── prompts/
│           └── my_agent.md     # System prompt
└── toolsets/                   # Tool implementations
    └── my_tools/
        └── tools.py
```

## Declarative Configuration

### Agent Configuration (agents.yaml)

```yaml
version: "1.0"

agents:
  my_agent:
    llm_profile_name: "default"
    name: "My Agent"
    description: "A helpful assistant"
    max_tool_iterations: 30
    planning_enabled: true
    system_prompt_file: "prompts/my_agent.md"
    
    context_compaction:
      enabled: true
      max_messages: 80
      max_tokens: 180000
    
    tools:
      - my_tool
      - another_tool
    
    subagents:
      - sub_agent_1
```

### Tool Configuration (tools.yaml)

```yaml
version: "1.0"

defaults:
  output_policy: managed
  preview_rows: 200

tools:
  my_tool:
    function: "toolsets.my_tools.tools:my_tool"
    description: "My custom tool"
    config:
      timeout: 30
      max_results: 100
```

### Platform and Agent-Team Configuration

```yaml
# env.yaml — platform infrastructure
logging:
  level: INFO

observability:
  enabled: true
  service_name: "my-agent"

llm_profiles:
  - name: default
    provider: azure
    model: gpt-4o
    deployment: gpt-4o
    base_url: ${AZURE_OPENAI_ENDPOINT}
    auth: azure_credential:openai
```

```yaml
# agent_teams/default/agent_team.env.yaml — Team-owned resources
llm_profile_sets:
  default:
    slots:
      master: default
```

## Tool Development

### Creating Tools

```python
from agent_framework import ai_function
from agentic_ai.artifacts import ToolResult, ok, error, persist
from agentic_ai.runtime import tool_handler

@ai_function(name="my_tool")
@tool_handler()  # Auto exception handling
async def my_tool(query: str) -> ToolResult:
    """My custom tool."""
    data = await fetch_data(query)
    return ok(data)

# For large data, use artifact persistence
@ai_function(name="generate_report")
@tool_handler()
async def generate_report(query: str) -> ToolResult:
    """Generate report with artifact persistence."""
    full_data = await fetch_large_dataset(query)
    preview = full_data[:50]
    
    return persist(
        data=full_data,           # Full data stored in artifact
        tool_return=preview,      # Preview returned to LLM
        summary={"total_rows": len(full_data)},
    )
```

### Configuration Injection (No Client Factory Required)

Runtime configuration is resolved as a per-Agent-Team effective view. Values
in `env.yaml` are inheritable platform defaults; the same sections in
`agent_teams/<team-id>/agent_team.env.yaml` override them only for that Team.
Concrete `llm_profiles` are a platform-owned catalog; Teams own
`llm_profile_sets`, `embedding`, `semantic_layer_indexer`, MCP,
and tool/resource connection sections. Equal set or resource-section names in
different Teams do not share resolved Team configuration. LLM profile clients,
authentication, observability, the memory-store backend, and the global Azure
credential factory remain application-scoped by design.

`memory_store.provider: file` is fully durable for a single-filesystem deployment: task
ownership, title, status, and Team/profile routing are atomically indexed in
`<workspace-root>/threads.json`, while messages stay in Team-scoped workspace
files. It supports task lists and history after restart. Use Cosmos for
horizontally scaled production deployments.

An explicit `null` Team override disables an inherited optional section.

```python
from agentic_ai.runtime import get_effective_tool_config

@ai_function(name="search_data")
@tool_handler()
async def search_data(query: str) -> ToolResult:
    """Most custom tools are plain functions and need no resource factory."""
    # Get merged config from env.yaml + tools.yaml
    config = get_effective_tool_config("my_section")
    limit = config["config"].get("limit", 10)
    results = await fetch_data(query, limit=limit)
    return ok(results)
```

### Client Lifetimes: Prefer the Public SDK

Toolsets do not need an SDK client factory by default. Construct the official
HTTP, Azure, or database client directly and let that package manage its
transport, connection pool, and reconnect behavior. For clients that are cheap
or already open a connection per operation, a plain function is enough:

```python
from databricks import sql

def run_query(config, statement):
    with sql.connect(**config.connect_kwargs()) as connection:
        with connection.cursor() as cursor:
            cursor.execute(statement)
            return cursor.fetchall()
```

Keep a client alive only when doing so has a measured benefit, such as reusing
an HTTP/TLS pool across calls. `ScopedResource` remains an optional lifetime
bridge for declarative sessions; it does not implement another connection
pool. The public client owns its transport and pooling; retries remain an
explicit operation policy because not every request is safe to retry.

```python
from agentic_ai.runtime import (
    HTTP_READ_RETRY,
    ResourceFactoryContext,
    ScopedResource,
    resolve_retry_policy,
)

def create_crm_client(context: ResourceFactoryContext):
    return CRMClient(endpoint=context.config.endpoint)

crm = ScopedResource(
    create_crm_client,
    # Optional: defaults to the factory's fully-qualified Python name.
    resource_id="my_company.crm.client",
    config_section="crm",
)

@ai_function(name="search_customer")
@tool_handler()
async def search_customer(query: str) -> ToolResult:
    results = await crm.call_async(
        lambda client: client.search(query),
        retry_policy=resolve_retry_policy(HTTP_READ_RETRY),
        recreate_on_retry=True,
    )
    return ok(results)
```

Agent Teams may tune an idempotent operation without changing toolset code:

```yaml
tools:
  search_customer:
    function: "my_toolsets.crm.tools:search_customer"
    config_section: crm
    config:
      retry:
        max_attempts: 3
        initial_delay_seconds: 0.5
        max_delay_seconds: 8
```

Do not apply read retry policies to writes or other non-idempotent operations.
Legacy `register_client()` / `get_client()` integrations remain supported for
existing toolsets. New toolsets should not register global short client names.
Use plain functions first, and a direct, namespaced `ScopedResource` only when
cross-call reuse is actually required.

Built-in short aliases such as `get_client("embedding")` and
`get_client("databricks")` are no longer registered. Existing extensions should
call their public provider directly or keep their own namespaced resource
handle; this prevents unrelated Agent Teams/toolsets from coupling through a
process-global alias.

## Sub-Agent Configuration

Sub-agents are invoked as tools by the master agent:

```yaml
agents:
  sub_agent:
    llm_profile_name: "default"
    name: "Sub Agent"
    system_prompt_file: "prompts/sub_agent.md"
    tools:
      - tool_a
      - tool_b
    
    as_subagent:
      tool_name: "invoke_sub_agent"
      tool_description: "Invoke the sub-agent for specialized tasks."
      tool_parameters:
        query:
          type: string
          description: "The query to process"
          required: true
      response_handling: last_artifact  # none | parse_json | last_artifact
      auto_load_artifacts: true
```

## Core Concepts

### DeepAgentSession

The main entry point for agent interaction:

- **Workspace Management**: Persistent storage for artifacts and state
- **Planning**: Built-in task planning with `update_plan` tool
- **Context Compaction**: Automatic long conversation management
- **Observability**: Logging and OpenTelemetry tracing

### Workspace

Each session has an isolated workspace:

```
.ws/{workspace_id}/
├── {agent_id}/
│   └── plan.json           # Execution plan
├── {artifact_id}/
│   ├── data.json           # Artifact data
│   └── .manifest.json      # Metadata
```

### Artifacts

Large tool outputs are persisted as artifacts:

```python
from agentic_ai.artifacts import persist, load_artifact

# Persist data
result = persist(data=large_data, summary={"rows": 1000})

# Load in another tool
data = load_artifact(artifact_id)
```

### ToolResult Structure

| Field | Description |
|-------|-------------|
| `status` | `"ok"` or `"error"` |
| `result` | Data returned to LLM |
| `artifact_id` | Artifact ID for persisted data |
| `summary` | Metadata summary |
| `is_preview` | Whether it's preview data |
| `error_message` | Error message (when status="error") |

## API Reference

### Package Structure

```
agentic_ai/
├── agent/          # Agent core (DeepAgentSession, SubAgentController)
├── config/         # Configuration (AgentConfig, BaseAppConfig)
├── runtime/        # Runtime (bootstrap, session factory, tool context)
├── middleware/     # Middleware (persistence, loader)
├── tools/          # Tool management (loader, manifest)
├── llm/            # LLM (client factory, embedding)
├── artifacts/      # Artifact storage (persist, load, ToolResult)
├── workspace/      # Workspace management
├── planning/       # Planning subsystem
├── observability/  # Logging and tracing
├── mcp/            # Model Context Protocol
├── genui/          # Generative UI (insight reports)
└── ag_ui/          # AG-UI protocol adapter
```

### Agent Builders

| Function | Description |
|----------|-------------|
| `build_agent()` | Create session with chat client |
| `build_agent_with_llm()` | Create session with LLM factory |
| `build_agent_from_config()` | Create session from AgentConfig |
| `build_agent_from_store()` | Create session from config store |
| `build_agent_session()` | Low-level session builder |

### Artifact API

| Function | Description |
|----------|-------------|
| `persist()` | Persist data to artifact, return ToolResult |
| `ok()` | Create success ToolResult |
| `error()` | Create error ToolResult |
| `load_artifact()` | Load artifact data by ID |
| `try_load_artifact()` | Load artifact, return None if not found |

### Runtime API

| Function | Description |
|----------|-------------|
| `bootstrap_runtime()` | Load configs and create RuntimeContext |
| `build_session()` | Build agent session from runtime context |
| `ctx()` | Get current tool execution context |
| `get_effective_tool_config()` | Get merged tool configuration |
| `get_client()` | Get managed client instance |
| `tool_handler()` | Decorator for auto exception handling |

### Observability API

| Function | Description |
|----------|-------------|
| `setup_logging()` | Configure logging |
| `enable_observability()` | Enable OpenTelemetry tracing |
| `get_tracer()` | Get OpenTelemetry tracer |
| `trace_http_request()` | Trace HTTP requests |
| `trace_database_query()` | Trace database queries |

## CLI Commands

```bash
# Run agent interactively
agentic-ai run --agent <agent_id> --config <config_path>

# Start AG-UI server
agentic-ai serve --port 8000 --host 0.0.0.0

# Options
--config, -c      Config file path (default: env.yaml)
--manifest-dir    Manifest directory (default: manifest)
--workspace       Workspace root (default: .ws)
--verbose         Enable debug logging
```

## Docker Deployment

```yaml
# docker-compose.yaml
version: '3.8'
services:
  backend:
    image: agentic-analyst:latest
    ports:
      - "8000:8000"
    volumes:
      - ./env.yaml:/app/env.yaml
      - ./manifest:/app/manifest
      - ./.ws:/app/.ws

  web:
    image: agentic-ai-web-default:latest
    ports:
      - "3000:3000"
    environment:
      - AGENT_BACKEND_URL=http://backend:8000/
    depends_on:
      - backend
```

## Documentation

- **[Development Guide](docs/agentic-ai-sdk-guide.md)**: Comprehensive development guide
- **[Tool Result Control](docs/tool-result-control.md)**: Artifact and result handling

## License

MIT License - see [LICENSE](LICENSE) for details.
