Fix provider routing and Telegram memory#109
Open
sistemabritto wants to merge 113 commits into
Open
Conversation
…volution-foundation#52) Vault audit §2.S1 CRITICAL: /api/shares/<token>/view had zero rate limiting. Add flask-limiter (in-memory, single-process MVP) with: - 60 req/min/IP on view_share (Vault §2.S1) - Global default 600 req/min on all other routes (non-blocking baseline) - Referrer-Policy, Cache-Control no-store, Pragma, HSTS, X-Content-Type-Options headers on every public share response (Vault §2.S2) The Limiter singleton lives in rate_limit.py to break the circular-import chain between app.py (which imports route blueprints) and the blueprints that need @limiter.limit() decorators. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ortals (evolution-foundation#53) * feat(security): rate-limit public share endpoint + security headers Vault audit §2.S1 CRITICAL: /api/shares/<token>/view had zero rate limiting. Add flask-limiter (in-memory, single-process MVP) with: - 60 req/min/IP on view_share (Vault §2.S1) - Global default 600 req/min on all other routes (non-blocking baseline) - Referrer-Policy, Cache-Control no-store, Pragma, HSTS, X-Content-Type-Options headers on every public share response (Vault §2.S2) The Limiter singleton lives in rate_limit.py to break the circular-import chain between app.py (which imports route blueprints) and the blueprints that need @limiter.limit() decorators. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(plugins): B2.0 public_pages capability — read-only token-bound portals Add the public_pages plugin capability (B2.0 scope, read-only): plugin_schema.py: - Add Capability.public_pages and Capability.safe_uninstall enum values - Add PluginPublicPageTokenSource + PluginPublicPage Pydantic models (bundle must be under ui/public/, revoked_when disallowed in v1 to prevent SQL injection) - Extend ReadonlyQuery with public_via + bind_token_param fields - Add 4 PluginManifest model validators: capability required, table slug-prefix, unique ids/route_prefixes, readonly_data references valid page routes/plugin_public_pages.py (new): - GET /p/<slug>/<route_prefix>/<token> — serve portal bundle (60 req/min/IP) - GET /p/<slug>/<route_prefix>/<token>/data — serve token-bound readonly query (120/min) - GET /p/<slug>/public-assets/<path> — serve ui/public/ static assets - Token validation via parametric SQL (identifiers validated at install by schema) - Module-level _PLUGIN_PUBLIC_PREFIXES cache for install/uninstall lifecycle - Vault §B2.S2: Referrer-Policy, Cache-Control no-store, HSTS, X-Content-Type-Options on all responses - CSP: default-src 'self' on portal bundles - Rate limiting via rate_limit.limiter (imported from PR evolution-foundation#52) app.py: - Import and register plugin_public_pages_bp - /p/... paths already bypass auth_middleware (non-/api/ paths are passthrough) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…vation, sandboxed hook (evolution-foundation#54) - plugin_schema.py: PluginSafeUninstall, PluginPreUninstallHook, PluginUserConfirmation models + validators (block_uninstall enforcement, preserved_tables slug-prefix check, safe_uninstall_enabled_requires_confirmation, no _orphan_* refs in readonly SQL) - routes/plugins.py: uninstall gate (admin-only, confirmation_phrase, exported_at check, zip_password); sandboxed pre-hook subprocess (no secrets, read-only DB copy, 600s timeout); cascade-DELETE filtering for preserved_host_entities; orphan table rename (_orphan_{slug}_{table}); EVONEXUS_ALLOW_FORCE_UNINSTALL=1 escape hatch with audit; reinstall SHA256 check against plugin_orphans before orphan recovery - app.py: plugin_orphans table migration (id, slug, tablename, orphaned_at, orphaned_by_user_id, original_plugin_version, original_sha256, original_publisher_url, recovered_at, UNIQUE(slug, tablename)) - PluginUninstall.tsx: 3-step wizard (regulatory reason+checkbox → ZIP password → typed phrase); force-uninstall orange banner; integrated in PluginDetail.tsx - docs/plugin-contract.md: full plugin.yaml contract for public_pages + safe_uninstall Vault §B3 mitigations: S1 block_uninstall gate, S2 admin enforcement, S3 sandboxed hook, S4 no _orphan_* SQL refs, S5 AES-256 ZIP password, S6 force-uninstall audit trail. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…er auto-injection (evolution-foundation#55) Two related Wave 2.1.x extensions to the plugin contract that close the last two gaps blocking endpoint-level RBAC for plugin authors (gap inventory in evonexus-plugin-nutri Step 3 RBAC decision). Changes - PluginWritableResource.requires_role: Optional[List[str]] — when set, the POST/PUT/DELETE handler returns 403 if current_user.role is not in the list. 'admin' role always passes (super-user override). Backwards compatible: resources without the field accept any authenticated user (legacy default). Validator enforces kebab-case role names (^[a-z][a-z0-9-]*$). - routes.plugins.writable_data: enforces requires_role at the endpoint, with a 403 message naming the required roles and the actor's current role. - routes.plugins.readonly_data: auto-injects :current_user_id and :current_user_role as bind params on every readonly query. Plugins can reference them directly in SQL for server-enforced scoping without an app-layer wrapper. The two parameter names are reserved — client requests carrying them in the query string get 400 (no identity spoofing). Tests - tests/backend/test_plugins_rbac_and_scoping.py — 13 cases covering Pydantic acceptance/rejection, 403/200 paths for writable, scoping/spoofing for readonly, backwards compat for resources without requires_role and queries without :current_user_id refs. Compat - Existing plugins (PM Essentials) continue to work unchanged — the new field defaults to None and the auto-injected bind params are silently ignored if the SQL doesn't reference them. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ser, raw bundle for clients (evolution-foundation#56) The portal_page handler at /p/{slug}/{route_prefix}/{token} previously served the plugin's JS bundle with mimetype application/javascript regardless of the caller. Browsers navigating to a portal URL saw the JS source instead of a rendered page. Discovered during evonexus-plugin-nutri Step 5. Changes - portal_page: when the Accept header includes text/html and NOT application/javascript, render a minimal HTML shell that loads the bundle as <script type="module" src="/p/{slug}/public-assets/{file}"> and instantiates the plugin's declared custom_element_name. Token reaches the element via data-token attribute (no need for the bundle to re-parse window.location). - _serve_html_shell: new helper. Defensive: validates bundle path is inside ui/public/ and custom_element_name matches alphanum-dash before emitting. Sets X-Content-Type-Options: nosniff + a tight CSP (default-src 'self', frame-ancestors 'none', no external scripts). - Programmatic clients (curl, fetch with Accept: application/javascript) keep getting the raw bundle — backwards compatible. - Bundle is fetched from the existing /p/{slug}/public-assets/{path} route (no token), which is safe because the bundle contains no patient data — data lives behind the token-gated /data endpoint. Tests - tests/backend/test_plugin_public_pages_html_shell.py — 9 cases: HTML accept renders shell, JS accept returns bundle, default Accept (*/*) returns bundle, invalid token returns 404 even with HTML accept, CSP + X-Content-Type-Options present, custom element name appears exactly once, XSS-safe (single <script> tag, token only inside data-token), legacy programmatic fetches unchanged. Compat - Existing public-page consumers using fetch() with Accept: application/json or default see no behaviour change. Plugins that already shipped a bundle start rendering correctly in browsers without any plugin update. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…volution-foundation#57) Bumps version to 0.33.0 so the plugin nutri (which requires this version) can install. Bundles the five plugin-contract PRs (evolution-foundation#52→evolution-foundation#56) merged today into a single release. Plus a UX fix on the install wizard so 409s say why they conflicted. The fix - lib/api.ts buildError now falls back to data.conflicts[0] when the standard error/message fields are absent. The plugin preview endpoint returns {conflicts: string[], manifest, ...} on 409 — without this fix the wizard showed only "409 CONFLICT" with the actual reason hidden. - PluginInstallModal: conflicts type was Record<string, unknown>, backend always returned string[]; the JSON.keys() coercion produced index strings. Now typed as string[] and rendered as a list. Tested - Frontend tsc --noEmit clean - Plugin nutri 200 pytest still pass after the 11 `# nosec B603` markers added to subprocess.run calls (false positives from regex security scan — all calls use list args, no shell=True) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… mode Non-Anthropic providers in the agent chat previously bypassed openclaude entirely — a raw /chat/completions fetch with no tool calling, no session history, and a hard API-key requirement that broke Codex OAuth. The terminal was separately blocked by the isCodeModel() name heuristic for agentic models like openrouter/owl-alpha. - chat-bridge: external providers in code mode now go through the Agent SDK with pathToClaudeCodeExecutable pointing at the openclaude binary and a clean whitelisted env (mirrors ClaudeBridge). Restores tool calling, structured streaming, UI tool approval, and session resume. Chat-only models keep the REST path; missing binary falls back with a clear log. - chat-bridge: external providers get full system-prompt replacement for agent personas (append is too weak for GPT models), matching the terminal behavior. - provider-config: new per-provider `mode: code|chat` field overrides the model-name heuristic; the terminal no longer refuses agentic models whose names don't match the code regex. - providers.example.json: mode field on openrouter/omnirouter + new NVIDIA NIM provider entry (OpenAI-compatible endpoint). - tests: provider-config mode override coverage (node --test). Verified end-to-end against OpenRouter: text streaming and Read tool call complete with all UI events (tool_use_start, tool_input_delta, block_stop, result). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OpenClaude >=0.18 detects integrate.api.nvidia.com and demands the key
in NVIDIA_API_KEY, exiting 1 when only OPENAI_API_KEY is set ("Claude
Code process exited with code 1" in the chat). Derive NVIDIA_API_KEY
from OPENAI_API_KEY in loadProviderConfig so the UI keeps a single key
field, and allowlist the var in both config layers.
Verified: chat session via Agent SDK + openclaude against NVIDIA NIM
(stepfun-ai/step-3.7-flash) completes with result: success.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extends the NVIDIA provider beyond chat/code into image generation, and fixes three bugs found while dogfooding the multi-provider flow: - ai-image-creator: NVIDIA NIM provider with FLUX models — flux.2-klein-4b (default, best composition, ~2.5s), flux.1-dev (30 steps), flux.1-schnell. Aspect-ratio mapping constrained to the dimension set and 1.06MP pixel budget the API validates; per-model cfg_scale/steps defaults (schnell requires cfg=0, klein requires cfg>=1); JPEG output auto-converted to PNG via ImageMagick with ffmpeg fallback (temp files beside the output — snap-confined ffmpeg cannot read /tmp). Uses NVIDIA_API_KEY from .env. - backend/providers: saving provider config with a blank key field no longer wipes the stored secret — the UI submits empty password inputs when editing other fields (e.g. model), silently erasing the API key and breaking every session afterwards with auth errors. - claude-bridge: terminal agent personas now resolve from WORKSPACE_ROOT with cwd fallback, matching chat-bridge (cab8966) — sessions started outside the workspace root were silently falling back to a generic "You are the X agent" persona. - Makefile: `make telegram` fails loudly when screen/bun are missing instead of printing a false success message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…le providers Enforce a minimum interval between chat completion requests and retry 429/503 responses with exponential backoff, honoring Retry-After. Configurable via CHAT_MIN_INTERVAL_MS, CHAT_MAX_RETRIES, CHAT_BASE_DELAY_MS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
onclose only cleared the keepalive and never reconnected — a dropped socket left the terminal/chat dead until the component remounted (switching tabs). Now both components reconnect with capped exponential backoff and rejoin immediately on visibilitychange, replaying the session buffer on a cleared terminal to avoid duplicate output. If the process died while disconnected, surface it instead of silently restarting the agent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r fallback - Pin the CLI conversation to the terminal-server session UUID: first start uses --session-id, restarts use --resume when a persisted conversation file exists — provider crashes and server restarts no longer lose the conversation. - Per-agent model tiers: agents declare model: opus|sonnet|haiku in frontmatter; providers.json maps each tier to a provider model via the new model_tiers field. - Pass --fallback-model from the new fallback_models chain (first entry distinct from the primary). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… totals Older skill versions logged image cost entries without token_usage.total_tokens — the unguarded access in the Image Generation table threw a TypeError and unmounted the whole page. Normalize the image-costs payload defensively, same pattern as normalizeCostData. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eator New 'openai' provider hitting api.openai.com/v1/images/generations directly, with the 'image2' model keyword (auto-detects provider). Requires a platform API key (AI_IMG_CREATOR_OPENAI_KEY or OPENAI_API_KEY) — ChatGPT Plus/Codex OAuth tokens lack the api.model.images.request scope (verified: 401), so they cannot be used for image generation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ude 0.18 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e cost estimate Images API bills text input and image output at different per-token rates — use the prompt/completion split when available instead of total_tokens at the input rate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…reds-bearing test script Top-level business folders (finance/, meetings/, social/, etc.) sit outside the workspace/** rule and were trackable — never commit private operational data, especially in a public PR. Also ignore local backups and scripts/ghost_integration_test.py (has hardcoded Ghost API keys). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dation - Heartbeats can now run an in-process Python handler instead of spawning a Claude agent: new 'handler' field (max_turns=0), DB migration, schema validation, dispatcher sync, runner execution path. - provider_fallback.py: 429/quota detection + model/provider rotation with cooldown tracking (foundation; not yet wired into the runner). Tests: tests/heartbeats 25/26 pass (the 1 failure is a data-driven seed assertion against the gitignored local heartbeats.yaml, not a regression). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
step7 now routes through provider_fallback.invoke_with_fallback so a 429/quota error rotates model→provider (NVIDIA chain → Codex → native claude) instead of failing the run. Disable with HEARTBEAT_PROVIDER_FALLBACK=0; unavailable engine falls back to the native claude path (preserved as _step7_invoke_claude_native). Also in provider_fallback.py: - fix NameError on 429 (DEFAULT_COOLDOWN → DEFAULT_COOLDOWN_SECONDS) - align default NVIDIA model chain with validated models; drop OpenRouter (stealth models 404 intermittently) - derive NVIDIA_API_KEY for NVIDIA base URLs (openclaude ≥0.18 needs it) - parse token usage + cost from the CLI JSON envelope so heartbeat runs land real numbers on /costs instead of nulls Tested: invoke_with_fallback + step7_invoke_claude run end-to-end via NVIDIA glm-5.1; tests/heartbeats 25/26 (the 1 failure is the pre-existing data-driven seed assertion on the gitignored local heartbeats.yaml). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bot ran on native claude (Anthropic) and got stuck on an Anthropic usage-limit prompt — it stopped responding because the bun MCP polling loop was blocked behind it. Route the channel agent to Codex via CLAUDE_CODE_USE_OPENAI=1 + OPENAI_MODEL=codexplan (native claude keeps --channels support; openclaude does not expose that flag). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @sistemabritto, your pull request is larger than the review limit of 150000 diff characters
0bc34bf to
4e97443
Compare
openclaude v0.22 (e Claude Code) recusam --dangerously-skip-permissions como root a menos que IS_SANDBOX=1 esteja no env do processo. A flag --allow-dangerously-skip-permissions do commit anterior não lifta esse check — ela só habilita o modo bypass como opção. O entrypoint.sh já exporta IS_SANDBOX=1, mas o whitelist de env limpo dos bridges descartava a variável, então o CLI nascia sem o marcador de sandbox e abortava com exit 1. - claude-bridge: sempre passa --dangerously-skip-permissions em trust mode e injeta IS_SANDBOX=1 quando root (claude e openclaude) - claude-bridge/chat-bridge: IS_SANDBOX adicionado aos whitelists - auto-accept do PTY cobre o diálogo "2. Yes, I accept" do primeiro uso do modo bypass Verificado com fakeroot + openclaude@0.22.0: sem IS_SANDBOX reproduz o erro; com IS_SANDBOX=1 o check passa e o CLI segue até a API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mais sem login claude.ai O caminho LiteLLM-proxy (Anthropic → NVIDIA) nunca passou na verificação server-side de channels da Anthropic — o claude printava "Channels are not currently available" e o bot ficava desconectado das mensagens. Novo comportamento do telegram_swarm_entry.sh (TELEGRAM_MODE=auto): - login claude.ai no volume → channels direto na Anthropic (como antes) - sem login → telegram_provider_bot.py no provider ativo (NVIDIA etc.), o mesmo runtime do make telegram local, sem gate de channels - TELEGRAM_MODE=channels|provider força um modo específico - espera TELEGRAM_BOT_TOKEN em vez de NVIDIA_API_KEY Smoke test na imagem sha-248a7b2 com o script montado: modo provider selecionado, channel config seedado, bot sobe e chama getMe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dois terminais abertos ao mesmo tempo para o mesmo agente caíam no mesmo PTY via find-or-create — cada tecla/comando ecoava e duplicava nos dois (ex.: /goal enviado duas vezes). Agora sessões com conexão WS ativa são puladas na reutilização e o segundo terminal ganha sessão própria. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Login claude.ai antigo no volume de auth fazia o modo auto escolher channels — e o canal voltava a morrer se o login/entitlement estiver inválido. O openclaude não resolve: o gate de channels (feature flag server-side + OAuth claude.ai) existe nele também, independente do provider. Provider mode usa o telegram_provider_bot.py, que já suporta NVIDIA/OmniRouter/OpenRouter (chat completions) e codex_auth (codex CLI). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Versão sanitizada da stack VPS para distribuir: domínio e token via variáveis de ambiente do Portainer, zero credenciais no arquivo, alias de rede evonexus-dashboard para o EVONEXUS_API_URL funcionar independente do nome da stack, TELEGRAM_MODE=provider como default e instruções de onboarding no cabeçalho. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gateway de IA (diegosouzapw/OmniRoute, MIT) rodando dentro do Swarm com alias omniroute na network_public. O provider omnirouter do EvoNexus aponta para http://omniroute:20128/v1 (model=auto para fallback entre 237 providers) em vez de depender de gateway externo — elimina o 503 sem fallback visto no bot do Telegram. Dashboard interno por padrão, com labels Traefik+basic-auth comentadas e aviso de segurança. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Serviço omniroute com alias interno (omniroute:20128) para o provider omnirouter do EvoNexus, dashboard exposto via Traefik com basic-auth, segredos movidos para variáveis de ambiente da stack no Portainer (DASHBOARD_API_TOKEN, OMNIROUTE_BASICAUTH), alias evonexus-dashboard para o EVONEXUS_API_URL não depender do nome da stack, e TELEGRAM_MODE=provider persistido. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Basic-auth na frente do dashboard entra em loop de 401: as chamadas internas (SSE/WS/API) enviam Authorization próprio que atropela o Basic. O OmniRoute tem auth nativa para reverse proxy: INITIAL_PASSWORD (login), JWT_SECRET (sessão em cookie), AUTH_COOKIE_SECURE atrás de HTTPS, OMNIROUTE_TRUST_PROXY para X-Forwarded-*, e STORAGE_ENCRYPTION_KEY cifrando o SQLite com as keys dos providers. Segredos via env da stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… VPS Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… recebe mais a chave NVIDIA O bot do Telegram e o FallbackEngine resolviam a API key priorizando NVIDIA_API_KEY/OPENAI_API_KEY do env do processo (carregadas do .env na inicialização) sobre a chave do próprio provider em config/providers.json. Resultado: toda chamada ao omnirouter mandava a chave NVIDIA pro OmniRoute e tomava 401, mesmo com key nova configurada no dashboard. - telegram_provider_bot: env_vars do provider primeiro; NVIDIA_API_KEY do env só para endpoints *.nvidia.com; invoke_cli não vaza [REDACTED] pro CLI - provider_fallback._get_api_key: mesma precedência (heartbeats/rotinas) - claude-bridge/chat-bridge/invoke_cli: DISABLE_AUTOUPDATER=1 — o openclaude se auto-migrava pro instalador nativo no meio da sessão e morria com exit 1 - .env.example: documenta a ordem de resolução de chaves, onde gerar cada key (OpenRouter/OpenAI/Gemini/NVIDIA NIM/OmniRoute) e o gotcha de keys do OmniRoute morrerem com o volume Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refeito com foco no que este fork adiciona: OmniRoute embutido na stack Swarm, seletor de providers, bot do Telegram multi-provider, pipeline de deploy VPS (GH Actions → Docker Hub próprio → Portainer/Traefik) e hardening de produção. Guia passo a passo completo de deploy na VPS com troubleshooting. Créditos devidos: Evolution Foundation (EvoNexus, base integral), Diego Souza (OmniRoute), Yeachan Heo (oh-my-claudecode, herdado do upstream) e OpenClaude. Licença original preservada (Apache 2.0 + condições de marca), com a camada Sistema Britto declarada como distribuição derivada e backlinks para sistemabritto.com.br. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gram multi-provider, deploy VPS Promove a branch feat/chat-openclaude-provider-routing (92 commits) à main do fork. A main passa a ser a branch canônica da distribuição Omni-Nexus. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…base O docker-image.yml (builds da main) apontava a imagem evo-nexus-runtime pro ./Dockerfile — imagem base sem claude/openclaude/entrypoints do Swarm. A stack da VPS espera o Dockerfile.swarm, o mesmo que o workflow da branch de feature já usa. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
O OmniRoute streama SSE por padrão quando o payload não traz "stream" — o bot fazia json.loads do corpo inteiro e explodia com "Expecting value: line 1 column 1 (char 0)". Agora pede stream=false explicitamente e, se o gateway ignorar e streamar mesmo assim, agrega os deltas dos chunks SSE. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PROMPT-OMNIROUTE-CONFIG.md — prompt copy-paste para Claude Code (ou agente similar) auditar e otimizar um OmniRoute remoto via management API + CLI em modo remoto: validação de access token, keys nomeadas (inferência + manage), autoRefreshProviderQuota, compressão com auto-trigger, re-teste de conexões para destravar modelos :free e validação fim-a-fim com headers de telemetria. Extraído da configuração real aplicada na VPS em 07/07/2026. Linkado no README na seção do OmniRoute. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-learning Agentes perdiam contexto após /clear — três mudanças fecham o ciclo: - Dockerfile.swarm.dashboard: mempalace pré-instalado na imagem (o install via botão caía na layer do container e sumia a cada redeploy; os dados chroma/sources já persistem no volume dashboard/data) - routes/mempalace.py: primeiro uso seeda fontes padrão — memory/, .claude/agent-memory/ e workspace/development/ — pra busca semântica cobrir as memórias do workspace e dos agentes sem setup manual - .claude/rules/memory-recall.md (auto-carregada): protocolo de recall no início da sessão (agent-memory → MemPalace search → inbox de tickets) e self-learning no final (learnings.md por agente, fatos em memory/, trabalho inacabado vira ticket, re-mine do índice) Testes atualizados pro comportamento de seed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… no check de PID O worker publica phase="done" e sai, mas o Flask nunca dá wait() no child — ele vira zumbi e os.kill(pid, 0) segue passando, então a UI ficava presa em "Mining in progress" até reiniciar o dashboard. Agora o status respeita a fase terminal (done/error): limpa o arquivo e faz reap best-effort do zumbi. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…moria 1024M→1536M - Adiciona fetch_mempalace_context() que busca no MemPalace via EVONEXUS_API_URL + DASHBOARD_API_TOKEN (env do container docker) - Injeta resultados no prompt como 'Contexto do MemPalace' entre a memoria recente e a mensagem atual, com fallback silencioso - Aumenta limite de memoria do telegram service: 1024M → 1536M
… vars do terminal
- evonexus-vps.stack.example.yml: telegram memory 1024M→1536M (RAG MemPalace)
- .env.example: adiciona EVONEXUS_DASHBOARD_CPUS, EVONEXUS_DASHBOARD_MEMORY,
TERMINAL_MAX_ACTIVE_SESSIONS, TERMINAL_DETACHED_TTL_MINUTES
- evonexus-vps.stack.yml: quoting consistente ("1536M", "1024M") alinhado
à stack de produção
- workspace_context() agora informa EVONEXUS_API_URL + DASHBOARD_API_TOKEN com lista de endpoints: /api/goals, /api/missions, /api/projects, /api/tickets, /api/mempalace/search - Instrucao no system prompt: NUNCA dizer 'nao tenho acesso' sem antes tentar uma chamada HTTP real — o exemplo mostra como fazer GET com urlopen + Request + Bearer token
… nvidia para omnirouter - Adiciona provider 'omnirouter' apontando para http://omniroute:20128/v1 (gateway local na VPS com 237+ providers e fallback automatico) - Telegram agora usa omnirouter em vez de nvidia — resolve ENOTFOUND porque NVIDIA resolvia de fora (integrate.api.nvidia.com) enquanto omnirouter e DNS interno do Docker (evonexus-dashboard:8080 ja funciona)
…osentado Na VPS o container do dashboard nao resolve hosts externos (mesmo ENOTFOUND do 1efe7c2), entao a chain nvidia->openrouter->anthropic esgotava: nvidia e openrouter falham por DNS e o claude nativo nao tem login apos redeploy (exit code 1 no attempt evolution-foundation#3 do atlas-4h). O omniroute resolve por DNS interno do Swarm e vira o segundo elo; local continua saindo pela nvidia direto. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
O db0c72b instruia o modelo a fazer urlopen na API do Nexus — impossivel: o bot e chat completion puro, sem executor de tools. O modelo respondia 'falta o endpoint de status' porque nao tem como executar HTTP. Segue o padrao ja existente (fetch_url_context/fetch_mempalace_context): o runtime detecta perguntas sobre cron/rotinas/heartbeats, busca /api/heartbeats (com last_run + erro) e /api/routines server-side e injeta o resultado no prompt. A instrucao impossivel do system prompt sai; entra a orientacao de responder com base no bloco injetado. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
O post agora roda no scheduler da VPS, que nao monta o .env da raiz — o post_to_x.py nao achava SOCIAL_TWITTER_* e nada era publicado. Alem disso o X rotaciona o refresh_token a cada refresh, entao env vars estaticas de stack apodrecem apos o primeiro refresh. - tokens sociais agora vivem em config/social.env (volume evonexus_config na VPS; gitignored), override via SOCIAL_ENV_PATH - read_env: social.env vence .env e env vars para chaves SOCIAL_*; reauth manual via social-auth vence pelo TOKEN_CREATED_AT mais novo - refresh grava ACCESS/REFRESH/TOKEN_CREATED_AT no social.env - scripts/seed_social_env.py exporta os tokens do .env local para copiar na VPS apos (re)autenticar Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dois problemas no fluxo /connect/<rede> montado no dashboard: - SESSION_COOKIE_SAMESITE=Strict: o redirect de volta do provedor (twitter.com -> /callback/twitter) e cross-site, o browser nao enviava o cookie de sessao e o state salvo sumia -> 403 "Invalid state — CSRF protection". Lax mantem a defesa contra CSRF mutante (POST/iframe) e permite a navegacao top-level do callback. - Sem ProxyFix, request.host_url atras do Traefik gera redirect_uri http:// — honrar X-Forwarded-Proto/Host (1 hop; porta 8080 nao e exposta direto na VPS). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Autenticar via dashboard na VPS gravava no .env da raiz do container — que nao e volume (some no redeploy) e nao e visivel pro scheduler, entao o post continuava sem credencial mesmo apos reconectar. - set_env roteia SOCIAL_* para config/social.env (volume evonexus_config, compartilhado dashboard+scheduler); demais chaves seguem no .env - read_env mescla os.environ < .env < social.env (client_id pode vir de env var de stack e sobreviver a redeploy) - delete_env limpa ambos os stores; social.env criado com chmod 600 Com isso a reautenticacao pode ser feita direto em https://nexus.workflowapi.com.br/connect/twitter — sem copiar arquivo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tico
O sync gravava local_path como string absoluta no DB. Quando o
dashboard.db migra de maquina (backup/restore local <-> VPS) o path
aponta pro filesystem antigo e o sync falhava com 500 "missing or
corrupt — re-connect" mesmo com credencial e URL validas no config.
- resolve_local_path(): tenta o path gravado e re-deriva o canonico
{workspace}/dashboard/data/brain-repos/{repo_name}; persiste o path
novo no config quando muda
- pipeline de sync re-clona automaticamente no caminho canonico quando
o working tree nao existe em lugar nenhum (token + repo_url ja estao
no config — re-connect manual so quando falta credencial)
- rotas sync/force e tag/milestone deixam o job enfileirar nesse caso
em vez de abortar 500
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
O card do AI Image Creator so expunha CF Gateway/OpenRouter/Google, mas o script ja suporta --provider openai (gpt-image-2 via Images API). - integrationMeta.ts: campos AI_IMG_CREATOR_OPENAI_KEY e AI_IMG_CREATOR_OPENAI_BASE_URL no card - generate-image.py: AI_IMG_CREATOR_OPENAI_BASE_URL reroteia o provider openai por qualquer gateway OpenAI-compativel (ex. OmniRoute http://omniroute:20128/v1) em vez de api.openai.com - SKILL.md: doc da base URL + selecao de provider Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tida Feedback: em vez de um campo generico de base URL preso a OpenAI key, cada gateway tem sua propria entrada com default embutido. - --provider omniroute: normaliza cedo para o flavor openai injetando AI_IMG_CREATOR_OMNIROUTE_KEY + base default http://omniroute:20128/v1 (override via AI_IMG_CREATOR_OMNIROUTE_BASE_URL fora da stack) - card de integracoes: OpenAI API Key e OmniRoute API Key lado a lado, sem campo de URL — mais limpo - e2e testado com gateway fake: POST /v1/images/generations, Bearer da key do omniroute, gpt-image-2 default, PNG decodificado Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sincroniza a documentacao publica com as mudancas recentes: - providers.md: NVIDIA NIM + OmniRoute na tabela, fallback chain dos heartbeats (provider_fallback), telegram_provider por canal - telegram.md: secao Provider Mode (Magneto) — chat completion sem tools, injecao server-side (URLs, MemPalace, status de cron/ heartbeats), /provider, transcricao de audio - ai-image-creator.md: opcoes D (OpenAI gpt-image-2) e E (OmniRoute), tabela de modelos com image2 + nvidia-*, troubleshooting - heartbeats.md: debugging de fallback exhausted (attempt #N, exit 1) - x-twitter.md (novo): token store config/social.env, precedencia, conexao via dashboard, regra de um-lado-so-refresca - brain-repo.md (novo): backup GitHub, portabilidade local<->VPS, re-clone automatico - env-variables.md: social.env + envs novas do AI Image Creator - overview de integracoes: entradas do X/Twitter - llms-full.txt regenerado (make docs-build) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR carries the provider routing work plus the Telegram runtime fixes:\n\n- route Telegram through the active provider / override config\n- add per-chat memory for the direct Telegram bot\n- harden heartbeat invocation for OpenClaude-backed providers\n- keep provider/model answers deterministic from config\n- add coverage for Telegram memory behavior\n\nValidation:\n- python3 -m unittest -q tests.backend.test_telegram_provider_bot\n- python3 -m py_compile scripts/telegram_provider_bot.py tests/backend/test_telegram_provider_bot.py\n- python3 dashboard/backend/heartbeat_runner.py --heartbeat-id zara-2h --triggered-by manual