# Plano de Implementacao: Consolidar Tools MCP v2 (Filosofia Deep Agents)

## Visao Geral

Consolidar 27 tools em 6, adicionando tool de exploracao (padrao investigador) e eviction inteligente (resumo com LLM em vez de truncamento bruto). Services layer (`supabase_client.py`, `llm_service.py`) permanece intacto — apenas a camada de tools muda.

```
NOVA (6 tools, 4 modulos):
tools/explorar.py         → explorar_processo      (NOVO - mapa do investigador)
tools/consultas.py        → consultar_documentos   (7 tools → 1)
                          → consultar_movimentacoes (3 tools → 1)
tools/analise.py          → analisar               (17 tools → 1)
tools/user.py             → whoami                  (sem mudanca)
```

---

## Fase 1: Foundation — `tools/_helpers.py`

Expandir o helper existente com funcoes compartilhadas que todas as novas tools vao usar.

### Tarefas

- [x] Adicionar constantes compartilhadas (atualmente duplicadas em 3+ arquivos)
  - [x] `SYNC_URL = "https://tecjusticamcp3.vercel.app/login"`
  - [x] `MSG_PROCESSO_NAO_ENCONTRADO` com sugestao instrutiva
  - [x] `MSG_DOCUMENTO_NAO_ENCONTRADO` com sugestao instrutiva
  - [x] `LIMIAR_EVICTION = 10_000` (chars, ~2500 tokens)
  - [x] `MAX_PROCESSOS = 50`, `MAX_DOCUMENTOS = 100`, `MAX_MOVIMENTACOES = 100`
- [x] Implementar `paginar_resultado()` [complexo]
  - [x] Aceita `items: list`, `total: int`, `limite: int`, `offset: int`
  - [x] Retorna dict com `total`, `limite`, `offset`, `has_more`, `resultados`
- [x] Implementar `_smart_response()` — eviction inteligente [complexo]
  - [x] Aceita `conteudo: str`, `tipo: str = "documento"`, `max_chars: int = LIMIAR_EVICTION`
  - [x] Se conteudo <= max_chars: retorna `{conteudo, foi_resumido: False, tamanho_original}`
  - [x] Se conteudo > max_chars: chama `llm.resumir_texto()` com instrucao adaptada por tipo
  - [x] Tipos suportados: "documento", "analise", "lista"
  - [x] Retorna `{conteudo: resumo, foi_resumido: True, tamanho_original, tamanho_final, nota}`
- [x] Implementar `erro_instrutivo()` — formato padrao de erro
  - [x] Aceita `erro: str`, `sugestao: str`
  - [x] Retorna `{"sucesso": False, "erro": erro, "sugestao": sugestao}`
- [x] Mover helpers de outros arquivos para `_helpers.py`
  - [x] `_montar_contexto_documentos()` de `tools/documentos.py`
  - [x] `_extrair_snippet()` de `tools/documentos.py`
  - [x] `CATEGORIAS_DOCS` de `tools/documentos.py`
- [x] Manter `analisar_com_selecao_modelo()` existente (sem mudanca)
- [x] Manter `LIMITE_GEMINI` e `LIMITE_GROK` existentes (sem mudanca)

### Detalhes Tecnicos

**Arquivo:** `tools/_helpers.py`

Funcoes existentes a manter:
```python
# Ja existe em _helpers.py (linhas 1-40)
LIMITE_GEMINI = 3_000_000
LIMITE_GROK = 7_000_000
async def analisar_com_selecao_modelo(contexto, prompt, max_tokens=2000) -> tuple[str, str]
```

Funcoes a mover de `tools/documentos.py`:
```python
# _montar_contexto_documentos() — monta texto de contexto a partir de lista de docs
# _extrair_snippet() — extrai 200 chars ao redor de um match de busca
# CATEGORIAS_DOCS — dict com categorias de documentos para filtro
```

Eviction — usa `llm.resumir_texto()` que ja existe em `services/llm_service.py`:
```python
# LLMService.resumir_texto(texto, max_tokens_saida=4000, instrucao=None, model=None)
# Usa Gemini Flash (1M context), temperature 0.2
```

---

## Fase 2: Tool de Exploracao — `tools/explorar.py`

Criar a tool `explorar_processo` — o "ls" do processo, padrao investigador dos Deep Agents.

### Tarefas

