Skip to content

Claude/setup openrouter gemini e cg p8#10

Open
KirillTrubitsyn wants to merge 59 commits intoeggent-ai:mainfrom
KirillTrubitsyn:claude/setup-openrouter-gemini-ECgP8
Open

Claude/setup openrouter gemini e cg p8#10
KirillTrubitsyn wants to merge 59 commits intoeggent-ai:mainfrom
KirillTrubitsyn:claude/setup-openrouter-gemini-ECgP8

Conversation

@KirillTrubitsyn
Copy link
Copy Markdown

Summary

Describe the problem and the intent of this PR.

What Changed

How to Test

Checklist

  • PR is focused on one topic.
  • I ran npm run lint.
  • I ran npm run build.
  • I updated docs when behavior changed.
  • I linked related issue(s).

KirillTrubitsyn and others added 30 commits February 27, 2026 10:53
Comprehensive proposal document describing the idea of deploying Eggent
on Railway with a multi-user system (roles, permissions, data isolation,
Telegram per-user support, usage statistics).

https://claude.ai/code/session_014UXjuRzQFgRp4Mm83PKqvt
Remove the sudoers rule that granted the node user passwordless root access.
This was convenient for local development but is a security vulnerability
for public deployment.

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
Create src/lib/storage/users-store.ts with:
- User model: id, username, displayName, passwordHash, role (admin/user),
  mustChangePassword, permissions, quotas, telegramUserId
- CRUD operations: getAllUsers, getUserById, getUserByUsername,
  getUserByTelegramId, createUser, updateUser, updateUserPassword, deleteUser
- SafeUser type that strips passwordHash for API responses
- Auto-migration from legacy settings.auth on first access
- Input validation (username format, password length)
- Protection against deleting the last admin
- File storage at data/settings/users.json

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
…t-HPTmw

Claude/setup eggent project hp tmw
- Add userId field to Chat/ChatListItem types for chat ownership
- Add ownerId/isShared fields to Project type for project ownership
- Create getCurrentUser() helper to extract user from session cookie
- Update chat-store to filter by userId (legacy chats without userId visible to all)
- Update project-store to filter by ownerId (shared projects visible to all)
- Update chat/history API to show only user's chats (admins see all)
- Update chat API to set userId on new chats
- Update projects API to set ownerId on new projects
- Add ownership checks on project GET/PUT/DELETE operations

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
- Resolve Telegram userId to app User via getUserByTelegramId()
- Check telegram permission before processing messages
- Pass userId to chats created from Telegram sessions
- Add quota checks (daily messages, monthly tokens) for Telegram users
- Record usage stats after successful agent responses
- Deny access with Russian-language messages when permissions/quotas fail

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
- Create usage-stats-store with per-user daily/monthly tracking
- Track message count and estimated token usage per user per day
- Auto-prune stats older than 90 days to keep storage compact
- Add daily message quota and monthly token quota checking
- Add GET /api/usage-stats endpoint (admins see all, users see own)
- Integrate quota checks into chat API (returns 429 when exceeded)
- Record usage stats fire-and-forget after agent responses

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
…t-HPTmw

Claude/setup eggent project hp tmw
…t-HPTmw

fix: upgrade next.js to 15.5.9 to resolve critical security vulnerabi…
…t-HPTmw

fix: update package-lock.json for next@15.5.9
- Change default provider from OpenAI to OpenRouter for all models
- Add multimediaModel slot (Gemini) alongside chatModel and utilityModel
- Add UtilityModelWizard and MultimediaModelWizard UI components
- Refactor model-wizards.tsx to use generic GenericChatModelWizard
- Update API settings route to mask/restore keys for all model types
- Update AgentConfig type to include multimediaModel
- Update .env.example to prioritize OPENROUTER_API_KEY

Default models:
  - Chat: anthropic/claude-opus-4-6
  - Utility: anthropic/claude-sonnet-4-6
  - Multimedia: google/gemini-2.5-pro-preview-05-06
  - Embeddings: openai/text-embedding-3-small

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
13x cheaper than OpenAI, #1 on MTEB multilingual, 32K context.
Using 1536 dims via MRL for storage/quality balance.

Also add Qwen3 and Gemini embedding models to known dimensions map.

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
Google's latest SOTA reasoning model with multimodal capabilities.
1M context, audio/image/video input support.

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
- chatModel: claude-sonnet-4-6 (everyday conversations, ~5x cheaper)
- utilityModel: claude-opus-4-6 (complex reasoning, coding, 8K output)

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
…for images

- Subordinate agents now use utilityModel (Opus) instead of chatModel
- Image attachments auto-route to multimediaModel (Gemini) with vision
- Added multimodal message building (base64 images via AI SDK ImagePart)
- Chat API, external handler, and Telegram all forward attachments
- Regular text messages continue using chatModel (Sonnet) as before

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
…t-HPTmw

