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

# API de agentes

> Referência interna para a API de Agentes — abrangendo operações CRUD, gerenciamento de ferramentas, conexões de armazenamento de dados, atualização de configuração e todos os sub-recursos.

> **Documentação interna para desenvolvedores.** Esta página documenta os endpoints da API dos agentes, os requisitos de autenticação, os padrões de consulta do Prisma e as notas de implementação. Não se destina a usuários finais.

***

## Mapa de rotas

| Método           | Ponto final                                | Arquivo manipulador                                    |
| ---------------- | ------------------------------------------ | ------------------------------------------------------ |
| `GET`            | `/api/agents`                              | `app/api/agents/route.ts`                              |
| `POST`           | `/api/agents`                              | `app/api/agents/route.ts`                              |
| `GET`            | `/api/agents/[id]`                         | `app/api/agents/[id]/route.ts`                         |
| `PATCH`          | `/api/agents/[id]`                         | `app/api/agents/[id]/route.ts`                         |
| `DELETE`         | `/api/agents/[id]`                         | `app/api/agents/[id]/route.ts`                         |
| `GET/POST`       | `/api/agents/[id]/skills`                  | `app/api/agents/[id]/skills/route.ts`                  |
| `PATCH`          | `/api/agents/[id]/skills/[skillId]`        | `app/api/agents/[id]/skills/[skillId]/route.ts`        |
| `GET`            | `/api/agents/[id]/skills/packs`            | `app/api/agents/[id]/skills/packs/route.ts`            |
| `POST`           | `/api/agents/[id]/skills/packs/apply`      | `app/api/agents/[id]/skills/packs/apply/route.ts`      |
| `POST`           | `/api/agents/[id]/skills/propose`          | `app/api/agents/[id]/skills/propose/route.ts`          |
| `POST`           | `/api/agents/[id]/skills/propose-from-rag` | `app/api/agents/[id]/skills/propose-from-rag/route.ts` |
| `POST`           | `/api/agents/[id]/skills/optimize`         | `app/api/agents/[id]/skills/optimize/route.ts`         |
| `GET/PATCH`      | `/api/agents/[id]/skills/cortex-mode`      | `app/api/agents/[id]/skills/cortex-mode/route.ts`      |
| `GET/POST/PUT`   | `/api/agents/[id]/specialists`             | `app/api/agents/[id]/specialists/route.ts`             |
| `GET`            | `/api/agents/[id]/tools`                   | `app/api/agents/[id]/tools/route.ts`                   |
| `PATCH`          | `/api/agents/[id]/tools/[toolId]`          | `app/api/agents/[id]/tools/[toolId]/route.ts`          |
| `GET/PATCH`      | `/api/agents/[id]/datastores`              | `app/api/agents/[id]/datastores/route.ts`              |
| `GET/POST/PATCH` | `/api/agents/[id]/datasources`             | `app/api/agents/[id]/datasources/route.ts`             |
| `PATCH`          | `/api/agents/[id]/visibility`              | `app/api/agents/[id]/visibility/route.ts`              |
| `POST`           | `/api/agents/[id]/reset-security`          | `app/api/agents/[id]/reset-security/route.ts`          |

***

## Padrão de autenticação

Todos os endpoints do agente usam `withPermissionRoute` de `@zappway/lib/create-route-handler`.

```ts theme={null}
withPermissionRoute(
  request,
  {
    anyPermission: ['agents.read'],  // or 'agents.write' for mutations
    authMode: 'lightweight',         // read endpoints use lightweight
  },
  async (req: AppRouteRequest) => { ... }
)
```

**LEIA os pontos de extremidade:** `anyPermission: ['agents.read']` + `authMode: 'lightweight'`

**Endpoints WRITE:** `anyPermission: ['agents.write']` (sem authMode — usa sessão completa)

**Isolamento da organização:** todas as consultas devem ter como escopo `req.session.organization.id`.

***

## CRUD principal

### Listar Agentes

```ts theme={null}
// GET /api/agents
const agents = await prisma.agent.findMany({
  where: { organizationId },
  orderBy: { updatedAt: 'desc' },
});
```

### Criar agente

```ts theme={null}
// POST /api/agents
const agent = await prisma.agent.create({
  data: {
    organizationId,
    name: data.name,
    description: data.description,
    // ...other fields
  },
});
```

### Obtenha agente por ID

```ts theme={null}
// GET /api/agents/[id]
const agent = await prisma.agent.findFirst({
  where: { id: agentId, organizationId },
});
if (!agent) return NextResponse.json({ error: 'Not found' }, { status: 404 });
```

***

## SubAPI de habilidades

### Principais funções da biblioteca