- [x] Criar `tools/explorar.py` com `register_explorar_tools(mcp)` [complexo]
- [x] Implementar `explorar_processo()` com dispatch implicito:
  - [x] `numero_processo` fornecido → mapa completo do processo
  - [x] `busca` fornecido → pesquisa por nome de parte
  - [x] Nenhum parametro → lista processos disponiveis
- [x] Para mapa completo (caso principal), chamar em paralelo (asyncio.gather):
  - [x] `client.processo_completo(numero_processo)` → dados_basicos + partes
  - [x] `client.stats_processo(numero_processo)` → estatisticas
  - [x] `client.listar_metadados_documentos(numero_processo)` → catalogo_documentos
  - [x] `client.tipos_documentos_agregados(numero_processo)` → tipos_documentos
  - [x] `client.tipos_movimentacoes_agregados(numero_processo)` → tipos_movimentacoes
  - [x] `detectar_tipo_processo(numero_processo)` → tipo_processo
- [x] Formatar catalogo_documentos: lista com {id, nome, tipo, tamanho_chars, data} para CADA doc
- [x] Retorno de lista de processos usa `paginar_resultado()`
- [x] Docstring completa com 4 elementos + exemplo + instrucao "use SEMPRE como primeiro passo"
- [x] Erros instrutivos com `erro_instrutivo()`

### Detalhes Tecnicos

**Arquivo:** `tools/explorar.py` (~100-120 linhas)

Metodos do `supabase_client.py` reutilizados:
```python
# services/supabase_client.py
client.processo_completo(numero_processo)     # linha ~156 — vw_processo_completo view
client.stats_processo(numero_processo)         # linha ~174 — vw_stats_processo view
client.listar_metadados_documentos(numero)     # linha 436 — documents table, 6 campos sem conteudo
client.tipos_documentos_agregados(numero)      # linha 391 — agregacao in-memory, max 500 registros
client.tipos_movimentacoes_agregados(numero)   # linha 363 — agregacao in-memory, max 500 registros
client.listar_todos_processos(limite)          # linha ~100 — jobs table com nested processos
client.buscar_por_parte(nome_parte)            # linha ~128 — RPC buscar_processos_por_parte
```

Tipo de processo via `supabase_client.py`:
```python
# detectar_tipo_processo() usa classe_descricao e assuntos contra TERMOS_CRIMINAL
# Retorna "civel" ou "criminal"
```

Signature:
```python
async def explorar_processo(
    numero_processo: str | None = None,
    busca: str | None = None,
    limite: int = 20,
    offset: int = 0,
    ctx: Context = None,
) -> dict[str, Any]:
```

Retorno para mapa completo:
```python
{
    "sucesso": True,
    "dados_basicos": {
        "numero_processo": "...",
        "classe": "...",
        "tribunal": "...",
        "instancia": "...",
        "valor_causa": "...",
        "data_ajuizamento": "...",
    },
    "partes": [{"nome": "...", "tipo": "autor"}, ...],
    "catalogo_documentos": [
        {"id": "uuid", "nome": "Sentenca", "tipo": "Sentenca",
         "tamanho_chars": 45000, "data": "2024-03-15"},
        ...
    ],
    "tipos_documentos": {"Sentenca": 3, "Peticao": 12, ...},
    "tipos_movimentacoes": {"Juntada": 45, "Despacho": 12, ...},
    "estatisticas": {
        "total_documentos": 45,
        "total_movimentacoes": 120,
        "tamanho_total_mb": 12.5,
    },
    "tipo_processo": "civel",
}
```

---

## Fase 3: Tools de Consulta — `tools/consultas.py`

Criar `consultar_documentos` e `consultar_movimentacoes` com dispatch implicito e eviction.

### Tarefas

- [x] Criar `tools/consultas.py` com `register_consultas_tools(mcp)` [complexo]
- [x] Implementar `consultar_documentos()` com dispatch implicito:
  - [x] `document_id` fornecido → le documento com `_smart_response()` (eviction)
  - [x] `busca` fornecido → `client.buscar_em_documentos()` com snippets
  - [x] `importantes=True` → `client.buscar_documentos_relevantes()` com filtro de categoria
  - [x] Apenas `numero_processo` → `client.listar_documentos()` sem conteudo
  - [x] Todos os caminhos de lista usam `paginar_resultado()`