Claude/setup eggent project hp tmw
Previously, only ExternalMessageError exceptions were caught and
reported back to the Telegram user. All other errors (LLM API failures,
missing API keys, timeouts) were silently swallowed, causing the bot to
not respond at all. Now the catch-all block sends the error description
to the user in Telegram so they can diagnose the issue.

https://claude.ai/code/session_01XjFNsYgKjJrENstcSbcoVT
The Telegram bot was not responding because:
1. The webhook was never registered with Telegram API (setWebhook not called)
2. Empty allowedUserIds list blocked all users without any way to self-onboard

Changes:
- Add instrumentation.ts that auto-registers the Telegram webhook on app
  startup when TELEGRAM_BOT_TOKEN, TELEGRAM_WEBHOOK_SECRET, and a base URL
  are available. Also auto-detects base URL from deployment platforms
  (Vercel, Railway, Render, Fly.io) when APP_BASE_URL is not set.
- Auto-allow the first user who messages the bot in a private chat when
  the allowedUserIds list is completely empty (no security boundary exists
  when nobody is configured).

https://claude.ai/code/session_01JuWqDF92mQPfXk7fVH4q3K
Two issues fixed:
1. Simple questions (weather, jokes, etc.) triggered code_execution unnecessarily
   because the system prompt pushed the model to always use tools. Updated prompts
   to instruct the model to respond directly with text for simple questions.

2. The model produced duplicate response bubbles because the `response` tool caused
   an extra agent round-trip — the model would call response tool, get the result
   back, then generate another text message. Fixed by:
   - Removing the response tool entirely (model now responds with text directly)
   - Merging consecutive assistant messages in both storage (onFinish) and
     rendering (chatMessagesToUIMessages) to prevent duplicate bubbles

https://claude.ai/code/session_016D6aN4HLJeTQkNSYRrprsv
APP_BASE_URL on Railway was set as 'kirilleggent-production.up.railway.app'
without the https:// prefix, causing webhook registration to fail because
Telegram requires a full URL. Now both instrumentation.ts and the runtime
config normalize the URL by adding https:// if no protocol is present.

https://claude.ai/code/session_01JuWqDF92mQPfXk7fVH4q3K
…t-HPTmw

fix: send error messages to Telegram user for all failure types
KirillTrubitsyn and others added 29 commits February 28, 2026 07:44
…issing project

When TELEGRAM_DEFAULT_PROJECT_ID is set to a non-existent project (e.g. "default"),
the bot threw 'Project "default" not found' instead of falling back to the first
available project. Now both resolveTelegramProjectContext() and handleExternalMessage()
silently skip invalid project IDs and use the session's active project or first
available project as fallback.

https://claude.ai/code/session_01JuWqDF92mQPfXk7fVH4q3K
…X4J0

fix: gracefully fallback when TELEGRAM_DEFAULT_PROJECT_ID points to m…
Railway mounts volumes as root, but the app runs as user "node".
Added an entrypoint script that:
- When running as root: fixes /app/data ownership then drops to node via gosu
- When running as non-root: ensures required subdirectories exist

This fixes EACCES errors when the app tries to create settings/projects/chats
directories inside the mounted volume.

https://claude.ai/code/session_016D6aN4HLJeTQkNSYRrprsv
…ions

- Add "Efficiency" section to system prompt instructing the agent to
  respond directly via the response tool for simple questions without
  unnecessary intermediate tool calls (code_execution, search, etc.)
- Reduce max tool loop steps: chat 15→6, background 15→6, subordinate 10→5
- Clarify that code_execution should only be used when code actually
  needs to run, and search results should not be "processed" with
  additional tool calls

Fixes the issue where a simple weather question triggered multiple
large chained API requests (visible in OpenRouter logs) instead of
a quick search + response.

https://claude.ai/code/session_01Vgzt756Yc1gpSixKgXsHYp
…logic-H8Osc

Claude/fix chat response logic h8 osc
…ments

Merged main branch changes (direct text response, "When to Use Tools"
section) with our branch changes (Efficiency section, reduced step counts,
"Respond as quickly as possible" rule).

https://claude.ai/code/session_01Vgzt756Yc1gpSixKgXsHYp
…-sFjDv

fix: prevent agent from making excessive API requests on simple quest…
- Add HOSTNAME=0.0.0.0 so Next.js binds to all interfaces (Railway requirement)
- Copy src/prompts/ to runner stage for runtime prompt loading
- Simplify entrypoint.sh: use gosu directly (su-exec was never installed),
  remove 2>/dev/null that was swallowing all application stderr
- Create data subdirectories in both root and non-root entrypoint branches

https://claude.ai/code/session_01W6YtViBYRmAHgvJvMivmwX
…-7CKQw

