Commit graph

501 commits

Author SHA1 Message Date
cf63e5c6cd Fix tiktoken mock: use class not instance, remove TESTING check 2026-01-11 09:17:49 -05:00
9fb7047866 Fix tiktoken SSL/gevent conflict in tests: use fallback token counting 2026-01-11 08:42:51 -05:00
4cc7e61c8b Fix GitLab CI for shell executor: use python3 and venv 2026-01-11 08:32:35 -05:00
6a4d9d560b Add GitLab CI pipeline for unit, integration, and functional tests 2026-01-11 07:53:58 -05:00
f5afedc5f7 Fix unturf capitalization to lowercase 2026-01-11 07:14:43 -05:00
ddf071161e Document git remote configuration with dual push targets 2026-01-11 07:14:12 -05:00
0d5d2c27be Switch Unsandbox API auth to HMAC-SHA256 with public/secret keys
Replace simple Bearer token auth with HMAC-SHA256 signature scheme:
- UNSANDBOX_PUBLIC_KEY for account identification (Bearer token)
- UNSANDBOX_SECRET_KEY for request signing (never transmitted)
- X-Timestamp header for replay attack prevention
- X-Signature header with HMAC-SHA256(secret, ts:method:path:body)
2025-12-28 13:44:38 -05:00
331c11e8f7 Only truncate large code blocks on page refresh, not during streaming 2025-12-15 11:31:43 -05:00
5329bccdec Add Open Graph and Twitter Card meta tags for social sharing
- Add helper functions to extract first image and generate description from chat messages
- Update base.html and index.html with og:image, og:description, twitter:card meta tags
- Chat rooms now use first image from messages for unfurling instead of site logo
- Description shows first 500 chars of room content for link previews
- Add default OG image (black with OC) as fallback when no image found
2025-12-15 08:17:01 -05:00
50404f62d9 Fix F824 lint error and add lint instructions to CLAUDE.md 2025-12-07 15:34:35 -05:00
6e279c0ed5 Use backend proxy for Unsandbox API calls to keep API key secure 2025-12-07 14:54:35 -05:00
8c128878c4 Fix is_base64_image() to detect all image formats, add debug logging
- is_base64_image() now detects any base64 image (jpeg, png, gif, webp, etc.)
  not just the hardcoded jpeg/png patterns
- Added [Vision] debug logging to trace image fetch/save flow
2025-12-07 13:58:47 -05:00
56800afae5 Fix SQL LIKE query for URLs with special characters (%, _)
URLs like eBay images contain % and _ which have special meaning in SQL
LIKE patterns. Added escape_like_pattern() helper to escape these chars.
This fixes saved base64 images not being found on refresh.
2025-12-07 13:51:40 -05:00
de5bdaaa68 Vision: send only most recent image, keep all text history
- Find the most recent image message
- Include full text conversation history for context
- Only send base64 for the most recent image
- Skip older images entirely (no useful text in them)
2025-12-07 11:44:56 -05:00
305375d9e6 Limit vision model to 2 most recent images to prevent slow/hanging requests
Multiple large base64 images can overwhelm the vision model. Now we:
1. First pass: identify the 2 most recent image messages
2. Second pass: build chat history, skipping older images
2025-12-07 11:42:53 -05:00
ff9d8011a6 Fix model/voice localStorage persistence on page refresh
Remove race condition where syncDropdownsAndQueryString() was called before
dropdowns were populated, causing empty values to overwrite localStorage.
Model and voice restoration now happens only in populateModelDropdown() and
populateVoiceDropdown() after async fetch completes.
2025-12-07 11:29:06 -05:00
38da58c33e Cache fetched external images to avoid re-fetching
- Add find_saved_base64_for_url() to lookup existing saved base64 in DB
- Check for existing saved version before fetching external images
- Prevent duplicate saves in save_fetched_image_as_message()
- Use in-memory cache for faster repeated lookups within same session
2025-12-07 11:18:01 -05:00
116fac4c90 Fix DetachedInstanceError: use room_name parameter instead of room.name
Replace room.name with room_name in chat_gpt, chat_claude, and chat_llama
functions to avoid accessing SQLAlchemy objects outside session context.
2025-12-07 10:59:13 -05:00
4714c2730a Fix streaming protocol tests for Message.query mocking and gevent conflicts
- Fix Message.query.filter_by() chain mocking in test_bedrock_streaming_protocol
  and test_streaming_protocol_backwards_compatibility
