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

# Native Tools

> Tool contract and onboarding flow for connecting external services (PIM, DAM, search, AI image generation) to the AI planner.

This document defines the tool contract and onboarding flow for connecting external services (PIM, DAM, search, etc.) to the AI planner. See [How It Works](/how-it-works) for how tools fit into the editing pipeline.

## Scope

* Provider path: Anthropic tool use today. The runtime is provider-neutral internally so OpenAI Responses tools can be added later.
* Built-in tools shipped today:
  * `unsplash.search` — licensed photo search (see schema below).
  * `image.generate` — AI image generation via OpenAI (`gpt-image-1`) or Google Gemini (`gemini-2.5-flash-image`, nicknamed "nano-banana"). Full reference: [Asset Manager & AI Images](/features/asset-picker#imagegenerate-tool-chat-pipeline-path).

## Internal Tool Contract

Every tool is registered with a `ToolManifest`:

* `name`: unique id (for example `unsplash.search`, `pim.getProduct`)
* `description`: natural-language purpose
* `inputSchema`: JSON Schema for tool input
* `outputSchema`: JSON Schema for tool output
* `capability`: `read` or `write`
* `timeoutMs`: per-call timeout
* `retryPolicy`: `{ maxAttempts, backoffMs? }`
* `idempotent`: whether identical calls can be replayed safely

Execution context passed to tools:

* `siteId`
* `sessionId`
* `userId` (optional)
* `traceId`
* `plannerProvider`

Result envelope returned by runtime:

* `ok`
* `data` (on success)
* `error` `{ code, message, retryable }` (on failure)
* `latencyMs`
* `attempts`

## Default Governance Policy

* Read tools auto-run.
* Write tools require approval (runtime blocks direct auto execution).

## Anthropic Adapter Behavior

Planner exposes tools as Anthropic `tools[]` with `input_schema`.
The planner loop supports:

1. model requests tool call (`tool_use`)
2. orchestrator executes tool server-side
3. orchestrator returns `tool_result`
4. model continues until `submit_edit_plan`

`submit_edit_plan` is still validated by existing normalizer + `editPlanSchema`.

## Unsplash Tool

`unsplash.search` input:

```json theme={null}
{ "query": "mountain sunset", "limit": 3 }
```

`unsplash.search` output:

```json theme={null}
{
  "items": [
    {
      "id": "...",
      "imageUrl": "https://...",
      "thumbUrl": "https://...",
      "alt": "...",
      "author": "Unsplash",
      "sourceUrl": "https://..."
    }
  ]
}
```

Photos served via `unsplash.search` are covered by the
[Unsplash License](https://unsplash.com/license). `author` and `sourceUrl`
are returned so adopters can render photographer + Unsplash attribution
alongside each used image. See
[Asset Manager & AI Images → Unsplash: licensing & attribution](/features/asset-picker#unsplash-licensing-attribution)
for the full rules (attribution, prohibited uses, download tracking).

## Adopter Onboarding

### Option A: Runtime registration endpoint

<Note>
  **Status: Future roadmap — not yet implemented.** The `GET /tools` and
  `POST /tools/register` endpoints described below are not wired up in the
  orchestrator today. Use Option B (bootstrap config file via
  `ORCHESTRATOR_TOOL_MANIFEST_PATH`) for now.
</Note>

* `GET /tools` to view enabled tools
* `POST /tools/register` to register a remote tool

Payload:

```json theme={null}
{
  "manifest": { "name": "pim.getProduct", "description": "...", "inputSchema": {"type":"object"}, "outputSchema": {"type":"object"}, "capability": "read", "timeoutMs": 3000, "retryPolicy": {"maxAttempts": 2}, "idempotent": true },
  "endpoint": "https://vendor.example.com/site-editor/tools/pim/getProduct",
  "staticHeaders": { "x-api-key": "***" }
}
```

### Option B: Bootstrap config file

Set `ORCHESTRATOR_TOOL_MANIFEST_PATH` to a JSON file:

```json theme={null}
{
  "tools": [
    {
      "manifest": { "name": "dam.searchAssets", "description": "...", "inputSchema": {"type":"object"}, "outputSchema": {"type":"object"}, "capability": "read", "timeoutMs": 5000, "retryPolicy": {"maxAttempts": 2}, "idempotent": true },
      "endpoint": "https://vendor.example.com/site-editor/tools/dam/searchAssets",
      "staticHeaders": { "x-api-key": "***" }
    }
  ]
}
```

## Remote Tool HTTP Contract

Orchestrator calls remote endpoints with:

```json theme={null}
{
  "toolName": "pim.getProduct",
  "arguments": { "sku": "SKU-123" },
  "context": {
    "siteId": "...",
    "sessionId": "...",
    "userId": "...",
    "traceId": "...",
    "plannerProvider": "anthropic"
  }
}
```

Expected response:

```json theme={null}
{ "data": { "...": "..." } }
```

On non-2xx responses, runtime returns normalized tool error to the model loop.

## PIM Skeleton Example

* Tool name: `pim.getProduct`
* Input schema: `{ sku: string }`
* Output schema: `{ sku: string, title: string, description?: string, imageUrl?: string, price?: string }`
* Capability: `read`

## DAM Skeleton Example

* Tool name: `dam.searchAssets`
* Input schema: `{ query: string, limit?: integer }`
* Output schema: `{ items: [{ id: string, url: string, alt?: string, mimeType?: string }] }`
* Capability: `read`
