Commit graph

459 commits

Author SHA1 Message Date
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
28bbec489d modified: flask-socketio-llm-completions-2.png
modified:   flask-socketio-llm-completions.png
2025-11-11 18:44:38 -05:00
3f9b1827c7
Use underscores instead of dashes for AI-generated filenames (#40)
Updated the artifact filename generator to use snake_case (underscores)
instead of kebab-case (dashes) for better consistency with Python
naming conventions.

Changes:
- Updated AI prompt examples to show underscore format
- Modified filename processing to replace spaces with underscores
- Updated validation regex to accept underscores instead of dashes
- Changed docstring to reflect underscore usage

Examples: hello_world, prime_checker, array_sort (instead of hello-world, etc.)

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 17:55:35 -05:00
45f183df37
Add AI-powered artifact filename generation (#39)
* Add AI-powered artifact naming for compiled binaries

Implements intelligent filename generation for downloaded binaries using
Hermes AI to analyze code and generate meaningful 1-3 word filenames.

Changes:
- Add /api/generate-artifact-name endpoint that uses MODEL_1 (Hermes)
- Modify frontend to call naming API before download
- Add ENABLE_AI_ARTIFACT_NAMING environment variable (enabled by default)
- Filenames are descriptive (e.g., "fizzbuzz", "hello-world", "prime-checker")
- Graceful fallback to "compiled_binary" if naming fails or is disabled

The feature can be disabled by setting ENABLE_AI_ARTIFACT_NAMING="false"
in environment variables.

* Rename env var to ENABLE_CODE_GEN_FILENAMES

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 17:43:52 -05:00
14bfce710d
Move download binary button next to Run button (#38)
- Reposition download button from output area to button container
- Place next to Copy and Run buttons with consistent styling
- Button hidden by default, shown only when artifact available
- Remove colored background to match other action buttons

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 16:41:55 -05:00
a260b5fa02
Handle cancellation and timeout recovery (#37)
* Enable binary downloads on timeout/cancellation

When code execution times out or is cancelled, the compiled binary
may still be available. This change ensures displayExecutionResults()
is called for timeout/cancelled jobs, allowing users to download
the binary artifact even when execution doesn't complete normally.

* Fix partial output display for timeout/cancellation

Previous commit broke partial output display by passing job.result
directly to displayExecutionResults(), but for timeout/cancelled jobs
the output is in partial_output field, not stdout.

Now properly maps partial_output to stdout before displaying, so users
see both the error message and any output that was captured before
timeout/cancellation, plus binary downloads if available.

* Add debugging for missing artifact on timeout/cancel

Check multiple possible locations for artifact:
- job.artifact (top level)
- job.result.artifact (nested)

Add console logging to see full job structure when timeout/cancel
occurs so we can understand why the binary isn't appearing.

* Try fetching artifact from separate endpoint on timeout/cancel

When timeout/cancel occurs, the artifact isn't in the job response.
Try fetching from /jobs/{job_id}/artifact endpoint as a fallback.

This explores whether the executor service has a separate artifact
endpoint that we can use to retrieve compiled binaries even when
execution is cancelled or times out.

* Remove debug logging, document artifact limitation

Removed console.log debugging statements now that we've confirmed
the executor service doesn't include artifacts in timeout/cancelled
responses and doesn't have a /jobs/{job_id}/artifact endpoint.

Kept the artifact fetching code with comments for future compatibility
if the executor service adds this feature.

Current limitation: Binary downloads only work for completed executions,
not for timeout/cancelled ones. The binary exists but the executor
service doesn't return it.

* Try multiple artifact endpoint patterns for timeout/cancel

When artifact isn't in the job response, try fetching from:
- /artifacts/{job_id}
- /jobs/{job_id}/artifact
- /jobs/{job_id}/download
- /jobs/{job_id}/binary
- /download/{job_id}
- /binary/{job_id}

Handles both JSON responses and direct binary responses. Logs
each attempt to console so we can see which endpoint (if any) works.

* Revert endpoint searching - artifact should be in /jobs/{id}

According to OpenAPI spec, there are no separate artifact endpoints.
The artifact should be included in GET /jobs/{id} response for ALL
job statuses (completed, cancelled, timeout).

Current limitation: The executor service only includes result.artifact
for "completed" status, not for "cancelled" or "timeout" status.

The frontend code is correct - it checks job.artifact and
job.result.artifact. The issue is the executor service needs to
include the artifact in cancelled/timeout responses.

* Add debug logging for cancelled/timeout artifact checks

Since the executor service was supposedly patched to include artifacts
in GET /jobs/{id} responses even for cancelled/timeout jobs, add
detailed logging to verify:

1. What the full job response looks like
2. Whether artifact is at job.artifact or job.result.artifact
3. Artifact details if found

This will help determine if the patch is deployed and working.

* Add test-artifact Makefile target for testing executor API

Tests binary artifact retrieval from code executor service:
- Compiles C code with return_artifact=true
- Extracts base64 artifact from response
- Decodes and executes the binary

Can test against different URLs:
  make test-artifact URL=https://code.ai.unturf.com

Tested against production and confirmed:
- Artifacts ARE included for completed jobs
- Artifacts are NOT included for cancelled/timeout jobs (even with
  return_artifact=true). Exit code 137 indicates SIGKILL.

* Document confirmed limitation - no artifacts for cancelled jobs

Tested against production executor API (make test-artifact) and confirmed:
- Cancelled jobs return exit_code 137 (SIGKILL)
- NO artifact field in response (neither job.artifact nor job.result.artifact)
- Artifacts only returned for fully completed jobs

Code still checks for artifacts in case this limitation is fixed
in the future, but currently binary downloads will not work for
cancelled/timeout executions.

To fix: Executor service needs to include compiled binary in
response even when execution is killed (compilation succeeded).

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 16:34:05 -05:00
108b6e270f
Add binary download support for compiled code (#35)
- Request compiled binaries via return_artifact parameter
- Add "Download Binary" button when artifact is available
- Support base64 decoding and browser download
- Handle artifact errors gracefully
- Works with C, C++, Rust, Go, Java, and other compiled languages

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 13:38:41 -05:00
ccedf063a0
Fix action buttons position - insert after <pre> not inside it (#36)
Problem:
- Buttons were being inserted as children of <pre> element
- This caused buttons to appear inside code blocks with wrong styling
- Template caching made changes appear to require "two commits"

Solution:
- Change insertion point from block.parentNode to preElement.parentNode
- This places buttons as siblings of <pre>, not children
- Add TEMPLATES_AUTO_RELOAD=True to prevent Flask template caching

Technical Details:
- block is the <code> element
- block.parentNode is the <pre> element
- preElement.parentNode.insertBefore puts buttons after <pre>
- Previous code put buttons inside <pre> after <code>

DOM Structure Before:
  <pre>
    <code>...</code>
    <buttons> <!-- Wrong: inside pre -->
  </pre>

DOM Structure After:
  <pre>
    <code>...</code>
  </pre>
  <buttons> <!-- Correct: after pre -->

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 13:38:03 -05:00
76b8058e92
Move copy and run buttons below code (#34)
* Move code block buttons below code instead of above

- Modified addCopyButtonToCodeBlock to insert button container after code block
- Updated truncateCodeBlock to remove duplicate buttons before adding its own
- Ensures clean button placement for both regular and truncated code blocks

* Refactor code block button rendering for efficiency

- Process blocks in optimal order: truncate → highlight → line numbers → buttons
- Eliminate redundant button creation/removal cycle
- truncateCodeBlock now only truncates and returns boolean
- addCopyButtonToCodeBlock handles all button creation (including Show More)
- Buttons always appear below code blocks after full processing

This prevents wasteful creation and immediate deletion of buttons for truncated blocks.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 13:22:40 -05:00
bafd2194ab
- Add download button next to Play button for all messages (#33)
* Add download button for TTS audio

- Add download button next to Play button for all messages
- Button is initially hidden and appears after TTS audio is generated
- Works for both manual play and auto-play modes
- Works for both regular and streaming messages
- Handles cached audio properly
- Download filename includes message ID and voice name

* Refactor: Extract download button logic into helper function

- Create enableDownloadButton() helper to eliminate code duplication
- Replace 4 identical blocks (56 lines) with 4 function calls (4 lines)
- Improves maintainability and follows DRY principle
- Handles both cached and fresh audio in both speakText functions

* Remove hardcoded voice fallbacks, use API or empty list

- Remove hardcoded voice options from HTML dropdown
- Remove all fallbacks to default voices (tts-1:onyx)
- If voices API fails, leave dropdown empty instead of falling back
- localStorage persistence for voice selection already implemented
- Voices API caching already working (1-minute cache like models)
- Voice selection now purely driven by API response

* Fix: Make download button visible after TTS audio loads

- Add download button to previous_messages handler (was missing)
- Change display from "" to "inline-block" for visibility
- Download button now appears properly after TTS processes

* Add debug logging for download button issue

- Add console.log to trace enableDownloadButton execution
- Change === to == for messageId comparison (handle type coercion)
- Log wrapper status, button status, and ID matching
- This will help identify why download button doesn't appear

* Remove debug logging, keep type coercion fix

- Remove console.log statements now that issue is identified
- Keep == comparison (was the actual fix)
- Add comment explaining why == instead of ===
- dataset.messageId is string, messageId param is number

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-11 09:56:57 -05:00
aa1651ae81 Fix integration tests: ensure Flask instance directory exists
The integration tests were failing in GitHub Actions with 'unable to open
database file' errors because the Flask instance directory didn't exist.

The app.py code at line 40 creates a database URI using app.instance_path,
which requires that directory to exist. In GitHub Actions, this directory
doesn't exist by default, causing SQLite to fail when trying to create
the database file (even though tests override to use :memory:).

Solution: Create instance directory in setUp() before app context is pushed.

Changes:
- Add os.makedirs(app.app.instance_path, exist_ok=True) in setUp()
- Also fixed temp file paths to use absolute paths for research directory
- All 9 integration tests now pass locally

This ensures tests work in both local and GitHub Actions environments.
2025-11-10 17:30:53 -05:00
4f8cf1ce6a Fix integration test file path handling for GitHub Actions
Fixed the integration tests to use absolute paths when creating
temporary activity YAML files in the research directory.

The tests were failing in GitHub Actions with "unable to open database
file" errors because they used relative paths (Path("research")) which
didn't work correctly in the GitHub Actions working directory.

Changes:
- Use Path(__file__).parent.parent.parent to get absolute base directory
- Apply absolute path to both file creation and cleanup operations
- All 9 integration tests pass locally

This ensures tests work consistently across local development and
GitHub Actions environments.
2025-11-10 17:25:47 -05:00
d484aedc67 Remove temporary test YAML files 2025-11-10 17:21:35 -05:00
d5004c8b78 Fix GitHub Actions functional test env var conflict
Fixed the functional test failure by removing MODEL_ENDPOINT_0 from
the functional test step in GitHub Actions workflow.

The functional test test_initialize_model_map_with_env_vars sets its
own test endpoints (MODEL_ENDPOINT_1, MODEL_ENDPOINT_2) and was failing
because MODEL_ENDPOINT_0 from the workflow was interfering.

Changes:
- .github/workflows/test.yml: Removed MODEL_ENDPOINT_0 from functional test step
- .github/workflows/test.yml: Updated unit/integration tests to use hermes.ai.unturf.com
- tests/functional/test_guarded_ai.py: Fixed patch.dict to use clear=False

Unit and integration tests still have MODEL_ENDPOINT_0 configured
since they need it for app initialization. Functional tests now run
without env var interference and can test their own endpoint configs.

All 46 functional tests pass locally.
2025-11-10 17:21:07 -05:00
4550407d7b Apply black formatting to test files 2025-11-10 17:05:08 -05:00
21acc90f2d Fix socketio mocking and add MODEL_ENDPOINT env vars for tests
Fixed remaining 2 integration test failures:

1. Socketio mocking issue:
   - Tests were setting app.socketio but activity module has its own reference
   - Fixed by mocking activity.socketio directly instead of app.socketio
   - Updated test_cancel_activity_integration to check both chat_message and activity_status events
   - Updated test_display_activity_metadata_integration to use activity.socketio

2. GitHub Actions environment variables:
   - Added MODEL_ENDPOINT_0 and MODEL_API_KEY_0 to all test steps
   - These are required for app.py initialization
   - Set to dummy values (https://test.api) for testing

Test Results:
- Before: 2 failed, 39 passed
- After: 41 passed 

All integration tests now pass locally and should pass on GitHub Actions.
2025-11-10 17:04:41 -05:00
aefb7005d1 Fix integration test failures - attempts increment and app context
Fixed 3 critical issues:

1. SQLAlchemy 'already registered' error in test_app_activity_functions.py:
   - Removed access to db.engine before app context was pushed (line 39)
   - Moved db.engine.dispose() to after context.push() (line 54)
   - Removed unnecessary init_activity_module() call in tests
   - Fixes 9 'Working outside of application context' errors

2. Attempts counter not incrementing for incorrect answers:
   - Added 'incorrect' to list of categories that stay on current step
   - Previously 'incorrect' was entering navigation block incorrectly
   - Now properly goes to ELSE block which increments attempts
   - Fixed in activity.py line 1082

Test Results:
- Before: 10 failed, 31 passed
- After: 2 failed, 39 passed
- Remaining 2 failures are minor socketio mocking issues (unrelated)
- Core functionality tests (attempts increment, correct navigation) now pass

Root Cause:
The activity.py logic assumed any category NOT in the special list should
try to navigate forward. But 'incorrect' should stay on the current step
and increment attempts, not try to find the next step.
2025-11-10 16:56:39 -05:00
6e4a11634b Fix SQLAlchemy RuntimeError in integration tests
- Remove db.init_app() call causing 'already registered' error
- Use db.engine.dispose() to clear existing engine
- Use db.session.remove() to clean up sessions
- Forces new connection with in-memory database config
- Fixes 10 failing tests in test_app_activity_functions.py
2025-11-10 16:39:33 -05:00
352c9879c9 Fix remaining integration test failures
- Fix test_app_activity_functions.py SQLAlchemy database issues:
  - Reinitialize db with test app config before creating tables
  - Store and restore original database URI in tearDown
  - Add try/except around drop_all in tearDown

- Fix test_activity_integration.py attempts increment test:
  - Remove next_section_and_step from incorrect transition
  - When next_section_and_step is specified, code navigates without incrementing attempts
  - Transition should only have counts_as_attempt without navigation to increment and stay on same step
  - This matches the actual behavior: navigation happens immediately when specified
2025-11-10 16:30:06 -05:00
f9ddc4ec03 Fix integration test failures
- Fix test_activity_processing.py: Import activity module and use activity.* functions
- Fix test_app_activity_functions.py: Import activity module, use activity.* functions, initialize activity module with app's socketio and db
- Fix test_activity_integration.py: Update YAML format to match current specification
  - Change buckets from objects to simple string lists
  - Use next_section_and_step instead of separate next_section_id/next_step_id
  - Add required title fields and tokens_for_ai
  - Replace type field with content_blocks for info steps
2025-11-10 16:06:59 -05:00
9003240762 Pin GitHub Actions to Python 3.13 to match local virtualenv
- Remove matrix testing against Python 3.10, 3.11, 3.12
- Use Python 3.13 exclusively in both test and lint jobs
- Matches local development environment (Python 3.13.7)
- Ensures consistent behavior between local and CI environments
2025-11-10 15:53:42 -05:00
a5a95ae729
Merge pull request #32 from russellballestrini/claude/github-action-test-pipeline-011CUzkwsHcPVEVJaAE8TcDZ
Set up GitHub Actions for automated testing
2025-11-10 15:42:52 -05:00
Claude
09ccba41f6
Fix streaming protocol test failures
Fixed 3 failing tests by correcting mock setup:

1. test_bedrock_streaming_protocol: Changed from mocking app.get_s3_client
   to mocking boto3.client directly, since chat_claude creates its own client

2. test_streaming_content_accumulation: Fixed Message mock patching and
   changed query mock to return mock_message instead of None

3. test_error_handling_in_streaming: Fixed Message mock patching, changed
   query mock to return mock_message, and updated assertion to check for
   chat_message event instead of message_chunk with is_complete flag

All streaming protocol tests now pass.
2025-11-10 20:19:32 +00:00
Claude
34c48743d0
Fix execute_processing_script to support list comprehensions
The exec() function was using empty globals dict which prevented list
comprehensions from accessing variables in the local scope. Changed to
use the same dict for both globals and locals to properly support
comprehensions in processing scripts.

Fixes battleship game flow tests that use list comprehensions.
2025-11-10 19:58:29 +00:00
Claude
803cdb0a0f
Fix battleship tests to use activity.execute_processing_script
Tests were incorrectly calling app.execute_processing_script when the
function exists in the activity module. Updated all references.
2025-11-10 19:54:04 +00:00
Claude
ad47efd31d
Fix test failures in guarded_ai test files
- Update test_initialize_model_map to mock models.list() response properly
- Update test_get_openai_client_and_model_default to match new MODEL_X behavior
- Fix test_initialize_model_map_with_env_vars in functional tests

Tests now properly mock the OpenAI client's models.list() response, which
returns model IDs that are used as keys in MODEL_CLIENT_MAP, not endpoint names.
2025-11-10 19:50:06 +00:00
Claude
39e39e80f1
Fix flake8 F824 errors - remove unused global declarations
Remove unnecessary global declarations for MODEL_CLIENT_MAP that are never reassigned
2025-11-10 19:39:36 +00:00
Claude
22db7a9a8a
Run black formatter on all Python files
Format code according to black style guidelines for consistency
2025-11-10 19:37:05 +00:00
Claude
408b419b94
Fix YAML syntax error in GitHub Actions workflow
Quote environment variable values containing colons to prevent YAML parsing errors
2025-11-10 19:35:34 +00:00
Claude
94cc147fed
Improve GitHub Actions test pipeline
- Make YAML validation failures fail the build (removed continue-on-error)
- Split flake8 into syntax errors (fails) and style warnings (continues)
- Add concurrency control to cancel redundant runs
- Add Python 3.10, 3.11, and 3.12 matrix testing for better compatibility
2025-11-10 19:28:18 +00:00
562711555e
Merge pull request #31 from russellballestrini/claude/template-system-documentation-011CUzhHbaPXsG7W92zZ1Dci
OpenCompletion Template System Documentation
2025-11-10 13:59:23 -05:00
Claude
6ce46fc5a0
Add template control structure validation to YAML validator
Enhance the activity YAML validator to detect and reject Jinja2 and
Handlebars control structures, enforcing the substitution-only template
system design.

Changes:
- Add regex patterns for Jinja2 ({% %}) and Handlebars ({{# }})
- Add _check_template_syntax() method
- Integrate checks in content_blocks, questions, tokens_for_ai, hints
- Add 7 comprehensive unit tests for template validation
- All 59 activity YAMLs + SPEC.yaml pass validation (0 errors)
2025-11-10 18:55:21 +00:00
Claude
b45712f503
Remove Jinja2 control structures from SPEC.yaml
Update the attempt counter example in SPEC.yaml to use substitution-only
template syntax instead of Jinja2 control structures ({% if %}).

The AI can naturally understand attempt context from {{current_attempt}},
{{max_attempts}}, and {{attempts_remaining}} variables without needing
conditional logic in the template itself.

This aligns with the substitution-only template system where logic lives
in scripts and templates only display pre-computed values.
2025-11-10 18:44:48 +00:00
5ad1279f72
Merge pull request #29 from russellballestrini/claude/yaml-spec-immersive-activities-011CUzPAMF9VZh8Po4GNrM6W
Identify YAML limitations for interactive activities
2025-11-10 12:08:25 -05:00
Claude
b833983b30
Add GitHub Actions workflow for automated testing
- Run unit, functional, and integration tests on push/PR
- Test on Python 3.11 with Ubuntu latest
- Include code coverage reporting for unit tests
- Add linting job with black and flake8
- Validate all activity YAML files
- Trigger on main, master, develop, and claude/** branches
2025-11-10 17:06:04 +00:00
Claude
653c72020c
Fix progressive hints in CLI simulator for first failed attempt
Removed "attempts > 0" check in research/guarded_ai.py that prevented
hints from showing on the first attempt. Matches the fix made to
activity.py for consistent behavior across web app and CLI simulator.
2025-11-10 17:02:56 +00:00
Claude
3df402505c
Fix progressive hints to display on first failed attempt
Removed "activity_state.attempts > 0" check that prevented hints from
showing on the first attempt. The code already correctly computes
current_attempt as activity_state.attempts + 1, so hints now work
starting from attempt 1 (when attempts = 0).
2025-11-10 17:02:06 +00:00
Claude
693dd9dace
Add comprehensive unit tests for activity_utils.py v2.0 features
- Created 58 unit tests covering all 8 utility functions
- Tests cover template rendering, metadata conditions, conditional content,
  navigation, weighted random, progressive hints, and context creation
- Fixed operator precedence bug: _not_contains and _not_exists must be
  checked before _contains and _exists to prevent false matches
- All tests passing (58/58)
2025-11-10 16:55:12 +00:00
Claude
bd779e06fa
Fix SPEC.yaml validation and refactor guarded_ai.py for v2.0 consistency
SPEC.yaml fixes:
- Comment out orphaned example code blocks that broke YAML parsing
- Convert progressive hints and dynamic question examples to comments
- Add placeholder keys to maintain valid YAML structure
- All examples now documented but non-executable (reference only)
- Validates with 0 errors

guarded_ai.py refactor (CLI simulator now uses v2.0 features):
- Import activity_utils.py for consistency with activity.py
- Use check_conditions() for advanced metadata conditions (gte, lt, contains, etc.)
- Use filter_content_blocks() for template rendering and conditional blocks
- Use render_template() for dynamic question text with {{variables}}
- Use resolve_conditional_navigation() for if/elif/else navigation
- Use select_weighted_random() for weighted random selection
- Use get_progressive_hint() for progressive hints system
- Create template contexts with built-in variables (current_attempt, etc.)

Benefits:
- Single source of truth for v2.0 logic (activity_utils.py)
- CLI simulator now tests all v2.0 features
- Maintainability: changes to features only need updates in one place
- Consistency: web app and CLI behave identically

All changes validated and tested.
2025-11-10 15:19:50 +00:00
Claude
2b19fc5b9d
Implement OpenCompletion Activity YAML v2.0 features for immersive activities
Add comprehensive v2.0 features to enhance activity creation:

Features Implemented:
- Template variables: {{metadata.key}}, {{current_attempt}}, etc.
- Conditional content blocks: show_if conditions for dynamic content
- Advanced metadata conditions: gte, lt, contains, regex, exists operators
- Conditional navigation: if/elif/else branching based on metadata
- Progressive hints system: Auto-display hints based on attempt number
- Weighted random selection: Probabilistic outcomes with custom weights
- Dynamic question text: Questions with template variables
- Built-in attempt counters: Access to current_attempt, max_attempts, attempts_remaining

Files Modified:
- activity.py: Integrated all v2.0 features into activity execution
- activity_utils.py: New utility module for templates and conditions
- activity_yaml_validator.py: Updated validator for v2.0 schema
- CLAUDE.md: Added session persistence and Twitch Plays model docs
- research/SPEC.yaml: Comprehensive v2.0 feature documentation

Added:
- research/activity-test-v2-features.yaml: Test activity demonstrating all features

All changes validated and tested. Zero errors in validator.
2025-11-10 15:13:02 +00:00
7c61328943 Require validation for all activity YAML files
Added mandatory validation step to activity creation workflow:
1. Read research/SPEC.yaml first (fresh spec)
2. Validate with activity_yaml_validator.py after changes
3. All YAMLs must pass validation (0 errors) before committing

Ensures quality and prevents broken activity files from entering the repo.
2025-11-10 09:28:54 -05:00
11b16aa12a Add instruction to read SPEC.yaml before creating activities
Ensures Claude always has the latest activity YAML specification
fresh in context when creating or modifying activity files.
2025-11-10 09:10:08 -05:00
da9792ad63 Fix SPEC.yaml validation errors
- Add random bucket names (emergency, surprise, bonus) to main buckets list
- Fix invalid transition targets to use existing steps
- Add tokens_for_ai to all feedback_prompts (required field)
- Add bonus transition definition

All validation errors resolved - SPEC.yaml now passes validation
2025-11-10 09:03:24 -05:00