Metadata-Version: 2.4
Name: marlo-sdk
Version: 0.0.1
Summary: Trajectory capture, reward signals, and learning infrastructure for agents.
Keywords: autonomy,agents,reasoning,reward-models,trajectories,learning
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: asyncpg
Requires-Dist: fastapi
Requires-Dist: python-dotenv
Requires-Dist: google-genai
Requires-Dist: httpx
Requires-Dist: importlib-resources
Requires-Dist: langgraph
Requires-Dist: langgraph-checkpoint-postgres
Requires-Dist: pydantic
Requires-Dist: sentry-sdk[fastapi]
Requires-Dist: sqlglot
Requires-Dist: uvicorn
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Provides-Extra: tokenizer
Requires-Dist: tiktoken; extra == "tokenizer"
Dynamic: license-file

# Marlo Python SDK

The official Python SDK for [Marlo](https://marshmallo.ai) - Continual learning platform.

## Installation

```bash
pip install marlo-sdk
```

## Quick Start

```python
import marlo

# Initialize with your API key
marlo.init(api_key="your-api-key")

# Register your agent
marlo.agent(
    name="my-agent",
    system_prompt="You are a helpful assistant.",
    tools=[{"name": "search", "description": "Search the web"}],
)

# Track a task using context manager
with marlo.task(thread_id="thread-123", agent="my-agent") as task:
    task.input("Hello, how can you help?")

    # Your agent logic here...
    task.llm(
        model="gpt-5",
        usage={"input_tokens": 50, "output_tokens": 100},
        messages=[{"role": "user", "content": "Hello"}],
        response="I can help with many things!",
    )

    task.output("I can help with many things!")

# Shutdown before exit
marlo.shutdown()
```

## Features

- **Task Tracking**: Capture agent inputs, outputs, and interactions
- **LLM Call Recording**: Track model usage, tokens, and responses
- **Tool Call Logging**: Record tool invocations and results
- **Multi-Agent Support**: Track parent-child agent relationships
- **Learnings Integration**: Fetch and apply learnings from past interactions
- **Async-Safe**: Background threading for non-blocking event sending

## API Reference

### Initialization

```python
# Initialize the SDK
marlo.init(api_key="your-api-key")

# Shutdown and flush pending events
marlo.shutdown()
```

### Agent Registration

```python
marlo.agent(
    name: str,
    system_prompt: str,
    tools: list[dict],
    mcp: list[dict] | None = None,
    model_config: dict | None = None,
)
```

| Parameter | Description |
|-----------|-------------|
| `name` | Unique identifier for your agent |
| `system_prompt` | System prompt used by your agent |
| `tools` | List of tool definitions `[{"name": "...", "description": "..."}]` |
| `mcp` | Optional list of MCP server definitions |
| `model_config` | Optional model configuration `{"model": "gpt-4", ...}` |

### Task Tracking

```python
# Create a task context (use as context manager)
with marlo.task(thread_id: str, agent: str, thread_name: str | None = None) as task:
    # Record events within the task
    task.input(text)                    # User input
    task.output(text)                   # Agent response
    task.llm(model, usage, messages, response)  # LLM call
    task.tool(name, input, output, error)       # Tool call
    task.reasoning(text)                # Chain-of-thought
    task.error(message)                 # Mark task as failed

    # Fetch learnings
    learnings = task.get_learnings()

    # Create child task for multi-agent
    with task.child(agent="sub-agent") as child_task:
        child_task.input("Sub-task input")
        child_task.output("Sub-task output")
```

### Task Methods

#### `task.input(text: str)`
Record the user's input message.

#### `task.output(text: str)`
Record the agent's final response.

#### `task.llm(...)`
Track an LLM call.

```python
task.llm(
    model="gpt-4",
    usage={"input_tokens": 100, "output_tokens": 50},
    messages=[{"role": "user", "content": "Hello"}],
    response="Hi there!",
)
```

#### `task.tool(...)`
Track a tool call.

```python
task.tool(
    name="search",
    input={"query": "weather"},
    output={"result": "sunny"},
    error=None,  # Optional error message
)
```

#### `task.reasoning(text: str)`
Record chain-of-thought or reasoning steps.

#### `task.error(message: str)`
Mark the task as failed with an error message.

#### `task.get_learnings()`
Fetch learnings from past interactions.

```python
learnings = task.get_learnings()
if learnings:
    # Apply learnings to your agent
    pass
```

#### `task.child(agent: str)`
Create a child task for multi-agent workflows.

## Complete Example

```python
import marlo

# Initialize
marlo.init(api_key="mk_abc123")

# Register agent with tools
marlo.agent(
    name="support-bot",
    system_prompt="You are a customer support agent.",
    tools=[
        {"name": "lookup_order", "description": "Find order by ID"},
        {"name": "check_inventory", "description": "Check product stock"},
    ],
    model_config={"model": "gpt-4", "temperature": 0.7},
)


async def handle_message(thread_id: str, user_message: str) -> str:
    with marlo.task(thread_id=thread_id, agent="support-bot") as task:
        task.input(user_message)

        # Get learnings to improve responses
        learnings = task.get_learnings()

        # Build messages
        messages = [
            {"role": "system", "content": "You are a customer support agent."},
            {"role": "user", "content": user_message},
        ]

        # Call LLM
        response = await llm.chat(messages)
        answer = response.content

        # Track the LLM call
        task.llm(
            model="gpt-4",
            usage={
                "input_tokens": response.usage.prompt_tokens,
                "output_tokens": response.usage.completion_tokens,
            },
            messages=messages,
            response=answer,
        )

        # Track any tool calls
        if response.tool_calls:
            for tool_call in response.tool_calls:
                result = execute_tool(tool_call)
                task.tool(
                    name=tool_call.name,
                    input=tool_call.arguments,
                    output=result,
                )

        task.output(answer)
        return answer


# Cleanup on shutdown
marlo.shutdown()
```

## Multi-Agent Example

```python
import marlo

marlo.init(api_key="mk_abc123")

marlo.agent(name="orchestrator", system_prompt="You coordinate tasks.", tools=[])
marlo.agent(name="researcher", system_prompt="You research topics.", tools=[])
marlo.agent(name="writer", system_prompt="You write content.", tools=[])

with marlo.task(thread_id="doc-123", agent="orchestrator") as main_task:
    main_task.input("Write a report about AI")

    # Delegate to researcher
    with main_task.child(agent="researcher") as research:
        research.input("Research AI trends")
        research.output("AI trends: ...")

    # Delegate to writer
    with main_task.child(agent="writer") as writer:
        writer.input("Write report based on research")
        writer.output("# AI Report\n...")

    main_task.output("Report completed")
```

## Environment Variables

```bash
MARLO_API_KEY=your-api-key
```

## Requirements

- Python 3.11 or later

## License

MIT