- [x] Implementar eviction na leitura de documento:
  - [x] Chamar `client.ler_documento(document_id)`
  - [x] Se conteudo > LIMIAR_EVICTION: chamar `_smart_response(conteudo, tipo="documento")`
  - [x] Retornar metadata: id, nome, tipo, data, paginas, tamanho_original, foi_resumido, conteudo
- [x] Implementar `consultar_movimentacoes()` com dispatch implicito:
  - [x] `numero_processo` + `busca` → `client.buscar_movimentacoes_por_termo()`
  - [x] `numero_processo` + `tipo` → `client.listar_movimentacoes(tipo=tipo)`
  - [x] `numero_processo` sozinho → `client.listar_movimentacoes()`
  - [x] Sem `numero_processo` → `client.movimentacoes_recentes()`
  - [x] Todos os caminhos usam `paginar_resultado()`
- [x] Docstrings completas com 4 elementos + instrucao "Use explorar_processo primeiro"
- [x] Erros instrutivos em todos os caminhos de erro

### Detalhes Tecnicos

**Arquivo:** `tools/consultas.py` (~200-250 linhas)

Metodos do `supabase_client.py` reutilizados para documentos:
```python
client.ler_documento(document_id)              # linha ~192 — documents table, todas as colunas
client.buscar_em_documentos(termo, numero, limite, incluir_conteudo=True)  # linha ~210
client.buscar_documentos_relevantes(numero, limite)  # linha ~262 — vw_documentos_relevantes
client.listar_documentos(numero, limite, ordenar_por, incluir_preview=False)  # linha ~188
```

Metodos para movimentacoes:
```python
client.buscar_movimentacoes_por_termo(numero, termo, limite)  # linha ~345
client.listar_movimentacoes(numero, tipo=None, limite=100)     # linha ~320
client.movimentacoes_recentes(limite=50)                       # linha ~305
```

Filtro de documentos importantes — reutilizar CATEGORIAS_DOCS (movido para _helpers.py):
```python
CATEGORIAS_DOCS = {
    "decisorio": ["sentenca", "acordao", "decisao", "despacho"],
    "peticoes": ["peticao", "contestacao", "replica", "embargos"],
    "provas": ["laudo", "pericia", "prova", "documento"],
    "criminal": ["denuncia", "queixa", "inquerito", "flagrante"],
}
```

Eviction na leitura — fluxo:
```
1. doc = client.ler_documento(document_id)
2. conteudo = doc.get("conteudo", "")
3. if len(conteudo) > LIMIAR_EVICTION:
     resultado = await _smart_response(conteudo, tipo="documento")
     doc["conteudo"] = resultado["conteudo"]
     doc["foi_resumido"] = resultado["foi_resumido"]
     doc["tamanho_original"] = resultado["tamanho_original"]
4. return doc
```

---

## Fase 4: Tool de Analise — `tools/analise.py`

Criar `analisar` — a tool unica que substitui todas as 17 tools com LLM.

### Tarefas

- [x] Criar `tools/analise.py` com `register_analise_tools(mcp)` [complexo]
- [x] Implementar `analisar()` com dois caminhos principais:
  - [x] Caminho 1: `document_ids` fornecido → analise de documentos especificos
    - [x] Parse document_ids (split por virgula, strip)
    - [x] Buscar cada doc via `client.ler_documento(id)`
    - [x] Montar contexto com `_montar_contexto_documentos()`
    - [x] Se 2+ docs: adicionar instrucao de comparacao ao prompt
  - [x] Caminho 2: sem document_ids → analise do processo completo
    - [x] Estrategia markdown-first (reutilizar logica de `analisar_processo` atual):
      - [x] Tentar `client.obter_markdown_processo()` — texto integral
      - [x] Se > LIMITE_GROK (7M): usar `client.selecionar_documentos_inteligente()`
      - [x] Se <= LIMITE_GROK: usar direto (ou `obter_contexto_processo()` como fallback)
- [x] Implementar deteccao automatica civel/criminal:
  - [x] Chamar `detectar_tipo_processo(numero_processo)`
  - [x] Prepend "TIPO DE PROCESSO: CIVEL/CRIMINAL" ao contexto
- [x] Implementar perspectiva:
  - [x] Se `perspectiva` fornecida: prepend "PERSPECTIVA DE ANALISE: {perspectiva}" ao contexto
- [x] Implementar selecao de modelo:
  - [x] Se `modelo` forcado: usar diretamente
  - [x] Se nao: usar `analisar_com_selecao_modelo()` (Gemini < 3M, Grok > 3M)