```ts theme={null}
import {
  getAvailableAgentSkillSlug,
  assertAgentBelongsToOrganization,
  normalizeAgentSkillSlug,
  AGENT_SKILL_STATUS_VALUES,
  AGENT_SKILL_ACTION_TYPES,
  listSkillPacksForAgent,
  applySkillPack,
  createAgentSkillOptimizationApprovals,
} from '@zappway/lib/agent-skills';
```

### Lógica do Escopo de Habilidade

```ts theme={null}
// scope: 'agent' → agentId = params.id
// scope: 'organization' → agentId = null
agentId: data.scope === 'organization' ? null : agentId,
```

### Restrição de exclusividade do slug

```
UniqueConstraint: organizationId_slug
```

Ao criar/atualizar um slug, sempre verifique se há conflitos:

```ts theme={null}
const conflict = await prisma.agentSkill.findUnique({
  where: { organizationId_slug: { organizationId, slug: nextSlug } },
  select: { id: true },
});
if (conflict && conflict.id !== current.id) return 409;
```

### Listar tipo de resposta de habilidades

```ts theme={null}
import type { AgentSkillsResponse } from '@zappway/lib/types/agent-skills';
// Response: { skills: AgentSkill[], approvals: ActionApproval[] }
```

***

## SubAPI de especialistas

### Detecção de ciclo

O manipulador `PUT /specialists` detecta ciclos em profundidade 1 antes de criar uma delegação:

```ts theme={null}
const reverseTools = await tx.tool.findMany({
  where: { agentId: targetAgentId, type: 'agent' },
  select: { config: true },
});
const hasCycle = reverseTools.some(
  (t) => (t.config as Record<string, unknown> | null)?.targetAgentId === parentAgentId
);
if (hasCycle) return 400 'CYCLE_BLOCKED';
```

### estrutura de configuração de regra especializada

```ts theme={null}
// Stored in tool.config (Prisma.InputJsonObject)
{
  targetAgentId: string,
  specialistRule: {
    toolId: string,
    targetAgentId: string,
    reason: string,
    confidence: number,
    signalsDetected: string[],
    matchedDocuments: string[],
    status: 'active',
    createdAt: string, // ISO
  }
}
```

### Desativar: remove a regra especializada

```ts theme={null}
if (data.action === 'deactivate') {
  delete config.specialistRule;
  await prisma.tool.update({ where: { id: data.toolId }, data: { config } });
}
```

***

## Problemas conhecidos/pegadinhas

* **`assertAgentBelongsToOrganization`** — Sempre chame isso antes de qualquer operação de banco de dados específica do agente para evitar vazamentos de dados entre organizações. Será lançado se o agente não corresponder à organização.
* **`propose-from-rag`** usa um contador `skipped` para propostas que correspondam às habilidades existentes (por slug). O limite é definido em `@zappway/lib/agent-skills`.
* **Especialistas `PUT`** é IDEMPOTENTE, mas NÃO ESTRITAMENTE ATÔMICO no nível do banco de dados (veja o comentário embutido no código: `IDEMPOTENT_BUT_NOT_ATOMIC`). Sob alta simultaneidade, duas solicitações paralelas poderiam criar uma delegação duplicada. Um índice exclusivo em nível de banco de dados em `(agent_id, type, config->>'targetAgentId')` resolveria isso.
* **O status `lastReviewedAt`** só é atualizado quando o status muda para `active` ou `archived`, e não em atualizações gerais de `PATCH`.

***

## Índices Prisma usados

| Tabela           | Índice/Restrição                      | Usado por                              |
| ---------------- | ------------------------------------- | -------------------------------------- |
| `AgentSkill`     | `organizationId_slug` (único)         | Verificação de conflito de slug        |
| `AgentSkill`     | `organizationId, agentId`             | Listar habilidades por agente          |
| `Tool`           | `agentId, type`                       | Pesquisa de ferramentas especializadas |
| `ActionApproval` | `organizationId, agentId, actionType` | Aprovações pendentes                   |

***

## Referência de erro

| Erro                                 | Estado | Causa                                                     |
| ------------------------------------ | ------ | --------------------------------------------------------- |
| `Agent not found for organization`   | 404    | `assertAgentBelongsToOrganization` lançado                |
| `Skill not found`                    | 404    | A habilidade não pertence ao agente/organização           |
| `Skill slug already exists`          | 409    | `organizationId_slug` restrição exclusiva                 |
| `An agent cannot delegate to itself` | 400    | Auto-loop em `PUT /specialists`                           |
| `Delegation cycle detected`          | 400    | Ciclo de profundidade 1 em `PUT /specialists`             |
| `Tool not found or invalid`          | 404    | A ferramenta não pertence ao agente ou `type !== 'agent'` |