- Add is_gevent_patched() helper to detect monkey patching
- Skip bedrock test at runtime when gevent has already patched (avoids RecursionError)
2025-12-07 10:53:51 -05:00
da9ed50d38 Fix DetachedInstanceError: save room_id early, use room_name parameter 2025-12-07 10:22:57 -05:00
0d19e0b9ce Fix model selection persistence: populate both dropdowns, validate stored value 2025-12-07 10:17:43 -05:00
5928ad3d9d Save fetched external images as new messages in database
- save_fetched_image_as_message() creates a new message with base64 content
- build_message_content() now accepts room_id to persist fetched images
- Fetched images saved with username "system" (added to SYSTEM_USERS)
- Prevents re-fetching: once fetched, base64 version is in chat history
2025-12-07 09:01:01 -05:00
51de5991c4 Add server-side fetching of external images for vision model chat context
- extract_external_image_url() to find http/https URLs in img tags
- fetch_external_image_as_base64() fetches via CORS proxy, converts to base64
- build_message_content() now handles both base64 and external image URLs
- Caches fetched images to avoid re-fetching
- Uses cors-proxy.uncloseai.com for robots.txt compliance
2025-12-07 08:58:18 -05:00
589406d11d Fix CORS proxy URL to cors-proxy.uncloseai.com 2025-12-07 08:49:28 -05:00
19b8ce4037 Add external image URL support via CORS proxy
- Fetch external images through proxy.unturf.com (respects robots.txt)
- Convert fetched images to base64 for vision API
- Cache both fetched images and descriptions
- Shows "Fetching image..." for external URLs, "Generating description..." for base64
- Handles 403 responses when blocked by robots.txt
2025-12-07 08:47:36 -05:00
d9976ffe31 Fix image hover: use mouseover instead of mouseenter for event delegation 2025-12-07 08:39:58 -05:00
bd2dbf7ed5 Add vision model support with auto alt-text on image hover
Backend:
- Track VISION_MODELS list at startup from available endpoints
- Add is_vision_model() to detect vision-capable models (*-vl*, *vision*, gpt-4o)
- Add extract_base64_from_img_tag() and build_message_content() helpers
- Modify chat_gpt() to include base64 images for vision models
- Add GET /vision endpoint for vision availability status
- Add POST /vision/describe endpoint for image alt-text generation

Frontend:
- Check vision availability on page load via /vision
- Add hover event delegation on chat images
- On hover: call vision model, cache result, set img.title and img.alt
- Shows cursor:wait while loading description
2025-12-07 08:36:47 -05:00
030b1cc447 Use only stderr for code auto-fix error detection
Update code execution error detection to use stderr exclusively
instead of checking both stdout and stderr. This aligns with the
Unsandbox API's proper stream separation where:
- stdout is for program output
- stderr is for errors/warnings

Changes:
- Remove stdout from error detection logic
- Only trigger auto-fix when exit_code != 0 AND stderr is non-empty
- Send only stderr to /api/fix-code endpoint

This prevents false positives where stdout contains normal output
that was previously being treated as error content.
2025-12-01 11:49:33 -05:00
22ed72da7e Store auto-exec attempt on code block to avoid empty DOM elements
- Use codeBlock.dataset.autoExecAttempt to pass attempt number
- executeCodeBlock transfers attempt to results container
- No longer pre-creates empty results container
- Clean up data attribute after use
2025-11-30 15:17:27 -05:00
5c25229429 Fix classList check for non-element nodes
- Add null check for classList before calling contains()
- Handles case where nextSibling might be a text node
- Prevents 'classList is undefined' error
2025-11-30 14:56:04 -05:00
36e713147a Fix DOM insertion error in auto-exec results container
- Correctly insert results container after button container
- Use buttonContainer.parentNode.insertBefore() instead of preElement
- Add proper styling when creating results container
- Fixes 'Child to insert before is not a child of this node' error
2025-11-30 14:47:17 -05:00
53f3e66943 Post auto-fixed code as new message and auto-execute
- Post fixed code to chat so user can see what was changed
- Store fix data in window.pendingAutoExec for message handler
- Auto-trigger execution on newly posted code block
- Preserve attempt counter across fix iterations
- User now sees: original error → fixed code posted → auto-execution → results
2025-11-30 14:45:43 -05:00
09c6f62083 Fix auto-retry: execute fixed code directly without posting to chat
- Remove chat message posting that prevented automatic re-execution
- Fixed code now executes directly using same blockElement
- Simplify re-execution flow with direct recursive call
- Results display in same execution results container
2025-11-30 14:42:06 -05:00
52cb0e4fdf Fix auto-retry: check stdout for errors (Python sends tracebacks to stdout) 2025-11-30 14:38:59 -05:00
474b12f175 Add full job response logging to debug stderr field 2025-11-30 14:36:18 -05:00
d79a9c8117 Add debug logging for code execution auto-fix retry logic 2025-11-30 14:31:50 -05:00
54be0761af Move network debugging docs to separate gitignored file
Extract infrastructure/proxy debugging information from CLAUDE.md
into unturf-debugging.md to avoid exposing internal network details.

