> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ntropii.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ntro.workflow.agents

> API reference for ntro.workflow.agents.invoke and the AgentResult shape — how runbook steps delegate to registered external agents.

`ntro.workflow.agents` is the SDK surface for invoking a registered external agent from inside a runbook step. For the registration lifecycle, see [Register agents](/workflows/agents/register).

## Install

```bash theme={null}
pip install 'ntro[workflow]'
```

The `agents` module is part of the `[workflow]` extra.

## `invoke`

```python theme={null}
from ntro.workflow.agents import invoke

result = await invoke(
    agent_id,
    *,
    input,
    tenant_slug=None,
    entity_slug=None,
    task_id=None,
    poll_interval_seconds=5.0,
    max_poll_seconds=1800.0,
)
```

Invokes a registered external agent and returns its result.

### Arguments

| Arg                     | Type                    | Purpose                                                                                                                                                                                                                 |
| ----------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_id`              | `str` (UUID)            | The Ntropii agent id — NOT the host platform's native id. Resolved against the workspace registry to look up `kind` + `external_ref`.                                                                                   |
| `input`                 | `dict[str, Any] \| str` | The agent's kickoff payload. Dicts are JSON-serialised before being sent as the user message; strings pass through. Periods, dates, and other temporal context belong **inside** this dict (they're data, not routing). |
| `tenant_slug`           | `str`                   | **Required** for any session that produces files (it's the data-plane connection target).                                                                                                                               |
| `entity_slug`           | `str \| None`           | Threads onto persisted `ingest.submitted_documents` rows for queryability.                                                                                                                                              |
| `task_id`               | `str \| None`           | Workflow id (root, stripped of any `:step:slug` suffix). Threads onto persisted rows.                                                                                                                                   |
| `poll_interval_seconds` | `float`                 | Default `5.0`. How often to poll session status.                                                                                                                                                                        |
| `max_poll_seconds`      | `float`                 | Default `1800.0` (30 min). Hard cap on polling before returning a `failed` result.                                                                                                                                      |

### Returns

`AgentResult` (pydantic):

```python theme={null}
class AgentResult(BaseModel):
    agent_id: str
    session_id: str
    status: Literal["completed", "failed", "terminated"]
    output_text: str | None
    output_files: list[AgentOutputFile]
    error: str | None
    raw: dict | None  # provider-specific session payload


class AgentOutputFile(BaseModel):
    document_ref: str    # FK into ingest.submitted_documents
    filename: str
    content_type: str
    size_bytes: int
    source: str          # always "agent_output:<agent_id>"
```

## Lifecycle

```
invoke(agent_id, …)
   │
   ├─ 1. Resolve agent           workspace API → {kind, external_ref}
   │
   ├─ 2. Pick provider           kind → AnthropicManagedAgentProvider, …
   │
   ├─ 3. Compose input           dict → JSON serialise
   │
   ├─ 4. Start session           provider.start_session(...)
   │
   ├─ 5. Poll to terminal        provider.poll_session(...) until terminal
   │
   ├─ 6. List session files      with backoff for index-eventual-consistency
   │
   ├─ 7. Persist each file       ntro.ingest.insert_submitted_document(
   │                              source='agent_output:<agent_id>', ...)
   │
   └─ 8. Return AgentResult      includes output_files refs
```

Activities calling `invoke` should give it a generous `start_to_close_timeout` — Anthropic Sessions can run for tens of minutes for complex agents.

```python theme={null}
await runbook.execute_activity(
    draft_auditor_handover,
    AuditHandoverInput(...),
    start_to_close_timeout=timedelta(minutes=45),
)
```

## File passback

Files persisted to the tenant data plane via `invoke` always carry `source = 'agent_output:<ntropii-agent-id>'`. They sit alongside user-uploaded documents in `ingest.submitted_documents` and are downloadable from the task UI like any other artefact.

The `period` column on the row is `NULL` for agent outputs — period is a runbook-domain concept (some runbooks have it, some don't), not part of the invocation contract. Runbooks that want the column populated should update the row downstream.

## Polling semantics

The Anthropic Sessions API surfaces three terminal states: `completed`, `failed`, `terminated`. The adapter also treats `idle` with positive `output_tokens` as `completed` (the agent finished its work and went idle).

The `/v1/files` index is eventually-consistent with session termination — files written in the agent's final tool call may not appear in the listing for \~1-2s after the session goes terminal. The adapter retries the listing up to 5 times at 1s intervals so a single empty response doesn't drop a real file.

## Providers

Built-in:

| Kind             | Provider                        | Notes                                                                             |
| ---------------- | ------------------------------- | --------------------------------------------------------------------------------- |
| `claude_managed` | `AnthropicManagedAgentProvider` | Production. See [Claude Managed Agents](/workflows/agents/claude-managed-agents). |
| `copilot_agent`  | TBD                             | Phase 3 — placeholder in the dispatch shell.                                      |

To add a provider, implement the `ManagedAgentProvider` protocol (`start_session`, `poll_session`, `list_session_files`, `download_file`) and wire it into `ntro/workflow/agents/_config.py`.

## Related

<CardGroup cols={2}>
  <Card title="Register agents" icon="server-cog" href="/workflows/agents/register">
    Registration lifecycle (build → register → reference).
  </Card>

  <Card title="Claude Managed Agents" icon="anthropic" href="/workflows/agents/claude-managed-agents">
    End-to-end walkthrough for the Anthropic adapter.
  </Card>

  <Card title="ntro.ingest" icon="database" href="/sdk/ingest">
    `insert_submitted_document` — the persistence function `invoke` uses.
  </Card>

  <Card title="Build runbooks" icon="code" href="/workflows/runbooks/overview">
    The runbook-side of `invoke`, inside a `@runbook.step` method.
  </Card>
</CardGroup>
