> ## 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

> Referencia interna para la API de agentes: que cubre operaciones CRUD, administración de herramientas, conexiones del almacén de datos, actualización de configuración y todos los subrecursos.

> **Documentación interna para desarrolladores.** Esta página documenta los puntos finales de API de los agentes, los requisitos de autenticación, los patrones de consulta de Prisma y las notas de implementación. No está destinado a usuarios finales.

***

## Mapa de ruta

| Método           | Punto final                                | Archivo de controlador                                 |
| ---------------- | ------------------------------------------ | ------------------------------------------------------ |
| `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`          |

***

## Patrón de autenticación

Todos los puntos finales del agente utilizan `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) => { ... }
)
```

**LEER puntos finales:** `anyPermission: ['agents.read']` + `authMode: 'lightweight'`

**ESCRIBIR puntos finales:** `anyPermission: ['agents.write']` (sin modo de autenticación; utiliza sesión completa)

**Aislamiento de organización:** Todas las consultas deben tener como alcance `req.session.organization.id`.

***

## CRUD central

### Listar agentes

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

### Crear agente

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

### Obtener 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 });
```

***

## Sub-API de habilidades

### Funciones clave de la 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 del alcance de la habilidad

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

### Restricción de unicidad de Slug

```
UniqueConstraint: organizationId_slug
```

Al crear/actualizar un slug, siempre verifique si hay conflictos:
***CÓDIGO\_BLOQUE\_7***

### Listar tipo de respuesta de habilidades

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

***

## Sub-API de especialistas

### Detección de ciclo

El controlador `PUT /specialists` detecta ciclos en profundidad-1 antes de crear una delegación:

```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';
```

### estructura de configuración de reglas especializadas

```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
  }
}
```

### Desactivar: elimina la regla especializada

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

***

## Problemas conocidos / Problemas

* **`assertAgentBelongsToOrganization`**: llame siempre a esto antes de cualquier operación de base de datos específica del agente para evitar fugas de datos entre organizaciones. Se lanza si el agente no coincide con la organización.
* **`propose-from-rag`** utiliza un contador `skipped` para propuestas que coinciden estrechamente con las habilidades existentes (por slug). El umbral se define en `@zappway/lib/agent-skills`.
* **Especialistas `PUT`** es IDEMPOTENTE pero NO ESTRICTAMENTE ATÓMICO a nivel de base de datos (consulte el comentario en línea en el código: `IDEMPOTENT_BUT_NOT_ATOMIC`). En condiciones de alta simultaneidad, dos solicitudes paralelas podrían crear una delegación duplicada. Un índice único a nivel de base de datos en `(agent_id, type, config->>'targetAgentId')` solucionaría este problema.
* **El estado `lastReviewedAt`** solo se actualiza cuando el estado cambia a `active` o `archived`, no en las actualizaciones generales de `PATCH`.

***

## Índices Prisma utilizados

| Mesa             | Índice / Restricción                  | Utilizado por                           |
| ---------------- | ------------------------------------- | --------------------------------------- |
| `AgentSkill`     | `organizationId_slug` (único)         | Verificación de conflictos de babosas   |
| `AgentSkill`     | `organizationId, agentId`             | Listar habilidades por agente           |
| `Tool`           | `agentId, type`                       | Búsqueda de herramientas especializadas |
| `ActionApproval` | `organizationId, agentId, actionType` | Aprobaciones pendientes                 |

***

## Referencia de errores

| Error                                | Estado | Causa                                                      |
| ------------------------------------ | ------ | ---------------------------------------------------------- |
| `Agent not found for organization`   | 404    | `assertAgentBelongsToOrganization` lanzó                   |
| `Skill not found`                    | 404    | La habilidad no pertenece al agente/org                    |
| `Skill slug already exists`          | 409    | `organizationId_slug` restricción única                    |
| `An agent cannot delegate to itself` | 400    | Auto-bucle en `PUT /specialists`                           |
| `Delegation cycle detected`          | 400    | Ciclo de profundidad 1 en `PUT /specialists`               |
| `Tool not found or invalid`          | 404    | La herramienta no pertenece al agente o `type !== 'agent'` |