fix: resolve Railway deploy crash — bind to 0.0.0.0, fix entrypoint
- chown -R only /app/data instead of entire /app + python venv.
  The old chown duplicated node_modules, .next, bundled-skills etc.
  into a separate layer (hundreds of MB). At runtime node user only
  needs write access to /app/data (the volume mount).
- Merge gosu into the main apt-get step (one fewer layer + apt-get update)
- Remove duplicate mkdir -p for data directories

https://claude.ai/code/session_01W6YtViBYRmAHgvJvMivmwX
…-7CKQw

perf: optimize Dockerfile — eliminate massive chown layer
gosu + python3-venv/python3-requests cause apt dependency conflicts
when installed in the same apt-get step on bookworm-slim. Split back
into two steps while keeping the chown optimization (only /app/data).

https://claude.ai/code/session_01W6YtViBYRmAHgvJvMivmwX
…-7CKQw

fix: separate gosu apt-get from python packages to avoid dep conflict
python3-requests from apt causes dependency resolution failures on
node:22-bookworm-slim. Install requests via pip in the venv instead,
which avoids the system package conflicts entirely.

https://claude.ai/code/session_01W6YtViBYRmAHgvJvMivmwX
…-7CKQw

fix: install requests via pip instead of apt to avoid dep conflicts
ENV TMPDIR=/app/data/tmp is set before apt-get install, but the
directory doesn't exist yet. ca-certificates post-install calls mktemp
which uses TMPDIR and fails, cascading to python3-pip/venv failures.

https://claude.ai/code/session_01W6YtViBYRmAHgvJvMivmwX
…-7CKQw

fix: create TMPDIR before apt-get to unblock ca-certificates
The system prompt was bloated with ~15.5KB of tool-*.md files that
duplicate the descriptions already in tool API schemas. A simple
"Hello" message cost 11k prompt tokens.

Changes:
- Remove all 22 tool-*.md prompt injections from system prompt
  (tool descriptions already exist in the API tool schema)
- Replace verbose markdown file table (50 files × 3 columns) with
  compact path-only list (30 files max)
- Condense system.md from 69 lines to 14 lines
- Replace XML skills metadata with simple markdown list
- Remove unused escapeXml() and formatFileSize() functions

Expected savings: ~80% reduction in prompt tokens per request.

https://claude.ai/code/session_016D6aN4HLJeTQkNSYRrprsv
Tool descriptions and parameter .describe() strings were excessively
verbose (e.g. "List all available projects. Use this when the user asks
what projects exist..." → "List all projects.").

Since the model can infer tool usage from short descriptions + parameter
names + types, the long prose was pure token waste — sent with EVERY
API call regardless of user message.

Removed 271 lines of redundant description text across 24 tools.
Combined with the system prompt optimization, a simple "Hello" should
now cost ~3-4k tokens instead of 11k.

https://claude.ai/code/session_016D6aN4HLJeTQkNSYRrprsv
…logic-H8Osc

Claude/fix chat response logic h8 osc
- Add tool priority rule: search_web > code_execution for info requests
- Make skill loading less aggressive: only load skills for multi-step
  workflows, not when a single tool call (e.g. search_web) suffices
- This should reduce weather/news questions from 2 LLM calls to 1

https://claude.ai/code/session_016D6aN4HLJeTQkNSYRrprsv
…logic-H8Osc

fix: reduce unnecessary tool calls for simple questions
…t Google API

Switch from google-genai SDK with GEMINI_API_KEY to httpx-based OpenRouter
API calls with OPENROUTER_API_KEY. Model changed to google/gemini-3.1-pro-preview.
Added --model flag for optional model override.

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
…tion

Update nano-banana-pro skill and default multimediaModel to use the correct
OpenRouter model ID (google/gemini-3.1-flash-image-preview) instead of
google/gemini-3.1-pro-preview.

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
The nano-banana-pro skill requires uv to run the generate_image.py script.
Also pre-install httpx and pillow in the Python venv so dependencies are
available immediately without network fetching at runtime.

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
- modalities: ["image", "text"] (image first per OpenRouter docs)
- Add image_config.image_size for resolution control (instead of text hint)
- Parse response images from message.images[] (OpenRouter format)
- Add fallback to parse images from content[] array
- Support 0.5K resolution (exclusive to gemini-3.1-flash-image-preview)
- Print full response on error for easier debugging

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
- Add /api/media/serve endpoint to serve image files from data/ directory
- Parse MEDIA: tokens from tool output in tool-output.tsx
- Render images inline (visible even when tool output is collapsed)
- Include filename and download link below each image
- Security: only serve image files within the data/ directory

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
- File click opens in new tab (images display inline, others download)
- Add ?inline=1 param to /api/files/download for inline content display
- Serve images with correct MIME type when inline mode is on
- Add FileImage icon for image files in the tree
- Add cursor pointer to indicate files are clickable

https://claude.ai/code/session_01C22Z5nyzY8gYRCSHtsxjPp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants