arcadiasuite/.planning/phases/03-miroflow-embutido/03-RESEARCH.md

29 KiB

Phase 3: MiroFlow Embutido - Research

Researched: 2026-03-25 Domain: Python agent framework (MiroFlow) integrado ao Node.js/Express + Ollama local + Superset bridge Confidence: HIGH (baseado em inspeção direta do código-fonte e serviços ativos)


Summary

O Phase 3 conecta o framework Python MiroFlow (já clonado como submodule em server/modules/miroflow/) ao backend Node.js do Arcádia Suite, expondo um endpoint POST /api/miroflow/analyze que despacha para um microserviço Python FastAPI. Esse microserviço instancia agentes MiroFlow configurados via YAML, aponta para o Ollama local (já rodando na porta 11434 com deepseek-r1:14b instalado), e registra cada execução como nó imutável no KG (tabela graph_nodes via /api/graph/nodes).

O padrão de integração Node ↔ Python já está estabelecido no projeto: server/bi/engine-proxy.ts e server/python/bi_analysis_service.py demonstram o fluxo exato — Express proxy faz fetch() para FastAPI local; a resposta é repassada ao cliente. O novo microserviço MiroFlow (miroflow_service.py) seguirá o mesmo padrão, rodando na porta 8006. O agente Researcher exige llama3.1:8b, que ainda não está instalado no Ollama (apenas deepseek-r1:14b, llama3.2:3b e nomic-embed-text estão disponíveis).

No frontend, o componente MiroFlowControl.tsx será um painel overlay/tab injetado na página BiWorkspace.tsx que já usa o SupersetDashboard component. O toggle "Modo Científico" chama POST /api/miroflow/analyze e exibe a resposta estruturada ao lado do dashboard Superset.

Primary recommendation: Construir server/python/miroflow_service.py como FastAPI standalone (porta 8006), instanciar agentes MiroFlow com YAML inline (sem arquivos externos), usar UnifiedOpenAIClient apontando para Ollama via OLLAMA_BASE_URL/v1, registrar execuções via createNode() do graph service.


User Constraints

(Seção obrigatória — copiada do STATE.md/ROADMAP.md/PROJECT.md que fazem as vezes de CONTEXT.md)

Locked Decisions

  • Stack: Node.js + TypeScript backend, React + TypeScript frontend, PostgreSQL, Neo4j KG
  • IA: Ollama local MÁXIMO 14B — deepseek-r1:14b para Statistician e Fiscal Auditor, llama3.1:8b para Researcher
  • NUNCA usar modelos acima de 14B: proibido citar ou planejar deepseek-r1:32b, deepseek-r1:70b, llama3.1:70b ou qualquer modelo maior
  • MiroFlow já clonado em server/modules/miroflow/ como submodule Python
  • Branch de deploy: Servidor
  • Superset em produção com RLS — não alterar configurações existentes
  • Backend-first: API definida antes do frontend
  • Auditoria imutável em todas as execuções (KG)

Claude's Discretion

  • Porta do microserviço MiroFlow (recomenda-se 8006 pelo padrão existente)
  • Estrutura interna dos agentes MiroFlow (YAML inline vs arquivos externos)
  • Forma de integrar o toggle no frontend (overlay, tab, painel lateral)
  • Como fazer o llama3.1:8b ser baixado (wave 0 task vs setup manual)

Deferred Ideas (OUT OF SCOPE)

  • Versionamento Git-like de skills (Phase 2 pendente, não Phase 3)
  • OpenClaw (Phase 4)
  • Automation Fabric (Phase 5)
  • Dev Center Completo (Phase 6)

Standard Stack

Core

Library Version Purpose Why Standard
MiroFlow 1.7.0 Framework de agentes Python Já no submodule, desenvolvido pela MiromindAI
FastAPI >=0.115.0 Microserviço Python Padrão já usado em todos os serviços Python do projeto
uvicorn >=0.32.0 ASGI server Usado em todos os serviços Python
omegaconf (via miroflow deps) Configuração YAML com variáveis Dependência central do MiroFlow
hydra-core >=1.3.2 Composição de configurações Dependência central do MiroFlow
openai ==1.78.1 Cliente HTTP para Ollama (OpenAI-compat.) MiroFlow usa UnifiedOpenAIClient via openai SDK
httpx / aiohttp >=0.28.1 / >=3.12.15 HTTP async Dependências do MiroFlow e FastAPI