- [x] Retorno com metadata: sucesso, numero_processo, tipo_processo, modelo, contexto_chars, estrategia, resposta
- [x] Docstring completa com exemplos de perguntas para todos os tipos de analise
- [x] Erros instrutivos em todos os caminhos

### Detalhes Tecnicos

**Arquivo:** `tools/analise.py` (~180-220 linhas)

Logica de contexto — reutilizar de `tools/processos.py` (linhas 201-284):
```python
# Estrategia markdown-first:
# 1. markdown = client.obter_markdown_processo(numero)
# 2. Se markdown existe e tem conteudo:
#    - Se len(markdown) <= LIMITE_GROK: usar direto
#    - Se > LIMITE_GROK: usar selecionar_documentos_inteligente()
# 3. Se markdown nao existe: usar obter_contexto_processo(max_chars=500000)
```

Metodos do `supabase_client.py` reutilizados:
```python
client.obter_markdown_processo(numero)             # linha 421
client.obter_contexto_processo(numero, max_chars)   # linha ~530+ — monta markdown otimizado
client.selecionar_documentos_inteligente(numero)    # linha 470 — prioridade por tipo
client.ler_documento(document_id)                   # linha ~192
detectar_tipo_processo(numero)                      # usa processo_completo + TERMOS_CRIMINAL
```

Helper existente:
```python
# tools/_helpers.py
analisar_com_selecao_modelo(contexto, prompt, max_tokens=2000) -> (resposta, modelo)
```

LLM service:
```python
# services/llm_service.py
llm.query(pergunta, contexto, model, temperature=0.3, max_tokens=2000) -> LLMResponse
```

Signature:
```python
async def analisar(
    numero_processo: str,
    pergunta: str = "Faca uma analise completa deste processo",
    document_ids: str | None = None,
    perspectiva: str | None = None,
    modelo: str | None = None,
    ctx: Context = None,
) -> dict[str, Any]:
```

---

## Fase 5: Integracao — `server.py`, `__init__.py`, prompts

Conectar tudo e atualizar prompts para referenciar os novos nomes.

### Tarefas

- [x] Atualizar `tools/__init__.py`:
  - [x] Remover imports antigos (register_processos_tools, register_documentos_tools, etc.)
  - [x] Adicionar: `from .explorar import register_explorar_tools`
  - [x] Adicionar: `from .consultas import register_consultas_tools`
  - [x] Adicionar: `from .analise import register_analise_tools`
  - [x] Manter: `from .user import register_user_tools`
- [x] Atualizar `server.py` imports e registros:
  - [x] Substituir 6 imports por 4 imports novos
  - [x] Substituir 6 `register_*_tools(mcp)` por 4 chamadas novas
- [x] Atualizar `@mcp.prompt analise_completa` [complexo]
  - [x] FASE 0: explorar_processo → mapa completo
  - [x] FASE 1: consultar_documentos seletivamente (baseado no catalogo)
  - [x] FASE 2: analisar com perguntas especificas
  - [x] FASE 3: analisar com perspectivas diferentes
- [x] Atualizar `@mcp.prompt parecer_tecnico`
  - [x] Usar analisar com pergunta especifica + explorar_processo
- [x] Atualizar `@mcp.prompt due_diligence`
  - [x] Seguir padrao: explorar → consultar → analisar
- [x] Atualizar `@mcp.prompt preparar_audiencia`
  - [x] Seguir padrao: explorar → consultar → analisar
- [x] Atualizar `@mcp.prompt estrategia_recursal`
  - [x] Seguir padrao: explorar → consultar → analisar
- [x] Reescrever `@mcp.prompt guia_ferramentas` [complexo]
  - [x] Listar apenas 6 tools com descricoes claras
  - [x] Incluir exemplos de uso para cada tool
  - [x] Explicar padrao investigador: explorar → planejar → executar

### Detalhes Tecnicos

**Arquivos:** `tools/__init__.py`, `server.py`

Novo `__init__.py`:
```python
from .explorar import register_explorar_tools
from .consultas import register_consultas_tools
from .analise import register_analise_tools
from .user import register_user_tools

__all__ = [
    "register_explorar_tools",
    "register_consultas_tools",
    "register_analise_tools",
    "register_user_tools",
]
```