- Created unturf-debugging.md with full proxy chain documentation
- Added unturf-debugging.md to .gitignore
- Simplified CLAUDE.md to reference debugging doc
- Documented Caddy configuration (not nginx)
- Included troubleshooting steps for 502 errors

This keeps sensitive infrastructure details out of the public repo
while maintaining documentation for internal debugging.
2025-11-30 13:22:28 -05:00
31fc7946a0 Improve code auto-fix: prefer Qwen Coder with Hermes fallback
Update /api/fix-code endpoint to try MODEL_3 (Qwen Coder) first for
better code generation, with graceful fallback to MODEL_1 (Hermes) if
MODEL_3 is unavailable or returns errors.

This ensures the auto-fix feature works reliably even when specialized
code models are temporarily unavailable (e.g., 502 errors).
2025-11-30 12:04:51 -05:00
6400a5eacb Add automatic code error fixing feature
Implements an AI-powered auto-fix system that automatically attempts to
repair code execution errors up to 3 times.

Backend changes (app.py):
- Add /api/fix-code endpoint that uses MODEL_1 (Hermes) to analyze
  stderr output and generate corrected code
- System prompt instructs AI to output only raw fixed code without
  explanations or markdown formatting
- Accepts code, language, stderr, exit_code, and attempt number

Frontend changes (templates/chat.html):
- Modify executeCodeBlock() to detect failed executions (exit_code !== 0)
- Track fix attempts per code block (max 3) using dataset attributes
- Call /api/fix-code when errors are detected
- Display fixed code as new chat message with markdown formatting
- Automatically re-execute the corrected code recursively
- Show progress messages during auto-fix attempts
- Display warning when max attempts (3) are exhausted

Features:
- Fixes common issues: missing imports, syntax errors, type errors
- Posts fixed code to chat for transparency
- Prevents infinite loops with 3-attempt limit
- Graceful error handling with user-friendly status messages
2025-11-30 11:59:46 -05:00
a3d1e18a37 Fix light mode flash on chat page
Add inline script at top of base.html <head> to set theme immediately
before any rendering occurs. Prevents white flash when loading chat
and other pages that extend base.html in dark mode.
2025-11-30 10:23:53 -05:00
2a85bbe53e Make logged-in username clickable to profile page
- Chat messages: logged-in user's name links to /profile
- User lists (sidebar): logged-in user's name is clickable link
- Previous messages: same profile link logic applied
- Other users still link to /profile/username (future feature)

Anywhere the logged-in user's name appears, it now links to their
profile settings page for quick access to logout and username change.
2025-11-30 10:02:58 -05:00
4d93819571 Fix theme flash and add logout to profile page
- Add inline script to set theme before page render (browse, profile)
- Prevents white flash when loading pages in dark mode
- Add logout button with confirmation to profile page
- Username already clickable in browse page header (links to profile)
2025-11-30 10:00:48 -05:00
277cd7306a Auto-detect sender email domain from request host or system FQDN
When SMTP_FROM_EMAIL is not set, automatically derive the sender domain from:
1. Flask request.host (if not localhost/127.0.0.1)
2. System FQDN hostname (socket.getfqdn())
3. SMTP_USER or fallback to noreply@opencompletion.local

