📡 POST /api/proxy/stream — anatomia
{ baseUrl, apiKey, model, messages } → SSE pass-through.
O que é
O endpoint canônico do daemon para usar BYOK (Bring Your Own Key):
POST /api/proxy/stream
Content-Type: application/json
{
"baseUrl": "https://api.anthropic.com",
"apiKey": "sk-ant-...",
"model": "claude-opus-4-7",
"messages": [{"role": "user", "content": "..."}]
}
→ Server-Sent Events (SSE) pass-through
Por que aprender
Esse endpoint é o que permite trocar de motor sem mudar UI. UI fala 1 protocolo (com daemon); daemon traduz pra 11+ providers diferentes. Saber a anatomia = saber adicionar provider novo, debugar request, e configurar headers customizados.
Conceitos-chave
- SSE pass-through: daemon não bufferiza; streaming token-by-token
- baseUrl override: qualquer endpoint OpenAI-compatible
- Headers customizáveis: Auth, x-api-key, anthropic-version
- Request transformation: Anthropic ≠ OpenAI ≠ Ollama (daemon adapta)
🛡️ Por que SSRF guard
Bloqueio de loopback / link-local / RFC1918.
O que é
Server-Side Request Forgery (SSRF) — atacante manda baseUrl: http://127.0.0.1:6379 e o daemon faz request pro Redis local. Bloqueio mecânico:
- 127.0.0.0/8 (loopback) — bloqueado por default
- 169.254.0.0/16 (link-local AWS metadata) — bloqueado
- 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC1918) — bloqueado
- Exception:
localhost:11434(Ollama) — explicitamente permitido
Por que aprender
SSRF é um vetor real: daemon tem privilégio de rede no host. Se UI puder controlar baseUrl sem guarda, qualquer site malicioso pode varrer rede interna. Guard mecânico = único modo de proteger.
Conceitos-chave
- Allowlist Ollama: exception explícita para localhost:11434
- DNS rebinding: resolve, valida IP, então connect
- Override: usuário pode whitelist endpoints custom em config
- Zero by default: qualquer não-explícito é bloqueado
🤝 Compatibilidade OpenAI — o padrão de fato
/v1/chat/completions.
O que é
Quase todos providers (exceto Anthropic) implementam o formato OpenAI: POST /v1/chat/completions com { model, messages, stream, tools }. Daemon usa esse formato como "lingua franca". Trocar provider = trocar baseUrl. Mesmos messages funcionam.
Por que aprender
Saber que OpenAI é o padrão = não se preocupar com format de cada provider. Adicionar provider novo = adicionar 1 entrada em KNOWN_PROVIDERS, sem código. Padronização = manutenção zero.
Conceitos-chave
- /v1/chat/completions: endpoint padrão
- SSE event format:
data: { ... }linha por linha - Anthropic exception:
/v1/messages, formato próprio - Adapter no daemon: traduz Anthropic ↔ OpenAI quando necessário
📋 KNOWN_PROVIDERS — preset table
MiMo, DeepSeek, Groq, OpenRouter.
O que é
Em apps/web/src/state/config.ts, uma tabela com presets:
export const KNOWN_PROVIDERS = {
anthropic: { baseUrl: 'https://api.anthropic.com', headers: {...}, models: [...] },
openai: { baseUrl: 'https://api.openai.com/v1' },
groq: { baseUrl: 'https://api.groq.com/openai/v1' },
deepseek: { baseUrl: 'https://api.deepseek.com' },
mimo: { baseUrl: 'https://api.xiaomi.com/...', toolChoice: 'none' },
openrouter:{ baseUrl: 'https://openrouter.ai/api/v1' },
ollama: { baseUrl: 'http://localhost:11434/v1' },
}
Por que aprender
Saber a tabela = saber qual provider escolher. Cada um tem trade-off: Groq = velocidade extrema (Llama, Mixtral). OpenRouter = catálogo amplo (qualquer modelo). DeepSeek = barato, modelo decente. Ollama = local, free, lento.
Conceitos-chave
- Preset table: baseUrl + headers + lista de modelos
- Add new: nova entrada em KNOWN_PROVIDERS, deploy
- Custom override: user pode usar baseUrl arbitrário
- Per-provider quirks: MiMo precisa
tool_choice: 'none'
💻 Ollama local — qual modelo escolher
qwen2.5-coder:32b > generalistas para HTML.
O que é
Ollama roda modelos locais via http://localhost:11434/v1. Para geração HTML/CSS/JS, modelos generalistas (llama3, mistral) são piores que coding-specialized (qwen2.5-coder, deepseek-coder, codestral). Recomendação: qwen2.5-coder:32b em GPU de 24GB+; qwen2.5-coder:7b em laptop sem GPU.
Por que aprender
"Vou rodar local" sem saber qual modelo = decepção. Llama 3 70B tem fama, mas em HTML é pior que qwen 7B. Coding-specialized vence generalist em 95% das tarefas de design HTML.
Conceitos-chave
- qwen2.5-coder:32b: sweet spot qualidade-velocidade (RTX 4090)
- qwen2.5-coder:7b: laptop CPU/MBP (M1/M2/M3)
- deepseek-coder-v2: alternativa
- codestral: Mistral coding, bom em raciocínio CSS
- Evitar: llama3, mistral, gemma para HTML — generalistas
⚙️ tool_choice: 'none' para MiMo
Por que (schema malcomportado em geração free-form).
O que é
MiMo (Xiaomi) implementa OpenAI-compatible, mas tem comportamento errático com tools: às vezes retorna tool_call vazio, às vezes ignora schema. Solução: forçar tool_choice: 'none' nesse provider — modelo gera só texto livre, OD parseia <artifact> do output, sem tools.
Por que aprender
É um padrão de adaptação para providers "quase compatíveis". Em vez de evitar MiMo, OD acomoda quirk. Mesmo padrão se aplica a outros providers de baixo custo que tenham bug em tool calling.
Conceitos-chave
- tool_choice: 'none': força modelo a gerar texto, sem tool
- Per-provider quirks: declarados em KNOWN_PROVIDERS
- Trade-off: sem tool = sem TodoWrite explícito (texto narra)
- Aplicável a: Qwen-API, alguns OpenRouter providers
🤔 Quando usar BYOK proxy vs CLI agent
Trade-off de skills do Claude Code.
O que é
2 caminhos pra falar com modelo:
Use: Claude Code, Codex local — você ganha skills nativas, TodoWrite real, file tools
Use: qualquer outro provider — você perde tools nativas, ganha modelo livre
Regra: CLI quando disponível; proxy quando não.
Por que aprender
CLI tem features que API não tem (TodoWrite live, file system tools, MCP servers). Para fluxos avançados, CLI é estritamente superior. BYOK proxy é o fallback. Saber escolher = não perder potência.
Conceitos-chave
- CLI vantagens: TodoWrite, file tools, MCP, skills nativas
- CLI desvantagens: só funciona com modelo da CLI
- BYOK vantagens: qualquer modelo (Ollama free, GPT-5, etc.)
- BYOK desvantagens: sem TodoWrite, sem skills nativas
- Hybrid: CLI default + BYOK fallback de provider
🛠️ Hands-on
Brief: Trocar de Claude Code para Ollama local na mesma sessão; comparar qualidade de output do mesmo brief.
- Instale Ollama:
brew install ollama(Mac) oucurl -fsSL https://ollama.com/install.sh | sh - Puxe modelo:
ollama pull qwen2.5-coder:7b(~4 GB) - Inicie Ollama:
ollama serve(porta 11434) - Configure OD: Settings → Provider → Ollama → escolha qwen2.5-coder:7b
- Mesmo brief: "Faça uma landing minimal pra um app de produtividade". Rode em Claude Code e em Ollama.
- Compare: qualidade visual, tempo de resposta, fluência da auto-crítica.
Comando de verificação
curl http://localhost:11434/api/tags | jq curl -s http://localhost:7331/api/proxy/health | jq # Dentro do OD: Settings → Active Provider → switch
📚 Fontes
No repositório
apps/daemon/src/server.ts(/api/proxy/stream)apps/web/src/state/config.ts(KNOWN_PROVIDERS)apps/daemon/src/agents.tsapps/web/src/components/SettingsDialog.tsx
Externas
- OpenAI Chat Completions API spec
- ollama.com/library — catálogo modelos
- OWASP SSRF mitigation guide
- github.com/farion1231/cc-switch — alternative provider switcher
📌 Resumo do Módulo
1. POST /api/proxy/stream com {baseUrl, apiKey, model, messages} → SSE pass-through.
2. SSRF guard bloqueia loopback/link-local/RFC1918 — Ollama é exceção whitelisted.
3. OpenAI /v1/chat/completions é o padrão de fato; Anthropic é exceção.
4. KNOWN_PROVIDERS table com presets para Anthropic, OpenAI, Groq, DeepSeek, MiMo, OpenRouter, Ollama.
5. Ollama: qwen2.5-coder > generalistas para HTML; 32b em GPU, 7b em laptop.
6. tool_choice: 'none' para MiMo (schema malcomportado).
7. CLI quando disponível (skills nativas); BYOK proxy quando não.
Próximo módulo:
Módulo 3.2 · ACP & adapters →