Supporting

Library Version Purpose When to Use
python-dotenv >=1.1.1 Leitura de .env Inicialização do microserviço
pydantic >=2.x Validação de request/response Models FastAPI
neo4j (driver) opcional Neo4j direto Apenas se precisar grafo real; por ora usa graph_nodes PostgreSQL
psycopg2-binary >=2.9.x PostgreSQL direto Se microserviço precisar escrever no banco

Alternatives Considered

Instead of Could Use Tradeoff
Microserviço FastAPI separado Subprocess Node → Python subprocess é síncrono e frágil; FastAPI segue padrão estabelecido
YAML files externos YAML inline (dict) em Python Inline elimina dependência de caminhos de arquivo em container
Ollama direto (porta 11434) Via LiteLLM gateway (porta 4000) LiteLLM tem fallback e roteamento; Ollama direto é mais simples para agentes isolados

Installation (para o microserviço):

# Instalar dependências no ambiente Python do servidor
pip install fastapi uvicorn omegaconf hydra-core openai python-dotenv pydantic psycopg2-binary
# Ou instalar o miroflow inteiro com uv:
cd server/modules/miroflow && uv sync

Version verification: Os pacotes acima são os listados no pyproject.toml do MiroFlow v1.7.0, verificado diretamente no arquivo.


Architecture Patterns

server/python/
├── miroflow_service.py      # novo microserviço FastAPI (porta 8006)
├── bi_analysis_service.py   # existente (referência de padrão)
└── ...

server/miroflow/
├── routes.ts                # Express router: POST /api/miroflow/analyze
└── engine-proxy.ts          # fetch() para http://localhost:8006

client/src/
├── pages/BiWorkspace.tsx    # EXISTENTE — adicionar tab "Científico"
└── components/
    └── MiroFlowControl.tsx  # NOVO — toggle + resultado da análise

docker/python-entrypoint.sh  # adicionar case "miroflow" → porta 8006
docker-compose.prod.yml      # adicionar serviço miroflow (porta 8006)

Pattern 1: Node → Python Microservice Proxy

What: Express recebe a request, faz fetch() para FastAPI, retorna o resultado. Sem subprocess, sem child_process. When to use: Sempre que Node.js precisar de lógica Python (pandas, ML, agentes). Example:

// Source: server/bi/engine-proxy.ts (padrão existente)
const MIROFLOW_URL = `http://${process.env.MIROFLOW_HOST || "localhost"}:${process.env.MIROFLOW_PORT || "8006"}`;