This allows the app to use the correct sender domain (e.g., noreply@ai.foxhop.net)
when deployed on different hosts, ensuring proper email relay through mx servers.
2025-11-30 07:07:09 -05:00
d8a7cc89b6 Fix gevent fork error and improve OTP email handling
- Disable Flask reloader to prevent gevent threading conflicts
- Remove SMTP configuration guard, attempt localhost:25 first
- Add graceful fallback chain: localhost → configured SMTP → console
- Catch socket errors and continue workflow in development
- Make SMTP environment variables truly optional
2025-11-30 06:53:51 -05:00
41e9e8ae7c Switch code execution to Unsandbox API
- Update CODE_EXEC_URL from code.ai.unturf.com to api.unsandbox.com
- Fix response field handling for Unsandbox API format (flat structure)
- Add exit code display with color coding (green=0, red=error)
- Update displayExecutionResults to handle stdout/stderr/exit_code at top level
- Simplify error handling for timeout/cancelled jobs
- Add comprehensive Unsandbox API documentation to CLAUDE.md
2025-11-30 06:08:17 -05:00
dc263f8613 modified: templates/browse.html 2025-11-30 05:22:11 -05:00
d46818b5dd
Redesign user interface across all pages (#42)
* Redesign UI: unified design system across all pages

- Replace scattered inline CSS with comprehensive single style.css
- Implement modern design system:
  - System font stack (-apple-system, Segoe UI, etc.)
  - Consistent spacing scale (4px base)
  - Unified color tokens for light/dark themes
  - Reusable component classes (buttons, cards, badges, forms)

- Update all templates to use new CSS classes:
  - browse.html: Less chunky, better space usage with room-grid
  - index.html: Cleaner centered card layout
  - auth.html: Streamlined 4-step flow with gradient background
  - profile.html: Modern settings interface
  - search.html: Browse-style card layout

- Chat page improvements:
  - Tighter layouts (240px/280px sidebars instead of 15%/25%)
  - Better message spacing
  - Improved code blocks with proper padding
  - Cleaner utility belt

- Better responsive design and dark mode support

* modified:   app.py
	modified:   templates/base.html
	modified:   templates/profile.html

* Revert standalone pages to original design

- Browse, index, auth, profile restored to original inline CSS
- Chat page improvements preserved in style.css
- Search page still uses improved card layout

* Add dark mode support to index and browse pages

- index.html now supports dark mode with CSS variables
- browse.html now supports dark mode with CSS variables
- Theme persists from localStorage across pages

* Remove theme toggle from chat page

- Theme toggle button removed from desktop chat sidebar
- Theme toggle button removed from mobile chat modal
- Theme management now done via profile page only

* Make usernames clickable links to profile pages in chat

* Update search page to match browse page layout and CSS

* Fix chat layout positioning

* Fix room list auto-update when title changes

* Fix new room creation appearing in sidebar

- Add socketio.emit in create_room_api() to broadcast new rooms
- Update socket handler to add new rooms to sidebar dynamically
- Rooms now appear without hard refresh

* Fix /title and /cancel commands being sent to LLM

- Add missing return statements after command handlers
- Commands now properly terminate message processing
- Prevents commands from being interpreted as chat messages

* Make usernames in user lists clickable links to profiles

- Update updateUserLists() to create links for all usernames
- Add hover effect CSS for user list links
- Works for both active and inactive users
- Works for both desktop and mobile views

* Revert user list profile links and update profile page layout

- Remove profile links from user lists (no backend route for other users)
- Update profile page to full-screen layout like browse page
- Add header with navigation buttons
- Remove centered container, use full-width layout
- Add box shadows to sections for visual separation

* Convert all flexbox layouts to CSS grid

- Replace all display: flex with CSS grid equivalents
- Update templates: profile, browse, search, index, auth
- Update static CSS for consistent grid usage
- Use grid-template-columns, grid-auto-flow, and place-items
- Improve layout consistency across all pages

* Fix chatroom horizontal scrolling

- Add overflow-x: hidden to #chat-container and #chat to prevent horizontal scroll
- Add word-break and overflow-wrap to message content for text wrapping
- Change pre tags from overflow: hidden to overflow-x: auto for individual scrolling
- Add min-width: 0 to grid containers to prevent overflow
- Code blocks can now scroll individually while chatroom wraps content

* Remove duplicate CSS variables and fix XSS vulnerability

- search.html: Remove inline styles, link to style.css
- index.html: Remove duplicate CSS variable blocks, link to style.css
- browse.html: Remove duplicate CSS variable blocks, link to style.css
- chat.html: Fix XSS vulnerability in room list updates
  - Use textContent/createTextNode instead of innerHTML for user data
  - Use DOM methods instead of string concatenation
  - Encode URL components with encodeURIComponent
  - Extract user count from textContent instead of innerHTML regex

* Merge duplicate CSS rules and replace inline styles with design system

style.css:
- Merge duplicate html, body rules (lines 137-143 and 159-167)
- Consolidate typography and layout properties in single rule
- Remove duplicate BASE LAYOUT section

profile.html:
- Replace style.display mutations with classList API
- Add .availability-indicator.show CSS rule for visibility
- Use classList.add('show') and classList.remove('show')
- Consistent with existing .message.show pattern

browse.html:
- Replace hard-coded gradient colors with CSS variables
- Use var(--gradient-start) and var(--gradient-end) for buttons
- Replace #667eea with var(--button-primary) for tabs and room names
- Remove inline .room-badge styles, use .badge .badge-public/.badge-private
- Apply existing badge classes from style.css for dark mode support

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Russell Ballestrini <russell@unturf.com>
2025-11-12 09:24:49 -05:00
e4cabf4be6
otp (#41)
* Add email OTP authentication system and private room management

## Authentication System
- Implement email OTP-based authentication with User and OTPToken models
- Add auth.py module with OTP generation, email sending, and session management
- Create authentication endpoints: /auth/send-otp, /auth/verify-otp, /auth/claim-name, /auth/status, /auth/logout
- Add authentication modal UI with email verification and display name claiming
- Support SMTP configuration via environment variables (optional)

## Room Privacy & Ownership
- Add is_private, is_archived, owner_id, and forked_from_id fields to Room model
- Implement private rooms (single-user, owner-only access)
- Add room forking: users can fork public rooms to public or private
- Add room archive/delete endpoints (owner-only operations)
- Implement access control for private room viewing

## UI Improvements
- Add public/private room tabs in sidebar
- Show authentication prompt in private rooms tab for non-authenticated users
- Add room action buttons (fork, archive, delete) with proper permissions
- Update homepage with statistics (public/private rooms, active users, active rooms)
- Remove model/voice from URL query strings, use localStorage exclusively

## Database Migration
- Create migration 2025011100 for User, OTPToken tables and Room model updates
- Add indexes for email, display_name, is_private, is_archived, owner_id

## Breaking Changes
- URL parameters now only include username (model/voice moved to localStorage)
- Private rooms require authentication to access
- Room creation can now require authentication (for private rooms)

* Update README with authentication and private room documentation

* Simplify README to be less verbose

* Add missing session import to fix linter errors

* Fix migration dependency to resolve multiple heads conflict

* asdf

* Fix SQLAlchemy auto-correlation error in homepage statistics query

* Change tagline from AI-Powered to Machine Learning Powered

* Add dedicated authentication page instead of modal

- Create new /auth route with full-page authentication flow
- Remove modal code from index.html
- Update Sign in link to point to /auth page
- Auth page has 4-step flow: email, OTP, display name, success
- Better UX with gradient background and cleaner design

* Fix migration: remove batch_alter_table to avoid circular dependency

- Use op.add_column() directly instead of batch_alter_table()
- Remove foreign key constraints (defined in models, not needed in migration)
- User and OTPToken tables created by db.create_all() in make init-db
- Fixes CircularDependencyError during migration

* Fix migration: check if columns exist before adding

- Use inspector to check existing columns and indexes
- Only add columns/indexes if they don't already exist
- Handles case where db.create_all() was run before migration
- Fixes 'duplicate column name' error

* Add profile page, room browsing, and updated_at timestamp

Features:
- Profile page with username change and dark/light mode settings
- Browse page for discovering public and private rooms
- Room updated_at timestamp (integer Unix epoch) that updates on new messages
- Dynamic room tabs based on current room type (public/private)
- Fork and delete room actions moved to right sidebar utility belt
- Remove archive feature and success alerts from room actions

Technical changes:
- Add updated_at column to Room model (integer timestamp)
- Add /profile route with authentication requirement
- Add /browse route for room discovery
- Add API endpoints for username availability check and update
- Update room.updated_at on message creation in app.py:1189
- Wider right sidebar (25% instead of 15%) for better button layout
- Profile link on homepage and browse page for authenticated users

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: russell@unturf. <russell@unturf.com>
2025-11-11 22:56:58 -05:00
d849ecbd7d Add code execution and TTS features to README
Document new code execution feature with 30+ language support, isolated sandbox containers, and binary downloads. Also mention text-to-speech capability.
2025-11-11 19:27:52 -05:00
4f59aa5dcc modified: README.rst 2025-11-11 18:52:31 -05:00