Novo registro em `server.py` (linha ~122-131):
```python
register_explorar_tools(mcp)
register_consultas_tools(mcp)
register_analise_tools(mcp)
register_user_tools(mcp)
```

Exemplo do prompt `analise_completa` atualizado:
```python
@mcp.prompt
def analise_completa(numero_processo: str) -> str:
    return f"""# ANALISE JURIDICA PROFISSIONAL - Processo {numero_processo}

Voce e um advogado senior realizando analise completa deste processo.

## FASE 0: EXPLORACAO (OBRIGATORIO)
1. `explorar_processo("{numero_processo}")` — Mapa completo: partes, catalogo de
   documentos com IDs e tamanhos, tipos, estatisticas, tipo civel/criminal

## FASE 1: COLETA SELETIVA
Com base no catalogo, escolha os documentos mais relevantes para ler:
2. `consultar_documentos(document_id="<id-sentenca>")` — Ler sentenca/acordao
3. `consultar_documentos(document_id="<id-peticao-inicial>")` — Ler peticao inicial
4. `consultar_movimentacoes(numero_processo="{numero_processo}")` — Timeline

## FASE 2: ANALISE
5. `analisar("{numero_processo}", "Qual a situacao atual? Fase, pendencias, alertas.")`
6. `analisar("{numero_processo}", "Extraia todos os pedidos com tipo, valor e status.")`
7. `analisar("{numero_processo}", "Analise as decisoes: fundamentacao, ratio decidendi.")`

## FASE 3: AVALIACAO ESTRATEGICA
8. `analisar("{numero_processo}", "Analise de risco completa com cenarios.", perspectiva="autor")`
9. `analisar("{numero_processo}", "Analise de risco completa com cenarios.", perspectiva="reu")`

## FASE 4: CONCLUSAO
Elabore: sintese (5 linhas), pontos criticos, probabilidade de exito,
recomendacoes estrategicas, proximos passos processuais.

Inicie pela FASE 0."""
```

---

## Fase 6: Cleanup e Documentacao

Mover arquivos antigos, atualizar CLAUDE.md, validar.

### Tarefas

- [x] Criar diretorio `tools/_legacy/`
- [x] Mover arquivos antigos para `tools/_legacy/`:
  - [x] `tools/processos.py` → `tools/_legacy/processos.py`
  - [x] `tools/documentos.py` → `tools/_legacy/documentos.py`
  - [x] `tools/timeline.py` → `tools/_legacy/timeline.py`
  - [x] `tools/queries.py` → `tools/_legacy/queries.py`
  - [x] `tools/analise_juridica.py` → `tools/_legacy/analise_juridica.py`
- [x] Atualizar `CLAUDE.md`:
  - [x] Secao Arquitetura: nova estrutura de tools
  - [x] Secao "Como adicionar nova tool": adaptar ao novo padrao
  - [x] Tabela de tools com descricoes atualizadas
  - [x] Mencionar eviction inteligente e padrao investigador
- [x] Rodar `ruff check --fix . && ruff format .`
- [x] Rodar `mypy .`
- [x] Verificar que todos os prompts referenciam tools corretas (grep por nomes antigos)

### Detalhes Tecnicos

Verificacao de nomes antigos (nenhum deve aparecer fora de _legacy):
```bash
grep -r "buscar_processo\|listar_processos\|buscar_por_parte\|estatisticas_processo" \
  --include="*.py" --exclude-dir="_legacy" tools/ server.py

grep -r "listar_documentos\|ler_documento\|buscar_em_documentos\|tipos_documentos" \
  --include="*.py" --exclude-dir="_legacy" tools/ server.py

grep -r "analisar_processo\|analisar_documento\|perguntar\|comparar_documentos" \
  --include="*.py" --exclude-dir="_legacy" tools/ server.py

grep -r "situacao_atual\|extrair_pedidos\|analise_risco\|parecer_juridico" \
  --include="*.py" --exclude-dir="_legacy" tools/ server.py
```

Nova secao do CLAUDE.md:
```markdown
## Arquitetura

tools/
  explorar.py          # 1 tool: explorar_processo (mapa do investigador)
  consultas.py         # 2 tools: consultar_documentos, consultar_movimentacoes
  analise.py           # 1 tool: analisar (toda analise com LLM)
  user.py              # 1 tool: whoami
  _helpers.py          # Eviction inteligente, paginacao, selecao de modelo
  _legacy/             # Tools antigos preservados para referencia
```