async function proxyToMiroFlow(path: string, body: object): Promise<any> {
  const response = await fetch(`${MIROFLOW_URL}${path}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(300_000), // 5min — modelos LLM são lentos
  });
  if (!response.ok) {
    const err = await response.json().catch(() => ({ detail: response.statusText }));
    throw new Error(err.detail || `MiroFlow error: ${response.status}`);
  }
  return response.json();
}

Pattern 2: MiroFlow Agent com Ollama via UnifiedOpenAIClient

What: MiroFlow usa UnifiedOpenAIClient com base_url apontando para Ollama (OpenAI-compatible API em /v1). When to use: Para todos os agentes do Phase 3. Example:

# Source: server/modules/miroflow/miroflow/llm/openai_client.py + config/llm/base.yaml
from miroflow.agents.factory import build_agent
from miroflow.agents.context import AgentContext

AGENT_CONFIG_STATISTICIAN = {
    "type": "IterativeAgentWithToolAndRollback",
    "max_turns": 10,
    "llm": {
        "provider_class": "UnifiedOpenAIClient",
        "model_name": "deepseek-r1:14b",
        "api_key": "ollama",  # Ollama não valida api_key
        "base_url": "http://localhost:11434/v1",  # Ollama OpenAI-compat
        "max_tokens": 8192,
        "temperature": 0.7,
        "top_p": 1.0, "min_p": 0.0, "top_k": -1,
        "reasoning_effort": None, "repetition_penalty": 1.0,
        "max_context_length": -1, "async_client": True,
        "disable_cache_control": True, "keep_tool_result": -1,
        "use_tool_calls": False, "oai_tool_thinking": False,
    },
}
agent = build_agent(AGENT_CONFIG_STATISTICIAN)
ctx = AgentContext(task_description="Analise os seguintes dados SQL: ...")
result = await agent.run(ctx)

Pattern 3: Registro Imutável no KG via graph_nodes

What: Após cada execução MiroFlow, registrar no PostgreSQL via POST /api/graph/nodes. When to use: Toda execução de agente (success ou error). Example:

// Source: server/graph/service.ts createNode() — chamado pelo routes.ts de miroflow
await fetch("/api/graph/nodes", {
  method: "POST",
  body: JSON.stringify({
    type: "miroflow_execution",
    tenantId: req.user?.tenantId,
    data: {
      agent: "statistician",
      model: "deepseek-r1:14b",
      input: analysisRequest,
      output: analysisResult,
      auditHash: sha256(JSON.stringify({ executionId, input, output })),
      executedAt: new Date().toISOString(),
    }
  })
});

Pattern 4: MiroFlowControl.tsx como tab em BiWorkspace

What: BiWorkspace.tsx já tem estrutura de tabs (Tabs/TabsContent de shadcn/ui). Adicionar tab "Científico" que renderiza MiroFlowControl. When to use: Ponto de entrada do toggle "Modo Científico" no contexto do BI. Example:

// Source: client/src/pages/BiWorkspace.tsx (padrão de tabs existente)
import { MiroFlowControl } from "@/components/MiroFlowControl";

// Dentro do <TabsList>:
<TabsTrigger value="cientifico"><Brain /> Científico</TabsTrigger>

// Dentro das <TabsContent>:
<TabsContent value="cientifico">
  <MiroFlowControl currentDashboardData={currentData} />
</TabsContent>

Anti-Patterns to Avoid

  • subprocess.run() no Node: Não usar child_process.spawn() para chamar Python — use o microserviço FastAPI (padrão estabelecido)
  • Carregar miroflow no container Node: O Dockerfile principal é Node.js puro — Python deve rodar em container separado (Dockerfile.python)
  • Modelos > 14B: Nunca usar deepseek-r1:32b, deepseek-r1:70b, llama3.1:70b ou qualquer modelo acima de 14B parâmetros
  • Modificar configurações do Superset: O proxy /superset/* e as rotas /api/superset/* existentes não devem ser alterados
  • Hardcoded OLLAMA_BASE_URL: Sempre ler de env var OLLAMA_BASE_URL (default http://localhost:11434)

Don't Hand-Roll

Problem Don't Build Use Instead Why
Orquestração de agentes LLM Loop manual de chamadas LLM MiroFlow IterativeAgentWithToolAndRollback Rollback automático, retry, tool calling já implementado
Proxy Node → Python Child process / spawn fetch() para FastAPI (padrão engine-proxy.ts) Stateless, async, sem gestão de processos
Configuração de LLM Classe própria de cliente UnifiedOpenAIClient do MiroFlow Já tem retry, context limit handling, tool protocol
Embedding da análise no Superset iframe manual com JS SupersetDashboard.tsx já existente Guest token, SDK do Superset, error handling prontos
Logs de execução imutáveis Nova tabela no banco graph_nodes + createNode() via server/graph/service.ts Infraestrutura de KG já existente com embeddings
Validação de request/response Manual Pydantic models + FastAPI auto-validation Type safety e OpenAPI spec grátis

Key insight: O projeto já tem todos os primitivos necessários. Phase 3 é essencialmente "conectar os pontos" — o agente Python já existe, o gateway LLM (LiteLLM/Ollama) já está configurado, o KG já tem tabelas, o padrão de proxy Node→Python já está implementado.


Runtime State Inventory

Fase é greenfield (novo microserviço e novas rotas). Não há renomeações ou migrações de dados existentes.

Category Items Found Action Required
Stored data graph_nodes no PostgreSQL — usado pelo KG existente Nenhum — novas inserções com type: "miroflow_execution"
Live service config Ollama rodando na porta 11434 com deepseek-r1:14b instalado llama3.1:8b NÃO instalado — precisa de ollama pull llama3.1:8b
OS-registered state Nenhum Task Scheduler / cron para MiroFlow Nenhuma ação necessária
Secrets/env vars OLLAMA_BASE_URL=http://ollama:11434 já no .env; LITELLM_API_KEY existente Adicionar MIROFLOW_PORT=8006 no .env e docker-compose
Build artifacts server/modules/miroflow/ tem uv.lock mas sem .venv instalado Wave 0: instalar dependências via uv sync ou pip install no Dockerfile.python

Modelo faltando: llama3.1:8b não está instalado no Ollama (False confirmado por curl http://localhost:11434/api/tags). Instalado: deepseek-r1:14b (8.4GB), arcadia-agent:latest (2GB), llama3.2:3b (2GB), nomic-embed-text (274MB). O plano deve incluir ollama pull llama3.1:8b como task de Wave 0 ou pré-requisito.


Environment Availability

Dependency Required By Available Version Fallback
Ollama API :11434 Todos os agentes MiroFlow 0.18.2
deepseek-r1:14b Statistician, Fiscal Auditor 8.4GB
llama3.1:8b Researcher llama3.2:3b (degraded) ou deepseek-r1:14b
Python 3.12 Microserviço FastAPI 3.12.3
uv Instalar deps MiroFlow 0.9.30 pip3
FastAPI/uvicorn Microserviço fastapi 0.128.8
omegaconf (sistema) MiroFlow direto Instalar via uv sync no server/modules/miroflow/
PostgreSQL :5432 KG graph_nodes 16
Neo4j :7687 KG real (opcional) Requer profile [kg] graph_nodes PostgreSQL (já usado)

Missing dependencies with no fallback:

  • llama3.1:8b para o agente Researcher — deve ser baixado em Wave 0 (ollama pull llama3.1:8b)

Missing dependencies with fallback:

  • omegaconf no sistema: instalar com pip3 install omegaconf hydra-core ou rodar MiroFlow dentro de venv com uv sync
  • llama3.1:8b temporariamente: usar deepseek-r1:14b como fallback até o download completar

Common Pitfalls

Pitfall 1: Ollama não expõe /v1 sem flag explícita em versões antigas

What goes wrong: UnifiedOpenAIClient do MiroFlow usa base_url=http://localhost:11434/v1 (OpenAI-compatible endpoint). Versões antigas do Ollama (<0.1.24) não tinham esse endpoint. Why it happens: Ollama 0.18.2 (confirmado no servidor) já suporta /v1/chat/completions. Mas o endpoint retorna erro se o modelo não estiver carregado. How to avoid: Verificar GET http://localhost:11434/api/tags antes de iniciar o agente. Pré-carregar o modelo com ollama run deepseek-r1:14b ou ollama pull. Warning signs: 404 Not Found na URL /v1/chat/completions, ou model not found no corpo da resposta.

Pitfall 2: MiroFlow requer dependências Python não instaladas no container Node

What goes wrong: O Dockerfile principal é Node.js Alpine — não tem Python. Se tentar importar miroflow no contexto Node (via python-bridge ou similar), vai falhar. Why it happens: A tentativa de from omegaconf import ... falha com ModuleNotFoundError porque o sistema Python não tem as deps do MiroFlow. How to avoid: Manter a separação clara: MiroFlow roda SOMENTE em Dockerfile.python como microserviço FastAPI. Node nunca importa Python diretamente. Warning signs: Erro de ModuleNotFoundError: No module named 'omegaconf' nos logs do app principal.

Pitfall 3: Timeout do fetch() insuficiente para modelos grandes

What goes wrong: deepseek-r1:14b com raciocínio pode levar 60-120 segundos para responder. O fetch padrão tem timeout de 30s nos outros proxies. Why it happens: O bi/engine-proxy.ts usa BI_ENGINE_TIMEOUT = 30000. Para LLMs de 14B, isso é insuficiente. How to avoid: Usar AbortSignal.timeout(300_000) (5 minutos) no proxy MiroFlow. Implementar streaming ou polling se necessário. Warning signs: AbortError: The operation was aborted nos logs do Node.

Pitfall 4: Neo4j não está ativo por padrão — usar graph_nodes do PostgreSQL

What goes wrong: O docker-compose.yml tem Neo4j no profile [kg] — não está ativo em deploy padrão. Why it happens: Neo4j é opcional; o KG do Arcádia usa graph_nodes PostgreSQL por padrão. How to avoid: Para imutabilidade, usar POST /api/graph/nodes (PostgreSQL), não o driver neo4j Python direto. O server/graph/service.ts já implementa isso com hashing. Warning signs: Connection refused: 7687 se tentar conectar ao Neo4j sem o profile ativo.

Pitfall 5: MiroFlow não tem llama3.1:8b instalado

What goes wrong: O agente Researcher usa llama3.1:8b mas esse modelo não está no Ollama (False confirmado por inspeção direta). Why it happens: Apenas deepseek-r1:14b, arcadia-agent:latest, llama3.2:3b e nomic-embed-text foram instalados. How to avoid: Incluir ollama pull llama3.1:8b como step explícito na Wave 0 do plano. Warning signs: Agente Researcher falha com model 'llama3.1:8b' not found.

Pitfall 6: BiWorkspace.tsx é uma página grande — cuidado ao modificar

What goes wrong: BiWorkspace.tsx tem muitas funcionalidades (datasets, charts, dashboards, backup, BI engine). Modificação descuidada pode quebrar features existentes. Why it happens: O arquivo tem ~1000+ linhas com múltiplas tabs e estados. How to avoid: Adicionar MiroFlowControl como componente SEPARADO importado, não modificar lógica existente. Adicionar apenas uma nova TabsTrigger e TabsContent. Warning signs: Erros de TypeScript em outros tabs depois da edição.


Code Examples

Verified patterns from official sources:

MiroFlow Agent com Ollama (config inline Python)

# Source: server/modules/miroflow/miroflow/agents/base.py + config/llm/base.yaml
import sys
sys.path.insert(0, "/app/server/modules/miroflow")

import asyncio
from miroflow.agents.factory import build_agent
from miroflow.agents.context import AgentContext

OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")

def make_agent_cfg(model: str) -> dict:
    return {
        "type": "IterativeAgentWithToolAndRollback",
        "name": f"arcadia_{model.replace(':', '_')}",
        "max_turns": 10,
        "llm": {
            "provider_class": "UnifiedOpenAIClient",
            "model_name": model,
            "api_key": "ollama",
            "base_url": f"{OLLAMA_BASE_URL}/v1",
            "max_tokens": 8192,
            "temperature": 0.7,
            "top_p": 1.0, "min_p": 0.0, "top_k": -1,
            "reasoning_effort": None, "repetition_penalty": 1.0,
            "max_context_length": -1, "async_client": True,
            "disable_cache_control": True, "keep_tool_result": -1,
            "use_tool_calls": False, "oai_tool_thinking": False,
        },
    }

async def run_agent(agent_type: str, task: str) -> str:
    model = "deepseek-r1:14b" if agent_type in ("statistician", "fiscal_auditor") else "llama3.1:8b"
    cfg = make_agent_cfg(model)
    agent = build_agent(cfg)
    ctx = AgentContext(task_description=task)
    result = await agent.run(ctx)
    return result.get("summary", str(result))

FastAPI endpoint pattern (seguindo bi_analysis_service.py)

# Source: server/python/bi_analysis_service.py (padrão existente)
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI(title="Arcádia MiroFlow Service", version="1.0.0")

class AnalyzeRequest(BaseModel):
    agent: str  # "statistician" | "fiscal_auditor" | "researcher"
    task: str
    context: dict = {}
    tenant_id: int | None = None

class AnalyzeResponse(BaseModel):
    agent: str
    model: str
    result: str
    execution_id: str
    duration_ms: int

@app.post("/analyze", response_model=AnalyzeResponse)
async def analyze(req: AnalyzeRequest):
    ...

Express proxy para MiroFlow (seguindo engine-proxy.ts)

// Source: server/bi/engine-proxy.ts (padrão existente)
const MIROFLOW_URL = `http://${process.env.MIROFLOW_HOST || "localhost"}:${
  process.env.MIROFLOW_PORT || "8006"
}`;

export function registerMiroFlowRoutes(app: Express): void {
  app.post("/api/miroflow/analyze", async (req: Request, res: Response) => {
    if (!req.isAuthenticated()) return res.status(401).json({ error: "Não autenticado" });
    try {
      const response = await fetch(`${MIROFLOW_URL}/analyze`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ...req.body, tenant_id: (req.user as any)?.tenantId }),
        signal: AbortSignal.timeout(300_000),
      });
      const data = await response.json();
      // Registrar no KG
      await registerExecutionInKG(req, data);
      res.json(data);
    } catch (err: any) {
      res.status(502).json({ error: err.message });
    }
  });

  app.get("/api/miroflow/health", async (_req, res) => {
    try {
      const r = await fetch(`${MIROFLOW_URL}/health`, { signal: AbortSignal.timeout(5000) });
      res.json({ online: r.ok, url: MIROFLOW_URL });
    } catch {
      res.json({ online: false, url: MIROFLOW_URL });
    }
  });
}

Registro no KG (graph_nodes)

// Source: server/graph/service.ts createNode()
import { createNode } from "../graph/service";
import crypto from "crypto";

async function registerExecutionInKG(req: any, execData: any) {
  const auditHash = crypto
    .createHash("sha256")
    .update(JSON.stringify(execData))
    .digest("hex");
  await createNode({
    type: "miroflow_execution",
    tenantId: req.user?.tenantId,
    data: { ...execData, auditHash, immutable: true },
  });
}

State of the Art

Old Approach Current Approach When Changed Impact
Llamaindex/LangChain para agentes MiroFlow (framework próprio MiromindAI) 2025-08 Performance-first, benchmarks públicos, já no submodule
OpenAI API direta Ollama local via LiteLLM gateway 2025 (Arcádia) Soberania total dos dados
Neo4j obrigatório para KG graph_nodes PostgreSQL + Neo4j opcional Phase 1 Sem dependência de serviço extra em produção básica
Hydra config files externos Config dict inline (Python) MiroFlow 1.x Sem dependência de paths, mais fácil em containers

Deprecated/outdated:

  • MiroFlow via CLI (python run_single_task.py): adequado para benchmark, mas não para microserviço de produção. Usar web_app/main.py como referência OU criar FastAPI própria.
  • Modelos > 14B: explicitamente proibidos na arquitetura do projeto.

Open Questions

  1. llama3.1:8b vs llama3.2:3b para Researcher

    • What we know: llama3.1:8b não está instalado; llama3.2:3b está (2GB, já disponível)
    • What's unclear: Se João quer baixar llama3.1:8b (4.7GB a mais) ou aceitar llama3.2:3b como substituto para o Researcher
    • Recommendation: Plano deve incluir ollama pull llama3.1:8b como Wave 0, com fallback para llama3.2:3b se bandwidth for problema
  2. MiroFlow via web_app existente vs FastAPI própria

    • What we know: server/modules/miroflow/web_app/main.py é uma FastAPI completa com session manager e task executor; server/python/bi_analysis_service.py é um FastAPI simples sem estado
    • What's unclear: Usar o web_app completo do MiroFlow (mais funcionalidades) ou escrever miroflow_service.py minimal seguindo o padrão de outros serviços
    • Recommendation: Escrever miroflow_service.py minimal — mais simples, sem session management, sem frontend próprio do MiroFlow
  3. Registro de execuções: graph_nodes vs skill_executions

    • What we know: skill_executions é específico para Skills Arcádia; graph_nodes é KG genérico
    • What's unclear: O requirement diz "KG" — se é necessário usar o Neo4j real ou PostgreSQL graph_nodes é suficiente
    • Recommendation: Usar graph_nodes PostgreSQL com type: "miroflow_execution" — atende o requisito de imutabilidade sem depender do Neo4j (profile opcional)
  4. Posicionamento do MiroFlowControl na UI

    • What we know: BiWorkspace.tsx já tem sistema de tabs (LayoutDashboard, Database, BarChart3...); Scientist.tsx já existe como página standalone de análise científica
    • What's unclear: Se o toggle deve ficar dentro do BiWorkspace (access contextual) ou se deve ser um botão flutuante ou se Scientist.tsx deve ser integrado ao BI
    • Recommendation: Tab "Científico" dentro de BiWorkspace.tsx — mais coerente com o objetivo "integrado ao Superset"

Validation Architecture

workflow.nyquist_validation não encontrado em .planning/config.json (arquivo não existe). Tratado como habilitado.

Test Framework

Property Value
Framework pytest (Python) + vitest/jest implícito (TS)
Config file Nenhum — Wave 0 deve criar pytest.ini para o microserviço
Quick run command pytest server/python/test_miroflow_service.py -x
Full suite command pytest server/python/ -v

Phase Requirements → Test Map

Req ID Behavior Test Type Automated Command File Exists?
REQ-3.1 MiroFlow configurado para Ollama local ≤14B integration pytest tests/test_miroflow_ollama.py -x Wave 0
REQ-3.2 Agente Statistician analisa SQL com deepseek-r1:14b integration pytest tests/test_miroflow_service.py::test_statistician -x Wave 0
REQ-3.3 Agente Fiscal Auditor valida NFe/SPED com deepseek-r1:14b integration pytest tests/test_miroflow_service.py::test_fiscal_auditor -x Wave 0
REQ-3.4 Agente Researcher consulta KG com llama3.1:8b integration pytest tests/test_miroflow_service.py::test_researcher -x Wave 0
REQ-3.5 POST /api/miroflow/analyze retorna análise estruturada integration curl -X POST localhost:5000/api/miroflow/analyze ... Wave 0
REQ-3.6 MiroFlowControl.tsx toggle aparece no Superset/BiWorkspace manual Inspeção visual no browser N/A
REQ-3.7 Execuções registradas com imutabilidade no KG unit pytest tests/test_miroflow_kg.py -x Wave 0

Sampling Rate

  • Per task commit: pytest server/python/test_miroflow_service.py -x
  • Per wave merge: pytest server/python/ -v
  • Phase gate: Health check /api/miroflow/health retorna {"online": true} + todos os 3 agentes respondem com modelo correto

Wave 0 Gaps

  • server/python/test_miroflow_service.py — cobre REQ-3.1, 3.2, 3.3, 3.4, 3.5, 3.7
  • server/python/miroflow_service.py — o microserviço principal
  • server/miroflow/routes.ts + engine-proxy.ts — rotas Express
  • client/src/components/MiroFlowControl.tsx — componente React
  • ollama pull llama3.1:8b — modelo necessário para Researcher (Wave 0 setup)
  • Instalar dependências MiroFlow: pip install omegaconf hydra-core openai (ou uv sync no diretório do submodule)

Sources

Primary (HIGH confidence)

  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/pyproject.toml — versão 1.7.0, dependências confirmadas
  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/miroflow/llm/openai_client.pyUnifiedOpenAIClient, base_url configurável
  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/miroflow/agents/base.pyBaseAgent, AgentContext, build_agent()
  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/config/llm/base.yaml — campos obrigatórios do LLM config
  • Inspeção direta: /opt/arcadia_merged/server/bi/engine-proxy.ts — padrão estabelecido de proxy Node → Python
  • Inspeção direta: /opt/arcadia_merged/server/python/bi_analysis_service.py — padrão do microserviço FastAPI
  • Inspeção direta: /opt/arcadia_merged/docker/litellm-config.yamldeepseek-r1:14b já configurado como arcadia-default
  • Inspeção direta: /opt/arcadia_merged/docker-compose.prod.ymlOLLAMA_BASE_URL configurado, serviço ollama com profile [ai]
  • Runtime check: curl http://localhost:11434/api/tags — modelos instalados confirmados
  • Runtime check: curl http://localhost:11434/api/version — Ollama 0.18.2 com /v1 support

Secondary (MEDIUM confidence)

  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/miroflow/agents/iterative_agent_with_rollback.py — tipo IterativeAgentWithToolAndRollback confirmado
  • Inspeção direta: /opt/arcadia_merged/server/modules/miroflow/web_app/main.py — FastAPI web_app existente no submodule (alternativa não usada)
  • Inspeção direta: /opt/arcadia_merged/server/graph/service.tscreateNode(), graph_nodes tabela

Tertiary (LOW confidence)

  • Inferência sobre tempo de resposta do deepseek-r1:14b (60-120s) baseada em conhecimento geral de modelos 14B — não medido diretamente no servidor

Metadata

Confidence breakdown:

  • Standard stack: HIGH — verificado diretamente nos arquivos do submodule e nas dependências instaladas
  • Architecture: HIGH — padrões copiados de código existente funcionando em produção
  • Pitfalls: HIGH (3-5) e MEDIUM (1-2) — baseados em inspeção direta do runtime e código
  • Ambiente: HIGH — testado com curl direto ao Ollama e listagem de modelos

Research date: 2026-03-25 Valid until: 2026-04-25 (30 dias; stack estável, Ollama versão fixada)


RESEARCH COMPLETE