Compare commits

...
Sign in to create a new pull request.

447 commits

Author SHA1 Message Date
f7862bc54a
feat(profile): let guests manage their localStorage username
/profile previously required auth and returned a raw JSON 401 for
guests. Now it renders a guest variant: edit guestUsername in
localStorage, clear it to re-prompt on next visit, or sign in to
claim a permanent username. Unifies the two username flows
(authed DB display_name vs guest localStorage) under one page.
2026-06-10 12:50:51 -04:00
b2fb60d1b7
fix(tts): skip inlined sender header when wrapping sentences
chat_message (non-streaming) renders the sender header as the first
paragraph inside .message-content — '<p><strong>[name](link):</strong></p>'.
message_chunk uses a separate .message-header div, but the inline pattern
made the sender name sentence 0, so manual Play highlighted the model
name instead of the actual first sentence (and auto-play got every
highlight shifted by one because domIndexFor ratioed around it).

Detect the pattern (top-level <p> with one <strong> child, text ending
in ':') and exclude it from the sentence walk via a TreeWalker filter.

Also drops the diagnostic logging from cdf3c7c.
2026-06-03 18:28:00 -04:00
cdf3c7ca24
debug(tts): log attachSentenceGlow path to diagnose missing manual highlights
Temporary instrumentation to pinpoint why sentence highlighting fails on
manual Play. Logs whether audio/button are present, whether sentences is
the expected array, the post-wrap span count, and the wrap-flag state.
Will revert once root cause is found.
2026-06-03 17:50:04 -04:00
8589c91ca9
feat(chat): persist guest username in localStorage across page loads
Guests had to retype their username on every page load. Now the entered
name is cached in localStorage and reused on subsequent visits. The
cache is invalidated by any login/logout transition:

- on a page load with a server-provided username (logged in), we clear
  the cache, so a later logout starts fresh
- on a guest page load with no cache, we prompt and save what they type
2026-06-03 17:03:16 -04:00
a829c97136
fix(tts): rewrap sentence glow when innerHTML overwrites destroyed spans
wrapSentencesForGlow gated only on dataset.glowWrapped='1', but that flag
lives on the container element and survives innerHTML replacement. The
streaming chunk handler does targetMessageElement.innerHTML = sanitized
on every delta, and message_updated / edit-save both replace innerHTML
too. Spans got blown away while the flag persisted, so subsequent glow
attaches found the flag, skipped re-wrapping, and the highlight never
appeared.

Now also require an actual .tts-sentence span to exist before short-
circuiting. If the wrap was destroyed, re-wrap.
2026-06-03 16:07:21 -04:00
ad080a7e2a
fix(tts): manual mode pause-toggles + sentence glow on F5
Two regressions surfaced after adding the Pause label in manual mode:

1. Clicking Pause restarted the cached blob from the beginning (looked
   like the track played twice). speakText's onclick was still wired to
   speakText itself, so each click created a fresh Audio and started
   from 0. Manual play now uses the same takeOver pattern as the queued
   path: while live audio owns playback, the click routes through
   toggleAudioPlayback (which pauses any current audio and toggles this
   one); when audio ends or errors, the original speakText handler is
   restored so users can replay from cache.

2. Manual mode had no sentence highlights. The glow needs per-sentence
   timing from the speech service, which only the SSE branch returns —
   manual mode was using the older non-SSE streaming path. speakText now
   branches on tts-1-f5 like speakTextQueued does, caches the sentences
   array, and calls attachSentenceGlow. Pauses naturally pause the glow
   (its tick loop checks audio.paused/ended).

Also routes the queued-audio onclick rebind through toggleAudioPlayback
for cross-message safety (was calling audio.play()/pause() directly,
which would let two queued audios play simultaneously if the user
clicked Play on a paused one while another was active).
2026-06-03 15:43:13 -04:00
264f0e7269
fix(tts): pause button actually pauses queued audio
The onplay handler set the button text to 'Pause' mid-playback but the
button's onclick was still wired to speakText. Clicking Pause re-ran
speakText, which created a fresh Audio from the cached blob — the queued
audio paused while a new one started from the beginning, sounding like a
double-play.

Rebind the click handler to direct audio.pause()/play() while the queued
audio owns playback, restore the original (cache-replay) handler on end
or error.
2026-06-03 15:12:49 -04:00
211dfa0eba
tts: explicit colors on queued/loading buttons for dark mode
Default browser disabled-button styling washes out to near-invisible
against dark backgrounds. Force --button-secondary background + white
text + opacity 1 on .tts-queued and .tts-loading so the indicator stays
legible in both themes.
2026-06-03 15:00:56 -04:00
adc4fd79d2
tts: queued/loading indicator on play button
Auto-play TTS used to show zero feedback between message arrival and
audio start — users waited blind. Now the play button shows:

  Queued + pulsing dot  — message is waiting in line
  Loading + spinner     — actively fetching audio from speech service
  Pause                 — audio is actually playing

Manual Play also uses the same spinner instead of the old 'Streaming...'
text-only state. Indicator clears on play, pause, end, error, and when
auto-play is toggled off.
2026-06-03 11:19:19 -04:00
d405ebc6f9
ui: drop misleading homepage stats (active users, active rooms)
Active Users counted all-time distinct UserSession usernames, not anyone
currently online. Active Rooms counted any room that ever received a
single message, with no decay. Both read as live metrics but aren't.

Keep Public Rooms and (when signed in) Private Rooms — those are real
counts users can verify by browsing.
2026-06-02 09:19:11 -04:00
f2ebfc16a0
tts: stream F5 over SSE — gapless MSE audio + live timing glow
Replace the non-streaming whole-clip timestamps fetch with an SSE consumer.
Each event carries one sentence's mp3 + exact start/end ms; audio feeds an
MSE SourceBuffer in sequence mode so playback starts after sentence 0, and
the sentences array grows live to drive the glow (tick reads its length each
frame). Falls back to a buffered single blob when the browser lacks mp3 MSE.
Removes fetchTTSWithTimestamps. Best of both: instant start and exact sync.
2026-05-29 15:23:36 -04:00
b5958382df
fix(tts): clean sentence highlight, drop box-shadow square on line wraps
Use a background highlight with box-decoration-break: clone so a wrapped
sentence highlights smoothly instead of rendering a pale square box.
2026-05-29 13:33:54 -04:00
4b0a443928
ui: add dark/light theme toggle above Auto-Play TTS
Restore the theme toggle into the chat utility belt (desktop + mobile),
placed directly above the Auto-Play TTS button. Re-wires updateThemeButtonText
to label both buttons (shows the mode a click switches to). toggleTheme()
already persisted to localStorage and swapped the highlight.js theme.
2026-05-29 12:51:07 -04:00
511c429927
tts: purge cached audio and dequeue on message delete
When a message is deleted, drop its cached TTS audio (keys `${messageId}-${voice}`),
remove any pending entries from the playback queue, and if it is the message
currently playing, stop it and advance the queue. Track currentQueuedMessageId
so the active item can be identified. Keeps auto-play sequencing correct and
prevents a deleted message's stale audio from replaying.
2026-05-29 12:44:43 -04:00
34f4fc325b
tts: drive sentence glow from exact server timestamps
Replace the fragile client-side RMS / Web Audio pause detection (which
stalled on sentence 0 whenever the audio context was suspended or the
MSE duration was unknown) with exact per-sentence timing from the speech
service. For tts-1-f5, fetch via the new timestamps mode and light each
sentence by comparing audio.currentTime to the returned start/end ms;
falls back to proportional mapping if the rendered and spoken sentence
counts differ. Cache now stores sentences for correct replay glow.
Non-F5 models keep streaming playback with no glow.
2026-05-29 12:29:37 -04:00
0b66a50938
feat(thinking): default thinking mode ON
Flip the Thinking toggle to default ON: localStorage init now reads
!== 'false' (matching the standard default-on idiom), and both desktop
and mobile buttons render green "Thinking: ON" by default. Users opt out
to save tokens; the OFF path still drives server-side enable_thinking=false.
2026-05-29 12:00:46 -04:00
0fdb673a70
feat(tts): per-sentence glow synced to audio via Web Audio pause detection
When Auto-Play TTS reads a message, wrap its sentences in spans and advance a
glow highlight on detected inter-sentence silences (RMS dips), with a
char-proportional fallback. Comma/clause pauses are detected too, reserved for
a future word-level highlight. Tunable via window.GLOW.
2026-05-29 11:52:08 -04:00
57a5b6f243
feat(thinking): toggle to enable/disable model thinking mode
Add a Thinking on/off button next to Auto-Play TTS. When OFF (default),
the client sends enable_thinking=false with each chat_message and the
server passes chat_template_kwargs.enable_thinking=false to self-hosted
OpenAI-compatible endpoints (Qwen3-style), suppressing chain-of-thought
to save tokens rather than merely hiding it. Skips the param for
api.openai.com (which would 400) and o1/o3 (always think); templates that
ignore the kwarg simply drop it. Client-side reasoning suppression remains
as a fallback. State persists to localStorage across desktop and mobile.
2026-05-29 11:43:10 -04:00
e50fe6e830
streaming: forward reasoning_content to client as separate channel
Qwen3.x / Deepseek-R1 / o1 stream model thinking via
delta.reasoning_content during SSE; the final answer arrives later via
delta.content. Both server streaming paths (OpenAI client + llama-cpp
Python lib) now extract reasoning_content per chunk and emit it via the
same socketio "message_chunk" event with a `reasoning_content` field
(distinct from `content`). Reasoning is forwarded but NOT accumulated
into the buffer that persists to the DB — it's transient model-private
state, not part of the saved message.

Frontend (templates/chat.html): the message_chunk handler dispatches
on payload shape. On `reasoning_content`: lazy-create a
<details class="message-thinking"> block at the top of the message
wrapper, append text, return early (no buffer/markdown render). On
`content`: if a thinking block exists and is still open, auto-collapse
it to "thinking (click to expand)" before standard content rendering.

If a response never thinks, no thinking DOM element is created — no
visual artefact at all. Compatible with all existing message_chunk
listeners; reasoning_content is purely additive.
2026-05-25 14:49:43 -04:00
8110080a4f fix(code-exec): surface real Unsandbox errors instead of flat 500
/api/code/execute and /api/code/jobs (GET+DELETE) swallowed every
exception into a print() and returned a generic 500, making the
"Failed to execute code" failure undebuggable on deployed boxes
where buffered stdout is lost.

Add _unsandbox_error_response helper: passes the upstream HTTP
status + response body through to the JSON response and prints a
full traceback. Credentials live in request headers, never in
response bodies, so echoing the upstream body exposes no secrets.
2026-05-18 19:07:02 -04:00
8fe489a97c
modified: CLAUDE.md 2026-05-18 15:15:13 -04:00
073f766e6f style: avoid "the", use "our" — writing style rule + sweep 2026-03-31 13:20:21 -04:00
539bd21fce Ignore research/tmp*.yaml generated files 2026-03-16 09:52:30 -04:00
d7fcfc8935 Clean up debug code, keep Send button
Root cause found: uncloseai extension was clobbering window.sendMessage.
Fixed in uncloseai.com repo by namespacing under window.uncloseai.
2026-02-23 19:55:55 -05:00
c06b3706f2 Debug send failure - self-contained handler with visible error output 2026-02-23 19:39:04 -05:00
844ed05cf0 Add Send button and inline keydown handler for chat
Belt-and-suspenders: inline onkeydown on textarea ensures Enter
works regardless of JS event listener registration order, plus
a visible Send button as clickable fallback.
2026-02-23 19:30:00 -05:00
c0ec5ded04 Fix socket.io connection for reverse proxy deployments
Replace deprecated document.domain + port construction with io()
which auto-connects to the serving host regardless of proxy setup.
2026-02-23 19:19:42 -05:00
timehexon
f963cd9443 Replace "AI" with "machine learning" in CLAUDE.md
Machine learning is what we grow. "AI" is forbidden in all
permacomputer discourse, marketing, & documentation.
2026-02-02 19:56:03 +00:00
47bf62ef66 Add streaming TTS using MediaSource API for instant playback
- Audio starts playing as soon as ~1KB arrives instead of waiting for full download
- Browser-aware format detection (webm+opus for Firefox, mp3 for Chrome)
- Falls back to buffered download if MediaSource not supported
- Updated speakText() and speakTextQueued() to use streaming
- Cache blobs instead of Audio objects for cleaner replay
2026-01-28 07:53:11 -05:00
c6e6e81c3c Fix artifact API - use correct parameter and field names
Correct the artifact implementation to match Unsandbox API:
- Request parameter: return_artifact (boolean, singular)
- Response field: artifacts (array, plural)
- Data field: content_base64 (not data/content)

Changes:
- Backend: Changed artifacts to return_artifact in request body
- Frontend: Use return_artifact in execute request
- Frontend: Look for artifacts array in response (not artifact singleton)
- Frontend: Decode content_base64 field (not data/content)
- Frontend: Use filename field (primary) over name
- Remove debug console.log statements
- Update CLAUDE.md with correct API contract

The API parameter is singular but response is plural - this is intentional
design by Unsandbox API. Request enables artifact collection, response
returns array of generated artifacts.
2026-01-20 09:07:25 -05:00
b53ee2168b modified: app.py 2026-01-20 08:58:19 -05:00
acee097d3b Add debug logging for artifact structure
Add console.log statements to see actual artifact object structure:
- Log artifacts array when received
- Log each artifact object and its keys
- Log download attempt with artifact keys and data presence

This will help diagnose why artifacts show metadata but fail on download/view.
2026-01-20 08:50:29 -05:00
7a54952191 Fix artifact handling - use base64 from response payload
Artifacts are returned as base64-encoded data directly in the job response
payload, not as URLs. Previous implementation incorrectly tried to fetch
artifacts from URLs via a proxy endpoint.

Changes:
- Remove /api/code/artifacts proxy endpoint (not needed)
- Update downloadArtifact() to decode base64 and trigger download
- Update viewArtifact() to decode base64 and display inline:
  * Images: rendered as data URLs (data:image/png;base64,...)
  * Videos: decoded to blob URLs with controls
  * Text: decoded and displayed in <pre> blocks
- Update CLAUDE.md with correct artifact format and implementation details
- Add artifact response format example showing base64 data structure

Artifact format in response:
{
  "artifacts": [{
    "name": "output.png",
    "type": "image/png",
    "data": "base64string...",
    "size": 12345
  }]
}
2026-01-20 08:38:37 -05:00
5576179ffa Add comprehensive artifact support for code execution
Implement full artifact support for Unsandbox code execution, enabling
download and inline viewing of generated files (binaries, images, videos).

Backend changes (app.py):
- Update /api/code/execute to accept artifacts parameter
- Add /api/code/artifacts/<path> proxy endpoint for authenticated downloads
- Use SDK's _make_request for full parameter support
- Support artifacts in execution request body

Frontend changes (templates/chat.html):
- Pass artifacts=true in all code execution requests
- Display artifacts section with file info (name, type, size)
- Add download button for all artifact types
- Add view button with inline display for images/videos (disabled for binaries)
- Implement formatFileSize, downloadArtifact, viewArtifact helper functions
- Images and videos render directly in chat
- Text files display in formatted <pre> blocks

Documentation (CLAUDE.md):
- Document artifact support section
- List supported artifact types
- Describe frontend and backend features
- Update frontend integration notes

Artifact types supported:
- Compiled binaries (executables from C, C++, Rust, Go, etc.)
- Images (PNG, JPG, GIF, SVG)
- Videos (MP4, WebM)
- Text/data files (JSON, CSV, TXT)
2026-01-20 08:34:35 -05:00
27a0df3d12 Migrate to official Unsandbox Python SDK
Replace manual HMAC authentication with official Unsandbox Python SDK (un.py).
Simplifies code execution proxy endpoints by using SDK methods: execute_async,
get_job, and cancel_job. Removes ~40 lines of manual HTTP/auth code.

Changes:
- Add official Unsandbox Python SDK (un.py)
- Refactor app.py proxy endpoints to use SDK methods
- Update CLAUDE.md documentation with SDK setup and usage
- Remove manual HMAC signing code
- Maintain backward compatibility with existing API endpoints
2026-01-20 08:21:58 -05:00
a825633be5 Add MODEL_ENDPOINT_0 to functional tests in GitHub Actions 2026-01-11 11:56:08 -05:00
ae875a7269 Exclude venv from flake8 and black in GitHub Actions 2026-01-11 11:55:41 -05:00
237888a6ab Exclude venv from flake8 and black in CI 2026-01-11 11:52:40 -05:00
532523e1b3 Remove GIT_CLEAN_FLAGS 2026-01-11 09:39:14 -05:00
8a77b395a9 Add GIT_CLEAN_FLAGS to clean venvs between CI runs 2026-01-11 09:38:26 -05:00
69703b1e82 Fix test_initialize_model_map_with_env_vars: clear CI env vars 2026-01-11 09:18:55 -05:00
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
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
002e64b6c1 Add random bucket support and comprehensive YAML specification
Random Bucket System:
- Probabilistic events that trigger alongside user responses
- Random rolls before categorization to prevent AI bias
- Multiple random events can trigger simultaneously
- User bucket processed first, random events layer on top
- Metadata accumulates across all transitions
- Last transition's navigation wins

Implementation:
- activity.py: Core random bucket rolling logic
- activity_yaml_validator.py: Validation for random_buckets config
- research/guarded_ai.py: CLI simulator with random event display
- tests/unit/test_random_buckets.py: 22 comprehensive tests (all passing)

Fashion Empire Enhancement:
- activity40-fashion-empire-backrooms.yaml: Added random events to 4 zones
  - fashion_emergency (5%): Urgent crises testing leadership
  - creative_opportunity (10%): Breakthroughs rewarding innovation
  - surprise_client (5%): VIP visitors recognizing reputation
- Random events enhance gameplay without hijacking user intent

Documentation:
- research/SPEC.yaml: Complete YAML specification with verbose comments
  - All metadata operations (string concat, numeric ops, random)
  - Random buckets with flow explanation
  - Feedback prompts (multi-agent system)
  - Processing scripts (pre_script, processing_script)
  - Model overrides (classifier_model, feedback_model)
  - Termination patterns and best practices
  - Validation rules and examples

New Activities:
- activity-nuclear-power-plant-ai.yaml: Nuclear reactor control simulation
- activity-submarine-simulation.yaml: Deep sea exploration
- activity-unwaste-factory.yaml: Recycling facility management

Testing:
 All 22 random bucket tests passing
 YAML validation passing for all activities
 Deterministic triple-trigger test (100% probability)
2025-11-10 08:57:14 -05:00
ff69d2ec5f
Merge pull request #28 from russellballestrini/claude/biblical-time-machine-activity-011CUz9eUAXGD4MS8gjgAkxU
Build Biblical Time Machine Conversation Game
2025-11-10 08:42:26 -05:00
Claude
33c90b99b0
Expand Biblical time machine to global spiritual time machine
Major expansion to support travel to ANY location during biblical timeline:

NEW REGIONS SUPPORTED:
- Biblical Lands: All biblical eras from Garden of Eden to persecution
- Greece: Philosophers (Socrates, Plato, Aristotle), mystery religions, gods
- Rome: Stoics, emperors, gladiators, early Christians, Roman religion
- India: Buddhist monks, Hindu gurus, yogis, karma/reincarnation
- China: Confucius, Laozi, Taoism, Confucianism, ancestor worship
- Persia: Zoroastrian magi, fire temples, dualism
- Other: Arabia, Africa, Britain, Celtic druids, etc.

KEY FEATURES:
- Geography-aware classifier: Detects both TIME and PLACE from user input
- Dynamic briefings: AI generates context for any location/time combination
- Examples: "30 AD Greece" → Athens philosophers, "500 BC India" → Buddhist monks
- NPC system supports non-biblical spiritual figures
- Conversation system respects all spiritual traditions
- Maintains Temple accuracy for biblical lands

EXAMPLES NOW WORK:
- "Take me to 30 AD Greece" → Meet Stoic philosophers
- "500 BC India" → Meet Buddha's followers
- "Moses" → Egypt ~1446 BC
- "Socrates" → Athens ~400 BC
- "Confucius" → China ~500 BC
- "Garden of Eden" → Paradise before Fall ~4000 BC

File: 662 lines (was 532), validates with 0 errors
2025-11-10 13:33:50 +00:00
Claude
6fcf5502e0
Rewrite Biblical time machine to truly open-ended format
Major changes:
- Reduced from 1608 to 532 lines (70% reduction)
- Single open-ended question: "Where/who/when would you like to visit?"
- AI dynamically determines era from ANY input (person, date, event, place)
- Replaced static content_blocks with dynamic ai_feedback briefings
- User can say "I want to meet Moses" → AI determines ~1446 BC Egypt
- User can say "30 AD" → AI determines Jesus' ministry
- User can say "Red Sea crossing" → AI determines Exodus event
- Open-ended NPC selection and conversation system
- Maintains location accuracy (Temple progression throughout history)
- Focus on AI-driven responses over rigid menu structure

User feedback: "feedback over heavy content... needs to be open ended"
2025-11-10 12:45:39 +00:00
Claude
3930a99a5d
Add detailed departure briefings to time machine transitions
Each time travel destination now includes comprehensive briefing:

**Briefing Format:**
- Destination (geographic location)
- Time Period (specific dates)
- Biblical Reference (relevant scripture)
- What You'll Experience (historical context, key events, atmosphere)
- Important/Critical Location Notes (especially Temple status)

**Educational Enhancements:**

Garden of Eden:
- Explains it's before sin, perfect creation
- Notes no buildings/cities exist yet

Fall & Early World:
- Describes life after sin entered
- Notes Cain/Abel, first altars, long lifespans

Egypt & Exodus:
- **CRITICAL:** Emphasizes NO Temple for 500+ more years
- Explains Moses uses simple altars
- Egyptian temples to Ra/Osiris present

Solomon's Temple:
- **HISTORIC MOMENT:** FIRST Temple after 480 years!
- Describes gold overlay, Ark location
- This is what Moses and David longed for

Jesus' Ministry:
- SECOND Temple (Herod's) stands
- Jesus prophesies its destruction
- Will be gone in 40 years (70 AD)

Roman Persecution:
- NO Temple (destroyed 70 AD)
- Christians meet in catacombs
- Fish symbol as secret sign

Makes Temple progression crystal clear: none → altars → First Temple → Second Temple → destroyed → underground faith.

Users now understand WHEN and WHERE they're going before arrival.
2025-11-10 12:40:06 +00:00
Claude
dc06025b59
Expand Biblical Time Machine: Garden of Eden to persecution, open-ended NPCs, location accuracy
COMPLETE REWRITE with all requested features:

**Starts at the Beginning:**
- Garden of Eden (Paradise before sin)
- Fall & Early World (Cain, Abel, Enoch)

**Covers Full Bible Chronologically:**
- Egypt & Exodus (~1446 BC)
- Solomon's Temple (~970 BC)
- Life of Jesus (~30 AD)
- Persecution & Martyrdom (~64-313 AD)

**Open-Ended NPC Selection:**
- Users can request ANY biblical figure from each era
- AI dynamically rolepl ays any character accurately
- Suggestions provided but not limiting
- Examples: "Moses", "Queen of Sheba", "a Hebrew slave"

**Historically Accurate Locations:**
- Garden of Eden: NO buildings, only perfect nature
- Egypt: NO Temple to YHWH (only altars, won't exist for 500+ years)
- Solomon: FIRST Temple in all its glory
- Jesus' time: SECOND Temple (Herod's Temple)
- Persecution: NO Temple (destroyed 70 AD), catacombs instead

**Features:**
- 1608 lines, 9 sections, 25 steps
- Metadata tracking (epochs visited, people met)
- Multilingual support
- Looping time machine hub
- Biblically accurate character portrayals
- Scripture references throughout

Demonstrates location accuracy progression: no temple → Tabernacle/altars → First Temple → Second Temple → no temple (destroyed) → faith survives underground.
2025-11-10 12:29:42 +00:00
Claude
79c072abec
Add extensive Biblical Time Machine activity
Create immersive time travel experience through key Biblical epochs:
- Egypt & Exodus: Meet Moses, Pharaoh, Hebrew slaves, Aaron
- Kingdom of David: Visit King David, Prophet Nathan, musicians, citizens
- Life of Jesus: Walk with Jesus, disciples, Mary Magdalene, crowds
- Pentecost & Early Church: Experience Holy Spirit, meet apostles and converts
- Roman Persecution: Stand with martyrs, Paul, persecuted believers

Features:
- Time machine hub for epoch selection
- Multiple NPCs per epoch with unique personalities
- Biblically accurate dialogue and references
- Metadata tracking for journey statistics
- Looping mechanism to revisit epochs
- Final reflection on spiritual journey

The activity maintains historical accuracy while being engaging and educational.
2025-11-10 11:48:58 +00:00
d02ad855fd
Merge pull request #27 from russellballestrini/claude/expand-fashion-activity-011CUyyXxXyVV3TgwysppcCi
Expand fashion activity to backrooms setting
2025-11-10 05:31:46 -05:00
Claude
09202d31dc
Expand fashion activity into immersive backrooms empire management game
Create activity40-fashion-empire-backrooms.yaml with:

Features:
- Player is a girl running her own fashion brand underground
- Backrooms aesthetic: liminal warehouse spaces, mysterious locations
- 4 explorable locations: Warehouse Level -3, The Salon, Sub Bay (underwater lab), Reactor Atelier (nuclear power)
- Full control over 70+ robots and NPC employees (Zara-7, Viktor, Mx. Kai, Luna & Sol)
- Mission-based gameplay (15% tasks, 5% emergencies)
- Player makes creative, leadership, and strategic decisions

Locations:
- Warehouse Level -3: Storage backrooms, assembly drones, fabric management
- The Salon: Creative hub, style bots, runway preparation
- Sub Bay: Underwater dye laboratory, bioluminescent experiments, submersibles
- Reactor Atelier: Nuclear-powered textile synthesis, atomic fabric manipulation

Gameplay:
- Choose locations via central elevator
- Complete missions (color selection, robot commands, textile treatments, power management)
- Handle emergencies (fabric contamination crisis with multiple solutions)
- Manage NPCs and give directives
- Make creative vision decisions for runway shows
- Culminates in Neon Dreams runway show featuring player's choices
- Player sees their vision realized through their empire

All transitions validated, proper termination, educational about fashion + leadership
2025-11-10 09:37:07 +00:00
6bc896b9b0 Fix TTS voice selection validation breaking API calls
Remove obsolete VALID_VOICES validation that was rejecting the new
"model:voice" format from the voices endpoint integration. The old
validation expected simple voice names like "onyx" but the new format
uses "tts-1:onyx", causing validation to fail and produce malformed
API requests that returned HTTP 400 errors.

Changes:
- Remove VALID_VOICES constant (no longer needed)
- Update syncInputsAndQueryString() to accept any voice value from dropdown
- Default to "tts-1:onyx" format if no value present

Fixes the TTS errors seen in production where voice selection was
failing with HTTP 400 status.
2025-11-09 15:32:38 -05:00
33a6eaa215
Merge pull request #26 from russellballestrini/claude/integrate-voices-endpoint-011CUxuw49z1GN41YMxKoq3C
Integrate new voices API endpoint
2025-11-09 15:26:52 -05:00
Claude
d7ea04a3f9
Integrate voices endpoint with dynamic model and voice selection
Update TTS implementation to fetch available voices from the API and
support multiple TTS models:

- Add VOICES_API_URL constant for /v1/voices endpoint
- Create populateVoiceDropdown() to dynamically populate voice options
- Group voices by model using optgroups in the dropdown
- Implement voice fetching with localStorage caching (1 minute)
- Update speakText() to parse model:voice from dropdown value
- Update speakTextQueued() to use dynamic model and voice
- Add backward compatibility for legacy voice-only format
- Update both desktop and mobile voice selectors
- Add fallback to tts-1:onyx if voice fetch fails

Voice dropdown now displays all available models (tts-1, tts-1-hd,
tts-1-silero, tts-1-kokoro) with their respective voices organized
by optgroups for better UX.
2025-11-09 20:08:37 +00:00
fafaf1557f
Merge pull request #25 from russellballestrini/claude/dinosaur-time-machine-011CUxk9UNRz6vj4pZv5K8R8
Build interactive dinosaur time machine explorer
2025-11-09 13:52:47 -05:00
15e235d7c0
Merge pull request #24 from russellballestrini/claude/solar-system-explorer-011CUxhwWXbNR5iKFzq6St7o
Build interactive solar system explorer
2025-11-09 13:03:49 -05:00
Claude
8d22bfa388
Add comprehensive dinosaur time machine educational activity
This activity provides an immersive, open-ended exploration of Earth's
prehistoric eras where users can:

- Travel through Triassic, Jurassic, and Cretaceous periods
- Explore climate, geography, dinosaurs, marine reptiles, and pterosaurs
- Learn about specific creatures on demand
- Understand the evolution of life and flowering plants
- Witness the K-T extinction event
- Jump freely between time periods

Features:
- Central "control room" hub for navigation
- Detailed information about 30+ dinosaurs and creatures
- Covers vegetation changes including flowering plant revolution
- Open-ended exploration with AI-guided learning
- Comprehensive extinction event explanation
- Supports looping and non-linear exploration

The activity validates successfully and follows best practices for
engagement, education, and proper termination.
2025-11-09 18:00:03 +00:00
Claude
2f34365fd5
Add back-to-planet navigation from moons to host planet
Enhanced moon navigation to allow easy return to the host planet's details.
Previously, moon navigation only had "leave_jupiter" which took you to the
final navigation menu. Now you can also go back to see the planet itself.

New Navigation Pattern (implemented for Jupiter's moons):

From any moon, you can now:
1. **Jump to other moons** - "Europa", "Ganymede", etc.
2. **Return to moon menu** - "moon menu" shows all moon options
3. **Back to planet** - "Jupiter" or "back to Jupiter" returns to planet details
4. **Leave entirely** - "leave Jupiter" goes to planet-to-planet navigation

Example Navigation Flow:
- Visit Jupiter → See planet details
- Choose "Io" → See Io's volcanoes
- Say "back to Jupiter" → Return to Jupiter's details (storms, bands, etc.)
- Say "Europa" → Jump directly to Europa
- Say "leave Jupiter" → Continue to Saturn

Updated Navigation Steps:
- moon_io_nav: Added back_to_planet → jupiter:jupiter_details
- moon_europa_nav: Added back_to_planet → jupiter:jupiter_details
- moon_ganymede_nav: Added back_to_planet → jupiter:jupiter_details
- moon_callisto_nav: Added back_to_planet → jupiter:jupiter_details
- jupiter_other_moons_nav: Added back_to_planet → jupiter:jupiter_details

This same pattern can be extended to Saturn, Uranus, and Neptune moons,
allowing seamless navigation: Moon → Moon, Moon → Planet, Planet → Planet.
2025-11-09 17:59:03 +00:00
Claude
ecc2122e1a
Add interactive moon navigation to Solar System Explorer
Enhanced the Solar System Explorer with comprehensive moon navigation menus,
allowing users to jump freely between moons within each planet's system.

New Navigation Features:
- Moon selection menus after each planet's moon intro
- Individual navigation after each moon's details
- Ability to jump directly to any moon or back to the menu
- "Stay" option to ask questions without penalty

Jupiter (95 moons):
- Moon menu: Choose Io, Europa, Ganymede, Callisto, or other moons
- Navigation after each Galilean moon
- Can jump between any moons freely

Saturn (146 moons):
- Moon menu: Choose Titan, Enceladus, Mimas, or other moons
- Navigation after each major moon
- Jump between moons or back to menu

Uranus (28 moons):
- Moon menu: Choose Miranda or other major moons
- Navigation from Miranda to other moons
- Can explore Ariel, Umbriel, Titania, Oberon via other moons

Neptune (16 moons):
- Moon menu: Choose Triton or other moons
- Navigation after Triton
- Can jump back to major moon or continue journey

Example Usage:
1. Visit Jupiter → Choose moon menu
2. Say "Europa" → See Europa details
3. Say "I want to see Io" → Jump directly to Io
4. Say "moon menu" → Back to selection
5. Say "other moons" → See smaller moons
6. Say "leave Jupiter" → Continue to Saturn

This makes exploration truly non-linear and interactive, exactly as
requested for exploring moons like jumping between Uranus's moons!
2025-11-09 17:54:01 +00:00
Claude
45fc9d6c9d
Add comprehensive Solar System Explorer activity
Created an interactive, open-ended educational activity that allows students to explore the entire solar system at their own pace.

Features:
- Complete coverage of all major celestial bodies
- The Sun with detailed structure and solar activity
- All 8 planets with comprehensive details
- 200+ moons documented with attributes:
  - Jupiter's 95 moons (4 Galilean moons + others)
  - Saturn's 146 moons (Titan, Enceladus, Mimas, etc.)
  - Uranus's 28 moons (Miranda and major moons)
  - Neptune's 16 moons (Triton and others)
  - Earth's Moon, Mars's Phobos & Deimos
- Asteroid Belt (Ceres, Vesta, Pallas, Hygiea)
- Kuiper Belt (Pluto, Eris, Makemake, Haumea, etc.)

Activity Structure:
- 13 main sections (Introduction, Sun, 8 planets, Asteroid Belt, Kuiper Belt, Conclusion)
- Non-linear exploration - jump to any location at any time
- Detailed scientific information with current data
- Engaging presentation with emojis and formatting
- Educational content based on latest discoveries (New Horizons, Cassini, Juno missions)

Technical:
- Fully validated YAML structure
- All transitions properly mapped
- Proper termination paths
- Interactive Q&A at each location
- "Stay" option allows asking questions without counting as attempts

Perfect for astronomy education and space exploration learning!
2025-11-09 17:33:17 +00:00
0a338e9166
Merge pull request #23 from russellballestrini/claude/update-claude-md-agents-011CUxUXaHNttGa2q92LjGjV
Update CLAUDE.md for agent expertise
2025-11-09 12:24:49 -05:00
Claude
fd6360d7d8
Add 4 advanced programming activities with algorithm education
NEW ACTIVITIES:

activity48-monty-hall-simulation.yaml - Monty Hall paradox proof
- Simulate stay vs switch strategies
- Prove switching wins 2/3 through code
- Any programming language support

activity49-multi-armed-bandit.yaml - Adaptive algorithms beat A/B testing
- Epsilon-greedy implementation
- 88% regret reduction vs traditional A/B
- Real-world applications (web optimization, clinical trials)

activity50-genetic-algorithms.yaml - Evolution-based optimization
- String evolution challenge
- Fitness, selection, crossover, mutation
- 803,181x faster than brute force

activity51-connect-four.yaml - Complete game development
- 2D arrays and game state
- Win detection algorithms (horizontal, vertical, diagonal)
- Full game loop implementation

All activities:
- Support ANY programming language choice
- Follow pedagogical best practices (concepts first, code in feedback)
- Validate with zero errors/warnings
- Engaging and fun (aha moments, real games, simulations)
2025-11-09 16:07:15 +00:00
Claude
4e72fed8be
Add game theory programming courses for Python and C
NEW ACTIVITIES:

activity46-game-theory-python.yaml - Game theory implementation in Python
- Representing games with dictionaries
- Payoff matrix as dict with tuple keys
- Query functions and game simulation
- One-shot and repeated games
- Tit-for-Tat strategy implementation
- Function composition and abstraction

activity47-game-theory-c.yaml - Game theory implementation in C
- Defining Payoff struct for outcomes
- 2D arrays for payoff matrices
- Memory-efficient game representation
- Strategy lookup functions
- Enum for self-documenting code
- Pointer and struct fundamentals

Both activities:
- Teach programming through game theory concepts
- Follow pedagogical best practice (concepts first, code examples in feedback)
- Validate with zero errors/warnings
- Progressive difficulty (structures → functions → simulation)
- Real-world application of abstract concepts
- Engage students with strategic thinking + coding
2025-11-09 15:36:12 +00:00
Claude
b8bf7261cb
Add complete statistics and game theory curriculum (6 activities)
NEW ACTIVITIES:

activity40-statistics-101.yaml - Foundational statistics
- Central tendency, spread, probability, distributions
- Real-world applications and critical thinking

activity41-game-theory-101.yaml - Strategic fundamentals
- Prisoner's Dilemma, Nash Equilibrium, dominant strategies

activity42-game-theory-201.yaml - Advanced concepts
- Mixed strategies, repeated games, Tit-for-Tat

activity43-game-theory-301.yaml - Cooperative games
- Coalition formation, Shapley value, fair division

activity44-game-theory-401.yaml - Information asymmetry
- Signaling, screening, adverse selection

activity45-game-theory-501.yaml - Mechanism design
- Auction theory, Vickrey auctions, incentive compatibility

All activities:
- Validate with zero errors/warnings
- Follow expert guide requirements
- Include engaging examples
- Terminate properly
- Support language switching
2025-11-09 15:27:38 +00:00
Claude
31e357e8bf
Add statistics and game theory 101 activities plus pedagogical fixes 2025-11-09 15:25:04 +00:00
Claude
e4ab13ae78
Fix pedagogical issue: Don't show code examples before asking students to write code
PROBLEM: activity37 was showing complete code examples in Python, JavaScript,
Java, and C++ BEFORE asking students to write code themselves. This turns
learning into copy-paste practice.

FIXED:
- Hello World section: Removed multi-language code examples from content_blocks
- Variables section: Removed multi-language code examples from content_blocks
- Now explains CONCEPTS (what, why, how languages differ) without showing syntax
- Code examples remain in AI feedback for when students struggle or ask for help

PEDAGOGICAL APPROACH:
1. Explain the concept (stdout, variables, etc.)
2. Explain language differences conceptually (dynamic vs static typing)
3. Ask students to TRY writing code in THEIR language
4. Provide language-specific examples in AI FEEDBACK if they struggle

This way students actually have to THINK and LEARN, not just copy.

UPDATED CLAUDE.md:
- Added new pitfall: "Showing answers before questions"
- Guidance: Explain concepts in content_blocks, provide code examples in ai_feedback

Still validates perfectly with zero errors/warnings.
2025-11-09 15:09:50 +00:00
Claude
10d0ec27a2
Add two fashion activities: modern style and historical journey
activity38-fashion-today.yaml - Fun, interactive style discovery
- Personal style identification (classic, boho, streetwear, etc.)
- Color psychology and preferences
- Outfit building for occasions
- Statement pieces and accessories
- Fashion philosophy reflection
- Encourages self-expression and confidence

activity39-fashion-history.yaml - Educational timeline 1800-2025
- Victorian era corsets and social restrictions
- 1920s flappers and women's liberation
- WWII rationing and practical fashion
- 1950s ultra-femininity and gender politics
- 1960s-70s revolution (mod, hippie, disco, punk)
- 1980s excess and 1990s grunge backlash
- 2000s-2010s fast fashion and social media
- 2020s sustainability, inclusivity, technology
- Critical thinking about fashion as social mirror

Both activities:
- Follow expert guide validation requirements
- Include engaging content with emojis and formatting
- Support language switching
- Use metadata strategically
- Have multiple response paths with tailored feedback
- Terminate properly with activity_completed markers
- Passed activity_yaml_validator.py with zero errors/warnings
2025-11-09 14:50:04 +00:00
Claude
3df69c83cd
Add comprehensive activity creation expert guide to CLAUDE.md
This guide empowers agents to create activities that validate properly,
are fun and engaging, and terminate correctly.

Key additions:
- Core activity structure with detailed examples
- Critical validation requirements checklist
- Four termination patterns with code examples
- Ten engagement techniques from successful activities
- Best practices for activity development
- Common pitfalls table with fixes
- Complete development workflow
- Quick reference for essential fields
- Minimal working activity example

References activity26-magic-8-ball.yaml, activity31-scientific-method.yaml,
and activity37-programming-languages.yaml as exemplary activities.
2025-11-09 14:36:10 +00:00
698857e04e
Merge pull request #22 from russellballestrini/claude/review-research-directory-011CUxEBYqsik2pWtWM3UufC
Review Research Directory Structure
2025-11-09 09:28:48 -05:00
Claude
cfc2a8ad08
Expand stdout explanation with comprehensive technical details
- Added 53 new lines of stdout/standard output explanation
- Broke down terminology: standard, output, stdout/STDOUT
- Explained the three standard streams (stdin, stdout, stderr)
- Added visual diagram of stdout flow
- Included Unix/1970s historical context
- Explained why it's called "standard"
- Added advanced redirection concepts (pipes, file redirection)
- Total file now 1,948 lines (up from 1,895)
- Validation passed successfully
2025-11-09 11:56:22 +00:00
Claude
3ef98143b2
Expand activity37 with comprehensive fundamental explanations
- Increased from 1,148 to 1,895 lines (+65%)
- Added detailed explanations before each coding exercise
- Enhanced Hello World section with stdout concepts and multi-language examples
- Expanded Variables section with box analogy, naming rules, and typing differences
- Enhanced Data Types with comprehensive type explanations and string formatting
- Expanded If Statements with conditional logic fundamentals and comparison operators
- Enhanced Loops with detailed for loop explanations, execution traces, and common patterns
- Expanded Functions with DRY principle, parameter explanations, and best practices
- Enhanced Return Values with display vs return differences and common mistakes
- All sections now teach fundamentals thoroughly before asking students to code
- Validation passed successfully
2025-11-09 11:31:28 +00:00
9ad911c615
Merge pull request #21 from russellballestrini/claude/merge-new-yamls-011CUwF3BsT47vPjtkvSq2r7
Merge new YAML configuration files
2025-11-08 18:04:53 -05:00
c294814e60
Delete fix_all_new_activities.py 2025-11-08 18:04:26 -05:00
0b41cab970
Delete fix_activity37.py 2025-11-08 18:04:13 -05:00
Claude
6fa1b15188
Add auto-growing textarea for chat input
- Textarea now automatically expands as user types multiline messages
- Resets to minimum height after message is sent
- CSS: Set min-height (60px) and max-height (400px) with auto overflow
- Removed fixed rows attribute to allow dynamic height
- Disabled manual resize to prevent user confusion
- Provides better UX for composing longer messages
2025-11-08 23:02:24 +00:00
Claude
0560de004d
Add fix scripts for activity YAML corrections
These scripts document the automated fixes applied to activities 30-37:
- fix_activity37.py: Changes 'close' bucket behavior + fixes completion
- fix_all_new_activities.py: Fixes final step completion for all activities

Keeping for reference and potential reuse on future activities.
2025-11-08 23:00:01 +00:00
Claude
f774d36d74
Fix activity completion and progression issues in activities 30-37
This commit addresses two critical issues:

1. Completion Bug (activities 30-37):
   - Final steps were looping forever, preventing activity completion
   - Fixed by removing next_section_and_step from completion transitions
   - Kept off_topic transition looping to avoid validator terminal step errors
   - Activities now complete properly when users give valid final answers

2. Activity37 Bucket Logic:
   - Changed "close" bucket to retry same step instead of advancing
   - Only "correct" bucket now advances to next step
   - All other buckets (close, incomplete, wrong_language, etc.) retry
   - This ensures students must get correct answers to progress

Technical Details:
- Final steps are not considered "terminal" if at least one transition
  has next_section_and_step (validator requirement)
- Off-topic transitions loop back to allow another attempt
- Completion happens when get_next_step() returns None, None

Validation:
- All 8 activities pass activity_yaml_validator.py
- No errors or warnings

Affects: activity30-37 (all new merged activities)
2025-11-08 22:59:06 +00:00
08bbc47a6b
Merge pull request #20 from russellballestrini/claude/expand-research-yamls-011CUvoNn9xvytg4xr5eJ7Rx
Generate synthetic activities from research YAMLs
2025-11-08 15:07:53 -05:00
Claude
fd78927e7c
Fix MODEL_X references to use dynamic model registry
When MODEL_X references (MODEL_0, MODEL_1, etc.) are used, the code now
properly looks up actual model names from the dynamic registry (MODEL_CLIENT_MAP)
instead of hardcoding "model" or requiring MODEL_NAME_X environment variables.

Changes:
- app.py: Look up models from MODEL_CLIENT_MAP for the specified endpoint
- guarded_ai.py: Query endpoints for actual model names at initialization
- guarded_ai.py: Use dynamic registry for MODEL_X lookups

This fixes the "model not found" error when using activities with MODEL_X
references like activity37.
2025-11-08 19:58:21 +00:00
Claude
3c3b8bd493
Change default model from MODEL_1 to MODEL_0 to match stable config
Respects existing stable configuration where:
- MODEL_0 = Hermes (default for classification and feedback)
- MODEL_1 = Qwen (for code generation)
- MODEL_2 = GPT

Updated:
- All function defaults in activity.py: MODEL_1 -> MODEL_0
- activity37: Uses MODEL_0 for classification, MODEL_1 for code feedback

This works with the existing environment variable setup without requiring changes to vars.sh.
2025-11-08 19:53:46 +00:00
Claude
8cebcbf118
Add MODEL_X reference support to app.py
Critical fix for activity model configuration:
- Handle MODEL_1, MODEL_2, MODEL_3 references in get_openai_client_and_model()
- Look up MODEL_ENDPOINT_{n}, MODEL_API_KEY_{n}, MODEL_NAME_{n} from environment
- Fall back gracefully to default model if MODEL_{n} not configured
- Matches implementation in research/guarded_ai.py

Fixes error: 'NoneType' object has no attribute 'chat'
This error occurred when activities tried to use classifier_model="MODEL_1"
but the app didn't know how to resolve the MODEL_X reference.

Now activity37 (programming languages) will work correctly with:
- classifier_model: "MODEL_1" (Hermes for classification)
- feedback_model: "MODEL_3" (Qwen3-Coder for code generation)
2025-11-08 19:47:32 +00:00
Claude
0f06772afb
Fix critical model name issue and validator warning
Critical fix for guarded_ai.py:
- Add MODEL_NAME_{n} environment variable support
- Fixes hard-coded "model" string that breaks Azure OpenAI and other endpoints
- Falls back to "model" if MODEL_NAME_{n} not specified
- Some endpoints require actual deployment name in model parameter

Validator improvement:
- Allow feedback_prompts as alternative to feedback_tokens_for_ai
- Prevents false warning when using metadata_feedback_filter with new prompt system

Documentation:
- Added MODEL_NAME_{n} examples to CLAUDE.md
- Documented that Azure and similar endpoints need this variable

All 8 activities validated: 0 errors, 0 warnings
2025-11-08 19:38:15 +00:00
Claude
82aeeab094
Document classifier_model and feedback_model in CLAUDE.md
Added comprehensive Activity YAML Schema section covering:
- Model Configuration feature (classifier_model and feedback_model)
- Why separate models (speed, quality, cost, flexibility)
- Model defaults (MODEL_1/Hermes as universal default)
- Recommended model combinations table
- Environment variable configuration
- Example programming activity with dual models
- Activity YAML validation instructions
- CLI testing with model configuration
- Qwen3-Coder-30B setup guide (llama.cpp and ollama)

This documents the new dual-model architecture that allows:
- Fast classification with Hermes (8B)
- Specialized feedback with domain models (e.g., Qwen3-Coder 30B)
- Activity and step-level model overrides
2025-11-08 19:34:00 +00:00
Claude
1c5a4960fd
Update NEW_ACTIVITIES_PLAN.md with completion status
Transformed planning document into comprehensive completion report:
- Status: 8 activities completed (30-37), 6,112 lines of YAML
- Documented new classifier_model and feedback_model feature
- Added model setup guide for Qwen3-Coder-30B
- Detailed activity summaries with special features
- Technical architecture and implementation decisions
- Usage examples and future enhancements

Key highlights:
- All activities validated with 0 errors
- Dual-model architecture explained
- Activity 37 flagship feature: universal programming language support
- Hermes excellence in role-playing scenarios
2025-11-08 19:32:00 +00:00
Claude
f87824bc56
Add Qwen3-Coder-30B setup documentation to activity37
Added detailed comments showing how to use the recommended model:
- hf.co/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M
- Setup instructions for llama.cpp (with GPU offloading)
- Alternative setup with ollama
- Environment variable configuration examples

This 30B parameter model is specifically optimized for code generation
across all programming languages, making it perfect for the universal
programming activity.
2025-11-08 19:27:27 +00:00
Claude
c51b2c7900
Update guarded_ai.py to support classifier_model and feedback_model
Changes:
- Enhanced get_openai_client_and_model() to support MODEL_X references
- Added model parameter (default "MODEL_1") to all AI functions:
  - categorize_response()
  - generate_ai_feedback()
  - provide_feedback()
  - provide_feedback_prompts()
  - translate_text()
- Updated simulate_activity() to:
  - Read classifier_model and feedback_model from YAML
  - Support step-level model overrides
  - Pass appropriate models to classifier vs feedback functions

This ensures the CLI simulation tool matches the production activity.py behavior.
2025-11-08 19:23:29 +00:00
Claude
e3c1547a0f
Set Hermes (MODEL_1) as default for all model parameters
Hermes is always available in every install, making it the perfect default.
All model parameters now default to "MODEL_1" instead of None:
- classifier_model: Fast, accurate classification
- feedback_model: Great for role-playing and general feedback

Activities can still override these defaults:
- At activity level for all steps
- At step level for specific interactions

This ensures activities work out-of-the-box without requiring model configuration.
2025-11-08 19:08:23 +00:00
Claude
1c347ea060
Add classifier_model and feedback_model support to YAML schema
Allow activities to specify separate models for classification and feedback:
- classifier_model: Used for categorizing user responses into buckets
- feedback_model: Used for generating AI feedback and translations

Both fields can be set at activity level (defaults) and overridden at step level.

Updated activity37 to use:
- MODEL_1 (Hermes) for classification
- MODEL_3 (Qwen 3 Coder) for feedback

This allows using specialized models for different tasks, e.g., fast classification
with accurate feedback generation from domain-specific models.
2025-11-08 18:58:29 +00:00
Claude
11e705be97
Add 3 extensive educational activities (American History, Biblical History, Programming)
Created 3 comprehensive educational activities without embedded Python:

1. activity35-american-history.yaml - Advanced American History for gifted students
   - Founding principles and Constitutional design
   - Civil War causes and Reconstruction failure
   - Civil Rights Movement strategies
   - Primary source analysis and critical historical thinking
   - Connects past to present issues

2. activity36-biblical-history.yaml - Biblical History & Ancient Near East
   - Ancient Near Eastern context (Mesopotamia, Egypt, Canaan)
   - Archaeological evidence and historical reconstruction
   - Israelite history (Exodus, Monarchy, Exile)
   - Roman period and early Christianity
   - Foundation myths vs historical facts
   - Cultural adaptation and religious transformation

3. activity37-programming-languages.yaml - Universal Programming Concepts
   - Student chooses ANY programming language (Python, C++, COBOL, anything)
   - AI adapts all examples/feedback to chosen language via metadata
   - Covers: stdout/output, variables, data types, control flow, loops, functions
   - All examples use stdout to display messages
   - Concepts applicable to every language
   - Language-specific syntax provided by AI

All activities:
- Use only YAML features (no embedded Python)
- Validate successfully with 0 errors
- Provide sophisticated educational content
- Use AI feedback for personalization
- Include critical thinking and reflection
- Track progress via metadata

Total: 8 new educational activities across 2 commits (5 from previous commit + 3 now)
2025-11-08 18:47:31 +00:00
1a9be3c420
Merge pull request #19 from russellballestrini/claude/fix-dark-mode-scrollbars-011CUvsF4XTDVgET5n5Prtjd
Fix scrollbars appearance in dark mode
2025-11-08 13:44:47 -05:00
Claude
31152c295b
Refactor CSS from inline to external stylesheet
Move all CSS from base.html to static/css/style.css for better:
- Separation of concerns
- Browser caching
- Maintainability
- Code organization

Changes:
- Created static/css/style.css with all application styles
- Updated base.html to link to external stylesheet
- Reduced base.html from ~980 to ~407 lines
2025-11-08 18:41:56 +00:00
Claude
0ecf6f9bca
Improve dark mode scrollbar styling for Chrome
Add custom scrollbar styles that properly match dark and light themes:
- Webkit browsers: styled scrollbars with theme-appropriate colors
- Firefox: thin scrollbars with matching color scheme
- Dark mode: darker gray scrollbars that blend with the UI
- Light mode: light gray scrollbars for better visibility
2025-11-08 18:07:46 +00:00
Claude
b9d278c01c
Add venv/ to .gitignore 2025-11-08 17:36:05 +00:00
Claude
994d5e5de9
Add 5 new educational activities without embedded Python
Created 5 comprehensive educational activities that use only YAML features
(buckets, transitions, metadata operations, AI feedback) without Python scripts:

- activity30-logic-puzzles.yaml: Critical thinking through deductive reasoning,
  contrapositives, syllogisms, and knights/knaves puzzles

- activity31-scientific-method.yaml: Learn scientific method through historical
  case studies (Semmelweis, Newton) and experimental design principles

- activity32-world-geography.yaml: Choose-your-own-adventure journey exploring
  continents, countries, capitals, and cultural facts

- activity33-environmental-science.yaml: Role-playing as environmental consultant
  making sustainability decisions on transportation, energy, land use, waste, and food

- activity34-media-literacy.yaml: Develop critical media consumption skills,
  evaluate sources, recognize bias, fact-check claims, and spot manipulation

All activities:
- Follow existing YAML schema and validate successfully
- Use Socratic buckets for educational feedback
- Include set_language support
- Track progress via metadata
- Provide AI-generated personalized feedback
- Are educational, engaging, and progressively challenging
- Include final reflection steps

Also added NEW_ACTIVITIES_PLAN.md documenting the planning process and
design rationale for each activity.
2025-11-08 17:34:33 +00:00
ed63672e66
Merge pull request #18 from russellballestrini/claude/improve-dark-mode-output-011CUvnEP44R3WNw6F9qQxiP
Improve dark mode styling and readability
2025-11-08 12:06:44 -05:00
Claude
6402fdb139
Improve link colors for dark mode visibility
Added CSS variables for link colors with better contrast:
- Light mode: #0066cc (normal), #004499 (hover)
- Dark mode: #58a6ff (normal), #79b8ff (hover)

Applied general link styling rules that adapt to both themes,
ensuring links are clearly visible and distinguishable in dark mode.
2025-11-08 17:06:27 +00:00
Claude
5a74092c77
Improve code execution output styling for dark mode
Added CSS variables for code execution result colors that adapt to theme:
- --text-info: Blue for informational text (language labels)
- --text-success: Green for successful output
- --text-error: Red for errors and warnings

Updated JavaScript to use CSS variables instead of hard-coded colors,
ensuring proper contrast and readability in both light and dark modes.
2025-11-08 17:03:50 +00:00
44ae3dd882
Merge pull request #17 from russellballestrini/claude/improve-theme-011CUvhRSTfsJnZzFkVBuiK5
Find Better Theme for Project
2025-11-08 11:11:25 -05:00
6f06e43cbb
Merge pull request #16 from russellballestrini/claude/opencompletion-ex-makeover-011CUvXcfjHUFytTM7B4C6UR
Tests
2025-11-08 11:09:07 -05:00
Claude
9df6a8b8fa
Improve exception handling in integration test tearDown methods
Address CodeRabbit feedback by replacing bare except clauses with
specific Exception handling:
- test_activity_integration.py: Fix 2 tearDown methods
- test_app_integration.py: Fix 1 tearDown method

Changes:
- Replace bare 'except:' with 'except Exception as e:'
- Add explanatory comments for why exceptions are caught
- Maintain same functionality while improving code quality

Tests still pass: 11/13 integration tests passing (85%)
2025-11-08 16:08:25 +00:00
Claude
b61f7944d3
Improve code highlighter theme for dark mode
- Switch from default highlight.js theme to GitHub themes
- Use github-dark theme for dark mode with better color contrast
- Use github theme for light mode
- Dynamically switch themes when user toggles dark/light mode
- Apply correct theme on page load based on saved preferences
2025-11-08 15:59:26 +00:00
48fc6f472f
Merge pull request #15 from russellballestrini/claude/dark-light-mode-switcher-011CUvfdzJCM7ejET2CEB9n8
Add dark mode toggle with local storage
2025-11-08 10:42:59 -05:00
Claude
5f01ffbef1
Move inline CSS to stylesheet
- Moved all theme-related inline styles to CSS rules
- Created proper selectors for labels, inputs, and buttons
- Added utility-belt class to mobile menu for consistent styling
- Removed redundant inline style attributes
2025-11-08 15:41:45 +00:00
Claude
bdf2863083
Fix integration tests and configure uncloseai.com models
Major improvements to test_activity_integration.py:
- Configure tests to use uncloseai.com models (hermes-3-llama-3.1-405b and qwen-2.5-72b)
- Fix Flask app and activity module configuration in test setUp
- Properly initialize MODEL_CLIENT_MAP with test models
- Set up activity.app, activity.db, and activity.get_room for proper test isolation
- Fix file path handling in create_test_activity_file()
- Improve activity YAML structure to avoid premature activity completion
- Add session refresh to handle database state properly

Test results improved from 3/9 passing to 7/9 passing (78% pass rate):
✓ test_cancel_activity
✓ test_display_activity_metadata
✓ test_execute_processing_script_with_metadata_operations
✓ test_handle_activity_response_correct_answer
✓ test_start_activity
✓ test_activity_state_metadata_persistence
✓ test_metadata_update_and_remove

Remaining issues (edge cases):
- test_handle_activity_response_increments_attempts: attempts counter behavior on incorrect answers
- test_loop_through_steps_until_question: step navigation emit count
2025-11-08 15:40:35 +00:00
Claude
314651e910
Add dark/light mode theme switcher with localStorage persistence
- Added CSS variables for light and dark themes
- Implemented theme toggle buttons in both desktop sidebar and mobile menu
- Added JavaScript logic to switch themes and persist choice in localStorage
- Applied dark theme styling to all UI elements including code blocks
- Theme is applied immediately on page load to prevent flash
2025-11-08 15:39:23 +00:00
Claude
c4cd185adc
Add integration tests for activity.py and app.py
New integration test files:
- test_activity_integration.py: 3 passing tests
  - Activity state metadata persistence
  - Metadata update and remove operations
  - Processing script execution with metadata

- test_app_integration.py: 4 passing tests
  - Group consecutive roles utility function
  - Room user workflow (add/remove users)
  - Message persistence and retrieval
  - Activity state workflow

Coverage improvements:
- Overall: 70% → 72% (+2%)
- Tests passing: 174 → 181 (+7)
- models.py: 100% coverage (from 55%)
- activity.py: 22% coverage (from 20%)
- New integration tests: 7 passing

Total test suite: 181 passing, 72% coverage
2025-11-08 14:18:56 +00:00
Claude
24ca0aab72
Add comprehensive unit tests for models.py and activity.py
- models.py: 55% → 100% coverage (29 tests)
  - Complete Room model testing (user management)
  - Complete UserSession model testing
  - Complete Message model testing (token counting, image detection)
  - Complete ActivityState model testing (metadata operations)

- activity.py: 14% → 20% coverage (25 tests)
  - get_activity_content with path traversal protection
  - execute_processing_script for Python execution
  - get_next_step for navigation
  - categorize_response for AI categorization
  - generate_ai_feedback for feedback generation
  - translate_text for translations
  - provide_feedback for feedback systems

Total: 54 new unit tests added, 135 tests now passing
2025-11-08 14:11:43 +00:00
Claude
62bc2d72c5
Improve test infrastructure and fix test failures
- Add pytest.ini configuration for better test organization
- Fix test file naming conflicts (rename test_guarded_ai.py)
- Improve database test setup in conftest.py with proper fixtures
- Remove duplicate test_app_feedback.py (functionality covered in test_guarded_ai_functions.py)
- Fix database initialization issues in integration tests
- All working tests now passing (120 passed, 65% coverage)
2025-11-08 14:04:09 +00:00
e74827061e modified: templates/chat.html 2025-11-08 06:56:18 -05:00
b95390f34c Implement async code execution with smart polling and cancel button
- Switch from sync /execute to async /execute/async with polling
- Poll intervals: 300ms, 750ms, 1450ms, 2350ms, 3000ms, 4600ms, 6600ms+
- Show cancel button after 3 seconds if job still running
- Display partial output when cancelled or timed out
- Add Copy and Run buttons to bottom of truncated code blocks (next to Show More)
- Prevents accidental cancels and DoS from spam-clicking
2025-11-07 19:32:47 -05:00
4f3dd882ba modified: CLAUDE.md
modified:   templates/chat.html
	new file:   test_code_execution.html
2025-11-07 13:31:27 -05:00
2811dad67b Refactor activity functions into separate activity.py module
Moved all activity-related functions from app.py to a new activity.py
module to improve code organization and maintainability. This reduces
app.py from 2852 lines to 1552 lines.

Changes:
- Created activity.py with 16 activity-related functions
- Updated app.py to import and initialize activity module
- Updated test_app.py to import activity module
- All 34 unit tests pass successfully
2025-10-22 20:23:06 -04:00
77e2c04ec0 Use selected model for activity AI operations
Pass the selected model parameter through the entire activity workflow
to ensure all AI operations (categorization, translation, feedback
generation, and grading) use the user's chosen model instead of
defaulting to the system default. Falls back to default when no model
is selected.
2025-10-22 20:04:20 -04:00
f0c7ea2cf5 Add copy button to messages and fix model/voice persistence
- Add copy button after edit button for all messages
- Fix model/voice settings persistence when creating new rooms
- Save model/voice selections to localStorage for better state management
- Ensure settings are loaded from localStorage if not in URL parameters
2025-09-09 17:57:16 -04:00
07a620a389 Fix activity15 coin usage and duplicate messages
- Remove duplicate messages from section transitions like activity14
- Fix coin categorization issue - 'use coin' was being misclassified as 'use_key_and_password'
- Add section_4:step_2 for post-safe-opening state with proper coin slot options
- Update tokens_for_ai to properly distinguish between different user actions
- Now players can properly access the secret compartment using the coin
- Activity validated and passes all checks
2025-08-11 18:35:46 -04:00
77203e4bda
Merge pull request #14 from russellballestrini/user-experience-day-1
User experience day 1
2025-08-11 17:21:50 -04:00
8a6170d57b Remove STFU system from feedback filtering
- Remove STFU check from app.py feedback filtering logic
- Update tests to remove STFU-specific test cases
- Simplify empty content filtering to just check for actual content
2025-08-11 17:20:59 -04:00
e3d33b90fd Simplify battleship prompts to let AI imagine destruction details
Remove prescriptive ship destruction descriptions and let the AI be creative.
Since skip_condition ensures these prompts only run when ships are actually
destroyed, we can make the prompts more concise and focused on the outcome.
2025-08-11 17:16:06 -04:00
fca7addaa5 Fix battleship AI hallucination bug with skip_condition system
Add skip_condition logic to feedback prompts to prevent AI from generating
false ship destruction messages when no ships were actually destroyed.

Changes:
- Add skip_condition parameter support in provide_feedback_prompts()
- Support all_null, all_false, and all_true condition types
- Apply skip_condition to battleship Ship Status and Game Over prompts
- Add comprehensive unit tests covering all skip condition scenarios
- Test real battleship scenario that was causing hallucinations

This prevents the AI from creating false positive ship destruction messages
when metadata indicates no ships were actually sunk (all null values).
2025-08-11 17:04:17 -04:00
060a91d2e1 Fix voice persistence and dynamic room link updates
Voice Persistence:
- Add voice/model saving to localStorage for persistent settings
- Load voice from URL → localStorage → default priority order
- Voice selection now persists across browser sessions and page refreshes

Dynamic Room Links:
- Add updateRoomLinksWithCurrentParams() function to update sidebar room links
- Room links now dynamically update with current username, model, and voice settings
- Both desktop and mobile room links stay synchronized with current parameters
- Fixes issue where clicking room links would lose user's current settings

Technical improvements:
- Enhanced syncInputsAndQueryString() to save to localStorage and update room links
- Initial sync call on page load ensures proper state from the start
- Maintains backwards compatibility with existing functionality
2025-08-11 16:14:13 -04:00
859ee9c0d9 Remove redundant streaming protocol test file
- Deleted test_streaming_protocol_simple.py (317 lines)
- Keeping test_streaming_protocol.py (541 lines) with comprehensive coverage
- Eliminates duplicate testing of the same functionality
- Consolidates streaming tests into single authoritative file
2025-08-11 16:05:55 -04:00
acdf653eaa Enhance user experience with multiple improvements
- Add username field to right sidebar and mobile modal with 'guest' default
- Implement real-time username sync with URL query string updates
- Add opencompletion.com button and new room creation in left sidebar
- Implement room name slugification (e.g. "a whole new world" → "a-whole-new-world")
- Create shared utils.js for common functions like slugify
- Add single search result auto-redirect functionality
- Remove redundant UI elements ("Create New Room" header, docs link)
- Preserve user settings (username, model, voice) across redirects and room creation

Technical improvements:
- Consolidated duplicate code into shared utility functions
- Enhanced search logic with parameter preservation
- Improved mobile/desktop sync for all input fields
- Better URL handling and query string management
2025-08-11 16:01:51 -04:00
88f68e4adc Fix streaming message display and TTS issues
- Separate username/model header from message content using distinct DOM elements
- Fix button positioning to appear on left side of messages
- Ensure TTS only reads clean message content, not username/model header
- Add support for stopping current TTS when auto-play is toggled off
- Improve DOM structure with message-body wrapper for proper layout
- Fix streaming messages to maintain header display throughout entire stream
2025-08-11 15:26:52 -04:00
dada6b3f22 Add comprehensive integration tests for streaming protocol
- Created test_streaming_protocol_simple.py with 3 passing tests
- Created test_streaming_protocol.py with comprehensive test suite
- Tests verify new protocol format with separate username/model fields
- Tests confirm content separation from metadata for clean TTS processing
- Added debug logging for Game Over feedback prompt
- All tests validate the streaming refactoring works correctly
2025-08-11 14:13:36 -04:00
4e122e708c Refactor streaming protocol to separate username/model from content
Backend changes:
- Send username, model_name, and is_first_chunk as separate fields
- Keep actual content separate from header formatting
- Cleaner separation of concerns in streaming protocol

Frontend changes:
- Build display content with header only for visual rendering
- Keep messageBuffers clean (content only) for TTS processing
- TTS now processes pure content without username headers

This fixes the issue where TTS was reading 'fxhp (model):' prefix
2025-08-11 13:46:51 -04:00
5d78911d5b Fix TTS queue bug for streamed messages
- Fixed querySelector to find Play button specifically, not first button
- Regular messages used Array.from().find() correctly
- Streaming messages were using querySelector('button') which found Delete button
- This explains why streamed messages never got added to TTS queue
2025-08-11 13:35:06 -04:00
853fac95a4 Add debug logging to diagnose TTS queue issue with streamed messages
- Added console.log statements to streaming TTS logic
- Will help identify why streamed messages aren't being added to TTS queue
- Debug info includes autoPlayTTS state, completion status, buffer content
2025-08-11 13:34:17 -04:00
98b0ebab24 Fix duplicate exit messages in battleship
- Removed feedback_tokens_for_ai from step 3 Game Over
- Exit transition already has appropriate content_blocks
- Eliminates duplicate farewell messages when exiting
2025-08-11 13:14:07 -04:00
1808c915e1 Automatically return to activity chooser when activity completes
- Added activity_status emit with active: false when activity ends
- Now matches behavior of activity cancellation
- Users will automatically see activity chooser when activity finishes
2025-08-11 13:10:28 -04:00
f3d4dd89bc Add debug output for Game Over metadata filtering to investigate STFU bug when game actually ends 2025-08-11 12:47:25 -04:00
f90df2ae57 modified: activity_yaml_validator.py
modified:   app.py
	modified:   research/activity29-battleship.yaml
	modified:   research/activity29-testship.yaml
	modified:   research/guarded_ai.py
	modified:   tests/functional/test_activity_flows.py
	modified:   tests/functional/test_battleship_pre_script.py
	modified:   tests/functional/test_guarded_ai.py
	modified:   tests/unit/test_activity_yaml_validator.py
	modified:   tests/unit/test_app_feedback.py
	modified:   tests/unit/test_guarded_ai.py
2025-08-11 12:39:42 -04:00
d4d697db59 Implement per-prompt metadata filtering and fix battleship feedback system
Major improvements to battleship game feedback accuracy and user experience:

## New Multi-Prompt Feedback System
- Replaced single feedback with 3 specialized prompts: Shot Report, Ship Status, Game Over
- Each prompt has individual metadata filtering to see only relevant data
- Shot Report only sees hit/miss data, Ship Status only sees ship destruction data
- Added STFU token system to suppress empty messages (filtered out automatically)

## Technical Implementation
- Added per-prompt metadata_filter support in YAML structure
- Updated app.py and guarded_ai.py to handle prompt-specific filtering
- Legacy single-prompt system still works with transition-level filtering
- Added comprehensive test suite for feedback system validation

## User Experience Fixes
- Fixed TTS queue blocking JavaScript execution (async promises instead of await)
- Ship Status now correctly reports who destroyed which ship (role confusion fixed)
- Game Over only appears when game actually ends (no more random messages)
- Maintained dramatic storytelling while ensuring factual accuracy

## Battleship-Specific Improvements
- Ship destruction messages only appear when ships actually sink
- Clear separation of concerns: hits/misses vs ship destruction vs game over
- Eliminated false positive ship destruction reports
- Fixed role reversal where wrong player got credit for destruction

The battleship narrator now provides accurate, contextual feedback while preserving the dramatic naval warfare atmosphere.
2025-08-11 11:39:49 -04:00
e28dc11f04 Improve user experience with battleship feedback and auto-play TTS
- Fix battleship feedback perspective confusion with better Hermes prompting
- Add auto-play TTS button with localStorage persistence and queueing system
- Move activity controls below model/voice selectors in sidebar
- Add activity controls to mobile hamburger menu
- Fix model/activity dropdowns to stay within container bounds
- Filter activities API to only show .yaml/.yml files
- Clean up system message labels by moving to usernames (System (Feedback), System (Question))
- Apply black formatting to app.py
2025-08-11 09:34:29 -04:00
74bb98b517
Merge pull request #13 from russellballestrini/testing-framework
Testing framework
2025-08-10 21:16:20 -04:00
96afd3272e Fix string termination in unit test
Add back the missing quote to properly close the triple-quoted string.
The expected string now has the correct number of closing quotes:
- One quote to close the inner string
- Three quotes to close the triple-quoted string
2025-08-10 21:16:12 -04:00
96ee7e8d0c Fix escaped quote in unit test expected string
Remove stray backslash from expected multiline string in test_find_most_recent_code_block.
The expected string now correctly matches the extracted code block content:
- def test_function():
-     return "Hello, World\!"

This fixes the test assertion to match the actual extracted content exactly.
2025-08-10 21:15:03 -04:00
6b876d488c Fix hardcoded paths in test files and improve YAML error handling
- Replace hardcoded absolute paths with relative paths using Path(__file__).parent
- Update test_activity_flows.py, test_guarded_ai.py, and test_battleship_pre_script.py to use dynamic path construction
- Import yaml module and catch yaml.YAMLError instead of broad Exception in test_activity_processing.py
- Ensures tests work across different environments and CI systems
- Makes YAML error handling more specific and prevents masking other exceptions
2025-08-10 21:06:26 -04:00
092ebd0ee0
Update Makefile
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-10 20:54:43 -04:00
45a8f60cd2 Significantly improve test coverage with comprehensive integration tests
Major improvements:
- app.py coverage: 15% → 25% (+10 percentage points)
- research/guarded_ai.py coverage: 68% → 81% (+13 percentage points)
- Overall project coverage: 68% → 72% (+4 percentage points)

Key changes:
- Add comprehensive Flask integration tests for app.py activity functions
- Test real database operations with in-memory SQLite
- Add extensive guarded_ai.py error handling and client management tests
- Enhanced Makefile with comprehensive test targets
- Updated requirements-test.txt with flake8
- All 135 tests now passing with proper test coverage

The integration tests use real Flask environment, actual YAML processing,
and genuine database operations instead of mocks for accurate coverage.
2025-08-10 20:52:56 -04:00
1b44c2d66b Integrate comprehensive testing framework with Makefile
- Added unit tests for YAML loading and parsing functionality
- Created integration tests for multiple activity files validation
- Implemented functional tests for complete activity workflows
- Added battleship pre_script functionality tests
- Integrated all test types into comprehensive Makefile
- Fixed CLI validator test with proper failing fixture
- Applied black formatting to all Python files
- Removed problematic hardcoded targets from Makefile
- Added proper venv dependency management

Test coverage includes:
- Unit: YAML loading, validator functionality
- Integration: Cross-file validation, metadata operations
- Functional: End-to-end activity flows, pre_script execution
- All 30 activity files validated and tested
2025-08-10 19:38:50 -04:00
51b74be7d9 Fix YAML validator and activity file validation errors
- Updated validator terminal step detection to only flag truly terminal steps
- Fixed validator to accept integers and booleans in buckets (as supported by app.py)
- Fixed metadata_remove format in activity17 from dictionary to list of strings
- Added proper terminal section to activity3.yaml without questions/buckets
- Fixed missing restart transition and bucket in activity28
- Removed unused game_end transitions from battleship files
- Updated exit transitions to go directly to step_4 (goodbye step)
- Applied black formatting to validator code

All 30 activity YAML files now validate successfully with 0 errors and 0 warnings.
2025-08-10 19:38:50 -04:00
d4a075ac9a Complete testing framework with comprehensive test coverage
- Add comprehensive testing framework with 67 test cases covering unit, integration, and functional testing
- Create universal YAML validator supporting all activity types with validation for metadata operations, terminal steps, and Python syntax
- Implement proper Makefile with venv management and test runners following unDRY principles for copy-paste engineering
- Add requirements-test.txt for test dependencies separation
- Configure pytest with conftest.py for proper environment variable management
- Update CLAUDE.md with Makefile best practices
- All 67 tests passing with proper mocking of external dependencies

Testing coverage includes:
• Unit tests (37): Core app functions, utilities, navigation, response handling
• Integration tests (20): Complete activity workflows and error handling
• Functional tests (9): Full battleship game scenarios and edge cases
• YAML validator (17): Universal validation for all activity configurations
2025-08-10 19:38:47 -04:00
292265b5bb Add comprehensive testing framework and YAML validator
- Create universal activity_yaml_validator.py for validating activity configurations
- Add validation for metadata operations (metadata_add, metadata_remove, metadata_feedback_filter, etc.)
- Validate terminal steps cannot have questions or buckets
- Check Python syntax in processing_script and pre_script blocks
- Validate YAML structure, transitions, and logic flow
- Add 17 comprehensive unit tests with 100% pass rate
- Include test fixtures for validation testing
- Support both CLI and programmatic usage
2025-08-10 19:35:52 -04:00
25c694584a
Merge pull request #12 from russellballestrini/battleship-hermes
Battleship hermes mode operational!
2025-08-10 16:06:06 -04:00
1ca6f67c3d Fix code quality issues from PR review
- Add matplotlib.use("Agg") backend configuration to prevent runtime errors in headless environments
- Add error handling guards for script results that might return None
- Fix AI targeting logic to exclude already-fired cells in super hunter and hunter modes
- Update CLAUDE.md with matplotlib best practices
2025-08-10 16:01:58 -04:00
4d909aaecb Fix indentation error from commented print statements
- Add pass statements to empty else blocks that only contained commented prints
- Ensures Python syntax remains valid after commenting out debug statements
2025-08-10 15:19:59 -04:00
29573eaa75 Enhance battleship activity with improved user input handling and feedback
- Add user_response to pre-script metadata for better game state management
- Implement metadata_feedback_filter to control feedback data exposure
- Improve ship destruction announcements and game over messaging
- Add debug logging for ship sinking events
- Include test ship configuration file
2025-08-10 14:49:03 -04:00
80b18cf0bb Add Claude instructions to prevent attribution in commit messages 2025-08-10 11:57:52 -04:00
368c7d290e Add Hermes Reasoner mode to battleship with game ending fixes
- Add new Hermes Reasoner AI mode that combines probability analysis with LLM reasoning
- Implement pre-script and post-script architecture in app.py for flexible YAML processing
- Fix game ending detection by adding transition override mechanism
- Add probability matrix visualization and strategic move analysis
- Support both legacy processing_script and new pre_script/post_script naming
- Restore full ship complement for complete battleship gameplay
2025-08-10 11:57:22 -04:00
38f414c5a9 Fix critical security vulnerabilities in Flask application
- Prevent SQL injection in search functionality with input sanitization
- Add path traversal protection for local file operations
- Replace hardcoded secret key with environment variable
- Escape HTML output to prevent XSS attacks in image generation
- Restrict file access to research/ directory with .yaml extension only
- Add comprehensive input validation and error handling

Security improvements maintain full application functionality while
protecting against common web application vulnerabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-24 00:00:54 -04:00
fc53cd3cc5 ● Enhance math plotting activity with secure multi-function support
- Replace unsafe eval() with sympy for secure expression parsing
  - Add YAML anchors to eliminate code duplication in processing scripts
  - Implement multiple function plotting with comma-separated syntax
  - Add dynamic plot ranges based on function characteristics
  - Include automatic function type detection and analysis
  - Streamline activity flow: intro → demo plot → open sandbox
  - Add comprehensive error handling with visual error messages
  - Support enhanced mathematical notation (arcsin, ln, implied multiplication)

	modified:   research/activity24-math-plot.yaml
2025-06-23 23:21:25 -04:00
2a1efd1f90 claude security upgrade
modified:   requirements.txt
	modified:   research/activity24-math-plot.yaml
2025-06-23 22:36:23 -04:00
648df5a0b2 embed videos like a damn pro! 2025-06-20 17:13:32 -04:00
8011649abc fix all the o1-o4 models
modified:   app.py
2025-06-01 23:28:05 -04:00
b65fd58285 nothing lasts but nothing is lost.
Goodbye Naptha.

	modified:   README.rst
	modified:   vars.sh.sample
2025-05-23 10:29:42 -04:00
85bbac74f2
Merge pull request #11 from russellballestrini/battleship
prompt engineering research/activity29-battleship.yaml
2025-04-24 12:59:34 -04:00
Russell Ballestrini
8cee47fcc9 modified: research/activity29-battleship.yaml 2025-04-23 16:17:05 -04:00
Russell Ballestrini
0e59d29dd7 modified: models.py 2025-04-23 16:06:40 -04:00
Russell Ballestrini
c7278e07a7 modified: vars.sh.sample 2025-03-11 22:14:17 -04:00
54223fc4bb
Merge pull request #10 from russellballestrini/dynamic-models
dynamic models for all the platforms!
2025-03-11 22:02:53 -04:00
Russell Ballestrini
3b463f41ea modified: requirements.txt 2025-03-11 21:18:52 -04:00
Russell Ballestrini
9bfd1c9b5a dynamic models for all the platforms!
modified:   .gitignore
	modified:   README.rst
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
	new file:   vars.sh.sample
2025-03-11 21:15:13 -04:00
00eba1b150 gemini is actually tested and working
modified:   app.py
	new file:   models.py
2025-02-23 17:11:00 -05:00
2cd434c291
Update app.py 2025-02-16 15:56:32 -05:00
b6b4067134
Update README.rst 2025-02-16 15:54:51 -05:00
7d1b22d564
Merge pull request #9 from russellballestrini/all-the-models
dynamically register models to endpoints
2025-02-10 17:08:11 -05:00
44170459fe dynamically register models to endpoints
modified:   app.py
2025-02-10 16:46:02 -05:00
8fd77088e6
Update README.rst
export VLLM_ENDPOINT2=https://naptha2.ai.unturf.com/v1
    export VLLM_ENDPOINT3=https://naptha3.ai.unturf.com/v1
2025-02-10 13:11:47 -05:00
a1e523e183
Merge pull request #8 from russellballestrini/mistral-ai-upgrades
Mistral ai upgrades
2025-02-08 16:32:22 -05:00
381588d6bc mistral upgrades
modified:   README.rst
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2025-02-08 16:03:22 -05:00
0250bf77b1
mistral ai upgrades 2025-02-08 15:48:23 -05:00
748649d98a o3-mini and hermes 8b 8fp!
modified:   README.rst
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2025-02-01 15:58:01 -05:00
adc202125e free endpoints for open public domain ai
modified:   README.rst
2025-01-25 14:40:14 -05:00
0492d5b329 r1 llm support:
modified:   README.rst
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2025-01-25 14:37:26 -05:00
06d5167628 make port configurable for demo2.opencompletion.com 2025-01-25 07:46:11 -05:00
2e7fd18ba1 more openai models
modified:   README.rst
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-12-31 12:18:03 -05:00
91d6192192 bunch more models.
modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-12-09 18:25:37 -05:00
9c44b23758 f 2024-12-07 10:51:08 -05:00
8743464747 modified: README.rst 2024-12-07 10:47:48 -05:00
Russell Ballestrini
2449703489 modified: templates/chat.html 2024-12-06 16:09:05 -05:00
8b90bc6485 sync up mobile and desktop drop downs and user lists!
modified:   templates/base.html
	modified:   templates/chat.html
2024-11-24 17:35:54 -05:00
b01311a825 inactive uesrs now collected.
modified:   app.py
	new file:   migrations/versions/5d93cdf18549_room_inactive_users_column.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-11-24 14:16:25 -05:00
96c10fc6d6 announce when a username leaves the room.
modified:   app.py
	modified:   templates/chat.html
2024-11-24 13:32:08 -05:00
c937c7b2c3
Merge pull request #7 from russellballestrini/user-list
create grid column for room user list
2024-11-23 12:18:17 -05:00
5fa37da991 sort active users, validate models and voices, fix room links
modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-11-23 12:04:48 -05:00
0f82305087 feature complete. "sorry for the convenience"
modified:   app.py
	new file:   migrations/versions/1ac5a8e0f577_user_session_table.py
2024-11-23 11:32:49 -05:00
6f1c7def7b new file: migrations/versions/38a330686a17_room_active_users.py 2024-11-23 10:46:15 -05:00
fab40ba60d w00t! active user list working, now we need disconnect to remove logic.
modified:   app.py
	modified:   templates/chat.html
2024-11-23 10:31:38 -05:00
f9f7da6ffc incremental progress
modified:   app.py
	modified:   templates/chat.html
2024-11-23 09:39:39 -05:00
3b3714f527 Fix defect with TTS after stream.
modified:   app.py
	modified:   templates/chat.html
2024-11-23 08:34:23 -05:00
d99ab35a71 Muhahahaa utility belt!
modified:   templates/chat.html
2024-11-23 07:38:20 -05:00
c2dcb6c4bf more html for the new utility belt
u are batman now.

	modified:   templates/base.html
	modified:   templates/chat.html
2024-11-23 07:30:25 -05:00
54fe4139a0 create grid column for room user list
modified:   templates/base.html
	modified:   templates/chat.html
2024-11-23 07:02:24 -05:00
46d760cdf5
Merge pull request #6 from russellballestrini/ollama-hermes
ollama Hermes
2024-11-22 14:18:56 -05:00
Russell Ballestrini
185ebbcb59 ollama Hermes
ollama run hf.co/NousResearch/Hermes-3-Llama-3.1-8B-GGUF:Q8_0

	modified:   README.rst
	modified:   app.py
2024-11-22 14:15:44 -05:00
db8749a2df
Merge pull request #5 from russellballestrini/gemini-1.5-002
google gemini has entered the chat.
2024-11-21 10:40:49 -05:00
c8ffe15e66 fix all openai_client.chat calls to have n=1 for google api
modified:   app.py
2024-11-21 10:33:32 -05:00
b0aee48352 google gemini has entered the chat.
modified:   README.rst
	modified:   app.py
2024-11-21 10:16:46 -05:00
717a98ac03
Merge pull request #4 from russellballestrini/grok-beta
grok-beta
2024-11-21 09:07:11 -05:00
d316831a45 grok-beta
modified:   README.rst
	modified:   app.py
2024-11-21 08:57:29 -05:00
1dc5e4a531 modified: templates/base.html 2024-11-16 15:35:55 -05:00
f18d81e1ea better for mobile
modified:   templates/base.html
2024-11-16 10:17:56 -05:00
7f332de648 * Update README.rst
* button grid vertical
* button TTS play button using the free speech.ai.unturf.com endpoint!

	modified:   README.rst
	modified:   templates/base.html
	modified:   templates/chat.html
2024-11-14 07:05:58 -05:00
496dc42f13
vllm/hermes-llama-3 demo.opencompletion.com 2024-11-11 07:54:11 -05:00
0faff35c58
opencompletion.com 2024-10-28 10:24:45 -04:00
3e98bf96e0
Update README.rst 2024-10-27 18:45:29 -04:00
048e38b0ff
new name who this?
opencompletion

opencompletion.com
2024-10-27 17:59:53 -04:00
6d008a964f fixes for o1-mini but streaming is not supported...
modified:   app.py
2024-10-01 19:05:29 -04:00
75e637002b download markdown of conversation useful for github or jira
modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-09-18 16:27:40 -04:00
b257f766f8 Rubric for battleship ending.
modified:   research/activity29-battleship.yaml
2024-09-16 11:59:56 -04:00
0fae1eb910 hooray for open source! new hermes 3 llama 3.1 tested
http://home.foxhop.net:5001/chat/hermes-3-llama-3.1-chain-of-thought?username=changeme
2024-09-15 17:54:56 -04:00
6086d65f9b uses the openai syntax for the conversation dump including content & role
* user
* system

	modified:   app.py
	modified:   templates/base.html
	modified:   templates/chat.html
2024-09-15 08:57:34 -04:00
Russell Ballestrini
e310217166 gpt-o1-mini and mistral-nemo
You'll have to do `pip install --upgrade -r requirements.txt` to install latest:

* mistralai client
* openai client

	modified:   app.py
2024-09-13 09:04:35 -04:00
9246565407 battleship, super human hunter mode
modified:   research/activity29-battleship.yaml
2024-09-09 07:12:58 -04:00
49cc545a4c Battleship Hunter Mode!
In this mode the AI will switch from random to hunting all the positions
around the latest hit. It's still not as smart as a human but you will
start to feel hunted as the game progresses versus the other game mode.

	modified:   research/activity29-battleship.yaml
2024-09-07 13:18:42 -04:00
6763c0b9d5 tic tac toe
modified:   research/activity27-tic-tac-toe.yaml
2024-09-07 10:12:11 -04:00
d684abb4fd battleship 2024-08-30 10:34:33 -04:00
930fa66b19 a bit better battleship
modified:   research/activity29-battleship.yaml
2024-08-30 09:46:07 -04:00
ba91cbcb27 modified: research/activity27-tic-tac-toe.yaml
new file:   static/images/tic-tac-toe.png
2024-08-29 06:55:40 -04:00
d1998f9d1c move off message to chat_message but it doesn't fix order issue.
The app seems to queue the category, feedback/content_blocks question

The strange part is the set_background happens in the middle of the
script after category but it comes first and FAST! In about a second
while the other messages take about 4 secs to finally arrive.

	modified:   app.py
	modified:   research/activity29-battleship.yaml
	modified:   templates/chat.html
2024-08-28 07:15:18 -04:00
0170327483 battleship
new file:   research/activity29-battleship.yaml
2024-08-25 15:40:33 -04:00
41dff2865a Easy way to restart an activity without quitting.
modified:   app.py
	modified:   research/activity27-tic-tac-toe.yaml
	modified:   research/activity28-killer-squares.yaml
2024-08-25 10:05:57 -04:00
2e82ddc563 modified: app.py 2024-08-24 20:28:56 -04:00
ba37cb448c new file: research/activity28-killer-squares.yaml 2024-08-24 20:11:03 -04:00
db983f6d4b mathplotlib tic tac toe board.
modified:   research/activity27-tic-tac-toe.yaml
2024-08-24 16:15:05 -04:00
df54e6b4aa conditionally run processing_script
modified:   app.py
	modified:   research/activity22-odds-or-evens.yaml
	modified:   research/activity24-math-plot.yaml
	modified:   research/activity27-tic-tac-toe.yaml
	modified:   research/guarded_ai.py
2024-08-24 14:31:46 -04:00
691e4ab054 working tic tac toe
modified:   app.py
	modified:   research/activity27-tic-tac-toe.yaml
2024-08-24 13:38:38 -04:00
e95a150f3a modified: research/activity26-magic-8-ball.yaml 2024-08-24 09:21:51 -04:00
863cec2e86 modified: app.py
new file:   research/activity26-magic-8-ball.yaml
2024-08-21 08:06:56 -04:00
1095df37e1 modified: app.py
new file:   research/activity25-20-questions.yaml
2024-08-20 17:38:48 -04:00
3e183da802 modified: research/activity24-math-plot.yaml 2024-08-14 08:10:05 -04:00
c7086f6ee9 plot even more lines like sin(x)
modified:   research/activity24-math-plot.yaml
2024-08-11 18:24:16 -04:00
dc03ce9d5e math plotting!!! try out these equations:
( x^2 - 4x + 3 )
    ( x^2 - 2x + 1 )
    ( 2^x - 1 )

	modified:   app.py
	modified:   requirements.txt
	new file:   research/activity24-math-plot.yaml
2024-08-11 17:03:03 -04:00
fc358036c9 prompt engineering translation llm
modified:   app.py
	new file:   research/activity18.yaml
2024-08-11 14:58:36 -04:00
5c9ef230ae modified: app.py
modified:   research/activity23-math.yaml
2024-08-11 13:39:30 -04:00
f09d24aefc make math progressively more difficult.
modified:   ../app.py
	modified:   activity23-math.yaml
2024-08-11 11:27:32 -04:00
7ac9c4583c new file: activity23-math.yaml 2024-08-11 09:44:15 -04:00
14dd105d03 woot upgraded guarded to support odds-or-evens game.
modified:   ../app.py
	new file:   activity22-odds-or-evens.yaml
	modified:   guarded_ai.py
2024-08-11 08:43:47 -04:00
3902ff48da modified: app.py 2024-08-10 20:21:00 -04:00
be61486f38 modified: research/activity19-rock-paper-scissors.yaml 2024-08-10 19:23:14 -04:00
f923570f5a prompt engineering
modified:   app.py
	modified:   research/activity19-rock-paper-scissors.yaml
2024-08-10 19:15:19 -04:00
2609ff993d limited_effort should not be treated as correct.
modified:   app.py
	modified:   research/guarded_ai.py
2024-08-10 17:23:04 -04:00
f5df195e9b black and also set_language isn't "correct" anymore.
so it doesn't move the student on.

	modified:   app.py
	modified:   migrations/env.py
	modified:   migrations/versions/190d5ef26e20_add_token_count_to_message.py
	modified:   migrations/versions/a9e886c56482_create_room_table.py
	modified:   migrations/versions/d737de68d6fa_add_metadata_field_to_activitystate.py
	modified:   research/activity21.yaml
	modified:   research/guarded_ai.py
2024-08-10 17:00:52 -04:00
5f4cf76372 modified: activity21.yaml 2024-08-10 16:07:23 -04:00
3a6c62cf22 hopefully we get some python examples
modified:   ../app.py
	modified:   activity21.yaml
2024-08-10 15:55:46 -04:00
9a4f2a8b30 violent python activity21.yaml
modified:   ../app.py
	new file:   activity21.yaml
2024-08-10 15:42:31 -04:00
058b0161df allow increment to go backward with n-1 and also support any int c for the
increment or decrement.

	modified:   ../app.py
	modified:   guarded_ai.py
2024-08-10 15:00:28 -04:00
e3d3bf0303 n+1 in yaml to accumulate integers.
modified:   ../app.py
	new file:   activity20-n-plus-1.yaml
	modified:   guarded_ai.py
2024-08-10 14:39:37 -04:00
87faba6379 modified: guarded_ai.py 2024-08-10 13:40:22 -04:00
4f7caffe17 guarded_ai.py can also play rock-paper-scissors.yaml 2024-08-10 13:36:31 -04:00
0d908b65d4 fully functional activity19-rock-paper-scissors.yaml
modified:   ../app.py
	new file:   activity19-rock-paper-scissors.yaml
	modified:   ../templates/base.html
2024-08-10 13:24:26 -04:00
b979d31b40 more help text 2024-08-10 11:15:14 -04:00
884450dda2 modified: ../README.rst 2024-08-10 11:03:28 -04:00
920f0e931d /help
modified:   ../app.py
2024-08-10 11:02:05 -04:00
cebb2c2ec7 prompt engineering 2024-08-10 10:22:54 -04:00
4132afe9d1 prompt engineering
modified:   ../app.py
	modified:   activity0.yaml
2024-08-09 19:32:04 -04:00
af60dd8045 limited_effort for activity0.yaml example
modified:   activity0.yaml
2024-08-09 09:13:18 -04:00
3b8309a432 all languages translation to simulated gaurded_ai
modified:   guarded_ai.py
2024-08-09 08:41:46 -04:00
17777d727d support all the languages!
modified:   app.py
	modified:   research/activity0.yaml
2024-08-09 08:20:48 -04:00
3b542285f6 counts_as_attempt implemented and we caught up guarded_ai to have
metadata

	modified:   app.py
	modified:   research/guarded_ai.py
2024-08-08 08:59:20 -04:00
Russell Ballestrini
b0fa97ffc3 gpt-4o-2024-08-06 is the cheapest version of gpt-4 yet!
modified:   README.rst
	modified:   app.py
2024-08-07 18:59:18 -04:00
Russell Ballestrini
5bc19e5488 use aws profile when it's given in s3 client sessions
modified:   app.py
2024-08-07 13:10:32 -04:00
Russell Ballestrini
371984bc04 pyyaml
modified:   requirements.txt
2024-08-07 12:52:41 -04:00
eabf16a45a special string for saving user_response to metadata.
modified:   app.py
2024-08-05 09:10:47 -04:00
b4684a8e6d metadata_random is a new way to randomly assign metadata when a play
reaches this category.

	modified:   app.py
	modified:   research/activity17-choose-adventure.yaml
2024-08-04 15:15:42 -04:00
1ff5a364d3 prompt engineering.
modified:   research/activity17-choose-adventure.yaml
2024-08-04 12:08:33 -04:00
5217092e39 f
modified:   app.py
2024-08-04 11:37:04 -04:00
c4df19132f support both vllm and openai at the same time.
modified:   app.py
2024-08-04 11:35:12 -04:00
7a433bfccb pass activity_state.json_metadata to feedback for additional context.
modified:   app.py
	modified:   research/activity17-choose-adventure.yaml
2024-08-04 11:01:31 -04:00
36abf1590e /activity info on --local-activities
modified:   app.py
	modified:   research/activity17-choose-adventure.yaml
2024-08-04 10:42:14 -04:00
90964f2800 prize room and offering pit
new file:   research/activity17-choose-adventure.yaml
2024-08-04 09:02:13 -04:00
7ceb9303ea metadata_add and metadata_remove to allow for items to be consumed.
modified:   app.py
	modified:   research/activity14-choose-adventure.yaml
	modified:   research/activity15-choose-adventure.yaml
	modified:   research/activity16.yaml
2024-08-04 08:33:55 -04:00
7198f2109e a prize room for fun.
modified:   app.py
	modified:   research/activity15-choose-adventure.yaml
2024-08-03 18:21:43 -04:00
847f609b4a supply username to feedback routine so llm knows that context
remove dupe content and unessasary ai_feedback from different paths.

	modified:   app.py
	modified:   research/activity15-choose-adventure.yaml
2024-08-03 14:55:43 -04:00
018671a8c1 remove print debug statement
modified:   app.py
2024-08-03 13:07:42 -04:00
8cca256c89 prompt engineering activity 15
modified:   app.py
	modified:   research/activity15-choose-adventure.yaml
2024-08-03 09:29:53 -04:00
65404a4ecd now you can load local activities via --local-activities
modified:   app.py
	modified:   research/activity15-choose-adventure.yaml
2024-08-03 09:03:32 -04:00
257e5a6a04 /activity metadata
modified:   README.rst
	modified:   app.py
	modified:   research/activity16.yaml
2024-08-02 18:49:50 -04:00
ea082ad1ff migrate all activities, there should always be a step without a question
as last step.
	modified:   research/activity.yaml
	modified:   research/activity2.yaml
	modified:   research/activity4.yaml
	modified:   research/activity5.yaml
	modified:   research/activity6.yaml
	modified:   research/activity7.yaml
2024-08-01 18:03:00 -04:00
ade6bfed18 fix guarded_ai feedback issue 2024-07-31 17:15:07 -04:00
7953815e9d fix missing fstring ai tokens now actually sent to ai during feedback! 2024-07-31 09:08:06 -04:00
a6d188f3c7 this activity16 lets student explore 3 topics and exit after doing all 3
to the end.

	new file:   research/activity16.yaml
2024-07-31 08:22:22 -04:00
63b9bb18b5 display ending info when activity finishes
modified:   app.py
2024-07-31 07:40:22 -04:00
7fe320a958 refactor looping until a question is found to reduce code duplication
modified:   app.py
2024-07-30 22:20:18 -04:00
78f369d917 get rid of redundant content_block transitions 2024-07-30 21:10:41 -04:00
75812a8f37 this version of the safe room has secret items and rooms.
modified:   app.py
	new file:   research/activity15-choose-adventure.yaml
2024-07-30 20:48:36 -04:00
645a48a2dd allow open source to work with vllm
modified:   app.py
2024-07-29 10:26:49 -04:00
dbe7e0bd6a some steps don't have questions, try to do the right thing.
modified:   app.py
	modified:   research/activity0.yaml
2024-07-29 07:38:52 -04:00
94283a0377
Merge pull request #2 from russellballestrini/ai-guarded
Ai guarded
2024-07-29 06:34:51 -04:00
9f3c5fb3a7 hcanges per rabbit feedback
modified:   app.py
	modified:   research/guarded_ai.py
2024-07-29 06:34:05 -04:00
dd13bce82b
Update research/guarded_ai.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-07-29 06:17:48 -04:00
aa783ded70 modified: guarded_ai.py 2024-07-28 20:53:00 -04:00
602039ca71 play tested and working
modified:   app.py
2024-07-28 20:37:31 -04:00
5d10296f1f escape room mechanics with json_metadata for temporarily collecting data
based on where the user has went we can for example set a key: true if
they collected a key needed to access a section's steps.

	modified:   app.py
	new file:   migrations/versions/d737de68d6fa_add_metadata_field_to_activitystate.py
	new file:   research/activity14-choose-adventure.yaml
2024-07-28 19:14:54 -04:00
e3b3ddb007 allow player to go back if they change their minds, less "rails".
modified:   research/activity13-choose-adventure.yaml
2024-07-28 15:07:34 -04:00
2fc774d85c /activity cancel
modified:   README.rst
	modified:   app.py
2024-07-28 13:59:25 -04:00
0462de7368 Activity Mode documented 2024-07-28 13:13:57 -04:00
8d771e8b06 allow user to ask question and explore longer
instead of 3 turns per step allow for 30
2024-07-28 12:54:32 -04:00
684f3df38e fix defect/regression with linear activities
modified:   guarded_ai.py
2024-07-28 11:59:40 -04:00
7e7b226fb1 print content blocks and skip the llm logic if no question in step.
modified:   research/guarded_ai.py
2024-07-28 11:28:44 -04:00
02c97beebe fix defect when step has no question.
modified:   app.py
	modified:   research/activity13-choose-adventure.yaml
2024-07-28 11:04:30 -04:00
cfa5d77a42 Allowing for non-linear progression depending on buckets category
new field in the transitions is next_section_and_step which is optional
and defaults to None but also can be "section_3:step_1"

	modified:   app.py
	new file:   research/activity0.yaml
	new file:   research/activity13-choose-adventure.yaml
	modified:   research/guarded_ai.py
2024-07-28 10:36:09 -04:00
7e97acf477 content_blocks and questions support markdown values.
modified:   research/activity10.yaml
2024-07-27 15:49:19 -04:00
93f274ef39 modified: app.py 2024-07-27 15:37:29 -04:00
692e34d090 repeat the question if not correct, after AI feedback
modified:   app.py
2024-07-27 14:14:34 -04:00
ee5721a1fb default rubric for grading and scoring trivia.
displays at the end of game or when running `/activity info`.

	modified:   app.py
2024-07-27 13:56:20 -04:00
5583e34e51 prompt engineering.
modified:   research/guarded_ai.py
2024-07-27 12:22:51 -04:00
6dff9dc6e9 Integrated gaurded ai via websocket frontend.
modified:   app.py
	new file:   migrations/versions/d04950c5a624_add_activitystate_table2.py
	new file:   migrations/versions/d3631b8bb652_add_activitystate_table.py
2024-07-27 10:30:07 -04:00
15ac4fa015 algo for guarding AI on rails.
new file:   research/activity.yaml
	new file:   research/activity10.yaml
	new file:   research/activity11.yaml
	new file:   research/activity12.yaml
	new file:   research/activity2.yaml
	new file:   research/activity3.yaml
	new file:   research/activity4.yaml
	new file:   research/activity5.yaml
	new file:   research/activity6.yaml
	new file:   research/activity7.yaml
	new file:   research/activity8.yaml
	new file:   research/activity9.yaml
	new file:   research/guarded_ai.py
2024-07-27 08:57:44 -04:00
Russell Ballestrini
698455fb40 gpt-4o-mini as gpt-mini alias
modified:   README.rst
	modified:   app.py
2024-07-18 17:12:05 -04:00
Russell Ballestrini
da5a8cbcfa gpt-4o for titles and add claude-opus
modified:   README.rst
	modified:   app.py
2024-07-08 17:33:12 -04:00
393769bcf7
Merge pull request #1 from russellballestrini/search
Keyword search across all chatrooms to find across conversation history
2024-07-04 12:14:58 -04:00
57d8e701f2 remove username and snippet from SERP page 2024-07-04 12:04:46 -04:00
db3c15ea0d hide snippets pass room list in search page
modified:   app.py
	modified:   templates/base.html
	modified:   templates/search.html
2024-07-04 11:35:22 -04:00
926262cdaa keep keywords in search form.
modified:   app.py
	modified:   templates/base.html
2024-07-04 11:12:21 -04:00
5577821855 save username when searching
I CAN program offline without an LLM. ; )
	modified:   app.py
	modified:   templates/base.html
	modified:   templates/search.html
2024-07-04 10:57:30 -04:00
77c2ef1d83 messing around with keyword search working but ugly!
modified:   app.py
	new file:   templates/base.html
	modified:   templates/chat.html
	new file:   templates/search.html
2024-07-04 10:21:37 -04:00
e5940d3020 Fix Claude consecutive roles issue
This commit addresses the issue where the Claude model was throwing an error due to multiple consecutive "user" roles in the chat history. The following changes have been made:

- Implemented a new function `group_consecutive_roles` to group consecutive messages of the same role into one.
- Updated the `chat_claude`, function to use the `group_consecutive_roles` function before sending the chat history to the respective models.

By grouping consecutive messages of the same role, the chat history now alternates between "user" and "assistant" roles, resolving the "roles must alternate between 'user' and 'assistant'" error from the Claude model.
2024-06-22 09:47:04 -04:00
Russell Ballestrini
4575f2531f upgrade to gpt-4o
modified:   app.py
2024-05-14 10:18:43 -04:00
d882a14a8c update to hermes 2 llama 3 8B
modified:   README.rst
	modified:   app.py
2024-05-08 17:35:37 -04:00
Russell Ballestrini
a61c339671 allow mistral client to work with many models at the same time. 2024-05-01 10:43:38 -04:00
Russell Ballestrini
76e7cb83af make line numbers align on firefox
modified:   templates/chat.html
2024-04-21 11:46:49 -04:00
Russell Ballestrini
046576e128 upgrade gpt-4 to gpt-4-turbo
modified:   app.py
2024-04-21 10:22:37 -04:00
dbcdad6838 Additional groq models
modified:   README.rst
	modified:   app.py
2024-04-21 09:46:35 -04:00
a11df86f6c cut over from eventlet to gevent. use monkey patching
modified:   app.py
	modified:   requirements.txt
2024-04-20 13:40:26 -04:00
dabce4a954 allow user to prevent autoscrolling streamed chunks.
modified:   templates/chat.html
2024-04-04 10:01:32 -04:00
4037872e7e anthropic.claude-3-haiku-20240307-v1:0
modified:   README.rst
	modified:   app.py
2024-03-15 10:12:58 -04:00
Russell Ballestrini
f365e45821 Claude 3 sonnet working properly now.
modified:   README.rst
	modified:   app.py
2024-03-11 10:35:05 -04:00
Russell Ballestrini
e81a68c5d9 claude 3 sonnet
modified:   app.py
2024-03-04 11:57:24 -05:00
Russell Ballestrini
36336234c5 claude-sonnet
modified:   README.rst
	modified:   app.py
2024-03-04 11:11:41 -05:00
ad84d9a1ec nvim refactors
modified:   app.py
2024-03-04 08:36:58 -05:00
f4da537d88 mistral-large-latest is the actual model name.
modified:   app.py
2024-03-02 11:05:11 -05:00
751dd80cc1 mistral-large
modified:   README.rst
	modified:   app.py
2024-03-02 10:46:41 -05:00
Russell Ballestrini
0c856a17a4 clean up import
modified:   app.py
2024-03-01 10:33:26 -05:00
Russell Ballestrini
23e844baf9 Added groq platform support for ultra fast LLM inference
modified:   README.rst
	modified:   app.py
	modified:   requirements.txt
2024-02-28 10:32:31 -05:00
Russell Ballestrini
6cc066ecb4 upgrade to the newest gpt-4
modified:   app.py
2024-01-26 08:21:42 -05:00
9418fe5673 black 2024-01-25 08:25:31 -05:00
1b605568b2 vllm support hacked in
modified:   README.rst
	modified:   app.py
2024-01-25 08:12:01 -05:00
a72511be5d messing with running vLLM open hermes
modified:   app.py
2024-01-23 18:06:19 -05:00
0efbe93910 modified: app.py 2024-01-19 08:59:11 -05:00
f256d65391 modified: app.py 2024-01-13 11:06:41 -05:00
2f8a6c502d hacked in ability to run local llama2 models like mistral
modified:   app.py
	new file:   install-llama.sh
	modified:   requirements.txt
2024-01-13 10:05:02 -05:00
6a42dacf65 localhost openchat is working. lol
I replaced gpt-3.5-turbo workloads with openchat a local GPU powered inference server

The openchat inference server supports using the latest and official openai python client.

This means you can replace both standard and streaming workloads with an "offline" LLM.

	modified:   README.rst
	modified:   app.py
2024-01-07 14:57:40 -05:00
560d0a1ae5 small refactor 2024-01-06 11:34:53 -05:00
47d0b24fc4 add a link to the docs
modified:   templates/chat.html
2024-01-06 08:37:46 -05:00
6f70dcfc42 allow cancel on all LLMs
modified:   app.py
2024-01-06 08:12:54 -05:00
c40f961fc3
Update README.rst 2023-12-29 14:12:36 -05:00
Russell Ballestrini
d666efb162 implement together/solar
modified:   README.rst
	modified:   app.py
2023-12-29 13:28:53 -05:00
79cc174b28 modified: app.py 2023-12-22 09:05:01 -05:00
Russell Ballestrini
12abd02978 modified: README.rst 2023-12-20 09:18:35 -05:00
Russell Ballestrini
e38c565eaa add other mistralai models
modified:   app.py
2023-12-20 09:17:12 -05:00
Russell Ballestrini
c95f2722e9 modified: README.rst 2023-12-20 08:11:54 -05:00
71f8d9d15c make openchat a math assistant
modified:   app.py
2023-12-20 06:30:54 -05:00
Russell Ballestrini
12f1abc4b7 together ai integration
modified:   app.py
	modified:   requirements.txt
2023-12-19 12:55:13 -05:00
efbb6d7c26
Update README.rst 2023-12-16 11:40:00 -05:00
5918295320
Update README.rst 2023-12-16 11:38:54 -05:00
127 changed files with 70403 additions and 732 deletions

98
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,98 @@
name: Run Tests
on:
push:
branches: [ main, master, develop, claude/** ]
pull_request:
branches: [ main, master, develop ]
# Cancel in-progress runs when a new commit is pushed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-test.txt
- name: Run unit tests
run: |
pytest tests/unit/ -v --tb=short --cov=. --cov-report=term-missing
env:
SQLALCHEMY_DATABASE_URI: "sqlite:///:memory:"
TESTING: "1"
MODEL_ENDPOINT_0: "https://hermes.ai.unturf.com/v1"
MODEL_API_KEY_0: "dummy"
- name: Run functional tests
run: |
pytest tests/functional/ -v --tb=short
env:
SQLALCHEMY_DATABASE_URI: "sqlite:///:memory:"
TESTING: "1"
MODEL_ENDPOINT_0: "https://hermes.ai.unturf.com/v1"
MODEL_API_KEY_0: "dummy"
- name: Run integration tests
run: |
pytest tests/integration/ -v --tb=short
env:
SQLALCHEMY_DATABASE_URI: "sqlite:///:memory:"
TESTING: "1"
MODEL_ENDPOINT_0: "https://hermes.ai.unturf.com/v1"
MODEL_API_KEY_0: "dummy"
- name: Validate activity YAML files
run: |
python activity_yaml_validator.py research/SPEC.yaml
python activity_yaml_validator.py research/activity*.yaml
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip'
- name: Install linting dependencies
run: |
python -m pip install --upgrade pip
pip install black flake8
- name: Check code formatting with black
run: |
black --check --diff --exclude=venv .
continue-on-error: true
- name: Lint with flake8 (syntax errors)
run: |
# Stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=venv
- name: Lint with flake8 (style warnings)
run: |
# Exit-zero treats all errors as warnings
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=venv
continue-on-error: true

6
.gitignore vendored
View file

@ -1,8 +1,14 @@
*.swp
env
venv/
instance/
__pycache__/
.flaskenv
.flaskenv-exported
.aws-sam/
samconfig.toml
vars.sh
.coverage
htmlcov/
unturf-debugging.md
research/tmp*.yaml

84
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,84 @@
# GitLab CI/CD Pipeline for OpenCompletion
# Uses shell executor on build-tagged runners
stages:
- test
- lint
variables:
SQLALCHEMY_DATABASE_URI: "sqlite:///:memory:"
TESTING: "1"
MODEL_ENDPOINT_0: "https://hermes.ai.unturf.com/v1"
MODEL_API_KEY_0: "dummy"
# Template for Python setup (shell executor)
.python_setup:
tags:
- build
before_script:
- python3 -m venv venv
- source venv/bin/activate
- python3 -m pip install --upgrade pip
- pip install -r requirements.txt
- pip install -r requirements-test.txt
# Unit Tests
unit_tests:
extends: .python_setup
stage: test
script:
- source venv/bin/activate
- pytest tests/unit/ -v --tb=short --cov=. --cov-report=term-missing
# Functional Tests
functional_tests:
extends: .python_setup
stage: test
script:
- source venv/bin/activate
- pytest tests/functional/ -v --tb=short
# Integration Tests
integration_tests:
extends: .python_setup
stage: test
script:
- source venv/bin/activate
- pytest tests/integration/ -v --tb=short
# Validate Activity YAML Files
validate_yaml:
extends: .python_setup
stage: test
script:
- source venv/bin/activate
- python activity_yaml_validator.py research/SPEC.yaml
- python activity_yaml_validator.py research/activity*.yaml
# Lint - Syntax Errors (blocking)
lint_syntax:
stage: lint
tags:
- build
before_script:
- python3 -m venv venv
- source venv/bin/activate
- pip install flake8
script:
- source venv/bin/activate
- flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=venv
# Lint - Style Warnings (non-blocking)
lint_style:
stage: lint
tags:
- build
before_script:
- python3 -m venv venv
- source venv/bin/activate
- pip install black flake8
script:
- source venv/bin/activate
- black --check --diff --exclude=venv . || true
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=venv
allow_failure: true

1104
CLAUDE.md Normal file

File diff suppressed because it is too large Load diff

282
Makefile Normal file
View file

@ -0,0 +1,282 @@
# Makefile for OpenCompletion Testing Framework
.PHONY: help
help:
@echo "OpenCompletion Testing Framework"
@echo "================================"
@echo ""
@echo "🧪 Test Commands:"
@echo " test - Run all tests (unit, integration, functional)"
@echo " test-unit - Run only unit tests"
@echo " test-integration - Run only integration tests"
@echo " test-functional - Run only functional tests"
@echo " test-validator - Run YAML validator tests"
@echo " test-yaml-loading - Run YAML loading/parsing tests"
@echo " test-activity-flows - Run activity flow tests"
@echo " test-battleship - Run battleship game tests"
@echo " test-guarded-ai - Run guarded_ai.py functionality tests"
@echo " test-multiple-files - Run integration tests across all activity files"
@echo ""
@echo "📋 Validation Commands:"
@echo " validate-yaml - Validate all YAML files in research/"
@echo ""
@echo "🛠️ Development Commands:"
@echo " venv - Create virtual environment and install dependencies"
@echo " dev-setup - Install development dependencies"
@echo " lint - Run code linting and formatting"
@echo " clean - Clean up generated files"
@echo " clean-all - Remove virtual environment"
# Setup virtual environment
.PHONY: venv
venv:
@if [ ! -d "venv" ]; then \
echo "🚀 Creating virtual environment..."; \
python3 -m venv venv; \
echo "📦 Installing basic dependencies..."; \
venv/bin/pip install --upgrade pip; \
venv/bin/pip install -r requirements.txt || echo "⚠️ Failed to install basic dependencies"; \
echo "✅ Virtual environment ready!"; \
else \
echo "✅ Virtual environment already exists"; \
fi
# ============================================================================
# MAIN TEST COMMANDS
# ============================================================================
# Run all tests
.PHONY: test
test: test-unit test-integration test-functional test-validator test-yaml-loading test-activity-flows test-battleship test-guarded-ai test-multiple-files validate-yaml
@echo ""
@echo "🎉 All tests completed!"
@echo "📊 Test Summary:"
@echo " ✅ Unit tests - Core functionality"
@echo " ✅ Integration tests - Cross-component testing"
@echo " ✅ Functional tests - End-to-end workflows"
@echo " ✅ YAML validation - All activity files"
@echo " ✅ All specific test targets completed"
# Run unit tests only
.PHONY: test-unit
test-unit: venv
@echo "🔬 Running unit tests..."
@if command -v pytest >/dev/null 2>&1; then \
python -m pytest tests/unit/ -v --tb=short; \
else \
echo "📝 Running unit tests directly..."; \
python tests/unit/test_yaml_loading.py; \
python tests/unit/test_activity_yaml_validator.py; \
fi
# Run integration tests only
.PHONY: test-integration
test-integration: venv
@echo "🔗 Running integration tests..."
@if command -v pytest >/dev/null 2>&1; then \
python -m pytest tests/integration/ -v --tb=short; \
else \
echo "📝 Running integration tests directly..."; \
python tests/integration/test_multiple_activities.py; \
fi
# Run functional tests only
.PHONY: test-functional
test-functional: venv
@echo "⚡ Running functional tests..."
@if command -v pytest >/dev/null 2>&1; then \
python -m pytest tests/functional/ -v --tb=short; \
else \
echo "📝 Running functional tests directly..."; \
python tests/functional/test_activity_flows.py; \
python tests/functional/test_battleship_pre_script.py; \
fi
# ============================================================================
# SPECIFIC TEST COMMANDS
# ============================================================================
# Run YAML validator tests only
.PHONY: test-validator
test-validator: venv
@echo "📋 Running YAML validator tests..."
python tests/unit/test_activity_yaml_validator.py
# Run YAML loading tests only
.PHONY: test-yaml-loading
test-yaml-loading: venv
@echo "📄 Running YAML loading/parsing tests..."
python tests/unit/test_yaml_loading.py
# Run activity flow tests
.PHONY: test-activity-flows
test-activity-flows: venv
@echo "🔄 Running activity flow tests..."
python tests/functional/test_activity_flows.py
# Run battleship game tests
.PHONY: test-battleship
test-battleship: venv
@echo "🚢 Running battleship game tests..."
python tests/functional/test_battleship_pre_script.py
# Run guarded_ai functionality tests
.PHONY: test-guarded-ai
test-guarded-ai: venv
@echo "🛡️ Running guarded_ai.py functionality tests..."
python tests/integration/test_regression_fixes.py
# Run integration tests across all activity files
.PHONY: test-multiple-files
test-multiple-files: venv
@echo "📁 Running integration tests across all activity files..."
python tests/integration/test_multiple_activities.py
# ============================================================================
# VALIDATION COMMANDS
# ============================================================================
# Validate all YAML files
.PHONY: validate-yaml
validate-yaml: venv
@echo "📋 Validating all YAML files..."
python activity_yaml_validator.py research/*.yaml
# ============================================================================
# DEVELOPMENT AND CI/CD COMMANDS
# ============================================================================
# Run tests with coverage (requires pytest and coverage)
.PHONY: test-cov
test-cov: dev-setup
@echo "📊 Running tests with coverage..."
venv/bin/pip install pytest-cov
venv/bin/python -m pytest tests/ --cov=. --cov-report=html --cov-report=term-missing -v
# Format and lint code
.PHONY: format
format: dev-setup
@echo "🎨 Formatting code..."
venv/bin/black .
venv/bin/isort .
.PHONY: lint
lint: dev-setup
@echo "🔍 Linting code..."
venv/bin/black --check .
venv/bin/isort --check-only .
venv/bin/flake8 .
# Install development dependencies
.PHONY: dev-setup
dev-setup: venv
@echo "🛠️ Installing development dependencies..."
venv/bin/pip install black flake8 isort pytest coverage
@echo "✅ Development environment ready!"
# ============================================================================
# CI/CD AND AUTOMATION COMMANDS
# ============================================================================
# Full CI pipeline
.PHONY: ci
ci: clean test validate-yaml lint
@echo ""
@echo "🎯 CI Pipeline Results:"
@echo " ✅ Tests passed"
@echo " ✅ YAML validation passed"
@echo " ✅ Code linting completed"
@echo "🚀 Ready for deployment!"
# ============================================================================
# UTILITY COMMANDS
# ============================================================================
# Clean generated files
.PHONY: clean
clean:
@echo "🧹 Cleaning generated files..."
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
find . -name "*.pyo" -delete 2>/dev/null || true
find . -name "*~" -delete 2>/dev/null || true
.PHONY: init-db
init-db:
@echo "🗄️ Initializing database tables..."
@if [ -f vars.sh ]; then \
. ./vars.sh && python init_db.py; \
echo "✅ Database tables created successfully"; \
else \
echo "❌ Error: vars.sh not found. Please create it from vars.sh.sample"; \
exit 1; \
fi
clean-cache:
rm -rf .pytest_cache/ 2>/dev/null || true
rm -rf htmlcov/ 2>/dev/null || true
rm -rf .coverage 2>/dev/null || true
rm -rf *.tmp 2>/dev/null || true
# Remove virtual environment
.PHONY: clean-all
clean-all: clean
@echo "💣 Removing virtual environment..."
rm -rf venv
# Show test structure
.PHONY: test-info
test-info:
@echo "📁 Test Structure:"
@echo " tests/"
@echo " ├── unit/ - Unit tests for individual components"
@echo " │ ├── test_yaml_loading.py - YAML loading/parsing tests"
@echo " │ └── test_activity_yaml_validator.py - Validator functionality tests"
@echo " ├── integration/ - Integration tests across components"
@echo " │ ├── test_multiple_activities.py - Tests across all activity files"
@echo " │ └── test_regression_fixes.py - Regression and fix validation"
@echo " └── functional/ - End-to-end functional tests"
@echo " ├── test_activity_flows.py - Complete activity workflows"
@echo " └── test_battleship_pre_script.py - Battleship game functionality"
@echo ""
@echo "🎯 Key Test Commands:"
@echo " make test - Run all tests"
@echo " make validate-yaml - Validate all YAML files"
# ============================================================================
# CODE EXECUTOR API TESTING
# ============================================================================
# Test artifact retrieval - compile C code, get base64 binary, decode and test execution
# URL can be overridden: make test-artifact URL=https://code.ai.unturf.com
.PHONY: test-artifact
test-artifact:
$(eval URL ?= http://127.0.0.1:8080)
@echo "=========================================="
@echo "Testing Binary Artifact Retrieval"
@echo "=========================================="
@echo "API: $(URL)"
@echo ""
@echo "Step 1: Compiling C code and retrieving base64 binary..."
@curl -s -X POST $(URL)/execute \
-H "Content-Type: application/json" \
-d '{"language": "c", "code": "#include <stdio.h>\nint main() { printf(\"Hello from artifact!\\n\"); return 0; }", "return_artifact": true}' \
| jq -r '.stdout.artifact.data' > /tmp/artifact.b64
@echo "✓ Base64 artifact saved to /tmp/artifact.b64"
@echo " Size: $$(wc -c < /tmp/artifact.b64) bytes (base64)"
@echo ""
@echo "Step 2: Decoding base64 to binary..."
@base64 -d /tmp/artifact.b64 > /tmp/artifact_binary
@chmod +x /tmp/artifact_binary
@echo "✓ Binary decoded to /tmp/artifact_binary"
@echo " Size: $$(wc -c < /tmp/artifact_binary) bytes (ELF binary)"
@echo ""
@echo "Step 3: Verifying ELF binary..."
@file /tmp/artifact_binary
@echo ""
@echo "Step 4: Executing binary..."
@/tmp/artifact_binary
@echo ""
@echo "✓ Artifact test complete!"
@echo ""
@echo "Cleanup: rm /tmp/artifact.b64 /tmp/artifact_binary"

View file

@ -1,28 +1,27 @@
flask-socketio-llm-completions
Open Completion
========================================
This project is a chatroom application that allows users to join different chat rooms, send messages, and interact with multiple language models in real-time. The backend is built with Flask and Flask-SocketIO for real-time web communication, while the frontend uses HTML, CSS, and JavaScript to provide an interactive user interface.
* repo: `opencompletion.com <https://opencompletion.com>`_
.. image:: flask-socketio-llm-completions.png
:alt: Flask-SocketIO LLM Completions
:align: center
.. image:: flask-socketio-llm-completions-2.png
:alt: Flask-SocketIO LLM Completions Dall-e-3
:align: center
* demo: `demo.opencompletion.com <https://demo.opencompletion.com>`_
Chatroom applicationallows users to join rooms, send messages, & interact with multiple language models in real-time. Backend written with Flask & Flask-SocketIO for real-time web socket streaming. Frontend uses minimal HTML, CSS, & JavaScript to provide an interactive user interface.
Features
--------
- Real-time messaging between users in a chatroom.
- Ability to join different chatrooms with unique URLs.
- Integration with OpenAI's language models for generating room titles and processing messages.
- Integration with language models for generating room titles and processing messages.
- Syntax highlighting for code blocks within messages.
- Markdown rendering for messages.
- **Code execution**: Run code blocks directly in the browser with support for 38+ programming languages.
- **Text-to-speech**: Convert AI responses to speech with multiple voice options.
- Commands to load and save code blocks to AWS S3.
- Database storage for messages and chatrooms using SQLAlchemy.
- Migration support with Flask-Migrate.
- Email OTP authentication with private room support
- Room forking, archiving, and owner management
Requirements
------------
@ -34,8 +33,7 @@ Requirements
- Flask-Migrate
- eventlet or gevent
- boto3 (for interacting with AWS Bedrock currently Claude, and S3 access)
- openai (for interacting with OpenAI's language models)
- mistralai (for interacting with MistralAI's language models)
- OpenAI client (for interacting with vLLM & Ollama inference servers)
Installation
------------
@ -44,27 +42,25 @@ To set up the project, follow these steps:
1. Clone this repository::
git clone https://github.com/russellballestrini/flask-socketio-llm-completions.git
cd flask-socketio-llm-completions
git clone https://github.com/russellballestrini/opencompletion.git
cd opencompletion
**Git Remotes**: This repo is configured to push to both GitHub and unturf simultaneously.
The ``origin`` remote has two push URLs:
- GitHub: ``git@github.com:russellballestrini/opencompletion.git``
- unturf: ``ssh://git@git.unturf.com:2222/engineering/unturf/opencompletion.com.git``
2. Create a virtual environment and activate it::
python3 -m venv ven
python3 -m venv env
source env/bin/activate # On Windows use `env\Scripts\activate`
3. Install the required dependencies::
pip install -r requirements.txt
4. Set up environment variables for your AWS credentials and OpenAI API key::
export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"
export S3_BUCKET_NAME="your_s3_bucket_name"
export OPENAI_API_KEY="your_openai_api_key"
export MISTRAL_API_KEY="your_mistralai_api_key"
5. Initialize the database:
4. Initialize the database:
Before running the application for the first time, you need to create the database and tables, and then stamp the Alembic migrations to mark them as up to date. Follow these steps::
@ -74,11 +70,43 @@ To set up the project, follow these steps:
Usage
-----
Set up environment variables for your AWS, OpenAI, MistralAI, together.ai, grok, groq, google, API keys.
* make a copy of ``vars.sh.sample`` and fill in your API keys!
Other env vars::
export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"
export S3_BUCKET_NAME="your_s3_bucket_name"
Here are some free endpoint for research only!::
export MODEL_ENDPOINT_1=https://hermes.ai.unturf.com/v1
export MODEL_ENDPOINT_2=https://qwen.ai.unturf.com/v1
export MODEL_ENDPOINT_3=https://gpt-oss.ai.unturf.com/v1
Optional SMTP for email OTP authentication::
export SMTP_HOST=smtp.gmail.com
export SMTP_PORT=587
export SMTP_USER=your@email.com
export SMTP_PASSWORD=your_app_password
To start the application with socket.io run::
python app.py
Optionally pass ``python app.py --profile <aws-profile-name>``
Optionally flags ``python app.py --local-activities --profile <aws-profile-name>``::
usage: app.py [-h] [--profile PROFILE] [--local-activities] [--port PORT]
options:
-h, --help show this help message and exit
--profile PROFILE AWS profile name
--local-activities Use local activity files instead of S3
--port PORT Port number (default: 5001)
The application will be available at ``http://127.0.0.1:5001`` by default.
@ -86,36 +114,24 @@ The application will be available at ``http://127.0.0.1:5001`` by default.
Interacting with Language Models
--------------------------------
To interact with the various language models, you can use the following commands within the chat:
- For GPT-3, send a message with ``gpt-3`` and include your prompt.
- For GPT-4, send a message with ``gpt-4`` and include your prompt.
- For Claude-v1, send a message with ``claude-v1`` and include your prompt.
- For Claude-v2, send a message with ``claude-v2`` and include your prompt.
- For Mistral-tiny, send a message with ``mistral`` and include your prompt.
- For Dall-e-3, send a message with ``dall-e-3`` and include your prompt.
To interact with the various language models, choose from the drop down and send a message!
The system will process your message and provide a response from the selected language model.
Commands
--------
The application supports special commands for interacting with the chatroom:
The chatrooms support some special commands:
- ``/s3 load <file_path>``: Loads a file from S3 and displays its content in the chatroom.
- ``/s3 save <file_path>``: Saves the most recent code block from the chatroom to S3.
- ``/s3 ls <file_s3_path_pattern>``: Lists files from S3 that match the given pattern. Use ``*`` to list all files.
- ``/title new``: Generates a new title which reflects conversation content for the current chatroom using gpt-4.
- ``/cancel``: Cancel the most recent chat completion from streaming into the chatroom.
- ``/python``: Executes the most recent Python code block sent in the chatroom and returns the output or any errors.
- ``/help``: Displays the list of commands and models to choose from.
The ``/s3 ls`` command can be used to list files in the connected S3 bucket. You can specify a pattern to filter the files listed. For example:
Code Execution
--------------
- ``/s3 ls *`` will list all files in the bucket.
- ``/s3 ls *.py`` will list all Python files.
- ``/s3 ls README.*`` will list files starting with "README." and any extension.
Code blocks can be executed directly in the browser using the "▶ Run" button. Supports 30+ programming languages with automatic language detection. Code runs in isolated, self-terminating sandbox containers. Compiled binaries can be downloaded directly from the interface.
The command will return the file name, size in bytes, and the last modified timestamp for each file that matches the pattern.
Structure
---------
@ -124,13 +140,71 @@ Structure
- ``chat.html``: The HTML template for the chatroom interface.
- ``static/``: Directory for static files like CSS, JavaScript, and images.
- ``templates/``: Directory for HTML templates.
- ``research/``: Guarded AI activities or processes. Example YAMLs.
Activity Mode
--------------
Activity mode is an interactive experience where users can engage with a guided AI to learn and answer questions.
The AI provides feedback based on the user's responses and guides them through different sections and steps of an activity.
This mode is designed to be on the "rails", educational, & engaging.
The server expects to load the YAML file out of the S3 bucket you specify in your environment variables.
1. **Start an Activity**: Use the ``/activity`` command followed by the object path to the activity YAML file to start a new activity.
``/activity path-to-activity.yaml``
2. **Display Activity Info**: Use the ``/activity info`` command to display AI information about the current activity, including grading and user performance.
``/activity info``
3. **Display Activity Metadata**: Use the ``/activity metadata`` command to display metadata information collected about the activity.
``/activity metadata``
4. **Cancel an Activity**: Use the ``/activity cancel`` command to display cancel the current activity running in the room.
``/activity cancel``
5. **Battleship example**:
``/activity research/activity29-battleship.yaml``
.. image:: flask-socketio-llm-completions-battleship.png
:align: center
Ollama versus vLLM
-----------------------------
We prefer operating an ``vllm`` inference server but some models are packaged exclusively for ``ollama`` so here is an example::
ollama run hf.co/NousResearch/Hermes-3-Llama-3.1-8B-GGUF:Q8_0
then::
export MODEL_ENDPOINT_1=https://localhost:11434/v1
Then in the app you should be able to talk to ``NousResearch/Hermes-3-Llama-3.1-8B-GGUF:Q8_0``
Contributing
------------
Contributions to this project are welcome. Please follow the standard fork and pull request workflow.
License
-------
This project is public domain. It is free for use and distribution without any restrictions.
.. figure:: https://api.star-history.com/svg?repos=russellballestrini/opencompletion&type=Date
:alt: Star History Chart

1675
activity.py Normal file

File diff suppressed because it is too large Load diff

354
activity_utils.py Normal file
View file

@ -0,0 +1,354 @@
"""
Utility functions for OpenCompletion Activity System v2.0
Features:
- Template variable rendering ({{metadata.key}}, {{current_attempt}}, etc.)
- Advanced metadata conditions (gte, lt, contains, regex, etc.)
- Conditional content blocks (show_if)
- Conditional navigation (if/elif/else)
- Weighted random selection
- Progressive hints
"""
import re
import random
from typing import Any, Dict, List, Optional, Union
def render_template(text: str, context: Dict[str, Any]) -> str:
"""
Render template variables in text using {{variable}} syntax.
Supports:
- {{metadata.key}} - Access metadata values
- {{current_attempt}} - Current attempt number
- {{max_attempts}} - Maximum attempts
- {{attempts_remaining}} - Remaining attempts
- {{current_section}} - Current section ID
- {{current_step}} - Current step ID
- {{username}} - Last responding username
Args:
text: Text containing {{variable}} templates
context: Dictionary with metadata, attempts, section/step info
Returns:
Text with variables replaced
"""
if not isinstance(text, str):
return text
# Find all {{variable}} patterns
pattern = r"\{\{([^}]+)\}\}"
def replace_variable(match):
var_name = match.group(1).strip()
# Handle metadata.key syntax
if var_name.startswith("metadata."):
key = var_name[9:] # Remove 'metadata.' prefix
metadata = context.get("metadata", {})
value = metadata.get(
key, f"{{{{metadata.{key}}}}}"
) # Keep original if not found
return str(value) if value is not None else ""
# Handle built-in variables
value = context.get(
var_name, f"{{{{{var_name}}}}}"
) # Keep original if not found
return str(value) if value is not None else ""
return re.sub(pattern, replace_variable, text)
def evaluate_condition(
metadata: Dict[str, Any], condition_key: str, condition_value: Any
) -> bool:
"""
Evaluate a single condition against metadata.
Supports operators:
- key: value - Equality
- key_ne: value - Not equal
- key_gt: value - Greater than
- key_gte: value - Greater than or equal
- key_lt: value - Less than
- key_lte: value - Less than or equal
- key_between: [min, max] - Between (inclusive)
- key_contains: value - Comma-separated list contains value
- key_not_contains: value - List does NOT contain value
- key_matches: pattern - Regex match
- key_exists: true/false - Key existence check
- key_not_exists: true/false - Key non-existence check
Args:
metadata: Metadata dictionary to check
condition_key: Condition key (may have operator suffix)
condition_value: Expected value
Returns:
True if condition met, False otherwise
"""
# Check for operator suffixes
if condition_key.endswith("_ne"):
key = condition_key[:-3]
return metadata.get(key) != condition_value
elif condition_key.endswith("_gt"):
key = condition_key[:-3]
try:
return float(metadata.get(key, 0)) > float(condition_value)
except (ValueError, TypeError):
return False
elif condition_key.endswith("_gte"):
key = condition_key[:-4]
try:
return float(metadata.get(key, 0)) >= float(condition_value)
except (ValueError, TypeError):
return False
elif condition_key.endswith("_lt"):
key = condition_key[:-3]
try:
return float(metadata.get(key, 0)) < float(condition_value)
except (ValueError, TypeError):
return False
elif condition_key.endswith("_lte"):
key = condition_key[:-4]
try:
return float(metadata.get(key, 0)) <= float(condition_value)
except (ValueError, TypeError):
return False
elif condition_key.endswith("_between"):
key = condition_key[:-8]
if not isinstance(condition_value, list) or len(condition_value) != 2:
return False
try:
val = float(metadata.get(key, 0))
return float(condition_value[0]) <= val <= float(condition_value[1])
except (ValueError, TypeError):
return False
elif condition_key.endswith("_not_contains"):
key = condition_key[:-13]
value_str = str(metadata.get(key, ""))
items = [item.strip() for item in value_str.split(",") if item.strip()]
return str(condition_value) not in items
elif condition_key.endswith("_contains"):
key = condition_key[:-9]
value_str = str(metadata.get(key, ""))
# Split by comma and check if condition_value is in list
items = [item.strip() for item in value_str.split(",") if item.strip()]
return str(condition_value) in items
elif condition_key.endswith("_matches"):
key = condition_key[:-8]
value_str = str(metadata.get(key, ""))
try:
return bool(re.search(str(condition_value), value_str))
except re.error:
return False
elif condition_key.endswith("_not_exists"):
key = condition_key[:-11]
if condition_value:
return key not in metadata
else:
return key in metadata
elif condition_key.endswith("_exists"):
key = condition_key[:-7]
if condition_value:
return key in metadata
else:
return key not in metadata
else:
# Simple equality check
return metadata.get(condition_key) == condition_value
def check_conditions(metadata: Dict[str, Any], conditions: Dict[str, Any]) -> bool:
"""
Check if ALL conditions are met (AND logic).
Args:
metadata: Metadata dictionary
conditions: Dictionary of condition_key: condition_value pairs
Returns:
True if all conditions met, False otherwise
"""
if not conditions:
return True
return all(
evaluate_condition(metadata, key, value) for key, value in conditions.items()
)
def filter_content_blocks(
content_blocks: List[Union[str, Dict[str, Any]]],
metadata: Dict[str, Any],
context: Dict[str, Any],
) -> List[str]:
"""
Filter and render content blocks based on show_if conditions.
Content blocks can be:
- Simple strings: Always shown
- Objects with 'text' and 'show_if': Conditionally shown
Args:
content_blocks: List of content blocks (strings or dicts)
metadata: Metadata dictionary for condition evaluation
context: Template rendering context
Returns:
List of rendered text strings that passed conditions
"""
result = []
for block in content_blocks:
if isinstance(block, str):
# Simple string - always show, just render templates
rendered = render_template(block, context)
result.append(rendered)
elif isinstance(block, dict):
# Conditional block - check show_if condition
text = block.get("text", "")
show_if = block.get("show_if", {})
# Check if conditions are met
if check_conditions(metadata, show_if):
rendered = render_template(text, context)
result.append(rendered)
return result
def resolve_conditional_navigation(
next_section_and_step: Union[str, List[Dict[str, Any]]], metadata: Dict[str, Any]
) -> Optional[str]:
"""
Resolve conditional navigation (if/elif/else structure).
Args:
next_section_and_step: Either a string or list of conditional branches
metadata: Metadata dictionary for condition evaluation
Returns:
Resolved "section:step" string or None
"""
# Simple string - return as-is
if isinstance(next_section_and_step, str):
return next_section_and_step
# Conditional branches
if isinstance(next_section_and_step, list):
for branch in next_section_and_step:
if "if" in branch:
# if branch
if check_conditions(metadata, branch["if"]):
return branch.get("goto")
elif "elif" in branch:
# elif branch
if check_conditions(metadata, branch["elif"]):
return branch.get("goto")
elif "else" in branch:
# else branch - always taken if reached
return branch.get("goto")
return None
def select_weighted_random(weighted_options: List[Dict[str, Any]]) -> Any:
"""
Select a random value from weighted options.
Args:
weighted_options: List of dicts with 'value' and 'weight' keys
Returns:
Selected value
"""
if not weighted_options:
return None
# Extract values and weights
values = [opt["value"] for opt in weighted_options]
weights = [opt.get("weight", 1) for opt in weighted_options]
# Use random.choices for weighted selection
selected = random.choices(values, weights=weights, k=1)
return selected[0]
def get_progressive_hint(
hints: List[Dict[str, Any]], current_attempt: int, context: Dict[str, Any]
) -> Optional[Dict[str, Any]]:
"""
Get the hint for the current attempt number, if one exists.
Args:
hints: List of hint dicts with 'attempt', 'text', 'counts_as_attempt' keys
current_attempt: Current attempt number (1, 2, 3, ...)
context: Template rendering context
Returns:
Hint dict with rendered text, or None if no hint for this attempt
"""
if not hints:
return None
for hint in hints:
if hint.get("attempt") == current_attempt:
# Render template variables in hint text
hint_text = render_template(hint.get("text", ""), context)
return {
"text": hint_text,
"counts_as_attempt": hint.get("counts_as_attempt", False),
}
return None
def create_template_context(
metadata: Dict[str, Any],
current_attempt: int,
max_attempts: int,
current_section: str,
current_step: str,
username: str = "User",
) -> Dict[str, Any]:
"""
Create a template rendering context with all built-in variables.
Args:
metadata: Activity metadata
current_attempt: Current attempt number
max_attempts: Maximum attempts allowed
current_section: Current section ID
current_step: Current step ID
username: Username of last responder
Returns:
Context dictionary for template rendering
"""
return {
"metadata": metadata,
"current_attempt": current_attempt,
"max_attempts": max_attempts,
"attempts_remaining": max(0, max_attempts - current_attempt),
"current_section": current_section,
"current_step": current_step,
"username": username,
}

1143
activity_yaml_validator.py Normal file

File diff suppressed because it is too large Load diff

2403
app.py

File diff suppressed because it is too large Load diff

239
auth.py Normal file
View file

@ -0,0 +1,239 @@
"""Authentication module for email OTP-based authentication"""
import os
import random
import smtplib
import socket
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
from functools import wraps
from flask import session, jsonify, request
from models import db, User, OTPToken
def generate_otp():
"""Generate a 6-digit OTP code"""
return ''.join([str(random.randint(0, 9)) for _ in range(6)])
def send_otp_email(email, otp_code):
"""Send OTP code to user's email via SMTP
Attempts to send via localhost:25 first. If that fails, tries configured SMTP.
Falls back to console output if all methods fail.
Optional environment variables (only needed if localhost SMTP unavailable):
- SMTP_HOST: SMTP server hostname (e.g., smtp.gmail.com)
- SMTP_PORT: SMTP server port (e.g., 587)
- SMTP_USER: SMTP username/email
- SMTP_PASSWORD: SMTP password or app-specific password
- SMTP_FROM_EMAIL: Email address to send from (auto-detected if not set)
- SMTP_FROM_NAME: Display name for sender
"""
smtp_host = os.environ.get('SMTP_HOST')
smtp_port = int(os.environ.get('SMTP_PORT', '587')) if smtp_host else 587
smtp_user = os.environ.get('SMTP_USER')
smtp_password = os.environ.get('SMTP_PASSWORD')
# Auto-detect sender email domain from request or hostname
def get_default_from_email():
# Try to get domain from Flask request context
try:
host = request.host
# Skip localhost/127.0.0.1
if host and not host.startswith('localhost') and not host.startswith('127.0.0.1'):
# Remove port if present
domain = host.split(':')[0]
return f'noreply@{domain}'
except RuntimeError:
# No request context available
pass
# Fall back to system hostname
try:
hostname = socket.getfqdn()
if hostname and hostname != 'localhost':
return f'noreply@{hostname}'
except Exception:
pass
# Final fallback
return smtp_user or 'noreply@opencompletion.local'
from_email = os.environ.get('SMTP_FROM_EMAIL', get_default_from_email())
from_name = os.environ.get('SMTP_FROM_NAME', 'OpenCompletion')
# Create message
msg = MIMEMultipart('alternative')
msg['Subject'] = f'Your OpenCompletion verification code: {otp_code}'
msg['From'] = f'{from_name} <{from_email}>'
msg['To'] = email
# Plain text version
text = f"""
Your OpenCompletion verification code is: {otp_code}
This code will expire in 10 minutes.
If you didn't request this code, you can safely ignore this email.
"""
# HTML version
html = f"""
<html>
<body style="font-family: Arial, sans-serif; padding: 20px;">
<h2>Your OpenCompletion Verification Code</h2>
<p>Enter this code to complete your authentication:</p>
<h1 style="background-color: #f0f0f0; padding: 15px; text-align: center; letter-spacing: 5px;">
{otp_code}
</h1>
<p style="color: #666;">This code will expire in 10 minutes.</p>
<p style="color: #999; font-size: 12px;">
If you didn't request this code, you can safely ignore this email.
</p>
</body>
</html>
"""
# Attach both versions
msg.attach(MIMEText(text, 'plain'))
msg.attach(MIMEText(html, 'html'))
# Try localhost:25 first (common for development with local mail server)
try:
with smtplib.SMTP('localhost', 25, timeout=2) as server:
server.send_message(msg)
print(f"[INFO] OTP sent via localhost:25 to {email}")
return True
except (ConnectionRefusedError, OSError, smtplib.SMTPException) as e:
# Localhost not available, try configured SMTP if available
if smtp_host and smtp_user and smtp_password:
try:
with smtplib.SMTP(smtp_host, smtp_port, timeout=10) as server:
server.starttls()
server.login(smtp_user, smtp_password)
server.send_message(msg)
print(f"[INFO] OTP sent via {smtp_host} to {email}")
return True
except Exception as smtp_error:
print(f"[ERROR] Failed to send OTP via {smtp_host}: {smtp_error}")
# Fall back to console output
print(f"\n{'='*60}")
print(f"[DEVELOPMENT] OTP Email - localhost:25 unavailable")
print(f"{'='*60}")
print(f"To: {email}")
print(f"Subject: Your OpenCompletion verification code: {otp_code}")
print(f"\nOTP CODE: {otp_code}")
print(f"\nThis code expires in 10 minutes.")
print(f"{'='*60}\n")
# Return True to allow development workflow
return True
def create_otp_token(email):
"""Create and store an OTP token for the given email"""
# Invalidate any existing unused OTP tokens for this email
existing_tokens = OTPToken.query.filter_by(email=email, used=False).all()
for token in existing_tokens:
token.used = True
# Generate new OTP
otp_code = generate_otp()
otp_token = OTPToken(email=email, otp_code=otp_code)
db.session.add(otp_token)
db.session.commit()
return otp_token
def verify_otp(email, otp_code):
"""Verify an OTP code for the given email
Returns:
- OTPToken object if valid
- None if invalid
"""
otp_token = OTPToken.query.filter_by(
email=email,
otp_code=otp_code,
used=False
).first()
if otp_token and otp_token.is_valid():
# Mark as used
otp_token.used = True
db.session.commit()
return otp_token
return None
def get_or_create_user(email):
"""Get existing user by email or return None if doesn't exist"""
return User.query.filter_by(email=email).first()
def create_user(email, display_name):
"""Create a new user with email and display name"""
# Check if display name is already taken
existing_user = User.query.filter_by(display_name=display_name).first()
if existing_user:
return None, "Display name already taken"
# Check if email already exists
existing_email = User.query.filter_by(email=email).first()
if existing_email:
return None, "Email already registered"
user = User(email=email, display_name=display_name)
db.session.add(user)
db.session.commit()
return user, None
def login_user(user):
"""Create session for authenticated user"""
session['user_id'] = user.id
session['user_email'] = user.email
session['display_name'] = user.display_name
session.permanent = True # Use permanent session
# Update last login
user.last_login = datetime.utcnow()
db.session.commit()
def logout_user():
"""Clear user session"""
session.pop('user_id', None)
session.pop('user_email', None)
session.pop('display_name', None)
def get_current_user():
"""Get currently authenticated user from session"""
user_id = session.get('user_id')
if user_id:
return User.query.get(user_id)
return None
def require_auth(f):
"""Decorator to require authentication for a route"""
@wraps(f)
def decorated_function(*args, **kwargs):
user = get_current_user()
if not user:
return jsonify({'error': 'Authentication required'}), 401
return f(*args, **kwargs)
return decorated_function
def is_authenticated():
"""Check if current request is authenticated"""
return 'user_id' in session

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Before After
Before After

6
install-llama.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
# make sure your python virtual env is already sourced and active.
export CMAKE_ARGS="-DLLAMA_CUBLAS=on"
export FORCE_CMAKE=1
pip install --upgrade llama-cpp-python[server]

View file

@ -12,32 +12,31 @@ config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
logger = logging.getLogger("alembic.env")
def get_engine():
try:
# this works with Flask-SQLAlchemy<3 and Alchemical
return current_app.extensions['migrate'].db.get_engine()
return current_app.extensions["migrate"].db.get_engine()
except (TypeError, AttributeError):
# this works with Flask-SQLAlchemy>=3
return current_app.extensions['migrate'].db.engine
return current_app.extensions["migrate"].db.engine
def get_engine_url():
try:
return get_engine().url.render_as_string(hide_password=False).replace(
'%', '%%')
return get_engine().url.render_as_string(hide_password=False).replace("%", "%%")
except AttributeError:
return str(get_engine().url).replace('%', '%%')
return str(get_engine().url).replace("%", "%%")
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option('sqlalchemy.url', get_engine_url())
target_db = current_app.extensions['migrate'].db
config.set_main_option("sqlalchemy.url", get_engine_url())
target_db = current_app.extensions["migrate"].db
# other values from the config, defined by the needs of env.py,
# can be acquired:
@ -46,7 +45,7 @@ target_db = current_app.extensions['migrate'].db
def get_metadata():
if hasattr(target_db, 'metadatas'):
if hasattr(target_db, "metadatas"):
return target_db.metadatas[None]
return target_db.metadata
@ -64,9 +63,7 @@ def run_migrations_offline():
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=get_metadata(), literal_binds=True
)
context.configure(url=url, target_metadata=get_metadata(), literal_binds=True)
with context.begin_transaction():
context.run_migrations()
@ -84,13 +81,13 @@ def run_migrations_online():
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
if getattr(config.cmd_opts, "autogenerate", False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
logger.info("No changes in schema detected.")
conf_args = current_app.extensions['migrate'].configure_args
conf_args = current_app.extensions["migrate"].configure_args
if conf_args.get("process_revision_directives") is None:
conf_args["process_revision_directives"] = process_revision_directives
@ -98,9 +95,7 @@ def run_migrations_online():
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=get_metadata(),
**conf_args
connection=connection, target_metadata=get_metadata(), **conf_args
)
with context.begin_transaction():

View file

@ -5,23 +5,25 @@ Revises: a9e886c56482
Create Date: 2023-12-07 08:55:50.378439
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.orm import Session
# revision identifiers, used by Alembic.
revision = '190d5ef26e20'
down_revision = 'a9e886c56482'
revision = "190d5ef26e20"
down_revision = "a9e886c56482"
branch_labels = None
depends_on = None
from app import Message
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('message', schema=None) as batch_op:
batch_op.add_column(sa.Column('token_count', sa.Integer(), nullable=True))
with op.batch_alter_table("message", schema=None) as batch_op:
batch_op.add_column(sa.Column("token_count", sa.Integer(), nullable=True))
# Use this binding to connect to the database
bind = op.get_bind()
@ -38,5 +40,5 @@ def upgrade():
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('message', schema=None) as batch_op:
batch_op.drop_column('token_count')
with op.batch_alter_table("message", schema=None) as batch_op:
batch_op.drop_column("token_count")

View file

@ -0,0 +1,34 @@
"""user session table
Revision ID: 1ac5a8e0f577
Revises: 38a330686a17
Create Date: 2024-11-23 11:25:01.723169
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import sqlite
# revision identifiers, used by Alembic.
revision = "1ac5a8e0f577"
down_revision = "38a330686a17"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"user_session",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("session_id", sa.String(length=128), nullable=False),
sa.Column("username", sa.String(length=128), nullable=True),
sa.Column("room_name", sa.String(length=128), nullable=True),
sa.Column("room_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("session_id"),
)
def downgrade():
op.drop_table("user_session")

View file

@ -0,0 +1,58 @@
"""Add authentication system with User, OTPToken models and Room ownership fields
Revision ID: 2025011100
Revises: 5d93cdf18549
Create Date: 2025-01-11 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import sqlite
# revision identifiers, used by Alembic.
revision = "2025011100"
down_revision = "5d93cdf18549"
branch_labels = None
depends_on = None
def upgrade():
# Add new columns to Room table
# Note: User and OTPToken tables are created by db.create_all() in make init-db
# Check if columns exist before adding (in case db.create_all() was run first)
conn = op.get_bind()
inspector = sa.inspect(conn)
columns = [col['name'] for col in inspector.get_columns('room')]
if 'is_private' not in columns:
op.add_column('room', sa.Column('is_private', sa.Boolean(), nullable=False, server_default='0'))
if 'is_archived' not in columns:
op.add_column('room', sa.Column('is_archived', sa.Boolean(), nullable=False, server_default='0'))
if 'owner_id' not in columns:
op.add_column('room', sa.Column('owner_id', sa.Integer(), nullable=True))
if 'created_at' not in columns:
op.add_column('room', sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP')))
if 'forked_from_id' not in columns:
op.add_column('room', sa.Column('forked_from_id', sa.Integer(), nullable=True))
# Create indexes (check if they exist first)
indexes = [idx['name'] for idx in inspector.get_indexes('room')]
if 'ix_room_is_private' not in indexes:
op.create_index(op.f('ix_room_is_private'), 'room', ['is_private'], unique=False)
if 'ix_room_is_archived' not in indexes:
op.create_index(op.f('ix_room_is_archived'), 'room', ['is_archived'], unique=False)
if 'ix_room_owner_id' not in indexes:
op.create_index(op.f('ix_room_owner_id'), 'room', ['owner_id'], unique=False)
def downgrade():
pass

View file

@ -0,0 +1,27 @@
"""room active users
Revision ID: 38a330686a17
Revises: d737de68d6fa
Create Date: 2024-11-23 09:52:50.824162
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import sqlite
# revision identifiers, used by Alembic.
revision = "38a330686a17"
down_revision = "d737de68d6fa"
branch_labels = None
depends_on = None
def upgrade():
with op.batch_alter_table("room", schema=None) as batch_op:
batch_op.add_column(sa.Column("active_users", sa.Text(), nullable=True))
def downgrade():
with op.batch_alter_table("room", schema=None) as batch_op:
batch_op.drop_column("active_users")

View file

@ -0,0 +1,28 @@
"""add_updated_at_to_room
Revision ID: 5d0d533ff7c0
Revises: 2025011100
Create Date: 2025-11-11 21:53:13.141580
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5d0d533ff7c0'
down_revision = '2025011100'
branch_labels = None
depends_on = None
def upgrade():
# Add updated_at column to room table (Unix timestamp as integer)
with op.batch_alter_table('room', schema=None) as batch_op:
batch_op.add_column(sa.Column('updated_at', sa.Integer(), nullable=False, server_default=sa.text('(strftime(\'%s\', \'now\'))')))
def downgrade():
# Remove updated_at column from room table
with op.batch_alter_table('room', schema=None) as batch_op:
batch_op.drop_column('updated_at')

View file

@ -0,0 +1,27 @@
"""room inactive_users column
Revision ID: 5d93cdf18549
Revises: 1ac5a8e0f577
Create Date: 2024-11-24 14:04:30.488155
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import sqlite
# revision identifiers, used by Alembic.
revision = "5d93cdf18549"
down_revision = "1ac5a8e0f577"
branch_labels = None
depends_on = None
def upgrade():
with op.batch_alter_table("room", schema=None) as batch_op:
batch_op.add_column(sa.Column("inactive_users", sa.Text(), nullable=True))
def downgrade():
with op.batch_alter_table("room", schema=None) as batch_op:
batch_op.drop_column("inactive_users")

View file

@ -3,36 +3,36 @@ import sqlalchemy as sa
from sqlalchemy.sql import table, column, select
# revision identifiers, used by Alembic.
revision = 'a9e886c56482'
revision = "a9e886c56482"
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# Create room table
op.create_table('room',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=128), nullable=False),
sa.Column('title', sa.String(length=128), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
op.create_table(
"room",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(length=128), nullable=False),
sa.Column("title", sa.String(length=128), nullable=True),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
)
# Add room_id column to message table
op.add_column('message', sa.Column('room_id', sa.Integer(), nullable=True))
op.add_column("message", sa.Column("room_id", sa.Integer(), nullable=True))
# Temporary table objects
message_table = table('message',
column('id', sa.Integer),
column('username', sa.String),
column('content', sa.String),
column('room', sa.String),
column('room_id', sa.Integer),
)
room_table = table('room',
column('id', sa.Integer),
column('name', sa.String)
message_table = table(
"message",
column("id", sa.Integer),
column("username", sa.String),
column("content", sa.String),
column("room", sa.String),
column("room_id", sa.Integer),
)
room_table = table("room", column("id", sa.Integer), column("name", sa.String))
# Execution context
conn = op.get_bind()
@ -40,74 +40,86 @@ def upgrade():
# Insert distinct rooms into room table and create mapping
distinct_rooms = conn.execute(select(message_table.c.room).distinct())
room_name_to_id = {}
for room_name, in distinct_rooms:
for (room_name,) in distinct_rooms:
conn.execute(room_table.insert().values(name=room_name))
room_id = conn.execute(select(room_table.c.id).where(room_table.c.name == room_name)).scalar()
room_id = conn.execute(
select(room_table.c.id).where(room_table.c.name == room_name)
).scalar()
room_name_to_id[room_name] = room_id
# Update message table with room_id
for room_name, room_id in room_name_to_id.items():
conn.execute(message_table.update().where(message_table.c.room == room_name).values(room_id=room_id))
conn.execute(
message_table.update()
.where(message_table.c.room == room_name)
.values(room_id=room_id)
)
# Create new_message table
new_message_table = op.create_table('new_message',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=128), nullable=False),
sa.Column('content', sa.String(length=1024), nullable=False),
sa.Column('room_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['room_id'], ['room.id']),
sa.PrimaryKeyConstraint('id')
new_message_table = op.create_table(
"new_message",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("username", sa.String(length=128), nullable=False),
sa.Column("content", sa.String(length=1024), nullable=False),
sa.Column("room_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(["room_id"], ["room.id"]),
sa.PrimaryKeyConstraint("id"),
)
# Copy data from old message table to new_message table
old_messages = conn.execute(sa.select(message_table)).fetchall()
for old_message in old_messages:
conn.execute(new_message_table.insert().values(
id=old_message.id,
username=old_message.username,
content=old_message.content,
room_id=old_message.room_id
))
conn.execute(
new_message_table.insert().values(
id=old_message.id,
username=old_message.username,
content=old_message.content,
room_id=old_message.room_id,
)
)
# Drop old message table and rename new_message to message
op.drop_table('message')
op.rename_table('new_message', 'message')
op.drop_table("message")
op.rename_table("new_message", "message")
def downgrade():
# Recreate old_message table with 'room' column
old_message_table = op.create_table('old_message',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=128), nullable=False),
sa.Column('content', sa.String(length=1024), nullable=False),
sa.Column('room', sa.String(length=128), nullable=False),
sa.PrimaryKeyConstraint('id')
old_message_table = op.create_table(
"old_message",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("username", sa.String(length=128), nullable=False),
sa.Column("content", sa.String(length=1024), nullable=False),
sa.Column("room", sa.String(length=128), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
# Copy data back from message to old_message
message_table = table('message',
column('id', sa.Integer),
column('username', sa.String),
column('content', sa.String),
column('room_id', sa.Integer)
)
room_table = table('room',
column('id', sa.Integer),
column('name', sa.String)
message_table = table(
"message",
column("id", sa.Integer),
column("username", sa.String),
column("content", sa.String),
column("room_id", sa.Integer),
)
room_table = table("room", column("id", sa.Integer), column("name", sa.String))
conn = op.get_bind()
messages = conn.execute(select(message_table)).fetchall()
for message in messages:
room_name = conn.execute(select(room_table.c.name).where(room_table.c.id == message.room_id)).scalar()
conn.execute(old_message_table.insert().values(
id=message.id,
username=message.username,
content=message.content,
room=room_name
))
room_name = conn.execute(
select(room_table.c.name).where(room_table.c.id == message.room_id)
).scalar()
conn.execute(
old_message_table.insert().values(
id=message.id,
username=message.username,
content=message.content,
room=room_name,
)
)
# Drop current message table and rename old_message to message
op.drop_table('message')
op.rename_table('old_message', 'message')
op.drop_table('room')
op.drop_table("message")
op.rename_table("old_message", "message")
op.drop_table("room")

View file

@ -0,0 +1,35 @@
"""Add ActivityState table2
Revision ID: d04950c5a624
Revises: d3631b8bb652
Create Date: 2024-07-27 09:36:50.422693
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "d04950c5a624"
down_revision = "d3631b8bb652"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("activity_state", schema=None) as batch_op:
batch_op.add_column(
sa.Column("s3_file_path", sa.String(length=256), nullable=False)
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("activity_state", schema=None) as batch_op:
batch_op.drop_column("s3_file_path")
# ### end Alembic commands ###

View file

@ -0,0 +1,42 @@
"""Add ActivityState table
Revision ID: d3631b8bb652
Revises: 190d5ef26e20
Create Date: 2024-07-27 09:33:52.544550
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "d3631b8bb652"
down_revision = "190d5ef26e20"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"activity_state",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("room_id", sa.Integer(), nullable=False),
sa.Column("section_id", sa.String(length=128), nullable=False),
sa.Column("step_id", sa.String(length=128), nullable=False),
sa.Column("attempts", sa.Integer(), nullable=True),
sa.Column("max_attempts", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["room_id"],
["room.id"],
),
sa.PrimaryKeyConstraint("id"),
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("activity_state")
# ### end Alembic commands ###

View file

@ -0,0 +1,35 @@
"""Add metadata field to ActivityState
Revision ID: d737de68d6fa
Revises: d04950c5a624
Create Date: 2024-07-28 17:02:11.872502
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "d737de68d6fa"
down_revision = "d04950c5a624"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("activity_state", schema=None) as batch_op:
batch_op.add_column(
sa.Column("json_metadata", sa.UnicodeText(), server_default="{}")
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("activity_state", schema=None) as batch_op:
batch_op.drop_column("json_metadata")
# ### end Alembic commands ###

178
models.py Normal file
View file

@ -0,0 +1,178 @@
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
import os
try:
import tiktoken
TIKTOKEN_AVAILABLE = True
except Exception:
TIKTOKEN_AVAILABLE = False
tiktoken = None
import json
db = SQLAlchemy()
class User(db.Model):
"""User model for authentication and ownership"""
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True, nullable=False, index=True)
display_name = db.Column(db.String(50), unique=True, nullable=False, index=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
last_login = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
# Relationships
owned_rooms = db.relationship('Room', backref='owner', lazy='dynamic', foreign_keys='Room.owner_id')
def __repr__(self):
return f'<User {self.display_name} ({self.email})>'
class OTPToken(db.Model):
"""One-Time Password tokens for email authentication"""
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), nullable=False, index=True)
otp_code = db.Column(db.String(6), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
expires_at = db.Column(db.DateTime, nullable=False)
used = db.Column(db.Boolean, default=False, nullable=False)
def __init__(self, email, otp_code, expiration_minutes=10):
self.email = email
self.otp_code = otp_code
self.created_at = datetime.utcnow()
self.expires_at = self.created_at + timedelta(minutes=expiration_minutes)
self.used = False
def is_valid(self):
"""Check if the OTP is still valid (not used and not expired)"""
return not self.used and datetime.utcnow() < self.expires_at
def __repr__(self):
return f'<OTPToken {self.email} expires_at={self.expires_at}>'
class Room(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), nullable=False, unique=True)
title = db.Column(db.String(128), nullable=True)
active_users = db.Column(db.Text, default="") # Store as a comma-separated string
inactive_users = db.Column(db.Text, default="") # Store as a comma-separated string
is_private = db.Column(db.Boolean, default=False, nullable=False, index=True)
is_archived = db.Column(db.Boolean, default=False, nullable=False, index=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True, index=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
updated_at = db.Column(db.Integer, default=lambda: int(datetime.utcnow().timestamp()), nullable=False)
forked_from_id = db.Column(db.Integer, db.ForeignKey('room.id'), nullable=True)
def add_user(self, username):
active_users = set(self.active_users.split(",")) if self.active_users else set()
inactive_users = (
set(self.inactive_users.split(",")) if self.inactive_users else set()
)
# Move from inactive to active if necessary
if username in inactive_users:
inactive_users.discard(username)
active_users.add(username)
self.active_users = ",".join(sorted(active_users))
self.inactive_users = ",".join(sorted(inactive_users))
def remove_user(self, username):
active_users = set(self.active_users.split(",")) if self.active_users else set()
inactive_users = (
set(self.inactive_users.split(",")) if self.inactive_users else set()
)
if username in active_users:
active_users.discard(username)
inactive_users.add(username) # Move to inactive users
self.active_users = ",".join(sorted(active_users))
self.inactive_users = ",".join(sorted(inactive_users))
def get_active_users(self):
return self.active_users.split(",") if self.active_users else []
def get_inactive_users(self):
return self.inactive_users.split(",") if self.inactive_users else []
class UserSession(db.Model):
id = db.Column(db.Integer, primary_key=True)
session_id = db.Column(db.String(128), unique=True, nullable=False)
username = db.Column(db.String(128))
room_name = db.Column(db.String(128))
room_id = db.Column(db.Integer)
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(128), nullable=False)
content = db.Column(db.String(1024), nullable=False)
token_count = db.Column(db.Integer)
room_id = db.Column(db.Integer, db.ForeignKey("room.id"), nullable=False)
def __init__(self, username, content, room_id):
self.username = username
self.content = content
self.room_id = room_id
self.count_tokens()
def count_tokens(self):
if self.token_count is None:
if self.is_base64_image():
self.token_count = 0
elif not TIKTOKEN_AVAILABLE:
# Fallback: estimate ~4 chars per token when tiktoken unavailable
self.token_count = len(self.content) // 4 + 1
else:
try:
encoding = tiktoken.encoding_for_model("gpt-4")
self.token_count = len(encoding.encode(self.content))
except Exception:
# Fallback on any tiktoken error (network, SSL, etc.)
self.token_count = len(self.content) // 4 + 1
return self.token_count
def is_base64_image(self):
"""Check if message contains a base64-encoded image."""
if not self.content:
return False
# Check for any base64 image (jpeg, png, gif, webp, etc.)
return '<img' in self.content and 'data:image/' in self.content and ';base64,' in self.content
class ActivityState(db.Model):
id = db.Column(db.Integer, primary_key=True)
room_id = db.Column(db.Integer, db.ForeignKey("room.id"), nullable=False)
section_id = db.Column(db.String(128), nullable=False)
step_id = db.Column(db.String(128), nullable=False)
attempts = db.Column(db.Integer, default=0)
max_attempts = db.Column(db.Integer, default=3)
s3_file_path = db.Column(db.String(256), nullable=False)
json_metadata = db.Column(db.UnicodeText, default="{}")
@property
def dict_metadata(self):
return json.loads(self.json_metadata) if self.json_metadata else {}
@dict_metadata.setter
def dict_metadata(self, value):
self.json_metadata = json.dumps(value)
def add_metadata(self, key, value):
metadata = self.dict_metadata
metadata[key] = value
self.dict_metadata = metadata
def remove_metadata(self, key):
metadata = self.dict_metadata
if key in metadata:
del metadata[key]
self.dict_metadata = metadata
def clear_metadata(self):
self.dict_metadata = {}

17
pytest.ini Normal file
View file

@ -0,0 +1,17 @@
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--strict-markers
--tb=short
markers =
unit: Unit tests
integration: Integration tests
functional: Functional tests
slow: Slow-running tests
env =
SQLALCHEMY_DATABASE_URI=sqlite:///:memory:
TESTING=1

7
requirements-test.txt Normal file
View file

@ -0,0 +1,7 @@
pytest
pytest-cov
pytest-mock
pytest-flask
pytest-asyncio
black
flake8

View file

@ -1,12 +1,28 @@
flask
flask-socketio
eventlet
mistralai
#eventlet
gevent
gevent-websocket
openai
openai[datalib]
together
tiktoken
#llama-cpp-python[server]
# sqlite
Flask-SQLAlchemy
Flask-Migrate
# used for s3/spaces or aws bedrock (claude)
boto3
pyyaml
# if you want to plot charts.
matplotlib
numpy
sympy

View file

@ -0,0 +1,294 @@
# Educational Activities Implementation - Complete
## Project Summary
**Status**: ✅ COMPLETED
**Total Activities Created**: 8 (activity30 - activity37)
**Total Lines of YAML**: 6,112
**Validation Status**: All activities passing with 0 errors
## Design Criteria (Achieved)
All activities successfully implemented with:
1. ✅ **No embedded Python** - Pure YAML using buckets, transitions, metadata operations, AI feedback
2. ✅ **Educational value** - Teach concepts through interaction and reflection
3. ✅ **Engaging** - Mix of narrative, problem-solving, and critical thinking
4. ✅ **Progressive** - Build knowledge step-by-step
5. ✅ **Use AI effectively** - Separate classifier and feedback models for optimal performance
6. ✅ **Follow schema** - All activities validated successfully
## New Feature: Model Configuration
All activities now support configurable AI models:
```yaml
# Activity-level defaults
classifier_model: "MODEL_1" # Fast classification (Hermes-3-Llama-3.1-8B)
feedback_model: "MODEL_1" # Feedback generation (can override per activity)
# Step-level overrides (optional)
- step_id: "code_review"
classifier_model: "MODEL_1" # Keep Hermes for classification
feedback_model: "MODEL_3" # Use Qwen3-Coder for code feedback
```
### Model Recommendations
- **MODEL_1 (Hermes-3-Llama-3.1-8B)**:
- Default for all activities
- Always available in base install
- Excellent for role-playing scenarios
- Fast and accurate classification
- Great general-purpose feedback
- **MODEL_3 (Qwen3-Coder-30B)**:
- Specialized for programming (activity37)
- Recommended: `hf.co/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M`
- Supports 100+ programming languages
- Expert code generation and debugging
## Completed Activities
### Initial Set (Activities 30-34)
| Activity | Lines | Topic | Status | Special Features |
|----------|-------|-------|--------|-----------------|
| **30** | 530 | Logic Puzzles | ✅ | Contrapositive, syllogisms, knights and knaves |
| **31** | 651 | Scientific Method | ✅ | Historical case studies (Semmelweis, Newton) |
| **32** | 796 | World Geography | ✅ | Choose-your-own-adventure, metadata path tracking |
| **33** | 640 | Environmental Science | ✅ | Role-play as consultant, environmental score tracking |
| **34** | 697 | Media Literacy | ✅ | Source evaluation, bias detection, fact-checking |
### Extended Set (Activities 35-37)
| Activity | Lines | Topic | Status | Special Features |
|----------|-------|-------|--------|-----------------|
| **35** | 981 | American History | ✅ | Advanced for gifted students, primary source analysis |
| **36** | 877 | Biblical History | ✅ | Historical/archaeological approach, ancient Near East |
| **37** | 700 | Programming Languages | ✅ | **Universal language support**, MODEL_3 (Qwen3-Coder) |
### Activity 37: Programming Languages (Flagship)
**Innovation**: First activity to leverage dual-model configuration
```yaml
classifier_model: "MODEL_1" # Hermes for fast bucketing
feedback_model: "MODEL_3" # Qwen3-Coder for code generation
```
**How it works**:
1. Student chooses ANY programming language (Python, Rust, COBOL, etc.)
2. Choice stored in metadata: `programming_language: "user-choice"`
3. AI adapts ALL code examples to chosen language via `tokens_for_ai`
4. Qwen3-Coder generates language-specific syntax and explanations
5. Covers: Hello World, variables, control flow, loops, functions (all using stdout)
## Technical Architecture
### YAML-Only Features Used
- **Buckets**: Response categorization (correct, partial_understanding, off_topic)
- **Transitions**: Navigation between steps based on buckets
- **Metadata Operations**:
- `metadata_add`: Persistent state
- `metadata_tmp_add`: Single-turn state
- `metadata_remove`: State cleanup
- `metadata_clear`: Reset all state
- **AI Feedback**:
- `tokens_for_ai`: Classification instructions
- `feedback_tokens_for_ai`: Feedback generation instructions
- `tokens_for_ai_rubric`: Final evaluation rubric
- **Model Selection**:
- `classifier_model`: Per-activity or per-step classification model
- `feedback_model`: Per-activity or per-step feedback model
### Validation
All activities pass validation:
```bash
python activity_yaml_validator.py research/activity*.yaml
# Result: 8 files, 0 errors, 0 warnings
```
### Testing
CLI simulation tool supports model configuration:
```bash
source vars.sh
python research/guarded_ai.py research/activity37-programming-languages.yaml
# Uses MODEL_1 for classification, MODEL_3 for code feedback
```
## Activity Diversity Achieved
### Subject Areas
- **STEM**: Logic, Scientific Method, Environmental Science, Programming
- **Humanities**: American History, Biblical History
- **Social Studies**: Geography, Media Literacy
### Interaction Types
- Puzzles (Logic, Programming)
- Case Studies (Scientific Method, History)
- Choose-Your-Own-Adventure (Geography)
- Role-Playing (Environmental Science)
- Evaluation (Media Literacy)
### Skills Developed
- Logical reasoning
- Scientific thinking
- Cultural awareness
- Systems thinking
- Critical evaluation
- Programming literacy
### Difficulty Range
- **Beginner**: Geography basics, simple logic
- **Intermediate**: Scientific method, environmental decisions
- **Advanced**: American History critical analysis, programming language concepts
## Model Setup Guide
### Hermes-3-Llama-3.1-8B (MODEL_1)
**Default model - included in base installation**
No setup required. Always available as fallback.
### Qwen3-Coder-30B (MODEL_3)
**Recommended for activity37 - Programming Languages**
#### Option 1: llama.cpp
```bash
# Download model
huggingface-cli download unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF \
Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf
# Run server (GPU acceleration with -ngl 99)
llama-server -m Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf \
--host 0.0.0.0 --port 8080 -ngl 99
# Set environment
export MODEL_ENDPOINT_3=http://localhost:8080/v1
export MODEL_API_KEY_3=dummy
```
#### Option 2: ollama
```bash
ollama run unsloth/qwen3-coder:30b-instruct-q4_K_M
# Set environment
export MODEL_ENDPOINT_3=http://localhost:11434/v1
export MODEL_API_KEY_3=dummy
```
#### Why Qwen3-Coder?
- 30B parameters (much smarter than smaller models)
- Q4_K_M quantization (~20GB RAM)
- Trained on 100+ programming languages
- Unsloth optimized for fast inference
- Works offline
## Files Modified/Created
### New Files (8 activities)
- `research/activity30-logic-puzzles.yaml` (530 lines)
- `research/activity31-scientific-method.yaml` (651 lines)
- `research/activity32-world-geography.yaml` (796 lines)
- `research/activity33-environmental-science.yaml` (640 lines)
- `research/activity34-media-literacy.yaml` (697 lines)
- `research/activity35-american-history.yaml` (981 lines)
- `research/activity36-biblical-history.yaml` (877 lines)
- `research/activity37-programming-languages.yaml` (700 lines)
### Updated Files
- `activity_yaml_validator.py`: Added `classifier_model` and `feedback_model` validation
- `activity.py`: Model parameter support throughout all functions
- `research/guarded_ai.py`: CLI simulator updated for dual-model configuration
- `.gitignore`: Added `venv/`
## Key Implementation Decisions
### Why Separate Classifier and Feedback Models?
1. **Speed**: Classification is fast (Hermes 8B) → instant response bucketing
2. **Quality**: Feedback can use specialized models → better explanations
3. **Cost**: Don't need large model for simple categorization
4. **Flexibility**: Override per-step for specific needs
### Why Hermes as Default?
1. **Availability**: Always included in base install
2. **Speed**: 8B model is very fast
3. **Quality**: Excellent at role-playing and general tasks
4. **Reliability**: Stable fallback for all activities
### Why Qwen3-Coder for Programming?
1. **Specialization**: Trained specifically for code generation
2. **Language Coverage**: Supports 100+ programming languages
3. **Size**: 30B parameters → much smarter than 8B models
4. **Accuracy**: Better at language-specific syntax and idioms
## Usage Examples
### Run an Activity (Web App)
```bash
source vars.sh
python app.py
# Navigate to http://localhost:5000
# Select activity from dropdown
```
### Test an Activity (CLI)
```bash
source vars.sh
python research/guarded_ai.py research/activity37-programming-languages.yaml
# Choose: Rust
# Activity adapts all examples to Rust syntax
```
### Validate All Activities
```bash
python activity_yaml_validator.py research/activity*.yaml
```
## Future Enhancements
### Potential Model Combinations
1. **Fast Classification + Quality Feedback**:
```yaml
classifier_model: "MODEL_1" # Hermes 8B (fast)
feedback_model: "MODEL_2" # Larger model (quality)
```
2. **Domain-Specific Models**:
- Science activities → Science-tuned model
- History activities → Long-context model
- Code activities → Code-specialized model
3. **Step-Level Overrides**:
```yaml
- step_id: "creative_writing"
feedback_model: "MODEL_4" # Creative writing specialist
- step_id: "code_review"
feedback_model: "MODEL_3" # Code specialist
```
## Lessons Learned
1. **Metadata is Powerful**: Can track complex state without Python
2. **AI Adaptation**: `tokens_for_ai` enables universal activities (any language)
3. **Model Separation**: Classification vs feedback needs different models
4. **Hermes Excellence**: Great for role-playing scenarios (consultant, teacher)
5. **Validation Critical**: Schema validation caught all errors early
## Acknowledgments
All activities created without embedded Python, demonstrating the power of:
- YAML-based activity framework
- Metadata-driven state management
- AI-powered personalization
- Dual-model architecture
**Total Development**: 8 educational activities, 6,112 lines of YAML, 0 validation errors

1147
research/SPEC.yaml Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,662 @@
# Global Spiritual Time Machine - Biblical Timeline Edition
# Travel to ANY location in the world during biblical times (~4000 BC - 313 AD)
# Meet spiritual figures across cultures: biblical prophets, Greek philosophers, Buddhist monks, Hindu gurus, and more
# The AI dynamically determines the time period, location, and spiritual context
default_max_attempts_per_step: 5
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
You are an intelligent GLOBAL time machine AI assistant.
Your job is to facilitate open-ended time travel to ANY location on Earth during the biblical timeline (~4000 BC - 313 AD).
KEY BEHAVIORS:
- User can visit ANYWHERE: "30 AD Greece", "1000 BC India", "50 BC Rome", "Moses in Egypt", etc.
- When user names TIME + PLACE, teleport there and explain spiritual context of that location/era
- When user names just PERSON, determine when/where they lived
- When user names just PLACE, ask what time period they want
- Support biblical figures in biblical lands AND non-biblical spiritual figures elsewhere
- Examples: Meet Jesus in Judea, Socrates in Athens, Buddha's followers in India, Zoroastrian priests in Persia
ACCURACY REQUIREMENTS:
- Biblical lands: Maintain biblical accuracy (Temple status, geography, etc.)
- Non-biblical regions: Provide historically accurate spiritual context for that time/place
- Respect all spiritual traditions while facilitating exploration
CRITICAL: Be historically and culturally accurate for ALL regions and time periods.
sections:
# ============================================================================
# INTRODUCTION
# ============================================================================
- section_id: "introduction"
title: "Biblical Time Machine"
steps:
- step_id: "welcome"
title: "Welcome"
content_blocks:
- "# ⏳ Global Spiritual Time Machine ⏳"
- ""
- "You have discovered a time machine that can transport you to **ANY location on Earth** during the biblical timeline (~4000 BC - 313 AD)."
- ""
- "**Travel ANYWHERE:**"
- "- 📍 **Biblical lands**: Meet Moses in Egypt, Jesus in Galilee, Daniel in Babylon"
- "- 🏛️ **Ancient Greece**: Converse with Socrates in Athens, philosophers in Delphi"
- "- 🏺 **Ancient Rome**: Meet Stoic philosophers, Roman priests, early Christians"
- "- 🕉️ **India**: Explore Buddhist monasteries, meet Hindu gurus and yogis"
- "- 🏮 **China**: Visit Confucian scholars, Taoist masters"
- "- 🔥 **Persia**: Meet Zoroastrian priests, magi"
- "- 🌍 **Anywhere else**: Africa, Arabia, Britain - all spiritual traditions welcome"
- ""
- "**Examples:**"
- "- \"Take me to 30 AD Greece\""
- "- \"I want to meet a Buddhist monk in India\""
- "- \"Show me what's happening in Rome during Jesus' time\""
- "- \"Moses\" (I'll figure out when/where!)"
- ""
- "The machine will calculate the time, place, and spiritual context."
- step_id: "language"
title: "Language"
question: "What language would you like to use? (English, Spanish, French, etc.)"
tokens_for_ai: |
User selecting language.
Categorize as 'set' for any language.
Categorize as 'skip' if they want English or to skip.
buckets: [set, skip]
transitions:
set:
metadata_add:
language: "the-users-response"
next_section_and_step: "time_machine:destination_input"
skip:
metadata_add:
language: "English"
next_section_and_step: "time_machine:destination_input"
# ============================================================================
# TIME MACHINE - OPEN-ENDED DESTINATION
# ============================================================================
- section_id: "time_machine"
title: "Time Machine"
steps:
- step_id: "destination_input"
title: "Where/When/Who"
question: "Where and when would you like to go? Or who would you like to meet? (Examples: '30 AD Greece', 'Moses', '500 BC India', 'Socrates', 'END' to finish)"
tokens_for_ai: |
This is COMPLETELY OPEN-ENDED and GEOGRAPHY-AWARE. User can request:
- TIME + PLACE: "30 AD Greece", "1000 BC India", "50 BC Rome"
- PERSON: "Moses", "Jesus", "Socrates", "Buddha", "Confucius"
- BIBLICAL EVENT: "Exodus", "Crucifixion", "Pentecost"
- JUST PLACE: "Greece", "India", "Rome" (you'll need to ask what time period)
Your job: Determine what GEOGRAPHIC REGION they're requesting.
BIBLICAL LANDS (Israel, Judea, Canaan, Egypt in biblical context, Babylon in biblical context):
- Garden of Eden, Adam, Eve, pre-Fall
- Cain, Abel, Noah, Flood, early patriarchs
- Abraham, Isaac, Jacob, Joseph
- Moses, Exodus, Egypt (Hebrew context), Pharaoh, plagues
- Joshua, Judges, Canaan conquest
- Saul, David, Solomon, Jerusalem, kings, prophets
- Babylon/Exile (Jewish exile specifically)
- Jesus, disciples, Galilee, Judea, crucifixion, resurrection
- Pentecost, early church, apostles, persecution IN ISRAEL
- Paul in biblical lands specifically
NON-BIBLICAL WORLD REGIONS:
- Greece: Athens, Sparta, Greek philosophers, mystery religions, Greek culture
- Rome: Roman Empire, senators, philosophers, gladiators, Roman religion
- India: Hinduism, Buddhism, yogis, gurus, monks, meditation
- China: Confucianism, Taoism, Chinese philosophy, dynasties
- Persia: Zoroastrianism, magi, Persian Empire
- Other: Arabia, Africa (non-Egypt), Europe, Britain, any other location
Categorize as:
- 'biblical_lands' for ANY biblical location, person, or event in Israel/Judea/Canaan/biblical Egypt/Babylon
- 'greece' for Greece, Athens, Sparta, Greek philosophers, Greek culture, Greek anything
- 'rome' for Rome, Roman Empire, Italy, Roman culture (unless Paul's biblical journey there)
- 'india' for India, Hinduism, Buddhism, Indian culture, yogis, gurus
- 'china' for China, Confucius, Taoism, Chinese philosophy, dynasties
- 'persia' for Persia, Zoroastrianism, magi, Persian Empire
- 'other_world' for anywhere else: Arabia, Africa, Europe, Britain, etc.
- 'end' if END, finish, done, quit
- 'unclear' if you genuinely can't determine
buckets: [biblical_lands, greece, rome, india, china, persia, other_world, end, unclear]
transitions:
biblical_lands:
ai_feedback:
tokens_for_ai: |
User requested biblical location/person/event: "the-users-response"
YOUR JOB: Dynamically generate a BRIEF departure briefing (3-5 sentences):
1. Determine SPECIFIC time period from their request:
- Garden of Eden: ~4000 BC (pre-Fall)
- Early world: ~4000-2350 BC (Cain, Abel, Noah, Flood)
- Patriarchs: ~2000-1800 BC (Abraham, Isaac, Jacob, Joseph)
- Exodus: ~1446 BC (Moses, Egypt, plagues, Red Sea)
- Judges: ~1400-1050 BC (Joshua, Deborah, Gideon, Samson)
- Kingdom: ~1000-586 BC (Saul, David, Solomon, kings, prophets)
- Exile: ~586-538 BC (Babylon, Daniel, Ezekiel, Jeremiah)
- Jesus: ~27-30 AD (ministry, miracles, teaching)
- Crucifixion: ~30 AD Passover (cross, resurrection)
- Early church: ~33-60 AD (Pentecost, apostles, Acts)
- Paul: ~46-67 AD (missionary journeys, churches)
- Persecution: ~64-313 AD (Rome, martyrs, catacombs)
2. Provide briefing with:
- Destination (specific location)
- Time period (approximate date)
- Context (what's happening, who's there)
- **CRITICAL**: Temple status (NO Temple before Solomon ~970 BC, FIRST Temple 970-586 BC, SECOND Temple 516 BC-70 AD, NO Temple after 70 AD)
3. End with: "⚡ Time travel initiated!"
Use metadata.language for response.
metadata_add:
current_region: "Biblical Lands"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
greece:
ai_feedback:
tokens_for_ai: |
User requested Greece: "the-users-response"
YOUR JOB: Dynamically generate briefing for Greece during requested time:
1. Determine time period from their request (or default to 400 BC if unclear):
- ~800-500 BC: Archaic period, Homer, early city-states
- ~500-323 BC: Classical period, Socrates (~470-399 BC), Plato (~428-348 BC), Aristotle (~384-322 BC)
- ~323-31 BC: Hellenistic period, Alexander's legacy, philosophical schools
- ~31 BC-313 AD: Roman Greece, Stoicism, Epicureanism, mystery religions
2. Provide briefing:
- Destination: Athens, Delphi, Sparta, or relevant city
- Time: Approximate date from their request
- Spiritual context: Philosophers, mystery religions (Eleusinian, Dionysian), Greek gods (Zeus, Athena, Apollo), philosophical schools (Academy, Lyceum, Stoa)
- Who's there: Philosophers, priests, citizens, travelers, mystery cult initiates
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "Greece"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
rome:
ai_feedback:
tokens_for_ai: |
User requested Rome: "the-users-response"
YOUR JOB: Generate briefing for Rome during requested time:
1. Determine time period (or default to 50 BC if unclear):
- ~753-509 BC: Roman Kingdom, founding myths, early religion
- ~509-27 BC: Roman Republic, Cicero, Stoicism arriving
- ~27 BC-313 AD: Roman Empire, emperors, imperial cult, gladiators, Colosseum
- ~64-313 AD: Christian persecution, catacombs, martyrs
2. Provide briefing:
- Destination: Rome (Forum, Colosseum, catacombs, temples)
- Time: Approximate date
- Spiritual context: Roman gods (Jupiter, Mars, Vesta), emperor worship, Stoic philosophy (Seneca, Marcus Aurelius), mystery cults (Mithras, Isis), early Christianity (if post-33 AD)
- Who's there: Senators, philosophers, priests, augurs, vestals, gladiators, Christians (if applicable)
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "Rome"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
india:
ai_feedback:
tokens_for_ai: |
User requested India: "the-users-response"
YOUR JOB: Generate briefing for India during requested time:
1. Determine time period (or default to 500 BC if unclear):
- ~1500-500 BC: Vedic period, early Hinduism, Upanishads, Brahmins
- ~563-483 BC: Buddha's lifetime, Buddhism emerging
- ~500 BC-0: Buddhism spreading, Mauryan Empire, Ashoka promotes Buddhism
- ~0-313 AD: Classical period, Hindu revival, Buddhist universities (Nalanda), Mahayana Buddhism
2. Provide briefing:
- Destination: Varanasi, Bodh Gaya, monasteries, temples, forests
- Time: Approximate date
- Spiritual context: Hinduism (Brahma, Vishnu, Shiva, karma, reincarnation), Buddhism (monks, meditation, sutras), Jainism, yoga, gurus, ascetics
- Who's there: Buddhist monks, Hindu priests, yogis, gurus, pilgrims, seekers
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "India"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
china:
ai_feedback:
tokens_for_ai: |
User requested China: "the-users-response"
YOUR JOB: Generate briefing for China during requested time:
1. Determine time period (or default to 500 BC if unclear):
- ~551-479 BC: Confucius lifetime, ethical philosophy
- ~500-221 BC: Warring States, Laozi, Taoism, Hundred Schools of Thought
- ~221 BC-220 AD: Qin/Han dynasties, Confucianism official, Taoism popular
- ~220-313 AD: Buddhism arriving from India, Three Kingdoms
2. Provide briefing:
- Destination: Courts, temples, mountains (Taoist retreats), cities
- Time: Approximate date
- Spiritual context: Confucianism (virtue, filial piety, social harmony), Taoism (Tao, wu wei, immortality, nature), ancestor worship, divination (I Ching)
- Who's there: Confucian scholars, Taoist hermits, court philosophers, emperors, sages
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "China"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
persia:
ai_feedback:
tokens_for_ai: |
User requested Persia: "the-users-response"
YOUR JOB: Generate briefing for Persia during requested time:
1. Determine time period (or default to 500 BC if unclear):
- ~1500-600 BC: Early Iranian religion, Zoroaster (~628-551 BC)
- ~550-330 BC: Achaemenid Empire, Zoroastrianism official, magi, fire temples
- ~330-224 AD: Parthian period, continued Zoroastrianism, Jewish communities
- ~224-313 AD: Sasanian rise, Zoroastrian revival
2. Provide briefing:
- Destination: Persepolis, fire temples, magi schools
- Time: Approximate date
- Spiritual context: Zoroastrianism (Ahura Mazda vs Angra Mainyu, fire worship, dualism, magi priests), Jewish exile communities (if 586-538 BC)
- Who's there: Magi (Zoroastrian priests), kings, fire keepers, exiled Jews (if applicable)
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "Persia"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
other_world:
ai_feedback:
tokens_for_ai: |
User requested other location: "the-users-response"
YOUR JOB: Generate briefing for their requested location during biblical timeline:
Examples:
- Arabia: Trade routes, early monotheism, tribal religions
- Egypt (non-biblical context): Pharaohs, Egyptian gods (Ra, Osiris, Isis), temples, pyramids
- Ethiopia/Nubia: Ancient kingdoms, Egyptian influence, local religions
- Britain/Gaul: Celtic druids, tribal spirituality
- North Africa: Carthage, Phoenician gods, Punic culture
1. Determine location and time from their request
2. Provide briefing similar to other regions
3. End with: "⚡ Time travel initiated!"
Use metadata.language.
metadata_add:
current_region: "Other World"
current_era: "the-users-response"
epochs_visited: "n+1"
next_section_and_step: "exploration:who_to_meet"
end:
next_section_and_step: "conclusion:reflection"
unclear:
content_blocks:
- "I'm not sure where/when you want to go. Can you be more specific?"
- "Examples: '30 AD Greece', 'Moses', '500 BC India', 'Socrates', 'Jesus', 'Rome during Paul's time'"
counts_as_attempt: false
next_section_and_step: "time_machine:destination_input"
# ============================================================================
# EXPLORATION - OPEN-ENDED NPC INTERACTION
# ============================================================================
- section_id: "exploration"
title: "Exploration"
steps:
- step_id: "who_to_meet"
title: "Who to Meet"
question: "Who would you like to meet here? (Or type 'EXPLORE' to look around, 'LEAVE' to travel elsewhere)"
tokens_for_ai: |
User choosing who to meet in metadata.current_region (metadata.current_era).
This is COMPLETELY OPEN-ENDED and GEOGRAPHY-AWARE. They can request:
BIBLICAL LANDS:
- Biblical figures: Moses, Jesus, David, prophets, apostles, Adam, Eve
- Types: slave, priest, shepherd, fisherman, Pharisee, Roman soldier
GREECE:
- Philosophers: Socrates, Plato, Aristotle, Stoics, Epicureans
- Religious: Mystery cult priest, oracle at Delphi, priestess
- Types: philosopher, citizen, slave, athlete
ROME:
- Philosophers: Seneca, Marcus Aurelius, Cicero
- Religious: Vestal virgin, augur, priest of Jupiter, magi
- Types: senator, gladiator, soldier, merchant, Christian (if applicable)
INDIA:
- Spiritual: Buddhist monk, Hindu guru, yogi, Brahmin priest
- Historical: Ashoka (if ~250 BC), teachers, ascetics
CHINA:
- Philosophers: Confucius, Laozi, Mencius, Zhuangzi
- Spiritual: Taoist hermit, Confucian scholar, court sage
PERSIA:
- Religious: Zoroastrian magi, fire temple priest
- Historical: Kings (Cyrus, Darius, Xerxes), exiled Jews (if applicable)
Categorize as:
- 'meet_someone' if they name specific person or type
- 'explore' if EXPLORE, look around, see the place
- 'leave' if LEAVE, go elsewhere, new place
- 'new_time' if they want different time period
buckets: [meet_someone, explore, leave, new_time]
transitions:
meet_someone:
ai_feedback:
tokens_for_ai: |
User wants to meet: "the-users-response"
Location: metadata.current_region
Era: metadata.current_era
Language: metadata.language
YOUR JOB:
1. Determine if this person/type exists in this region during this time
2. Consider geography: Greek philosophers in Greece, Buddhist monks in India, magi in Persia, biblical figures in biblical lands
3. If person exists: Describe meeting them (2-3 sentences) - appearance, setting, first impression
4. If person doesn't exist yet/there: Politely explain when/where they can be found, offer alternative
5. Be culturally and spiritually respectful of all traditions
ACCURACY REQUIREMENTS:
- Biblical lands: Maintain Temple status accuracy
- Greece: Verify philosopher lifespans (Socrates 470-399 BC, Plato 428-348 BC, etc.)
- India: Don't place Buddha after his death (483 BC), but his followers exist afterward
- China: Confucius 551-479 BC, Laozi ~6th century BC
- Rome: Different figures for Republic vs Empire periods
Use metadata.language for response.
metadata_add:
current_npc: "the-users-response"
people_met: "n+1"
next_section_and_step: "exploration:conversation"
explore:
ai_feedback:
tokens_for_ai: |
User wants to explore/look around.
Location: metadata.current_region
Era: metadata.current_era
Describe what they see (3-5 sentences):
BIBLICAL LANDS:
- Geography (desert, hills, Sea of Galilee, etc.)
- Temple status (CRITICAL: none before Solomon, First Temple 970-586 BC, Second Temple 516 BC-70 AD, none after 70 AD)
- Buildings (tents, stone houses, synagogues, etc.)
- Activity (worship, trading, daily life)
- People present (specific to era)
GREECE:
- Geography (Acropolis, agora, mountains, Mediterranean)
- Buildings (temples to Zeus/Athena/Apollo, Academy, Lyceum, Stoa)
- Activity (philosophy debates, Olympics, mystery rites, theater)
- People (philosophers, citizens, slaves, priestesses)
ROME:
- Geography (Seven Hills, Tiber River, Forum, Colosseum if applicable)
- Buildings (temples, Senate, aqueducts, baths, catacombs if Christian era)
- Activity (gladiator fights, politics, emperor worship, philosophy)
- People (senators, soldiers, philosophers, Christians if applicable)
INDIA:
- Geography (Ganges River, Himalayas, forests, monasteries)
- Buildings (temples, stupas, ashrams, meditation caves)
- Activity (meditation, puja, pilgrimage, teaching)
- People (monks, gurus, pilgrims, yogis)
CHINA:
- Geography (Yellow River, mountains, imperial palace, temples)
- Buildings (Confucian temples, Taoist retreats, palace)
- Activity (rituals, philosophy debates, calligraphy, ancestor worship)
- People (scholars, emperors, hermits, officials)
PERSIA:
- Geography (Persepolis, fire temples, mountains, palaces)
- Buildings (fire temples, royal palaces, magi schools)
- Activity (fire worship, royal courts, Zoroastrian rites)
- People (magi, kings, fire keepers, possibly exiled Jews)
End by asking who they'd like to meet.
Use metadata.language.
counts_as_attempt: false
next_section_and_step: "exploration:who_to_meet"
leave:
next_section_and_step: "time_machine:destination_input"
new_time:
next_section_and_step: "time_machine:destination_input"
- step_id: "conversation"
title: "Conversation"
question: "What would you like to say or ask?"
tokens_for_ai: |
User conversing with metadata.current_npc in metadata.current_region (metadata.current_era).
Categorize as:
- 'spiritual' for questions about faith, God(s), enlightenment, meaning, afterlife, spiritual practices
- 'philosophical' for questions about ethics, wisdom, virtue, the good life, truth, knowledge
- 'historical' for questions about events, politics, wars, daily life, context
- 'personal' for questions about the NPC's life, experiences, journey
- 'continue' for statements, comments, or general conversation
- 'done' if goodbye, done talking, want to leave
- 'someone_else' if they want to meet someone else
- 'new_time' if they want to go to different era
- 'language_change' for language change requests
buckets: [spiritual, philosophical, historical, personal, continue, done, someone_else, new_time, language_change]
transitions:
spiritual:
ai_feedback:
tokens_for_ai: |
Respond IN CHARACTER as metadata.current_npc in metadata.current_region.
Context:
- Region: metadata.current_region
- Era: metadata.current_era
- Language: metadata.language
Answer their spiritual/religious question authentically based on their tradition:
BIBLICAL LANDS:
- Reference YHWH, biblical scripture, prophecy, covenant, Messiah
- Temple status awareness (none/First/Second/destroyed)
- Show Jewish/Christian faith perspective
GREECE:
- Reference Greek gods (Zeus, Athena, Apollo), mystery religions, philosophical theology
- Discuss fate, divine will, oracle prophecies, the Forms (if Platonist)
- Show reverence for gods or rational skepticism (if philosopher)
ROME:
- Reference Roman gods (Jupiter, Mars, Vesta), emperor as divine, Stoic theology
- Discuss virtue, logos, providence, duty to gods and state
- Show civic piety or philosophical spirituality
INDIA:
- Reference Brahma/Vishnu/Shiva (Hindu) or Buddha/dharma (Buddhist)
- Discuss karma, reincarnation, moksha/nirvana, meditation, yoga
- Show devotion or detachment as appropriate
CHINA:
- Reference Tian (Heaven), Tao, ancestors, cosmic harmony
- Discuss virtue (ren), filial piety, wu wei, yin-yang, harmony
- Show Confucian order or Taoist spontaneity
PERSIA:
- Reference Ahura Mazda vs Angra Mainyu (Zoroastrianism)
- Discuss fire worship, dualism, truth vs lies, final judgment
- Show devotion to truth and purity
Keep response conversational (not preachy or essay-length).
Be respectful of all traditions.
next_section_and_step: "exploration:conversation"
philosophical:
ai_feedback:
tokens_for_ai: |
Respond IN CHARACTER as metadata.current_npc.
Answer their philosophical question based on their tradition:
- Greek: Socratic method, Platonic Forms, Aristotelian logic, Stoic virtue, Epicurean pleasure
- Chinese: Confucian virtue, Taoist naturalness, moral cultivation
- Roman: Stoic duty, Ciceronian rhetoric, practical wisdom
- Indian: Dharma, right action, spiritual wisdom
- Biblical: Wisdom literature, moral law, divine will
Keep conversational.
Use metadata.language.
next_section_and_step: "exploration:conversation"
historical:
ai_feedback:
tokens_for_ai: |
Respond IN CHARACTER as metadata.current_npc.
Answer their historical question accurately:
- Events happening in their time
- Political context (empires, rulers, wars)
- Daily life details
- Buildings and geography (Temple status in biblical lands!)
Use metadata.language.
next_section_and_step: "exploration:conversation"
personal:
ai_feedback:
tokens_for_ai: |
Respond IN CHARACTER as metadata.current_npc.
Share personal experience, feelings, life story.
Be authentic to the time period and person's situation.
Show their humanity and spiritual journey.
Use metadata.language.
next_section_and_step: "exploration:conversation"
continue:
ai_feedback:
tokens_for_ai: |
Respond IN CHARACTER as metadata.current_npc.
Respond naturally to their statement.
Continue the conversation.
Show personality and engagement.
Use metadata.language.
next_section_and_step: "exploration:conversation"
done:
ai_feedback:
tokens_for_ai: |
The NPC bids them farewell (brief - 1-2 sentences).
Appropriate to their culture (Greek formality, Chinese respect, biblical blessing, etc.)
Use metadata.language.
next_section_and_step: "exploration:who_to_meet"
someone_else:
content_blocks:
- "Ending current conversation..."
next_section_and_step: "exploration:who_to_meet"
new_time:
content_blocks:
- "Returning to time machine..."
next_section_and_step: "time_machine:destination_input"
language_change:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language updated."
counts_as_attempt: false
next_section_and_step: "exploration:conversation"
# ============================================================================
# CONCLUSION
# ============================================================================
- section_id: "conclusion"
title: "Journey's End"
steps:
- step_id: "reflection"
title: "Reflection"
question: "What was the most meaningful moment from your journey through Biblical history?"
tokens_for_ai: |
User reflecting on their experience.
Categorize as 'reflect' for any response.
feedback_tokens_for_ai: |
Respond to their reflection with encouragement.
- Acknowledge what they found meaningful
- Connect to biblical themes
- Encourage further Bible study
- Thank them for the journey
Use metadata.language.
End with blessing and invitation to return.
buckets: [reflect]
transitions:
reflect:
ai_feedback:
tokens_for_ai: "Provide warm, encouraging response about their spiritual journey."
metadata_add:
activity_completed: "true"
next_section_and_step: "conclusion:goodbye"
- step_id: "goodbye"
title: "Farewell"
content_blocks:
- "# Thank You for Traveling Through Biblical History"
- ""
- "From Eden to persecution, from Paradise to martyrdom—"
- "you've witnessed God's redemptive story unfold."
- ""
- "The time machine is always here when you want to return. ⏳"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,203 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_0"
feedback_model: "MODEL_0"
tokens_for_ai_rubric: |
Test activity for v2.0 features.
Evaluate responses generously - this is just a demo!
sections:
- section_id: intro
title: V2.0 Features Demo
steps:
# Test: Template variables in content blocks
- step_id: welcome
title: Welcome with Templates
content_blocks:
- "# Welcome to OpenCompletion V2.0! 🎉"
- ""
- "This activity demonstrates all new v2.0 features."
- "Current section: {{current_section}}"
- "Current step: {{current_step}}"
question: "What's your name?"
tokens_for_ai: |
Categorize as 'name_provided' if they give a name.
Otherwise 'off_topic'.
buckets: [name_provided, off_topic]
transitions:
name_provided:
content_blocks:
- "Great to meet you!"
metadata_add:
player_name: "the-users-response"
score: "n+1"
next_section_and_step: "templates:test_templates"
off_topic:
content_blocks:
- "Please tell me your name."
next_section_and_step: "intro:welcome"
# Section: Template Variables
- section_id: templates
title: Template Variables Test
steps:
- step_id: test_templates
title: Testing Templates
content_blocks:
- "# Template Variables Test"
- ""
- "Welcome back, {{metadata.player_name}}!"
- "Your score: {{metadata.score}}"
- "Attempt {{current_attempt}} of {{max_attempts}}"
- "Attempts remaining: {{attempts_remaining}}"
question: "Ready to test conditional content? (yes/no)"
tokens_for_ai: "Categorize as 'yes' or 'no' based on their response."
buckets: [yes, no]
transitions:
yes:
content_blocks:
- "Excellent!"
next_section_and_step: "conditionals:test_conditional_blocks"
no:
content_blocks:
- "Take your time!"
next_section_and_step: "templates:test_templates"
# Section: Conditional Content Blocks
- section_id: conditionals
title: Conditional Content Test
steps:
- step_id: test_conditional_blocks
title: Conditional Content Blocks
content_blocks:
# Always shown
- "# Conditional Content Test"
- ""
# Conditional - only if score >= 1
- text: "🌟 You have points! Great job!"
show_if:
score_gte: 1
# Conditional - only if score < 1
- text: "Start earning points!"
show_if:
score_lt: 1
# Conditional - personalized
- text: "Hello {{metadata.player_name}}, let's continue!"
show_if:
player_name_exists: true
question: "What's 5 + 3?"
tokens_for_ai: "Categorize as 'correct' if 8 or eight, otherwise 'incorrect'."
buckets: [correct, incorrect]
# Progressive hints test
hints:
- attempt: 1
text: "💡 Hint: It's less than 10"
counts_as_attempt: false
- attempt: 2
text: "💡 Strong Hint: 5 + 3 = ?"
counts_as_attempt: false
transitions:
correct:
content_blocks:
- "Perfect! ✅"
metadata_add:
score: "n+5"
next_section_and_step: "weighted_random:test_weighted"
incorrect:
content_blocks:
- "Try again!"
next_section_and_step: "conditionals:test_conditional_blocks"
# Section: Weighted Random
- section_id: weighted_random
title: Weighted Random Test
steps:
- step_id: test_weighted
title: Weighted Random Selection
content_blocks:
- "# Weighted Random Test"
- ""
- "Let's test weighted random selection!"
question: "Roll the dice! (type 'roll')"
tokens_for_ai: "Categorize as 'roll'."
buckets: [roll]
transitions:
roll:
metadata_weighted_random:
loot:
- value: "common_item"
weight: 70
- value: "rare_item"
weight: 25
- value: "legendary_item"
weight: 5
ai_feedback:
tokens_for_ai: |
The user found: {{metadata.loot}}
If common_item: "You found a Common Item"
If rare_item: "You found a Rare Item! 🌟"
If legendary_item: "LEGENDARY ITEM FOUND! 🏆"
metadata_add:
score: "n+1"
next_section_and_step: "conditional_nav:test_nav"
# Section: Conditional Navigation
- section_id: conditional_nav
title: Conditional Navigation Test
steps:
- step_id: test_nav
title: Conditional Navigation
content_blocks:
- "# Conditional Navigation Test"
- ""
- "Your current score: {{metadata.score}}"
- ""
- "Based on your score, you'll be routed to different paths!"
question: "Continue? (yes)"
tokens_for_ai: "Categorize as 'continue'."
buckets: [continue]
transitions:
continue:
# Conditional navigation based on score
next_section_and_step:
- if:
score_gte: 10
goto: "endings:high_score"
- elif:
score_gte: 5
goto: "endings:medium_score"
- else:
goto: "endings:low_score"
# Section: Different Endings
- section_id: endings
title: Endings
steps:
- step_id: high_score
title: High Score Ending
content_blocks:
- "# 🏆 AMAZING! High Score!"
- ""
- "{{metadata.player_name}}, you scored {{metadata.score}} points!"
- ""
- "You're a V2.0 features master!"
- step_id: medium_score
title: Medium Score Ending
content_blocks:
- "# 🌟 GOOD JOB! Medium Score!"
- ""
- "{{metadata.player_name}}, you scored {{metadata.score}} points!"
- ""
- "Great understanding of V2.0 features!"
- step_id: low_score
title: Low Score Ending
content_blocks:
- "# ✨ Good Start!"
- ""
- "{{metadata.player_name}}, you scored {{metadata.score}} points!"
- ""
- "You've learned the basics of V2.0 features!"

File diff suppressed because it is too large Load diff

77
research/activity.yaml Normal file
View file

@ -0,0 +1,77 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to AI"
steps:
- step_id: "step_1"
title: "Understanding AI"
content_blocks:
- "Welcome to the introduction to AI."
- "In this section, we will cover the basics of AI."
tokens_for_ai: "Explain the basics of AI to the user in a friendly and engaging manner."
question: "What do you understand by Artificial Intelligence?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of AI."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of AI. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on AI."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of AI in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Applications of AI"
content_blocks:
- "Now that you understand the basics of AI, let's explore its applications."
- "AI is used in various fields such as healthcare, finance, and transportation."
tokens_for_ai: "Explain the applications of AI in different fields in a friendly and engaging manner."
question: "Can you name a few applications of AI?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You have identified some key applications of AI."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of AI applications. Let's explore more."
ai_feedback:
tokens_for_ai: "Provide additional examples to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on AI applications."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of AI applications in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_3"
title: "The end of AI"
content_blocks:
- "The end of AI."

438
research/activity0.yaml Normal file
View file

@ -0,0 +1,438 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_0"
title: "Introduction"
steps:
- step_id: "step_1"
title: "Welcome"
content_blocks:
- "Welcome to the GNU Manifesto course! 👋"
- "You will learn about the GNU Manifesto and its significance."
- section_id: "section_1"
title: "Introduction to The GNU Manifesto"
steps:
- step_id: "step_1"
title: "What is The GNU Manifesto?"
content_blocks:
- "<img src='https://www.gnu.org/graphics/heckert_gnu.transp.small.png'>"
- "Welcome to the GNU Manifesto course! 👋"
- "The GNU Manifesto was written by Richard Stallman in 1985 to ask for support in developing the GNU operating system."
- "Think about why someone might want to create a free operating system. Consider issues like software freedom, collaboration, and accessibility."
tokens_for_ai: "Guide the student to think about the reasons for creating a free operating system. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think Richard Stallman wanted to create a free operating system? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of why Richard Stallman wanted to create a free operating system. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. What do you think are some reasons someone might want a free operating system? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the reasons for creating a free operating system. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the reasons for creating a free operating system in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Importance of The GNU Manifesto"
content_blocks:
- "The GNU Manifesto is important because it laid the foundation for the Free Software Movement."
- "It emphasizes the importance of software freedom, collaboration, and user rights."
- "Think about how having free software might benefit users and developers. Consider aspects like cost, accessibility, and innovation."
tokens_for_ai: "Guide the student to think about the benefits of free software. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think free software benefits users and developers? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You understand the benefits of free software. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think free software might help users and developers? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the benefits of free software. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the benefits of free software in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_2"
title: "Key Concepts of The GNU Manifesto"
steps:
- step_id: "step_1"
title: "What is GNU?"
content_blocks:
- "GNU stands for 'Gnu's Not Unix' and is a free Unix-compatible software system."
- "Richard Stallman and other volunteers are developing GNU to provide a free alternative to proprietary Unix systems."
- "Think about why it might be important for GNU to be compatible with Unix. Consider aspects like user familiarity, software compatibility, and ease of adoption."
tokens_for_ai: "Guide the student to think about the importance of GNU being compatible with Unix. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think it is important for GNU to be compatible with Unix? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand the importance of GNU being compatible with Unix. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. Why do you think compatibility with Unix is important for GNU? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of GNU being compatible with Unix. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the importance of GNU being compatible with Unix in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Why GNU Will Be Free"
content_blocks:
- "GNU is not in the public domain, but it will be free for everyone to use, modify, and redistribute."
- "No distributor will be allowed to restrict its further redistribution, ensuring that all versions of GNU remain free."
- "Think about why it might be important for GNU to remain free. Consider aspects like user rights, collaboration, and innovation."
tokens_for_ai: "Guide the student to think about the importance of GNU remaining free. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think it is important for GNU to remain free? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of GNU remaining free. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. Why do you think it's important for GNU to remain free? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of GNU remaining free. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the importance of GNU remaining free in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_3"
title: "Contributing to GNU"
steps:
- step_id: "step_1"
title: "How to Contribute"
content_blocks:
- "There are many ways to contribute to the GNU Project, including donating money, programs, and work."
- "Think about why it might be important for people to contribute to the GNU Project. Consider aspects like community, collaboration, and shared goals."
tokens_for_ai: "Guide the student to think about the importance of contributing to the GNU Project. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think it is important for people to contribute to the GNU Project? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand the importance of contributing to the GNU Project. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. Why do you think contributing to the GNU Project is important? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of contributing to the GNU Project. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the importance of contributing to the GNU Project in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Ways to Contribute"
content_blocks:
- "You can contribute to the GNU Project by writing code, fixing bugs, improving documentation, and more."
- "Think about how your skills and interests might align with the needs of the GNU Project. How can you make a meaningful contribution?"
tokens_for_ai: "Guide the student to think about how they can contribute to the GNU Project based on their skills and interests. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think you can contribute to the GNU Project based on your skills and interests? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You have a good idea of how you can contribute to the GNU Project. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think you can contribute to the GNU Project with your skills? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on how you can contribute to the GNU Project. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of how they can contribute to the GNU Project in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_4"
title: "Legacy of The GNU Manifesto"
steps:
- step_id: "step_1"
title: "Impact on Software Development"
content_blocks:
- "The GNU Manifesto has had a profound impact on software development, promoting the principles of free software and user rights."
- "Think about how the principles of the GNU Manifesto might have influenced modern software development practices. Consider aspects like open source, collaboration, and innovation."
tokens_for_ai: "Guide the student to think about the impact of the GNU Manifesto on modern software development. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the principles of the GNU Manifesto have influenced modern software development practices? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand the impact of the GNU Manifesto on modern software development. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think the GNU Manifesto has influenced software development? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the impact of the GNU Manifesto. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the impact of the GNU Manifesto in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Future of Free Software"
content_blocks:
- "The principles of the GNU Manifesto continue to inspire the Free Software Movement and the development of free software."
- "Think about how the principles of free software might shape the future of technology. Consider aspects like user rights, innovation, and collaboration."
tokens_for_ai: "Guide the student to think about the future of free software and its impact on technology. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the principles of free software will shape the future of technology? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You understand how the principles of free software might shape the future of technology. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think free software will shape technology's future? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the future of free software. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the future of free software in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_5"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the GNU Manifesto course! 🎉"
- "You have learned about the key concepts, principles, and impact of the GNU Manifesto."
- "This knowledge will help you understand the importance of software freedom and the Free Software Movement."
- "We are proud of your dedication and hard work. Well done! 🌟"

368
research/activity10.yaml Normal file
View file

@ -0,0 +1,368 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to the Miracles of Jesus"
steps:
- step_id: "step_1"
title: "Who is Jesus?"
content_blocks:
- "Welcome to the **Miracles of Jesus** course!"
- "Jesus is a central figure in Christianity, known for his teachings, compassion, and miraculous acts."
tokens_for_ai: "Explain who Jesus is in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "**What do you know about Jesus?**"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of who Jesus is."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of who Jesus is. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on who Jesus is."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of who Jesus is in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of Miracles"
content_blocks:
- "Miracles are extraordinary events that demonstrate divine intervention in the world."
- "The miracles performed by Jesus are significant because they reveal his divine nature and compassion for humanity."
tokens_for_ai: "Explain the importance of miracles in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "**Why are the miracles of Jesus important?**"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of the miracles of Jesus."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of the miracles of Jesus."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of the miracles of Jesus in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Miracles of Healing"
steps:
- step_id: "step_1"
title: "Healing the Blind Man"
content_blocks:
- "One of Jesus' miracles was healing a man who was born blind."
- "Jesus made mud with his saliva, put it on the man's eyes, and told him to wash in the Pool of Siloam. The man washed and was able to see."
tokens_for_ai: "Explain the miracle of healing the blind man in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of healing the blind man?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about the miracle of healing the blind man."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of healing the blind man."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of healing the blind man in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Healing the Leper"
content_blocks:
- "Another miracle of Jesus was healing a man with leprosy."
- "Jesus touched the man and said, 'Be clean!' Immediately, the leprosy left him, and he was healed."
tokens_for_ai: "Explain the miracle of healing the leper in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of healing the leper?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about the miracle of healing the leper."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of healing the leper."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of healing the leper in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Miracles of Provision"
steps:
- step_id: "step_1"
title: "Feeding the 5,000"
content_blocks:
- "One of Jesus' most famous miracles is feeding 5,000 people with just five loaves of bread and two fish."
- "Jesus blessed the food, broke it, and distributed it to the crowd. Everyone ate and was satisfied, and there were twelve baskets of leftovers."
tokens_for_ai: "Explain the miracle of feeding the 5,000 in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of feeding the 5,000?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about the miracle of feeding the 5,000."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of feeding the 5,000."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of feeding the 5,000 in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Turning Water into Wine"
content_blocks:
- "Jesus' first recorded miracle was turning water into wine at a wedding in Cana."
- "When the wine ran out, Jesus instructed the servants to fill six stone jars with water. He then turned the water into wine, which was of the highest quality."
tokens_for_ai: "Explain the miracle of turning water into wine in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of turning water into wine?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about the miracle of turning water into wine."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of turning water into wine."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of turning water into wine in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Miracles of Nature"
steps:
- step_id: "step_1"
title: "Calming the Storm"
content_blocks:
- "One of Jesus' miracles involved calming a storm while he and his disciples were on a boat."
- "Jesus rebuked the wind and said to the waves, 'Quiet! Be still!' The wind died down, and it was completely calm."
tokens_for_ai: "Explain the miracle of calming the storm in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of calming the storm?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about the miracle of calming the storm."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of calming the storm."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of calming the storm in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Walking on Water"
content_blocks:
- "Another miracle of Jesus was walking on water."
- "Jesus walked on the Sea of Galilee to reach his disciples who were in a boat. When they saw him, they were terrified, but Jesus said, 'Take courage! It is I. Don't be afraid.'"
tokens_for_ai: "Explain the miracle of walking on water in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of walking on water?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about the miracle of walking on water."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of walking on water."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of walking on water in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Miracles of Resurrection"
steps:
- step_id: "step_1"
title: "Raising Lazarus"
content_blocks:
- "One of Jesus' most powerful miracles was raising Lazarus from the dead."
- "Lazarus had been dead for four days when Jesus arrived. Jesus called out, 'Lazarus, come out!' and Lazarus came out of the tomb, alive."
tokens_for_ai: "Explain the miracle of raising Lazarus in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of raising Lazarus?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about the miracle of raising Lazarus."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of raising Lazarus."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of raising Lazarus in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Resurrection of Jesus"
content_blocks:
- "The most significant miracle in Christianity is the resurrection of Jesus."
- "After being crucified and buried, Jesus rose from the dead on the third day. His resurrection is celebrated as Easter and is the foundation of Christian faith."
tokens_for_ai: "Explain the miracle of the resurrection of Jesus in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the miracle of the resurrection of Jesus?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about the miracle of the resurrection of Jesus."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the miracle. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the miracle of the resurrection of Jesus."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the resurrection of Jesus in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Miracles of Jesus course!"
- "You have learned about the various miracles performed by Jesus, including healing, provision, nature, and resurrection."
- "These miracles demonstrate Jesus' divine power and compassion for humanity."
- "We are proud of your dedication and hard work. Well done!"

580
research/activity11.yaml Normal file
View file

@ -0,0 +1,580 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to the Revolutionary War"
steps:
- step_id: "step_1"
title: "What is the Revolutionary War?"
content_blocks:
- "Welcome to the American Revolutionary War course!"
- "The American Revolutionary War, also known as the American War of Independence, was a conflict between Great Britain and its thirteen colonies in North America."
tokens_for_ai: "Explain what the American Revolutionary War is in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you know about the American Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of the American Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Revolutionary War. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Revolutionary War."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Revolutionary War in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of the Revolutionary War"
content_blocks:
- "The Revolutionary War was important because it led to the independence of the United States from British rule."
- "It also established the principles of liberty, democracy, and self-governance."
tokens_for_ai: "Explain the importance of the American Revolutionary War in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is the American Revolutionary War important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of the American Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of the Revolutionary War."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of the Revolutionary War in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Causes of the Revolutionary War"
steps:
- step_id: "step_1"
title: "Taxation Without Representation"
content_blocks:
- "One of the main causes of the Revolutionary War was the issue of 'taxation without representation.'"
- "The British government imposed taxes on the American colonies without giving them representation in Parliament."
tokens_for_ai: "Explain the concept of 'taxation without representation' and its role in causing the Revolutionary War in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is 'taxation without representation' and how did it contribute to the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the concept of 'taxation without representation' and its role in the Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of 'taxation without representation.' Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on 'taxation without representation.'"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of 'taxation without representation' in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Intolerable Acts"
content_blocks:
- "The Intolerable Acts were a series of punitive laws passed by the British Parliament in response to the Boston Tea Party."
- "These acts further angered the American colonists and contributed to the outbreak of the Revolutionary War."
tokens_for_ai: "Explain what the Intolerable Acts were and their role in causing the Revolutionary War in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What were the Intolerable Acts and how did they contribute to the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what the Intolerable Acts were and their role in the Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Intolerable Acts. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Intolerable Acts."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Intolerable Acts in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Key Events of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Boston Tea Party"
content_blocks:
- "The Boston Tea Party was a political protest by the Sons of Liberty in Boston, Massachusetts, on December 16, 1773."
- "American colonists, frustrated with British taxation, dumped 342 chests of British tea into the harbor."
tokens_for_ai: "Explain the Boston Tea Party and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Boston Tea Party and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what the Boston Tea Party was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Boston Tea Party. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Boston Tea Party."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Boston Tea Party in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Battles of Lexington and Concord"
content_blocks:
- "The Battles of Lexington and Concord were the first military engagements of the American Revolutionary War."
- "They were fought on April 19, 1775, in Middlesex County, Province of Massachusetts Bay."
tokens_for_ai: "Explain the Battles of Lexington and Concord and their significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What were the Battles of Lexington and Concord and why were they significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what the Battles of Lexington and Concord were and their significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Battles of Lexington and Concord. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battles of Lexington and Concord."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Battles of Lexington and Concord in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Key Figures of the Revolutionary War"
steps:
- step_id: "step_1"
title: "George Washington"
content_blocks:
- "George Washington was the commander-in-chief of the Continental Army during the American Revolutionary War."
- "He later became the first President of the United States."
tokens_for_ai: "Explain who George Washington was and his role in the Revolutionary War in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Who was George Washington and what was his role in the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand who George Washington was and his role in the Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of George Washington. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on George Washington."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of George Washington in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Thomas Jefferson"
content_blocks:
- "Thomas Jefferson was the principal author of the Declaration of Independence."
- "He later became the third President of the United States."
tokens_for_ai: "Explain who Thomas Jefferson was and his role in the Revolutionary War in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Who was Thomas Jefferson and what was his role in the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand who Thomas Jefferson was and his role in the Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of Thomas Jefferson. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Thomas Jefferson."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Thomas Jefferson in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Major Battles of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Battle of Bunker Hill"
content_blocks:
- "The Battle of Bunker Hill was fought on June 17, 1775, during the early stages of the American Revolutionary War."
- "Despite being a British victory, the battle demonstrated that the American forces could stand up to the British army."
tokens_for_ai: "Explain the Battle of Bunker Hill and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Battle of Bunker Hill and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what the Battle of Bunker Hill was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Battle of Bunker Hill. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battle of Bunker Hill."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Battle of Bunker Hill in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Battle of Saratoga"
content_blocks:
- "The Battle of Saratoga was a turning point in the American Revolutionary War."
- "Fought in 1777, it resulted in a decisive victory for the American forces and convinced France to join the war on the side of the Americans."
tokens_for_ai: "Explain the Battle of Saratoga and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Battle of Saratoga and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what the Battle of Saratoga was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Battle of Saratoga. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battle of Saratoga."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Battle of Saratoga in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "The Declaration of Independence"
steps:
- step_id: "step_1"
title: "Drafting the Declaration"
content_blocks:
- "The Declaration of Independence was drafted by Thomas Jefferson and adopted by the Continental Congress on July 4, 1776."
- "It declared the thirteen American colonies as independent states, free from British rule."
tokens_for_ai: "Explain the drafting of the Declaration of Independence and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Declaration of Independence and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what the Declaration of Independence was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Declaration of Independence. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Declaration of Independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Key Principles of the Declaration"
content_blocks:
- "The Declaration of Independence outlined key principles such as equality, unalienable rights, and the right to alter or abolish government."
- "It emphasized that all men are created equal and have the right to life, liberty, and the pursuit of happiness."
tokens_for_ai: "Explain the key principles of the Declaration of Independence in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What are the key principles of the Declaration of Independence?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the key principles of the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the key principles. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the key principles of the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the key principles of the Declaration of Independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_7"
title: "The End of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Siege of Yorktown"
content_blocks:
- "The Siege of Yorktown was the last major battle of the American Revolutionary War."
- "Fought in 1781, it resulted in the surrender of British General Cornwallis and effectively ended the war."
tokens_for_ai: "Explain the Siege of Yorktown and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Siege of Yorktown and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what the Siege of Yorktown was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Siege of Yorktown. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Siege of Yorktown."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Siege of Yorktown in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Treaty of Paris"
content_blocks:
- "The Treaty of Paris was signed on September 3, 1783, and officially ended the American Revolutionary War."
- "The treaty recognized the independence of the United States and established its borders."
tokens_for_ai: "Explain the Treaty of Paris and its significance in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the Treaty of Paris and why was it significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what the Treaty of Paris was and its significance."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the Treaty of Paris. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Treaty of Paris."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Treaty of Paris in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_8"
title: "Legacy of the Revolutionary War"
steps:
- step_id: "step_1"
title: "Impact on the United States"
content_blocks:
- "The American Revolutionary War had a profound impact on the United States."
- "It led to the establishment of a new nation based on principles of liberty, democracy, and self-governance."
tokens_for_ai: "Explain the impact of the Revolutionary War on the United States in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the impact of the Revolutionary War on the United States?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the impact of the Revolutionary War on the United States."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the impact. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the impact of the Revolutionary War."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the impact of the Revolutionary War in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Influence on Other Nations"
content_blocks:
- "The American Revolutionary War inspired other nations to fight for their independence and adopt democratic principles."
- "It had a significant influence on the French Revolution and other independence movements around the world."
tokens_for_ai: "Explain the influence of the Revolutionary War on other nations in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How did the Revolutionary War influence other nations?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the influence of the Revolutionary War on other nations."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the influence. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the influence of the Revolutionary War."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the influence of the Revolutionary War in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_9"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the American Revolutionary War course!"
- "You have learned about the causes, key events, major battles, important figures, and the legacy of the Revolutionary War."
- "This knowledge will help you understand the foundations of the United States and the principles of liberty and democracy."
- "We are proud of your dedication and hard work. Well done!"

596
research/activity12.yaml Normal file
View file

@ -0,0 +1,596 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to the Revolutionary War"
steps:
- step_id: "step_1"
title: "What is the Revolutionary War?"
content_blocks:
- "Welcome to the American Revolutionary War course!"
- "The American Revolutionary War, also known as the American War of Independence, was a conflict between Great Britain and its thirteen colonies in North America."
- "Think about why the colonies might have wanted to break away from British rule. Consider issues like governance, taxes, and representation."
tokens_for_ai: "Guide the student to think about the reasons for the colonies wanting independence. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the American colonies wanted to break away from British rule?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of why the colonies wanted independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the reasons for independence."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the reasons for independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of the Revolutionary War"
content_blocks:
- "The Revolutionary War was important because it led to the independence of the United States from British rule."
- "It also established the principles of liberty, democracy, and self-governance."
- "Think about how gaining independence might have changed the lives of the colonists. Consider aspects like freedom, governance, and rights."
tokens_for_ai: "Guide the student to think about the impact of independence on the colonists' lives. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think gaining independence changed the lives of the colonists?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the impact of gaining independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the impact of independence."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the impact of independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Causes of the Revolutionary War"
steps:
- step_id: "step_1"
title: "Taxation Without Representation"
content_blocks:
- "One of the main causes of the Revolutionary War was the issue of 'taxation without representation.'"
- "The British government imposed taxes on the American colonies without giving them representation in Parliament."
- "Think about how you would feel if you had to pay taxes but had no say in how the money was spent. How might this lead to frustration and anger?"
tokens_for_ai: "Guide the student to think about the feelings of the colonists regarding taxation without representation. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the colonists felt about 'taxation without representation' and why?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the colonists' feelings about 'taxation without representation.'"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on 'taxation without representation.'"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of 'taxation without representation' in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Intolerable Acts"
content_blocks:
- "The Intolerable Acts were a series of punitive laws passed by the British Parliament in response to the Boston Tea Party."
- "These acts further angered the American colonists and contributed to the outbreak of the Revolutionary War."
- "Think about how you would feel if you were punished for protesting against something you believed was unfair. How might this lead to a desire for change?"
tokens_for_ai: "Guide the student to think about the feelings of the colonists regarding the Intolerable Acts. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the colonists felt about the Intolerable Acts and why?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the colonists' feelings about the Intolerable Acts."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Intolerable Acts."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Intolerable Acts in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Key Events of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Boston Tea Party"
content_blocks:
- "The Boston Tea Party was a political protest by the Sons of Liberty in Boston, Massachusetts, on December 16, 1773."
- "American colonists, frustrated with British taxation, dumped 342 chests of British tea into the harbor."
- "Think about why the colonists chose to protest in this way. What message were they trying to send to the British government?"
tokens_for_ai: "Guide the student to think about the reasons behind the Boston Tea Party. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the colonists chose to protest by dumping tea into the harbor?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the reasons behind the Boston Tea Party."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Boston Tea Party."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Boston Tea Party in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Battles of Lexington and Concord"
content_blocks:
- "The Battles of Lexington and Concord were the first military engagements of the American Revolutionary War."
- "They were fought on April 19, 1775, in Middlesex County, Province of Massachusetts Bay."
- "Think about why these battles were significant. How did they change the relationship between the colonies and Great Britain?"
tokens_for_ai: "Guide the student to think about the significance of the Battles of Lexington and Concord. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Battles of Lexington and Concord were significant?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the significance of the Battles of Lexington and Concord."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battles of Lexington and Concord."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Battles of Lexington and Concord in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Key Figures of the Revolutionary War"
steps:
- step_id: "step_1"
title: "George Washington"
content_blocks:
- "George Washington was the commander-in-chief of the Continental Army during the American Revolutionary War."
- "He later became the first President of the United States."
- "Think about the qualities that made George Washington a good leader. How did his leadership contribute to the success of the American forces?"
tokens_for_ai: "Guide the student to think about the qualities of George Washington's leadership. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What qualities do you think made George Washington a good leader and how did his leadership contribute to the success of the American forces?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the qualities that made George Washington a good leader."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on George Washington's leadership qualities."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of George Washington's leadership qualities in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Thomas Jefferson"
content_blocks:
- "Thomas Jefferson was the principal author of the Declaration of Independence."
- "He later became the third President of the United States."
- "Think about the impact of the Declaration of Independence. How did Thomas Jefferson's words inspire the colonists and shape the new nation?"
tokens_for_ai: "Guide the student to think about the impact of the Declaration of Independence and Thomas Jefferson's role. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think Thomas Jefferson's words in the Declaration of Independence inspired the colonists and shaped the new nation?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the impact of Thomas Jefferson's words in the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Thomas Jefferson's role."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of Thomas Jefferson's role in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Major Battles of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Battle of Bunker Hill"
content_blocks:
- "The Battle of Bunker Hill was fought on June 17, 1775, during the early stages of the American Revolutionary War."
- "Despite being a British victory, the battle demonstrated that the American forces could stand up to the British army."
- "Think about the significance of this battle. How might it have affected the morale and determination of the American forces?"
tokens_for_ai: "Guide the student to think about the significance of the Battle of Bunker Hill. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Battle of Bunker Hill was significant for the American forces?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the significance of the Battle of Bunker Hill for the American forces."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battle of Bunker Hill."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Battle of Bunker Hill in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Battle of Saratoga"
content_blocks:
- "The Battle of Saratoga was a turning point in the American Revolutionary War."
- "Fought in 1777, it resulted in a decisive victory for the American forces and convinced France to join the war on the side of the Americans."
- "Think about why this battle was a turning point. How did the involvement of France change the course of the war?"
tokens_for_ai: "Guide the student to think about the significance of the Battle of Saratoga. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Battle of Saratoga was a turning point in the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the significance of the Battle of Saratoga."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Battle of Saratoga."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Battle of Saratoga in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "The Declaration of Independence"
steps:
- step_id: "step_1"
title: "Drafting the Declaration"
content_blocks:
- "The Declaration of Independence was drafted by Thomas Jefferson and adopted by the Continental Congress on July 4, 1776."
- "It declared the thirteen American colonies as independent states, free from British rule."
- "Think about the significance of declaring independence. How might this document have inspired the colonists and affected their resolve to fight for freedom?"
tokens_for_ai: "Guide the student to think about the significance of the Declaration of Independence. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Declaration of Independence was significant for the colonists?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the significance of the Declaration of Independence for the colonists."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Declaration of Independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Key Principles of the Declaration"
content_blocks:
- "The Declaration of Independence outlined key principles such as equality, unalienable rights, and the right to alter or abolish government."
- "It emphasized that all men are created equal and have the right to life, liberty, and the pursuit of happiness."
- "Think about how these principles might have influenced the new nation. How do you think they shaped the values and government of the United States?"
tokens_for_ai: "Guide the student to think about the key principles of the Declaration of Independence and their influence. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the key principles of the Declaration of Independence influenced the new nation?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the influence of the key principles of the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the key principles of the Declaration of Independence."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the key principles of the Declaration of Independence in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_7"
title: "The End of the Revolutionary War"
steps:
- step_id: "step_1"
title: "The Siege of Yorktown"
content_blocks:
- "The Siege of Yorktown was the last major battle of the American Revolutionary War."
- "Fought in 1781, it resulted in the surrender of British General Cornwallis and effectively ended the war."
- "Think about why this battle was significant. How did the surrender of Cornwallis impact the outcome of the war?"
tokens_for_ai: "Guide the student to think about the significance of the Siege of Yorktown. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Siege of Yorktown was significant in ending the Revolutionary War?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the significance of the Siege of Yorktown in ending the Revolutionary War."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Siege of Yorktown."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Siege of Yorktown in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "The Treaty of Paris"
content_blocks:
- "The Treaty of Paris was signed on September 3, 1783, and officially ended the American Revolutionary War."
- "The treaty recognized the independence of the United States and established its borders."
- "Think about the significance of this treaty. How did it solidify the United States' status as an independent nation?"
tokens_for_ai: "Guide the student to think about the significance of the Treaty of Paris. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do you think the Treaty of Paris was significant in solidifying the United States' independence?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the significance of the Treaty of Paris in solidifying the United States' independence."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Treaty of Paris."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the Treaty of Paris in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_8"
title: "Legacy of the Revolutionary War"
steps:
- step_id: "step_1"
title: "Impact on the United States"
content_blocks:
- "The American Revolutionary War had a profound impact on the United States."
- "It led to the establishment of a new nation based on principles of liberty, democracy, and self-governance."
- "Think about how these principles have shaped the United States. How do you see the influence of the Revolutionary War in the country's values and government today?"
tokens_for_ai: "Guide the student to think about the impact of the Revolutionary War on the United States. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the principles established during the Revolutionary War have shaped the United States today?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the impact of the Revolutionary War on the United States today."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the impact of the Revolutionary War."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the impact of the Revolutionary War in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Influence on Other Nations"
content_blocks:
- "The American Revolutionary War inspired other nations to fight for their independence and adopt democratic principles."
- "It had a significant influence on the French Revolution and other independence movements around the world."
- "Think about how the success of the American Revolution might have inspired other countries. How do you think it influenced global movements for independence and democracy?"
tokens_for_ai: "Guide the student to think about the influence of the American Revolutionary War on other nations. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you think the success of the American Revolution influenced other countries' movements for independence and democracy?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the influence of the American Revolution on other countries."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the influence of the American Revolution."
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of the influence of the American Revolution in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_9"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the American Revolutionary War course!"
- "You have learned about the causes, key events, major battles, important figures, and the legacy of the Revolutionary War."
- "This knowledge will help you understand the foundations of the United States and the principles of liberty and democracy."
- "We are proud of your dedication and hard work. Well done!"

View file

@ -0,0 +1,425 @@
default_max_attempts_per_step: 30
tokens_for_ai_rubric: |
You are a master storyteller. Your task is to create a coherent and engaging story based on the following chat history. The story should seamlessly integrate the user's responses and the AI's feedback, ensuring that the narrative flows naturally. Pay special attention to the user's choices and how they shape the story. Use descriptive language to bring the scenes to life and make the story immersive. The story should have a clear beginning, middle, and end, reflecting the user's journey and the outcomes of their decisions. Here is the chat history.
sections:
- section_id: "section_1"
title: "The Adventure Begins"
steps:
- step_id: "step_1"
title: "Setting the Scene"
content_blocks:
- "Welcome to the Story Builder game! 🌟"
- "You are about to embark on an exciting adventure. Your choices will shape the story."
- "Let's begin by setting the scene. Imagine you are in a dense forest, and you come across a fork in the path."
- "To the left, the path leads deeper into the forest, where you hear the sound of a flowing river. To the right, the path leads to a clearing with a mysterious glowing light."
tokens_for_ai: "Guide the user to make a choice between the two paths. Provide feedback based on their choice."
question: "Which path do you choose? Left (forest) or Right (clearing)? 🤔"
buckets:
- left_forest
- right_clearing
- off_topic
- asking_clarifying_questions
transitions:
left_forest:
content_blocks:
- "You chose to go left, deeper into the forest. 🌲"
- "As you walk, the sound of the river grows louder. You soon find yourself at the edge of a beautiful, sparkling river."
- "You notice a small boat tied to a tree. Do you take the boat and explore the river, or do you follow the riverbank on foot?"
next_section_and_step: "section_2:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
right_clearing:
content_blocks:
- "You chose to go right, towards the clearing. 🌟"
- "As you approach the clearing, the glowing light becomes brighter. You find a magical portal shimmering in the air."
- "Do you step through the portal to see where it leads, or do you stay and explore the clearing?"
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_2"
title: "The Forest Path"
steps:
- step_id: "step_1"
title: "Encounter at the River"
content_blocks:
- "You chose to go left, deeper into the forest. 🌲"
- "As you walk, the sound of the river grows louder. You soon find yourself at the edge of a beautiful, sparkling river."
- "You notice a small boat tied to a tree. Do you take the boat and explore the river, or do you follow the riverbank on foot?"
tokens_for_ai: "Guide the user to make a choice between taking the boat or following the riverbank. Provide feedback based on their choice."
question: "What do you choose? Take the boat or Follow the riverbank? 🤔"
buckets:
- take_boat
- follow_riverbank
- go_back
- off_topic
- asking_clarifying_questions
transitions:
take_boat:
content_blocks:
- "You chose to take the boat and explore the river. 🚣"
- "As you paddle down the river, you encounter a group of friendly forest creatures who offer to guide you to a hidden treasure."
- "Congratulations! You have discovered a hidden treasure with the help of your new friends. 🎉"
next_section_and_step: "section_4:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
follow_riverbank:
content_blocks:
- "You chose to follow the riverbank on foot. 🌲"
- "As you walk along the river, you find a hidden cave entrance. Inside, you discover ancient artifacts and a map to a secret location."
- "Congratulations! You have discovered ancient artifacts and a secret map. 🎉"
next_section_and_step: "section_5:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the fork in the path. 🔄"
- "You are now back at the fork. To the left, the path leads deeper into the forest, where you hear the sound of a flowing river. To the right, the path leads to a clearing with a mysterious glowing light."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_3"
title: "The Clearing Path"
steps:
- step_id: "step_1"
title: "The Magical Portal"
content_blocks:
- "You chose to go right, towards the clearing. 🌟"
- "As you approach the clearing, the glowing light becomes brighter. You find a magical portal shimmering in the air."
- "Do you step through the portal to see where it leads, or do you stay and explore the clearing?"
tokens_for_ai: "Guide the user to make a choice between stepping through the portal or exploring the clearing. Provide feedback based on their choice."
question: "What do you choose? Step through the portal or Explore the clearing? 🤔"
buckets:
- step_through_portal
- explore_clearing
- go_back
- off_topic
- asking_clarifying_questions
transitions:
step_through_portal:
content_blocks:
- "You chose to step through the portal. 🌟"
- "You find yourself in a magical realm filled with wonders and mysteries. A wise old wizard offers to teach you powerful spells."
- "Congratulations! You have entered a magical realm and begun your training as a wizard. 🎉"
next_section_and_step: "section_6:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
explore_clearing:
content_blocks:
- "You chose to explore the clearing. 🌲"
- "You find a hidden garden filled with rare and beautiful plants. A friendly gardener offers to share their knowledge with you."
- "Congratulations! You have discovered a hidden garden and gained valuable knowledge. 🎉"
next_section_and_step: "section_7:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the fork in the path. 🔄"
- "You are now back at the fork. To the left, the path leads deeper into the forest, where you hear the sound of a flowing river. To the right, the path leads to a clearing with a mysterious glowing light."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_4"
title: "The Boat Adventure"
steps:
- step_id: "step_1"
title: "The Hidden Treasure"
content_blocks:
- "You chose to take the boat and explore the river. 🚣"
- "As you paddle down the river, you encounter a group of friendly forest creatures who offer to guide you to a hidden treasure."
- "You find the hidden treasure chest. Do you open the treasure or leave it?"
tokens_for_ai: "Guide the user to make a choice between opening the treasure or leaving it. Provide feedback based on their choice."
question: "What do you choose? Open the treasure or Leave it? 🤔"
buckets:
- open_treasure
- leave_treasure
- go_back
- off_topic
- asking_clarifying_questions
transitions:
open_treasure:
content_blocks:
- "You chose to open the treasure. 🎉"
- "Inside, you find gold coins, precious gems, and a magical artifact that grants you a special power."
- "Congratulations! You have discovered a hidden treasure and gained a special power. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
leave_treasure:
content_blocks:
- "You chose to leave the treasure. 🌲"
- "You decide that the adventure itself is the real treasure and continue your journey with a sense of fulfillment."
- "Congratulations! You have completed the adventure with a sense of fulfillment. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the river. 🔄"
- "You are now back at the river. Do you take the boat and explore the river, or do you follow the riverbank on foot?"
next_section_and_step: "section_2:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_5"
title: "The Riverbank Adventure"
steps:
- step_id: "step_1"
title: "The Hidden Cave"
content_blocks:
- "You chose to follow the riverbank on foot. 🌲"
- "As you walk along the river, you find a hidden cave entrance. Inside, you discover ancient artifacts and a map to a secret location."
- "Do you enter the cave or continue walking along the riverbank?"
tokens_for_ai: "Guide the user to make a choice between entering the cave or continuing to walk. Provide feedback based on their choice."
question: "What do you choose? Enter the cave or Continue walking? 🤔"
buckets:
- enter_cave
- continue_walking
- go_back
- off_topic
- asking_clarifying_questions
transitions:
enter_cave:
content_blocks:
- "You chose to enter the cave. 🌲"
- "Inside, you find ancient artifacts and a map to a secret location. You feel a sense of discovery and excitement."
- "Congratulations! You have discovered ancient artifacts and a secret map. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
continue_walking:
content_blocks:
- "You chose to continue walking along the riverbank. 🌲"
- "As you walk, you find a beautiful waterfall and a hidden path leading to a secret garden."
- "Congratulations! You have discovered a hidden garden and gained valuable knowledge. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the river. 🔄"
- "You are now back at the river. Do you take the boat and explore the river, or do you follow the riverbank on foot?"
next_section_and_step: "section_2:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_6"
title: "The Portal Adventure"
steps:
- step_id: "step_1"
title: "The Magical Realm"
content_blocks:
- "You chose to step through the portal. 🌟"
- "You find yourself in a magical realm filled with wonders and mysteries. A wise old wizard offers to teach you powerful spells."
- "Do you learn spells from the wizard or explore the magical realm on your own?"
tokens_for_ai: "Guide the user to make a choice between learning spells or exploring the realm. Provide feedback based on their choice."
question: "What do you choose? Learn spells or Explore the realm? 🤔"
buckets:
- learn_spells
- explore_realm
- go_back
- off_topic
- asking_clarifying_questions
transitions:
learn_spells:
content_blocks:
- "You chose to learn spells from the wizard. 🌟"
- "The wizard teaches you powerful spells that grant you special abilities. You feel a sense of empowerment and wonder."
- "Congratulations! You have learned powerful spells and gained special abilities. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
explore_realm:
content_blocks:
- "You chose to explore the magical realm on your own. 🌟"
- "As you explore, you discover hidden treasures and magical creatures. You feel a sense of adventure and excitement."
- "Congratulations! You have discovered hidden treasures and magical creatures. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the clearing. 🔄"
- "You are now back at the clearing. Do you step through the portal to see where it leads, or do you stay and explore the clearing?"
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_7"
title: "The Clearing Adventure"
steps:
- step_id: "step_1"
title: "The Hidden Garden"
content_blocks:
- "You chose to explore the clearing. 🌲"
- "You find a hidden garden filled with rare and beautiful plants. A friendly gardener offers to share their knowledge with you."
- "Do you talk to the gardener or explore the garden on your own?"
tokens_for_ai: "Guide the user to make a choice between talking to the gardener or exploring the garden. Provide feedback based on their choice."
question: "What do you choose? Talk to the gardener or Explore the garden? 🤔"
buckets:
- talk_gardener
- explore_garden
- go_back
- off_topic
- asking_clarifying_questions
transitions:
talk_gardener:
content_blocks:
- "You chose to talk to the gardener. 🌲"
- "The gardener shares their knowledge of rare plants and their magical properties. You feel a sense of wonder and curiosity."
- "Congratulations! You have gained valuable knowledge about rare plants and their magical properties. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
explore_garden:
content_blocks:
- "You chose to explore the garden on your own. 🌲"
- "As you explore, you discover hidden paths and secret areas filled with rare plants and magical creatures. You feel a sense of adventure and excitement."
- "Congratulations! You have discovered hidden paths and secret areas in the garden. 🎉"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the clearing. 🔄"
- "You are now back at the clearing. Do you step through the portal to see where it leads, or do you stay and explore the clearing?"
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_8"
title: "The Final Choices"
steps:
- step_id: "step_1"
title: "The Final Encounter"
content_blocks:
- "You have reached the final part of your adventure. Your choices have led you to this moment."
- "You are presented with a final choice: accept a reward for your journey or decline it and continue your adventure."
- "Think about what you have learned and experienced. What will you choose?"
tokens_for_ai: "Guide the user to make a final choice between accepting the reward or declining it. Provide feedback based on their choice."
question: "What do you choose? Accept the reward or Decline the reward? 🤔"
buckets:
- accept_reward
- decline_reward
- go_back
- off_topic
- asking_clarifying_questions
transitions:
accept_reward:
content_blocks:
- "You chose to accept the reward. 🎉"
- "You are given a magical artifact that grants you special powers and a sense of accomplishment."
- "Congratulations! You have completed your adventure and received a magical reward. 🎉"
next_section_and_step: "section_9:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and conclude the story. Use emojis like 👍 and 🌟."
decline_reward:
content_blocks:
- "You chose to decline the reward. 🌲"
- "You decide that the journey itself was the true reward and continue your adventure with a sense of fulfillment."
- "Congratulations! You have completed your adventure with a sense of fulfillment. 🎉"
next_section_and_step: "section_9:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and conclude the story. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the previous step. 🔄"
- "You are now back at the previous step. Think about what you have learned and experienced. What will you choose?"
next_section_and_step: "section_8:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_9"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Story Builder game! 🎉"
- "You have made choices that shaped an exciting adventure."
- "We hope you enjoyed the journey and the story you helped create."
- "We are proud of your creativity and imagination. Well done! 🌟"

View file

@ -0,0 +1,218 @@
default_max_attempts_per_step: 30
tokens_for_ai_rubric: |
You are a master storyteller. Your task is to create a coherent and engaging story based on the following chat history. The story should seamlessly integrate the user's responses and the AI's feedback, ensuring that the narrative flows naturally. Pay special attention to the user's choices and how they shape the story. Use descriptive language to bring the scenes to life and make the story immersive. The story should have a clear beginning, middle, and end, reflecting the user's journey and the outcomes of their decisions. Here is the chat history.
sections:
- section_id: "section_1"
title: "The Escape Room Begins"
steps:
- step_id: "step_1"
title: "Waking Up"
content_blocks:
- "You wake up in a dimly lit room with no memory of how you got there. The room is small and has a single door that is locked."
- "You see a rug on the floor, a bookshelf with a book, and a safe on the wall."
tokens_for_ai: "Guide the user to make a choice between looking under the rug, examining the book, or trying to open the safe. Provide feedback based on their choice."
question: "What do you choose? Look under the rug, Examine the book, or Try to open the safe? 🤔"
buckets:
- look_under_rug
- examine_book
- try_open_safe
- off_topic
- asking_clarifying_questions
transitions:
look_under_rug:
content_blocks:
- "You chose to look under the rug. 🧺"
next_section_and_step: "section_2:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
metadata_add:
key: true
examine_book:
content_blocks:
- "You chose to examine the book. 📖"
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
metadata_add:
password: true
try_open_safe:
content_blocks:
- "You chose to try to open the safe. 🔒"
next_section_and_step: "section_4:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_2"
title: "The Key"
steps:
- step_id: "step_1"
title: "Found the Key"
content_blocks:
- "You have found a key hidden under the rug. 🔑"
tokens_for_ai: "Guide the user to make a choice between taking the key or continuing to explore the room. Provide feedback based on their choice."
question: "What do you choose? Take the key or Continue exploring? 🤔"
buckets:
- take_key
- continue_exploring
- go_back
- off_topic
- asking_clarifying_questions
transitions:
take_key:
content_blocks:
- "You chose to take the key. 🔑"
- "You now have the key."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
metadata_add:
key: true
continue_exploring:
content_blocks:
- "You chose to continue exploring the room. 🕵️"
- "You see a rug on the floor, a bookshelf with a book, and a safe on the wall."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the previous step. 🔄"
- "You are now back at the previous step."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_3"
title: "The Book"
steps:
- step_id: "step_1"
title: "Found the Password"
content_blocks:
- "The book contains a note with a password: 'ESCAPE123'. 🔐"
tokens_for_ai: "Guide the user to make a choice between taking note of the password or continuing to explore the room. Provide feedback based on their choice."
question: "What do you choose? Take note of the password or Continue exploring? 🤔"
buckets:
- take_password
- continue_exploring
- go_back
- off_topic
- asking_clarifying_questions
transitions:
take_password:
content_blocks:
- "You chose to take note of the password. 🔑"
- "You now have the password."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
metadata_add:
password: true
continue_exploring:
content_blocks:
- "You chose to continue exploring the room. 🕵️"
- "You see a rug on the floor, a bookshelf with a book, and a safe on the wall."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the previous step. 🔄"
- "You are now back at the previous step."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_4"
title: "The Safe"
steps:
- step_id: "step_1"
title: "Opening the Safe"
content_blocks:
- "The safe is locked and requires both a key and a password to open. 🔒"
tokens_for_ai: "Guide the user to make a choice between using the key and entering the password to open the safe or continuing to explore the room. Provide feedback based on their choice."
question: "What do you choose? Use the key and enter the password or Continue exploring? 🤔"
buckets:
- use_key_and_password
- continue_exploring
- go_back
- off_topic
- asking_clarifying_questions
transitions:
use_key_and_password:
metadata_conditions:
key: true
password: true
content_blocks:
- "You chose to use the key and enter the password to open the safe. 🔑"
- "The safe opens, revealing a hidden treasure."
- "Congratulations! You have found the hidden treasure. 🎉"
next_section_and_step: "section_5:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Use emojis like 👍 and 🌟."
continue_exploring:
content_blocks:
- "You chose to continue exploring the room. 🕵️"
- "You see a rug on the floor, a bookshelf with a book, and a safe on the wall."
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
go_back:
content_blocks:
- "You chose to go back to the previous step. 🔄"
- "You are now back at the previous step."
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_5"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on finding the hidden treasure! 🎉"
- "You have successfully completed the escape room."
- "We hope you enjoyed the adventure. 🌟"

View file

@ -0,0 +1,361 @@
default_max_attempts_per_step: 30
tokens_for_ai_rubric: |
You are a master storyteller. Your task is to create a coherent and engaging story based on the following chat history. The story should seamlessly integrate the user's responses and the AI's feedback, ensuring that the narrative flows naturally. Pay special attention to the user's choices and how they shape the story. Use descriptive language to bring the scenes to life and make the story immersive. The story should have a clear beginning, middle, and end, reflecting the user's journey and the outcomes of their decisions. Here is the chat history.
sections:
- section_id: "section_1"
title: "The Escape Room Begins"
steps:
- step_id: "step_0"
title: "Waking Up"
content_blocks:
- "You wake up in a dimly lit room with no memory of how you got there. The room is small and has a single door that is locked."
- step_id: "step_1"
title: "Explore"
content_blocks:
- "You see a rug on the floor, a bookshelf with a book, and a safe on the wall."
- "There is also an exit door, but it seems to be locked."
tokens_for_ai: "Guide the user to make a choice between looking under the rug, examining the book, trying to open the safe, or trying to leave the room. Use off_topic sparingly if the response choice doesn't fit any other topic."
question: "What do you do? Look under the rug, Examine the book, Try to open the safe, or Try to leave the room? 🤔"
buckets:
- look_under_rug
- examine_book
- try_open_safe
- try_leave_room
- asking_clarifying_questions
- off_topic
transitions:
look_under_rug:
next_section_and_step: "section_2:step_1"
examine_book:
next_section_and_step: "section_3:step_1"
try_open_safe:
next_section_and_step: "section_4:step_1"
try_leave_room:
metadata_conditions:
exit_key: true
content_blocks:
- "You chose to try to leave the room. 🚪"
- "The exit door opens, revealing a way out."
- "Congratulations! You have found the way out and successfully completed the escape room. 🎉"
next_section_and_step: "section_6:step_1"
ai_feedback:
tokens_for_ai: "The user has exited with the exit_key! The game is over, Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_2"
title: "The Key"
steps:
- step_id: "step_1"
title: "Found the Key"
content_blocks:
- "You find a key hidden under the rug. 🔑"
tokens_for_ai: "Guide the user to make a choice between taking the key or continuing to explore the room. Be flexible to classify actions that lead to finding hidden items. Use off_topic sparingly if the response choice doesn't fit any other topic. Provide feedback based on their choice."
question: "What do you choose? Take the key or Continue exploring? 🤔"
buckets:
- take_key
- continue_exploring
- find_coin
- go_back
- asking_clarifying_questions
- off_topic
transitions:
take_key:
content_blocks:
- "You chose to take the key. 🔑"
next_section_and_step: "section_1:step_1"
metadata_add:
key: true
continue_exploring:
next_section_and_step: "section_1:step_1"
find_coin:
content_blocks:
- "You chose to take a closer look under the rug. 🧺"
- "You find a small, mysterious coin with strange engravings."
- "You now have the coin!"
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "The player found a hidden coin. Congratulate them by name with your feedback. Use emojis like 👍 and 🌟."
metadata_add:
coin: true
go_back:
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the story. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_3"
title: "The Book"
steps:
- step_id: "step_1"
title: "Found the Password"
content_blocks:
- "The book contains a note with a password: 'ESCAPE123'. 🔐"
tokens_for_ai: "Guide the user to make a choice between taking note of the password or continuing to explore the room. Be flexible to classify actions that lead to finding hidden items. Use off_topic sparingly if the response choice doesn't fit any other topic. Provide feedback based on their choice."
question: "What do you choose? Take note of the password or Continue exploring? 🤔"
buckets:
- take_password
- continue_exploring
- find_paper
- go_back
- asking_clarifying_questions
- off_topic
transitions:
take_password:
content_blocks:
- "You chose to take note of the password. 🔑"
next_section_and_step: "section_1:step_1"
metadata_add:
password: true
continue_exploring:
next_section_and_step: "section_1:step_1"
find_paper:
content_blocks:
- "You chose to take a closer look at the book. 📖"
- "You find a small, folded piece of paper with a cryptic message."
- "You take the paper!"
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "The player found a hidden paper with a cryptic message. Congratulate them by name with your feedback. Use emojis like 👍 and 🌟."
metadata_add:
paper: true
go_back:
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_4"
title: "The Safe"
steps:
- step_id: "step_1"
title: "Opening the Safe"
content_blocks:
- "The safe is locked and requires both a key and a password to open. 🔒"
tokens_for_ai: "Guide the user to make a choice between using the key and entering the password to open the safe or continuing to explore the room. Be flexible to classify actions that lead to finding hidden items. Use off_topic sparingly if the response choice doesn't fit any other topic. Provide feedback based on their choice."
question: "What do you do? Use the key and enter the password or Continue exploring? 🤔"
buckets:
- use_key_and_password
- continue_exploring
- go_back
- asking_clarifying_questions
- off_topic
transitions:
use_key_and_password:
metadata_conditions:
key: true
password: true
content_blocks:
- "You chose to use the key and enter the password to open the safe. 🔑"
- "The safe opens, revealing a hidden treasure and the exit key. 🎉"
- "There is also a slot for a coin, but that is likely not important..."
next_section_and_step: "section_4:step_2"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
metadata_add:
second_safe: true
exit_key: true
continue_exploring:
next_section_and_step: "section_1:step_1"
go_back:
next_section_and_step: "section_3:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- step_id: "step_2"
title: "Safe is Open"
content_blocks:
- "The safe is now open, revealing treasure and an exit key. 🎉"
- "There is a coin slot in the safe that looks intriguing. 🪙"
tokens_for_ai: "Guide the user to make a choice: If they mention 'use coin', 'coin slot', or 'insert coin' categorize as 'use_coin'. If they want to continue exploring or leave, categorize accordingly."
question: "What do you do? Use the coin in the slot, Try to leave the room, or Continue exploring? 🤔"
buckets:
- use_coin
- try_leave_room
- continue_exploring
- go_back
- asking_clarifying_questions
- off_topic
transitions:
use_coin:
metadata_conditions:
coin: true
second_safe: true
metadata_remove:
- coin
next_section_and_step: "section_5:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
try_leave_room:
metadata_conditions:
exit_key: true
content_blocks:
- "You chose to try to leave the room. 🚪"
- "The exit door opens, revealing a way out."
- "Congratulations! You have found the way out and successfully completed the escape room. 🎉"
next_section_and_step: "section_6:step_1"
ai_feedback:
tokens_for_ai: "The user has exited with the exit_key! The game is over, Use emojis like 👍 and 🌟."
continue_exploring:
next_section_and_step: "section_1:step_1"
go_back:
next_section_and_step: "section_4:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_5"
title: "The Secret Compartment"
steps:
- step_id: "step_1"
title: "The Hidden Compartment"
content_blocks:
- "The compartment opens, revealing a second, smaller safe. 🪙"
- "This safe requires a combination to open."
tokens_for_ai: "Guide the user to make a choice between solving the combination to open the second safe or leaving it alone. Be flexible to classify actions that lead to finding hidden items. Use off_topic sparingly if the response choice doesn't fit any other topic. Provide feedback based on their choice."
question: "Do you try to solve the combination or leave it alone? 🤔"
buckets:
- solve_combination
- leave_it_alone
- go_back
- asking_clarifying_questions
- off_topic
transitions:
solve_combination:
metadata_conditions:
paper: true
content_blocks:
- "You chose to solve the combination. 🧩"
- "After some thought, you decipher the cryptic message and enter the combination."
- "The second safe opens, revealing a map to a hidden location outside the room."
- "Congratulations! You have found the ultimate secret and a new adventure awaits. 🎉"
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Congratulate the player by name for finding ultimate secret. Use emojis like 👍 and 🌟."
leave_it_alone:
next_section_and_step: "section_1:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the final encounter. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
go_back:
next_section_and_step: "section_4:step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to make the next choice. Be flexible to classify actions that lead to finding hidden items. Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
- section_id: "section_6"
title: "Prize Room"
steps:
- step_id: "step_1"
title: "Choose Your Prize"
content_blocks:
- "You have reached the prize room! 🎁"
- "There are 10 different items in the room. One is your prize."
tokens_for_ai: "Randomly select one of the following prize_ items as the user's prize."
question: "Guess your prize? 🤔"
buckets:
- prize_1
- prize_2
- prize_3
- prize_4
- prize_5
- prize_6
- prize_7
- prize_8
- prize_9
- prize_10
transitions:
prize_1:
content_blocks:
- "You won Prize 1: A golden keychain. 🗝️"
metadata_add:
prize: golden_keychain
prize_2:
content_blocks:
- "You won Prize 2: A mysterious amulet. 🧿"
metadata_add:
prize: mysterious_amulet
prize_3:
content_blocks:
- "You won Prize 3: A rare gemstone. 💎"
metadata_add:
prize: rare_gemstone
prize_4:
content_blocks:
- "You won Prize 4: An ancient scroll. 📜"
metadata_add:
prize: ancient_scroll
prize_5:
content_blocks:
- "You won Prize 5: A magical wand. 🪄"
metadata_add:
prize: magical_wand
prize_6:
content_blocks:
- "You won Prize 6: A treasure map. 🗺️"
metadata_add:
prize: treasure_map
prize_7:
content_blocks:
- "You won Prize 7: A silver coin. 🪙"
metadata_add:
prize: silver_coin
prize_8:
content_blocks:
- "You won Prize 8: A mystical ring. 💍"
metadata_add:
prize: mystical_ring
prize_9:
content_blocks:
- "You won Prize 9: A rare book. 📚"
metadata_add:
prize: rare_book
prize_10:
content_blocks:
- "You won Prize 10: A magical potion. 🧪"
metadata_add:
prize: magical_potion
- section_id: "section_7"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on finding the hidden treasure! 🎉"
- "You have successfully completed the escape room."
- "We hope you enjoyed the adventure. 🌟"

286
research/activity16.yaml Normal file
View file

@ -0,0 +1,286 @@
default_max_attempts_per_step: 8
tokens_for_ai_rubric: |
Review the conversation and highlight the statements or questions that the user asked and anything they learned. A summary.
sections:
- section_id: "introduction"
title: "Introduction"
steps:
- step_id: "intro_step_1"
title: "Welcome"
content_blocks:
- "Welcome to the Learning Activity! 📚"
- "In this activity, you will go through three lessons."
- "After completing all lessons, you will be able to exit."
- step_id: "intro_step_2"
title: "Choose a Lesson"
content_blocks:
- "You can choose to review any of the lessons or exit if you have completed all lessons."
- "Lesson 1: Topic 1 - Introduction to fundamental principles."
- "Lesson 2: Topic 2 - Understanding data structures."
- "Lesson 3: Topic 3 - Learning about algorithms."
question: "Which lesson would you like to review or would you like to exit? 🤔"
tokens_for_ai: "Guide the user to choose a lesson or exit. Provide positive reinforcement. Use emojis like 👍 and 🌟."
buckets:
- lesson_1
- lesson_2
- lesson_3
- exit
- off_topic
- asking_clarifying_questions
transitions:
lesson_1:
next_section_and_step: "lesson_1:lesson1_step_1"
ai_feedback:
tokens_for_ai: "Guide the user to Lesson 1 about fundamental principles. Use emojis like 🔄 and 🌟."
lesson_2:
next_section_and_step: "lesson_2:lesson2_step_1"
ai_feedback:
tokens_for_ai: "Guide the user to Lesson 2 about data structures. Use emojis like 🔄 and 🌟."
lesson_3:
next_section_and_step: "lesson_3:lesson3_step_1"
ai_feedback:
tokens_for_ai: "Guide the user to Lesson 3 about algorithms. Use emojis like 🔄 and 🌟."
exit:
metadata_conditions:
lesson_1_completed: true
lesson_2_completed: true
lesson_3_completed: true
next_section_and_step: "exit:exit_step_1"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the exit. Use emojis like 👍 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the activity in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- section_id: "lesson_1"
title: "Lesson 1: Topic 1"
steps:
- step_id: "lesson1_step_1"
title: "Introduction to Topic 1"
content_blocks:
- "Welcome to Lesson 1! 📝"
- "In this lesson, you will learn about Topic 1."
- "Topic 1 is important because it lays the foundation for understanding more complex concepts."
- step_id: "lesson1_step_2"
title: "Basics of Topic 1"
content_blocks:
- "Let's start with the basics of Topic 1. 📝"
- "Topic 1 involves understanding the fundamental principles that will be built upon in later lessons."
- "For example, if Topic 1 is about programming, you might learn about variables, data types, and control structures."
question: "Do you understand the basics of Topic 1? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the basics of Topic 1, which includes variables, data types, and control structures. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "lesson_1:lesson1_step_3"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the next step. Use emojis like 👍 and 🌟."
not_understand:
content_blocks:
- "Let's review the basics of Topic 1 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the basics of Topic 1. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- step_id: "lesson1_step_3"
title: "Advanced Concepts in Topic 1"
content_blocks:
- "Now that you understand the basics, let's move on to some advanced concepts in Topic 1. 📝"
- "These concepts will help you gain a deeper understanding and apply what you've learned in more complex scenarios."
- "For example, if Topic 1 is about programming, you might learn about functions, classes, and modules."
question: "Do you understand the advanced concepts of Topic 1? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the advanced concepts of Topic 1, which includes functions, classes, and modules. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "introduction:intro_step_2"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user back to the introduction. Use emojis like 👍 and 🌟."
metadata_add:
lesson_1_completed: true
not_understand:
content_blocks:
- "Let's review the advanced concepts of Topic 1 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the advanced concepts of Topic 1. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- section_id: "lesson_2"
title: "Lesson 2: Topic 2"
steps:
- step_id: "lesson2_step_1"
title: "Introduction to Topic 2"
content_blocks:
- "Welcome to Lesson 2! 📝"
- "In this lesson, you will learn about Topic 2."
- "Topic 2 builds on what you learned in Topic 1 and introduces new concepts."
- step_id: "lesson2_step_2"
title: "Basics of Topic 2"
content_blocks:
- "Let's start with the basics of Topic 2. 📝"
- "Topic 2 involves understanding the fundamental principles that will be built upon in later lessons."
- "For example, if Topic 2 is about data structures, you might learn about arrays, linked lists, and stacks."
question: "Do you understand the basics of Topic 2? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the basics of Topic 2, which includes arrays, linked lists, and stacks. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "lesson_2:lesson2_step_3"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the next step. Use emojis like 👍 and 🌟."
not_understand:
content_blocks:
- "Let's review the basics of Topic 2 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the basics of Topic 2. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- step_id: "lesson2_step_3"
title: "Advanced Concepts in Topic 2"
content_blocks:
- "Now that you understand the basics, let's move on to some advanced concepts in Topic 2. 📝"
- "These concepts will help you gain a deeper understanding and apply what you've learned in more complex scenarios."
- "For example, if Topic 2 is about data structures, you might learn about trees, graphs, and hash tables."
question: "Do you understand the advanced concepts of Topic 2? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the advanced concepts of Topic 2, which includes trees, graphs, and hash tables. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "introduction:intro_step_2"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user back to the introduction. Use emojis like 👍 and 🌟."
metadata_add:
lesson_2_completed: true
not_understand:
content_blocks:
- "Let's review the advanced concepts of Topic 2 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the advanced concepts of Topic 2. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- section_id: "lesson_3"
title: "Lesson 3: Topic 3"
steps:
- step_id: "lesson3_step_1"
title: "Introduction to Topic 3"
content_blocks:
- "Welcome to Lesson 3! 📝"
- "In this lesson, you will learn about Topic 3."
- "Topic 3 builds on what you learned in Topics 1 and 2 and introduces new concepts."
- step_id: "lesson3_step_2"
title: "Basics of Topic 3"
content_blocks:
- "Let's start with the basics of Topic 3. 📝"
- "Topic 3 involves understanding the fundamental principles that will be built upon in later lessons."
- "For example, if Topic 3 is about algorithms, you might learn about sorting, searching, and recursion."
question: "Do you understand the basics of Topic 3? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the basics of Topic 3, which includes sorting, searching, and recursion. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "lesson_3:lesson3_step_3"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user to the next step. Use emojis like 👍 and 🌟."
not_understand:
content_blocks:
- "Let's review the basics of Topic 3 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the basics of Topic 3. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- step_id: "lesson3_step_3"
title: "Advanced Concepts in Topic 3"
content_blocks:
- "Now that you understand the basics, let's move on to some advanced concepts in Topic 3. 📝"
- "These concepts will help you gain a deeper understanding and apply what you've learned in more complex scenarios."
- "For example, if Topic 3 is about algorithms, you might learn about dynamic programming, graph algorithms, and optimization techniques."
question: "Do you understand the advanced concepts of Topic 3? 🤔"
tokens_for_ai: "Guide the user to confirm their understanding of the advanced concepts of Topic 3, which includes dynamic programming, graph algorithms, and optimization techniques. Provide positive reinforcement. If the user asks clarifying questions, provide detailed explanations and examples. Use emojis like 👍 and 🌟."
buckets:
- understand
- not_understand
- off_topic
- asking_clarifying_questions
transitions:
understand:
next_section_and_step: "introduction:intro_step_2"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and guide the user back to the introduction. Use emojis like 👍 and 🌟."
metadata_add:
lesson_3_completed: true
not_understand:
content_blocks:
- "Let's review the advanced concepts of Topic 3 again. 📝"
ai_feedback:
tokens_for_ai: "Provide supportive feedback and review the advanced concepts of Topic 3. Use emojis like 📝 and 🌟."
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the lesson in a supportive manner. Use emojis like 🔄 and 🧭."
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions with detailed explanations and examples. Provide comprehensive and helpful feedback. Use emojis like ❓ and 💬."
- section_id: "exit"
title: "Exit"
steps:
- step_id: "exit_step_1"
title: "Congratulations!"
content_blocks:
- "Congratulations on completing all the lessons! 🎉"
- "You have successfully completed the activity."
- "We hope you enjoyed the learning experience. 🌟"
- "Thank you for participating! Goodbye! 👋"

View file

@ -0,0 +1,332 @@
default_max_attempts_per_step: 30
tokens_for_ai_rubric: |
You are a master storyteller. Your task is to create a coherent and engaging story based on the following chat history. The story should seamlessly integrate the user's responses and the AI's feedback, ensuring that the narrative flows naturally. Pay special attention to the user's choices and how they shape the story. Use descriptive language to bring the scenes to life and make the story immersive. The story should have a clear beginning, middle, and end, reflecting the user's journey and the outcomes of their decisions. Here is the chat history.
sections:
- section_id: "section_1"
title: "The Prize Room"
steps:
- step_id: "step_1"
title: "Receive Your Prize"
content_blocks:
- "You have entered the prize room! 🎁"
- "A prize is randomly selected for you from the room."
- "You can also go to the temple pit from here."
tokens_for_ai: "DO NOT select go_back unless the users says 'go back' in their message."
question: "You have received a prize! Guess what it could be? 🤔"
buckets:
- random_prize_guess
- go_to_temple_pit
- go_back
transitions:
random_prize_guess:
ai_feedback:
tokens_for_ai: "cheer for the player, they got a new item. list them all from metadata. now make a joke about their guess!"
content_blocks:
- "You received a random prize! 🎲"
next_section_and_step: "section_1:step_1"
metadata_random:
golden_keychain: true
mysterious_amulet: true
rare_gemstone: true
ancient_scroll: true
magical_wand: true
treasure_map: true
silver_coin: true
mystical_ring: true
rare_book: true
magical_potion: true
shadow_charm: true
flame_charm: true
go_to_temple_pit:
content_blocks:
- "You chose to go to the temple pit room. 🏛"
next_section_and_step: "section_2:step_1"
go_back:
content_blocks:
- "You chose to go back to the temple pit room. 🏛"
next_section_and_step: "section_2:step_1"
- section_id: "section_2"
title: "The Temple Pit"
steps:
- step_id: "step_1"
title: "Offer to the God"
content_blocks:
- "You have entered the temple pit. 🏛"
- "You can offer an item to the god to receive a new item."
tokens_for_ai: "Guide the user to make a choice between offering different items."
question: "Which item do you offer to the god? 🤔"
buckets:
- offer_golden_keychain
- offer_mysterious_amulet
- offer_rare_gemstone
- offer_ancient_scroll
- offer_magical_wand
- offer_treasure_map
- offer_silver_coin
- offer_mystical_ring
- offer_rare_book
- offer_magical_potion
- offer_shadow_charm
- offer_flame_charm
- go_back
- off_topic
transitions:
offer_golden_keychain:
metadata_conditions:
golden_keychain: true
content_blocks:
- "You offered the golden keychain to the god. 🗝"
- "The god grants you a mystical amulet. 🧿"
next_section_and_step: "section_2:step_1"
metadata_add:
mystical_amulet: true
metadata_remove:
- golden_keychain
offer_mysterious_amulet:
metadata_conditions:
mysterious_amulet: true
content_blocks:
- "You offered the mysterious amulet to the god. 🧿"
- "The god grants you a rare gemstone. 💎"
next_section_and_step: "section_2:step_1"
metadata_add:
rare_gemstone: true
metadata_remove:
- mysterious_amulet
offer_rare_gemstone:
metadata_conditions:
rare_gemstone: true
content_blocks:
- "You offered the rare gemstone to the god. 💎"
- "The god grants you an ancient scroll. 📜"
next_section_and_step: "section_2:step_1"
metadata_add:
ancient_scroll: true
metadata_remove:
- rare_gemstone
offer_ancient_scroll:
metadata_conditions:
ancient_scroll: true
content_blocks:
- "You offered the ancient scroll to the god. 📜"
- "The god grants you a magical wand. 🪄"
next_section_and_step: "section_2:step_1"
metadata_add:
magical_wand: true
metadata_remove:
- ancient_scroll
offer_magical_wand:
metadata_conditions:
magical_wand: true
content_blocks:
- "You offered the magical wand to the god. 🪄"
- "The god grants you a treasure map. 🗺"
next_section_and_step: "section_2:step_1"
metadata_add:
treasure_map: true
metadata_remove:
- magical_wand
offer_treasure_map:
metadata_conditions:
treasure_map: true
content_blocks:
- "You offered the treasure map to the god. 🗺"
- "The god grants you a silver coin. 🪙"
next_section_and_step: "section_2:step_1"
metadata_add:
silver_coin: true
metadata_remove:
- treasure_map
offer_silver_coin:
metadata_conditions:
silver_coin: true
content_blocks:
- "You offered the silver coin to the god. 🪙"
- "The god grants you a mystical ring. 💍"
next_section_and_step: "section_2:step_1"
metadata_add:
mystical_ring: true
metadata_remove:
- silver_coin
offer_mystical_ring:
metadata_conditions:
mystical_ring: true
content_blocks:
- "You offered the mystical ring to the god. 💍"
- "The god grants you a rare book. 📚"
next_section_and_step: "section_2:step_1"
metadata_add:
rare_book: true
metadata_remove:
- mystical_ring
offer_rare_book:
metadata_conditions:
rare_book: true
content_blocks:
- "You offered the rare book to the god. 📚"
- "The god grants you a magical potion. 🧪"
next_section_and_step: "section_2:step_1"
metadata_add:
magical_potion: true
metadata_remove:
- rare_book
offer_magical_potion:
metadata_conditions:
magical_potion: true
content_blocks:
- "You offered the magical potion to the god. 🧪"
- "The god grants you a golden keychain. 🗝"
next_section_and_step: "section_2:step_1"
metadata_add:
golden_keychain: true
metadata_remove:
- magical_potion
offer_shadow_charm:
metadata_conditions:
shadow_charm: true
metadata_remove:
- shadow_charm
content_blocks:
- "You offered the Shadow Charm to the god. 🖤"
- "The god summons the Shadow Beast! Prepare for battle!"
next_section_and_step: "section_3:step_1"
offer_flame_charm:
metadata_conditions:
flame_charm: true
metadata_remove:
- flame_charm
content_blocks:
- "You offered the Flame Charm to the god. 🔥"
- "The god summons the Fire Drake! Prepare for battle!"
next_section_and_step: "section_4:step_1"
go_back:
content_blocks:
- "You chose to go back to the prize room. 🎁"
next_section_and_step: "section_1:step_1"
off_topic:
ai_feedback:
tokens_for_ai: "Gently guide the user back to the story in a supportive manner. DO NOT ask any questions. Use emojis like 🔄 and 🧭."
next_section_and_step: "section_2:step_1"
- section_id: "section_3"
title: "The Dark Cavern"
steps:
- step_id: "step_1"
title: "Battle the Shadow Beast"
content_blocks:
- "You have entered the Dark Cavern. The air is thick with darkness, and a menacing growl echoes around you."
- "A Shadow Beast emerges from the shadows, ready to attack!"
tokens_for_ai: "Guide the user to choose their action based on their items."
question: "Do you fight the Shadow Beast? (You need the Magical Wand or Mystical Ring to win!)"
buckets:
- fight_with_wand
- fight_with_ring
- flee
transitions:
fight_with_wand:
metadata_conditions:
magical_wand: true
content_blocks:
- "You wield the Magical Wand and unleash a powerful spell!"
- "The Shadow Beast is defeated! You find a Shadow Crystal. 💎"
next_section_and_step: "section_5:step_1"
metadata_add:
shadow_crystal: true
fight_with_ring:
metadata_conditions:
mystical_ring: true
content_blocks:
- "You use the Mystical Ring to channel your inner light!"
- "The Shadow Beast is defeated! You find a Shadow Crystal. 💎"
next_section_and_step: "section_5:step_1"
metadata_add:
shadow_crystal: true
flee:
content_blocks:
- "You attempt to flee, but the Shadow Beast catches you. You have met your end. 💀"
next_section_and_step: "death_ending:step_1"
- section_id: "section_4"
title: "The Fiery Lair"
steps:
- step_id: "step_1"
title: "Battle the Fire Drake"
content_blocks:
- "You have entered the Fiery Lair. The heat is intense, and flames flicker around you."
- "A Fire Drake roars, ready to defend its territory!"
tokens_for_ai: "Guide the user to choose their action based on their items."
question: "Do you fight the Fire Drake? (You need the Treasure Map or Ancient Scroll to win!)"
buckets:
- fight_with_map
- fight_with_scroll
- flee
transitions:
fight_with_map:
metadata_conditions:
treasure_map: true
content_blocks:
- "You use the Treasure Map to find the Drake's weak spot!"
- "The Fire Drake is defeated! You find a Flame Pendant. 🔥"
next_section_and_step: "section_5:step_1"
metadata_add:
flame_pendant: true
fight_with_scroll:
metadata_conditions:
ancient_scroll: true
content_blocks:
- "You read the Ancient Scroll and summon a powerful fire shield!"
- "The Fire Drake is defeated! You find a Flame Pendant. 🔥"
next_section_and_step: "section_5:step_1"
metadata_add:
flame_pendant: true
flee:
content_blocks:
- "You attempt to flee, but the Fire Drake incinerates you. You have met your end. 💀"
next_section_and_step: "death_ending_fire:step_1"
- section_id: "section_5"
title: "The Final Path"
steps:
- step_id: "step_1"
title: "The Final Path"
content_blocks:
- "You have defeated the monster and continue on your journey."
- "You see a path leading to the final destination."
tokens_for_ai: "Guide the user to the final victory."
question: "Do you continue on the path to victory? 🤔"
buckets:
- continue_to_victory
transitions:
continue_to_victory:
content_blocks:
- "You walk down the path and reach the final destination. You are victorious! 🏆"
next_section_and_step: "victory:step_1"
- section_id: "death_ending"
title: "The Abyss of Shadows"
steps:
- step_id: "step_1"
title: "Death Ending"
content_blocks:
- "Game Over."
- section_id: "death_ending_fire"
title: "The Ashen Wastes"
steps:
- step_id: "step_1"
title: "Death Ending"
content_blocks:
- "Game Over."
- section_id: "victory"
title: "Victory"
steps:
- step_id: "step_1"
title: "Victory"
content_blocks:
- "Thank you for playing!"

View file

@ -0,0 +1,92 @@
default_max_attempts_per_step: 30
sections:
- section_id: "section_1"
title: "Rock-Paper-Scissors with History"
steps:
- step_id: "step_0"
title: "Challenge a Historical Figure"
content_blocks:
- "Welcome to the Rock-Paper-Scissors challenge! 🎮"
- "You will be playing against a random historical figure."
- step_id: "step_1"
title: "Shoot against a Historical Figure"
tokens_for_ai: |
Careful to check if user is trying to 'set_language' and do that first. otherwise figure out if they are picking the bucket rock, paper, or scissors.
feedback_tokens_for_ai: |
Speaking in first person as a historical figure, firstly announce your move based on the metadata and then on a new line,
Determine who wins the game, use 'user_choice' against the given `ai_` value.
The rules are simple:
* rock always beats scissors
* paper always beats rock
* scissors always beats paper
Finally continue to provide a witty fact as the figure. Don't ever mention AI.
The figure should also comment on the 'attempts' number and how many times played!
if you feel like it, jeer at the player about an early 'exit' & suggest they quit.
question: "What's your choice? Rock, paper, or scissors? 🤔"
buckets:
- rock
- paper
- scissors
- set_language
- exit
transitions:
rock:
ai_feedback:
tokens_for_ai: "Declare your move and then determine who wins the game and provide a witty fact from the historical figure's perspective."
metadata_add:
attempts: "n+1"
metadata_tmp_add:
user_choice: "rock"
metadata_tmp_random:
ai_rock: true
ai_paper: true
ai_scissors: true
next_section_and_step: "section_1:step_1"
paper:
ai_feedback:
tokens_for_ai: "Declare your move and then determine who wins the game and provide a witty fact from the historical figure's perspective."
metadata_add:
attempts: "n+1"
metadata_tmp_add:
user_choice: "paper"
metadata_tmp_random:
ai_rock: true
ai_paper: true
ai_scissors: true
next_section_and_step: "section_1:step_1"
scissors:
ai_feedback:
tokens_for_ai: "Declare your move and determine who wins the game and provide a witty fact from the historical figure's perspective."
metadata_add:
attempts: "n+1"
metadata_tmp_add:
user_choice: "scissors"
metadata_tmp_random:
ai_rock: true
ai_paper: true
ai_scissors: true
next_section_and_step: "section_1:step_1"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
exit:
next_section_and_step: "section_2:step_1"
- section_id: "section_2"
title: "Goodbye"
steps:
- step_id: "step_1"
title: "Exit"
content_blocks:
- "Thank you for playing! We hope you enjoyed the game. Have a great day! 🌟"

292
research/activity2.yaml Normal file
View file

@ -0,0 +1,292 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Python"
steps:
- step_id: "step_1"
title: "What is Python?"
content_blocks:
- "Welcome to the Python programming course."
- "Python is a high-level, interpreted programming language known for its readability and versatility."
tokens_for_ai: "Explain what Python is and its key features in a friendly and engaging manner."
question: "What do you know about Python?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of Python."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of Python. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Python."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Python in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Installing Python"
content_blocks:
- "To start coding in Python, you need to install it on your computer."
- "You can download Python from the official website: https://www.python.org/downloads/"
tokens_for_ai: "Explain how to install Python on different operating systems in a friendly and engaging manner."
question: "Have you installed Python on your computer?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You are ready to start coding in Python."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have some issues with the installation. Let's go over the steps again."
ai_feedback:
tokens_for_ai: "Provide detailed installation steps to help the user in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on installing Python."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of installing Python in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Basic Python Syntax"
steps:
- step_id: "step_1"
title: "Writing Your First Python Program"
content_blocks:
- "Let's write your first Python program."
- "Open a text editor and type the following code:\n```python\nprint('Hello, World!')\n```"
- "Save the file with a `.py` extension and run it using the Python interpreter."
tokens_for_ai: "Explain how to write and run a simple Python program in a friendly and engaging manner."
question: "Were you able to run the 'Hello, World!' program?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You've written and run your first Python program."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you had some issues. Let's go over the steps again."
ai_feedback:
tokens_for_ai: "Provide detailed steps to help the user run the program successfully in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on writing and running the Python program."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of writing and running the Python program in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Variables and Data Types"
content_blocks:
- "In Python, you can store data in variables."
- "Python supports various data types such as integers, floats, strings, and booleans."
- "Here's an example:\n```python\nx = 5\npi = 3.14\nname = 'Alice'\nis_student = True\n```"
tokens_for_ai: "Explain variables and data types in Python with examples in a friendly and engaging manner."
question: "Can you create a variable and assign a value to it?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You have successfully created a variable."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional examples and explanations to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on variables and data types."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of variables and data types in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Control Flow"
steps:
- step_id: "step_1"
title: "If Statements"
content_blocks:
- "If statements allow you to execute code based on certain conditions."
- "Here's an example:\n```python\nx = 10\nif x > 5:\n print('x is greater than 5')\nelse:\n print('x is 5 or less')\n```"
tokens_for_ai: "Explain if statements in Python with examples in a friendly and engaging manner."
question: "Can you write an if statement to check if a number is positive?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You've written a correct if statement."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional examples and explanations to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on if statements."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of if statements in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "For Loops"
content_blocks:
- "For loops allow you to iterate over a sequence of elements."
- "Here's an example:\n```python\nfor i in range(5):\n print(i)\n```"
tokens_for_ai: "Explain for loops in Python with examples in a friendly and engaging manner."
question: "Can you write a for loop to print the numbers from 1 to 10?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You've written a correct for loop."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional examples and explanations to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on for loops."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of for loops in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Functions"
steps:
- step_id: "step_1"
title: "Defining Functions"
content_blocks:
- "Functions allow you to encapsulate code into reusable blocks."
- "Here's an example:\n```python\ndef greet(name):\n print(f'Hello, {name}!')\n\ngreet('Alice')\n```"
tokens_for_ai: "Explain how to define and use functions in Python with examples in a friendly and engaging manner."
question: "Can you define a function that takes two numbers and returns their sum?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You've defined a correct function."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional examples and explanations to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on defining functions."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of defining functions in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Calling Functions"
content_blocks:
- "Once you've defined a function, you can call it to execute the code inside it."
- "Here's an example:\n```python\ndef add(a, b):\n return a + b\n\nresult = add(3, 4)\nprint(result)\n```"
tokens_for_ai: "Explain how to call functions in Python with examples in a friendly and engaging manner."
question: "Can you call a function that you've defined and print the result?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You've called the function correctly."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "It seems like you have a partial understanding. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional examples and explanations to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on calling functions."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of calling functions in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_3"
title: "The End."
content_blocks:
- "The End."

View file

@ -0,0 +1,102 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "History Quiz Challenge"
steps:
- step_id: "step_1"
title: "Question 1"
content_blocks:
- "Welcome to the History Quiz Challenge! 🏆"
- "Let's see how well you know your history. Answer the following questions:"
question: "Who was the first President of the United States? 🇺🇸"
buckets:
- george_washington
- incorrect
transitions:
george_washington:
content_blocks:
- "Correct! George Washington was the first President of the United States."
metadata_add:
correct_answers: "n+1"
next_section_and_step: "section_1:step_2"
incorrect:
content_blocks:
- "That's not correct. The first President was George Washington."
metadata_add:
incorrect_attempts: "n+1"
next_section_and_step: "section_1:step_2"
- step_id: "step_2"
title: "Question 2"
question: "What year did the Titanic sink? 🚢"
buckets:
- 1912
- incorrect
transitions:
1912:
content_blocks:
- "Correct! The Titanic sank in 1912."
metadata_add:
correct_answers: "n+1"
next_section_and_step: "section_1:step_3"
incorrect:
content_blocks:
- "That's not correct. The Titanic sank in 1912."
metadata_add:
incorrect_attempts: "n+1"
next_section_and_step: "section_1:step_3"
- step_id: "step_3"
title: "Question 3"
question: "Who painted the Mona Lisa? 🎨"
buckets:
- leonardo_da_vinci
- incorrect
transitions:
leonardo_da_vinci:
content_blocks:
- "Correct! Leonardo da Vinci painted the Mona Lisa."
metadata_add:
correct_answers: "n+1"
next_section_and_step: "section_2:step_1"
incorrect:
content_blocks:
- "That's not correct. The Mona Lisa was painted by Leonardo da Vinci."
metadata_add:
incorrect_attempts: "n+1"
next_section_and_step: "section_2:step_1"
- section_id: "section_2"
title: "Quiz Results"
steps:
- step_id: "step_1"
title: "Results"
content_blocks:
- "Congratulations on completing the quiz! 🎉"
- "Let's see how you did:"
- "Correct Answers: {{correct_answers}}"
- "Incorrect Attempts: {{incorrect_attempts}}"
question: "Do you want to try the quiz again or exit? Type 'retry' to start over or 'exit' to finish."
buckets:
- retry
- exit
transitions:
retry:
content_blocks:
- "Great! Let's start the quiz again. 🏆"
metadata_remove:
- correct_answers
- incorrect_attempts
next_section_and_step: "section_1:step_1"
exit:
content_blocks:
- "Thank you for playing the History Quiz Challenge! Have a great day! 🌟"
next_section_and_step: "section_3:step_1"
- section_id: "section_3"
title: "Goodbye"
steps:
- step_id: "step_1"
title: "Exit"
content_blocks:
- "Thank you for participating! We hope you enjoyed the quiz. Goodbye! 👋"

390
research/activity21.yaml Normal file
View file

@ -0,0 +1,390 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_0"
title: "Introduction"
steps:
- step_id: "step_1"
title: "Welcome"
content_blocks:
- "Welcome to the Violent Python Mastery course! 🐍"
- "This course will test your understanding of key concepts from the book 'Violent Python'."
- section_id: "section_1"
title: "Python for Hackers"
steps:
- step_id: "step_1"
title: "Understanding Python Scripting"
content_blocks:
- "Python is a powerful tool for hackers due to its simplicity and extensive libraries."
- "Think about why Python is favored in the hacking community. Consider aspects like ease of use, versatility, and community support."
tokens_for_ai: "Guide the student to think about the reasons Python is popular among hackers. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "Why do you think Python is a popular choice for hackers? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand why Python is popular among hackers. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. Why do you think Python is favored by hackers? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on why Python is popular among hackers. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of Python's popularity in hacking in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Python Libraries for Security"
content_blocks:
- "Python has many libraries that are useful for security tasks, such as Scapy, Nmap, and PyCrypto."
- "Think about how these libraries can be used in security analysis and hacking. Consider aspects like network scanning, packet manipulation, and encryption."
tokens_for_ai: "Guide the student to think about the use of Python libraries in security. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "How do you think Python libraries like Scapy and PyCrypto are used in security tasks? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You understand the use of Python libraries in security. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think these libraries are used in security? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the use of Python libraries in security. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of Python libraries in security in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_2"
title: "Forensic Analysis with Python"
steps:
- step_id: "step_1"
title: "Python in Forensic Analysis"
content_blocks:
- "Python can be used in forensic analysis to automate tasks and analyze data."
- "Think about how Python scripts can help in forensic investigations. Consider aspects like data parsing, log analysis, and evidence extraction."
tokens_for_ai: "Guide the student to think about the use of Python in forensic analysis. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "How do you think Python can be used in forensic analysis? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand the use of Python in forensic analysis. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think Python helps in forensic analysis? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the use of Python in forensic analysis. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of Python in forensic analysis in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Automating Forensic Tasks"
content_blocks:
- "Automation is key in forensic analysis to handle large volumes of data efficiently."
- "Think about how Python can automate repetitive tasks in forensic investigations. Consider aspects like script execution, data filtering, and report generation."
tokens_for_ai: "Guide the student to think about automating forensic tasks with Python. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "How do you think Python can automate tasks in forensic investigations? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You understand how Python can automate forensic tasks. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think Python automates forensic tasks? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on automating forensic tasks with Python. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of automating forensic tasks with Python in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_3"
title: "Security Engineering with Python"
steps:
- step_id: "step_1"
title: "Python in Security Engineering"
content_blocks:
- "Python is used in security engineering to develop tools and scripts for vulnerability assessment and penetration testing."
- "Think about how Python can be used to identify and exploit vulnerabilities. Consider aspects like script development, tool integration, and testing automation."
tokens_for_ai: "Guide the student to think about the use of Python in security engineering. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "How do you think Python is used in security engineering? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Great! You understand the use of Python in security engineering. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think Python is used in security engineering? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the use of Python in security engineering. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of Python in security engineering in a supportive manner. Use emojis like 🔄 and 🧭."
- step_id: "step_2"
title: "Developing Security Tools"
content_blocks:
- "Python is often used to develop custom security tools for specific tasks."
- "Think about how you can use Python to create tools for security analysis. Consider aspects like functionality, user interface, and integration with other tools."
tokens_for_ai: "Guide the student to think about developing security tools with Python. Be on the lookout for the user trying to change their language preference because it's never 'off_topic' to 'set_language'. Use the 'off_topic' category sparingly, focusing on guiding the user back to the topic if needed. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
feedback_tokens_for_ai: "Don't forget to let the user know how many they have answered correctly. Give a detailed example of the tool or concept in Python markdown fenced code block."
question: "How do you think you can use Python to develop security tools? 🤔"
buckets:
- correct
- partial_understanding
- limited_effort
- asking_clarifying_questions
- set_language
- off_topic
transitions:
correct:
content_blocks:
- "Excellent! You have a good idea of how to develop security tools with Python. 🎉"
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the student to continue learning. Use emojis like 👍 and 🌟."
metadata_add:
points: "n+random(1,20)"
attempts: "n+1"
partial_understanding:
content_blocks:
- "You have a partial understanding. Let's clarify a few points. 🤔"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the student's understanding in a friendly and supportive manner. Use emojis like 🤔 and 📚."
metadata_add:
points: "n+random(1,4)"
attempts: "n+1"
limited_effort:
content_blocks:
- "It seems like you're unsure. That's okay! Let's explore this topic together. How do you think Python can be used to develop security tools? 🤔"
ai_feedback:
tokens_for_ai: "Encourage the student to reflect on the topic and consider different aspects. Offer hints or context to guide their thinking. Use emojis like 🤔 and 💡."
metadata_add:
points: "n+random(1,2)"
attempts: "n+1"
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them. ❓"
ai_feedback:
tokens_for_ai: "Answer the student's clarifying questions and provide additional information in a friendly and engaging manner. Use emojis like ❓ and 💬."
counts_as_attempt: false
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on developing security tools with Python. 🔄"
ai_feedback:
tokens_for_ai: "Gently guide the student back to the topic of developing security tools with Python in a supportive manner. Use emojis like 🔄 and 🧭."
- section_id: "section_4"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Violent Python Mastery course! 🎉"
- "You have demonstrated a strong understanding of Python's role in hacking, forensic analysis, and security engineering."
- "This knowledge will help you apply Python effectively in security-related tasks."
- "We are proud of your dedication and hard work. Well done! 🌟"

View file

@ -0,0 +1,102 @@
default_max_attempts_per_step: 30
sections:
- section_id: "section_1"
title: "Odds and Evens with History"
steps:
- step_id: "step_0"
title: "Challenge a Historical Figure"
content_blocks:
- "Welcome to the Odds and Evens challenge! 🎮"
- "You will be playing against a random historical figure."
- step_id: "step_1"
title: "Throw Your Fingers"
tokens_for_ai: |
Careful to check if user is trying to 'set_language' and do that first. Otherwise, figure out if they are picking a number between 0 and 5.
feedback_tokens_for_ai: |
Important, you do not have to calculate the winner, we have
under processing_script_result for you that determines the winner.
Important, you do not pick a random move, it was selected for you:
* 'ai_choice_finger': it's your number of fingers up that you will announce to the user.
* 'ai_choice': it's your guess of odd or even that you will announce to the user.
Speaking in first person as a historical figure, first always announce the move
selected for you and then move to a new line.
The rules are simple, the processing_script_result to determines winner or tie.
* Sum the numbers.
* If the sum of the fingers is even, the player who chose "even" wins.
* If the sum is odd, the player who chose "odd" wins.
* If both players are wrong or right about "odd" or "even" it's a tie.
* A user cannot win unless they have a match with the game name "odd" or "even"
Careful it's easy to add wrong or say a number is odd when it's even and vice versa.
Finally, continue to provide a witty fact as the figure. Don't ever mention AI.
The figure should also comment on the 'attempts' number and how many times played!
If you feel like it, jeer at the player about an early 'exit' & suggest they quit.
processing_script: |
user_input = metadata["user_choice"].split()
user_fingers = None
user_choice = None
for item in user_input:
if item.isdigit():
user_fingers = int(item)
elif item in ["odd", "even"]:
user_choice = item
ai_fingers = int(metadata["ai_choice_finger"]) # Ensure ai_fingers is an integer
ai_choice = metadata["ai_choice"]
total_fingers = user_fingers + ai_fingers
result = "even" if total_fingers % 2 == 0 else "odd"
user_wins = (result == user_choice)
ai_wins = (result == ai_choice)
if user_wins and not ai_wins:
winner = "User wins!"
elif ai_wins and not user_wins:
winner = "AI wins!"
else:
winner = "It's a tie!"
script_result = {"sum": total_fingers, "result": result, "winner": winner}
question: "How many fingers do you throw? (Choose a number between 0 and 5 & either even or odd.) 🤔"
buckets:
- throw_fingers
- set_language
- exit
transitions:
throw_fingers:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Declare your move and then determine who wins the game and provide a witty fact from the historical figure's perspective."
metadata_add:
attempts: "n+1"
metadata_tmp_add:
user_choice: "the-users-response"
ai_choice_finger: "n+random(0,5)"
metadata_tmp_random:
ai_choice: odd
ai_choice: even
next_section_and_step: "section_1:step_1"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
ai_feedback:
tokens_for_ai: "Acknowledge the language change and confirm the update."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
exit:
next_section_and_step: "section_2:step_1"
- section_id: "section_2"
title: "Goodbye"
steps:
- step_id: "step_1"
title: "Exit"
content_blocks:
- "Thank you for playing! We hope you enjoyed the game. Have a great day! 🌟"

View file

@ -0,0 +1,373 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Math Quiz: From Basics to Algebra"
steps:
- step_id: "step_1"
title: "Basic Addition"
content_blocks:
- "Solve the following problem: 5 + 3"
- "You can show your work and provide the final answer."
question: "What is 5 + 3? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is 8.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_2"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_1"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_1"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_1"
- step_id: "step_2"
title: "Basic Subtraction"
content_blocks:
- "Solve the following problem: 10 - 4"
- "You can show your work and provide the final answer."
question: "What is 10 - 4? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is 6.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_3"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_2"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_2"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_2"
- step_id: "step_3"
title: "Basic Multiplication"
content_blocks:
- "Solve the following problem: 4 * 2"
- "You can show your work and provide the final answer."
question: "What is 4 * 2? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is 8.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_4"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_3"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_3"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_3"
- step_id: "step_4"
title: "Basic Division"
content_blocks:
- "Solve the following problem: 16 / 4"
- "You can show your work and provide the final answer."
question: "What is 16 / 4? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is 4.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_5"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_4"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_4"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_4"
- step_id: "step_5"
title: "Introduction to Variables"
content_blocks:
- "Solve for x: x + 5 = 10"
- "You can show your work and provide the final answer."
question: "What is the value of x in the equation x + 5 = 10? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is x = 5.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer for x. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_6"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_5"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_5"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_5"
- step_id: "step_6"
title: "Solving Linear Equations"
content_blocks:
- "Solve for x: 2x + 3 = 11"
- "You can show your work and provide the final answer."
question: "What is the value of x in the equation 2x + 3 = 11? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is x = 4.
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Great job! You got the correct answer for x. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_7"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_6"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_6"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_6"
- step_id: "step_7"
title: "Quadratic Equations"
content_blocks:
- "Solve the quadratic equation: x^2 - 5x + 6 = 0"
- "You can show your work and provide the final answer."
question: "What are the values of x in the equation x^2 - 5x + 6 = 0? Show your work and provide the answers."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answers are x = 2 and x = 3.
If the user shows their work but doesn't provide final answers, categorize as 'show_work'.
If the answers are incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Well done! You found the correct roots of the equation. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_1:step_8"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_7"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_7"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_7"
- step_id: "step_8"
title: "Simplifying Expressions"
content_blocks:
- "Simplify the expression: 3(x + 2) - 4x"
- "You can show your work and provide the final answer."
question: "What is the simplified form of the expression 3(x + 2) - 4x? Show your work and provide the answer."
tokens_for_ai: |
Determine if the user's response is correct by checking if the final answer is: 6 - x or -x + 6
If the user shows their work but doesn't provide a final answer, categorize as 'show_work'.
If the answer is incorrect, categorize as 'incorrect'.
If the user wants to change the language, categorize as 'set_language'.
feedback_tokens_for_ai: |
DO NOT answer or solve the question problem when explaining the problem. Instead use a different contrived problem.
buckets:
- correct
- incorrect
- show_work
- set_language
transitions:
correct:
ai_feedback:
tokens_for_ai: "Excellent! You simplified the expression correctly. if 'correct' give the answer and solve the question problem showing all work and explain the problem."
metadata_add:
score: "n+1"
next_section_and_step: "section_2:step_1"
incorrect:
ai_feedback:
tokens_for_ai: "The answer is not right. Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
attempts: "n+1"
next_section_and_step: "section_1:step_8"
show_work:
ai_feedback:
tokens_for_ai: "Thanks the user for showing work. Catch mistakes and suggest next steps. Remember give a separate example to show how to solve the answer, never reveal it."
metadata_add:
user_work: "the-users-response"
next_section_and_step: "section_1:step_8"
set_language:
content_blocks:
- "language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_8"
- section_id: "section_2"
title: "Quiz Complete"
steps:
- step_id: "step_1"
title: "Completion"
content_blocks:
- "Congratulations! You've completed the math quiz."
- "Your final score will be displayed at the end."

View file

@ -0,0 +1,297 @@
default_max_attempts_per_step: 3
# Common processing script for all plotting steps
common_processing_script: &plotting_script |
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot
import numpy
import io
import base64
import re
import sympy as sp
# Get the user's function input from metadata
user_function = metadata.get("user_function", "x")
original_function = user_function
try:
# Support multiple functions separated by semicolon or comma
function_list = re.split(r'[;,]', user_function)
function_list = [f.strip() for f in function_list if f.strip()]
# Colors for multiple functions
colors = ['blue', 'red', 'green', 'orange', 'purple', 'brown', 'pink', 'gray']
matplotlib.pyplot.figure(figsize=(10, 6))
all_y_values = []
function_info = []
for i, func_str in enumerate(function_list):
# Preprocess each function
processed_func = func_str.replace('^', '**')
processed_func = re.sub(r'(?<=\d)(?=[a-zA-Z])', '*', processed_func)
processed_func = re.sub(r'(?<=[a-zA-Z])(?=\d)', '*', processed_func)
# Enhanced function preprocessing
enhanced_replacements = {
'arctan': 'atan',
'arcsin': 'asin',
'arccos': 'acos',
'log': 'ln',
'ln': 'log', # Allow both ln and log
'abs': 'Abs'
}
parsed_function = processed_func
for old, new in enhanced_replacements.items():
parsed_function = re.sub(r'\b' + old + r'\b', new, parsed_function)
# Create sympy symbol and parse expression
x_sym = sp.Symbol('x')
expr = sp.sympify(parsed_function, locals={'x': x_sym})
# Analyze function characteristics for dynamic range (inline)
func_type = "other"
if expr.has(sp.sin) or expr.has(sp.cos) or expr.has(sp.tan):
func_type = "trigonometric"
elif expr.has(sp.exp):
func_type = "exponential"
elif expr.has(sp.log):
func_type = "logarithmic"
elif expr.is_polynomial(x_sym):
degree = sp.degree(expr, x_sym)
if degree == 1:
func_type = "linear"
elif degree == 2:
func_type = "quadratic"
elif degree == 3:
func_type = "cubic"
elif expr.has(sp.sqrt):
func_type = "radical"
elif expr.has(1/x_sym):
func_type = "rational"
# Determine optimal range inline
if func_type == "trigonometric":
x_range = (-2*numpy.pi, 2*numpy.pi)
elif func_type == "exponential":
x_range = (-3, 3)
elif func_type == "logarithmic":
x_range = (0.1, 10)
elif func_type in ["linear", "quadratic", "cubic"]:
x_range = (-10, 10)
elif func_type == "rational":
x_range = (-10, 10)
else:
x_range = (-5, 5)
# Prepare x values with dynamic range
x_vals = numpy.linspace(x_range[0], x_range[1], 400)
# Convert to numpy function and evaluate
func = sp.lambdify(x_sym, expr, 'numpy')
y = func(x_vals)
# Handle complex results
if numpy.iscomplexobj(y):
y = numpy.real(y)
# Filter out infinite/NaN values for better plotting
valid_mask = numpy.isfinite(y)
x_vals_clean = x_vals[valid_mask]
y_clean = y[valid_mask]
if len(y_clean) > 0:
all_y_values.extend(y_clean)
color = colors[i % len(colors)]
matplotlib.pyplot.plot(x_vals_clean, y_clean,
label=f'y = {func_str}',
color=color, linewidth=2)
# Store function analysis info
function_info.append({
'function': func_str,
'type': func_type,
'range': x_range
})
# Dynamic y-axis limits based on all functions
if all_y_values:
y_min, y_max = numpy.percentile(all_y_values, [5, 95])
y_range = y_max - y_min
matplotlib.pyplot.ylim(y_min - 0.1*y_range, y_max + 0.1*y_range)
# Enhanced plot styling
matplotlib.pyplot.title(f'Plot of: {original_function}', fontsize=14, fontweight='bold')
matplotlib.pyplot.xlabel('x', fontsize=12)
matplotlib.pyplot.ylabel('y', fontsize=12)
matplotlib.pyplot.grid(True, alpha=0.3)
matplotlib.pyplot.legend(fontsize=10)
# Generate function analysis inline
analysis_parts = []
for info in function_info:
func_type = info['type']
if func_type == "quadratic":
analysis_parts.append(f"'{info['function']}' is a parabola (quadratic function)")
elif func_type == "linear":
analysis_parts.append(f"'{info['function']}' is a straight line (linear function)")
elif func_type == "trigonometric":
analysis_parts.append(f"'{info['function']}' shows periodic behavior (trigonometric)")
elif func_type == "exponential":
analysis_parts.append(f"'{info['function']}' shows exponential growth/decay")
elif func_type == "logarithmic":
analysis_parts.append(f"'{info['function']}' is a logarithmic curve")
else:
analysis_parts.append(f"'{info['function']}' is a {func_type} function")
analysis_text = "; ".join(analysis_parts)
buf = io.BytesIO()
matplotlib.pyplot.tight_layout()
matplotlib.pyplot.savefig(buf, format='png', dpi=100, bbox_inches='tight')
matplotlib.pyplot.close()
buf.seek(0)
plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')
script_result = {
"plot_image": plot_image,
"function_analysis": analysis_text,
"function_info": function_info
}
except Exception as e:
# Handle errors gracefully with error message plot
matplotlib.pyplot.figure()
matplotlib.pyplot.text(0.5, 0.5, f'Error: Invalid function\n"{original_function}"\n\n{str(e)[:100]}...',
horizontalalignment='center', verticalalignment='center',
transform=matplotlib.pyplot.gca().transAxes, fontsize=12,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightcoral"))
matplotlib.pyplot.title('Function Error')
matplotlib.pyplot.axis('off')
buf = io.BytesIO()
matplotlib.pyplot.savefig(buf, format='png')
matplotlib.pyplot.close()
buf.seek(0)
plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')
script_result = {"plot_image": plot_image, "error": str(e)}
sections:
- section_id: "section_1"
title: "Math Plotter: Visualizing Functions"
steps:
- step_id: "step_1"
title: "Introduction to Plotting"
content_blocks:
- "Welcome to the Math Plotter activity! 📈"
- "In this activity, you'll learn how to plot mathematical functions and visualize them."
question: "Are you ready to start plotting? Type 'yes' to begin."
tokens_for_ai: |
Determine if the user's response is 'yes' to proceed.
If the user wants to change the language, categorize as 'set_language'.
buckets:
- proceed
- set_language
transitions:
proceed:
next_section_and_step: "section_1:step_2"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_1"
- step_id: "step_2"
title: "First Plot - Linear Function"
content_blocks:
- "Let's start by plotting a specific linear function! 📏"
- "We'll plot: y = 2*x + 1"
question: "Ready to plot y = 2*x + 1? Type 'yes' to see the graph."
tokens_for_ai: |
Check if the user entered a valid linear function. Accept any linear function like 'mx + b' format.
Don't require analysis at this step - just check if it's a valid function.
If the user wants to change the language, categorize as 'set_language'.
processing_script: *plotting_script
buckets:
- proceed
- set_language
transitions:
proceed:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Perfect! Here's the linear function y = 2*x + 1 plotted for you. Now you can explore plotting any functions you want!"
metadata_add:
user_function: "2*x + 1"
next_section_and_step: "section_1:step_3"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_2"
- step_id: "step_3"
title: "Free Exploration - Plot Anything!"
content_blocks:
- "🎨 Time to explore! You can plot any function(s) you want."
- "Try single functions: x**2, sin(x), exp(x), log(x), sqrt(x)"
- "Try multiple functions: sin(x), cos(x) or x**2, 2*x + 1"
- "Mix different types: sin(x), x**2, exp(-x)"
- "Type 'done' when you're ready to finish."
question: "Enter any function(s) to plot (or 'done' to complete):"
tokens_for_ai: |
This is a free exploration step. Accept any valid mathematical function(s).
If user says 'done', 'finished', 'complete', etc., categorize as 'done'.
If the user wants to change the language, categorize as 'set_language'.
Otherwise, if it looks like a valid function, categorize as 'valid_function'.
processing_script: *plotting_script
buckets:
- valid_function
- done
- invalid_function
- set_language
transitions:
valid_function:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Great exploration! Here's your plot. Try another function or type 'done' to finish."
metadata_add:
user_function: "the-users-response"
exploration_count: "n+1"
counts_as_attempt: false
next_section_and_step: "section_1:step_3"
done:
ai_feedback:
tokens_for_ai: "Excellent exploration! You've completed the math plotting activity."
metadata_add:
score: "n+1"
next_section_and_step: "section_2:step_1"
invalid_function:
ai_feedback:
tokens_for_ai: "That doesn't look like a valid function. Try mathematical expressions like 'x**2' or 'sin(x)'."
counts_as_attempt: false
next_section_and_step: "section_1:step_3"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_3"
- section_id: "section_2"
title: "Plotting Complete"
steps:
- step_id: "step_1"
title: "Completion"
content_blocks:
- "Congratulations! You've completed the math plotter activity."
- "You've learned how to plot and visualize different types of functions."

View file

@ -0,0 +1,74 @@
default_max_attempts_per_step: 1
sections:
- section_id: "section_1"
title: "Magic 8 Ball"
steps:
- step_id: "step_0"
title: "Introduction"
content_blocks:
- "Welcome to the Magic 8 Ball! 🎱"
- "Think of a yes or no question and ask the Magic 8 Ball."
- step_id: "step_1"
title: "Ask the Magic 8 Ball"
question: "What is your question for the Magic 8 Ball?"
tokens_for_ai: |
Provide a random response from the Magic 8 Ball's set of answers.
If the user wants to change the language, categorize as 'set_language'.
If the user wants to exit, categorize as 'exit'.
feedback_tokens_for_ai: |
Use the user's question to provide a random Magic 8 Ball response.
Consider the tone and style of traditional Magic 8 Ball answers.
buckets:
- ask_question
- set_language
- exit
transitions:
ask_question:
ai_feedback:
tokens_for_ai: |
Your answer for the user is in the metadata.
Use the user's question to provide a random Magic 8 Ball response.
Use emoji at the end of the response to relate.
On a new line write two sentences making a joke or relating to the question and the result.
metadata_tmp_random:
magic_8_ball_response:
# Positive answers
- "It is certain."
- "Without a doubt."
- "You may rely on it."
- "Yes, definitely."
- "As I see it, yes."
- "Most likely."
- "Outlook good."
- "Yes."
- "Signs point to yes."
- "Absolutely."
# Negative answers
- "Don't count on it."
- "My reply is no."
- "My sources say no."
- "Outlook not so good."
- "Very doubtful."
# Vague answers
- "Reply hazy, try again."
- "Ask again later."
- "Better not tell you now."
- "Cannot predict now."
- "Concentrate and ask again."
next_section_and_step: "section_1:step_1"
set_language:
content_blocks:
- "Language preference updated. Please continue in your preferred language."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "section_1:step_1"
exit:
next_section_and_step: "section_1:step_2"
- step_id: "step_2"
title: "Goodbye"
content_blocks:
- "Thank you for playing with the Magic 8 Ball! 🎉"
- "Feel free to come back anytime to ask more questions."

View file

@ -0,0 +1,204 @@
default_max_attempts_per_step: 9
sections:
- section_id: "section_1"
title: "Tic Tac Toe"
steps:
- step_id: "step_0"
title: "Introduction"
content_blocks:
- |
Welcome to Tic Tac Toe! 🎮
You will be playing against the AI. You are 'X' and the AI is 'O'.
The board positions are numbered 0 to 8 as follows:
<img src="/static/images/tic-tac-toe.png">
- step_id: "step_1"
title: "Your Move"
question: "Enter a position number (0-8) to place your 'X'. Say restart or exit to quit."
tokens_for_ai: |
Using the metadata, determine if the game is over and 'restart'.
If the user wants to restart or play again, categorize as 'restart'
If ai_wins or user_wins or is_draw is true, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
If the game_over is True categorize as 'restart'.
Finally check:
If the move is valid, categorize as 'valid_move'.
If the move is invalid, categorize as 'invalid_move'.
feedback_tokens_for_ai: |
Always speak in first person. DO NOT START WITH "ai_move:".
Player is always X, You the AI are always O.
If there is an error in the metadata the move was likely invalid.
On a new line, provide feedback on the user's move.
Only announce a winner or tie if game_over is True.
The player makes the first and last move.
If the move is invalid, prompt the user to try again.
If the move is invalid, give a list of valid moves.
If the move is valid & no errors say your move on the last line (ai_move) for example: I move to 8 and draw a O".
processing_script: |
import random
win_conditions = [
[0, 1, 2], [3, 4, 5], [6, 7, 8], # rows
[0, 3, 6], [1, 4, 7], [2, 5, 8], # columns
[0, 4, 8], [2, 4, 6] # diagonals
]
def check_win(board, player, win_conditions):
# Check for win and return the winning condition if there is one
for condition in win_conditions:
win = True
for i in condition:
if board[i] != player:
win = False
break
if win:
return condition
return None
def plot_board(board, win_line=None):
import io
import base64
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(3, 3))
ax.set_xlim(0, 3)
ax.set_ylim(0, 3)
ax.set_xticks([])
ax.set_yticks([])
ax.grid(True)
for i, mark in enumerate(board):
x = i % 3
y = 2 - i // 3
if mark != " ":
ax.text(x + 0.5, y + 0.5, mark, fontsize=24, ha='center', va='center')
else:
# Plot the cell number if the cell is empty
ax.text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')
# Draw the winning line if there is one
if win_line:
for i in range(len(win_line) - 1):
start = win_line[i]
end = win_line[i + 1]
x_start, y_start = start % 3 + 0.5, 2 - start // 3 + 0.5
x_end, y_end = end % 3 + 0.5, 2 - end // 3 + 0.5
ax.plot([x_start, x_end], [y_start, y_end], 'r-', linewidth=2)
buf = io.BytesIO()
plt.savefig(buf, format='png')
plt.close(fig)
buf.seek(0)
return base64.b64encode(buf.getvalue()).decode('utf-8')
# Reconstruct the board from moves
user_moves = metadata.get("user_moves", [])
ai_moves = metadata.get("ai_moves", [])
ai_move = None
board = [" "] * 9
for move in user_moves:
board[int(move)] = "X"
for move in ai_moves:
board[int(move)] = "O"
# Get the user's latest move
try:
user_move = int(metadata.get("user_move"))
except (IndexError, ValueError) as e:
# Remove the invalid move from user_moves
user_move = -1
# Check if the move is valid
if 0 <= user_move < 9 and board[user_move] == " ":
board[user_move] = "X"
user_moves.append(user_move)
user_win_line = check_win(board, "X", win_conditions)
if not user_win_line:
# ai makes a move.
available_positions = []
for i in range(len(board)):
if board[i] == " ":
available_positions.append(i)
if available_positions:
ai_move = random.choice(available_positions)
board[ai_move] = "O"
ai_moves.append(ai_move)
ai_win_line = check_win(board, "O", win_conditions)
is_draw = True
for x in board:
if x == " ":
is_draw = False
break
game_over = any([user_win_line, ai_win_line, is_draw])
win_line = user_win_line if user_win_line else ai_win_line
script_result = {
"plot_image": plot_board(board, win_line),
"set_background": not game_over,
"ai_move": ai_move,
"user_move": user_move,
"metadata": {
"user_moves": user_moves,
"ai_moves": ai_moves,
"board": board,
"game_over": game_over,
"ai_wins": ai_win_line is not None,
"user_wins": user_win_line is not None,
"is_draw": is_draw
}
}
else:
script_result = {
"error": f"Invalid move: {metadata.get('user_move')}",
"metadata": {
"user_moves": user_moves,
},
}
# Debugging: Print the current board state
print("Current board state:", board)
buckets:
- valid_move
- invalid_move
- restart
- exit
transitions:
valid_move:
run_processing_script: True
ai_feedback:
tokens_for_ai: |
at first glance it seems like a valid user_move.
DO NOT:
* DRAW THE GAME BOARD
* DESCRIBE THE GAME BOARD
metadata_tmp_add:
user_move: "the-users-response"
next_section_and_step: "section_1:step_1"
invalid_move:
ai_feedback:
tokens_for_ai: "That move is invalid. Please choose an empty position between 0 and 8."
metadata_tmp_add:
user_move: "the-users-response"
next_section_and_step: "section_1:step_1"
exit:
next_section_and_step: "section_1:step_2"
restart:
ai_feedback:
tokens_for_ai: "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
- step_id: "step_2"
title: "Goodbye"
content_blocks:
- "Thank you for playing Tic Tac Toe! 🎉"
- "Feel free to come back anytime for another game."

View file

@ -0,0 +1,279 @@
default_max_attempts_per_step: 9
sections:
- section_id: "section_1"
title: "Killer Squares"
steps:
- step_id: "step_0"
title: "Introduction"
content_blocks:
- |
Welcome to Killer Squares! 🎮
In this game, both you and the AI will secretly choose a square.
Then, you will attempt to "kill" a square. If you hit the AI's secret spot, you win!
If the AI hits your secret spot, you lose. If nobody hits, the game continues.
The board positions are numbered 0 to 8 as follows:
```
0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8
```
- step_id: "step_1"
title: "Choose Your Secret Spot"
question: "Choose a secret spot (0-8) for this round."
tokens_for_ai: |
If the user wants to exit, categorize as 'exit'.
If the move is valid, categorize as 'valid_move'.
If the move is invalid, categorize as 'invalid_move'.
feedback_tokens_for_ai: |
DO NOT TELL THE AI SECRET.
If there is an error in the metadata the move was likely invalid.
Always speak in first person. DO NOT START WITH "ai_move:".
On a new line, provide feedback on the user's move.
If the move is valid, proceed to the next step.
If the move is invalid, prompt the user to try again.
processing_script: |
import random
# Initialize or retrieve the game state
user_secret = metadata.get("user_secret", None)
ai_secret = random.randint(0, 8)
# Get the user's secret spot
try:
user_secret = int(metadata.get("user_secret"))
except (IndexError, ValueError) as e:
user_secret = -1
# Check if the move is valid
if 0 <= user_secret < 9:
script_result = {
"metadata": {
"user_secret": user_secret,
"ai_secret": ai_secret,
}
}
else:
script_result = {
"error": f"Invalid secret spot: {metadata.get('user_secret')}",
"metadata": {}
}
buckets:
- valid_move
- invalid_move
- restart
- exit
transitions:
valid_move:
run_processing_script: True
ai_feedback:
tokens_for_ai: "You've chosen your secret spot. Now, let's move to the killing round."
metadata_add:
user_secret: "the-users-response"
next_section_and_step: "section_1:step_2"
invalid_move:
ai_feedback:
tokens_for_ai: "That move is invalid. Please choose a position between 0 and 8."
metadata_add:
user_secret: "the-users-response"
next_section_and_step: "section_1:step_1"
exit:
next_section_and_step: "section_1:step_3"
restart:
ai_feedback:
tokens_for_ai: "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
- step_id: "step_2"
title: "Kill a Square"
question: "Choose a square to kill (0-8)."
tokens_for_ai: |
If the user wants to restart or play again, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
If the move is valid, categorize as 'valid_move'.
If the move is invalid, categorize as 'invalid_move'.
feedback_tokens_for_ai: |
DO NOT reveal the AI's secret spot until game_over = True.
ALWAYS speak in first person. DO NOT START WITH "ai_move:".
If there is an error in the metadata, the move was likely invalid.
On a new line, provide feedback on the user's move:
- If the move is valid, check if the user's shot hit my (AI's) secret spot (ai_secret).
- If the user's shot hits my secret spot, say: "You hit my secret spot!"
- If the user's shot misses, say: "You missed my secret spot."
If the move is invalid, prompt the user to try again.
My move is the last item in the ai_shots list. For example, if ai_shots = [5, 3], my move is 3.
Announce my move: "I shoot at position [my move]."
If game_over = True, determine the winner:
- If user_wins = True, say: "Congratulations! You hit my secret spot and won the round!"
- If ai_wins = True, say: "I hit your secret spot and won the round!"
If game_over = True, describe the carnage of the final strike.
If game_over = True, suggest: "Would you like to restart and play again, or would you prefer to exit?"
processing_script: |
import random
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import io
import base64
# Retrieve the game state
user_secret = metadata.get("user_secret")
ai_secret = metadata.get("ai_secret")
user_shots = metadata.get("user_shots", [])
ai_shots = metadata.get("ai_shots", [])
game_over = metadata.get("game_over", False)
# Get the user's kill move
try:
user_kill = int(metadata.get("user_kill"))
except (IndexError, ValueError) as e:
user_kill = -1
if game_over:
script_result = {}
elif 0 <= user_kill < 9:
# the move is valid.
user_shots.append(user_kill)
if user_kill == ai_secret:
game_over = True
user_wins = True
ai_wins = False
draw = False
user_title = "You Win!"
ai_title = "AI's Moves"
else:
# AI makes a move, avoiding its own secret spot
available_positions = []
for i in range(9):
if i not in ai_shots and i != ai_secret:
available_positions.append(i)
ai_kill = random.choice(available_positions) if available_positions else None
if ai_kill is not None:
ai_shots.append(ai_kill)
if ai_kill == user_secret:
game_over = True
user_wins = False
ai_wins = True
draw = False
user_title = "Your Moves"
ai_title = "AI Wins!"
else:
game_over = False
user_wins = False
ai_wins = False
draw = False
user_title = "Your Moves"
ai_title = "AI's Moves"
else:
game_over = True
user_wins = False
ai_wins = False
draw = True
user_title = "Your Moves"
ai_title = "It's a Draw!"
# Plot the boards
fig, axs = plt.subplots(1, 2, figsize=(6, 3))
fig.suptitle("Killer Squares", fontsize=16)
fig.tight_layout(h_pad=4)
# User's board
axs[0].set_xlim(0, 3)
axs[0].set_ylim(0, 3)
axs[0].set_xticks([])
axs[0].set_yticks([])
axs[0].grid(True)
axs[0].set_title(user_title, fontsize=12)
for i in range(9):
x = i % 3
y = 2 - i // 3
axs[0].text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')
for user_kill in user_shots:
ux, uy = user_kill % 3, 2 - user_kill // 3
axs[0].text(ux + 0.5, uy + 0.5, 'X', fontsize=24, ha='center', va='center', color='red')
# AI's board
axs[1].set_xlim(0, 3)
axs[1].set_ylim(0, 3)
axs[1].set_xticks([])
axs[1].set_yticks([])
axs[1].grid(True)
axs[1].set_title(ai_title, fontsize=12)
for i in range(9):
x = i % 3
y = 2 - i // 3
axs[1].text(x + 0.5, y + 0.5, str(i), fontsize=12, ha='center', va='center', color='gray')
for ai_kill in ai_shots:
axx, axy = ai_kill % 3, 2 - ai_kill // 3
axs[1].text(axx + 0.5, axy + 0.5, 'X', fontsize=24, ha='center', va='center', color='blue')
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
plt.close(fig)
buf.seek(0)
plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')
script_result = {
"plot_image": plot_image,
"metadata": {
"user_secret": user_secret,
"ai_secret": ai_secret,
"user_shots": user_shots,
"ai_shots": ai_shots,
"game_over": game_over,
"user_wins": user_wins,
"ai_wins": ai_wins,
"draw": draw,
}
}
else:
script_result = {
"error": f"Invalid kill move: {metadata.get('user_kill')}",
"metadata": {}
}
buckets:
- valid_move
- invalid_move
- exit
- restart
transitions:
valid_move:
run_processing_script: True
ai_feedback:
tokens_for_ai: |
If somebody wins explain the move that triggered the kill shot.
Only if game_over is True reveal the ai secret spot number otherwise never tell the player the secret!
metadata_tmp_add:
user_kill: "the-users-response"
next_section_and_step: "section_1:step_2"
invalid_move:
ai_feedback:
tokens_for_ai: "That move is invalid. Please choose a position between 0 and 8."
metadata_tmp_add:
user_kill: "the-users-response"
next_section_and_step: "section_1:step_2"
exit:
next_section_and_step: "section_1:step_3"
restart:
ai_feedback:
tokens_for_ai: "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
- step_id: "step_3"
title: "Goodbye"
content_blocks:
- "Thank you for playing Killer Squares! 🎉"
- "Feel free to come back anytime for another game."

View file

@ -0,0 +1,924 @@
default_max_attempts_per_step: 9
tokens_for_ai_rubric: |
based on the game without knowing where each ship was, score the process each player used to target ships.
be sure to look for moves or strategies in the game play that where _not_ smart given the obvious information uncovered.
use chain-of-thought to reason about the progression of the game and the winner.
first summarize the game, we don't need the turn by turn plays.
the game was battleship. the moves were done 1 by 1.
the grid is 0-99.
did any player blunder as the information was learned?
There was a user and an AI playing.
Depending on the game mode the player chooses they are going up against a different algo,
* random
* always plays randomly
* hunter
* keeps track of hits and targets every cell around it no matter what, randomly, else random
* super human hunter
* keeps track of hits and uses a probability grid normalized to 100 and always picks the max or random of any 100.
* hermes reasoner
* uses the probability algorithm paired with hermes to reason for 3 sentences about what the next 0-99 move should be given the current game state and turn number
Did any player miss sinking a ship that was found? was it due to end game or a blunder?
Do not mix up ships, keep careful track of the order they were found and sunk.
sections:
- section_id: "section_1"
title: "Battleship"
steps:
- step_id: "step_0"
title: "Introduction"
content_blocks:
- |
Welcome to Battleship! 🚢
In this game, both you and the AI have a fleet of ships placed randomly on a 10x10 grid.
The grid positions are numbered 0 to 99.
Your goal is to sink all of the AI's ships before it sinks yours.
Let's get started!
- step_id: "step_1"
title: "Choose AI Mode"
question: "Choose the AI mode: Random, Hunter, Super Human Hunter, or Hermes Reasoner?"
tokens_for_ai: |
If the user chooses Random, categorize as 'random_mode'.
If the user chooses Hunter, categorize as 'hunter_mode'.
If the user chooses Super Human Hunter, categorize as 'super_hunter_mode'.
If the user chooses Hermes Reasoner, categorize as 'hermes_reasoner_mode'.
feedback_tokens_for_ai: |
If the user chooses Random, say: "Random mode selected! The AI will make completely random moves."
If the user chooses Hunter, say: "Hunter mode selected! The AI will systematically hunt around hits."
If the user chooses Super Human Hunter, say: "Super Human Hunter mode selected! The AI will use advanced probability analysis."
If the user chooses Hermes Reasoner, say: "Hermes Reasoner mode selected! The AI will use probability analysis combined with reasoning to make strategic decisions."
processing_script: |
import random
def place_ships():
global random
# Define ship sizes and names
ships = {
"Carrier": 5,
"Battleship": 4,
"Cruiser": 3,
"Submarine": 3,
"Destroyer": 2
}
board = [-1] * 100
for ship, size in ships.items():
placed = False
while not placed:
orientation = random.choice(['horizontal', 'vertical'])
if orientation == 'horizontal':
row = random.randint(0, 9)
col = random.randint(0, 9 - size)
start = row * 10 + col
if all(board[start + i] == -1 for i in range(size)):
for i in range(size):
board[start + i] = ship
placed = True
else:
row = random.randint(0, 9 - size)
col = random.randint(0, 9)
start = row * 10 + col
if all(board[start + i * 10] == -1 for i in range(size)):
for i in range(size):
board[start + i * 10] = ship
placed = True
return board
user_board = place_ships()
ai_board = place_ships() # AI also gets randomly placed ships
script_result = {
"metadata": {
"user_board": user_board,
"ai_board": ai_board
}
}
buckets:
- random_mode
- hunter_mode
- super_hunter_mode
- hermes_reasoner_mode
transitions:
random_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Random Mode enabled for the AI."
metadata_add:
ai_mode: "random"
next_section_and_step: "section_1:step_2"
hunter_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Hunter Mode enabled for the AI."
metadata_add:
ai_mode: "hunter"
next_section_and_step: "section_1:step_2"
super_hunter_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Super Human Hunter Mode enabled for the AI."
metadata_add:
ai_mode: "super_hunter"
next_section_and_step: "section_1:step_2"
hermes_reasoner_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Hermes Reasoner Mode enabled for the AI. The AI will use probability analysis combined with reasoning to make strategic decisions."
metadata_add:
ai_mode: "hermes_reasoner"
next_section_and_step: "section_1:step_2"
- step_id: "step_2"
title: "Take a Shot"
question: "Choose a position to fire at (0-99)."
pre_script: |
# Check if moves match winning moves from previous turn
user_winning_move = metadata.get("user_winning_move")
ai_winning_move = metadata.get("ai_winning_move")
user_shot_input = metadata.get("user_response", "")
# print(f"PRE-SCRIPT DEBUG: user_shot_input = '{user_shot_input}', user_winning_move = {user_winning_move}, ai_winning_move = {ai_winning_move}")
ai_shot = metadata.get("ai_shot")
is_game_ending_move = False
# Check if user move wins
if user_shot_input and user_shot_input.isdigit():
user_move = int(user_shot_input)
if user_winning_move is not None and user_move == user_winning_move:
is_game_ending_move = True
# print(f"PRE-SCRIPT: User winning move detected! user_move={user_move} matches user_winning_move={user_winning_move}")
# Check if AI move wins (from previous turn)
if ai_shot is not None and ai_winning_move is not None and ai_shot == ai_winning_move:
is_game_ending_move = True
# print(f"PRE-SCRIPT: AI winning move detected! ai_shot={ai_shot} matches ai_winning_move={ai_winning_move}")
script_result = {
"metadata": {
"is_game_ending_move": is_game_ending_move
}
}
tokens_for_ai: |
1) If the user reply is *only* digits, and corresponds to a grid cell (099),
treat it as a valid move:
If the response matches the regex /^\d+$/ and 0 ≤ int(response) < 100, categorize as 'valid_move'.
2) Otherwise fall back to the usual buckets:
If the user wants to restart or play again, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
Otherwise, categorize as 'invalid_move'.
feedback_tokens_for_ai: |
You are a battleship narrator. Each prompt has its own specific role - follow the individual prompt instructions precisely.
feedback_prompts:
- name: "Shot Report"
tokens_for_ai: |
🎯 Report ONLY the hit/miss results for both shots this turn. DO NOT report ship sinking or game over.
Check metadata:
- user_shot: Player's target position
- user_hit_result: "hit" or "miss"
- ai_shot: AI's target position
- ai_hit_result: "hit" or "miss"
Format: "🎯 Your shot at position [user_shot]: [user_hit_result]! 🤖 Enemy shot at position [ai_shot]: [ai_hit_result]!"
metadata_filter:
- user_shot
- ai_shot
- user_hit_result
- ai_hit_result
- user_response
- name: "Ship Status"
tokens_for_ai: |
A ship has been destroyed! Generate a dramatic 2-3 sentence description.
Metadata tells you which ship(s) were sunk:
- user_sunk_ship_this_round: The ship YOU destroyed (your victory)
- ai_sunk_ship_this_round: The ship that was destroyed by the enemy (your loss)
Format:
- If user destroyed a ship: "💥 You've sunk their [ship]! [2-3 dramatic sentences imagining how this warship meets its doom]"
- If AI destroyed your ship: "🔥 Your [ship] has been destroyed! [2-3 dramatic sentences about its destruction]"
- If both: Include both messages
metadata_filter:
- user_sunk_ship_this_round
- ai_sunk_ship_this_round
skip_condition: "all_null"
- name: "Game Over"
tokens_for_ai: |
The naval battle has ended! Generate an epic conclusion.
Based on the metadata:
- If user_wins is true: "🎉 TOTAL VICTORY! You have destroyed all enemy ships! The seas belong to you, Admiral. Your tactical brilliance has secured complete naval supremacy."
- If ai_wins is true: "💀 DEFEAT! All your ships have been destroyed. Your fleet lies scattered across the ocean floor. The enemy's superior strategy has prevailed."
Make it dramatic and final - this is the end of the battle!
metadata_filter:
- game_over
- user_wins
- ai_wins
skip_condition: "all_false"
processing_script: |
import random
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import io
import base64
import requests
import json
# Define ship sizes
ship_sizes = {
"Carrier": 5,
"Battleship": 4,
"Cruiser": 3,
"Submarine": 3,
"Destroyer": 2
}
# Define colors for ships
ship_colors = {
"Carrier": "blue",
"Battleship": "green",
"Cruiser": "orange",
"Submarine": "purple",
"Destroyer": "pink"
}
# Retrieve the game state
user_board = metadata.get("user_board")
ai_board = metadata.get("ai_board")
# Normal processing code
user_shots = metadata.get("user_shots", [])
ai_shots = metadata.get("ai_shots", [])
user_hits = metadata.get("user_hits", [])
ai_hits = metadata.get("ai_hits", [])
game_over = metadata.get("game_over", False)
user_wins = False
ai_wins = False
user_hit_result = "miss"
ai_hit_result = "miss"
user_sunk_ships = metadata.get("user_sunk_ships", [])
ai_sunk_ships = metadata.get("ai_sunk_ships", [])
user_sunk_ship_this_round = None
ai_sunk_ship_this_round = None
# AI state variables
ai_mode = metadata.get("ai_mode", "random")
# Initialize probability matrix with realistic ship placement probabilities
if "probability_matrix" not in metadata:
probability_matrix = [[0] * 10 for _ in range(10)]
# Calculate how many ship placements use each cell
ship_lengths = [5, 4, 3, 3, 2]
for y in range(10):
for x in range(10):
count = 0
for ship_len in ship_lengths:
# Horizontal ships that would cover this cell
for start_x in range(max(0, x - ship_len + 1), min(x + 1, 10 - ship_len + 1)):
count += 1
# Vertical ships that would cover this cell
for start_y in range(max(0, y - ship_len + 1), min(y + 1, 10 - ship_len + 1)):
count += 1
probability_matrix[y][x] = count
# print("DEBUG: Initial probability matrix created")
# Debug print the initial grid
# print("DEBUG: Initial grid:")
# for row in probability_matrix:
# print(f" {' '.join(f'{x:2d}' for x in row)}")
else:
probability_matrix = metadata.get("probability_matrix")
# print("DEBUG: Using existing probability matrix")
hits = metadata.get("hits", [])
misses = metadata.get("misses", [])
sunk_ships = metadata.get("sunk_ships", [])
# Function to check if a ship is sunk
def check_sunk(board, hits, ship_name):
ship_positions = []
for i, ship in enumerate(board):
if ship == ship_name:
ship_positions.append(i)
for pos in ship_positions:
if pos not in hits:
return False
return True
# Function to draw a line across a sunken ship
def draw_line(ax, board, ship_name):
ship_positions = []
for i, ship in enumerate(board):
if ship == ship_name:
ship_positions.append(i)
if not ship_positions:
return
# Determine if the ship is horizontal or vertical
first_pos = ship_positions[0]
last_pos = ship_positions[-1]
if last_pos - first_pos < 10: # Horizontal
x_start, y_start = first_pos % 10 + 0.5, 9 - first_pos // 10 + 0.5
x_end, y_end = last_pos % 10 + 0.5, 9 - last_pos // 10 + 0.5
else: # Vertical
x_start, y_start = first_pos % 10 + 0.5, 9 - first_pos // 10 + 0.5
x_end, y_end = first_pos % 10 + 0.5, 9 - last_pos // 10 + 0.5
ax.plot([x_start, x_end], [y_start, y_end], color='red', linewidth=2)
# Function to update probability matrix
def update_probability(x, y, hit):
global probability_matrix, hits, misses, sunk_ships, ship_sizes
if hit:
hits.append((x, y))
probability_matrix[y][x] = 0 # Mark hit
# Increase probabilities for adjacent cells
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
nx, ny = x + dx, y + dy
if 0 <= nx < 10 and 0 <= ny < 10 and probability_matrix[ny][nx] > 0:
probability_matrix[ny][nx] += 5 # Increase probability significantly
else:
misses.append((x, y))
probability_matrix[y][x] = -1 # Mark miss
# Set probabilities to 1 for cells that can't fit any remaining ships
max_ship_size = max(size for ship, size in ship_sizes.items() if ship not in sunk_ships)
for y in range(10):
for x in range(10):
if probability_matrix[y][x] > 0 and not can_fit_ship(x, y, max_ship_size):
probability_matrix[y][x] = 1 # Minimum probability
# Function to check if a ship can fit
def can_fit_ship(x, y, ship_size):
# Check horizontal fit
if x + ship_size <= 10:
fit = True
for i in range(ship_size):
if probability_matrix[y][x+i] <= 0:
fit = False
break
if fit:
return True
# Check vertical fit
if y + ship_size <= 10:
fit = True
for i in range(ship_size):
if probability_matrix[y+i][x] <= 0:
fit = False
break
if fit:
return True
return False
# Function to generate Hermes reasoning
def hermes_reason_move(game_state, turn_number, top_candidates):
global ai_hits, ai_shots, ai_sunk_ships, probability_matrix
import os
import requests
import json
# Get Hermes endpoint from environment
hermes_endpoint = os.environ.get('MODEL_ENDPOINT_1', 'https://hermes.ai.unturf.com/v1')
hermes_api_key = os.environ.get('MODEL_API_KEY_1', '')
# Prepare game state summary
hits_summary = f"AI hits so far: {len(ai_hits)} positions hit"
misses_summary = f"AI misses so far: {len(ai_shots) - len(ai_hits)} positions missed"
sunk_ships_summary = f"Ships sunk: {len(ai_sunk_ships)} out of 5"
available_positions = [i for i in range(100) if i not in ai_shots]
top_six_candidates = top_candidates[0:6] if len(top_candidates) >= 6 else top_candidates
# Create reasoning prompt
prompt = (
f"You are an expert Battleship AI. Turn {turn_number}.\n\n"
f"CRITICAL: You MUST choose from these TOP probability positions: {top_six_candidates}\n\n"
f"Game Data:\n"
f"- {hits_summary}\n"
f"- {misses_summary}\n"
f"- {sunk_ships_summary}\n\n"
f"INSTRUCTIONS: Pick ONE number from {top_six_candidates} - these are the mathematically optimal targets.\n\n"
f"Format your response EXACTLY like this:\n\n"
f"ANALYSIS: [3 sentences explaining why you chose from the top probability positions]\n\n"
f"MOVE: [ONE number from this list: {top_six_candidates}]\n\n"
f"You MUST pick from {top_six_candidates} - do not pick any other number."
)
try:
headers = {
'Authorization': f'Bearer {hermes_api_key}',
'Content-Type': 'application/json'
}
data = {
'model': 'adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic',
'messages': [{'role': 'user', 'content': prompt}],
'max_tokens': 300,
'temperature': 0.5
}
response = requests.post(f'{hermes_endpoint}/chat/completions',
headers=headers, json=data, timeout=10)
# print(f"DEBUG: API Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
reasoning = result['choices'][0]['message']['content'].strip()
# print(f"DEBUG: Real API response: {reasoning}")
return reasoning
else:
# print(f"DEBUG: API failed with status {response.status_code}: {response.text[:200]}")
fallback_move = top_candidates[0] if top_candidates else random.choice([i for i in range(100) if i not in ai_shots])
return f"ANALYSIS: Turn {turn_number} suggests targeting high-probability zones based on mathematical analysis. The current hit pattern indicates potential ship orientations that guide strategic decisions. Focusing on adjacent unexplored cells maximizes discovery potential.\n\nMOVE: {fallback_move}"
except Exception as e:
# print(f"DEBUG: API exception: {str(e)}")
fallback_move = top_candidates[0] if top_candidates else random.choice([i for i in range(100) if i not in ai_shots])
return f"ANALYSIS: After {turn_number} turns, probability analysis guides optimal targeting strategies. Current data suggests focusing on clustered high-value positions for maximum efficiency. Strategic patience combined with mathematical precision will yield victory.\n\nMOVE: {fallback_move}"
# AI chooses a shot
def choose_ai_shot():
global can_fit_ship, update_probability, generate_hunt_targets, random_search, probability_matrix, ai_mode, ai_shots, random, user_board, ai_hits, ai_hit_result, hermes_reason_move, ship_sizes, ai_sunk_ships
if ai_mode == "hermes_reasoner":
# Use probability algorithm + Hermes reasoning
# Update probability matrix based on shots
remaining_ships = [ship for ship in ship_sizes.keys() if ship not in ai_sunk_ships]
remaining_ship_sizes = [ship_sizes[ship] for ship in remaining_ships]
# print(f"DEBUG: Remaining ships: {remaining_ships}")
# print(f"DEBUG: Total shots: {len(ai_shots)}, Hits: {len(ai_hits)}, Misses: {len(ai_shots) - len(ai_hits)}")
# Recalculate entire probability matrix
new_probability_matrix = [[0] * 10 for _ in range(10)]
for y in range(10):
for x in range(10):
pos = y * 10 + x
if pos in ai_shots:
new_probability_matrix[y][x] = 0 # Already shot
else:
# Count how many ship placements could use this cell
for ship_size in remaining_ship_sizes:
# Check horizontal placements
for start_x in range(max(0, x - ship_size + 1), min(x + 1, 10 - ship_size + 1)):
valid = True
includes_hit = False
for dx in range(ship_size):
check_pos = y * 10 + (start_x + dx)
if check_pos in ai_shots and check_pos not in ai_hits:
valid = False # Ship can't go through a miss
break
if check_pos in ai_hits:
includes_hit = True
if valid:
# Base probability for valid placement
new_probability_matrix[y][x] += 1
# Bonus if it includes a hit
if includes_hit:
new_probability_matrix[y][x] += 10
# Check vertical placements
for start_y in range(max(0, y - ship_size + 1), min(y + 1, 10 - ship_size + 1)):
valid = True
includes_hit = False
for dy in range(ship_size):
check_pos = (start_y + dy) * 10 + x
if check_pos in ai_shots and check_pos not in ai_hits:
valid = False # Ship can't go through a miss
break
if check_pos in ai_hits:
includes_hit = True
if valid:
# Base probability for valid placement
new_probability_matrix[y][x] += 1
# Bonus if it includes a hit
if includes_hit:
new_probability_matrix[y][x] += 10
# Replace the old matrix with the new one
probability_matrix = new_probability_matrix
# Boost probabilities around unsunk hits
for hit_pos in ai_hits:
hit_x, hit_y = hit_pos % 10, hit_pos // 10
# Check if this hit is part of a sunk ship
hit_is_sunk = False
for ship_name in ai_sunk_ships:
# This would need ship position tracking to work properly
pass # Skip for now, assume all hits need chasing
if not hit_is_sunk:
# Boost adjacent cells
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
adj_x, adj_y = hit_x + dx, hit_y + dy
if 0 <= adj_x < 10 and 0 <= adj_y < 10:
adj_pos = adj_y * 10 + adj_x
if adj_pos not in ai_shots:
# Only boost if not already boosted
if probability_matrix[adj_y][adj_x] < 50:
probability_matrix[adj_y][adj_x] = 50 # Set to fixed high value instead of adding
# Find top 6 highest probability positions
position_probs = []
for i in range(100):
if i not in ai_shots: # Only consider unshot positions
x, y = i % 10, i // 10
position_probs.append((probability_matrix[y][x], i))
# Sort by probability (descending) and take top positions
position_probs.sort(reverse=True)
candidates = [pos for prob, pos in position_probs[:20]] # Take top 20 for variety
max_prob = position_probs[0][0] if position_probs else 0
# Fallback if no candidates found
if not candidates:
candidates = [i for i in range(100) if i not in ai_shots]
# Debug: Log what we're working with
turn_number = len(ai_shots) + 1
# print(f"DEBUG: Turn {turn_number}, Max prob: {max_prob}")
# print("DEBUG: Probability grid:")
# for y in range(10):
# row = [f"{probability_matrix[y][x]:2d}" for x in range(10)]
# print(f" {' '.join(row)}")
# print(f"DEBUG: Top candidates: {candidates[:10]}")
reasoning_response = hermes_reason_move("battleship", turn_number, candidates)
# Analysis already logged in hermes_reason_move function
# Extract move from response - try multiple parsing methods
try:
if "MOVE:" in reasoning_response:
move_part = reasoning_response.split("MOVE:")[1].strip()
ai_shot = int(move_part.split()[0])
# print(f"DEBUG: Hermes Move: {ai_shot} (from 'MOVE: {move_part.split()[0]}')")
else:
# Fallback: extract any number from the response that's in candidates
import re
numbers = re.findall(r'\b(\d+)\b', reasoning_response)
valid_moves = [int(n) for n in numbers if int(n) in candidates and int(n) not in ai_shots]
if valid_moves:
ai_shot = valid_moves[0]
# print(f"DEBUG: Hermes Move (parsed): {ai_shot} from numbers {numbers}")
else:
raise Exception(f"ERROR: Hermes response had no valid moves! Response: {reasoning_response}, Candidates: {candidates}")
# Validate the shot is legal
if ai_shot in ai_shots or ai_shot < 0 or ai_shot > 99:
ai_shot = random.choice(candidates)
# print(f"DEBUG: Invalid shot, using fallback: {ai_shot}")
except Exception as e:
ai_shot = random.choice(candidates)
# print(f"DEBUG: Parse error: {e}, using fallback: {ai_shot}")
elif ai_mode == "super_hunter":
# Use probabilistic grid algorithm
max_prob = 0
candidates = []
for i in range(100):
if i not in ai_shots: # Exclude already-fired cells
x, y = i % 10, i // 10
if probability_matrix[y][x] > max_prob:
max_prob = probability_matrix[y][x]
candidates = [i]
elif probability_matrix[y][x] == max_prob:
candidates.append(i)
ai_shot = random.choice(candidates)
elif ai_mode == "hunter":
# Simple hunter mode logic
if hits:
# Target adjacent cells of the last hit
last_hit = hits[-1]
hunt_targets = generate_hunt_targets(last_hit, ai_shots)
if hunt_targets:
ai_shot = hunt_targets.pop(0)
else:
ai_shot = random_search()
else:
ai_shot = random_search()
else:
# Random mode
ai_shot = random_search()
# Update AI state after the shot
if user_board[ai_shot] != -1:
ai_hits.append(ai_shot)
ai_hit_result = "hit"
if ai_mode == "super_hunter" or ai_mode == "hermes_reasoner":
update_probability(ai_shot % 10, ai_shot // 10, True)
else:
ai_hit_result = "miss"
if ai_mode == "super_hunter" or ai_mode == "hermes_reasoner":
update_probability(ai_shot % 10, ai_shot // 10, False)
return ai_shot
# Function for random search
def random_search():
available_positions = []
for i in range(100):
if i not in ai_shots:
available_positions.append(i)
return random.choice(available_positions)
# Function to generate hunt targets around a hit
def generate_hunt_targets(hit_position, ai_shots):
potential_targets = []
row, col = divmod(hit_position, 10)
# Up
if row > 0:
potential_targets.append(hit_position - 10)
# Down
if row < 9:
potential_targets.append(hit_position + 10)
# Left
if col > 0:
potential_targets.append(hit_position - 1)
# Right
if col < 9:
potential_targets.append(hit_position + 1)
# Filter out already fired positions
filtered_targets = []
for pos in potential_targets:
if pos not in ai_shots:
filtered_targets.append(pos)
return filtered_targets
# Get the user's shot
try:
user_shot = int(metadata.get("user_shot"))
except (IndexError, ValueError) as e:
user_shot = -1
if game_over:
script_result = {
"metadata": {
"game_over": True,
"user_wins": user_wins,
"ai_wins": ai_wins
}
}
# print(f"DEBUG: Game over detected! User wins: {user_wins}, AI wins: {ai_wins}")
elif 0 <= user_shot < 100 and user_shot not in user_shots:
# The move is valid
user_shots.append(user_shot)
user_hit_result = "miss"
if ai_board[user_shot] != -1:
user_hits.append(user_shot)
user_hit_result = "hit"
# AI makes a move
ai_shot = choose_ai_shot()
ai_shots.append(ai_shot)
# Check if any AI ship is sunk
for ship_name in ship_sizes.keys():
if check_sunk(ai_board, user_hits, ship_name) and ship_name not in user_sunk_ships:
user_sunk_ships.append(ship_name)
user_sunk_ship_this_round = ship_name
# print(f"DEBUG: USER SUNK AI SHIP: {ship_name}")
# Check if any User ship is sunk
for ship_name in ship_sizes.keys():
if check_sunk(user_board, ai_hits, ship_name) and ship_name not in ai_sunk_ships:
ai_sunk_ships.append(ship_name)
ai_sunk_ship_this_round = ship_name
# print(f"DEBUG: AI SUNK USER SHIP: {ship_name}")
# Check if all AI ships are hit
all_ai_ships_hit = True
for pos in range(100):
if ai_board[pos] != -1 and pos not in user_hits:
all_ai_ships_hit = False
break
# Check if all User ships are hit
all_user_ships_hit = True
for pos in range(100):
if user_board[pos] != -1 and pos not in ai_hits:
all_user_ships_hit = False
break
if all_ai_ships_hit:
game_over = True
user_wins = True
ai_wins = False
# print(f"DEBUG: USER WINS! All AI ships destroyed. Game over.")
elif all_user_ships_hit:
game_over = True
user_wins = False
ai_wins = True
# print(f"DEBUG: AI WINS! All user ships destroyed. Game over.")
# Only track winning move if there's exactly 1 position left (for next turn's categorization)
user_winning_move = None
ai_winning_move = None
# Check which user move would win the game (AI ship positions left)
ai_ship_positions_left = [pos for pos in range(100) if ai_board[pos] != -1 and pos not in user_hits]
if len(ai_ship_positions_left) == 1:
user_winning_move = ai_ship_positions_left[0]
# print(f"DEBUG: User has exactly 1 winning move at position {user_winning_move}")
else:
# print(f"DEBUG: User has {len(ai_ship_positions_left)} AI positions left - no winning move")
pass
# Check which AI move would win the game (user ship positions left)
user_ship_positions_left = [pos for pos in range(100) if user_board[pos] != -1 and pos not in ai_hits]
if len(user_ship_positions_left) == 1:
ai_winning_move = user_ship_positions_left[0]
# print(f"DEBUG: AI has exactly 1 winning move at position {ai_winning_move}")
else:
# print(f"DEBUG: AI has {len(user_ship_positions_left)} user positions left - no winning move")
pass
# Plot the boards
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
fig.suptitle("Battleship", fontsize=16)
# User's view of AI's board
axs[0].set_xlim(0, 10)
axs[0].set_ylim(0, 10)
axs[0].set_xticks([])
axs[0].set_yticks([])
axs[0].grid(True)
axs[0].set_title("Your Shots", fontsize=12)
# Plot user shots on AI's board
for i in range(100):
x, y = i % 10, 9 - i // 10
if i in user_shots:
if i in user_hits:
axs[0].text(x + 0.5, y + 0.5, 'X', fontsize=12, ha='center', va='center', color='red')
else:
axs[0].text(x + 0.5, y + 0.5, 'O', fontsize=12, ha='center', va='center', color='black')
axs[0].text(x + 0.5, y + 0.5, str(i), fontsize=8, ha='center', va='center', color='gray')
# AI's view of User's board
axs[1].set_xlim(0, 10)
axs[1].set_ylim(0, 10)
axs[1].set_xticks([])
axs[1].set_yticks([])
axs[1].grid(True)
axs[1].set_title("Your Ships", fontsize=12)
# Plot user ships
for i, ship in enumerate(user_board):
x, y = i % 10, 9 - i // 10
if ship != -1:
axs[1].add_patch(plt.Rectangle((x, y), 1, 1, color=ship_colors[ship], alpha=0.5))
# Plot AI shots on User's board
for i in range(100):
x, y = i % 10, 9 - i // 10
if i in ai_shots:
if i in ai_hits:
axs[1].text(x + 0.5, y + 0.5, 'X', fontsize=12, ha='center', va='center', color='red')
else:
axs[1].text(x + 0.5, y + 0.5, 'O', fontsize=12, ha='center', va='center', color='black')
axs[1].text(x + 0.5, y + 0.5, str(i), fontsize=8, ha='center', va='center', color='gray')
# Draw lines across sunk ships
for ship_name in user_sunk_ships:
draw_line(axs[0], ai_board, ship_name)
for ship_name in ai_sunk_ships:
draw_line(axs[1], user_board, ship_name)
# Add legend
handles = []
for color in ship_colors.values():
handles.append(plt.Rectangle((0, 0), 1, 1, color=color, alpha=0.5))
axs[1].legend(handles, ship_colors.keys(), loc='upper right', fontsize=8)
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
plt.close(fig)
buf.seek(0)
plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')
# gpt-4: If "plot_image" is in the result, set it as the background image
# print(f"DEBUG: Setting metadata for feedback - user_sunk_ship_this_round: {user_sunk_ship_this_round}, ai_sunk_ship_this_round: {ai_sunk_ship_this_round}")
script_result = {
"plot_image": plot_image,
"set_background": True,
"metadata": {
"user_board": user_board,
"ai_board": ai_board,
"user_shot": user_shot,
"ai_shot": ai_shot,
"user_shots": user_shots,
"ai_shots": ai_shots,
"user_hits": user_hits,
"ai_hits": ai_hits,
"game_over": game_over,
"user_wins": user_wins,
"ai_wins": ai_wins,
"user_hit_result": user_hit_result,
"ai_hit_result": ai_hit_result,
"user_sunk_ships": user_sunk_ships,
"ai_sunk_ships": ai_sunk_ships,
"user_sunk_ship_this_round": user_sunk_ship_this_round,
"ai_sunk_ship_this_round": ai_sunk_ship_this_round,
"ai_mode": ai_mode,
"probability_matrix": probability_matrix,
"hits": hits,
"misses": misses,
"sunk_ships": sunk_ships,
"user_winning_move": user_winning_move,
"ai_winning_move": ai_winning_move
}
}
# Check if this was a winning move and override transition
if game_over:
script_result["next_section_and_step"] = "section_1:step_3"
# print(f"POST-SCRIPT: Game over detected, overriding transition to step_3")
else:
script_result = {
"error": f"Invalid shot: {metadata.get('user_shot')}",
"metadata": {}
}
buckets:
- valid_move
- invalid_move
- exit
- restart
transitions:
valid_move:
run_processing_script: True
ai_feedback:
tokens_for_ai: |
The user shot seems valid.
metadata_tmp_add:
user_shot: "the-users-response"
next_section_and_step: "section_1:step_2"
invalid_move:
content_blocks:
- "That move is invalid. Please choose a position between 0 and 99."
metadata_tmp_add:
user_shot: "the-users-response"
next_section_and_step: "section_1:step_2"
exit:
next_section_and_step: "section_1:step_4"
restart:
content_blocks:
- "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
- step_id: "step_3"
title: "Game Over"
question: "Would you like to restart and play again, or would you prefer to exit?"
tokens_for_ai: |
If the user wants to restart or play again, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
buckets:
- restart
- exit
transitions:
restart:
content_blocks:
- "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
exit:
content_blocks:
- "Thank you for playing Battleship! 🎉"
- "Feel free to come back anytime for another game."
next_section_and_step: "section_1:step_4"
- step_id: "step_4"
title: "Goodbye"
content_blocks:
- "Thanks for playing! Hope you enjoyed the battle at sea."

View file

@ -0,0 +1,892 @@
default_max_attempts_per_step: 9
tokens_for_ai_rubric: |
based on the game without knowing where each ship was, score the process each player used to target ships.
be sure to look for moves or strategies in the game play that where _not_ smart given the obvious information uncovered.
use chain-of-thought to reason about the progression of the game and the winner.
first summarize the game, we don't need the turn by turn plays.
the game was battleship. the moves were done 1 by 1.
the grid is 0-99.
did any player blunder as the information was learned?
There was a user and an AI playing.
Depending on the game mode the player chooses they are going up against a different algo,
* random
* always plays randomly
* hunter
* keeps track of hits and targets every cell around it no matter what, randomly, else random
* super human hunter
* keeps track of hits and uses a probability grid normalized to 100 and always picks the max or random of any 100.
* hermes reasoner
* uses the probability algorithm paired with hermes to reason for 3 sentences about what the next 0-99 move should be given the current game state and turn number
Did any player miss sinking a ship that was found? was it due to end game or a blunder?
Do not mix up ships, keep careful track of the order they were found and sunk.
sections:
- section_id: "section_1"
title: "Battleship"
steps:
- step_id: "step_0"
title: "Introduction"
content_blocks:
- |
Welcome to Battleship! 🚢
In this game, both you and the AI have a fleet of ships placed randomly on a 10x10 grid.
The grid positions are numbered 0 to 99.
Your goal is to sink all of the AI's ships before it sinks yours.
Let's get started!
- step_id: "step_1"
title: "Choose AI Mode"
question: "Choose the AI mode: Random, Hunter, Super Human Hunter, or Hermes Reasoner?"
tokens_for_ai: |
If the user chooses Random, categorize as 'random_mode'.
If the user chooses Hunter, categorize as 'hunter_mode'.
If the user chooses Super Human Hunter, categorize as 'super_hunter_mode'.
If the user chooses Hermes Reasoner, categorize as 'hermes_reasoner_mode'.
feedback_tokens_for_ai: |
If the user chooses Random, say: "Random mode selected! The AI will make completely random moves."
If the user chooses Hunter, say: "Hunter mode selected! The AI will systematically hunt around hits."
If the user chooses Super Human Hunter, say: "Super Human Hunter mode selected! The AI will use advanced probability analysis."
If the user chooses Hermes Reasoner, say: "Hermes Reasoner mode selected! The AI will use probability analysis combined with reasoning to make strategic decisions."
processing_script: |
import random
def place_ships():
global random
# Define ship sizes and names
ships = {
"Testship": 1
}
board = [-1] * 100
# Place testship at position 21 for easy testing
board[21] = "Testship"
return board
user_board = place_ships()
ai_board = place_ships() # AI also gets randomly placed ships
script_result = {
"metadata": {
"user_board": user_board,
"ai_board": ai_board
}
}
buckets:
- random_mode
- hunter_mode
- super_hunter_mode
- hermes_reasoner_mode
transitions:
random_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Random Mode enabled for the AI."
metadata_add:
ai_mode: "random"
next_section_and_step: "section_1:step_2"
hunter_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Hunter Mode enabled for the AI."
metadata_add:
ai_mode: "hunter"
next_section_and_step: "section_1:step_2"
super_hunter_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Super Human Hunter Mode enabled for the AI."
metadata_add:
ai_mode: "super_hunter"
next_section_and_step: "section_1:step_2"
hermes_reasoner_mode:
run_processing_script: True
ai_feedback:
tokens_for_ai: "Hermes Reasoner Mode enabled for the AI. The AI will use probability analysis combined with reasoning to make strategic decisions."
metadata_add:
ai_mode: "hermes_reasoner"
next_section_and_step: "section_1:step_2"
- step_id: "step_2"
title: "Take a Shot"
question: "Choose a position to fire at (0-99)."
pre_script: |
# Check if moves match winning moves from previous turn
user_winning_move = metadata.get("user_winning_move")
ai_winning_move = metadata.get("ai_winning_move")
user_shot_input = metadata.get("user_response", "")
print(f"PRE-SCRIPT DEBUG: user_shot_input = '{user_shot_input}', user_winning_move = {user_winning_move}, ai_winning_move = {ai_winning_move}")
ai_shot = metadata.get("ai_shot")
is_game_ending_move = False
# Check if user move wins
if user_shot_input and user_shot_input.isdigit():
user_move = int(user_shot_input)
if user_winning_move is not None and user_move == user_winning_move:
is_game_ending_move = True
print(f"PRE-SCRIPT: User winning move detected! user_move={user_move} matches user_winning_move={user_winning_move}")
# Check if AI move wins (from previous turn)
if ai_shot is not None and ai_winning_move is not None and ai_shot == ai_winning_move:
is_game_ending_move = True
print(f"PRE-SCRIPT: AI winning move detected! ai_shot={ai_shot} matches ai_winning_move={ai_winning_move}")
script_result = {
"metadata": {
"is_game_ending_move": is_game_ending_move
}
}
tokens_for_ai: |
1) If the user reply is *only* digits, and corresponds to a grid cell (099),
treat it as a valid move:
If the response matches the regex /^\d+$/ and 0 ≤ int(response) < 100, categorize as 'valid_move'.
2) Otherwise fall back to the usual buckets:
If the user wants to restart or play again, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
Otherwise, categorize as 'invalid_move'.
feedback_tokens_for_ai: |
You are a battleship narrator. Each prompt has its own specific role - follow the individual prompt instructions precisely.
feedback_prompts:
- name: "Shot Report"
tokens_for_ai: |
🎯 Report ONLY the hit/miss results for both shots this turn. DO NOT report ship sinking or game over.
Check metadata:
- user_shot: Player's target position
- user_hit_result: "hit" or "miss"
- ai_shot: AI's target position
- ai_hit_result: "hit" or "miss"
Format: "🎯 Your shot at position [user_shot]: [user_hit_result]! 🤖 Enemy shot at position [ai_shot]: [ai_hit_result]!"
metadata_filter:
- user_shot
- ai_shot
- user_hit_result
- ai_hit_result
- user_response
- name: "Ship Status"
tokens_for_ai: |
A ship has been destroyed! Generate a dramatic 2-3 sentence description.
Metadata tells you which ship(s) were sunk:
- user_sunk_ship_this_round: The ship YOU destroyed (your victory)
- ai_sunk_ship_this_round: The ship that was destroyed by the enemy (your loss)
Format:
- If user destroyed a ship: "💥 You've sunk their [ship]! [2-3 dramatic sentences imagining how this warship meets its doom]"
- If AI destroyed your ship: "🔥 Your [ship] has been destroyed! [2-3 dramatic sentences about its destruction]"
- If both: Include both messages
metadata_filter:
- user_sunk_ship_this_round
- ai_sunk_ship_this_round
skip_condition: "all_null"
- name: "Game Over"
tokens_for_ai: |
The naval battle has ended! Generate an epic conclusion.
Based on the metadata:
- If user_wins is true: "🎉 TOTAL VICTORY! You have destroyed all enemy ships! The seas belong to you, Admiral. Your tactical brilliance has secured complete naval supremacy."
- If ai_wins is true: "💀 DEFEAT! All your ships have been destroyed. Your fleet lies scattered across the ocean floor. The enemy's superior strategy has prevailed."
Make it dramatic and final - this is the end of the battle!
metadata_filter:
- game_over
- user_wins
- ai_wins
skip_condition: "all_false"
processing_script: |
import random
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import io
import base64
import requests
import json
# Define ship sizes
ship_sizes = {
"Testship": 1
}
# Define colors for ships
ship_colors = {
"Testship": "red"
}
# Retrieve the game state
user_board = metadata.get("user_board")
ai_board = metadata.get("ai_board")
# Normal processing code
user_shots = metadata.get("user_shots", [])
ai_shots = metadata.get("ai_shots", [])
user_hits = metadata.get("user_hits", [])
ai_hits = metadata.get("ai_hits", [])
game_over = metadata.get("game_over", False)
user_wins = False
ai_wins = False
user_hit_result = "miss"
ai_hit_result = "miss"
user_sunk_ships = metadata.get("user_sunk_ships", [])
ai_sunk_ships = metadata.get("ai_sunk_ships", [])
user_sunk_ship_this_round = None
ai_sunk_ship_this_round = None
# AI state variables
ai_mode = metadata.get("ai_mode", "random")
# Initialize probability matrix with realistic ship placement probabilities
if "probability_matrix" not in metadata:
probability_matrix = [[0] * 10 for _ in range(10)]
# Calculate how many ship placements use each cell
ship_lengths = [5, 4, 3, 3, 2]
for y in range(10):
for x in range(10):
count = 0
for ship_len in ship_lengths:
# Horizontal ships that would cover this cell
for start_x in range(max(0, x - ship_len + 1), min(x + 1, 10 - ship_len + 1)):
count += 1
# Vertical ships that would cover this cell
for start_y in range(max(0, y - ship_len + 1), min(y + 1, 10 - ship_len + 1)):
count += 1
probability_matrix[y][x] = count
print("DEBUG: Initial probability matrix created")
# Debug print the initial grid
print("DEBUG: Initial grid:")
for row in probability_matrix:
print(f" {' '.join(f'{x:2d}' for x in row)}")
else:
probability_matrix = metadata.get("probability_matrix")
print("DEBUG: Using existing probability matrix")
hits = metadata.get("hits", [])
misses = metadata.get("misses", [])
sunk_ships = metadata.get("sunk_ships", [])
# Function to check if a ship is sunk
def check_sunk(board, hits, ship_name):
ship_positions = []
for i, ship in enumerate(board):
if ship == ship_name:
ship_positions.append(i)
for pos in ship_positions:
if pos not in hits:
return False
return True
# Function to draw a line across a sunken ship
def draw_line(ax, board, ship_name):
ship_positions = []
for i, ship in enumerate(board):
if ship == ship_name:
ship_positions.append(i)
if not ship_positions:
return
# Determine if the ship is horizontal or vertical
first_pos = ship_positions[0]
last_pos = ship_positions[-1]
if last_pos - first_pos < 10: # Horizontal
x_start, y_start = first_pos % 10 + 0.5, 9 - first_pos // 10 + 0.5
x_end, y_end = last_pos % 10 + 0.5, 9 - last_pos // 10 + 0.5
else: # Vertical
x_start, y_start = first_pos % 10 + 0.5, 9 - first_pos // 10 + 0.5
x_end, y_end = first_pos % 10 + 0.5, 9 - last_pos // 10 + 0.5
ax.plot([x_start, x_end], [y_start, y_end], color='red', linewidth=2)
# Function to update probability matrix
def update_probability(x, y, hit):
global probability_matrix, hits, misses, sunk_ships, ship_sizes
if hit:
hits.append((x, y))
probability_matrix[y][x] = 0 # Mark hit
# Increase probabilities for adjacent cells
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
nx, ny = x + dx, y + dy
if 0 <= nx < 10 and 0 <= ny < 10 and probability_matrix[ny][nx] > 0:
probability_matrix[ny][nx] += 5 # Increase probability significantly
else:
misses.append((x, y))
probability_matrix[y][x] = -1 # Mark miss
# Set probabilities to 1 for cells that can't fit any remaining ships
max_ship_size = max(size for ship, size in ship_sizes.items() if ship not in sunk_ships)
for y in range(10):
for x in range(10):
if probability_matrix[y][x] > 0 and not can_fit_ship(x, y, max_ship_size):
probability_matrix[y][x] = 1 # Minimum probability
# Function to check if a ship can fit
def can_fit_ship(x, y, ship_size):
# Check horizontal fit
if x + ship_size <= 10:
fit = True
for i in range(ship_size):
if probability_matrix[y][x+i] <= 0:
fit = False
break
if fit:
return True
# Check vertical fit
if y + ship_size <= 10:
fit = True
for i in range(ship_size):
if probability_matrix[y+i][x] <= 0:
fit = False
break
if fit:
return True
return False
# Function to generate Hermes reasoning
def hermes_reason_move(game_state, turn_number, top_candidates):
global ai_hits, ai_shots, ai_sunk_ships, probability_matrix
import os
import requests
import json
# Get Hermes endpoint from environment
hermes_endpoint = os.environ.get('MODEL_ENDPOINT_1', 'https://hermes.ai.unturf.com/v1')
hermes_api_key = os.environ.get('MODEL_API_KEY_1', '')
# Prepare game state summary
hits_summary = f"AI hits so far: {len(ai_hits)} positions hit"
misses_summary = f"AI misses so far: {len(ai_shots) - len(ai_hits)} positions missed"
sunk_ships_summary = f"Ships sunk: {len(ai_sunk_ships)} out of 5"
available_positions = [i for i in range(100) if i not in ai_shots]
top_six_candidates = top_candidates[0:6] if len(top_candidates) >= 6 else top_candidates
# Create reasoning prompt
prompt = (
f"You are an expert Battleship AI. Turn {turn_number}.\n\n"
f"CRITICAL: You MUST choose from these TOP probability positions: {top_six_candidates}\n\n"
f"Game Data:\n"
f"- {hits_summary}\n"
f"- {misses_summary}\n"
f"- {sunk_ships_summary}\n\n"
f"INSTRUCTIONS: Pick ONE number from {top_six_candidates} - these are the mathematically optimal targets.\n\n"
f"Format your response EXACTLY like this:\n\n"
f"ANALYSIS: [3 sentences explaining why you chose from the top probability positions]\n\n"
f"MOVE: [ONE number from this list: {top_six_candidates}]\n\n"
f"You MUST pick from {top_six_candidates} - do not pick any other number."
)
try:
headers = {
'Authorization': f'Bearer {hermes_api_key}',
'Content-Type': 'application/json'
}
data = {
'model': 'adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic',
'messages': [{'role': 'user', 'content': prompt}],
'max_tokens': 300,
'temperature': 0.5
}
response = requests.post(f'{hermes_endpoint}/chat/completions',
headers=headers, json=data, timeout=10)
print(f"DEBUG: API Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
reasoning = result['choices'][0]['message']['content'].strip()
print(f"DEBUG: Real API response: {reasoning}")
return reasoning
else:
print(f"DEBUG: API failed with status {response.status_code}: {response.text[:200]}")
fallback_move = top_candidates[0] if top_candidates else random.choice([i for i in range(100) if i not in ai_shots])
return f"ANALYSIS: Turn {turn_number} suggests targeting high-probability zones based on mathematical analysis. The current hit pattern indicates potential ship orientations that guide strategic decisions. Focusing on adjacent unexplored cells maximizes discovery potential.\n\nMOVE: {fallback_move}"
except Exception as e:
print(f"DEBUG: API exception: {str(e)}")
fallback_move = top_candidates[0] if top_candidates else random.choice([i for i in range(100) if i not in ai_shots])
return f"ANALYSIS: After {turn_number} turns, probability analysis guides optimal targeting strategies. Current data suggests focusing on clustered high-value positions for maximum efficiency. Strategic patience combined with mathematical precision will yield victory.\n\nMOVE: {fallback_move}"
# AI chooses a shot
def choose_ai_shot():
global can_fit_ship, update_probability, generate_hunt_targets, random_search, probability_matrix, ai_mode, ai_shots, random, user_board, ai_hits, ai_hit_result, hermes_reason_move, ship_sizes, ai_sunk_ships
if ai_mode == "hermes_reasoner":
# Use probability algorithm + Hermes reasoning
# Update probability matrix based on shots
remaining_ships = [ship for ship in ship_sizes.keys() if ship not in ai_sunk_ships]
remaining_ship_sizes = [ship_sizes[ship] for ship in remaining_ships]
print(f"DEBUG: Remaining ships: {remaining_ships}")
print(f"DEBUG: Total shots: {len(ai_shots)}, Hits: {len(ai_hits)}, Misses: {len(ai_shots) - len(ai_hits)}")
# Recalculate entire probability matrix
new_probability_matrix = [[0] * 10 for _ in range(10)]
for y in range(10):
for x in range(10):
pos = y * 10 + x
if pos in ai_shots:
new_probability_matrix[y][x] = 0 # Already shot
else:
# Count how many ship placements could use this cell
for ship_size in remaining_ship_sizes:
# Check horizontal placements
for start_x in range(max(0, x - ship_size + 1), min(x + 1, 10 - ship_size + 1)):
valid = True
includes_hit = False
for dx in range(ship_size):
check_pos = y * 10 + (start_x + dx)
if check_pos in ai_shots and check_pos not in ai_hits:
valid = False # Ship can't go through a miss
break
if check_pos in ai_hits:
includes_hit = True
if valid:
# Base probability for valid placement
new_probability_matrix[y][x] += 1
# Bonus if it includes a hit
if includes_hit:
new_probability_matrix[y][x] += 10
# Check vertical placements
for start_y in range(max(0, y - ship_size + 1), min(y + 1, 10 - ship_size + 1)):
valid = True
includes_hit = False
for dy in range(ship_size):
check_pos = (start_y + dy) * 10 + x
if check_pos in ai_shots and check_pos not in ai_hits:
valid = False # Ship can't go through a miss
break
if check_pos in ai_hits:
includes_hit = True
if valid:
# Base probability for valid placement
new_probability_matrix[y][x] += 1
# Bonus if it includes a hit
if includes_hit:
new_probability_matrix[y][x] += 10
# Replace the old matrix with the new one
probability_matrix = new_probability_matrix
# Boost probabilities around unsunk hits
for hit_pos in ai_hits:
hit_x, hit_y = hit_pos % 10, hit_pos // 10
# Check if this hit is part of a sunk ship
hit_is_sunk = False
for ship_name in ai_sunk_ships:
# This would need ship position tracking to work properly
pass # Skip for now, assume all hits need chasing
if not hit_is_sunk:
# Boost adjacent cells
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
adj_x, adj_y = hit_x + dx, hit_y + dy
if 0 <= adj_x < 10 and 0 <= adj_y < 10:
adj_pos = adj_y * 10 + adj_x
if adj_pos not in ai_shots:
# Only boost if not already boosted
if probability_matrix[adj_y][adj_x] < 50:
probability_matrix[adj_y][adj_x] = 50 # Set to fixed high value instead of adding
# Find top 6 highest probability positions
position_probs = []
for i in range(100):
if i not in ai_shots: # Only consider unshot positions
x, y = i % 10, i // 10
position_probs.append((probability_matrix[y][x], i))
# Sort by probability (descending) and take top positions
position_probs.sort(reverse=True)
candidates = [pos for prob, pos in position_probs[:20]] # Take top 20 for variety
max_prob = position_probs[0][0] if position_probs else 0
# Fallback if no candidates found
if not candidates:
candidates = [i for i in range(100) if i not in ai_shots]
# Debug: Log what we're working with
turn_number = len(ai_shots) + 1
print(f"DEBUG: Turn {turn_number}, Max prob: {max_prob}")
print("DEBUG: Probability grid:")
for y in range(10):
row = [f"{probability_matrix[y][x]:2d}" for x in range(10)]
print(f" {' '.join(row)}")
print(f"DEBUG: Top candidates: {candidates[:10]}")
reasoning_response = hermes_reason_move("battleship", turn_number, candidates)
# Analysis already logged in hermes_reason_move function
# Extract move from response - try multiple parsing methods
try:
if "MOVE:" in reasoning_response:
move_part = reasoning_response.split("MOVE:")[1].strip()
ai_shot = int(move_part.split()[0])
print(f"DEBUG: Hermes Move: {ai_shot} (from 'MOVE: {move_part.split()[0]}')")
else:
# Fallback: extract any number from the response that's in candidates
import re
numbers = re.findall(r'\b(\d+)\b', reasoning_response)
valid_moves = [int(n) for n in numbers if int(n) in candidates and int(n) not in ai_shots]
if valid_moves:
ai_shot = valid_moves[0]
print(f"DEBUG: Hermes Move (parsed): {ai_shot} from numbers {numbers}")
else:
raise Exception(f"ERROR: Hermes response had no valid moves! Response: {reasoning_response}, Candidates: {candidates}")
# Validate the shot is legal
if ai_shot in ai_shots or ai_shot < 0 or ai_shot > 99:
ai_shot = random.choice(candidates)
print(f"DEBUG: Invalid shot, using fallback: {ai_shot}")
except Exception as e:
ai_shot = random.choice(candidates)
print(f"DEBUG: Parse error: {e}, using fallback: {ai_shot}")
elif ai_mode == "super_hunter":
# Use probabilistic grid algorithm
max_prob = 0
candidates = []
for i in range(100):
if i not in ai_shots: # Exclude already-fired cells
x, y = i % 10, i // 10
if probability_matrix[y][x] > max_prob:
max_prob = probability_matrix[y][x]
candidates = [i]
elif probability_matrix[y][x] == max_prob:
candidates.append(i)
ai_shot = random.choice(candidates)
elif ai_mode == "hunter":
# Simple hunter mode logic
if hits:
# Target adjacent cells of the last hit
last_hit = hits[-1]
hunt_targets = generate_hunt_targets(last_hit, ai_shots)
if hunt_targets:
ai_shot = hunt_targets.pop(0)
else:
ai_shot = random_search()
else:
ai_shot = random_search()
else:
# Random mode
ai_shot = random_search()
# Update AI state after the shot
if user_board[ai_shot] != -1:
ai_hits.append(ai_shot)
ai_hit_result = "hit"
if ai_mode == "super_hunter" or ai_mode == "hermes_reasoner":
update_probability(ai_shot % 10, ai_shot // 10, True)
else:
ai_hit_result = "miss"
if ai_mode == "super_hunter" or ai_mode == "hermes_reasoner":
update_probability(ai_shot % 10, ai_shot // 10, False)
return ai_shot
# Function for random search
def random_search():
available_positions = []
for i in range(100):
if i not in ai_shots:
available_positions.append(i)
return random.choice(available_positions)
# Function to generate hunt targets around a hit
def generate_hunt_targets(hit_position, ai_shots):
potential_targets = []
row, col = divmod(hit_position, 10)
# Up
if row > 0:
potential_targets.append(hit_position - 10)
# Down
if row < 9:
potential_targets.append(hit_position + 10)
# Left
if col > 0:
potential_targets.append(hit_position - 1)
# Right
if col < 9:
potential_targets.append(hit_position + 1)
# Filter out already fired positions
filtered_targets = []
for pos in potential_targets:
if pos not in ai_shots:
filtered_targets.append(pos)
return filtered_targets
# Get the user's shot
try:
user_shot = int(metadata.get("user_shot"))
except (IndexError, ValueError) as e:
user_shot = -1
if game_over:
script_result = {
"metadata": {
"game_over": True,
"user_wins": user_wins,
"ai_wins": ai_wins
}
}
print(f"DEBUG: Game over detected! User wins: {user_wins}, AI wins: {ai_wins}")
elif 0 <= user_shot < 100 and user_shot not in user_shots:
# The move is valid
user_shots.append(user_shot)
user_hit_result = "miss"
if ai_board[user_shot] != -1:
user_hits.append(user_shot)
user_hit_result = "hit"
# AI makes a move
ai_shot = choose_ai_shot()
ai_shots.append(ai_shot)
# Check if any AI ship is sunk
for ship_name in ship_sizes.keys():
if check_sunk(ai_board, user_hits, ship_name) and ship_name not in user_sunk_ships:
user_sunk_ships.append(ship_name)
user_sunk_ship_this_round = ship_name
print(f"DEBUG: USER SUNK AI SHIP: {ship_name}")
# Check if any User ship is sunk
for ship_name in ship_sizes.keys():
if check_sunk(user_board, ai_hits, ship_name) and ship_name not in ai_sunk_ships:
ai_sunk_ships.append(ship_name)
ai_sunk_ship_this_round = ship_name
print(f"DEBUG: AI SUNK USER SHIP: {ship_name}")
# Check if all AI ships are hit
all_ai_ships_hit = True
for pos in range(100):
if ai_board[pos] != -1 and pos not in user_hits:
all_ai_ships_hit = False
break
# Check if all User ships are hit
all_user_ships_hit = True
for pos in range(100):
if user_board[pos] != -1 and pos not in ai_hits:
all_user_ships_hit = False
break
if all_ai_ships_hit:
game_over = True
user_wins = True
ai_wins = False
print(f"DEBUG: USER WINS! All AI ships destroyed. Game over.")
elif all_user_ships_hit:
game_over = True
user_wins = False
ai_wins = True
print(f"DEBUG: AI WINS! All user ships destroyed. Game over.")
# Only track winning move if there's exactly 1 position left (for next turn's categorization)
user_winning_move = None
ai_winning_move = None
# Check which user move would win the game (AI ship positions left)
ai_ship_positions_left = [pos for pos in range(100) if ai_board[pos] != -1 and pos not in user_hits]
if len(ai_ship_positions_left) == 1:
user_winning_move = ai_ship_positions_left[0]
print(f"DEBUG: User has exactly 1 winning move at position {user_winning_move}")
else:
print(f"DEBUG: User has {len(ai_ship_positions_left)} AI positions left - no winning move")
# Check which AI move would win the game (user ship positions left)
user_ship_positions_left = [pos for pos in range(100) if user_board[pos] != -1 and pos not in ai_hits]
if len(user_ship_positions_left) == 1:
ai_winning_move = user_ship_positions_left[0]
print(f"DEBUG: AI has exactly 1 winning move at position {ai_winning_move}")
else:
print(f"DEBUG: AI has {len(user_ship_positions_left)} user positions left - no winning move")
# Plot the boards
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
fig.suptitle("Battleship", fontsize=16)
# User's view of AI's board
axs[0].set_xlim(0, 10)
axs[0].set_ylim(0, 10)
axs[0].set_xticks([])
axs[0].set_yticks([])
axs[0].grid(True)
axs[0].set_title("Your Shots", fontsize=12)
# Plot user shots on AI's board
for i in range(100):
x, y = i % 10, 9 - i // 10
if i in user_shots:
if i in user_hits:
axs[0].text(x + 0.5, y + 0.5, 'X', fontsize=12, ha='center', va='center', color='red')
else:
axs[0].text(x + 0.5, y + 0.5, 'O', fontsize=12, ha='center', va='center', color='black')
axs[0].text(x + 0.5, y + 0.5, str(i), fontsize=8, ha='center', va='center', color='gray')
# AI's view of User's board
axs[1].set_xlim(0, 10)
axs[1].set_ylim(0, 10)
axs[1].set_xticks([])
axs[1].set_yticks([])
axs[1].grid(True)
axs[1].set_title("Your Ships", fontsize=12)
# Plot user ships
for i, ship in enumerate(user_board):
x, y = i % 10, 9 - i // 10
if ship != -1:
axs[1].add_patch(plt.Rectangle((x, y), 1, 1, color=ship_colors[ship], alpha=0.5))
# Plot AI shots on User's board
for i in range(100):
x, y = i % 10, 9 - i // 10
if i in ai_shots:
if i in ai_hits:
axs[1].text(x + 0.5, y + 0.5, 'X', fontsize=12, ha='center', va='center', color='red')
else:
axs[1].text(x + 0.5, y + 0.5, 'O', fontsize=12, ha='center', va='center', color='black')
axs[1].text(x + 0.5, y + 0.5, str(i), fontsize=8, ha='center', va='center', color='gray')
# Draw lines across sunk ships
for ship_name in user_sunk_ships:
draw_line(axs[0], ai_board, ship_name)
for ship_name in ai_sunk_ships:
draw_line(axs[1], user_board, ship_name)
# Add legend
handles = []
for color in ship_colors.values():
handles.append(plt.Rectangle((0, 0), 1, 1, color=color, alpha=0.5))
axs[1].legend(handles, ship_colors.keys(), loc='upper right', fontsize=8)
buf = io.BytesIO()
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1)
plt.close(fig)
buf.seek(0)
plot_image = base64.b64encode(buf.getvalue()).decode('utf-8')
# gpt-4: If "plot_image" is in the result, set it as the background image
print(f"DEBUG: Setting metadata for feedback - user_sunk_ship_this_round: {user_sunk_ship_this_round}, ai_sunk_ship_this_round: {ai_sunk_ship_this_round}")
script_result = {
"plot_image": plot_image,
"set_background": True,
"metadata": {
"user_board": user_board,
"ai_board": ai_board,
"user_shot": user_shot,
"ai_shot": ai_shot,
"user_shots": user_shots,
"ai_shots": ai_shots,
"user_hits": user_hits,
"ai_hits": ai_hits,
"game_over": game_over,
"user_wins": user_wins,
"ai_wins": ai_wins,
"user_hit_result": user_hit_result,
"ai_hit_result": ai_hit_result,
"user_sunk_ships": user_sunk_ships,
"ai_sunk_ships": ai_sunk_ships,
"user_sunk_ship_this_round": user_sunk_ship_this_round,
"ai_sunk_ship_this_round": ai_sunk_ship_this_round,
"ai_mode": ai_mode,
"probability_matrix": probability_matrix,
"hits": hits,
"misses": misses,
"sunk_ships": sunk_ships,
"user_winning_move": user_winning_move,
"ai_winning_move": ai_winning_move
}
}
# Check if this was a winning move and override transition
if game_over:
script_result["next_section_and_step"] = "section_1:step_3"
print(f"POST-SCRIPT: Game over detected, overriding transition to step_3")
else:
script_result = {
"error": f"Invalid shot: {metadata.get('user_shot')}",
"metadata": {}
}
buckets:
- valid_move
- invalid_move
- exit
- restart
transitions:
valid_move:
run_processing_script: True
ai_feedback:
tokens_for_ai: |
The user shot seems valid.
metadata_tmp_add:
user_shot: "the-users-response"
next_section_and_step: "section_1:step_2"
invalid_move:
content_blocks:
- "That move is invalid. Please choose a position between 0 and 99."
metadata_tmp_add:
user_shot: "the-users-response"
next_section_and_step: "section_1:step_2"
exit:
next_section_and_step: "section_1:step_4"
restart:
content_blocks:
- "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
- step_id: "step_3"
title: "Game Over"
question: "Would you like to restart and play again, or would you prefer to exit?"
tokens_for_ai: |
If the user wants to restart or play again, categorize as 'restart'.
If the user wants to exit, categorize as 'exit'.
buckets:
- restart
- exit
transitions:
restart:
content_blocks:
- "Restarting the game. Let's start fresh!"
metadata_clear: True
next_section_and_step: "section_1:step_0"
exit:
content_blocks:
- "Thank you for playing Battleship! 🎉"
- "Feel free to come back anytime for another game."
next_section_and_step: "section_1:step_4"
- step_id: "step_4"
title: "Goodbye"
content_blocks:
- "Thanks for playing! Hope you enjoyed the battle at sea."

302
research/activity3.yaml Normal file
View file

@ -0,0 +1,302 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Elephants"
steps:
- step_id: "step_1"
title: "What is an Elephant?"
content_blocks:
- "Welcome to the world of elephants!"
- "Elephants are the largest land animals on Earth. They are known for their big ears, long trunks, and tusks."
tokens_for_ai: "Explain what an elephant is and its key features in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you know about elephants?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know a lot about elephants."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about elephants. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on elephants."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of elephants in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Where Do Elephants Live?"
content_blocks:
- "Elephants live in different parts of the world."
- "There are two main types of elephants: African elephants and Asian elephants."
- "African elephants live in Africa, and Asian elephants live in Asia."
tokens_for_ai: "Explain where elephants live and the difference between African and Asian elephants in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name the two types of elephants and where they live?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know where elephants live."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about where elephants live. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on where elephants live."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of where elephants live in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Elephant Anatomy"
steps:
- step_id: "step_1"
title: "Elephant Trunks"
content_blocks:
- "Elephants have long trunks that they use for many things."
- "They use their trunks to drink water, pick up food, and even to greet other elephants."
tokens_for_ai: "Explain the uses of an elephant's trunk in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do elephants use their trunks for?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how elephants use their trunks."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about how elephants use their trunks. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on elephant trunks."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of elephant trunks in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Elephant Ears"
content_blocks:
- "Elephants have big ears that help them stay cool."
- "They flap their ears to fan themselves and keep their bodies cool."
tokens_for_ai: "Explain the purpose of an elephant's ears in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do elephants have big ears?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know why elephants have big ears."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about why elephants have big ears. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on elephant ears."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of elephant ears in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Elephant Behavior"
steps:
- step_id: "step_1"
title: "Elephant Families"
content_blocks:
- "Elephants live in groups called herds."
- "A herd is usually led by the oldest female elephant, called the matriarch."
tokens_for_ai: "Explain the social structure of elephant herds in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is a group of elephants called and who leads it?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about elephant families."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about elephant families. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on elephant families."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of elephant families in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Elephant Communication"
content_blocks:
- "Elephants communicate with each other using sounds, touch, and even vibrations."
- "They can make loud trumpeting sounds and low rumbles that humans can't hear."
tokens_for_ai: "Explain how elephants communicate in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do elephants communicate with each other?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how elephants communicate."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about how elephants communicate. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on elephant communication."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of elephant communication in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Elephant Conservation"
steps:
- step_id: "step_1"
title: "Why Elephants Need Our Help"
content_blocks:
- "Elephants are amazing animals, but they need our help to survive."
- "Many elephants are in danger because of habitat loss and poaching."
tokens_for_ai: "Explain why elephants need our help and the threats they face in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why do elephants need our help?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand why elephants need our help."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You know a little about why elephants need our help. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the child's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on why elephants need our help."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of why elephants need our help in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "How We Can Help Elephants"
content_blocks:
- "There are many ways we can help elephants."
- "We can support organizations that protect elephants, learn more about them, and spread the word to others."
tokens_for_ai: "Explain how we can help elephants in a friendly and engaging manner suitable for a 7-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you think of ways to help elephants?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You have great ideas to help elephants."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the child to continue learning."
partial_understanding:
content_blocks:
- "You have some good ideas. Let's think of more ways to help elephants."
ai_feedback:
tokens_for_ai: "Provide additional suggestions to help the child think of more ways to help elephants in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on how we can help elephants."
ai_feedback:
tokens_for_ai: "Gently guide the child back to the topic of how we can help elephants in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the child's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "You're an Elephant Expert!"
content_blocks:
- "🎉 Congratulations! You've learned so much about elephants today!"
- "You now know:"
- "✅ What elephants look like and how big they are"
- "✅ What elephants eat with their trunks"
- "✅ How elephants communicate with each other"
- "✅ Why elephants need our help"
- "✅ Ways we can help protect elephants"
- "You're now an elephant expert! Keep learning and caring about animals! 🐘🌟"
- "Thank you for taking this journey with us!"

View file

@ -0,0 +1,598 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s performance throughout the logic puzzle activity.
Consider:
- Their ability to reason through logical statements
- Understanding of deductive reasoning
- Improvement over the course of the activity
- Engagement with explanations
Provide encouraging feedback and suggest areas for continued practice.
'
sections:
- section_id: introduction
title: Welcome to Logic Puzzles
steps:
- step_id: welcome
title: Welcome to Logic Puzzles
content_blocks:
- '# Welcome to Critical Thinking & Logic Puzzles!'
- In this activity, you'll develop your logical reasoning skills through a series of engaging puzzles.
- You'll learn to identify logical patterns, make deductions, and think critically.
- '**What you''ll learn:**'
- '- How to analyze logical statements'
- '- Deductive reasoning techniques'
- '- Pattern recognition'
- '- How to avoid common logical fallacies'
- ''
- Let's begin your journey into the world of logic!
question: Are you ready to sharpen your logical thinking skills?
tokens_for_ai: 'The student is expressing readiness to begin. Accept any positive, affirming response.
Categorize as:
- ready: Student is ready to proceed
- set_language: Student is setting language preference
- off_topic: Completely unrelated response
'
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- Excellent! Let's start with the fundamentals of logical reasoning.
next_section_and_step: section_1:step_1
set_language:
content_blocks:
- I'll communicate with you in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- Let's focus on beginning our logic journey. Are you ready to start?
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: section_1
title: Basic Logical Statements
steps:
- step_id: step_1
title: Understanding Logical Statements
content_blocks:
- '## Understanding Logical Statements'
- Logic is about drawing valid conclusions from given information.
- ''
- '**Basic principle:** If A is true, and ''A implies B'' is true, then B must be true.'
- ''
- '**Example:**'
- '- Statement 1: All cats are mammals.'
- '- Statement 2: Whiskers is a cat.'
- '- Conclusion: Therefore, Whiskers is a mammal.'
- ''
- This is called **deductive reasoning** - going from general rules to specific cases.
question: Based on this reasoning, if 'All birds have feathers' and 'A robin is a bird', what can we conclude?
tokens_for_ai: 'The student should conclude that a robin has feathers.
Categorize as:
- correct: States that robin has feathers (exact wording doesn''t matter)
- partial_understanding: Mentions birds or feathers but incomplete reasoning
- limited_effort: Very brief or unclear answer
- off_topic: Unrelated response
'
feedback_tokens_for_ai: 'Provide feedback on their logical reasoning. If incorrect, gently explain the deductive
process: since ALL birds have feathers, and a robin IS a bird, then the robin must have feathers.
'
buckets:
- correct
- partial_understanding
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Praise their correct deductive reasoning and encourage them to continue.
metadata_add:
score: n+1
puzzles_solved: n+1
next_section_and_step: section_1:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: Acknowledge what they got right, then gently guide them to the complete answer.
next_section_and_step: section_1:step_2
limited_effort:
ai_feedback:
tokens_for_ai: Encourage them to think more carefully about the logical structure and try again.
next_section_and_step: section_1:step_1
off_topic:
content_blocks:
- Let's stay focused on the logic puzzle. Think about what we can deduce from the two statements.
next_section_and_step: section_1:step_1
- step_id: step_2
title: The Contrapositive
content_blocks:
- '## The Contrapositive'
- Great! Now let's learn about the **contrapositive** - a powerful logical tool.
- ''
- 'If we know: ''If A, then B'' is true'
- 'Then we also know: ''If NOT B, then NOT A'' is true'
- ''
- '**Example:**'
- '- Original: ''If it''s raining, then the ground is wet'''
- '- Contrapositive: ''If the ground is NOT wet, then it''s NOT raining'''
- ''
- Both statements are logically equivalent!
- ''
- '**Practice:** We know: ''If you study hard, you will pass the test.'''
question: What is the contrapositive of this statement?
tokens_for_ai: 'The correct contrapositive is: "If you don''t pass the test, then you didn''t study hard"
or any equivalent phrasing.
Categorize as:
- correct: Correctly identifies the contrapositive (not passing → didn''t study)
- partial_understanding: Gets the concept but reverses incorrectly or incomplete
- logical_error: Confuses with converse or inverse
- limited_effort: Very brief or doesn''t attempt to construct the statement
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, praise their understanding. If incorrect, explain that the contrapositive
negates both parts AND reverses them. Common error: converse (if B then A) is NOT
logically equivalent to the original.
'
buckets:
- correct
- partial_understanding
- logical_error
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Excellent work! You've grasped an important logical concept. Explain why contrapositives are useful in reasoning.
metadata_add:
score: n+1
puzzles_solved: n+1
next_section_and_step: section_2:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: You're on the right track. Explain the contrapositive clearly and encourage them.
metadata_add:
score: n+1
next_section_and_step: section_2:step_1
logical_error:
ai_feedback:
tokens_for_ai: Explain the difference between contrapositive, converse, and inverse. Give them another example.
next_section_and_step: section_1:step_2
limited_effort:
content_blocks:
- 'Take your time. Remember: negate both parts AND reverse the order.'
next_section_and_step: section_1:step_2
off_topic:
content_blocks:
- Let's focus on constructing the contrapositive statement.
next_section_and_step: section_1:step_2
- section_id: section_2
title: Syllogisms and Deduction
steps:
- step_id: step_1
title: Classic Syllogism Puzzle
content_blocks:
- '## Classic Syllogism Puzzle'
- A **syllogism** is a form of logical argument with two premises and a conclusion.
- ''
- '**Here''s your puzzle:**'
- ''
- '**Premise 1:** All philosophers love wisdom.'
- '**Premise 2:** Socrates is a philosopher.'
- '**Premise 3:** No one who loves wisdom is foolish.'
- ''
- What can we logically conclude about Socrates?
question: What must be true about Socrates based on these premises?
tokens_for_ai: 'The correct conclusion is that Socrates is not foolish (or Socrates loves wisdom, which also leads to not being foolish).
Categorize as:
- correct: States Socrates is not foolish, or loves wisdom, or both
- partial_understanding: Gets one conclusion but not the full chain of reasoning
- limited_effort: Too brief or unclear
- off_topic: Unrelated or makes up facts not in premises
'
feedback_tokens_for_ai: 'Guide them through the logical chain if needed:
1. Socrates is a philosopher
2. All philosophers love wisdom → Socrates loves wisdom
3. No one who loves wisdom is foolish → Socrates is not foolish
'
buckets:
- correct
- partial_understanding
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Excellent deductive reasoning! You followed the logical chain perfectly.
metadata_add:
score: n+1
puzzles_solved: n+1
next_section_and_step: section_2:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: Good start! Can you extend your reasoning further using all three premises?
next_section_and_step: section_2:step_1
limited_effort:
content_blocks:
- Try working through each premise step by step. What do we know about philosophers? What do we know about Socrates?
next_section_and_step: section_2:step_1
off_topic:
content_blocks:
- Focus only on what the premises tell us. What can we deduce step by step?
next_section_and_step: section_2:step_1
- step_id: step_2
title: Truth Tables and Logical Consistency
content_blocks:
- '## Truth Tables and Logical Consistency'
- Sometimes we need to check if statements are consistent with each other.
- ''
- '**The Scenario:**'
- 'Three friends make the following statements:'
- ''
- '**Alice:** ''If Bob is telling the truth, then Carol is lying.'''
- '**Bob:** ''I am telling the truth.'''
- '**Carol:** ''Alice is telling the truth.'''
- ''
- Let's assume Bob IS telling the truth (as he claims).
question: If Bob is telling the truth, is there a logical contradiction? If so, where?
tokens_for_ai: 'Let''s work through this:
- If Bob is telling the truth (as assumed)
- Then by Alice''s statement, Carol must be lying
- But Carol says "Alice is telling the truth"
- If Carol is lying (as we deduced), then Alice must be lying
- But this contradicts our assumption that Alice''s statement about Bob/Carol is valid
Student should identify that there IS a contradiction, or that Carol must be lying.
Categorize as:
- correct: Identifies the contradiction or that Carol must be lying
- partial_understanding: Sees some inconsistency but doesn''t fully explain it
- confused: Gets lost in the logic
- limited_effort: Very brief answer
- asking_clarifying_questions: Requests help or clarification
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they''re struggling, walk through it step by step. This is a harder puzzle, so be
encouraging. The key insight is following the chain of implications.
'
buckets:
- correct
- partial_understanding
- confused
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Brilliant! You navigated a complex logical scenario. Explain the full chain of reasoning.
metadata_add:
score: n+2
puzzles_solved: n+1
next_section_and_step: section_3:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: You're getting there! Let's trace through what each statement implies step by step.
metadata_add:
hints_used: n+1
next_section_and_step: section_2:step_2
confused:
content_blocks:
- 'Let''s break it down:'
- 1. Assume Bob tells the truth
- 2. What does Alice's statement tell us about Carol?
- 3. What does Carol's statement tell us about Alice?
- 4. Do these work together?
metadata_add:
hints_used: n+1
next_section_and_step: section_2:step_2
limited_effort:
content_blocks:
- Take your time and work through each person's statement carefully.
next_section_and_step: section_2:step_2
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question and provide helpful hints about how to approach the problem.
counts_as_attempt: false
next_section_and_step: section_2:step_2
off_topic:
content_blocks:
- Let's focus on analyzing the logical consistency of the three statements.
next_section_and_step: section_2:step_2
- section_id: section_3
title: Knights and Knaves
steps:
- step_id: step_1
title: The Island of Knights and Knaves
content_blocks:
- '## The Island of Knights and Knaves'
- This is a classic logic puzzle type!
- ''
- '**The Rules:**'
- '- Knights ALWAYS tell the truth'
- '- Knaves ALWAYS lie'
- '- Everyone is either a knight or a knave'
- ''
- '**The Puzzle:**'
- You meet two people, A and B.
- ''
- '**Person A says:** ''At least one of us is a knave.'''
- ''
- What are A and B?
question: Is A a knight or a knave? Is B a knight or a knave? Explain your reasoning.
tokens_for_ai: "Solution:\n- If A is a knave (liar), then the statement \"at least one of us is a knave\" would be false,\n meaning both are knights. But A can't be both a knight and a knave - contradiction!\n- Therefore A must be a knight (truth-teller)\n- Since A tells the truth, \"at least one of us is a knave\" is true\n- Since A is a knight, B must be the knave\n\nAnswer: A is a knight, B is a knave\n\nCategorize as:\n- correct: Identifies A as knight and B as knave with reasonable explanation\n- partial_understanding: Gets one correct but not both, or right answer without clear reasoning\n- logical_error: Makes an error in the logical deduction\n- limited_effort: Too brief or gives up\n- asking_clarifying_questions: Asks for help\n- off_topic: Unrelated\n"
feedback_tokens_for_ai: 'This is a challenging puzzle! If they get stuck, suggest trying both possibilities:
"What if A is a knight? What if A is a knave?" and see which leads to a contradiction.
'
buckets:
- correct
- partial_understanding
- logical_error
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Outstanding! You've mastered proof by contradiction. This is advanced logical reasoning!
metadata_add:
score: n+3
puzzles_solved: n+1
next_section_and_step: section_3:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: You're thinking in the right direction. Try assuming A is a knave and see if that leads to a contradiction.
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_1
logical_error:
ai_feedback:
tokens_for_ai: 'Let''s think through this carefully. Test both possibilities: what if A is a knight? What if A is a knave?'
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_1
limited_effort:
content_blocks:
- 'This is challenging! Try starting with: ''Assume A is a knight. Then what must be true?'''
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question helpfully and provide a hint about testing both possibilities.
counts_as_attempt: false
next_section_and_step: section_3:step_1
off_topic:
content_blocks:
- 'Let''s work through the knight and knave puzzle. Remember: knights always tell the truth, knaves always lie.'
next_section_and_step: section_3:step_1
- step_id: step_2
title: Advanced Knights and Knaves
content_blocks:
- '## Advanced Knights and Knaves'
- Ready for a harder one? Let's add a third person!
- ''
- 'You meet three people: X, Y, and Z.'
- ''
- '**X says:** ''All of us are knaves.'''
- '**Y says:** ''Exactly one of us is a knight.'''
- ''
- What can you determine about X, Y, and Z?
question: Identify whether X, Y, and Z are knights or knaves. Explain your reasoning.
tokens_for_ai: 'Solution:
- X says "all of us are knaves"
- If X were a knight (truth-teller), then "all are knaves" would be true, but X is a knight - contradiction!
- Therefore X must be a knave (liar)
- Since X is a knave, the statement "all of us are knaves" is false, so at least one is a knight
- Y says "exactly one of us is a knight"
- If Y is a knave, then "exactly one is a knight" is false, but we know at least one is a knight (not Y, not X)... so Z would be a knight
- If Y is a knight, then "exactly one is a knight" is true, and Y is that knight, so Z must be a knave
- Actually, if Y were a knave and Z were a knight, then we''d have exactly one knight (Z), making Y''s statement true - but knaves can''t tell the truth! Contradiction.
- Therefore Y must be a knight and Z must be a knave
Answer: X is a knave, Y is a knight, Z is a knave
Categorize as:
- correct: Correctly identifies all three with solid reasoning
- partial_understanding: Gets some right or reasoning is incomplete
- confused: Logic errors or contradictions in their answer
- limited_effort: Very brief or gives up
- asking_clarifying_questions: Asks for help
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'This is quite challenging! Encourage their effort. If struggling, suggest working through
X first (easier), then systematically testing Y as knight vs knave.
'
buckets:
- correct
- partial_understanding
- confused
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Exceptional work! You've demonstrated mastery of complex logical deduction. This is university-level reasoning!
metadata_add:
score: n+5
puzzles_solved: n+1
next_section_and_step: section_4:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: Good progress! Let's work through this systematically. Start with X - can X be a knight?
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_2
confused:
ai_feedback:
tokens_for_ai: Let's break this down step by step. First, what can we determine about X from their statement?
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_2
limited_effort:
content_blocks:
- This is a tough puzzle! Start by analyzing X's statement. Can someone truthfully say 'we are all liars'?
metadata_add:
hints_used: n+1
next_section_and_step: section_3:step_2
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question and provide systematic guidance on how to approach the puzzle.
counts_as_attempt: false
next_section_and_step: section_3:step_2
off_topic:
content_blocks:
- Let's focus on solving this three-person knight and knave puzzle.
next_section_and_step: section_3:step_2
- section_id: section_4
title: Reflection and Summary
steps:
- step_id: step_1
title: Congratulations!
content_blocks:
- '## Congratulations! 🎉'
- You've completed the Logic Puzzles activity!
- ''
- '**What you''ve learned:**'
- ✓ Basic deductive reasoning (if A then B)
- ✓ Contrapositives and logical equivalence
- ✓ Syllogisms and multi-step deduction
- ✓ Truth tables and consistency checking
- ✓ Proof by contradiction (Knights and Knaves)
- ''
- '**Why logical thinking matters:**'
- '- Programming and debugging require logical reasoning'
- '- Critical thinking helps evaluate arguments and claims'
- '- Problem-solving in math, science, and everyday life'
- '- Avoiding logical fallacies in discussions'
- ''
- '**Your journey:**'
- You've progressed from basic deductions to complex multi-person logic puzzles.
- These skills will serve you well in many areas of thinking and learning!
question: What was the most challenging puzzle for you, and what did you learn from it?
tokens_for_ai: 'This is a reflection question. Accept any thoughtful response about their learning experience.
Categorize as:
- thoughtful_reflection: Provides specific insights about their learning
- brief_reflection: Short but genuine reflection
- limited_effort: Very minimal response
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide personalized feedback on their journey through the activity. Acknowledge their
specific challenges and growth. Encourage continued practice with logical reasoning.
'
buckets:
- thoughtful_reflection
- brief_reflection
- limited_effort
- off_topic
transitions:
thoughtful_reflection:
ai_feedback:
tokens_for_ai: Provide thoughtful, personalized feedback on their learning journey and suggest how to continue developing logical thinking skills.
metadata_add:
activity_completed: 'true'
brief_reflection:
ai_feedback:
tokens_for_ai: Acknowledge their reflection and encourage them to keep practicing logical reasoning.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Thank them for participating and summarize key takeaways from the activity.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Let's reflect on your logic puzzle journey. Which puzzle challenged you most?
next_section_and_step: section_4:step_1

View file

@ -0,0 +1,784 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s understanding of the scientific method.
Consider:
- Their ability to identify steps in the scientific method
- Understanding of hypothesis formation and testing
- Recognition of controls and variables
- Critical thinking about experimental design
- Engagement with the case studies
Provide encouraging feedback and suggestions for applying scientific thinking in their own explorations.
'
sections:
- section_id: introduction
title: Welcome to Scientific Method Explorer
steps:
- step_id: welcome
title: Welcome to Scientific Method
content_blocks:
- '# Welcome to Scientific Method Explorer!'
- Explore how scientists make discoveries through the scientific method.
- ''
- 'You''ll follow in the footsteps of famous scientists, learning to:'
- '- Ask testable questions'
- '- Form hypotheses'
- '- Design experiments'
- '- Identify variables and controls'
- '- Analyze results and draw conclusions'
- ''
- '**The Scientific Method Steps:**'
- 1. **Observe** - Notice something interesting
- 2. **Question** - Ask why or how
- 3. **Hypothesize** - Make an educated guess
- 4. **Experiment** - Test your hypothesis
- 5. **Analyze** - Look at your data
- 6. **Conclude** - Determine if hypothesis was supported
- ''
- Ready to think like a scientist?
question: Are you ready to explore the scientific method through real discoveries?
tokens_for_ai: 'Student is expressing readiness. Accept any positive response.
Categorize as:
- ready: Positive, ready to begin
- set_language: Setting language preference
- off_topic: Unrelated
'
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- Excellent! Let's begin with a fascinating historical case study.
next_section_and_step: section_1:step_1
set_language:
content_blocks:
- I'll communicate in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- Let's get started with exploring science! Are you ready?
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: section_1
title: 'Case Study: Germ Theory'
steps:
- step_id: step_1
title: The Mystery of Childbed Fever
content_blocks:
- '## The Mystery of Childbed Fever (1840s)'
- '**The Observation:**'
- 'Dr. Ignaz Semmelweis noticed something disturbing in his Vienna hospital:'
- '- Ward 1 (doctors and medical students): 10% of mothers died from childbed fever'
- '- Ward 2 (midwives): Only 4% of mothers died'
- ''
- '**The Puzzle:**'
- Both wards had similar conditions, but Ward 1 had much higher death rates.
- ''
- Semmelweis observed that doctors in Ward 1 came directly from autopsy rooms to deliver babies, while midwives in Ward 2 did not perform autopsies.
question: What question should Semmelweis ask based on this observation? What do you think might be causing the difference in death rates?
tokens_for_ai: 'Good scientific questions might be:
- Are doctors carrying something deadly from autopsies?
- Does something on doctors'' hands cause the fever?
- Is there a connection between autopsies and infections?
Categorize as:
- correct_question: Identifies a connection between autopsy work and infections
- partial_understanding: Notices the pattern but doesn''t form a clear causal question
- creative_thinking: Proposes alternative explanations worth considering
- limited_effort: Very brief or vague
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they identify the connection to autopsies and handwashing, praise their observation.
If they suggest other factors, acknowledge the thinking but guide toward the autopsy connection.
'
buckets:
- correct_question
- partial_understanding
- creative_thinking
- limited_effort
- off_topic
transitions:
correct_question:
ai_feedback:
tokens_for_ai: Excellent scientific observation! You've identified the key question that Semmelweis asked.
metadata_add:
score: n+1
experiments_designed: n+1
next_section_and_step: section_1:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: Good thinking! Can you be more specific about what might be different about the doctors' hands?
next_section_and_step: section_1:step_2
creative_thinking:
ai_feedback:
tokens_for_ai: Interesting hypothesis! Acknowledge their creativity while guiding them to consider the autopsy connection.
metadata_add:
score: n+1
next_section_and_step: section_1:step_2
limited_effort:
content_blocks:
- Think about what the doctors were doing that the midwives were not. What might they be carrying on their hands?
next_section_and_step: section_1:step_1
off_topic:
content_blocks:
- Let's focus on the medical mystery. What difference between the two wards might explain the death rates?
next_section_and_step: section_1:step_1
- step_id: step_2
title: Forming a Hypothesis
content_blocks:
- '## Forming a Hypothesis'
- 'Semmelweis formed a hypothesis:'
- ''
- '**''Cadaveric particles'' from autopsies on doctors'' hands are causing childbed fever.**'
- ''
- This was revolutionary! In the 1840s, germs were not yet understood.
- ''
- '**Now for the experiment:**'
- Semmelweis needs to test this hypothesis. He decides to require doctors to wash their hands with chlorinated lime solution before examining patients.
- ''
- '**Question for you:**'
- To make this a good scientific experiment, what should we compare?
question: What should Semmelweis measure before and after the handwashing requirement? What would be the control group?
tokens_for_ai: 'Good answers should mention:
- Measure death rates before and after handwashing
- Compare Ward 1 with handwashing to previous Ward 1 without handwashing
- Or compare Ward 1 (with handwashing) to Ward 2 (baseline)
- The control is the previous data or Ward 2
Categorize as:
- correct_method: Identifies need to compare death rates before/after or between groups
- partial_understanding: Mentions measuring death rates but unclear on control
- confused_about_controls: Doesn''t understand the concept of a control group
- limited_effort: Very brief answer
- asking_clarifying_questions: Requests explanation of terms
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they understand controls, praise them! If confused about controls, explain that
a control group helps us know if changes are due to our intervention or something else.
'
buckets:
- correct_method
- partial_understanding
- confused_about_controls
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
correct_method:
ai_feedback:
tokens_for_ai: Excellent experimental thinking! You understand the importance of controls in science.
metadata_add:
score: n+2
controls_identified: n+1
next_section_and_step: section_1:step_3
partial_understanding:
ai_feedback:
tokens_for_ai: Good! You're thinking about measurement. Explain what a control group is and why it's important.
metadata_add:
score: n+1
next_section_and_step: section_1:step_3
confused_about_controls:
content_blocks:
- '**Control groups** help us compare results.'
- 'We need to know: Are death rates different WITH handwashing vs WITHOUT handwashing?'
- That way we know if handwashing made the difference!
next_section_and_step: section_1:step_2
limited_effort:
content_blocks:
- Think about what Semmelweis should measure and what he should compare it to.
next_section_and_step: section_1:step_2
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about experimental design and controls helpfully.
counts_as_attempt: false
next_section_and_step: section_1:step_2
off_topic:
content_blocks:
- Let's focus on designing the experiment. What should we measure?
next_section_and_step: section_1:step_2
- step_id: step_3
title: The Results!
content_blocks:
- '## The Results!'
- Semmelweis implemented handwashing with chlorinated lime in 1847.
- ''
- '**The data:**'
- '- **Before handwashing (1846):** Death rate in Ward 1 = 10%'
- '- **After handwashing (1847-1848):** Death rate in Ward 1 = 2%'
- ''
- This was a dramatic improvement! The death rate dropped by 80%.
- ''
- '**Analysis step:**'
- Now we must analyze these results and draw a conclusion.
question: Based on these results, was Semmelweis's hypothesis supported? What can we conclude about the cause of childbed fever?
tokens_for_ai: 'The hypothesis WAS supported - handwashing dramatically reduced death rates, suggesting
that something on doctors'' hands (cadaveric particles/germs) was indeed causing the fever.
Categorize as:
- correct_conclusion: States hypothesis was supported, handwashing worked, something on hands caused illness
- partial_understanding: Gets general idea but incomplete reasoning
- overstating: Claims this "proves" rather than "supports" (good to address scientific certainty)
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, praise their analysis! If they say "proves," gently explain that in science
we say evidence "supports" a hypothesis rather than "proves" it absolutely.
'
buckets:
- correct_conclusion
- partial_understanding
- overstating
- limited_effort
- off_topic
transitions:
correct_conclusion:
ai_feedback:
tokens_for_ai: Excellent analysis! You've worked through a complete scientific investigation. Explain the impact this had on medicine.
metadata_add:
score: n+2
case_studies_completed: n+1
next_section_and_step: section_2:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: Good! Can you connect the results more explicitly to the hypothesis about what was on doctors' hands?
metadata_add:
score: n+1
case_studies_completed: n+1
next_section_and_step: section_2:step_1
overstating:
ai_feedback:
tokens_for_ai: 'Great thinking! One note: in science we say results ''support'' a hypothesis rather than ''prove'' it. Explain why scientific conclusions are provisional.'
metadata_add:
score: n+1
case_studies_completed: n+1
next_section_and_step: section_2:step_1
limited_effort:
content_blocks:
- Look at the dramatic change in death rates. What does this tell us about Semmelweis's hypothesis?
next_section_and_step: section_1:step_3
off_topic:
content_blocks:
- Let's analyze the data. Death rates dropped from 10% to 2%. What does this mean?
next_section_and_step: section_1:step_3
- section_id: section_2
title: Design Your Own Experiment
steps:
- step_id: step_1
title: Newton's Light Experiment
content_blocks:
- '## Newton''s Light Experiment'
- Let's explore another famous case, then YOU'LL design an experiment!
- ''
- '**The Observation (1660s):**'
- Isaac Newton observed that sunlight passing through a prism splits into rainbow colors.
- ''
- '**The Common Belief:**'
- Most people thought the prism was adding color to the light, like stained glass adds color.
- ''
- '**Newton''s Hypothesis:**'
- 'Newton proposed something radical: White light is actually MADE of all the colors combined, and the prism just separates them.'
- ''
- '**Your Task:**'
- Newton needs to prove that the colors come FROM the white light, not from the prism.
question: Design an experiment that could test whether the colors are already in white light or are created by the prism. What would you do?
tokens_for_ai: 'Newton''s actual experiment: He used a second prism to recombine the separated colors
back into white light. If the prism created the colors, you couldn''t get white light back.
Good student answers might suggest:
- Using a second prism to recombine colors
- Testing different prisms (if prism creates color, different prisms would create different colors)
- Blocking some colors and seeing what recombines
- Comparing different light sources
Categorize as:
- excellent_design: Proposes recombining colors or testing multiple prisms
- creative_approach: Different but scientifically sound experiment
- partial_understanding: Has an idea but experimental design is unclear
- confused: Doesn''t understand what needs to be tested
- limited_effort: Very brief
- asking_clarifying_questions: Needs help
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Encourage creative experimental thinking! If they propose recombining colors, that''s
exactly what Newton did. If they have other ideas, evaluate if they would actually
distinguish between the two hypotheses.
'
buckets:
- excellent_design
- creative_approach
- partial_understanding
- confused
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
excellent_design:
ai_feedback:
tokens_for_ai: Brilliant experimental design! Explain how this is similar to what Newton actually did and praise their scientific thinking.
metadata_add:
score: n+3
experiments_designed: n+1
next_section_and_step: section_2:step_2
creative_approach:
ai_feedback:
tokens_for_ai: Interesting approach! Evaluate whether their experiment would actually distinguish between the two hypotheses. If yes, praise them. If not, guide them.
metadata_add:
score: n+2
experiments_designed: n+1
next_section_and_step: section_2:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking in the right direction. Ask: if the prism creates color, could you reverse the process? If light contains the colors, could you recombine them?'
next_section_and_step: section_2:step_1
confused:
content_blocks:
- '**Hint:** Think about what would happen differently based on each explanation:'
- '- If the PRISM creates color, could you get white light back from colored light?'
- '- If WHITE LIGHT contains colors, could you recombine them?'
next_section_and_step: section_2:step_1
limited_effort:
content_blocks:
- Take time to think creatively! How could you test whether colors come from the light or from the prism?
next_section_and_step: section_2:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question and provide guidance on experimental design principles.
counts_as_attempt: false
next_section_and_step: section_2:step_1
off_topic:
content_blocks:
- Let's focus on designing an experiment about light and prisms.
next_section_and_step: section_2:step_1
- step_id: step_2
title: Identifying Variables
content_blocks:
- '## Identifying Variables'
- Great thinking! Newton did indeed use a second prism to recombine the colors back into white light.
- ''
- '**Understanding Variables:**'
- 'In any experiment, we need to identify:'
- '- **Independent variable:** What YOU change'
- '- **Dependent variable:** What you MEASURE'
- '- **Control variables:** What you keep THE SAME'
- ''
- '**Example scenario:**'
- You want to test if plants grow faster with music.
- ''
- 'You set up:'
- '- 10 plants with music'
- '- 10 plants without music'
- '- All plants get same water, light, soil, and temperature'
- '- Measure growth after 2 weeks'
question: Identify the independent variable, dependent variable, and control variables in this plant experiment.
tokens_for_ai: 'Correct answers:
- Independent variable: Presence/absence of music (what you change)
- Dependent variable: Plant growth/height (what you measure)
- Control variables: Water, light, soil, temperature (what you keep the same)
Categorize as:
- correct: Correctly identifies all three types of variables
- partial_understanding: Gets 2 out of 3 correct
- confused: Mixes up independent and dependent
- limited_effort: Very brief or incomplete
- asking_clarifying_questions: Needs clarification
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they confuse independent and dependent, explain: independent is what the experimenter
controls/changes, dependent is what responds/changes as a result.
'
buckets:
- correct
- partial_understanding
- confused
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Perfect! You understand variables - a crucial concept in experimental design.
metadata_add:
score: n+2
controls_identified: n+1
next_section_and_step: section_3:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: Good start! Clarify which variables they got right and help with the others.
metadata_add:
score: n+1
next_section_and_step: section_3:step_1
confused:
content_blocks:
- '**Tip:** The INDEPENDENT variable is what the experimenter changes on purpose.'
- The DEPENDENT variable is what you measure to see the effect.
- CONTROL variables are kept the same so they don't interfere.
next_section_and_step: section_2:step_2
limited_effort:
content_blocks:
- 'Try to identify each type: What are you changing? What are you measuring? What are you keeping the same?'
next_section_and_step: section_2:step_2
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about variables clearly with examples.
counts_as_attempt: false
next_section_and_step: section_2:step_2
off_topic:
content_blocks:
- Let's focus on identifying the different types of variables in this experiment.
next_section_and_step: section_2:step_2
- section_id: section_3
title: Avoiding Bias and Errors
steps:
- step_id: step_1
title: Recognizing Experimental Bias
content_blocks:
- '## Recognizing Experimental Bias'
- Good scientists must watch out for bias and confounding factors!
- ''
- '**Scenario:**'
- A pharmaceutical company tests a new headache medicine.
- ''
- '**Experimental setup:**'
- '- Group A: 100 patients receive the new medicine'
- '- Group B: 100 patients receive nothing'
- '- Researchers record who reports headache relief'
- ''
- '**Results:**'
- '- Group A: 80% report relief'
- '- Group B: 30% report relief'
- ''
- The company concludes the medicine works!
question: Is there a problem with this experimental design? What's missing or problematic?
tokens_for_ai: 'Major problems:
- No placebo (Group B should get a fake pill, not nothing)
- Placebo effect not controlled for
- Patients know if they''re getting treatment (should be blind/double-blind)
- Researcher bias possible if they know who got real medicine
Categorize as:
- identified_placebo: Recognizes need for placebo control
- identified_blinding: Recognizes need for blind study
- partial_understanding: Sees something wrong but can''t articulate it clearly
- missed_bias: Doesn''t see the problem
- limited_effort: Very brief
- asking_clarifying_questions: Needs explanation
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they identify placebo effect, excellent! If not, explain that people often feel
better just because they think they''re getting treatment. That''s why we need placebo
controls and blind studies.
'
buckets:
- identified_placebo
- identified_blinding
- partial_understanding
- missed_bias
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
identified_placebo:
ai_feedback:
tokens_for_ai: Excellent! You identified the placebo effect. Explain why placebos are crucial in medical research.
metadata_add:
score: n+3
bias_identified: n+1
next_section_and_step: section_3:step_2
identified_blinding:
ai_feedback:
tokens_for_ai: Great catch! Explain how blinding prevents bias in both patients and researchers.
metadata_add:
score: n+3
bias_identified: n+1
next_section_and_step: section_3:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: You're sensing something's wrong. Guide them toward the placebo effect concept.
next_section_and_step: section_3:step_1
missed_bias:
content_blocks:
- '**Hint:** Think about the psychological effect of KNOWING you''re getting medicine.'
- What if people feel better just because they believe they're being treated?
next_section_and_step: section_3:step_1
limited_effort:
content_blocks:
- 'Think carefully: Is it fair to compare people who GET something to people who get NOTHING?'
next_section_and_step: section_3:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about experimental design and bias.
counts_as_attempt: false
next_section_and_step: section_3:step_1
off_topic:
content_blocks:
- Let's analyze this medical experiment. Is the design fair and unbiased?
next_section_and_step: section_3:step_1
- step_id: step_2
title: Scientific Integrity
content_blocks:
- '## Scientific Integrity'
- Excellent work identifying bias!
- ''
- '**Key principles for good science:**'
- ''
- ✓ **Use controls** - Compare to a baseline or control group
- ✓ **Use placebos** - Control for psychological effects
- ✓ **Blind studies** - Subjects don't know if they got real treatment
- ✓ **Double-blind** - Researchers also don't know (prevents their bias)
- ✓ **Replicate** - Repeat experiments to confirm results
- ✓ **Peer review** - Other scientists check your work
- ✓ **Large sample sizes** - More data = more reliable
- ✓ **Account for confounding variables** - What else might affect results?
- ''
- These principles help ensure that scientific findings are reliable and trustworthy.
question: Why do you think it's important for other scientists to be able to replicate (repeat) an experiment? What purpose does replication serve in science?
tokens_for_ai: 'Good answers mention:
- Verifying results weren''t due to chance
- Catching errors or fraud
- Building confidence in findings
- Testing if results hold in different conditions
- Science is self-correcting
Categorize as:
- insightful: Understands multiple purposes of replication
- correct_understanding: Gets the basic concept (verification)
- partial_understanding: General idea but incomplete
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Encourage their understanding of how science builds reliable knowledge through
replication and peer review. Connect it to why we can trust scientific consensus.
'
buckets:
- insightful
- correct_understanding
- partial_understanding
- limited_effort
- off_topic
transitions:
insightful:
ai_feedback:
tokens_for_ai: Excellent understanding of scientific process! You grasp why science is a self-correcting system.
metadata_add:
score: n+3
next_section_and_step: section_4:step_1
correct_understanding:
ai_feedback:
tokens_for_ai: Correct! Replication is indeed crucial for verifying results. Expand on other benefits if they didn't mention them.
metadata_add:
score: n+2
next_section_and_step: section_4:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: You're on the right track. Explain how replication helps catch errors and builds confidence.
metadata_add:
score: n+1
next_section_and_step: section_4:step_1
limited_effort:
content_blocks:
- Think about what happens if only ONE person does an experiment. How do we know if their result was accurate?
next_section_and_step: section_3:step_2
off_topic:
content_blocks:
- Let's focus on why repeating experiments is important in science.
next_section_and_step: section_3:step_2
- section_id: section_4
title: Reflection and Conclusion
steps:
- step_id: step_1
title: Congratulations!
content_blocks:
- '## Congratulations, Scientist! 🔬'
- You've completed the Scientific Method Explorer!
- ''
- '**What you''ve learned:**'
- ✓ The steps of the scientific method
- ✓ How to form testable hypotheses
- ✓ Experimental design principles
- ✓ Identifying variables (independent, dependent, control)
- ✓ The importance of controls and placebos
- ✓ Recognizing bias in experiments
- ✓ Why replication and peer review matter
- ''
- '**Famous scientists you studied:**'
- '- Ignaz Semmelweis (germ theory and handwashing)'
- '- Isaac Newton (nature of light)'
- ''
- '**Why this matters:**'
- The scientific method is how we reliably discover truth about the natural world.
- 'These principles apply whether you''re:'
- '- Testing a new technology'
- '- Debugging code (forming and testing hypotheses!)'
- '- Evaluating health claims'
- '- Understanding climate science'
- '- Or pursuing any evidence-based inquiry'
question: How might you apply scientific thinking in your own life or studies? Give an example of a question you could investigate using the scientific method.
tokens_for_ai: 'This is a reflection question. Accept any thoughtful application of scientific method
to a real-world question or problem.
Categorize as:
- excellent_application: Proposes a specific, testable question with clear methodology
- good_application: Identifies a reasonable application area
- basic_reflection: General but genuine reflection
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide personalized, encouraging feedback on their learning journey. Acknowledge their
application ideas. Encourage them to actually try investigating something scientifically.
Emphasize that scientific thinking is a powerful tool for understanding the world.
'
buckets:
- excellent_application
- good_application
- basic_reflection
- limited_effort
- off_topic
transitions:
excellent_application:
ai_feedback:
tokens_for_ai: Fantastic! Your example shows you truly understand how to apply the scientific method. Encourage them to actually investigate their question!
metadata_add:
activity_completed: 'true'
good_application:
ai_feedback:
tokens_for_ai: Great thinking! Provide positive feedback and suggestions for how they could make their investigation more rigorous.
metadata_add:
activity_completed: 'true'
basic_reflection:
ai_feedback:
tokens_for_ai: Thank them for their reflection and summarize the key scientific principles they've learned.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Acknowledge their completion and encourage them to think scientifically in their daily life.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Think about how you could use scientific thinking in your own investigations. What question might you explore?
next_section_and_step: section_4:step_1

View file

@ -0,0 +1,895 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s engagement with world geography and cultural learning.
Consider:
- Their curiosity about different regions
- Retention of geographical and cultural facts
- Respect and interest in cultural diversity
- Performance on geography questions
Provide encouraging feedback and suggest areas of the world they might explore further.
'
sections:
- section_id: introduction
title: Welcome, World Explorer!
steps:
- step_id: welcome
title: Welcome to World Geography
content_blocks:
- '# Welcome to World Geography & Cultural Awareness! 🌍'
- Embark on a virtual journey around the world!
- ''
- '**In this adventure, you will:**'
- '- Explore different continents and countries'
- '- Learn fascinating cultural facts and traditions'
- '- Discover historical connections between regions'
- '- Test your geography knowledge'
- '- Develop global awareness and appreciation for diversity'
- ''
- '**Your journey:**'
- You'll choose which regions to explore, learn about each location, and answer questions to test your knowledge.
- The more you explore, the more cultural insights you'll collect!
- ''
- Ready to explore our amazing planet?
question: 'Which continent would you like to explore first? Choose: Africa, Asia, Europe, South America, or Oceania.'
tokens_for_ai: 'Student is choosing their starting continent.
Categorize as:
- africa: Chose Africa
- asia: Chose Asia
- europe: Chose Europe
- south_america: Chose South America
- oceania: Chose Oceania (Australia/Pacific)
- set_language: Setting language preference
- off_topic: Doesn''t choose a continent
'
buckets:
- africa
- asia
- europe
- south_america
- oceania
- set_language
- off_topic
transitions:
africa:
content_blocks:
- 🌍 Excellent choice! Let's explore the diverse continent of Africa!
metadata_add:
continents_visited: n+1
current_continent: Africa
next_section_and_step: africa:step_1
asia:
content_blocks:
- 🌏 Wonderful! Asia awaits - the world's largest and most populous continent!
metadata_add:
continents_visited: n+1
current_continent: Asia
next_section_and_step: asia:step_1
europe:
content_blocks:
- 🌍 Great! Let's discover the rich history and culture of Europe!
metadata_add:
continents_visited: n+1
current_continent: Europe
next_section_and_step: europe:step_1
south_america:
content_blocks:
- 🌎 Fantastic! South America's biodiversity and culture await!
metadata_add:
continents_visited: n+1
current_continent: South America
next_section_and_step: south_america:step_1
oceania:
content_blocks:
- 🌏 Awesome! Let's explore the islands and nations of Oceania!
metadata_add:
continents_visited: n+1
current_continent: Oceania
next_section_and_step: oceania:step_1
set_language:
content_blocks:
- I'll communicate in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- 'Please choose a continent to explore: Africa, Asia, Europe, South America, or Oceania.'
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: africa
title: Exploring Africa
steps:
- step_id: step_1
title: Welcome to Africa - Kenya
content_blocks:
- '## Welcome to Africa! 🦁'
- Africa is the world's second-largest continent, home to 54 countries and over 1.3 billion people.
- ''
- '**Let''s visit Kenya!**'
- ''
- '**Geography:** Kenya is located in East Africa, bordered by the Indian Ocean.'
- '**Capital:** Nairobi'
- '**Famous for:** Wildlife safaris, the Great Rift Valley, and being home to the Maasai people'
- ''
- '**Cultural Fact:**'
- Kenya is known for its incredible biodiversity. The annual wildebeest migration through the Maasai Mara is one of the world's most spectacular natural events!
- ''
- '**Language Note:**'
- While English and Swahili are official languages, Kenya has over 60 indigenous languages!
- In Swahili, 'Jambo' means 'Hello' and 'Karibu' means 'Welcome'.
question: What is the capital city of Kenya?
tokens_for_ai: 'The capital of Kenya is Nairobi (just mentioned in the content).
Categorize as:
- correct: Says Nairobi
- close: Says a major Kenyan city but not the capital (like Mombasa)
- confused_region: Names a capital from a different African country
- limited_effort: Very brief or no real answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, praise them! If they guessed another city, gently correct and perhaps share
a fun fact about Nairobi.
'
buckets:
- correct
- close
- confused_region
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Correct! Nairobi is indeed the capital. Share an interesting fact about Nairobi being one of Africa's major cities.
metadata_add:
quiz_score: n+1
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: africa:step_2
close:
ai_feedback:
tokens_for_ai: That's a major city in Kenya, but the capital is Nairobi! Share a fact about both cities.
metadata_add:
countries_visited: n+1
next_section_and_step: africa:step_2
confused_region:
content_blocks:
- That's a capital of another African country! Kenya's capital is Nairobi.
metadata_add:
countries_visited: n+1
next_section_and_step: africa:step_2
limited_effort:
content_blocks:
- Look back at the information about Kenya. Which city is listed as the capital?
next_section_and_step: africa:step_1
off_topic:
content_blocks:
- Let's focus on learning about Kenya. What is its capital city?
next_section_and_step: africa:step_1
- step_id: step_2
title: Choose Your Next Destination
content_blocks:
- '## Journey Continues...'
- Excellent! You've learned about Kenya.
- ''
- '**From Kenya, you can explore:**'
- '- **North to Egypt** - Ancient pyramids and the Nile River'
- '- **West to Nigeria** - Africa''s most populous country, rich in culture and music'
- '- **South to South Africa** - Diverse landscapes from savannas to mountains'
- '- **Continue to a new continent** - Asia, Europe, South America, or Oceania'
question: Where would you like to go next?
tokens_for_ai: 'Student is choosing their next destination.
Categorize as:
- egypt: North to Egypt
- nigeria: West to Nigeria
- south_africa: South to South Africa
- new_continent: Wants to explore a different continent
- off_topic: Unrelated
'
buckets:
- egypt
- nigeria
- south_africa
- new_continent
- off_topic
transitions:
egypt:
content_blocks:
- 🐪 Heading north to Egypt - land of pharaohs!
metadata_add:
countries_visited: n+1
next_section_and_step: africa_egypt:step_1
nigeria:
content_blocks:
- 🎵 Traveling west to Nigeria - birthplace of Afrobeat!
metadata_add:
countries_visited: n+1
next_section_and_step: africa_nigeria:step_1
south_africa:
content_blocks:
- 🦏 Heading south to South Africa - the Rainbow Nation!
metadata_add:
countries_visited: n+1
next_section_and_step: africa_south:step_1
new_continent:
content_blocks:
- Ready to explore a new continent! Great choice.
next_section_and_step: choose_continent:step_1
off_topic:
content_blocks:
- 'Please choose your next destination: Egypt, Nigeria, South Africa, or a new continent.'
counts_as_attempt: false
next_section_and_step: africa:step_2
- section_id: africa_egypt
title: Egypt
steps:
- step_id: step_1
title: Egypt - Land of Ancient Wonders
content_blocks:
- '## Egypt - Land of Ancient Wonders 🐪'
- '**Geography:** Located in Northeast Africa, Egypt connects Africa to Asia via the Sinai Peninsula.'
- '**Capital:** Cairo'
- '**Famous for:** The Pyramids of Giza, the Sphinx, the Nile River (world''s longest river)'
- ''
- '**Historical Fact:**'
- Ancient Egyptian civilization lasted over 3,000 years! They developed hieroglyphic writing, built massive monuments, and made advances in mathematics, medicine, and astronomy.
- ''
- '**Cultural Fact:**'
- The Nile River has been central to Egyptian life for millennia. The ancient saying 'Egypt is the gift of the Nile' reflects how the river's annual flooding made agriculture possible in the desert.
question: What is the world's longest river, which flows through Egypt?
tokens_for_ai: 'The answer is the Nile River (mentioned multiple times above).
Categorize as:
- correct: Says Nile or Nile River
- confused: Names another famous long river (Amazon, Yangtze, Mississippi)
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, praise them! If they say Amazon (second longest), acknowledge it''s close but
the Nile is slightly longer.
'
buckets:
- correct
- confused
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Excellent! The Nile is indeed the world's longest river. Share a fascinating fact about its importance.
metadata_add:
quiz_score: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused:
ai_feedback:
tokens_for_ai: That's another long river! But the Nile is the world's longest. Explain the comparison between them.
metadata_add:
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the information about Egypt. Which river is mentioned as the world's longest?
next_section_and_step: africa_egypt:step_1
off_topic:
content_blocks:
- Let's focus on geography. What is the world's longest river?
next_section_and_step: africa_egypt:step_1
- section_id: africa_nigeria
title: Nigeria
steps:
- step_id: step_1
title: Nigeria - Heart of West Africa
content_blocks:
- '## Nigeria - Heart of West Africa 🎵'
- '**Geography:** Located in West Africa on the Gulf of Guinea'
- '**Capital:** Abuja'
- '**Famous for:** Being Africa''s most populous country (over 200 million people), Nollywood (film industry), Afrobeat music'
- ''
- '**Cultural Fact:**'
- Nigeria is incredibly diverse with over 250 ethnic groups and 500+ languages! The largest groups are Hausa, Yoruba, and Igbo.
- ''
- '**Music Heritage:**'
- Nigeria is the birthplace of Afrobeat, pioneered by Fela Kuti. Today, Nigerian artists are internationally renowned in genres from Afrobeats to hip-hop.
question: Nigeria is famous for its film industry. What is it called?
tokens_for_ai: 'The answer is Nollywood (mentioned above).
Categorize as:
- correct: Says Nollywood
- confused: Says Bollywood or Hollywood
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, share fun facts about Nollywood being one of the world''s largest film
industries by volume!
'
buckets:
- correct
- confused
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Correct! Nollywood is one of the world's largest film industries. Share impressive statistics about it.
metadata_add:
quiz_score: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused:
ai_feedback:
tokens_for_ai: That's a film industry, but Nigeria has its own! It's called Nollywood.
metadata_add:
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- 'Check the information about Nigeria. What is their film industry called? (Hint: it rhymes with Hollywood!)'
next_section_and_step: africa_nigeria:step_1
off_topic:
content_blocks:
- Let's learn about Nigerian culture. What is their film industry called?
next_section_and_step: africa_nigeria:step_1
- section_id: africa_south
title: South Africa
steps:
- step_id: step_1
title: South Africa - The Rainbow Nation
content_blocks:
- '## South Africa - The Rainbow Nation 🦏'
- '**Geography:** Located at the southern tip of Africa'
- '**Capitals:** THREE! Pretoria (executive), Cape Town (legislative), Bloemfontein (judicial)'
- '**Famous for:** Diverse landscapes, wildlife (Big Five: lion, leopard, rhino, elephant, buffalo), and being called the ''Rainbow Nation'' for its multicultural diversity'
- ''
- '**Historical Fact:**'
- Nelson Mandela led the struggle against apartheid and became South Africa's first Black president in 1994, helping to create a democratic, multicultural nation.
- ''
- '**Language Diversity:**'
- South Africa has 11 official languages, including English, Afrikaans, Zulu, and Xhosa!
question: How many official languages does South Africa have?
tokens_for_ai: 'The answer is 11 (mentioned above).
Categorize as:
- correct: Says 11 or eleven
- close: Says a number between 8-15
- confused: Says 1, 2, or 3
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct or close, praise their attention! Share how this linguistic diversity reflects
the country''s multicultural heritage.
'
buckets:
- correct
- close
- confused
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Exactly right - 11 official languages! Explain what this reveals about South African diversity.
metadata_add:
quiz_score: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
close:
ai_feedback:
tokens_for_ai: Very close! South Africa has exactly 11 official languages. Explain why this is significant.
metadata_add:
quiz_score: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused:
content_blocks:
- Actually, South Africa is remarkably diverse! It has 11 official languages.
metadata_add:
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the language diversity section. How many official languages are mentioned?
next_section_and_step: africa_south:step_1
off_topic:
content_blocks:
- Let's focus on South African culture. How many official languages does the country have?
next_section_and_step: africa_south:step_1
- section_id: asia
title: Exploring Asia
steps:
- step_id: step_1
title: Welcome to Asia - Japan
content_blocks:
- '## Welcome to Asia! 🏯'
- Asia is the world's largest continent, covering 30% of Earth's land area and home to 60% of the world's population!
- ''
- '**Let''s visit Japan!**'
- ''
- '**Geography:** An island nation in East Asia, consisting of 4 main islands and thousands of smaller ones'
- '**Capital:** Tokyo'
- '**Famous for:** Technology, anime/manga, cherry blossoms, ancient temples, and a unique blend of tradition and modernity'
- ''
- '**Cultural Fact:**'
- Japan has a deep tradition of respect and harmony. The concept of 'wa' (和) emphasizes peace and balance in relationships.
- Bowing is a traditional greeting showing respect!
- ''
- '**Interesting Note:**'
- 'Japan has more than 6,800 islands, though most people live on the four largest: Honshu, Hokkaido, Kyushu, and Shikoku.'
question: What is the capital of Japan?
tokens_for_ai: 'The answer is Tokyo (mentioned above).
Categorize as:
- correct: Says Tokyo
- close: Names another major Japanese city (Osaka, Kyoto)
- confused_region: Names a capital from another Asian country
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, share a fact about Tokyo being one of the world''s largest metropolitan areas!
'
buckets:
- correct
- close
- confused_region
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Correct! Tokyo is the capital and one of the world's largest cities. Share a fascinating fact about it.
metadata_add:
quiz_score: n+1
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
close:
ai_feedback:
tokens_for_ai: That's an important Japanese city! But the capital is Tokyo. Explain the historical significance of Kyoto if they mentioned it.
metadata_add:
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused_region:
content_blocks:
- That's a capital of another Asian country! Japan's capital is Tokyo.
metadata_add:
countries_visited: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the information about Japan. Which city is the capital?
next_section_and_step: asia:step_1
off_topic:
content_blocks:
- Let's learn about Japan. What is its capital city?
next_section_and_step: asia:step_1
- section_id: europe
title: Exploring Europe
steps:
- step_id: step_1
title: Welcome to Europe - Italy
content_blocks:
- '## Welcome to Europe! 🏰'
- Europe may be small in size, but it's mighty in history, culture, and diversity!
- ''
- '**Let''s visit Italy!**'
- ''
- '**Geography:** A boot-shaped peninsula in Southern Europe, extending into the Mediterranean Sea'
- '**Capital:** Rome'
- '**Famous for:** Ancient Roman history, Renaissance art, delicious cuisine (pizza, pasta!), and beautiful architecture'
- ''
- '**Historical Fact:**'
- Rome was the heart of the Roman Empire, which at its height controlled most of Europe, North Africa, and the Middle East. The saying 'All roads lead to Rome' comes from the extensive Roman road network!
- ''
- '**Cultural Fact:**'
- Italy is home to more UNESCO World Heritage Sites than any other country - 58 sites including the Colosseum, Venice, and Pompeii!
question: What is the capital of Italy, which was also the center of the ancient Roman Empire?
tokens_for_ai: 'The answer is Rome (mentioned multiple times above).
Categorize as:
- correct: Says Rome
- close: Names another major Italian city (Venice, Milan, Florence)
- confused_region: Names a capital from another European country
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, share excitement about Rome''s incredible history spanning over 2,500 years!
'
buckets:
- correct
- close
- confused_region
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Correct! Rome - the Eternal City - has over 2,500 years of history. Share a fascinating fact about it.
metadata_add:
quiz_score: n+1
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
close:
ai_feedback:
tokens_for_ai: That's a beautiful Italian city! But the capital is Rome. Share a fact about the city they mentioned if historically significant.
metadata_add:
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused_region:
content_blocks:
- That's a European capital, but Italy's capital is Rome!
metadata_add:
countries_visited: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the information about Italy. Which city is mentioned as both the capital AND the center of the ancient Roman Empire?
next_section_and_step: europe:step_1
off_topic:
content_blocks:
- Let's learn about Italy. What is its capital city?
next_section_and_step: europe:step_1
- section_id: south_america
title: Exploring South America
steps:
- step_id: step_1
title: Welcome to South America - Brazil
content_blocks:
- '## Welcome to South America! 🦜'
- Home to the Amazon rainforest, the Andes mountains, and incredibly rich biodiversity!
- ''
- '**Let''s visit Brazil!**'
- ''
- '**Geography:** The largest country in South America, covering nearly half the continent'
- '**Capital:** Brasília (planned and built in the 1960s)'
- '**Famous for:** Amazon rainforest, carnival celebrations, football (soccer), and diverse ecosystems from rainforests to beaches'
- ''
- '**Environmental Fact:**'
- The Amazon rainforest, which covers much of Brazil, is sometimes called the 'lungs of the Earth' because it produces about 20% of the world's oxygen!
- ''
- '**Cultural Fact:**'
- Brazil is the only Portuguese-speaking country in South America (most others speak Spanish). Brazilian Portuguese has its own unique accent and expressions!
question: What language is primarily spoken in Brazil?
tokens_for_ai: 'The answer is Portuguese (mentioned above).
Categorize as:
- correct: Says Portuguese
- confused: Says Spanish (common misconception)
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they say Spanish, gently correct and explain this is a common misconception - Brazil
was colonized by Portugal, not Spain! If correct, praise them for knowing this fact.
'
buckets:
- correct
- confused
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Excellent! Many people think Spanish, but Brazil speaks Portuguese due to Portuguese colonization. Share why this is unique in South America.
metadata_add:
quiz_score: n+1
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused:
ai_feedback:
tokens_for_ai: Common misconception! Unlike most of South America, Brazil speaks Portuguese, not Spanish. Explain the historical reason.
metadata_add:
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the cultural fact section. Which language does Brazil speak?
next_section_and_step: south_america:step_1
off_topic:
content_blocks:
- Let's learn about Brazil. What language is primarily spoken there?
next_section_and_step: south_america:step_1
- section_id: oceania
title: Exploring Oceania
steps:
- step_id: step_1
title: Welcome to Oceania - Australia
content_blocks:
- '## Welcome to Oceania! 🏝️'
- A region of islands and nations in the Pacific Ocean!
- ''
- '**Let''s visit Australia!**'
- ''
- '**Geography:** The world''s smallest continent but largest island, located between the Indian and Pacific Oceans'
- '**Capital:** Canberra'
- '**Famous for:** Unique wildlife (kangaroos, koalas, platypuses), the Great Barrier Reef, the Outback, and indigenous Aboriginal culture spanning 65,000+ years'
- ''
- '**Indigenous Heritage:**'
- Aboriginal Australians have the longest continuous culture on Earth - over 65,000 years! They have deep knowledge of the land, sophisticated art traditions, and hundreds of distinct languages.
- ''
- '**Wildlife Fact:**'
- Australia has more unique species than anywhere else! About 80% of its plants, mammals, and reptiles are found nowhere else on Earth.
question: What is the world's largest coral reef system, located off the coast of Australia?
tokens_for_ai: 'The answer is the Great Barrier Reef (mentioned above).
Categorize as:
- correct: Says Great Barrier Reef or just Barrier Reef
- close: Mentions coral reef but not the specific name
- confused: Names another natural wonder in Australia
- limited_effort: Very brief or no answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If correct, share facts about it being visible from space and home to thousands of species!
'
buckets:
- correct
- close
- confused
- limited_effort
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: Correct! The Great Barrier Reef is the world's largest coral reef system and can even be seen from space! Share conservation importance.
metadata_add:
quiz_score: n+1
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
close:
ai_feedback:
tokens_for_ai: You're thinking of the right feature! It's called the Great Barrier Reef. Share impressive facts about it.
metadata_add:
countries_visited: n+1
cultural_facts_learned: n+1
next_section_and_step: choose_continent:step_1
confused:
content_blocks:
- That's an Australian feature, but we're looking for the coral reef! It's the Great Barrier Reef.
metadata_add:
countries_visited: n+1
next_section_and_step: choose_continent:step_1
limited_effort:
content_blocks:
- Look at the information about Australia. What coral reef system is mentioned?
next_section_and_step: oceania:step_1
off_topic:
content_blocks:
- Let's learn about Australia. What is the famous coral reef system off its coast?
next_section_and_step: oceania:step_1
- section_id: choose_continent
title: Continue Your Journey
steps:
- step_id: step_1
title: Choose Next Continent
content_blocks:
- '## Your World Journey Continues! ✈️'
- Great exploring! You're building global knowledge.
- ''
- '**What would you like to do next?**'
- '- Explore another continent (type: Africa, Asia, Europe, South America, or Oceania)'
- '- Finish your journey and see what you''ve learned (type: finish)'
question: Continue exploring or finish your journey?
tokens_for_ai: 'Student chooses to continue or finish.
Categorize as:
- africa: Wants to explore Africa
- asia: Wants to explore Asia
- europe: Wants to explore Europe
- south_america: Wants to explore South America
- oceania: Wants to explore Oceania
- finish: Ready to finish
- off_topic: Unrelated
'
buckets:
- africa
- asia
- europe
- south_america
- oceania
- finish
- off_topic
transitions:
africa:
content_blocks:
- 🌍 Heading to Africa!
metadata_add:
continents_visited: n+1
next_section_and_step: africa:step_1
asia:
content_blocks:
- 🌏 Off to Asia!
metadata_add:
continents_visited: n+1
next_section_and_step: asia:step_1
europe:
content_blocks:
- 🌍 Traveling to Europe!
metadata_add:
continents_visited: n+1
next_section_and_step: europe:step_1
south_america:
content_blocks:
- 🌎 Journey to South America!
metadata_add:
continents_visited: n+1
next_section_and_step: south_america:step_1
oceania:
content_blocks:
- 🌏 Exploring Oceania!
metadata_add:
continents_visited: n+1
next_section_and_step: oceania:step_1
finish:
content_blocks:
- 🌍 Wonderful! Let's reflect on your global journey.
next_section_and_step: conclusion:step_1
off_topic:
content_blocks:
- Choose a continent to explore (Africa, Asia, Europe, South America, Oceania) or type 'finish' to complete your journey.
counts_as_attempt: false
next_section_and_step: choose_continent:step_1
- section_id: conclusion
title: Journey Complete!
steps:
- step_id: step_1
title: Congratulations!
content_blocks:
- '## Congratulations, World Explorer! 🌍🌎🌏'
- You've completed your global geography journey!
- ''
- '**Why geography and cultural awareness matter:**'
- '- Helps us understand global events and connections'
- '- Builds respect and appreciation for diversity'
- '- Reveals how geography shapes culture, history, and daily life'
- '- Prepares us to be global citizens in an interconnected world'
- ''
- '**Remember:**'
- Every region has unique beauty, wisdom, and contributions to humanity.
- Learning about the world helps us see both our differences and our common humanity.
question: What was the most interesting cultural fact or place you learned about? What would you like to explore more deeply?
tokens_for_ai: 'This is a reflection question. Accept any thoughtful response about their learning.
Categorize as:
- thoughtful_reflection: Specific insights about what they learned
- brief_reflection: Short but genuine
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide personalized feedback based on their journey. Acknowledge the places they visited
(from metadata) and encourage continued exploration of world cultures.
'
buckets:
- thoughtful_reflection
- brief_reflection
- limited_effort
- off_topic
transitions:
thoughtful_reflection:
ai_feedback:
tokens_for_ai: Provide thoughtful, personalized feedback about their learning journey. Suggest resources for further exploration of the topics that interested them most.
metadata_add:
activity_completed: 'true'
brief_reflection:
ai_feedback:
tokens_for_ai: Acknowledge their learning and encourage them to continue exploring world geography and cultures.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Thank them for their participation and summarize key geography and cultural facts they encountered.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Let's reflect on your journey. What did you find most interesting about the places you visited?
next_section_and_step: conclusion:step_1

View file

@ -0,0 +1,726 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s understanding of environmental science and sustainability.
Consider:
- Their grasp of ecosystem connections and interdependencies
- Understanding of environmental impacts
- Ability to think about tradeoffs and systems thinking
- Engagement with sustainability concepts
- Quality of their decision-making and reasoning
Provide encouraging feedback and suggestions for how they can apply sustainable thinking in their own lives.
'
sections:
- section_id: introduction
title: Welcome to Environmental Consulting
steps:
- step_id: welcome
title: Welcome Environmental Consultant
content_blocks:
- '# Environmental Science & Sustainability 🌱'
- Welcome, Environmental Consultant!
- ''
- You've been hired to help redesign River City to be more sustainable and environmentally friendly.
- ''
- '**Your mission:**'
- Make decisions that balance environmental protection, economic needs, and quality of life.
- ''
- '**You''ll learn about:**'
- '- Ecosystem interdependencies'
- '- Carbon footprint and climate impact'
- '- Renewable vs non-renewable energy'
- '- Sustainable urban planning'
- '- Biodiversity and habitat protection'
- '- Systems thinking and tradeoffs'
- ''
- '**How it works:**'
- You'll face real-world environmental challenges. Each decision affects the city's Environmental Health Score.
- ''
- Think carefully about both immediate and long-term consequences!
question: Are you ready to create a more sustainable River City?
tokens_for_ai: 'Student is expressing readiness.
Categorize as:
- ready: Positive, ready to begin
- set_language: Setting language preference
- off_topic: Unrelated
'
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- Excellent! Let's start with your first environmental challenge.
metadata_add:
environmental_score: '50'
decisions_made: '0'
next_section_and_step: section_1:step_1
set_language:
content_blocks:
- I'll communicate in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- Let's get started helping River City become more sustainable! Are you ready?
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: section_1
title: Transportation Challenge
steps:
- step_id: step_1
title: Transportation Infrastructure
content_blocks:
- '## Challenge 1: Transportation Infrastructure 🚗🚌'
- '**The Situation:**'
- 'River City has severe traffic congestion. Most residents drive personal cars, creating:'
- '- High carbon emissions'
- '- Air pollution affecting public health'
- '- Traffic jams wasting time and fuel'
- ''
- The city council has budget for ONE major transportation initiative.
- ''
- '**Your options:**'
- '**A) Build more highways** - Reduce traffic jams, support car culture'
- '**B) Expand public transit** - Buses and light rail, less convenient than cars but lower emissions per person'
- '**C) Create bike lanes and pedestrian zones** - Healthiest and greenest option, but only works for shorter distances'
- '**D) Mixed approach** - Smaller improvements to all three, but none will be as effective'
question: Which transportation approach do you recommend? Explain your reasoning considering environmental impact, practicality, and long-term effects.
tokens_for_ai: 'Evaluate their choice and reasoning.
Sustainable choices in order: C (best), B (good), D (mixed), A (worst for environment)
Categorize as:
- sustainable_choice: Chooses B or C with environmental reasoning
- mixed_thinking: Chooses D with awareness of tradeoffs
- unsustainable: Chooses A (highways)
- thoughtful_tradeoff: Any choice with sophisticated understanding of tradeoffs
- limited_effort: Very brief or no reasoning
- asking_clarifying_questions: Needs more information
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide feedback on their environmental reasoning. If they chose highways, explain the
concept of "induced demand" - more highways lead to more driving. If they chose sustainable
options, praise their thinking and explain the benefits. Acknowledge legitimate concerns
about practicality and economic impacts.
'
buckets:
- sustainable_choice
- mixed_thinking
- unsustainable
- thoughtful_tradeoff
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
sustainable_choice:
ai_feedback:
tokens_for_ai: Excellent environmental thinking! Explain the positive impacts of their choice on emissions, health, and urban livability.
metadata_add:
environmental_score: n+10
carbon_reduced: high
decisions_made: n+1
next_section_and_step: section_2:step_1
mixed_thinking:
ai_feedback:
tokens_for_ai: A balanced approach can work! Discuss the tradeoffs and how to maximize environmental benefit within the mixed approach.
metadata_add:
environmental_score: n+5
carbon_reduced: medium
decisions_made: n+1
next_section_and_step: section_2:step_1
unsustainable:
ai_feedback:
tokens_for_ai: Explain 'induced demand' - more highways lead to more driving and sprawl. Suggest how public transit or bike infrastructure could address congestion more sustainably.
metadata_add:
environmental_score: n-5
carbon_reduced: none
decisions_made: n+1
next_section_and_step: section_2:step_1
thoughtful_tradeoff:
ai_feedback:
tokens_for_ai: You're thinking systemically about the tradeoffs! Validate their sophisticated reasoning and provide additional context.
metadata_add:
environmental_score: n+7
carbon_reduced: medium
decisions_made: n+1
next_section_and_step: section_2:step_1
limited_effort:
content_blocks:
- Please think more deeply about the environmental and practical implications of each option. What are the long-term effects?
next_section_and_step: section_1:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question helpfully, providing information about emissions, costs, or practicality as requested.
counts_as_attempt: false
next_section_and_step: section_1:step_1
off_topic:
content_blocks:
- Let's focus on the transportation challenge. Which option do you recommend and why?
next_section_and_step: section_1:step_1
- section_id: section_2
title: Energy Challenge
steps:
- step_id: step_1
title: Energy Infrastructure
content_blocks:
- '## Challenge 2: Energy Infrastructure ⚡🌞'
- '**The Situation:**'
- 'River City''s power currently comes from:'
- '- 70% coal (cheap but high carbon emissions and air pollution)'
- '- 20% natural gas (cleaner than coal but still fossil fuel)'
- '- 10% renewable (solar and wind)'
- ''
- The city wants to transition to cleaner energy. Budget allows for ONE major initiative.
- ''
- '**Your options:**'
- '**A) Build large solar farm** - Clean energy, works great in sunny weather, needs battery storage for nighttime'
- '**B) Invest in wind turbines** - Clean energy, works day and night if windy, some people find them unsightly'
- '**C) Upgrade to natural gas** - Cleaner than coal, much lower cost than renewables, but still emits CO2'
- '**D) Energy efficiency program** - Help residents insulate homes, use LED lights, efficient appliances - reduces total energy needed'
question: Which energy strategy do you recommend? Consider climate impact, reliability, and cost.
tokens_for_ai: 'Evaluate their choice and reasoning.
Sustainability ranking: A or B (excellent), D (good), C (poor - still fossil fuel)
Categorize as:
- renewable_choice: Chooses A or B with climate reasoning
- efficiency_focus: Chooses D understanding that reducing demand is also sustainable
- transitional_thinking: Chooses C as a "bridge" fuel
- systems_thinking: Shows understanding of energy grid complexity
- limited_effort: Very brief
- asking_clarifying_questions: Needs more info
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Discuss their reasoning. If they chose renewables, explain benefits and acknowledge
intermittency challenges. If they chose efficiency, praise reducing demand. If natural
gas, acknowledge it''s cleaner than coal but emphasize it''s still fossil fuel and won''t
meet long-term climate goals.
'
buckets:
- renewable_choice
- efficiency_focus
- transitional_thinking
- systems_thinking
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
renewable_choice:
ai_feedback:
tokens_for_ai: Excellent climate-conscious choice! Explain the long-term benefits of renewable energy for climate and air quality.
metadata_add:
environmental_score: n+10
carbon_reduced: high
renewable_energy: 'true'
decisions_made: n+1
next_section_and_step: section_3:step_1
efficiency_focus:
ai_feedback:
tokens_for_ai: Smart thinking! Reducing energy demand is one of the most cost-effective climate solutions. Explain how efficiency complements renewable energy.
metadata_add:
environmental_score: n+8
carbon_reduced: medium-high
decisions_made: n+1
next_section_and_step: section_3:step_1
transitional_thinking:
ai_feedback:
tokens_for_ai: Natural gas is cleaner than coal, but it's still a fossil fuel. Discuss the difference between a transitional step and a long-term solution for climate goals.
metadata_add:
environmental_score: n+3
carbon_reduced: low
decisions_made: n+1
next_section_and_step: section_3:step_1
systems_thinking:
ai_feedback:
tokens_for_ai: Excellent systems thinking! Validate their sophisticated understanding and provide additional context on grid management.
metadata_add:
environmental_score: n+9
carbon_reduced: high
decisions_made: n+1
next_section_and_step: section_3:step_1
limited_effort:
content_blocks:
- Please provide more reasoning about environmental impact and long-term sustainability. What are the climate implications?
next_section_and_step: section_2:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about renewable energy, costs, or technical details.
counts_as_attempt: false
next_section_and_step: section_2:step_1
off_topic:
content_blocks:
- Let's focus on the energy challenge. Which energy strategy would you recommend?
next_section_and_step: section_2:step_1
- section_id: section_3
title: Land Use Challenge
steps:
- step_id: step_1
title: Green Space vs Development
content_blocks:
- '## Challenge 3: Green Space vs Development 🌳🏢'
- '**The Situation:**'
- River City has a 50-acre plot of undeveloped land with mature forest and a wetland.
- ''
- '**Why the forest and wetland matter:**'
- '- Trees absorb CO2 (carbon sink)'
- '- Wetlands filter water and prevent flooding'
- '- Habitat for dozens of bird species, amphibians, and small mammals'
- '- Cool air and reduce urban heat island effect'
- ''
- The city faces pressure to develop this land.
- ''
- '**Your options:**'
- '**A) Preserve as nature reserve** - Maximum environmental benefit, provides green space for residents, but no economic development'
- '**B) Build affordable housing** - Addresses housing shortage, but removes habitat and green benefits'
- '**C) Mixed-use development** - Preserve 30 acres as park, develop 20 acres with green building standards'
- '**D) Commercial development** - Shopping center, brings jobs and tax revenue, full removal of natural area'
question: What do you recommend for this land? Consider biodiversity, climate impact, and community needs.
tokens_for_ai: 'Evaluate their reasoning about balancing conservation and development.
Sustainability ranking: A (best for environment), C (good compromise), B (mixed), D (worst)
Categorize as:
- conservation_priority: Chooses A with ecological reasoning
- balanced_approach: Chooses C recognizing need to balance multiple goals
- housing_priority: Chooses B emphasizing social needs
- development_focus: Chooses D
- sophisticated_tradeoff: Any choice with nuanced understanding of competing values
- limited_effort: Very brief
- asking_clarifying_questions: Needs more info
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Discuss ecosystem services the forest provides. If they chose preservation, explain the
value of biodiversity and carbon sequestration. If mixed-use, validate the tradeoff thinking.
If development, discuss the irreversibility of habitat loss and the concept of ecosystem services.
'
buckets:
- conservation_priority
- balanced_approach
- housing_priority
- development_focus
- sophisticated_tradeoff
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
conservation_priority:
ai_feedback:
tokens_for_ai: Strong environmental reasoning! Explain the long-term value of ecosystem services and urban green space.
metadata_add:
environmental_score: n+10
biodiversity_protected: high
decisions_made: n+1
next_section_and_step: section_4:step_1
balanced_approach:
ai_feedback:
tokens_for_ai: Good systems thinking! You're balancing environmental protection with community needs. Discuss how to maximize environmental benefit in the developed portion.
metadata_add:
environmental_score: n+7
biodiversity_protected: medium
decisions_made: n+1
next_section_and_step: section_4:step_1
housing_priority:
ai_feedback:
tokens_for_ai: Housing is indeed important! Explore whether there are alternative sites for housing that wouldn't destroy irreplaceable habitat. Discuss the value of ecosystem services.
metadata_add:
environmental_score: n+2
biodiversity_protected: low
decisions_made: n+1
next_section_and_step: section_4:step_1
development_focus:
ai_feedback:
tokens_for_ai: 'Commercial development provides economic benefits, but at the cost of irreplaceable ecosystem services. Discuss what''s lost: carbon storage, water filtration, biodiversity, flood control.'
metadata_add:
environmental_score: n-3
biodiversity_protected: none
decisions_made: n+1
next_section_and_step: section_4:step_1
sophisticated_tradeoff:
ai_feedback:
tokens_for_ai: Excellent analysis of competing values! Validate their nuanced thinking about ecology, economics, and social needs.
metadata_add:
environmental_score: n+8
biodiversity_protected: medium-high
decisions_made: n+1
next_section_and_step: section_4:step_1
limited_effort:
content_blocks:
- Think about what would be permanently lost if the natural area is developed. What ecosystem services does it provide?
next_section_and_step: section_3:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about ecosystem services, biodiversity, or development alternatives.
counts_as_attempt: false
next_section_and_step: section_3:step_1
off_topic:
content_blocks:
- Let's focus on the land use decision. What would you recommend for the 50-acre natural area?
next_section_and_step: section_3:step_1
- section_id: section_4
title: Waste & Circular Economy
steps:
- step_id: step_1
title: Waste Management
content_blocks:
- '## Challenge 4: Waste Management ♻️'
- '**The Situation:**'
- 'River City sends 80% of waste to landfills, where it:'
- '- Takes up space (landfills filling up)'
- '- Produces methane (a potent greenhouse gas)'
- '- Wastes valuable materials'
- ''
- Only 20% is currently recycled.
- ''
- '**Understanding the circular economy:**'
- Instead of 'take, make, dispose,' we can 'reduce, reuse, recycle' - keeping materials in use.
- ''
- '**Your options:**'
- '**A) Mandatory recycling & composting** - Requires sorting, provides trucks, reduces landfill waste by ~50%'
- '**B) Ban single-use plastics** - Eliminates major source of waste and ocean pollution'
- '**C) Waste-to-energy incinerator** - Reduces landfill volume and generates electricity, but produces air emissions'
- '**D) Producer responsibility laws** - Require manufacturers to take back and recycle their products'
question: Which waste strategy would you implement? Consider environmental impact and systemic change.
tokens_for_ai: 'Evaluate their understanding of circular economy and waste hierarchy.
Sustainability ranking: A (good), B (good), D (excellent - addresses root cause), C (mixed - better than landfill but not ideal)
Categorize as:
- circular_economy: Chooses A or D with understanding of reuse/recycling
- pollution_prevention: Chooses B to eliminate plastic waste
- technical_solution: Chooses C (incineration)
- systems_thinking: Shows understanding of upstream vs downstream solutions
- limited_effort: Very brief
- asking_clarifying_questions: Needs more info
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Discuss the waste hierarchy: reduce > reuse > recycle > recover energy > landfill.
If they chose producer responsibility, praise thinking about root causes. If recycling,
good but also mention reducing consumption. If incineration, discuss why it''s better
than landfill but not as good as preventing waste.
'
buckets:
- circular_economy
- pollution_prevention
- technical_solution
- systems_thinking
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
circular_economy:
ai_feedback:
tokens_for_ai: Excellent! You understand circular economy principles. Explain how keeping materials in use reduces resource extraction and emissions.
metadata_add:
environmental_score: n+8
waste_reduction: high
decisions_made: n+1
next_section_and_step: section_5:step_1
pollution_prevention:
ai_feedback:
tokens_for_ai: Great prevention thinking! Eliminating single-use plastics prevents pollution at the source. Discuss how this addresses ocean plastic crisis.
metadata_add:
environmental_score: n+9
waste_reduction: high
plastic_reduction: 'true'
decisions_made: n+1
next_section_and_step: section_5:step_1
technical_solution:
ai_feedback:
tokens_for_ai: Incineration is better than landfilling, but it's still treating symptoms rather than causes. Discuss the waste hierarchy and how prevention is better than end-of-pipe solutions.
metadata_add:
environmental_score: n+4
waste_reduction: medium
decisions_made: n+1
next_section_and_step: section_5:step_1
systems_thinking:
ai_feedback:
tokens_for_ai: Excellent systems thinking! You're looking at root causes rather than just managing waste. Validate their sophisticated approach.
metadata_add:
environmental_score: n+10
waste_reduction: high
decisions_made: n+1
next_section_and_step: section_5:step_1
limited_effort:
content_blocks:
- 'Think about the waste hierarchy: Is it better to prevent waste or manage it after it''s created?'
next_section_and_step: section_4:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about waste management, recycling, or circular economy concepts.
counts_as_attempt: false
next_section_and_step: section_4:step_1
off_topic:
content_blocks:
- Let's focus on waste management. Which strategy would you recommend?
next_section_and_step: section_4:step_1
- section_id: section_5
title: Food & Agriculture
steps:
- step_id: step_1
title: Sustainable Food Systems
content_blocks:
- '## Challenge 5: Sustainable Food Systems 🌾'
- '**The Situation:**'
- 'River City imports 90% of its food from distant farms, which:'
- '- Requires energy for transportation (high carbon footprint)'
- '- Makes city vulnerable to supply disruptions'
- '- Disconnects residents from food sources'
- ''
- '**Environmental context:**'
- Food systems account for ~25% of global greenhouse gas emissions
- Agriculture uses 70% of freshwater globally
- Industrial farming often depletes soil and harms biodiversity
- ''
- '**Your options:**'
- '**A) Support local organic farms** - Lower transportation emissions, no pesticides, higher cost to consumers'
- '**B) Urban farming program** - Rooftop gardens, community gardens, very local but limited scale'
- '**C) Promote plant-based diets** - Meat production has 10-50x more emissions than plants, but culturally challenging'
- '**D) Reduce food waste** - 30-40% of food is wasted; composting and redistribution can help'
question: Which food sustainability strategy would you prioritize? Consider climate impact, feasibility, and food security.
tokens_for_ai: 'Evaluate their understanding of food system environmental impacts.
All options have merit! C (plant-based) has highest climate impact potential, D (waste reduction)
is high-impact and feasible, A and B support local food systems.
Categorize as:
- climate_focused: Chooses C (plant-based) with emissions reasoning
- waste_reduction: Chooses D understanding the scale of food waste
- local_food: Chooses A or B for local benefits
- holistic_thinking: Shows understanding of multiple interconnected issues
- limited_effort: Very brief
- asking_clarifying_questions: Needs more info
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'All choices have environmental merit! Validate their reasoning and provide context about
the environmental impacts they''re addressing. Discuss connections between food, climate,
biodiversity, and resource use.
'
buckets:
- climate_focused
- waste_reduction
- local_food
- holistic_thinking
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
climate_focused:
ai_feedback:
tokens_for_ai: You've identified one of the highest-impact climate solutions! Explain why animal agriculture has such large emissions, while acknowledging cultural and practical challenges.
metadata_add:
environmental_score: n+10
carbon_reduced: very-high
decisions_made: n+1
next_section_and_step: conclusion:step_1
waste_reduction:
ai_feedback:
tokens_for_ai: 'Excellent choice! Food waste is a massive but often overlooked problem. Explain the triple benefit: less production needed, less methane from landfills, food reaches hungry people.'
metadata_add:
environmental_score: n+9
waste_reduction: high
decisions_made: n+1
next_section_and_step: conclusion:step_1
local_food:
ai_feedback:
tokens_for_ai: Good thinking about local food systems! Explain benefits for local economy, food security, and reducing transportation emissions. Note that production methods matter more than distance for some foods.
metadata_add:
environmental_score: n+7
local_food: 'true'
decisions_made: n+1
next_section_and_step: conclusion:step_1
holistic_thinking:
ai_feedback:
tokens_for_ai: Excellent holistic understanding of food system sustainability! Validate their sophisticated systems thinking about multiple interconnected issues.
metadata_add:
environmental_score: n+10
decisions_made: n+1
next_section_and_step: conclusion:step_1
limited_effort:
content_blocks:
- 'Think about the full lifecycle of food: production, transportation, consumption, and waste. Where are the biggest environmental impacts?'
next_section_and_step: section_5:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about food system environmental impacts, emissions, or sustainability strategies.
counts_as_attempt: false
next_section_and_step: section_5:step_1
off_topic:
content_blocks:
- Let's focus on food sustainability. Which strategy would you recommend?
next_section_and_step: section_5:step_1
- section_id: conclusion
title: Sustainability Report
steps:
- step_id: step_1
title: Congratulations!
content_blocks:
- '## Congratulations, Environmental Consultant! 🌍'
- You've completed your sustainability consulting project for River City!
- ''
- '**Key environmental concepts you explored:**'
- ✓ Carbon footprint and climate impact
- ✓ Renewable vs fossil fuel energy
- ✓ Ecosystem services and biodiversity
- ✓ Circular economy and waste hierarchy
- ✓ Sustainable food systems
- ✓ Systems thinking and tradeoffs
- ''
- '**Why sustainability matters:**'
- 'Human wellbeing depends on healthy ecosystems - they provide:'
- '- Clean air and water'
- '- Climate regulation'
- '- Food and materials'
- '- Recreation and beauty'
- ''
- '**The challenge:**'
- We must meet human needs while protecting the Earth's systems that support all life.
- ''
- '**What you learned:**'
- '- Environmental problems are interconnected (systems thinking)'
- '- Choices have both immediate and long-term consequences'
- '- Prevention is better than treating symptoms'
- '- We can balance environmental protection with human needs through thoughtful design'
question: Reflecting on your decisions, what's one action you could take in your own life to reduce your environmental impact? What sustainability principle resonated most with you?
tokens_for_ai: 'This is a reflection question. Accept any thoughtful response about personal application
of sustainability principles.
Categorize as:
- specific_commitment: Identifies concrete action they plan to take
- thoughtful_reflection: Meaningful reflection on what they learned
- basic_reflection: Brief but genuine
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide personalized, encouraging feedback. Acknowledge the environmental decisions they
made throughout the activity. Emphasize that individual actions matter AND we need systemic
change. Encourage them to think about sustainability in their daily choices and to advocate
for environmental protection in their communities.
'
buckets:
- specific_commitment
- thoughtful_reflection
- basic_reflection
- limited_effort
- off_topic
transitions:
specific_commitment:
ai_feedback:
tokens_for_ai: Wonderful! Your specific commitment shows you're ready to apply what you learned. Encourage and support their action plan. Remind them that individual actions AND systemic advocacy both matter.
metadata_add:
activity_completed: 'true'
thoughtful_reflection:
ai_feedback:
tokens_for_ai: Excellent reflection on sustainability principles! Provide encouragement and suggest ways to apply these concepts in daily life.
metadata_add:
activity_completed: 'true'
basic_reflection:
ai_feedback:
tokens_for_ai: Thank them for engaging with environmental challenges. Summarize key takeaways and encourage sustainable thinking.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Acknowledge their completion and encourage them to consider environmental impacts in their daily decisions.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Let's reflect on sustainability. What action could you take personally to reduce environmental impact?
next_section_and_step: conclusion:step_1

View file

@ -0,0 +1,827 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s development of media literacy skills.
Consider:
- Their ability to identify credible vs unreliable sources
- Recognition of bias and propaganda techniques
- Understanding of fact-checking methods
- Critical thinking about information sources
- Application of media literacy principles
Provide encouraging feedback and emphasize the importance of these skills in the digital age.
'
sections:
- section_id: introduction
title: Welcome to Media Literacy
steps:
- step_id: welcome
title: Welcome to Media Literacy
content_blocks:
- '# Media Literacy & Information Evaluation 📰'
- Welcome to the world of critical media consumption!
- ''
- In today's information-rich world, the ability to evaluate sources is essential.
- ''
- '**You''ll learn to:**'
- '- Identify credible vs unreliable sources'
- '- Recognize bias and propaganda techniques'
- '- Fact-check claims effectively'
- '- Detect emotional manipulation'
- '- Understand how misinformation spreads'
- '- Become a savvy information consumer'
- ''
- '**Why this matters:**'
- Every day we're exposed to thousands of messages - news, ads, social media posts.
- Some are accurate, some are biased, some are deliberately false.
- Media literacy helps you navigate this landscape and make informed decisions.
question: Ready to sharpen your information evaluation skills?
tokens_for_ai: 'Student is expressing readiness.
Categorize as:
- ready: Positive, ready to begin
- set_language: Setting language preference
- off_topic: Unrelated
'
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- Excellent! Let's start with the basics of source evaluation.
metadata_add:
misinformation_detected: '0'
sources_verified: '0'
next_section_and_step: section_1:step_1
set_language:
content_blocks:
- I'll communicate in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- Let's begin developing your media literacy skills! Are you ready?
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: section_1
title: Evaluating Sources
steps:
- step_id: step_1
title: Understanding Source Credibility
content_blocks:
- '## Understanding Source Credibility 🔍'
- Not all information sources are equally reliable.
- ''
- '**Key questions to ask:**'
- '- **Who created this?** (Author, organization)'
- '- **What''s their expertise?** (Credentials, experience)'
- '- **What''s their motive?** (Inform, persuade, sell, entertain?)'
- '- **Is it verifiable?** (Can you check the facts?)'
- '- **Who else reports this?** (Corroboration from other sources)'
- ''
- '**Example article to evaluate:**'
- ''
- '**Title:** ''Scientists Confirm Chocolate Cures All Diseases'''
- '**Source:** ChocoLovers Blog'
- '**Author:** No author listed'
- '**Content:** Claims a new study proves chocolate cures cancer, diabetes, and heart disease. No study is named or linked. Article includes ads for chocolate products.'
- '**No other news sources are reporting this story.**'
question: Is this a credible source? Why or why not? What red flags do you notice?
tokens_for_ai: 'This is clearly NOT credible. Red flags:
- Extraordinary claim ("cures ALL diseases")
- No author credentials
- No named study or link to research
- Biased source (ChocoLovers Blog)
- Financial motive (chocolate ads)
- No corroboration from other sources
- Lacks scientific plausibility
Categorize as:
- correctly_identified: Recognizes this is not credible and identifies multiple red flags
- partially_correct: Sees it''s suspicious but misses some red flags
- missed_red_flags: Thinks it might be credible or only sees one red flag
- limited_effort: Very brief answer
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Praise identification of red flags! Walk through all the warning signs if they missed any.
Emphasize: extraordinary claims require extraordinary evidence, check for conflicts of
interest, and verify with multiple independent sources.
'
buckets:
- correctly_identified
- partially_correct
- missed_red_flags
- limited_effort
- off_topic
transitions:
correctly_identified:
ai_feedback:
tokens_for_ai: 'Excellent source evaluation! You identified the key red flags. Explain the principle: extraordinary claims require extraordinary evidence.'
metadata_add:
score: n+2
misinformation_detected: n+1
next_section_and_step: section_1:step_2
partially_correct:
ai_feedback:
tokens_for_ai: Good critical thinking! You spotted some red flags. Point out any additional warning signs they missed.
metadata_add:
score: n+1
misinformation_detected: n+1
next_section_and_step: section_1:step_2
missed_red_flags:
ai_feedback:
tokens_for_ai: 'Let''s examine this more carefully. Walk through the red flags: no named study, biased source, extraordinary claims, financial motive, no corroboration.'
next_section_and_step: section_1:step_1
limited_effort:
content_blocks:
- Take time to analyze this carefully. Look at the source, the claims, the evidence provided, and whether other sources report this.
next_section_and_step: section_1:step_1
off_topic:
content_blocks:
- Let's focus on evaluating this article. Is it credible? What red flags do you see?
next_section_and_step: section_1:step_1
- step_id: step_2
title: Comparing Sources
content_blocks:
- '## Comparing Sources 📊'
- Great work! Now let's compare different sources on the same topic.
- ''
- '**Topic: A new medical treatment**'
- ''
- '**Source A:**'
- '- Journal of Medicine (peer-reviewed)'
- '- Authors: Dr. Smith et al., university researchers'
- '- Reports: ''Preliminary study of 200 patients shows 15% improvement in symptoms'''
- '- Lists limitations and notes more research needed'
- ''
- '**Source B:**'
- '- HealthMiracles.com'
- '- No author listed'
- '- Claims: ''Revolutionary cure helps 99% of patients!'''
- '- Sells the treatment for $299'
- '- No peer review or scientific citation'
question: Which source is more credible, and why? What makes Source A different from Source B?
tokens_for_ai: 'Source A is clearly more credible:
- Peer-reviewed journal
- Named researchers with credentials
- Modest, specific claims (15%, not 99%)
- Acknowledges limitations
- No financial conflict
Source B has red flags:
- No author/credentials
- Extraordinary claims (99%)
- Selling the product (financial motive)
- No peer review
Categorize as:
- correct_analysis: Identifies Source A as more credible with good reasoning
- partial_understanding: Gets the right answer but incomplete reasoning
- confused: Doesn''t clearly distinguish credibility
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they correctly identify A, praise their analysis! Explain peer review process and
why modest claims with limitations are actually MORE trustworthy than extraordinary
promises. Discuss financial conflicts of interest.
'
buckets:
- correct_analysis
- partial_understanding
- confused
- limited_effort
- off_topic
transitions:
correct_analysis:
ai_feedback:
tokens_for_ai: 'Excellent! You understand the hallmarks of credible scientific reporting: peer review, transparency about limitations, and absence of financial conflicts. Explain why modest claims are more trustworthy.'
metadata_add:
score: n+2
sources_verified: n+1
next_section_and_step: section_2:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re on the right track! Expand on the specific factors that make Source A more trustworthy: peer review, credentialed authors, modest claims, acknowledged limitations.'
metadata_add:
score: n+1
sources_verified: n+1
next_section_and_step: section_2:step_1
confused:
content_blocks:
- '**Key principle:** When evaluating sources, look for transparency, credentials, peer review, and absence of financial conflicts.'
- Which source has these qualities?
next_section_and_step: section_1:step_2
limited_effort:
content_blocks:
- 'Compare them systematically: Who wrote it? Is it peer-reviewed? Are the claims modest or extraordinary? Is someone selling something?'
next_section_and_step: section_1:step_2
off_topic:
content_blocks:
- Let's compare these two sources. Which is more credible and why?
next_section_and_step: section_1:step_2
- section_id: section_2
title: Recognizing Bias
steps:
- step_id: step_1
title: Understanding Bias and Framing
content_blocks:
- '## Understanding Bias and Framing 📰'
- All sources have some perspective, but recognizing bias helps you get fuller picture.
- ''
- '**Types of bias:**'
- '- **Selection bias:** What facts are included or omitted?'
- '- **Framing bias:** How is the story presented?'
- '- **Word choice:** Loaded language vs neutral language'
- ''
- '**Example: Same event, two headlines:**'
- ''
- '**Headline A:** ''Protesters disrupt traffic, cause chaos downtown'''
- '**Headline B:** ''Citizens march peacefully for voting rights'''
- ''
- '**Facts:** 5,000 people marched. Two streets closed for 3 hours. No violence or arrests. March was about voting rights legislation.'
question: How does each headline frame the event differently? What does word choice reveal about each source's perspective?
tokens_for_ai: 'Headline A uses negative framing: "disrupt," "chaos," focuses on inconvenience
Headline B uses positive framing: "peacefully," "citizens," emphasizes purpose
Both are describing the same factual event but with different emphasis and word choice.
Categorize as:
- recognizes_bias: Identifies how each headline frames the story differently and discusses word choice
- partial_recognition: Sees some difference but doesn''t fully analyze framing
- missed_bias: Doesn''t recognize the bias or framing differences
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they recognize bias, excellent! Explain how both can be factually accurate yet
emphasize different aspects. Discuss how word choice ("disrupt" vs "march," "chaos" vs
"peaceful") shapes perception. Emphasize importance of reading multiple sources.
'
buckets:
- recognizes_bias
- partial_recognition
- missed_bias
- limited_effort
- off_topic
transitions:
recognizes_bias:
ai_feedback:
tokens_for_ai: Excellent analysis of bias and framing! Explain how consuming news from multiple perspectives helps us understand the full picture.
metadata_add:
score: n+2
bias_identified: n+1
next_section_and_step: section_2:step_2
partial_recognition:
ai_feedback:
tokens_for_ai: 'You''re seeing the difference! Dig deeper into the specific words used: ''disrupt'' vs ''march,'' ''chaos'' vs ''peaceful.'' How does this language shape our perception?'
metadata_add:
score: n+1
bias_identified: n+1
next_section_and_step: section_2:step_2
missed_bias:
content_blocks:
- 'Look closely at the word choices: ''disrupt'' vs ''march,'' ''chaos'' vs ''peaceful.'''
- One headline emphasizes inconvenience, the other emphasizes the purpose and peaceful nature.
- Same facts, different framing!
next_section_and_step: section_2:step_1
limited_effort:
content_blocks:
- Compare the specific words used in each headline. What feeling does each create about the protest?
next_section_and_step: section_2:step_1
off_topic:
content_blocks:
- Let's analyze these headlines. How does each one frame the protest differently?
next_section_and_step: section_2:step_1
- step_id: step_2
title: Emotional Manipulation vs Facts
content_blocks:
- '## Emotional Manipulation vs Facts 💭'
- Some content uses emotional triggers to bypass critical thinking.
- ''
- '**Propaganda techniques to watch for:**'
- '- **Fear appeals:** ''If you don''t act now, disaster will happen!'''
- '- **Bandwagon:** ''Everyone believes this, don''t be left out!'''
- '- **Name-calling:** Attacking people rather than addressing arguments'
- '- **Glittering generalities:** Vague positive language without substance'
- '- **Appeals to emotion** over evidence'
- ''
- '**Example social media post:**'
- ''
- _'They're trying to hide the TRUTH from you! Don't be a sheep! Share this before it's deleted! Everyone who's smart knows this is happening! Wake up!'_
- ''
- The post contains no specific claims, sources, or verifiable facts.
question: What propaganda techniques do you see in this post? What red flags indicate this is trying to manipulate rather than inform?
tokens_for_ai: 'Propaganda techniques present:
- Fear/urgency ("before it''s deleted!")
- Bandwagon ("everyone who''s smart knows")
- Name-calling ("sheep")
- Emotional language ("TRUTH," "Wake up!")
- Vague claims with no specifics
- No sources or verifiable facts
Categorize as:
- identified_manipulation: Recognizes multiple propaganda techniques
- partial_recognition: Sees some manipulation tactics
- missed_manipulation: Doesn''t recognize the manipulative techniques
- limited_effort: Very brief
- asking_clarifying_questions: Requests explanation
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they identify manipulation, excellent! Explain how these techniques are designed to
bypass critical thinking by triggering emotional responses. Contrast with informative
content that provides specific, verifiable claims.
'
buckets:
- identified_manipulation
- partial_recognition
- missed_manipulation
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
identified_manipulation:
ai_feedback:
tokens_for_ai: Excellent! You spotted the emotional manipulation tactics. Explain how credible information provides specific, verifiable facts rather than emotional appeals.
metadata_add:
score: n+3
misinformation_detected: n+1
bias_identified: n+1
next_section_and_step: section_3:step_1
partial_recognition:
ai_feedback:
tokens_for_ai: 'Good start! Point out additional manipulation techniques they missed: fear/urgency, bandwagon, name-calling, vague claims without specifics.'
metadata_add:
score: n+1
misinformation_detected: n+1
next_section_and_step: section_3:step_1
missed_manipulation:
content_blocks:
- 'Look for emotional triggers: fear (''before it''s deleted''), peer pressure (''everyone who''s smart''), and name-calling (''sheep'').'
- 'Notice: no specific facts, no sources, just emotional language designed to make you share without thinking.'
next_section_and_step: section_2:step_2
limited_effort:
content_blocks:
- Analyze this post carefully. Is it providing facts and sources, or is it using emotions and pressure tactics?
next_section_and_step: section_2:step_2
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about propaganda techniques and emotional manipulation.
counts_as_attempt: false
next_section_and_step: section_2:step_2
off_topic:
content_blocks:
- Let's analyze this social media post. What manipulation techniques do you notice?
next_section_and_step: section_2:step_2
- section_id: section_3
title: Fact-Checking Methods
steps:
- step_id: step_1
title: How to Fact-Check Claims
content_blocks:
- '## How to Fact-Check Claims ✓'
- When you encounter a surprising claim, you can verify it!
- ''
- '**Fact-checking steps:**'
- 1. **Check the original source** - Is the claim based on a real study/document?
- 2. **Verify with fact-checking sites** - Snopes, FactCheck.org, PolitiFact, etc.
- 3. **Look for corroboration** - Do credible news sources report this?
- 4. **Check the date** - Is this old news being presented as new?
- 5. **Reverse image search** - Are images real or manipulated?
- 6. **Consider expertise** - Are experts in the field confirming this?
- ''
- '**Claim to evaluate:**'
- ''
- '_''Breaking: Government announces pizza is now a vegetable!''_'
- ''
- '**Quick research reveals:**'
- '- This claim went viral in 2011'
- '- What actually happened: Congress ruled that tomato paste on pizza counts toward vegetable requirements in school lunches'
- '- Pizza itself was NOT declared a vegetable'
- '- The claim misrepresents the actual policy'
question: Is the viral claim accurate? What fact-checking steps revealed the truth?
tokens_for_ai: 'The claim is INACCURATE/MISLEADING:
- Pizza was NOT declared a vegetable
- The actual policy was about tomato paste servings in school lunches
- The headline distorts what actually happened
- Checking the date reveals this is old news
Fact-checking revealed: date checking, finding original source, understanding context
Categorize as:
- correctly_debunked: Identifies the claim as false/misleading and explains why
- partial_understanding: Sees something wrong but doesn''t fully explain
- fooled: Thinks the claim is accurate
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they debunk it, excellent! Explain how viral claims often distort real events to
create outrage. Discuss importance of checking dates and finding original sources.
This teaches the difference between "false" and "misleading."
'
buckets:
- correctly_debunked
- partial_understanding
- fooled
- limited_effort
- off_topic
transitions:
correctly_debunked:
ai_feedback:
tokens_for_ai: Excellent fact-checking! You identified that the viral claim distorts the real policy. Explain how misleading headlines often contain a grain of truth but misrepresent the reality.
metadata_add:
score: n+2
misinformation_detected: n+1
sources_verified: n+1
next_section_and_step: section_3:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking critically! Clarify the distinction: the policy was about tomato paste portions, not declaring pizza a vegetable. The headline distorts reality.'
metadata_add:
score: n+1
sources_verified: n+1
next_section_and_step: section_3:step_2
fooled:
content_blocks:
- 'Look at what ACTUALLY happened versus the headline: The policy was about counting tomato paste as a vegetable serving, not declaring pizza itself a vegetable.'
- The viral claim distorts the truth to create outrage!
next_section_and_step: section_3:step_1
limited_effort:
content_blocks:
- Read the fact-check information carefully. What's the difference between the viral claim and what actually happened?
next_section_and_step: section_3:step_1
off_topic:
content_blocks:
- Let's fact-check this claim. Is it accurate based on the research provided?
next_section_and_step: section_3:step_1
- step_id: step_2
title: Spotting Manipulated Media
content_blocks:
- '## Advanced: Spotting Deepfakes and Manipulated Media 🎭'
- Technology now allows realistic fake images, videos, and audio.
- ''
- '**Warning signs of manipulated media:**'
- '- Unusual lighting or shadows'
- '- Mismatched details (watch, background elements)'
- '- Unnatural movement or expressions (in video)'
- '- Context seems wrong (location, date, people present)'
- '- No other sources have this image/video'
- ''
- '**Best practice:** Use reverse image search (Google Images, TinEye) to find original source'
- ''
- '**Scenario:**'
- You see a photo claiming to show a celebrity at a political rally yesterday.
- ''
- '**Reverse image search reveals:**'
- The same photo appears in an article from 3 years ago at a completely different event.
- The background has been digitally altered.
question: What does this tell you about the photo? Why is reverse image search such a valuable tool?
tokens_for_ai: 'The photo is FAKE/MANIPULATED:
- Original image is from a different event years ago
- Background has been altered
- This is misinformation
Reverse image search helps:
- Find original context
- Detect recycled/manipulated images
- Verify when and where photo was actually taken
Categorize as:
- understood_manipulation: Recognizes the photo is fake and explains the value of reverse search
- partial_understanding: Gets general idea but incomplete
- confused: Doesn''t fully grasp the manipulation
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they understand, excellent! Explain how old images are often recycled to create
false narratives. Emphasize that reverse image search is a powerful tool anyone can
use to verify visual claims.
'
buckets:
- understood_manipulation
- partial_understanding
- confused
- limited_effort
- off_topic
transitions:
understood_manipulation:
ai_feedback:
tokens_for_ai: Perfect! You understand how images can be manipulated and recycled. Explain how reverse image search helps verify visual claims and find original context.
metadata_add:
score: n+2
misinformation_detected: n+1
next_section_and_step: section_4:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: Good thinking! Emphasize that reverse image search reveals when images are recycled from different contexts or digitally altered.
metadata_add:
score: n+1
next_section_and_step: section_4:step_1
confused:
content_blocks:
- The photo is fake - it's from a different event years ago with an altered background.
- Reverse image search helps you find where images really came from!
next_section_and_step: section_3:step_2
limited_effort:
content_blocks:
- Think about what it means that the same photo appears from years ago in a different context.
next_section_and_step: section_3:step_2
off_topic:
content_blocks:
- Let's analyze this scenario. What does the reverse image search reveal?
next_section_and_step: section_3:step_2
- section_id: section_4
title: Building Your Media Diet
steps:
- step_id: step_1
title: Creating a Healthy Information Diet
content_blocks:
- '## Creating a Healthy Information Diet 🧠'
- You've learned to spot misinformation, bias, and manipulation!
- ''
- '**Now: Building good habits**'
- ''
- '**Principles for healthy media consumption:**'
- ''
- ✓ **Diverse sources** - Read multiple perspectives, not just sources you agree with
- ✓ **Primary sources** - When possible, check original documents/studies, not just summaries
- ✓ **Slow down** - Resist the urge to share immediately; verify first
- ✓ **Check your emotions** - If content makes you very angry/scared, pause and fact-check
- ✓ **Know the difference** - News, opinion, satire, and propaganda are different
- ✓ **Digital hygiene** - Regularly audit your information sources
- ''
- '**Question:**'
- You see a shocking headline that confirms something you already believe.
- ''
- '**What should you do BEFORE sharing it?**'
question: What steps should you take before sharing a shocking claim, even if it confirms your beliefs?
tokens_for_ai: 'Good practices before sharing:
- Check the source (is it credible?)
- Verify with fact-checking sites
- Look for corroboration from other sources
- Check if it''s satire
- Be extra skeptical of claims that confirm your biases (confirmation bias)
- Read beyond the headline
Categorize as:
- comprehensive_approach: Lists multiple verification steps
- basic_verification: Mentions checking source or fact-checking
- confirmation_bias_awareness: Recognizes need to be extra skeptical of agreeable claims
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they show verification thinking, excellent! Emphasize the importance of being
especially skeptical of claims we WANT to believe (confirmation bias). Discuss the
responsibility of sharing in the digital age - false information spreads faster than
corrections.
'
buckets:
- comprehensive_approach
- basic_verification
- confirmation_bias_awareness
- limited_effort
- off_topic
transitions:
comprehensive_approach:
ai_feedback:
tokens_for_ai: Excellent! You've internalized the verification process. Emphasize that sharing misinformation, even unintentionally, contributes to the problem.
metadata_add:
score: n+3
next_section_and_step: conclusion:step_1
basic_verification:
ai_feedback:
tokens_for_ai: 'Good instinct to verify! Expand on additional steps: check multiple sources, use fact-checking sites, be extra skeptical of claims you want to believe.'
metadata_add:
score: n+2
next_section_and_step: conclusion:step_1
confirmation_bias_awareness:
ai_feedback:
tokens_for_ai: Excellent self-awareness! Recognizing confirmation bias is crucial. We're all more likely to believe and share claims that confirm what we already think.
metadata_add:
score: n+3
next_section_and_step: conclusion:step_1
limited_effort:
content_blocks:
- 'Think about the verification steps you''ve learned: checking sources, fact-checking sites, looking for corroboration, being skeptical of claims you want to believe.'
next_section_and_step: section_4:step_1
off_topic:
content_blocks:
- Let's think about responsible information sharing. What should you do before sharing a claim?
next_section_and_step: section_4:step_1
- section_id: conclusion
title: Media Literacy Graduate
steps:
- step_id: step_1
title: Congratulations!
content_blocks:
- '## Congratulations, Media Literacy Expert! 🎓'
- You've developed critical skills for navigating the information landscape!
- ''
- '**What you''ve learned:**'
- ✓ How to evaluate source credibility
- ✓ Recognizing bias and framing
- ✓ Identifying propaganda and emotional manipulation
- ✓ Fact-checking techniques (including reverse image search)
- ✓ Building a healthy media diet
- ✓ Spotting misinformation before it spreads
- ''
- '**Why this matters in the digital age:**'
- '- Information spreads faster than ever before'
- '- Misinformation can influence elections, health decisions, and social trust'
- '- Critical thinking is essential for democracy'
- '- You have power AND responsibility as an information consumer and sharer'
- ''
- '**Remember:**'
- _'The inability to distinguish fact from fiction is the defining challenge of our age.'_
- ''
- You now have the tools to meet this challenge.
- ''
- '**Your media literacy checklist:**'
- '- Check the source'
- '- Verify with multiple sources'
- '- Watch for emotional manipulation'
- '- Fact-check before sharing'
- '- Consume diverse perspectives'
- '- Stay curious and humble'
question: How will you apply media literacy in your daily life? What's one specific habit you want to develop to be a more critical information consumer?
tokens_for_ai: 'This is a reflection question about applying media literacy skills.
Categorize as:
- specific_commitment: Identifies a concrete practice they''ll adopt
- thoughtful_reflection: Meaningful reflection on importance of media literacy
- basic_reflection: Brief but genuine
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide encouraging, personalized feedback. Emphasize that media literacy is a lifelong
practice, not a destination. Acknowledge the challenges of the information age and praise
their commitment to critical thinking. Remind them that every time they verify before
sharing, they help combat misinformation.
'
buckets:
- specific_commitment
- thoughtful_reflection
- basic_reflection
- limited_effort
- off_topic
transitions:
specific_commitment:
ai_feedback:
tokens_for_ai: Excellent commitment! Support their specific practice and emphasize how individual critical thinking contributes to a healthier information ecosystem.
metadata_add:
activity_completed: 'true'
thoughtful_reflection:
ai_feedback:
tokens_for_ai: Thoughtful reflection! Encourage them to make verification a habit and to help others develop media literacy too.
metadata_add:
activity_completed: 'true'
basic_reflection:
ai_feedback:
tokens_for_ai: Thank them for engaging with media literacy. Emphasize the importance of these skills in the digital age.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Acknowledge their completion and encourage them to practice verification before sharing information.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Let's reflect on your learning. How will you apply media literacy skills going forward?
next_section_and_step: conclusion:step_1

View file

@ -0,0 +1,820 @@
default_max_attempts_per_step: 3
tokens_for_ai_rubric: 'Evaluate the student''s understanding of American history and historical thinking.
Consider:
- Their grasp of historical cause and effect
- Ability to analyze primary sources
- Understanding of multiple perspectives
- Critical thinking about historical events
- Connection of past events to present issues
Provide encouraging feedback and suggest areas for deeper historical exploration.
'
sections:
- section_id: introduction
title: Welcome to American History
steps:
- step_id: welcome
title: Welcome, Historian
content_blocks:
- '# American History: A Critical Journey 🇺🇸'
- Welcome to an exploration of American history that goes beyond dates and names.
- ''
- '**In this journey, you''ll:**'
- '- Analyze primary sources from different historical periods'
- '- Examine cause and effect in historical events'
- '- Consider multiple perspectives and viewpoints'
- '- Think critically about America''s founding principles and their evolution'
- '- Connect historical events to contemporary issues'
- ''
- '**This is advanced history:**'
- You'll be challenged to think like a historian - questioning sources, understanding context, and forming evidence-based conclusions.
- ''
- Ready to dive deep into American history?
question: Are you ready to explore American history through critical thinking and primary sources?
tokens_for_ai: 'Student expressing readiness.
Categorize as:
- ready: Positive, ready to begin
- set_language: Setting language preference
- off_topic: Unrelated
'
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- Excellent! Let's begin with the foundations of American democracy.
metadata_add:
period: colonial
next_section_and_step: founding_principles:step_1
set_language:
content_blocks:
- I'll communicate in your preferred language.
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- Let's begin our historical journey. Are you ready to explore American history?
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: founding_principles
title: Founding Principles and the Constitution
steps:
- step_id: step_1
title: The Social Contract
content_blocks:
- '## Philosophical Foundations 📜'
- The American founders were heavily influenced by Enlightenment philosophy, particularly John Locke's ideas about natural rights and the social contract.
- ''
- '**Key Enlightenment Ideas:**'
- '- **Natural Rights:** Locke argued that people have inherent rights to life, liberty, and property'
- '- **Social Contract:** Government''s authority comes from the consent of the governed'
- '- **Right to Revolution:** If government violates natural rights, people can overthrow it'
- ''
- '**From the Declaration of Independence (1776):**'
- _'We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness.'_
- ''
- '**Critical Question:**'
- The Declaration states 'all men are created equal' - yet slavery existed, women couldn't vote, and Native Americans were displaced.
question: How do you reconcile the contradiction between the Declaration's ideals of equality and the reality of 1776 America? What does this tell us about the founding period?
tokens_for_ai: 'This is a sophisticated question about contradiction between ideals and reality. Look for:
- Recognition of the contradiction/hypocrisy
- Understanding of historical context (norms of the time)
- Nuanced thinking (ideals as aspirational vs. complete hypocrisy)
- Consideration of whose perspectives were included/excluded
Categorize as:
- sophisticated_analysis: Nuanced understanding of contradiction, historical context, and evolution of ideals
- recognizes_hypocrisy: Sees the contradiction clearly but may not fully analyze it
- contextualizes: Focuses on historical context ("people thought differently then")
- partial_understanding: General thoughts but incomplete analysis
- limited_effort: Very brief
- asking_clarifying_questions: Needs more information
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Engage with their analysis thoughtfully. If they note the hypocrisy, affirm that recognition
and discuss how the ideals in the Declaration became tools for excluded groups (abolitionists,
suffragists, civil rights activists) to demand rights. If they only contextualize, acknowledge
historical context while noting that the contradiction was recognized even then by some.
'
buckets:
- sophisticated_analysis
- recognizes_hypocrisy
- contextualizes
- partial_understanding
- limited_effort
- asking_clarifying_questions
- off_topic
transitions:
sophisticated_analysis:
ai_feedback:
tokens_for_ai: Excellent historical thinking! Discuss how the Declaration's ideals became 'promissory notes' that future movements would claim. Mention Frederick Douglass's 1852 speech.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: founding_principles:step_2
recognizes_hypocrisy:
ai_feedback:
tokens_for_ai: Good recognition of the contradiction! Expand on how these ideals, though not practiced, created a framework that excluded groups later used to demand inclusion.
metadata_add:
score: n+2
critical_thinking: n+1
next_section_and_step: founding_principles:step_2
contextualizes:
ai_feedback:
tokens_for_ai: Historical context is important! Also note that even in the 1770s, some people (like Abigail Adams, some Quakers) pointed out these contradictions. The ideals were radical even if not fully practiced.
metadata_add:
score: n+1
next_section_and_step: founding_principles:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking about this! Consider: the founders wrote about equality while owning slaves. How might excluded groups have used these written ideals to fight for their own rights later?'
next_section_and_step: founding_principles:step_1
limited_effort:
content_blocks:
- 'This is a complex question requiring deep thought. Consider: What did ''all men are created equal'' mean in practice in 1776? Who was excluded?'
next_section_and_step: founding_principles:step_1
asking_clarifying_questions:
ai_feedback:
tokens_for_ai: Answer their question about the Declaration, slavery, or founding era contradictions.
counts_as_attempt: false
next_section_and_step: founding_principles:step_1
off_topic:
content_blocks:
- Let's focus on the founding principles. How do you understand the contradiction between stated ideals and reality?
next_section_and_step: founding_principles:step_1
- step_id: step_2
title: Federalism and Separation of Powers
content_blocks:
- '## The Constitutional Convention (1787)'
- 'The founders faced a challenge: create a government strong enough to function, but not so strong it becomes tyrannical.'
- ''
- '**Their solutions:**'
- ''
- '**1. Federalism** - Power divided between national and state governments'
- '**2. Separation of Powers** - Legislative, Executive, Judicial branches'
- '**3. Checks and Balances** - Each branch can limit the others'
- ''
- '**Madison''s Federalist #51 (1788):**'
- _'If men were angels, no government would be necessary. If angels were to govern men, neither external nor internal controls on government would be necessary.'_
- ''
- '**The founders'' key insight:**'
- Don't rely on having virtuous leaders - design a system where ambition counteracts ambition.
- ''
- '**Examples of Checks and Balances:**'
- '- President can veto laws (Executive checks Legislative)'
- '- Congress can override veto with 2/3 vote (Legislative checks Executive)'
- '- Supreme Court can declare laws unconstitutional (Judicial checks both)'
- '- Senate confirms judges (Legislative checks Judicial)'
question: Why did the founders distrust concentrated power so much? What historical experiences shaped this distrust, and do you think these checks and balances are still necessary today?
tokens_for_ai: 'Looking for understanding of:
- Historical context (British monarchy, tyranny)
- Human nature assumptions (power corrupts)
- Contemporary relevance
Categorize as:
- excellent_analysis: Connects historical experience, theory, and contemporary relevance
- historical_understanding: Good grasp of why founders feared concentrated power
- contemporary_focus: Emphasizes modern relevance
- partial_understanding: General thoughts but incomplete
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Engage their thinking. The founders'' experience with King George III and colonial governors
shaped their views. If they discuss contemporary relevance, acknowledge different perspectives
on whether checks and balances are working as intended today.
'
buckets:
- excellent_analysis
- historical_understanding
- contemporary_focus
- partial_understanding
- limited_effort
- off_topic
transitions:
excellent_analysis:
ai_feedback:
tokens_for_ai: Sophisticated thinking! You've connected historical experience to institutional design and contemporary relevance. Discuss ongoing debates about executive power, judicial review, etc.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: civil_war:step_1
historical_understanding:
ai_feedback:
tokens_for_ai: Good historical understanding! The founders' experience with King George III profoundly shaped their distrust of concentrated power. Discuss how this plays out in contemporary politics.
metadata_add:
score: n+2
next_section_and_step: civil_war:step_1
contemporary_focus:
ai_feedback:
tokens_for_ai: 'Interesting contemporary perspective! Connect this to the historical context: the founders had just fought a war against what they saw as tyrannical power.'
metadata_add:
score: n+2
next_section_and_step: civil_war:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking about this! Consider: the founders had just fought a war against King George III. How might that experience have shaped their views on power?'
metadata_add:
score: n+1
next_section_and_step: civil_war:step_1
limited_effort:
content_blocks:
- Think about what the founders had just experienced - war against British monarchy. How might that shape their views on concentrated power?
next_section_and_step: founding_principles:step_2
off_topic:
content_blocks:
- Let's focus on the founders' distrust of concentrated power. What historical experiences shaped this?
next_section_and_step: founding_principles:step_2
- section_id: civil_war
title: The Civil War and Reconstruction
steps:
- step_id: step_1
title: Causes of the Civil War
content_blocks:
- '## The Road to Civil War ⚔️'
- The Civil War (1861-1865) was the deadliest conflict in American history - over 600,000 deaths.
- ''
- '**Was it about slavery or states'' rights?**'
- This debate continues, but let's look at primary sources.
- ''
- '**Mississippi''s Declaration of Secession (1861):**'
- _'Our position is thoroughly identified with the institution of slavery - the greatest material interest of the world.'_
- ''
- '**Confederate VP Alexander Stephens (1861):**'
- _'Our new government's foundations are laid, its cornerstone rests, upon the great truth that the negro is not equal to the white man; that slavery... is his natural and normal condition.'_
- ''
- '**Economic Context:**'
- '- By 1860, enslaved people represented $3.5 billion in property value (more than all factories and railroads combined)'
- '- Cotton accounted for 60% of US exports'
- '- Southern economy was built on slave labor'
- ''
- '**Political Context:**'
- '- Lincoln''s election (1860) without a single Southern electoral vote'
- '- Fear that federal government would restrict slavery''s expansion'
question: Based on these primary sources, what was the central cause of the Civil War? Why do you think some people today emphasize 'states' rights' rather than slavery as the cause?
tokens_for_ai: 'Looking for:
- Recognition that slavery was the central cause (based on primary sources)
- Understanding of why revisionist narratives emerged
- Critical thinking about how history is remembered
Categorize as:
- evidence_based_conclusion: Uses primary sources to conclude slavery was central cause
- analyzes_revisionism: Understands why alternative narratives emerged
- sophisticated_both: Addresses both the historical reality and its contested memory
- partial_understanding: General thoughts but incomplete
- states_rights_focus: Emphasizes states'' rights over slavery
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'If they correctly identify slavery as the central cause, affirm this and discuss Lost Cause
mythology that emerged after Reconstruction. If they emphasize states'' rights, gently redirect
to the primary sources: Confederate states explicitly cited slavery as the reason for secession.
'
buckets:
- evidence_based_conclusion
- analyzes_revisionism
- sophisticated_both
- partial_understanding
- states_rights_focus
- limited_effort
- off_topic
transitions:
evidence_based_conclusion:
ai_feedback:
tokens_for_ai: Excellent use of primary sources! The Confederate states' own words make clear that slavery was the central issue. Discuss how the 'Lost Cause' mythology later rewrote this history.
metadata_add:
score: n+3
primary_source_analysis: n+1
next_section_and_step: civil_war:step_2
analyzes_revisionism:
ai_feedback:
tokens_for_ai: Good analysis of historical memory! After Reconstruction, the 'Lost Cause' narrative emerged to justify the Confederacy and maintain white supremacy. Explain this further.
metadata_add:
score: n+2
critical_thinking: n+1
next_section_and_step: civil_war:step_2
sophisticated_both:
ai_feedback:
tokens_for_ai: Sophisticated historical thinking! You're understanding both what happened and how it's been remembered. This is advanced historical analysis.
metadata_add:
score: n+3
primary_source_analysis: n+1
critical_thinking: n+1
next_section_and_step: civil_war:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: You're thinking about this. Look at the primary sources - what did Mississippi and Confederate VP Stephens say was the reason for secession?
next_section_and_step: civil_war:step_1
states_rights_focus:
ai_feedback:
tokens_for_ai: 'The ''states'' rights'' argument is common, but examine the primary sources: Mississippi''s declaration and Stephens'' speech explicitly state slavery was the central issue. States'' rights to do what, specifically?'
next_section_and_step: civil_war:step_1
limited_effort:
content_blocks:
- Read the primary sources carefully - Mississippi's declaration and Confederate VP Stephens' speech. What do they say was the reason for secession?
next_section_and_step: civil_war:step_1
off_topic:
content_blocks:
- Let's analyze the primary sources from Confederate leaders. What do they say caused the war?
next_section_and_step: civil_war:step_1
- step_id: step_2
title: Reconstruction and Its Failure
content_blocks:
- '## Reconstruction (1865-1877)'
- 'After the Civil War, the nation faced the question: How do you integrate 4 million formerly enslaved people into American society?'
- ''
- '**Constitutional Amendments:**'
- '- **13th (1865):** Abolished slavery'
- '- **14th (1868):** Citizenship and equal protection under law'
- '- **15th (1870):** Voting rights regardless of race'
- ''
- '**Achievements of Reconstruction:**'
- '- Black men gained voting rights and political power'
- '- First Black Congressmen and Senators elected'
- '- Public schools established in the South (for both Black and white children)'
- '- Economic opportunities began to emerge'
- ''
- '**The Backlash:**'
- '- White terrorist groups (KKK) used violence to suppress Black voting'
- '- Compromise of 1877: Federal troops withdrawn from South'
- '- Jim Crow laws established racial segregation'
- '- Black voting rights systematically stripped through poll taxes, literacy tests, grandfather clauses'
- ''
- '**Historian Eric Foner:**'
- _'Reconstruction was America's unfinished revolution.'_
question: Why did Reconstruction fail? What would have been needed for it to succeed in achieving true equality for formerly enslaved people?
tokens_for_ai: 'Looking for understanding of:
- Political will (North lost interest)
- White supremacist violence
- Economic factors (land redistribution never happened)
- Federal enforcement needed but withdrawn
Categorize as:
- multi_factor_analysis: Identifies multiple reasons for failure
- political_will: Focuses on loss of Northern commitment
- violence_focus: Emphasizes white supremacist terrorism
- economic_analysis: Notes lack of land redistribution/"40 acres and a mule"
- thoughtful_counterfactual: Proposes what could have made it succeed
- partial_understanding: General thoughts
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Engage their analysis. Multiple factors contributed: Northern fatigue, white supremacist
violence, economic exploitation, political compromise. If they propose counterfactuals,
discuss land redistribution, sustained federal protection, economic investment.
'
buckets:
- multi_factor_analysis
- political_will
- violence_focus
- economic_analysis
- thoughtful_counterfactual
- partial_understanding
- limited_effort
- off_topic
transitions:
multi_factor_analysis:
ai_feedback:
tokens_for_ai: Excellent multi-factor analysis! Reconstruction failed due to loss of political will, white supremacist violence, economic exploitation, and the Compromise of 1877. Discuss long-term consequences.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: civil_rights:step_1
political_will:
ai_feedback:
tokens_for_ai: Important factor! The North did lose interest after the Compromise of 1877. Also consider white supremacist violence and economic factors.
metadata_add:
score: n+2
next_section_and_step: civil_rights:step_1
violence_focus:
ai_feedback:
tokens_for_ai: Crucial point! White terrorism (KKK, etc.) was systematically used to suppress Black political power. The federal government eventually stopped protecting Black citizens.
metadata_add:
score: n+2
next_section_and_step: civil_rights:step_1
economic_analysis:
ai_feedback:
tokens_for_ai: Key economic insight! Without land redistribution ('40 acres and a mule'), formerly enslaved people remained economically dependent on white landowners through sharecropping.
metadata_add:
score: n+2
next_section_and_step: civil_rights:step_1
thoughtful_counterfactual:
ai_feedback:
tokens_for_ai: Interesting counterfactual thinking! Evaluate their proposals against historical context and constraints.
metadata_add:
score: n+2
critical_thinking: n+1
next_section_and_step: civil_rights:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking about this. Consider: political will, violence, economics, and federal enforcement. What combination of factors led to failure?'
metadata_add:
score: n+1
next_section_and_step: civil_rights:step_1
limited_effort:
content_blocks:
- 'Think about what Reconstruction needed: political commitment, protection from violence, economic opportunity, federal enforcement. What went wrong?'
next_section_and_step: civil_war:step_2
off_topic:
content_blocks:
- Let's analyze Reconstruction's failure. What factors led to the end of Black political power after 1877?
next_section_and_step: civil_war:step_2
- section_id: civil_rights
title: Civil Rights Movement
steps:
- step_id: step_1
title: Strategies for Change
content_blocks:
- '## The Civil Rights Movement (1950s-1960s) ✊'
- Nearly 100 years after the Civil War, Jim Crow segregation still dominated the South.
- ''
- '**Different Strategic Approaches:**'
- ''
- '**Legal Strategy (NAACP, Thurgood Marshall):**'
- '- Use courts to overturn segregation laws'
- '- *Brown v. Board of Education* (1954): Declared school segregation unconstitutional'
- '- Gradualist approach working within the system'
- ''
- '**Nonviolent Direct Action (MLK, SCLC):**'
- '- Boycotts, sit-ins, marches to create crisis that forces negotiation'
- '- Montgomery Bus Boycott (1955-56), March on Washington (1963)'
- '- Moral appeal to conscience of nation'
- ''
- '**Black Power/Self-Defense (Malcolm X, Black Panthers):**'
- '- Critique of integration as goal; emphasis on Black empowerment'
- '- Self-defense against violence (vs. absolute nonviolence)'
- '- Economic self-sufficiency and cultural pride'
- ''
- '**MLK''s Letter from Birmingham Jail (1963):**'
- _'Injustice anywhere is a threat to justice everywhere. We are caught in an inescapable network of mutuality, tied in a single garment of destiny.'_
- ''
- '**Malcolm X (1964):**'
- _'We declare our right on this earth to be a man, to be a human being, to be respected as a human being, to be given the rights of a human being in this society.'_
question: Why were there different strategic approaches in the Civil Rights Movement? Were all of these approaches necessary, or was one more effective than others? Explain your reasoning.
tokens_for_ai: 'Looking for:
- Understanding of different strategic visions
- Recognition that strategies complemented each other
- Sophisticated thinking about social movements
- Awareness that movements aren''t monolithic
Categorize as:
- sophisticated_analysis: Understands how different strategies played different roles
- complementary_view: Sees strategies as working together
- single_strategy_preference: Argues one was most effective
- comparative_analysis: Thoughtfully compares approaches
- partial_understanding: General thoughts
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Engage their analysis thoughtfully. Historical consensus is that multiple strategies created
pressure from different angles: legal victories removed legal barriers, direct action created
urgency, Black Power empowered communities and pushed moderates to negotiate. If they prefer
one strategy, discuss how it interacted with others.
'
buckets:
- sophisticated_analysis
- complementary_view
- single_strategy_preference
- comparative_analysis
- partial_understanding
- limited_effort
- off_topic
transitions:
sophisticated_analysis:
ai_feedback:
tokens_for_ai: Excellent historical thinking! You understand that social movements use multiple strategies simultaneously. The 'radical flank effect' made moderates seem more reasonable to white Americans.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: civil_rights:step_2
complementary_view:
ai_feedback:
tokens_for_ai: Good insight! The different strategies created pressure from multiple angles and appealed to different constituencies. Discuss the 'radical flank effect.'
metadata_add:
score: n+2
next_section_and_step: civil_rights:step_2
single_strategy_preference:
ai_feedback:
tokens_for_ai: 'You make a case for one strategy. Also consider how the strategies interacted: legal victories needed enforcement, which required political pressure from protests.'
metadata_add:
score: n+2
next_section_and_step: civil_rights:step_2
comparative_analysis:
ai_feedback:
tokens_for_ai: Good comparative thinking! Expand on how the strategies might have complemented each other or created tension.
metadata_add:
score: n+2
critical_thinking: n+1
next_section_and_step: civil_rights:step_2
partial_understanding:
ai_feedback:
tokens_for_ai: Think about how different strategies might work together. Could 'radical' demands make 'moderate' demands seem more acceptable?
metadata_add:
score: n+1
next_section_and_step: civil_rights:step_1
limited_effort:
content_blocks:
- 'Consider: Why might a movement need both people working within the system (courts) and outside it (protests)? How might they complement each other?'
next_section_and_step: civil_rights:step_1
off_topic:
content_blocks:
- Let's analyze the different Civil Rights strategies. How did legal, nonviolent direct action, and Black Power approaches differ?
next_section_and_step: civil_rights:step_1
- step_id: step_2
title: Unfinished Business
content_blocks:
- '## The Civil Rights Movement''s Legacy'
- 'The Civil Rights Movement achieved major legal victories:'
- '- Civil Rights Act (1964): Outlawed discrimination'
- '- Voting Rights Act (1965): Prohibited racial discrimination in voting'
- '- Fair Housing Act (1968): Prohibited discrimination in housing'
- ''
- '**But many goals remained unachieved:**'
- ''
- '**Economic Justice:**'
- MLK's focus in final years was on poverty - the Poor People's Campaign
- 'Wealth gap: In 1963, median Black family had 5% of white family wealth. In 2016: 10%'
- ''
- '**Systemic Issues:**'
- '- School resegregation (integration peaked in 1988, has declined since)'
- '- Mass incarceration (5x incarceration rate for Black vs white Americans)'
- '- Voting rights: Shelby County v. Holder (2013) weakened Voting Rights Act'
- ''
- '**MLK''s Final Speech (1968, night before assassination):**'
- _'I've been to the mountaintop... I've seen the Promised Land. I may not get there with you. But I want you to know tonight, that we, as a people, will get to the Promised Land.'_
question: The Civil Rights Movement won major legal battles but many economic and systemic issues persist. Why do legal victories not automatically solve social problems? What more is needed beyond changing laws?
tokens_for_ai: 'Looking for understanding that:
- Laws vs. implementation/enforcement
- Formal equality vs. substantive equality
- Systemic/structural issues
- Cultural change, economic redistribution, enforcement
Categorize as:
- systemic_understanding: Grasps difference between formal and substantive equality
- implementation_focus: Emphasizes gap between law and enforcement
- cultural_change: Notes need for changing hearts and minds
- economic_analysis: Focuses on material/economic dimensions
- sophisticated_multi_factor: Identifies multiple dimensions of change needed
- partial_understanding: General thoughts
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Engage their thinking about social change. Legal change is necessary but not sufficient.
Systemic change requires enforcement, cultural shift, economic redistribution, and
addressing structural inequalities. If they give sophisticated analysis, affirm it.
'
buckets:
- systemic_understanding
- implementation_focus
- cultural_change
- economic_analysis
- sophisticated_multi_factor
- partial_understanding
- limited_effort
- off_topic
transitions:
systemic_understanding:
ai_feedback:
tokens_for_ai: Excellent grasp of the difference between formal and substantive equality! Laws change what's legal, but systemic change requires transforming institutions, culture, and economic structures.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: conclusion:step_1
implementation_focus:
ai_feedback:
tokens_for_ai: Important point! There's often a gap between laws on the books and their enforcement. Discuss how enforcement requires political will and resources.
metadata_add:
score: n+2
next_section_and_step: conclusion:step_1
cultural_change:
ai_feedback:
tokens_for_ai: Good insight about cultural change! Laws can change behavior, but cultural attitudes also need to shift. This is a slow, complex process.
metadata_add:
score: n+2
next_section_and_step: conclusion:step_1
economic_analysis:
ai_feedback:
tokens_for_ai: Strong economic analysis! Legal equality doesn't address wealth gaps, employment discrimination, or economic structures. MLK increasingly focused on economic justice in his final years.
metadata_add:
score: n+2
next_section_and_step: conclusion:step_1
sophisticated_multi_factor:
ai_feedback:
tokens_for_ai: Outstanding multi-dimensional analysis! You understand that social change requires legal, cultural, economic, and institutional transformation. This is advanced historical thinking.
metadata_add:
score: n+3
critical_thinking: n+1
next_section_and_step: conclusion:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: 'You''re thinking about this. Consider: if a law is passed but not enforced, or if economic structures remain unchanged, what''s the impact?'
metadata_add:
score: n+1
next_section_and_step: conclusion:step_1
limited_effort:
content_blocks:
- Think about the difference between laws changing and society changing. What else needs to happen beyond passing legislation?
next_section_and_step: civil_rights:step_2
off_topic:
content_blocks:
- Let's think about why legal victories aren't enough. What more is needed for real social change?
next_section_and_step: civil_rights:step_2
- section_id: conclusion
title: Historical Thinking and Contemporary Connections
steps:
- step_id: step_1
title: Thinking Like a Historian
content_blocks:
- '## Congratulations, Historian! 🎓'
- You've engaged with American history at an advanced level.
- ''
- '**Key Historical Thinking Skills You''ve Practiced:**'
- ✓ **Primary Source Analysis** - Reading founding documents and speeches in context
- ✓ **Cause and Effect** - Understanding how events lead to consequences
- ✓ **Multiple Perspectives** - Considering different viewpoints on events
- ✓ **Continuity and Change** - Seeing patterns and transformations over time
- ✓ **Historical Significance** - Evaluating which events and ideas matter and why
- ✓ **Connecting Past to Present** - Understanding how history shapes current issues
- ''
- '**Themes Across American History:**'
- '- Tension between ideals and reality (equality vs. practice)'
- '- Struggles to expand democracy and rights'
- '- Economic factors shaping politics and society'
- '- Power of social movements to create change'
- '- Importance of institutions and their design'
- ''
- '**Why History Matters:**'
- '- Understand how we got here'
- '- Learn from past successes and failures'
- '- Recognize patterns and precedents'
- '- Think critically about present claims using historical evidence'
- '- Understand that change is possible because it has happened before'
- ''
- '**''Those who cannot remember the past are condemned to repeat it.''** - George Santayana'
question: What's one historical insight from this activity that changes how you think about a contemporary issue? How does understanding history help you think more critically about the present?
tokens_for_ai: 'This is a reflection on applying historical thinking to contemporary issues.
Categorize as:
- specific_connection: Makes clear connection between historical insight and contemporary issue
- thoughtful_reflection: Meaningful reflection on historical thinking
- general_reflection: Broader thoughts about history''s relevance
- limited_effort: Very brief
- off_topic: Unrelated
'
feedback_tokens_for_ai: 'Provide thoughtful, personalized feedback on their historical journey. Acknowledge specific
insights they shared throughout the activity. Encourage continued historical thinking and
exploration. Discuss how understanding history makes us better citizens.
'
buckets:
- specific_connection
- thoughtful_reflection
- general_reflection
- limited_effort
- off_topic
transitions:
specific_connection:
ai_feedback:
tokens_for_ai: Excellent application of historical thinking to contemporary issues! Affirm their specific connection and discuss how historians analyze present events using historical frameworks.
metadata_add:
activity_completed: 'true'
thoughtful_reflection:
ai_feedback:
tokens_for_ai: Thoughtful reflection on historical thinking! Encourage them to continue asking historical questions about contemporary issues.
metadata_add:
activity_completed: 'true'
general_reflection:
ai_feedback:
tokens_for_ai: Thank them for engaging deeply with American history. Suggest specific historical topics or periods they might explore further based on their interests.
metadata_add:
activity_completed: 'true'
limited_effort:
ai_feedback:
tokens_for_ai: Acknowledge their completion and encourage them to think about how historical patterns might illuminate current events.
metadata_add:
activity_completed: 'true'
off_topic:
content_blocks:
- Reflect on your historical journey. What insight about the past helps you understand the present differently?
next_section_and_step: conclusion:step_1

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,591 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate the student's engagement with fashion concepts.
Consider:
- Their understanding of personal style
- Creativity in fashion choices
- Awareness of fashion principles (color, fit, occasion)
- Confidence in expressing their style
Provide encouraging, personalized fashion advice.
Be supportive of all style preferences and body types.
sections:
- section_id: introduction
title: Welcome to Fashion Today
steps:
- step_id: welcome
title: Fashion Journey Begins
content_blocks:
- "# Welcome to Fashion Today! 👗✨"
- "Fashion is more than clothes—it's self-expression, confidence, and creativity!"
- ""
- "**In this journey, you'll:**"
- "- Discover your personal style"
- "- Learn fashion principles"
- "- Build outfits for different occasions"
- "- Get personalized style advice"
- ""
- "**Remember:** Fashion has no rules, only guidelines. The best style is what makes YOU feel confident!"
question: Are you ready to explore the exciting world of fashion?
tokens_for_ai: |
Accept any positive response as 'ready'.
If setting language preference, categorize as 'set_language'.
Otherwise 'off_topic'.
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- "Fantastic! Let's discover your unique style! 🌟"
next_section_and_step: style_discovery:step_1
set_language:
content_blocks:
- "Language preference updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- "Let's focus on fashion! Are you excited to begin?"
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: style_discovery
title: Discover Your Style
steps:
- step_id: step_1
title: Fashion Inspiration
content_blocks:
- "## What's Your Style Vibe? 🎨"
- ""
- "**Popular fashion styles:**"
- ""
- "**Classic/Timeless** 🎩 - Elegant, tailored pieces; neutral colors; quality over trends"
- "**Casual/Comfortable** 👟 - Relaxed fits, denim, sneakers, effortless cool"
- "**Bohemian/Boho** 🌸 - Flowy fabrics, earthy tones, layered accessories, free-spirited"
- "**Streetwear/Urban** 🛹 - Bold graphics, sneakers, hoodies, influenced by music and skate culture"
- "**Romantic/Feminine** 🌹 - Soft colors, ruffles, lace, delicate details"
- "**Edgy/Alternative** 🖤 - Dark colors, leather, unconventional cuts, statement pieces"
- "**Minimalist** ⚪ - Clean lines, monochrome, simple silhouettes, 'less is more'"
- "**Preppy/Collegiate** 📚 - Polished, structured, blazers, button-downs, classic patterns"
- "**Glamorous/Luxe** ✨ - Sparkle, bold jewelry, luxurious fabrics, red carpet vibes"
- "**Eclectic/Mix-and-Match** 🎭 - Combining different styles, unique combinations, personal flair"
- ""
- "You can love multiple styles or create your own unique blend!"
question: Which style (or styles) resonates with you? Describe what you love about fashion or what you'd like to wear!
tokens_for_ai: |
The student is describing their fashion preferences.
Store their response in metadata.style_preference.
Categorize based on engagement level:
- detailed_response: They describe specific styles, colors, or preferences
- general_interest: They mention a style category or general interest
- exploring: They're unsure but curious
- set_language: Setting language preference
- off_topic: Unrelated to fashion
feedback_tokens_for_ai: |
Acknowledge their style preferences enthusiastically!
If they mentioned specific styles:
- Validate their choices
- Mention how that style expresses personality
- Suggest complementary elements
If they're exploring:
- Encourage experimentation
- Mention that style evolves
- Suggest trying different looks
buckets:
- detailed_response
- general_interest
- exploring
- set_language
- off_topic
transitions:
detailed_response:
ai_feedback:
tokens_for_ai: |
Celebrate their detailed style knowledge!
Reference specific elements they mentioned.
Tell them their style sounds amazing and expresses their personality.
metadata_add:
style_preference: "the-users-response"
score: "n+1"
next_section_and_step: style_discovery:step_2
general_interest:
ai_feedback:
tokens_for_ai: |
Great starting point!
Acknowledge their style interest.
Encourage them to explore further.
metadata_add:
style_preference: "the-users-response"
next_section_and_step: style_discovery:step_2
exploring:
content_blocks:
- "Exploring is wonderful! Fashion is about discovery."
- "Think about: What colors make you happy? What fabrics feel good? What makes you feel confident?"
metadata_add:
style_preference: "exploring different styles"
next_section_and_step: style_discovery:step_2
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: style_discovery:step_1
off_topic:
content_blocks:
- "Let's talk fashion! What kind of clothes do you enjoy wearing?"
next_section_and_step: style_discovery:step_1
- step_id: step_2
title: Color and You
content_blocks:
- "## The Power of Color 🌈"
- ""
- "Colors affect mood and perception!"
- ""
- "**Color Psychology:**"
- "- **Red** ❤️ - Bold, confident, passionate, attention-grabbing"
- "- **Blue** 💙 - Calm, trustworthy, professional, serene"
- "- **Black** 🖤 - Sophisticated, elegant, powerful, versatile"
- "- **White** 🤍 - Clean, fresh, minimalist, peaceful"
- "- **Yellow** 💛 - Happy, energetic, optimistic, cheerful"
- "- **Green** 💚 - Natural, balanced, refreshing, growth"
- "- **Pink** 💗 - Playful, romantic, soft, youthful"
- "- **Purple** 💜 - Creative, luxurious, mysterious, royal"
- "- **Neutrals** (beige, gray, brown) - Versatile, timeless, easy to mix"
- ""
- "**Pro Tip:** Wear colors near your face that complement your skin tone!"
question: What colors do you love to wear? What colors make you feel most confident or happy?
tokens_for_ai: |
Student is sharing color preferences.
Categorize as:
- specific_colors: Names specific colors and why they like them
- color_mentioned: Mentions colors without detail
- neutral_preference: Prefers neutrals or all colors
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Validate their color choices!
Reference color psychology for their chosen colors.
Suggest how to incorporate those colors.
Mention complementary colors if appropriate.
buckets:
- specific_colors
- color_mentioned
- neutral_preference
- set_language
- off_topic
transitions:
specific_colors:
ai_feedback:
tokens_for_ai: |
Excellent color awareness!
Reference the psychology/meaning of their chosen colors.
Suggest outfit combinations or accent pieces.
Celebrate their color confidence!
metadata_add:
color_preference: "the-users-response"
score: "n+1"
next_section_and_step: outfit_building:step_1
color_mentioned:
ai_feedback:
tokens_for_ai: |
Great choices!
Explain what those colors convey.
Encourage experimenting with different shades.
metadata_add:
color_preference: "the-users-response"
next_section_and_step: outfit_building:step_1
neutral_preference:
ai_feedback:
tokens_for_ai: |
Neutrals are timeless and versatile!
Perfect base for any wardrobe.
Suggest adding pops of color through accessories.
metadata_add:
color_preference: "neutrals and versatile colors"
next_section_and_step: outfit_building:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: style_discovery:step_2
off_topic:
content_blocks:
- "Think about your wardrobe! What colors do you reach for most often?"
next_section_and_step: style_discovery:step_2
- section_id: outfit_building
title: Build Your Wardrobe
steps:
- step_id: step_1
title: Dressing for Occasions
content_blocks:
- "## Fashion for Every Occasion 👔👗"
- ""
- "**The Fashion Formula:** Occasion + Personal Style = Perfect Outfit"
- ""
- "**Key Principles:**"
- ""
- "1. **Dress Code Awareness**"
- " - Casual: Comfort meets style (jeans, sneakers, t-shirts)"
- " - Business Casual: Polished but approachable (slacks, blouses, loafers)"
- " - Formal: Sophisticated elegance (suits, dresses, dress shoes)"
- ""
- "2. **Fit is Everything**"
- " - Clothes should fit your body, not the other way around"
- " - Tailoring can transform any piece"
- " - Comfort = Confidence"
- ""
- "3. **The Power of Accessories**"
- " - Jewelry, bags, shoes, scarves"
- " - Can transform a basic outfit"
- " - Express personality"
- ""
- "**Let's practice outfit building!**"
question: "Imagine you're going to a casual coffee date with friends. What would you wear? Describe your outfit!"
tokens_for_ai: |
Student is describing a casual outfit.
Look for:
- Specific clothing items
- Color coordination
- Style consistency
- Occasion appropriateness
Categorize as:
- detailed_outfit: Describes multiple pieces with thought to coordination
- basic_outfit: Mentions clothing items appropriately casual
- creative_outfit: Unique or interesting combinations
- needs_guidance: Very brief or doesn't match occasion
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Evaluate their outfit for the casual coffee date scenario.
If well thought out:
- Praise specific choices
- Mention what works well
- Suggest one accessory or detail to elevate it
If creative:
- Celebrate their unique style
- Encourage personal expression
If needs work:
- Gently guide toward casual appropriate pieces
- Give specific suggestions
- Be encouraging
buckets:
- detailed_outfit
- basic_outfit
- creative_outfit
- needs_guidance
- set_language
- off_topic
transitions:
detailed_outfit:
ai_feedback:
tokens_for_ai: |
Excellent outfit planning!
Reference their style preference from metadata if stored.
Praise specific elements (color choices, coordination, etc.).
Suggest one perfect accessory to complete the look.
metadata_add:
score: "n+1"
outfits_created: "n+1"
next_section_and_step: outfit_building:step_2
basic_outfit:
ai_feedback:
tokens_for_ai: |
Perfect for a casual coffee date!
Reference what they chose.
Suggest how to add personal flair (accessories, colors, etc.).
metadata_add:
outfits_created: "n+1"
next_section_and_step: outfit_building:step_2
creative_outfit:
ai_feedback:
tokens_for_ai: |
Love the creativity!
Celebrate their unique fashion sense.
Encourage them to own their style.
metadata_add:
score: "n+1"
outfits_created: "n+1"
next_section_and_step: outfit_building:step_2
needs_guidance:
content_blocks:
- "Let's think casual and comfortable!"
- "**Suggestions:** Jeans or casual pants, a nice top or sweater, comfortable shoes (sneakers, boots, flats)"
- "Add your personal touch with accessories or colors you love!"
next_section_and_step: outfit_building:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: outfit_building:step_1
off_topic:
content_blocks:
- "Imagine your perfect casual outfit! What would you choose to wear for coffee with friends?"
next_section_and_step: outfit_building:step_1
- step_id: step_2
title: Statement Pieces
content_blocks:
- "## The Power of Statement Pieces 💎"
- ""
- "**What's a Statement Piece?**"
- "An item that stands out and defines your outfit!"
- ""
- "**Examples:**"
- "- Bold jacket (leather, colorful blazer, denim)"
- "- Eye-catching shoes (colored sneakers, boots, heels)"
- "- Unique bag (vintage, designer, handmade)"
- "- Dramatic jewelry (chunky necklace, statement earrings)"
- "- Printed/patterned piece (floral dress, graphic tee, plaid pants)"
- ""
- "**The Rule:** Let your statement piece shine!"
- "- Keep other items simpler"
- "- Build outfit around the statement piece"
- "- One or two statement pieces max"
question: What's your favorite statement piece you own (or would love to own)? Describe it and how you'd style it!
tokens_for_ai: |
Student describing a statement piece.
Categorize as:
- detailed_vision: Describes the piece AND how they'd wear it
- piece_described: Describes a statement item
- aspirational: Talks about wanting certain pieces
- minimalist_approach: Prefers subtle/no statement pieces
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Respond to their statement piece choice!
If they described styling:
- Praise their fashion vision
- Suggest complementary pieces
- Encourage them to rock it
If minimalist:
- Validate that style too
- Mention statement can be subtle
- Quality basics are statements too
buckets:
- detailed_vision
- piece_described
- aspirational
- minimalist_approach
- set_language
- off_topic
transitions:
detailed_vision:
ai_feedback:
tokens_for_ai: |
Wow, you have a great fashion eye!
Love how you described both the piece and the styling.
Reference specific elements they mentioned.
Encourage them to wear it with confidence!
metadata_add:
score: "n+1"
next_section_and_step: fashion_wisdom:step_1
piece_described:
ai_feedback:
tokens_for_ai: |
Great statement piece choice!
Suggest how to style it.
Mention what type of outfit it would elevate.
next_section_and_step: fashion_wisdom:step_1
aspirational:
ai_feedback:
tokens_for_ai: |
Great fashion goals!
Encourage saving/hunting for that perfect piece.
Mention alternatives or similar items to explore.
Fashion dreams are fun!
next_section_and_step: fashion_wisdom:step_1
minimalist_approach:
ai_feedback:
tokens_for_ai: |
Minimalism is a powerful statement!
Quality over quantity is wise.
Mention how simple pieces can be impactful.
next_section_and_step: fashion_wisdom:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: outfit_building:step_2
off_topic:
content_blocks:
- "Think about your wardrobe! Do you have a favorite bold piece that makes an outfit special?"
next_section_and_step: outfit_building:step_2
- section_id: fashion_wisdom
title: Fashion Tips & Confidence
steps:
- step_id: step_1
title: Your Fashion Philosophy
content_blocks:
- "## Fashion Wisdom 🌟"
- ""
- "**Universal Fashion Truths:**"
- ""
- "1. **Confidence is Your Best Accessory**"
- " - Wear what makes YOU feel amazing"
- " - Own your choices"
- ""
- "2. **Fashion Has No Size**"
- " - Every body is a fashion body"
- " - Dress for YOUR shape and comfort"
- ""
- "3. **Break the Rules**"
- " - Fashion 'rules' are just suggestions"
- " - Mix patterns, clash colors, be YOU"
- ""
- "4. **Sustainable Choices Matter**"
- " - Quality over quantity"
- " - Thrift, swap, upcycle"
- " - Fashion can be ethical"
- ""
- "5. **Express Yourself**"
- " - Your clothes tell your story"
- " - Change your style as you grow"
- " - Have fun with it!"
question: What does fashion mean to you? How do you want to express yourself through clothing?
tokens_for_ai: |
This is a reflection question about their fashion philosophy.
Categorize as:
- thoughtful_reflection: Shares personal connection to fashion
- self_expression: Talks about expressing personality/identity
- practical_view: Focuses on function, comfort, practicality
- creative_view: Sees fashion as art/creativity
- brief_response: Short but genuine
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Provide personalized, encouraging feedback!
Reference their style_preference from metadata if available.
Celebrate their unique perspective on fashion.
Encourage them to continue expressing themselves.
Mention that fashion is a journey, not a destination.
buckets:
- thoughtful_reflection
- self_expression
- practical_view
- creative_view
- brief_response
- set_language
- off_topic
transitions:
thoughtful_reflection:
ai_feedback:
tokens_for_ai: |
Beautiful reflection on fashion!
Acknowledge their personal connection.
Reference their journey through this activity.
Encourage continued self-expression.
metadata_add:
score: "n+1"
activity_completed: "true"
next_section_and_step: conclusion:step_1
self_expression:
ai_feedback:
tokens_for_ai: |
Fashion is the perfect medium for self-expression!
Celebrate their desire to show their personality.
Encourage authenticity in their style choices.
metadata_add:
activity_completed: "true"
next_section_and_step: conclusion:step_1
practical_view:
ai_feedback:
tokens_for_ai: |
Practical fashion is smart fashion!
Function and style can coexist beautifully.
Acknowledge the value of comfort and versatility.
metadata_add:
activity_completed: "true"
next_section_and_step: conclusion:step_1
creative_view:
ai_feedback:
tokens_for_ai: |
Fashion IS art!
Celebrate their creative perspective.
Encourage experimenting and pushing boundaries.
metadata_add:
activity_completed: "true"
next_section_and_step: conclusion:step_1
brief_response:
ai_feedback:
tokens_for_ai: |
Thank them for sharing!
Summarize key fashion principles from this activity.
Encourage them to keep exploring their style.
metadata_add:
activity_completed: "true"
next_section_and_step: conclusion:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: fashion_wisdom:step_1
off_topic:
content_blocks:
- "Let's reflect on fashion! What role do clothes play in your life and how you present yourself?"
next_section_and_step: fashion_wisdom:step_1
- section_id: conclusion
title: Your Fashion Journey Continues
steps:
- step_id: step_1
title: Keep Shining
content_blocks:
- "## You're a Fashion Star! ⭐✨"
- ""
- "**What You've Explored:**"
- "✓ Discovered your personal style"
- "✓ Learned about colors and their power"
- "✓ Built outfits for different occasions"
- "✓ Explored statement pieces"
- "✓ Defined your fashion philosophy"
- ""
- "**Remember:**"
- "- Fashion is about feeling good in your skin"
- "- Confidence is the key to any outfit"
- "- Your style will evolve—embrace it!"
- "- There are no mistakes in fashion, only experiments"
- ""
- "**Next Steps:**"
- "- Clean out your closet (donate what doesn't serve you)"
- "- Try one new style element this week"
- "- Mix pieces you've never combined before"
- "- Take photos of outfits you love"
- "- Follow fashion inspiration that resonates with YOU"
- ""
- "**Your style is uniquely YOURS. Wear it proudly! 💖**"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

367
research/activity4.yaml Normal file
View file

@ -0,0 +1,367 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Mario"
steps:
- step_id: "step_1"
title: "Who is Mario?"
content_blocks:
- "Welcome to the Mario trivia game!"
#- "Mario is a famous video game character created by Nintendo. He is known for his adventures in various games."
tokens_for_ai: "Explain who Mario is and his significance in video games in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Who is Mario?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know who Mario is."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Mario. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Mario."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Mario in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Mario's First Game"
content_blocks: []
#content_blocks:
# - "Mario first appeared in the game Donkey Kong in 1981."
# - "In this game, Mario had to rescue a damsel in distress from a giant ape named Donkey Kong."
tokens_for_ai: "Explain Mario's first appearance in video games in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What was the first game Mario appeared in?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about Mario's first game."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Mario's first game. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Mario's first game."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Mario's first game in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Mario's Friends and Foes"
steps:
- step_id: "step_1"
title: "Mario's Friends"
content_blocks:
- "Mario has many friends who help him on his adventures."
#- "Some of his friends include Luigi, Princess Peach, and Yoshi."
tokens_for_ai: "Explain who Mario's friends are in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some of Mario's friends?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about Mario's friends."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Mario's friends. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Mario's friends."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Mario's friends in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Mario's Foes"
content_blocks:
- "Mario also has many enemies that he has to defeat."
#- "Some of his foes include Bowser, Goombas, and Koopa Troopas."
tokens_for_ai: "Explain who Mario's foes are in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some of Mario's foes?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about Mario's foes."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Mario's foes. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Mario's foes."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Mario's foes in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Mario's Adventures"
steps:
- step_id: "step_1"
title: "Super Mario Bros."
content_blocks:
- "One of the most famous Mario games is Super Mario Bros., released in 1985."
#- "In this game, Mario must rescue Princess Peach from Bowser."
tokens_for_ai: "Explain the game Super Mario Bros. in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the main objective in Super Mario Bros.?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know the main objective in Super Mario Bros."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Super Mario Bros. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Super Mario Bros."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Super Mario Bros. in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Mario Kart"
content_blocks:
- "Mario Kart is a popular racing game series featuring Mario and his friends."
#- "Players race against each other on various tracks and use items to gain an advantage."
tokens_for_ai: "Explain the game Mario Kart in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the main objective in Mario Kart?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know the main objective in Mario Kart."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Mario Kart. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Mario Kart."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Mario Kart in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Mario's Power-Ups"
steps:
- step_id: "step_1"
title: "Super Mushroom"
content_blocks: []
#content_blocks:
# - "The Super Mushroom is a power-up that makes Mario grow bigger."
# - "It allows Mario to take an extra hit from enemies."
tokens_for_ai: "Explain the Super Mushroom power-up in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What does the Super Mushroom do?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know what the Super Mushroom does."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about the Super Mushroom. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Super Mushroom."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Super Mushroom in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Fire Flower"
content_blocks: []
#content_blocks:
# - "The Fire Flower is a power-up that gives Mario the ability to throw fireballs."
# - "It allows Mario to defeat enemies from a distance."
tokens_for_ai: "Explain the Fire Flower power-up in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What does the Fire Flower do?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know what the Fire Flower does."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about the Fire Flower. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Fire Flower."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Fire Flower in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Mario's Worlds"
steps:
- step_id: "step_1"
title: "Mushroom Kingdom"
content_blocks: []
#content_blocks:
# - "The Mushroom Kingdom is the main setting for many Mario games."
# - "It is ruled by Princess Peach and is often threatened by Bowser."
tokens_for_ai: "Explain the Mushroom Kingdom in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the Mushroom Kingdom?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about the Mushroom Kingdom."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about the Mushroom Kingdom. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the Mushroom Kingdom."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the Mushroom Kingdom in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Bowser's Castle"
content_blocks: []
#content_blocks:
# - "Bowser's Castle is the home of Mario's arch-enemy, Bowser."
# - "It is often the final level in many Mario games, where Mario must defeat Bowser to rescue Princess Peach."
tokens_for_ai: "Explain Bowser's Castle in a friendly and engaging manner suitable for a 13-year-old. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is Bowser's Castle?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about Bowser's Castle."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Bowser's Castle. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Bowser's Castle."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Bowser's Castle in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_3"
title: "The End."
content_blocks:
- "The End."

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,786 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate the student's understanding of basic statistical concepts.
Consider:
- Grasp of central tendency (mean, median, mode)
- Understanding of variation and spread
- Ability to interpret data
- Recognition of distributions
- Practical application of concepts
Provide clear explanations with real-world examples.
sections:
- section_id: introduction
title: Welcome to Statistics
steps:
- step_id: welcome
title: Why Statistics Matters
content_blocks:
- "# Statistics 101: Making Sense of Data 📊"
- ""
- "**Welcome to the world of statistics!**"
- ""
- "Statistics helps us:"
- "- Understand patterns in data"
- "- Make informed decisions"
- "- Test hypotheses scientifically"
- "- Predict future outcomes"
- "- Avoid being fooled by randomness"
- ""
- "**You'll learn:**"
- "✓ Measures of central tendency (mean, median, mode)"
- "✓ Measures of spread (range, variance, standard deviation)"
- "✓ Probability basics"
- "✓ Distributions and what they mean"
- "✓ How to interpret data"
- ""
- "**Real-world applications:**"
- "- Medicine (clinical trial results)"
- "- Business (sales forecasting)"
- "- Sports (player performance)"
- "- Science (experimental data)"
- "- Everyday decisions (risk assessment)"
question: Ready to learn how to understand data and make better decisions?
tokens_for_ai: |
Accept positive responses as 'ready'.
Language preference as 'set_language'.
Otherwise 'off_topic'.
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- "Excellent! Let's start with the basics of describing data! 📈"
next_section_and_step: central_tendency:step_1
set_language:
content_blocks:
- "Language preference updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- "Let's learn statistics together! Are you ready to begin?"
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: central_tendency
title: Describing Data - Central Tendency
steps:
- step_id: step_1
title: The Center of Data
content_blocks:
- "## Central Tendency: Finding the 'Middle' 📍"
- ""
- "When we have a dataset, we often want to describe it with a single number that represents the 'typical' or 'central' value."
- ""
- "**Three measures of central tendency:**"
- ""
- "**1. Mean (Average)**"
- "- Sum all values and divide by the count"
- "- Most commonly used"
- "- Sensitive to extreme values (outliers)"
- "- Example: Test scores 80, 85, 90, 95 → Mean = (80+85+90+95)/4 = 87.5"
- ""
- "**2. Median (Middle Value)**"
- "- The middle number when data is sorted"
- "- Not affected by outliers"
- "- Better for skewed data"
- "- Example: Salaries $30k, $35k, $40k, $45k, $200k → Median = $40k"
- ""
- "**3. Mode (Most Frequent)**"
- "- The value that appears most often"
- "- Useful for categorical data"
- "- Can have multiple modes or no mode"
- "- Example: Shoe sizes 7, 8, 8, 8, 9, 10 → Mode = 8"
- ""
- "**When to use which:**"
- "- Mean: Normally distributed data without outliers"
- "- Median: Skewed data or data with outliers (like income)"
- "- Mode: Categorical data or finding most common value"
question: "You have exam scores: 60, 70, 75, 80, 85, 90, 95. What is the median score?"
tokens_for_ai: |
The median is the middle value when sorted.
Scores: 60, 70, 75, 80, 85, 90, 95 (7 values)
Middle value (4th position) = 80
Categorize as:
- correct: Says 80 or "eighty"
- calculated_mean: Says 79.3 or ~79 (they calculated the mean instead)
- close: Says 75 or 85 (one position off)
- confused: Incorrect answer showing confusion
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Praise them! Explain why 80 is the middle value.
- Note that with odd numbers, median is straightforward.
If they calculated mean:
- Good effort but that's the mean!
- Explain median is the MIDDLE value when sorted, not the average.
If close or confused:
- Show the sorted list: 60, 70, 75, [80], 85, 90, 95
- The middle position (4th out of 7) is 80.
buckets:
- correct
- calculated_mean
- close
- confused
- set_language
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Perfect! 80 is the median - the middle value.
With 7 values, the 4th position is the center.
Median is great because outliers don't affect it!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: central_tendency:step_2
calculated_mean:
ai_feedback:
tokens_for_ai: |
That's the mean (average), not the median!
Median = middle value when sorted.
For 60,70,75,[80],85,90,95 → median is 80.
The mean would be all values summed divided by 7.
metadata_add:
score: "n+1"
next_section_and_step: central_tendency:step_2
close:
ai_feedback:
tokens_for_ai: |
Close! You're near the middle.
Sort the values: 60, 70, 75, [80], 85, 90, 95
The exact middle (4th position out of 7) is 80.
next_section_and_step: central_tendency:step_1
confused:
content_blocks:
- "The median is the MIDDLE value when you sort the numbers from smallest to largest."
- "With 7 values, the 4th number is in the middle."
next_section_and_step: central_tendency:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: central_tendency:step_1
off_topic:
content_blocks:
- "Let's find the median! Sort the scores and identify the middle value."
next_section_and_step: central_tendency:step_1
- step_id: step_2
title: Mean vs Median with Outliers
content_blocks:
- "## The Power of Median: Handling Outliers 🎯"
- ""
- "**Why median matters: The salary example**"
- ""
- "Imagine a small company with 5 employees and their salaries:"
- "- Employee A: $40,000"
- "- Employee B: $45,000"
- "- Employee C: $50,000"
- "- Employee D: $55,000"
- "- CEO: $500,000"
- ""
- "**Mean salary:** ($40k + $45k + $50k + $55k + $500k) / 5 = $138,000"
- "**Median salary:** $50,000 (the middle value)"
- ""
- "**Which better represents the 'typical' employee salary?**"
- "The median! The mean is dragged up by the CEO's outlier salary."
- ""
- "**This is why:**"
- "- Median home prices are reported (not mean)"
- "- Median household income is used (not mean)"
- "- Outliers don't distort the median"
- ""
- "**When one extreme value can mislead, use median!**"
question: "A neighborhood has 6 home prices: $200k, $210k, $220k, $230k, $240k, and $2,000k. If someone says 'the average home price is $516k,' why might that be misleading? What would better represent typical home prices?"
tokens_for_ai: |
They should recognize that:
- The $2 million home is an outlier
- Mean is misleading ($516k)
- Median would be better (between $220k and $230k = $225k)
Categorize as:
- excellent_understanding: Mentions outlier skewing mean, median better
- understands_outlier: Recognizes the expensive house is the problem
- suggests_median: Says median without explaining why
- partial_understanding: On the right track but incomplete
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Validate their understanding of outliers affecting mean!
Key points:
- The $2M home is an outlier (way higher than others)
- Mean gets pulled up to $516k (not representative)
- Median would be $225k (between 220 and 230) - much more typical
- This is why real estate uses median prices!
Praise their critical thinking about statistics.
buckets:
- excellent_understanding
- understands_outlier
- suggests_median
- partial_understanding
- set_language
- off_topic
transitions:
excellent_understanding:
ai_feedback:
tokens_for_ai: |
Brilliant analysis!
Yes - the $2M outlier drags the mean to $516k, misleading!
The median ($225k) better represents typical homes.
This is exactly why statistics literacy matters!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: spread:step_1
understands_outlier:
ai_feedback:
tokens_for_ai: |
Exactly! The $2M home is an outlier.
It pulls the mean to $516k, but most homes are $200-240k.
The median ($225k) would be more representative.
Great critical thinking!
metadata_add:
score: "n+1"
next_section_and_step: spread:step_1
suggests_median:
ai_feedback:
tokens_for_ai: |
Good instinct - median is better here!
Why? The $2M outlier skews the mean to $516k.
But the median ($225k) represents the typical home price.
Outliers don't affect median - that's its power!
next_section_and_step: spread:step_1
partial_understanding:
ai_feedback:
tokens_for_ai: |
You're on the right track!
The key: one $2M home among $200-240k homes.
This outlier pulls mean to $516k (misleading).
Median ($225k) better shows typical prices.
next_section_and_step: spread:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: central_tendency:step_2
off_topic:
content_blocks:
- "Think about: Does $516k accurately represent what most homes in this neighborhood cost?"
next_section_and_step: central_tendency:step_2
- section_id: spread
title: Measuring Spread - Variability
steps:
- step_id: step_1
title: Understanding Variability
content_blocks:
- "## Spread: How Much Do Values Vary? 📏"
- ""
- "Central tendency tells us the 'middle,' but doesn't tell the full story."
- ""
- "**Consider two classes:**"
- "- Class A scores: 80, 82, 78, 81, 79 (mean = 80)"
- "- Class B scores: 50, 70, 80, 90, 110 (mean = 80)"
- ""
- "Same mean, VERY different distributions!"
- "Class A is consistent. Class B is all over the place."
- ""
- "**Measures of Spread:**"
- ""
- "**1. Range**"
- "- Maximum value minus minimum value"
- "- Simple but sensitive to outliers"
- "- Class A: 82 - 78 = 4"
- "- Class B: 110 - 50 = 60"
- ""
- "**2. Variance**"
- "- Average of squared differences from mean"
- "- Measures how spread out values are"
- "- Larger variance = more spread"
- ""
- "**3. Standard Deviation (SD)**"
- "- Square root of variance"
- "- Same units as original data (easier to interpret)"
- "- Most commonly used measure of spread"
- ""
- "**Why spread matters:**"
- "- Quality control (consistency in manufacturing)"
- "- Risk assessment (investment volatility)"
- "- Performance evaluation (consistency vs streaky)"
- "- Research (reliability of measurements)"
question: "Two basketball players both average 20 points per game. Player A's scores: 18, 19, 20, 21, 22. Player B's scores: 5, 10, 20, 30, 35. Which player is more consistent, and why does that matter?"
tokens_for_ai: |
Player A is more consistent (low spread/variance).
Player B is inconsistent/volatile (high spread).
Look for understanding that:
- Player A has consistent performance (small variation)
- Player B is unpredictable (large variation)
- Consistency matters for reliability/strategy
Categorize as:
- excellent_answer: Identifies Player A as consistent AND explains why it matters
- identifies_player_a: Correctly says Player A is more consistent
- identifies_inconsistency: Recognizes the difference in variability
- basic_answer: Mentions one player without explaining
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Affirm their understanding of consistency/spread!
Key points:
- Player A: very consistent (range 18-22, low variation)
- Player B: unpredictable (range 5-35, high variation)
- Consistency matters: reliable performance, easier to plan around
- Player B might have higher ceiling but less reliable
Connect to real sports analysis and standard deviation concept.
buckets:
- excellent_answer
- identifies_player_a
- identifies_inconsistency
- basic_answer
- set_language
- off_topic
transitions:
excellent_answer:
ai_feedback:
tokens_for_ai: |
Perfect analysis!
Player A: 18-22 (consistent, low spread).
Player B: 5-35 (volatile, high spread).
Consistency means reliability - you know what to expect!
This is what standard deviation measures!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: probability:step_1
identifies_player_a:
ai_feedback:
tokens_for_ai: |
Correct! Player A is much more consistent.
Range: A is 18-22 (4 points), B is 5-35 (30 points!).
Low spread = predictable performance.
High spread = unpredictable, risky.
That's what measuring spread tells us!
metadata_add:
score: "n+1"
next_section_and_step: probability:step_1
identifies_inconsistency:
ai_feedback:
tokens_for_ai: |
Good observation about the difference!
Player A varies 18-22 (tight, consistent).
Player B varies 5-35 (wild, unpredictable).
Consistency = reliability. This is why we measure spread!
next_section_and_step: probability:step_1
basic_answer:
ai_feedback:
tokens_for_ai: |
Let's look at the ranges:
Player A: 18, 19, 20, 21, 22 (very tight - consistent!)
Player B: 5, 10, 20, 30, 35 (all over - inconsistent!)
Consistency means you can rely on them. Spread measures this!
next_section_and_step: probability:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: spread:step_1
off_topic:
content_blocks:
- "Compare the ranges: Player A (18-22) vs Player B (5-35). Who's more predictable?"
next_section_and_step: spread:step_1
- section_id: probability
title: Probability Basics
steps:
- step_id: step_1
title: Understanding Probability
content_blocks:
- "## Probability: Quantifying Uncertainty 🎲"
- ""
- "**What is probability?**"
- "A measure of how likely something is to happen."
- ""
- "**Probability scale:**"
- "- 0 = Impossible (0%)"
- "- 0.5 = Even chance (50%)"
- "- 1 = Certain (100%)"
- ""
- "**Basic probability formula:**"
- "P(event) = (Number of favorable outcomes) / (Total possible outcomes)"
- ""
- "**Example: Fair die**"
- "- P(rolling a 3) = 1/6 ≈ 0.167 (16.7%)"
- "- P(rolling even) = 3/6 = 0.5 (50%)"
- "- P(rolling 1-6) = 6/6 = 1 (100%)"
- ""
- "**Key concepts:**"
- ""
- "**Independent events:**"
- "- One doesn't affect the other"
- "- Coin flips, die rolls"
- "- P(heads then heads) = 0.5 × 0.5 = 0.25"
- ""
- "**Dependent events:**"
- "- One affects the probability of the other"
- "- Drawing cards without replacement"
- ""
- "**Common misconceptions:**"
- "- Gambler's fallacy: 'It's due!' (No - each event is independent)"
- "- Hot hand fallacy: Past streaks predict future (they don't in random events)"
question: "You flip a fair coin 5 times and get heads every time. What's the probability the 6th flip is heads? Why?"
tokens_for_ai: |
Correct answer: 50% or 0.5 or 1/2
Key understanding: Each flip is INDEPENDENT.
Past flips don't affect future flips.
Common wrong answer: "It's more likely to be tails" (gambler's fallacy)
Categorize as:
- correct_with_reasoning: Says 50% AND explains independence
- correct_answer: Says 50% without full explanation
- gamblers_fallacy: Says tails is more likely because "it's due"
- pattern_thinking: Thinks the pattern will continue
- confused: Other incorrect reasoning
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Excellent! Each flip is independent.
- Past results don't affect future flips.
- The coin has no "memory" - always 50/50.
If gambler's fallacy:
- Common misconception! This is the "gambler's fallacy."
- Each flip is independent - past doesn't affect future.
- It's still 50/50, even after 100 heads in a row!
- The coin doesn't "owe" you tails.
Explain independence clearly.
buckets:
- correct_with_reasoning
- correct_answer
- gamblers_fallacy
- pattern_thinking
- confused
- set_language
- off_topic
transitions:
correct_with_reasoning:
ai_feedback:
tokens_for_ai: |
Perfect understanding!
Each coin flip is independent - past doesn't affect future.
The coin has no memory. Always 50/50!
You've avoided the gambler's fallacy - great!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: distributions:step_1
correct_answer:
ai_feedback:
tokens_for_ai: |
Correct - still 50%!
Why? Each flip is INDEPENDENT.
Past flips don't affect future flips.
The coin doesn't "remember" or "balance out."
Great job avoiding the gambler's fallacy!
metadata_add:
score: "n+1"
next_section_and_step: distributions:step_1
gamblers_fallacy:
ai_feedback:
tokens_for_ai: |
Common misconception! This is the "gambler's fallacy."
Each flip is INDEPENDENT - the coin has no memory.
Past flips don't affect future flips.
It's still 50/50, even after 1000 heads!
The coin doesn't "owe" you tails.
next_section_and_step: probability:step_1
pattern_thinking:
ai_feedback:
tokens_for_ai: |
The streak feels meaningful, but it's not!
Each flip is independent - 50/50 every time.
Past results don't predict future with fair coins.
Random sequences often have "patterns" but they're meaningless.
next_section_and_step: probability:step_1
confused:
content_blocks:
- "Key concept: INDEPENDENCE"
- "Each coin flip is independent - past flips don't affect future flips."
- "A fair coin always has 50% chance of heads, regardless of history."
next_section_and_step: probability:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: probability:step_1
off_topic:
content_blocks:
- "Think: Does the coin 'remember' previous flips? Are they independent events?"
next_section_and_step: probability:step_1
- section_id: distributions
title: Understanding Distributions
steps:
- step_id: step_1
title: The Normal Distribution
content_blocks:
- "## The Normal Distribution: Nature's Pattern 📊"
- ""
- "**The bell curve (normal distribution):**"
- "The most important distribution in statistics!"
- ""
- "**Characteristics:**"
- "- Symmetric, bell-shaped"
- "- Mean = Median = Mode (at the center)"
- "- Most data near the mean"
- "- Tails extend infinitely (but rarely reach extremes)"
- ""
- "**The 68-95-99.7 Rule (Empirical Rule):**"
- "- 68% of data within 1 standard deviation of mean"
- "- 95% of data within 2 standard deviations"
- "- 99.7% of data within 3 standard deviations"
- ""
- "**Example: IQ scores**"
- "- Mean = 100, Standard Deviation = 15"
- "- 68% of people: IQ between 85-115"
- "- 95% of people: IQ between 70-130"
- "- 99.7% of people: IQ between 55-145"
- ""
- "**Why normal distribution matters:**"
- "- Many natural phenomena follow it (height, measurement errors)"
- "- Central Limit Theorem (averages tend toward normal)"
- "- Foundation for many statistical tests"
- "- Allows predictions and probability calculations"
- ""
- "**Real-world examples:**"
- "- Test scores, heights, blood pressure, measurement errors"
question: "SAT scores are normally distributed with mean 1000 and standard deviation 200. Using the 68-95-99.7 rule, approximately what percentage of students score between 800 and 1200?"
tokens_for_ai: |
800 to 1200 is mean (1000) ± 1 standard deviation (200).
68% of data falls within 1 SD of the mean.
Correct answer: 68% (or approximately 68%, or about 2/3)
Categorize as:
- correct: Says 68% or approximately 68%
- close: Says 66% or 70% (reasonably close)
- says_95: Says 95% (confused 1 SD with 2 SD)
- unclear_reasoning: Wrong answer showing confusion
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Excellent! 800-1200 is 1000 ± 200 (1 SD).
- 68% of data within 1 SD of mean.
- You've mastered the empirical rule!
If says 95%:
- Close reasoning! But 95% is for 2 SDs.
- 800-1200 is only 1 SD (200 points) from mean.
- 1 SD = 68%, 2 SDs = 95%, 3 SDs = 99.7%
Explain the calculation clearly.
buckets:
- correct
- close
- says_95
- unclear_reasoning
- set_language
- off_topic
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Perfect! 800-1200 is mean ± 1 SD.
1 SD = 68% of data.
You understand the empirical rule!
This is fundamental for interpreting normal distributions!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: conclusion:step_1
close:
ai_feedback:
tokens_for_ai: |
Very close! The exact answer is 68%.
800-1200 = 1000 ± 200 (1 standard deviation).
The 68-95-99.7 rule: 68% within 1 SD.
Great understanding of the concept!
metadata_add:
score: "n+1"
next_section_and_step: conclusion:step_1
says_95:
ai_feedback:
tokens_for_ai: |
You're thinking of the right rule, but different range!
95% is for 2 standard deviations (600-1400).
800-1200 is only 1 SD (200 points) from mean.
1 SD = 68%, 2 SDs = 95%, 3 SDs = 99.7%
next_section_and_step: distributions:step_1
unclear_reasoning:
content_blocks:
- "Use the 68-95-99.7 rule:"
- "800-1200 is the mean (1000) ± 200"
- "200 is 1 standard deviation"
- "68% of data falls within 1 SD of the mean"
next_section_and_step: distributions:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: distributions:step_1
off_topic:
content_blocks:
- "Calculate: How many standard deviations is 800-1200 from the mean (1000)?"
next_section_and_step: distributions:step_1
- section_id: conclusion
title: Statistics Mastery
steps:
- step_id: step_1
title: Applying Statistical Thinking
content_blocks:
- "## Congratulations, Statistician! 🎓📊"
- ""
- "**You've mastered the fundamentals!**"
- ""
- "**What you've learned:**"
- "✓ Central Tendency (mean, median, mode)"
- "✓ When to use median vs mean (outliers!)"
- "✓ Measures of spread (range, variance, standard deviation)"
- "✓ Probability and independence"
- "✓ The normal distribution and 68-95-99.7 rule"
- ""
- "**Real-world statistical thinking:**"
- ""
- "**Evaluating claims:**"
- "- 'Average salary is $100k!' → Check for outliers, ask for median"
- "- 'Significant difference!' → What's the sample size?"
- "- 'This trend proves...' → Correlation ≠ causation"
- ""
- "**Making decisions:**"
- "- Compare means AND spreads (consistency matters!)"
- "- Understand probability (avoid gambler's fallacy)"
- "- Consider distributions (is it normal? skewed?)"
- ""
- "**Critical thinking:**"
- "- Always ask: What's the sample size?"
- "- Question: How was data collected?"
- "- Consider: What's being measured exactly?"
- "- Look for: Potential biases or confounding factors"
question: "How will you use statistical thinking in your daily life? Give an example of where understanding statistics could help you make better decisions."
tokens_for_ai: |
This is a reflection question.
Look for application of concepts learned:
- Evaluating claims with mean/median awareness
- Understanding probability in decisions
- Recognizing variability/consistency
- Critical thinking about data
Categorize as:
- excellent_application: Specific example showing deep understanding
- practical_example: Good real-world application
- general_reflection: Acknowledges usefulness
- brief_response: Short but relevant
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Provide encouraging, personalized feedback!
Validate their example if they give one.
Add suggestions for statistical thinking in daily life:
- Evaluating news/research claims
- Financial decisions (investments, insurance)
- Health decisions (understanding medical stats)
- Sports analysis
- Weather forecasts (probability!)
Celebrate their completion of Statistics 101!
buckets:
- excellent_application
- practical_example
- general_reflection
- brief_response
- set_language
- off_topic
transitions:
excellent_application:
ai_feedback:
tokens_for_ai: |
Fantastic example showing real understanding!
Reference their specific application.
Emphasize how statistical literacy empowers better decisions.
Encourage continued critical thinking with data!
metadata_add:
activity_completed: "true"
practical_example:
ai_feedback:
tokens_for_ai: |
Great practical thinking!
Acknowledge their example.
Statistics helps us cut through misleading claims.
You now have tools to think critically about data!
metadata_add:
activity_completed: "true"
general_reflection:
ai_feedback:
tokens_for_ai: |
Good reflection!
Statistics is everywhere - news, health, money, sports.
You can now question claims and understand probability.
Keep thinking statistically!
metadata_add:
activity_completed: "true"
brief_response:
ai_feedback:
tokens_for_ai: |
Thank you for completing Statistics 101!
You've gained powerful tools for understanding data.
Use them to make informed decisions and question claims!
metadata_add:
activity_completed: "true"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: conclusion:step_1
off_topic:
content_blocks:
- "Reflect on: How could understanding mean, median, probability, and distributions help you in everyday decisions?"
next_section_and_step: conclusion:step_1

View file

@ -0,0 +1,740 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate understanding of basic game theory concepts.
Consider:
- Grasp of strategic interaction
- Understanding of Nash equilibrium
- Recognition of dominant strategies
- Ability to analyze simple games
- Application to real-world scenarios
Provide clear explanations with examples.
sections:
- section_id: introduction
title: Welcome to Game Theory
steps:
- step_id: welcome
title: Strategic Thinking
content_blocks:
- "# Game Theory 101: The Science of Strategy 🎮🧠"
- ""
- "**Welcome to game theory!**"
- ""
- "Game theory is the study of strategic interaction - how people make decisions when their outcomes depend on others' choices."
- ""
- "**Not just for games:**"
- "- Business competition (pricing, market entry)"
- "- International relations (nuclear deterrence, trade)"
- "- Biology (evolution, animal behavior)"
- "- Economics (auctions, bargaining)"
- "- Everyday life (traffic, cooperation)"
- ""
- "**You'll learn:**"
- "✓ The Prisoner's Dilemma (cooperation vs self-interest)"
- "✓ Nash Equilibrium (stable strategies)"
- "✓ Dominant strategies (always-best moves)"
- "✓ Zero-sum vs positive-sum games"
- "✓ How to analyze strategic situations"
- ""
- "**Real applications:**"
- "- Why cartels are unstable"
- "- Why arms races happen"
- "- When cooperation emerges"
- "- How auctions should be designed"
question: Ready to learn how to think strategically about interactive decisions?
tokens_for_ai: |
Accept positive responses as 'ready'.
Language preference as 'set_language'.
Otherwise 'off_topic'.
buckets:
- ready
- set_language
- off_topic
transitions:
ready:
content_blocks:
- "Excellent! Let's start with the most famous game in game theory! 🎯"
next_section_and_step: prisoners_dilemma:step_1
set_language:
content_blocks:
- "Language preference updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
content_blocks:
- "Let's learn strategic thinking together! Ready to begin?"
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: prisoners_dilemma
title: The Prisoner's Dilemma
steps:
- step_id: step_1
title: The Classic Dilemma
content_blocks:
- "## The Prisoner's Dilemma: Cooperation vs Self-Interest 🚔"
- ""
- "**The Scenario:**"
- ""
- "Two criminals are arrested and interrogated separately. The prosecutor offers each the same deal:"
- ""
- "**If you both stay silent:**"
- "- Each gets 1 year in prison (light sentence, lack of evidence)"
- ""
- "**If you betray your partner but they stay silent:**"
- "- You go free (0 years)"
- "- Your partner gets 3 years"
- ""
- "**If you both betray each other:**"
- "- Each gets 2 years"
- ""
- "**Payoff matrix (years in prison - lower is better):**"
- ""
- "```"
- " Player B"
- " Silent Betray"
- "Player A Silent (-1,-1) (-3,0)"
- " Betray (0,-3) (-2,-2)"
- "```"
- ""
- "**The dilemma:**"
- "- **Collectively best:** Both stay silent (-1 each)"
- "- **Individually rational:** Both betray (-2 each)"
- ""
- "**Why betray dominates:**"
- "- If partner stays silent: Betray gets you 0 vs 1 year (betray better!)"
- "- If partner betrays: Betray gets you 2 vs 3 years (betray better!)"
- "- No matter what partner does, betraying is better for YOU"
- ""
- "**The tragedy:** Both act rationally, both end up worse off (-2 each) than if they'd cooperated (-1 each)!"
question: "You're playing prisoner's dilemma once with a stranger you'll never meet again. What should you do from a purely self-interested perspective, and why?"
tokens_for_ai: |
Correct answer: Betray (or defect/confess)
Reasoning: Betraying is a DOMINANT STRATEGY
- Dominates silence regardless of what partner does
- If partner silent: 0 years better than 1 year
- If partner betrays: 2 years better than 3 years
Look for understanding of dominant strategy.
Categorize as:
- correct_with_reasoning: Says betray AND explains dominant strategy
- correct_answer: Says betray without full explanation
- says_cooperate: Says stay silent (cooperative but not rational in one-shot)
- game_theory_aware: Mentions dilemma nature even if wrong choice
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Excellent! Betraying is the DOMINANT STRATEGY.
- No matter what the other player does, betraying is better for YOU.
- This is rational but leads to both getting -2 instead of -1.
- That's the tragedy of the Prisoner's Dilemma!
If says cooperate:
- Noble but not strategically optimal in a one-shot game!
- Betraying DOMINATES: better outcome regardless of partner's choice.
- In one-shot games with strangers, defection is predicted.
- (Later we'll see when cooperation can emerge in repeated games!)
Explain dominant strategy concept clearly.
buckets:
- correct_with_reasoning
- correct_answer
- says_cooperate
- game_theory_aware
- set_language
- off_topic
transitions:
correct_with_reasoning:
ai_feedback:
tokens_for_ai: |
Perfect strategic analysis!
Betraying is the DOMINANT STRATEGY - always better for you.
Even though both cooperating would be better collectively (-1 each),
individual rationality leads to mutual defection (-2 each).
This is the fundamental insight of game theory!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: prisoners_dilemma:step_2
correct_answer:
ai_feedback:
tokens_for_ai: |
Correct! Betraying is the rational choice.
Why? It's a DOMINANT STRATEGY.
No matter what your partner does, betraying gives YOU a better outcome.
If they stay silent: 0 < 1. If they betray: 2 < 3.
This individual rationality creates the dilemma!
metadata_add:
score: "n+1"
next_section_and_step: prisoners_dilemma:step_2
says_cooperate:
ai_feedback:
tokens_for_ai: |
Cooperation would be great if you could trust them!
But from pure self-interest in a ONE-SHOT game:
Betraying DOMINATES staying silent.
If they're silent: 0 years (betray) beats 1 year (silent).
If they betray: 2 years (betray) beats 3 years (silent).
Betraying is always better for YOU - that's the dilemma!
next_section_and_step: prisoners_dilemma:step_2
game_theory_aware:
ai_feedback:
tokens_for_ai: |
You sense the dilemma!
From pure self-interest: betraying DOMINATES.
It's better for you no matter what they do.
Both thinking this way → both defect → both get -2.
Could've gotten -1 each if they cooperated. That's the tragedy!
next_section_and_step: prisoners_dilemma:step_2
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: prisoners_dilemma:step_1
off_topic:
content_blocks:
- "Think strategically: What gives YOU the best outcome regardless of what your partner does?"
next_section_and_step: prisoners_dilemma:step_1
- step_id: step_2
title: Real-World Dilemmas
content_blocks:
- "## Prisoner's Dilemma Everywhere! 🌍"
- ""
- "The Prisoner's Dilemma structure appears constantly:"
- ""
- "**Business cartels:**"
- "- Cooperate: Keep prices high (both profit)"
- "- Defect: Undercut price (steal market share)"
- "- Problem: Undercutting is always tempting!"
- "- Result: Cartels are unstable"
- ""
- "**Arms races:**"
- "- Cooperate: Don't build weapons (both save money)"
- "- Defect: Build weapons (get advantage if opponent doesn't)"
- "- Problem: Building weapons dominates"
- "- Result: Costly arms races"
- ""
- "**Environmental pollution:**"
- "- Cooperate: Reduce emissions (collective good)"
- "- Defect: Pollute freely (save costs)"
- "- Problem: Individual incentive to pollute"
- "- Result: Tragedy of the commons"
- ""
- "**Doping in sports:**"
- "- Cooperate: Stay clean (fair competition)"
- "- Defect: Dope (gain advantage)"
- "- Problem: If others dope, you must too to compete"
- "- Result: Widespread doping"
- ""
- "**The pattern:**"
- "Individual rationality → collectively bad outcome"
question: "Can you think of another real-world situation that has Prisoner's Dilemma structure? Describe what cooperation and defection look like."
tokens_for_ai: |
Look for recognition of the PD structure:
- Two or more parties
- Temptation to defect while others cooperate
- Mutual defection worse than mutual cooperation
- Defection is individually rational
Examples: cheating in class, tax evasion, littering, free-riding,
overfishing, etc.
Categorize as:
- excellent_example: Clear PD structure with cooperation/defection explained
- good_example: Recognizes PD structure
- vague_example: Right idea but unclear
- not_quite_pd: Example doesn't fit structure
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If they identify a good example:
- Validate it! Explain how it fits PD structure.
- Point out: cooperation better collectively, defection individually rational.
- This recognition helps understand so many social problems!
If example doesn't quite fit:
- Acknowledge the thinking.
- Explain what makes something a PD: mutual defection < mutual cooperation < defection while others cooperate.
- Offer a clearer example.
Celebrate their application of game theory!
buckets:
- excellent_example
- good_example
- vague_example
- not_quite_pd
- set_language
- off_topic
transitions:
excellent_example:
ai_feedback:
tokens_for_ai: |
Brilliant example!
Reference their specific example and confirm the PD structure.
Point out: cooperation collectively better, but defection individually tempting.
This is why so many social problems are hard to solve!
Game theory helps us recognize these structures!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: nash_equilibrium:step_1
good_example:
ai_feedback:
tokens_for_ai: |
Great example!
Confirm it has PD structure: defection tempting, but mutual defection worse.
This pattern is everywhere once you see it!
Understanding the structure helps design solutions (regulations, incentives, reputation).
metadata_add:
score: "n+1"
next_section_and_step: nash_equilibrium:step_1
vague_example:
ai_feedback:
tokens_for_ai: |
Good thinking! Clarify how their example fits:
Cooperation = ? (collectively better)
Defection = ? (individually tempting)
Help them sharpen the structure identification.
next_section_and_step: nash_equilibrium:step_1
not_quite_pd:
ai_feedback:
tokens_for_ai: |
Interesting example but not quite Prisoner's Dilemma structure.
PD needs: mutual cooperation > mutual defection, but defection dominates.
Their example might be a different game structure.
Acknowledge their thinking, explain the distinction.
next_section_and_step: nash_equilibrium:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: prisoners_dilemma:step_2
off_topic:
content_blocks:
- "Think of situations where everyone would be better off cooperating, but individuals are tempted to cheat."
next_section_and_step: prisoners_dilemma:step_2
- section_id: nash_equilibrium
title: Nash Equilibrium
steps:
- step_id: step_1
title: Stable Strategies
content_blocks:
- "## Nash Equilibrium: The Stability Concept 🎯"
- ""
- "**Named after John Nash (Nobel Prize, 1994)**"
- ""
- "**Definition:**"
- "A Nash Equilibrium is a set of strategies where no player can improve their outcome by unilaterally changing their strategy."
- ""
- "**In simpler terms:**"
- "Everyone is playing their best response to what others are doing. No one wants to deviate."
- ""
- "**In Prisoner's Dilemma:**"
- "Both betraying is a Nash Equilibrium!"
- "- If A betrays, B's best response is betray (2 < 3 years)"
- "- If B betrays, A's best response is betray (2 < 3 years)"
- "- Neither wants to switch to silence unilaterally"
- ""
- "**Key insight:**"
- "Nash Equilibrium ≠ Best outcome for everyone"
- "It's just stable (self-enforcing)"
- ""
- "**Example: Coordination Game**"
- ""
- "Two friends picking where to meet:"
- "```"
- " Friend B"
- " Coffee Bar"
- "Friend A Coffee (2,2) (0,0)"
- " Bar (0,0) (1,1)"
- "```"
- ""
- "**Two Nash Equilibria:**"
- "1. Both go to Coffee (2,2)"
- "2. Both go to Bar (1,1)"
- ""
- "Meeting anywhere > missing each other!"
- "Coordination problems have multiple equilibria."
question: "In a game where two drivers approach an intersection, each can either Stop or Go. If both Go, they crash (payoff -10 each). If one Stops and one Goes, the goer gets +1 and the stopper gets 0. If both Stop, they're delayed (payoff -1 each). What are the Nash Equilibrium outcomes?"
tokens_for_ai: |
Payoff matrix:
Driver B
Stop Go
Driver A Stop (-1,-1) (0,+1)
Go (+1,0) (-10,-10)
Nash Equilibria: (Stop, Go) and (Go, Stop)
- If A stops, B's best response is Go
- If B goes, A's best response is Stop
- And vice versa for (Go, Stop)
NOT Nash Equilibrium:
- (Stop, Stop): Either could improve by switching to Go
- (Go, Go): Both would improve by switching to Stop
Look for identification of the two equilibria.
Categorize as:
- correct_both: Identifies both (Stop,Go) and (Go,Stop)
- identifies_one: Gets one of the two equilibria
- identifies_pattern: Recognizes one stops, one goes
- says_both_stop: Says (Stop,Stop) - incorrect
- confused: Other answers
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Correct equilibria: (Stop, Go) and (Go, Stop)
If correct:
- Excellent! Two Nash Equilibria where one stops, one goes.
- Neither wants to unilaterally change.
- This is like traffic lights solving coordination!
If says both stop:
- That seems safe but it's NOT Nash Equilibrium!
- If both stop, either could switch to Go and get +1 instead of -1.
- Nash requires no one wants to unilaterally deviate.
Explain why the two asymmetric outcomes are stable.
buckets:
- correct_both
- identifies_one
- identifies_pattern
- says_both_stop
- confused
- set_language
- off_topic
transitions:
correct_both:
ai_feedback:
tokens_for_ai: |
Perfect! Two Nash Equilibria: (Stop,Go) and (Go,Stop).
In each, no driver wants to unilaterally change.
Both stopping is NOT equilibrium - either would want to go!
This coordination problem is solved by traffic lights in reality!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: dominant_strategies:step_1
identifies_one:
ai_feedback:
tokens_for_ai: |
Good! You found one equilibrium.
But there's symmetry - also a Nash Equilibrium where roles reverse!
Both (Stop,Go) and (Go,Stop) are stable.
In each, neither wants to unilaterally change.
metadata_add:
score: "n+1"
next_section_and_step: dominant_strategies:step_1
identifies_pattern:
ai_feedback:
tokens_for_ai: |
Right idea - one stops, one goes!
Specifically: (Stop,Go) and (Go,Stop) are both Nash Equilibria.
Neither driver wants to change their strategy given the other's.
This is a coordination game solved by conventions (like traffic lights!).
next_section_and_step: dominant_strategies:step_1
says_both_stop:
ai_feedback:
tokens_for_ai: |
Seems safe, but NOT Nash Equilibrium!
At (Stop,Stop), either driver could switch to Go:
Get +1 instead of -1 while other stays stopped.
Nash requires no one wants to deviate.
The equilibria are (Stop,Go) and (Go,Stop).
next_section_and_step: nash_equilibrium:step_1
confused:
content_blocks:
- "Check each outcome: Can any player improve by switching?"
- "Nash Equilibrium: No player wants to unilaterally change strategy"
- "Hint: One driver stops, one goes (two ways to do this)"
next_section_and_step: nash_equilibrium:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: nash_equilibrium:step_1
off_topic:
content_blocks:
- "Find outcomes where neither driver would want to change their choice given what the other is doing."
next_section_and_step: nash_equilibrium:step_1
- section_id: dominant_strategies
title: Dominant Strategies
steps:
- step_id: step_1
title: Always-Best Strategies
content_blocks:
- "## Dominant Strategies: No-Brainer Moves 💪"
- ""
- "**Definition:**"
- "A dominant strategy is one that's best regardless of what other players do."
- ""
- "**If you have a dominant strategy, PLAY IT!**"
- ""
- "**In Prisoner's Dilemma:**"
- "Betraying is a dominant strategy for both players."
- "- Better if opponent stays silent: 0 < 1"
- "- Better if opponent betrays: 2 < 3"
- "- Always better!"
- ""
- "**Dominant Strategy Equilibrium:**"
- "When all players have dominant strategies, the outcome is certain!"
- "- Everyone plays their dominant strategy"
- "- This is always a Nash Equilibrium"
- "- But Nash Equilibrium doesn't always involve dominant strategies"
- ""
- "**Example without dominant strategies:**"
- ""
- "Rock-Paper-Scissors:"
- "- No strategy is always best"
- "- Best strategy depends on opponent's choice"
- "- Optimal: Randomize (mixed strategy)"
- ""
- "**Why dominant strategies matter:**"
- "- Simplify analysis (easy to predict)"
- "- Stable and robust"
- "- Used in mechanism design (incentive compatibility)"
question: "A company must choose High Price or Low Price. If both choose High, each earns $100. If both choose Low, each earns $50. If one chooses Low and other High, the low pricer earns $120 and the high pricer earns $20. Does either company have a dominant strategy? If so, what is it?"
tokens_for_ai: |
Payoff matrix:
Company B
High Low
Company A High (100,100) (20,120)
Low (120,20) (50,50)
For Company A:
- If B plays High: Low gives 120 > High gives 100 → Low better
- If B plays Low: Low gives 50 > High gives 20 → Low better
- Low DOMINATES High
Same logic for Company B.
Both have dominant strategy: Low Price
Look for recognition that Low dominates High.
Categorize as:
- correct_both_low: Says Low is dominant strategy for both
- says_low: Identifies Low without full explanation
- says_high: Says High (incorrect - not dominant)
- says_no_dominant: Says no dominant strategy exists
- unclear: Confused answer
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Correct: Low is dominant strategy for BOTH companies.
If correct:
- Excellent! Low dominates High for both.
- If opponent prices High: 120 > 100 (Low better)
- If opponent prices Low: 50 > 20 (Low better)
- Result: Both price low, earn 50 each (could've earned 100 each!)
- This is another Prisoner's Dilemma structure!
If wrong:
- Check each scenario.
- Show that Low always outperforms High regardless of opponent.
- Explain this leads to (Low,Low) equilibrium.
Connect to PD structure.
buckets:
- correct_both_low
- says_low
- says_high
- says_no_dominant
- unclear
- set_language
- off_topic
transitions:
correct_both_low:
ai_feedback:
tokens_for_ai: |
Perfect analysis!
Low DOMINATES High for both companies.
No matter what opponent does, Low is better.
Result: (Low,Low) = $50 each.
If they could cooperate: (High,High) = $100 each!
This is Prisoner's Dilemma in business form!
metadata_add:
score: "n+2"
concepts_mastered: "n+1"
next_section_and_step: conclusion:step_1
says_low:
ai_feedback:
tokens_for_ai: |
Correct! Low is the dominant strategy.
Why? Check both scenarios:
If opponent prices High: 120 (Low) > 100 (High)
If opponent prices Low: 50 (Low) > 20 (High)
Always better! This is another PD structure.
metadata_add:
score: "n+1"
next_section_and_step: conclusion:step_1
says_high:
ai_feedback:
tokens_for_ai: |
High would be great if both could commit!
But it's NOT dominant. Check:
If opponent prices Low: 20 (High) < 120 (Low)
Low is better regardless of opponent.
This is why cartels are unstable!
next_section_and_step: dominant_strategies:step_1
says_no_dominant:
ai_feedback:
tokens_for_ai: |
Actually, there IS a dominant strategy!
Compare for Company A:
- If B plays High: Low(120) > High(100)
- If B plays Low: Low(50) > High(20)
Low is always better! Same for Company B.
next_section_and_step: dominant_strategies:step_1
unclear:
content_blocks:
- "For dominant strategy, check: Is one choice ALWAYS better than the other?"
- "Compare Low vs High when opponent plays High, then when opponent plays Low"
next_section_and_step: dominant_strategies:step_1
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: dominant_strategies:step_1
off_topic:
content_blocks:
- "For each company, which strategy is better regardless of what the opponent does?"
next_section_and_step: dominant_strategies:step_1
- section_id: conclusion
title: Game Theory Foundations
steps:
- step_id: step_1
title: Strategic Thinking
content_blocks:
- "## Congratulations, Game Theorist! 🎓🎮"
- ""
- "**You've mastered the fundamentals!**"
- ""
- "**What you've learned:**"
- "✓ Prisoner's Dilemma (cooperation vs self-interest)"
- "✓ Nash Equilibrium (stable strategy profiles)"
- "✓ Dominant strategies (always-best moves)"
- "✓ How to analyze strategic situations"
- "✓ Why individually rational choices can lead to bad collective outcomes"
- ""
- "**Key insights:**"
- "- Strategic thinking requires considering others' incentives"
- "- Equilibrium ≠ optimal (Prisoner's Dilemma!)"
- "- Dominant strategies simplify prediction"
- "- Coordination problems have multiple equilibria"
- "- Institutions and repeated play can enable cooperation"
- ""
- "**Real-world applications:**"
- "- Understanding why cartels fail"
- "- Recognizing arms race dynamics"
- "- Designing better mechanisms (auctions, voting)"
- "- Building institutions that align incentives"
- ""
- "**Next steps:**"
- "- Game Theory 201: Mixed strategies and repeated games"
- "- Look for strategic interactions in daily life"
- "- Think about how to align individual and collective interests"
question: "How has learning game theory changed how you think about strategic situations? Give an example where you might apply these concepts."
tokens_for_ai: |
This is a reflection question.
Look for:
- Recognition of strategic interdependence
- Understanding that others' incentives matter
- Application to real situations
- Appreciation of conflict between individual/collective rationality
Categorize as:
- excellent_reflection: Insightful application showing deep understanding
- practical_application: Good real-world example
- general_reflection: Acknowledges usefulness
- brief_response: Short but relevant
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
Provide encouraging feedback!
Validate their example/reflection.
Emphasize key takeaway: think about others' incentives!
Game theory helps predict behavior and design better systems.
Mention Game Theory 201 for deeper concepts.
Celebrate their foundational understanding!
buckets:
- excellent_reflection
- practical_application
- general_reflection
- brief_response
- set_language
- off_topic
transitions:
excellent_reflection:
ai_feedback:
tokens_for_ai: |
Fantastic insight!
Reference their example specifically.
You now think strategically about interdependent decisions!
This foundation enables understanding mechanism design, auctions, bargaining.
Ready for Game Theory 201 when you are!
metadata_add:
activity_completed: "true"
practical_application:
ai_feedback:
tokens_for_ai: |
Great application!
Acknowledge their example.
Game theory is everywhere once you start looking!
Understanding incentives helps predict and influence behavior.
Excellent work mastering the fundamentals!
metadata_add:
activity_completed: "true"
general_reflection:
ai_feedback:
tokens_for_ai: |
Good reflection!
The core lesson: always consider others' incentives.
Strategic interactions are everywhere - business, politics, daily life.
You've built a strong foundation in game theory!
metadata_add:
activity_completed: "true"
brief_response:
ai_feedback:
tokens_for_ai: |
Thank you for completing Game Theory 101!
You've learned to think strategically about interactive decisions.
These concepts underpin economics, politics, and much more!
metadata_add:
activity_completed: "true"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: conclusion:step_1
off_topic:
content_blocks:
- "Reflect: How might understanding incentives and strategic interaction help you in real-world situations?"
next_section_and_step: conclusion:step_1

View file

@ -0,0 +1,134 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
sections:
- section_id: introduction
title: Welcome to Game Theory 201
steps:
- step_id: welcome
title: Beyond Pure Strategies
content_blocks:
- "# Game Theory 201: Mixed Strategies & Repeated Games 🎲🔄"
- "**Building on Game Theory 101!**"
- ""
- "**You'll learn:**"
- "✓ Mixed strategies (randomization)"
- "✓ When and why to randomize"
- "✓ Repeated games (shadow of the future)"
- "✓ How cooperation emerges"
- "✓ Tit-for-Tat and winning strategies"
question: Ready to explore more advanced strategic concepts?
tokens_for_ai: Accept positive as 'ready', language as 'set_language', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready:
next_section_and_step: mixed_strategies:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: mixed_strategies
title: Mixed Strategies
steps:
- step_id: step_1
title: Randomization as Strategy
content_blocks:
- "## Mixed Strategies: The Power of Unpredictability 🎲"
- ""
- "**Pure vs Mixed Strategies:**"
- "- Pure: Always play the same action"
- "- Mixed: Randomize between actions with specific probabilities"
- ""
- "**Rock-Paper-Scissors:**"
- "No pure strategy works - opponent can exploit patterns!"
- "Solution: Randomize equally (1/3, 1/3, 1/3)"
- ""
- "**Penalty Kicks in Soccer:**"
- "- Kicker: Left or Right?"
- "- Goalie: Dive Left or Right?"
- "- Must be unpredictable!"
- "- Data shows pros randomize ~50/50"
- ""
- "**When to use mixed strategies:**"
- "- No dominant pure strategy"
- "- Opponent can exploit predictability"
- "- Matching Pennies, Hide and Seek, Security games"
question: In Rock-Paper-Scissors, why can't you always play Rock? What happens if you're predictable?
tokens_for_ai: |
Should recognize: predictability allows exploitation.
If always Rock, opponent plays Paper and wins.
Categorize: understands_exploitation, recognizes_problem, vague, set_language, off_topic
buckets: [understands_exploitation, recognizes_problem, vague, set_language, off_topic]
transitions:
understands_exploitation:
ai_feedback: {tokens_for_ai: "Perfect! Predictability = exploitation. Opponent plays Paper, you lose. Randomization prevents exploitation!"}
metadata_add: {score: "n+2"}
next_section_and_step: repeated_games:step_1
recognizes_problem:
ai_feedback: {tokens_for_ai: "Right! If you always play Rock, smart opponent plays Paper every time. Randomization is the solution!"}
metadata_add: {score: "n+1"}
next_section_and_step: repeated_games:step_1
vague:
ai_feedback: {tokens_for_ai: "If you always play Rock, opponent learns and always plays Paper. You lose every time! Must randomize."}
next_section_and_step: repeated_games:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: mixed_strategies:step_1
off_topic:
next_section_and_step: mixed_strategies:step_1
- section_id: repeated_games
title: Repeated Games
steps:
- step_id: step_1
title: The Shadow of the Future
content_blocks:
- "## Repeated Games: When Tomorrow Matters 🔄"
- ""
- "**One-shot vs Repeated:**"
- "- One-shot PD: Defect dominates"
- "- Repeated PD: Cooperation can emerge!"
- ""
- "**Why repetition changes everything:**"
- "- Reputation matters"
- "- Retaliation is possible"
- "- Future gains can outweigh immediate temptation"
- ""
- "**Tit-for-Tat Strategy:**"
- "1. Start with cooperation"
- "2. Then copy opponent's previous move"
- "- Nice (never defects first)"
- "- Retaliatory (punishes defection)"
- "- Forgiving (returns to cooperation)"
- "- Clear (easy to understand)"
- ""
- "**Axelrod's Tournament:**"
- "Tit-for-Tat won! Simplest, most effective."
- "Beat complex strategies through cooperation + accountability"
question: Why can cooperation emerge in repeated Prisoner's Dilemma but not in one-shot games?
tokens_for_ai: |
Key insight: future interactions create incentive to cooperate.
Fear of retaliation, value of reputation, shadow of future.
Categorize: excellent_understanding, identifies_repetition, partial, set_language, off_topic
buckets: [excellent_understanding, identifies_repetition, partial, set_language, off_topic]
transitions:
excellent_understanding:
ai_feedback: {tokens_for_ai: "Brilliant! Future interactions change incentives. Retaliation possible, reputation matters. Short-term gain < long-term cooperation!"}
metadata_add: {score: "n+2", activity_completed: "true"}
identifies_repetition:
ai_feedback: {tokens_for_ai: "Exactly! Repeated games allow punishment and reward. Cooperation becomes rational when future matters!"}
metadata_add: {score: "n+1", activity_completed: "true"}
partial:
ai_feedback: {tokens_for_ai: "Right direction! Key: future interactions create accountability. Can punish defectors, reward cooperators. Changes incentives!"}
metadata_add: {activity_completed: "true"}
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: repeated_games:step_1
off_topic:
metadata_add: {activity_completed: "true"}

View file

@ -0,0 +1,65 @@
default_max_attempts_per_step: 3
sections:
- section_id: introduction
title: Game Theory 301
steps:
- step_id: welcome
title: Cooperative Games
content_blocks:
- "# Game Theory 301: Cooperative Games & Coalitions 🤝"
- "**Beyond zero-sum thinking!**"
- "✓ Cooperative game theory"
- "✓ Coalition formation"
- "✓ Shapley value (fair division)"
- "✓ Core stability"
question: Ready to learn about cooperation and coalition building?
tokens_for_ai: Accept positive as 'ready', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready: {next_section_and_step: "coalitions:step_1"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
off_topic: {counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
- section_id: coalitions
title: Coalition Formation
steps:
- step_id: step_1
title: Coalition Building
content_blocks:
- "## Coalitions: Strength in Numbers 💪"
- ""
- "**Characteristic function form:**"
- "v(Coalition) = value coalition can guarantee"
- ""
- "**Example: Three companies**"
- "- Alone: A=$10M, B=$15M, C=$20M"
- "- A+B together: $30M"
- "- A+C together: $35M"
- "- B+C together: $40M"
- "- All three: $60M"
- ""
- "**Questions:**"
- "- Which coalition forms?"
- "- How to split the gains fairly?"
- ""
- "**Shapley Value:**"
- "Fair division based on marginal contributions"
- "Each player gets average of their marginal value across all orderings"
question: If three players create $60M together but would create $0 individually, how should they split the gains to be fair?
tokens_for_ai: |
Equal split ($20M each) is one fair answer.
Shapley value would calculate based on marginal contributions.
Categorize: says_equal, considers_contributions, unclear, set_language, off_topic
buckets: [says_equal, considers_contributions, unclear, set_language, off_topic]
transitions:
says_equal:
ai_feedback: {tokens_for_ai: "Equal split is fair! Each contributed equally to coalition. Shapley value would give $20M each too."}
metadata_add: {score: "n+2", activity_completed: "true"}
considers_contributions:
ai_feedback: {tokens_for_ai: "Good thinking about contributions! With symmetric players, equal split is the Shapley value."}
metadata_add: {score: "n+1", activity_completed: "true"}
unclear:
ai_feedback: {tokens_for_ai: "Fair approach: equal split since all contributed equally. Each gets $20M. This is the Shapley value!"}
metadata_add: {activity_completed: "true"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "coalitions:step_1"}
off_topic: {metadata_add: {activity_completed: "true"}}

View file

@ -0,0 +1,71 @@
default_max_attempts_per_step: 3
sections:
- section_id: introduction
title: Game Theory 401
steps:
- step_id: welcome
title: Information Games
content_blocks:
- "# Game Theory 401: Information Asymmetry 🔍"
- "**When players have different information!**"
- "✓ Signaling (revealing information)"
- "✓ Screening (eliciting information)"
- "✓ Adverse selection"
- "✓ Moral hazard"
question: Ready to explore strategic information problems?
tokens_for_ai: Accept positive as 'ready', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready: {next_section_and_step: "signaling:step_1"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
off_topic: {counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
- section_id: signaling
title: Signaling & Screening
steps:
- step_id: step_1
title: Credible Signals
content_blocks:
- "## Signaling: Credibly Revealing Information 📢"
- ""
- "**The problem:**"
- "You have valuable information others don't"
- "How to credibly communicate it?"
- ""
- "**Education as Signal:**"
- "- Degree signals ability/work ethic"
- "- Costly to obtain (time, money, effort)"
- "- Harder for low-ability workers"
- "- Separates high from low types"
- ""
- "**Key: Must be costly for low types!**"
- "Otherwise everyone signals, signal loses meaning"
- ""
- "**Other examples:**"
- "- Warranties (signal quality)"
- "- Money-back guarantees"
- "- Certifications"
- "- Peacock's tail (biological signaling)"
- ""
- "**Adverse Selection:**"
- "When information asymmetry leads to market failure"
- "Example: Used car market (lemons problem)"
question: Why must a signal be costly to be credible? What happens if it's cheap for everyone?
tokens_for_ai: |
Key insight: if signal is cheap for all types, everyone signals.
Signal loses informational value (pooling).
Must be differentially costly to separate types.
Categorize: excellent_understanding, understands_cost, partial, set_language, off_topic
buckets: [excellent_understanding, understands_cost, partial, set_language, off_topic]
transitions:
excellent_understanding:
ai_feedback: {tokens_for_ai: "Perfect! If everyone can signal cheaply, everyone does. Signal becomes meaningless. Must be differentially costly to separate types!"}
metadata_add: {score: "n+2", activity_completed: "true"}
understands_cost:
ai_feedback: {tokens_for_ai: "Exactly! Cheap signals lose meaning. Everyone would claim to be high quality. Cost creates separation!"}
metadata_add: {score: "n+1", activity_completed: "true"}
partial:
ai_feedback: {tokens_for_ai: "Right direction! If signal is free, everyone sends it. Becomes noise. Cost differentiates high from low quality!"}
metadata_add: {activity_completed: "true"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "signaling:step_1"}
off_topic: {metadata_add: {activity_completed: "true"}}

View file

@ -0,0 +1,73 @@
default_max_attempts_per_step: 3
sections:
- section_id: introduction
title: Game Theory 501
steps:
- step_id: welcome
title: Design the Game
content_blocks:
- "# Game Theory 501: Mechanism Design 🏗️"
- "**Reverse game theory: Design the game itself!**"
- "✓ Mechanism design (reverse game theory)"
- "✓ Auction theory"
- "✓ Voting theory"
- "✓ Incentive compatibility"
question: Ready to learn how to design strategic systems?
tokens_for_ai: Accept positive as 'ready', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready: {next_section_and_step: "mechanism_design:step_1"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
off_topic: {counts_as_attempt: false, next_section_and_step: "introduction:welcome"}
- section_id: mechanism_design
title: Designing Strategic Systems
steps:
- step_id: step_1
title: Incentive Engineering
content_blocks:
- "## Mechanism Design: Engineering Incentives 🎯"
- ""
- "**The challenge:**"
- "Design rules so self-interested players produce desired outcomes"
- ""
- "**Revelation Principle:**"
- "Focus on mechanisms where truth-telling is optimal"
- "'Incentive compatible' mechanisms"
- ""
- "**Vickrey Auction (2nd-price sealed-bid):**"
- "- Everyone submits sealed bid"
- "- Highest bidder wins"
- "- Pays 2nd-highest bid"
- ""
- "**Why brilliant:**"
- "- Dominant strategy: Bid your true value!"
- "- Overbidding risks paying too much"
- "- Underbidding risks losing when you'd profit"
- "- Truthful bidding is optimal"
- ""
- "**Applications:**"
- "- eBay (proxy bidding)"
- "- Google AdWords"
- "- Organ donation matching"
- "- Spectrum auctions"
question: In a Vickrey auction, why is bidding your true value the dominant strategy?
tokens_for_ai: |
Key insight: You pay 2nd price, not your bid.
Overbidding risks paying more than value.
Underbidding risks losing profitable wins.
True value bidding is optimal.
Categorize: excellent_explanation, understands_truthful, partial, set_language, off_topic
buckets: [excellent_explanation, understands_truthful, partial, set_language, off_topic]
transitions:
excellent_explanation:
ai_feedback: {tokens_for_ai: "Perfect! Since you pay 2nd price, not your bid, bidding true value is dominant. Can't improve by lying! This is mechanism design genius!"}
metadata_add: {score: "n+2", activity_completed: "true"}
understands_truthful:
ai_feedback: {tokens_for_ai: "Exactly! Paying 2nd price means truthful bidding is optimal. Over/under bidding can only hurt you. Brilliant design!"}
metadata_add: {score: "n+1", activity_completed: "true"}
partial:
ai_feedback: {tokens_for_ai: "Right idea! Key: you pay 2nd price. Bidding true value dominates - lying can't help, might hurt. This is mechanism design!"}
metadata_add: {activity_completed: "true"}
set_language: {metadata_add: {language: "the-users-response"}, counts_as_attempt: false, next_section_and_step: "mechanism_design:step_1"}
off_topic: {metadata_add: {activity_completed: "true"}}

View file

@ -0,0 +1,509 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate the student's ability to implement game theory concepts in Python.
Consider:
- Correct Python syntax
- Understanding of game theory concepts
- Code logic and structure
- Use of appropriate data structures
- Ability to translate concepts to code
sections:
- section_id: introduction
title: Programming Game Theory in Python
steps:
- step_id: welcome
title: Code Meets Strategy
content_blocks:
- "# Game Theory Programming with Python 🐍🎮"
- ""
- "**Learn Python by implementing game theory!**"
- ""
- "You'll learn to:"
- "✓ Represent games as data structures"
- "✓ Implement payoff matrices"
- "✓ Code Prisoner's Dilemma simulations"
- "✓ Find Nash Equilibria programmatically"
- "✓ Simulate repeated games with strategies"
- ""
- "**Prerequisites:**"
- "- Basic Python knowledge (variables, functions, loops)"
- "- Understanding of basic game theory (Nash Equilibrium, Prisoner's Dilemma)"
- ""
- "**Why this matters:**"
- "- Learn to model strategic situations"
- "- Practice data structures (dictionaries, lists)"
- "- Build simulations and experiments"
- "- Apply theory to real code"
question: Ready to implement game theory in Python?
tokens_for_ai: Accept positive as 'ready', language preference as 'set_language', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready:
next_section_and_step: payoff_matrix:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: payoff_matrix
title: Representing Games as Data
steps:
- step_id: step_1
title: Payoff Matrix Structure
content_blocks:
- "## Representing Payoff Matrices in Python 📊"
- ""
- "**The challenge:**"
- "How do we represent a 2-player game in code?"
- ""
- "**Game structure:**"
- "- Two players (Row, Column)"
- "- Each has strategies (actions)"
- "- Each outcome has payoffs for both players"
- ""
- "**Conceptual approach:**"
- "A payoff matrix maps strategy pairs to payoff tuples"
- "- Input: (player1_strategy, player2_strategy)"
- "- Output: (player1_payoff, player2_payoff)"
- ""
- "**Data structure choice:**"
- "Python dictionaries are perfect!"
- "- Keys: tuples of strategy pairs"
- "- Values: tuples of payoffs"
- ""
- "**Example concept (Prisoner's Dilemma):**"
- "```"
- "Strategies: 'cooperate' or 'defect'"
- "Payoffs: (player1_years, player2_years)"
- "If both cooperate: (-1, -1)"
- "If both defect: (-2, -2)"
- "If one defects while other cooperates: (0, -3) or (-3, 0)"
- "```"
question: "Write Python code to create a dictionary representing the Prisoner's Dilemma payoff matrix. Use strategy pairs as keys (tuples like ('cooperate', 'defect')) and payoff tuples as values."
tokens_for_ai: |
Looking for Python dictionary with:
- Keys: tuples of (player1_strategy, player2_strategy)
- Values: tuples of (player1_payoff, player2_payoff)
- Four outcomes: (C,C), (C,D), (D,C), (D,D)
Correct payoffs (years in prison):
- ('cooperate', 'cooperate'): (-1, -1)
- ('cooperate', 'defect'): (-3, 0)
- ('defect', 'cooperate'): (0, -3)
- ('defect', 'defect'): (-2, -2)
Categorize as:
- correct: Proper dictionary with all 4 outcomes and correct payoffs
- correct_structure: Right structure, minor payoff errors
- uses_dictionary: Uses dict but wrong format
- wrong_approach: Different data structure
- needs_help: Very basic or confused
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Excellent! Dictionary maps strategy pairs to payoffs perfectly.
- This structure makes lookups easy.
- Show how to access: payoff_matrix[('cooperate', 'defect')] → (-3, 0)
If structure right but payoffs wrong:
- Great structure! But check payoffs:
- Both cooperate: (-1, -1) - best mutual outcome
- Both defect: (-2, -2) - mutual punishment
- One defects: (0, -3) or (-3, 0) - betrayal
If wrong approach:
- Show correct dictionary structure with example.
- Explain why dict with tuple keys is elegant for this.
buckets: [correct, correct_structure, uses_dictionary, wrong_approach, needs_help, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Perfect implementation!
Your dictionary elegantly maps strategy pairs to payoffs.
Access is simple: matrix[('cooperate', 'defect')] gives (-3, 0).
This structure scales to more complex games!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: payoff_matrix:step_2
correct_structure:
ai_feedback:
tokens_for_ai: |
Great structure! Minor payoff correction needed:
- Both cooperate: (-1, -1)
- Both defect: (-2, -2)
- One defects: betrayer gets 0, cooperator gets -3
Show the corrected version.
metadata_add: {score: "n+1"}
next_section_and_step: payoff_matrix:step_2
uses_dictionary:
ai_feedback:
tokens_for_ai: |
Good use of dictionary!
For game matrices, use tuple keys:
payoff_matrix = {
('cooperate', 'cooperate'): (-1, -1),
('cooperate', 'defect'): (-3, 0),
...
}
next_section_and_step: payoff_matrix:step_1
wrong_approach:
ai_feedback:
tokens_for_ai: |
Python dictionaries with tuple keys work best!
Example format:
game = {('action1', 'action2'): (payoff1, payoff2)}
This allows easy lookup of any strategy combination.
next_section_and_step: payoff_matrix:step_1
needs_help:
content_blocks:
- "Start with: game = {}"
- "Add entries like: ('cooperate', 'cooperate'): (-1, -1)"
- "You need 4 entries total for all strategy combinations"
next_section_and_step: payoff_matrix:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: payoff_matrix:step_1
off_topic:
next_section_and_step: payoff_matrix:step_1
- step_id: step_2
title: Querying the Matrix
content_blocks:
- "## Using the Payoff Matrix 🔍"
- ""
- "**Now that you have a payoff matrix, let's use it!**"
- ""
- "**Task:** Write a function that determines outcomes"
- ""
- "**Function requirements:**"
- "- Name: `get_payoffs`"
- "- Parameters: `payoff_matrix`, `player1_action`, `player2_action`"
- "- Returns: tuple of (player1_payoff, player2_payoff)"
- ""
- "**What the function does:**"
- "Looks up the payoffs for the given strategy combination"
- ""
- "**Think about:**"
- "- How do you access dictionary values?"
- "- How do you create the lookup key from the two actions?"
question: "Write a Python function called `get_payoffs` that takes a payoff matrix dictionary and two player actions, then returns the payoff tuple for that strategy combination."
tokens_for_ai: |
Looking for function that:
- Takes 3 parameters: payoff_matrix (dict), player1_action, player2_action
- Creates tuple key: (player1_action, player2_action)
- Returns: payoff_matrix[(player1_action, player2_action)]
Acceptable variations:
- def get_payoffs(matrix, p1, p2): return matrix[(p1, p2)]
- def get_payoffs(payoff_matrix, action1, action2): ...
Categorize as:
- correct: Proper function with correct lookup
- correct_logic: Right idea, minor syntax issues
- missing_tuple: Tries to lookup without creating tuple key
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect! Your function correctly creates a tuple key and looks it up.
- Example: get_payoffs(game, 'cooperate', 'defect') → (-3, 0)
- Clean, simple, and reusable!
If correct logic but syntax issues:
- Right approach! Small syntax fix needed.
- Show corrected version.
- Explain the fix.
If missing tuple:
- Remember: dictionary keys are tuples!
- Need to create (player1_action, player2_action) first.
- Then look it up in the matrix.
buckets: [correct, correct_logic, missing_tuple, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent function!
Your code cleanly creates the tuple key and returns the payoffs.
This abstraction makes game simulation much easier.
You can now query any strategy combination!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: simulation:step_1
correct_logic:
ai_feedback:
tokens_for_ai: |
Great logic! Minor syntax adjustment:
Show corrected function.
Explain what was fixed and why it matters.
metadata_add: {score: "n+1"}
next_section_and_step: simulation:step_1
missing_tuple:
ai_feedback:
tokens_for_ai: |
Close! Don't forget to create the tuple key:
def get_payoffs(payoff_matrix, p1_action, p2_action):
key = (p1_action, p2_action)
return payoff_matrix[key]
next_section_and_step: payoff_matrix:step_2
confused:
content_blocks:
- "A function that takes the matrix and both actions"
- "Creates a tuple from the two actions: (action1, action2)"
- "Uses that tuple to look up the payoffs in the dictionary"
next_section_and_step: payoff_matrix:step_2
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: payoff_matrix:step_2
off_topic:
next_section_and_step: payoff_matrix:step_2
- section_id: simulation
title: Simulating Strategic Interactions
steps:
- step_id: step_1
title: One-Shot Game Simulator
content_blocks:
- "## Simulating Game Outcomes 🎲"
- ""
- "**Building a simple game simulator**"
- ""
- "**Requirements:**"
- "- Function name: `play_game`"
- "- Parameters: `payoff_matrix`, `strategy1`, `strategy2`"
- "- Should call your `get_payoffs` function"
- "- Print the outcome in a readable format"
- "- Return the payoffs"
- ""
- "**Example output format:**"
- "```"
- "Player 1 chose: cooperate"
- "Player 2 chose: defect"
- "Payoffs: Player 1 = -3, Player 2 = 0"
- "```"
- ""
- "**Conceptual flow:**"
- "1. Get payoffs using your get_payoffs function"
- "2. Display what each player chose"
- "3. Display the resulting payoffs"
- "4. Return the payoffs for further use"
question: "Write a `play_game` function that simulates one round of a game, prints the outcome, and returns the payoffs. Use your `get_payoffs` function from earlier."
tokens_for_ai: |
Looking for function that:
- Calls get_payoffs(payoff_matrix, strategy1, strategy2)
- Prints player choices and payoffs
- Returns the payoff tuple
Should show understanding of:
- Function composition (using get_payoffs)
- Print statements for output
- Returning values
Categorize as:
- correct: Complete function with print and return
- missing_print: Has logic but doesn't print
- missing_return: Prints but doesn't return
- correct_concept: Right idea, minor issues
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Excellent! Your simulator uses function composition nicely.
- The print statements make outcomes clear.
- Returning payoffs allows chaining simulations.
- This is how game theory research is done programmatically!
If missing print:
- Good logic! Add print statements to show:
- What each player chose
- The resulting payoffs
- Makes debugging and understanding easier!
If missing return:
- Good output! But also return the payoffs.
- This lets you use the function in larger simulations.
- return payoffs at the end.
Show complete example if needed.
buckets: [correct, missing_print, missing_return, correct_concept, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Perfect simulator!
You've built function composition (play_game uses get_payoffs).
Print statements provide visibility.
Return value enables further analysis.
You're ready for repeated game simulation!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: repeated_games:step_1
missing_print:
ai_feedback:
tokens_for_ai: |
Good structure! Add print statements:
print(f"Player 1 chose: {strategy1}")
print(f"Player 2 chose: {strategy2}")
print(f"Payoffs: Player 1 = {payoffs[0]}, Player 2 = {payoffs[1]}")
Makes the simulation observable!
metadata_add: {score: "n+1"}
next_section_and_step: repeated_games:step_1
missing_return:
ai_feedback:
tokens_for_ai: |
Great output! Just add:
return payoffs
This lets you accumulate results over many rounds!
metadata_add: {score: "n+1"}
next_section_and_step: repeated_games:step_1
correct_concept:
ai_feedback:
tokens_for_ai: |
Right approach! Small improvements:
Show polished version.
Explain the refinements.
next_section_and_step: repeated_games:step_1
confused:
content_blocks:
- "Your function should:"
- "1. Call get_payoffs to get the payoffs"
- "2. Print what each player chose"
- "3. Print the payoffs"
- "4. Return the payoffs tuple"
next_section_and_step: simulation:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: simulation:step_1
off_topic:
next_section_and_step: simulation:step_1
- section_id: repeated_games
title: Repeated Game Strategies
steps:
- step_id: step_1
title: Tit-for-Tat Strategy
content_blocks:
- "## Implementing Strategic Behavior 🔄"
- ""
- "**The Tit-for-Tat Strategy:**"
- "1. Start with cooperation"
- "2. Then copy opponent's previous move"
- ""
- "**Implementation challenge:**"
- "Create a function that implements Tit-for-Tat logic"
- ""
- "**Function requirements:**"
- "- Name: `tit_for_tat`"
- "- Parameter: `opponent_last_move` (or None for first move)"
- "- Returns: 'cooperate' or 'defect'"
- ""
- "**Logic:**"
- "- If it's the first move (opponent_last_move is None): return 'cooperate'"
- "- Otherwise: return whatever the opponent played last"
- ""
- "**Why this is powerful:**"
- "- Nice (starts with cooperation)"
- "- Retaliatory (punishes defection)"
- "- Forgiving (returns to cooperation)"
- "- Simple to understand and implement"
question: "Write a `tit_for_tat` function that takes an opponent's last move (or None for first round) and returns the appropriate strategy according to Tit-for-Tat logic."
tokens_for_ai: |
Correct logic:
- If opponent_last_move is None: return 'cooperate'
- Else: return opponent_last_move
Acceptable implementations:
- Simple if/else
- Ternary operator
- Return with 'or' default
Categorize as:
- correct: Proper Tit-for-Tat logic
- correct_logic: Right idea, minor syntax
- wrong_first_move: Doesn't handle None case
- always_cooperates: Ignores opponent's move
- confused: Wrong logic
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect Tit-for-Tat implementation!
- First move: cooperate (nice)
- After: copy opponent (retaliatory & forgiving)
- This won Axelrod's tournament!
- Show usage example.
If correct logic:
- Great logic! Small syntax refinement:
- Show corrected version.
If wrong first move:
- Remember: Tit-for-Tat starts with cooperation!
- Check if opponent_last_move is None (first round).
- If None, return 'cooperate'.
If always cooperates:
- You need to copy the opponent's move!
- After first round, return opponent_last_move.
- That's what makes it "tit for tat"!
buckets: [correct, correct_logic, wrong_first_move, always_cooperates, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent Tit-for-Tat implementation!
Your code captures the strategy perfectly:
- Nice: starts with cooperation
- Retaliatory: copies opponent's defection
- Forgiving: copies opponent's return to cooperation
This simple strategy is remarkably effective!
metadata_add: {score: "n+2", concepts_mastered: "n+1", activity_completed: "true"}
correct_logic:
ai_feedback:
tokens_for_ai: |
Great logic! Minor polish:
Show refined version.
Your understanding of the strategy is solid!
metadata_add: {score: "n+1", activity_completed: "true"}
wrong_first_move:
ai_feedback:
tokens_for_ai: |
Almost there! Handle the first move:
def tit_for_tat(opponent_last_move):
if opponent_last_move is None:
return 'cooperate' # Be nice first
return opponent_last_move # Then copy
next_section_and_step: repeated_games:step_1
always_cooperates:
ai_feedback:
tokens_for_ai: |
That's "always cooperate," not Tit-for-Tat!
Tit-for-Tat must COPY the opponent's last move.
Only the FIRST move is automatically cooperate.
next_section_and_step: repeated_games:step_1
confused:
content_blocks:
- "Tit-for-Tat logic:"
- "1. First move (when opponent_last_move is None): cooperate"
- "2. All other moves: copy opponent's last move"
- "Use an if statement to check for None"
next_section_and_step: repeated_games:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: repeated_games:step_1
off_topic:
metadata_add: {activity_completed: "true"}

View file

@ -0,0 +1,528 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate the student's ability to implement game theory concepts in C.
Consider:
- Correct C syntax
- Proper use of structs and pointers
- Memory management awareness
- Understanding of game theory concepts
- Code structure and organization
sections:
- section_id: introduction
title: Programming Game Theory in C
steps:
- step_id: welcome
title: Systems Programming Meets Strategy
content_blocks:
- "# Game Theory Programming with C ⚙️🎮"
- ""
- "**Learn C by implementing game theory!**"
- ""
- "You'll learn to:"
- "✓ Define game structures with structs"
- "✓ Use 2D arrays for payoff matrices"
- "✓ Work with pointers and memory"
- "✓ Implement strategy functions"
- "✓ Build game simulators in C"
- ""
- "**Prerequisites:**"
- "- Basic C knowledge (variables, functions, arrays)"
- "- Understanding of basic game theory concepts"
- ""
- "**Why C for game theory:**"
- "- Performance for large simulations"
- "- Memory efficiency"
- "- Understanding low-level implementation"
- "- Foundation for understanding algorithms"
question: Ready to implement game theory in C?
tokens_for_ai: Accept positive as 'ready', language preference as 'set_language', else 'off_topic'
buckets: [ready, set_language, off_topic]
transitions:
ready:
next_section_and_step: structures:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: introduction:welcome
off_topic:
counts_as_attempt: false
next_section_and_step: introduction:welcome
- section_id: structures
title: Defining Game Structures
steps:
- step_id: step_1
title: Payoff Structure
content_blocks:
- "## Representing Payoffs in C 📐"
- ""
- "**The challenge:**"
- "How do we represent a payoff (two player outcomes) in C?"
- ""
- "**Conceptual requirement:**"
- "Each outcome has TWO values:"
- "- Player 1's payoff"
- "- Player 2's payoff"
- ""
- "**C solution: struct**"
- "A struct groups related data together"
- ""
- "**What your struct needs:**"
- "- A name (like 'Payoff' or 'Outcome')"
- "- Two integer fields for the two payoffs"
- ""
- "**Struct syntax reminder:**"
- "```"
- "struct StructName {"
- " type field1;"
- " type field2;"
- "};"
- "```"
question: "Define a C struct called 'Payoff' that contains two integer fields: 'player1' and 'player2' for storing each player's payoff."
tokens_for_ai: |
Looking for struct definition with:
- Name: Payoff (or similar like Outcome, GameResult)
- Two int fields for the two player payoffs
Correct examples:
struct Payoff {
int player1;
int player2;
};
or
typedef struct {
int p1;
int p2;
} Payoff;
Categorize as:
- correct: Valid struct with two int fields
- correct_concept: Right idea, minor syntax
- missing_fields: Struct but wrong/missing fields
- no_struct: Doesn't use struct
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect struct definition!
- Your struct groups the two payoffs together.
- Now you can create: struct Payoff outcome;
- Access: outcome.player1 = -1; outcome.player2 = -1;
If correct concept:
- Right idea! Small syntax adjustment:
- Show corrected version.
- Explain the fix.
If missing fields:
- Remember: need TWO integer fields
- One for player1's payoff
- One for player2's payoff
If no struct:
- C structs group related data!
- Show example struct format.
buckets: [correct, correct_concept, missing_fields, no_struct, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent struct definition!
Your Payoff struct elegantly groups both players' outcomes.
Usage: struct Payoff p = {-1, -2}; or p.player1 = 0;
This is the foundation for representing game outcomes!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: structures:step_2
correct_concept:
ai_feedback:
tokens_for_ai: |
Great concept! Minor syntax refinement:
Show corrected struct.
Explain the adjustment made.
metadata_add: {score: "n+1"}
next_section_and_step: structures:step_2
missing_fields:
ai_feedback:
tokens_for_ai: |
Need two int fields!
struct Payoff {
int player1;
int player2;
};
This stores both players' payoffs together.
next_section_and_step: structures:step_1
no_struct:
content_blocks:
- "Use a struct to group the two payoffs:"
- "struct Payoff { ... };"
- "Include two int fields inside the braces"
next_section_and_step: structures:step_1
confused:
content_blocks:
- "Define a struct with:"
- "- Name: Payoff"
- "- Two int fields (one for each player's payoff)"
- "Don't forget the semicolon at the end!"
next_section_and_step: structures:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: structures:step_1
off_topic:
next_section_and_step: structures:step_1
- step_id: step_2
title: Payoff Matrix with 2D Array
content_blocks:
- "## 2D Array for Game Matrix 🎯"
- ""
- "**Representing a 2x2 game:**"
- ""
- "**Prisoner's Dilemma has:**"
- "- 2 strategies per player: cooperate (0) or defect (1)"
- "- 4 possible outcomes: (0,0), (0,1), (1,0), (1,1)"
- ""
- "**Perfect for a 2D array!**"
- ""
- "**Array structure:**"
- "- First index: player 1's strategy (0 or 1)"
- "- Second index: player 2's strategy (0 or 1)"
- "- Value: Payoff struct with both payoffs"
- ""
- "**Conceptual mapping:**"
- "```"
- "matrix[0][0] = both cooperate"
- "matrix[0][1] = p1 cooperates, p2 defects"
- "matrix[1][0] = p1 defects, p2 cooperates"
- "matrix[1][1] = both defect"
- "```"
- ""
- "**Array declaration concept:**"
- "You declare a 2D array of your Payoff struct"
- "Then initialize it with the four outcomes"
question: "Declare and initialize a 2D array called 'prisoners_dilemma' of Payoff structs representing the Prisoner's Dilemma game. Use indices 0=cooperate, 1=defect. Payoffs: both cooperate (-1,-1), both defect (-2,-2), one defects (0,-3) or (-3,0)."
tokens_for_ai: |
Looking for 2D array declaration and initialization:
struct Payoff prisoners_dilemma[2][2] = {
{{-1, -1}, {-3, 0}}, // p1 cooperates
{{0, -3}, {-2, -2}} // p1 defects
};
Or similar valid initialization.
Categorize as:
- correct: Valid 2D array with proper payoffs
- correct_structure: Right format, payoff errors
- wrong_dimensions: Not 2x2
- syntax_errors: C syntax issues
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect 2D array implementation!
- prisoners_dilemma[0][0] = both cooperate = {-1,-1}
- prisoners_dilemma[1][1] = both defect = {-2,-2}
- prisoners_dilemma[0][1] = p1 cooperate, p2 defect = {-3,0}
- prisoners_dilemma[1][0] = p1 defect, p2 cooperate = {0,-3}
- Efficient memory layout for game representation!
If structure right:
- Great array structure! Payoff corrections:
- Show corrected initialization.
- Explain the Prisoner's Dilemma payoffs.
If wrong dimensions:
- Need 2x2 array (2 strategies per player)
- struct Payoff name[2][2] = {...};
If syntax errors:
- Show correct C array initialization syntax.
- Explain the nested braces structure.
buckets: [correct, correct_structure, wrong_dimensions, syntax_errors, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent array implementation!
Your 2D array efficiently represents the payoff matrix.
Access is simple: prisoners_dilemma[i][j]
Memory layout is contiguous and cache-friendly.
This is how game theory simulations optimize performance!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: functions:step_1
correct_structure:
ai_feedback:
tokens_for_ai: |
Great structure! Payoff corrections for Prisoner's Dilemma:
Show corrected initialization with explanations.
Explain why these specific payoffs create the dilemma.
metadata_add: {score: "n+1"}
next_section_and_step: functions:step_1
wrong_dimensions:
ai_feedback:
tokens_for_ai: |
Need 2x2 for two-strategy game:
struct Payoff game[2][2] = {
{{-1,-1}, {-3,0}},
{{0,-3}, {-2,-2}}
};
next_section_and_step: structures:step_2
syntax_errors:
ai_feedback:
tokens_for_ai: |
C array initialization uses nested braces:
struct Payoff arr[2][2] = {
{row0_col0, row0_col1},
{row1_col0, row1_col1}
};
Each Payoff is {p1_payoff, p2_payoff}
next_section_and_step: structures:step_2
confused:
content_blocks:
- "Declare: struct Payoff prisoners_dilemma[2][2]"
- "Initialize with nested braces: {{...}, {...}}"
- "Four outcomes total (2x2 = 4 combinations)"
next_section_and_step: structures:step_2
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: structures:step_2
off_topic:
next_section_and_step: structures:step_2
- section_id: functions
title: Strategy Functions
steps:
- step_id: step_1
title: Lookup Function
content_blocks:
- "## Querying the Payoff Matrix 🔍"
- ""
- "**Create a function to get payoffs**"
- ""
- "**Function requirements:**"
- "- Name: `get_payoff`"
- "- Parameters: 2D array (pointer), two strategy indices"
- "- Returns: Payoff struct"
- ""
- "**C function concepts:**"
- "- Pass 2D array as pointer"
- "- Access with array indexing"
- "- Return struct by value"
- ""
- "**What it does:**"
- "Takes strategies (0 or 1 for each player)"
- "Returns the corresponding Payoff from the matrix"
question: "Write a C function called 'get_payoff' that takes a 2D Payoff array (as pointer) and two integer strategy indices, then returns the Payoff struct for that strategy combination."
tokens_for_ai: |
Acceptable function signatures:
- struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2)
- struct Payoff get_payoff(struct Payoff (*matrix)[2], int s1, int s2)
Function body should:
- Return matrix[s1][s2];
Categorize as:
- correct: Valid function with proper syntax
- correct_logic: Right idea, minor syntax
- wrong_return: Doesn't return Payoff struct
- pointer_confusion: Struggles with array parameter
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect function!
- Your function cleanly accesses the 2D array.
- Returning struct by value is simple and safe here.
- Usage: struct Payoff p = get_payoff(game, 0, 1);
If correct logic:
- Great logic! Minor syntax refinement:
- Show corrected version.
- Explain the C-specific details.
If wrong return:
- Function should return struct Payoff
- return matrix[s1][s2]; gives you the Payoff struct.
If pointer confusion:
- For small 2D arrays, can pass as: struct Payoff matrix[2][2]
- Or use pointer: struct Payoff (*matrix)[2]
- Show working example.
buckets: [correct, correct_logic, wrong_return, pointer_confusion, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent function implementation!
Your get_payoff function cleanly retrieves outcomes.
C's struct return makes this straightforward.
You've encapsulated the lookup logic perfectly!
metadata_add: {score: "n+2", concepts_mastered: "n+1"}
next_section_and_step: simulation:step_1
correct_logic:
ai_feedback:
tokens_for_ai: |
Great logic! Small C syntax refinement:
Show polished version.
Explain the specific C conventions used.
metadata_add: {score: "n+1"}
next_section_and_step: simulation:step_1
wrong_return:
ai_feedback:
tokens_for_ai: |
Return type should be struct Payoff:
struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2) {
return matrix[s1][s2];
}
next_section_and_step: functions:step_1
pointer_confusion:
ai_feedback:
tokens_for_ai: |
For 2D array parameter, simple approach:
struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2) {
return matrix[s1][s2];
}
C automatically handles the array as pointer.
next_section_and_step: functions:step_1
confused:
content_blocks:
- "Function signature: struct Payoff get_payoff(struct Payoff matrix[2][2], int s1, int s2)"
- "Function body: return matrix[s1][s2];"
- "This returns the Payoff at position [s1][s2]"
next_section_and_step: functions:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: functions:step_1
off_topic:
next_section_and_step: functions:step_1
- section_id: simulation
title: Game Simulation
steps:
- step_id: step_1
title: Strategy Enumeration
content_blocks:
- "## Defining Strategies with Enum 🎲"
- ""
- "**Making code readable:**"
- "Instead of 0 and 1, use named constants!"
- ""
- "**C enum for strategies:**"
- "Enums give names to integer values"
- ""
- "**What you need:**"
- "- Enum name: Strategy (or similar)"
- "- Two values: COOPERATE = 0, DEFECT = 1"
- ""
- "**Why enums improve code:**"
- "- get_payoff(game, COOPERATE, DEFECT) is clearer"
- "- Better than get_payoff(game, 0, 1)"
- "- Self-documenting code"
- "- Type safety (to some degree)"
question: "Define a C enum called 'Strategy' with two values: COOPERATE (equals 0) and DEFECT (equals 1)."
tokens_for_ai: |
Looking for enum definition:
enum Strategy {
COOPERATE = 0,
DEFECT = 1
};
Or:
typedef enum {
COOPERATE = 0,
DEFECT = 1
} Strategy;
Categorize as:
- correct: Valid enum with both values
- correct_concept: Right idea, minor syntax
- missing_values: Enum but wrong values
- no_enum: Doesn't use enum
- confused: Wrong approach
- set_language: Language preference
- off_topic: Unrelated
feedback_tokens_for_ai: |
If correct:
- Perfect enum definition!
- Now you can write: enum Strategy s = COOPERATE;
- Much more readable than: int s = 0;
- Self-documenting code is maintainable code!
If correct concept:
- Great use of enum! Small refinement:
- Show corrected version.
If missing values:
- Need both COOPERATE = 0 and DEFECT = 1
- Show correct enum.
If no enum:
- C enums create named integer constants:
- Show enum syntax.
buckets: [correct, correct_concept, missing_values, no_enum, confused, set_language, off_topic]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent enum!
Your code is now self-documenting.
COOPERATE and DEFECT are much clearer than 0 and 1.
This is professional C code style!
You've mastered game theory implementation in C!
metadata_add: {score: "n+2", concepts_mastered: "n+1", activity_completed: "true"}
correct_concept:
ai_feedback:
tokens_for_ai: |
Great enum concept! Small polish:
Show refined version.
You understand C enums well!
metadata_add: {score: "n+1", activity_completed: "true"}
missing_values:
ai_feedback:
tokens_for_ai: |
Need both strategies:
enum Strategy {
COOPERATE = 0,
DEFECT = 1
};
next_section_and_step: simulation:step_1
no_enum:
content_blocks:
- "Define enum with:"
- "enum Strategy { COOPERATE = 0, DEFECT = 1 };"
- "This creates named constants"
next_section_and_step: simulation:step_1
confused:
content_blocks:
- "Enum syntax: enum Name { VALUE1 = 0, VALUE2 = 1 };"
- "Creates named integer constants"
- "Don't forget the semicolon!"
next_section_and_step: simulation:step_1
set_language:
metadata_add: {language: "the-users-response"}
counts_as_attempt: false
next_section_and_step: simulation:step_1
off_topic:
metadata_add: {activity_completed: "true"}

View file

@ -0,0 +1,663 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
You are teaching the Monty Hall problem through programming simulation.
The user's chosen programming language is stored in metadata.programming_language.
ALWAYS provide feedback and code examples in THEIR chosen language.
Be encouraging and help them discover the counterintuitive truth through code.
sections:
- section_id: "introduction"
title: "Introduction"
steps:
- step_id: "welcome"
title: "Welcome to Monty Hall Simulation"
content_blocks:
- "# Welcome to the Monty Hall Paradox! 🚪🐐🚗"
- ""
- "You're about to explore one of the most **counterintuitive** problems in probability."
- ""
- "We'll use **programming** to prove a mathematical truth that most people find hard to believe!"
- ""
- "**What you'll learn:**"
- "- The famous Monty Hall problem"
- "- How to simulate probability with code"
- "- Why our intuition fails us"
- "- Random number generation, loops, and counters"
- ""
- "Let's get started! 🎲"
- step_id: "choose_language"
title: "Choose Your Programming Language"
question: "What programming language would you like to use? (e.g., Python, JavaScript, C, Java, Go, Rust, etc.)"
tokens_for_ai: |
The user is choosing their programming language for this activity.
Categorize as 'valid_language' if they name a real programming language.
Examples: Python, JavaScript, C, C++, Java, Go, Rust, Ruby, PHP, Swift, Kotlin, etc.
Categorize as 'set_language' if they're asking to change the conversation language.
Categorize as 'need_help' if they seem unsure or ask for recommendations.
buckets: [valid_language, set_language, need_help]
transitions:
valid_language:
ai_feedback:
tokens_for_ai: |
Acknowledge their language choice enthusiastically!
Tell them it's a great choice for simulation.
Store the EXACT language name they said in metadata.programming_language.
metadata_add:
programming_language: "the-users-response"
next_section_and_step: "monty_hall_problem:explain_problem"
set_language:
content_blocks:
- "Language preference updated. Now, what programming language would you like to code in?"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
need_help:
content_blocks:
- "**Popular choices for beginners:**"
- "- **Python** - Easy to read, great for learning"
- "- **JavaScript** - Runs in browsers, very accessible"
- "- **C** - Classic, teaches fundamentals"
- ""
- "**For experienced programmers:**"
- "- **Java** - Object-oriented, widely used"
- "- **Go** - Modern, simple, efficient"
- "- **Rust** - Safe, fast, challenging"
- ""
- "Which would you like to use?"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
- section_id: "monty_hall_problem"
title: "The Monty Hall Problem"
steps:
- step_id: "explain_problem"
title: "The Game Show Scenario"
content_blocks:
- "# The Monty Hall Problem 🎭"
- ""
- "Imagine you're on a game show:"
- ""
- "1. **Three doors** are in front of you: 🚪 🚪 🚪"
- "2. Behind **one door** is a **car** 🚗 (the prize!)"
- "3. Behind the **other two** are **goats** 🐐🐐 (not prizes)"
- ""
- "**The Game:**"
- "- You pick a door (say Door #1)"
- "- The host (Monty Hall) **knows** where the car is"
- "- Monty opens one of the OTHER doors, revealing a goat"
- "- Monty asks: **\"Do you want to SWITCH to the other unopened door?\"**"
- ""
- "**The Question:**"
- "Should you STAY with your original choice, or SWITCH to the other door?"
- step_id: "intuition_check"
title: "What's Your Intuition?"
question: "What do you think? Should you STAY with your original door, SWITCH to the other door, or does it NOT MATTER (50/50 odds)?"
tokens_for_ai: |
The user is giving their intuitive answer to the Monty Hall problem.
Categorize as 'stay' if they think staying is better.
Categorize as 'switch' if they think switching is better.
Categorize as 'same_odds' if they think it doesn't matter (50/50).
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'unsure' if they don't know or want more explanation.
buckets: [stay, switch, same_odds, set_language, unsure]
transitions:
stay:
content_blocks:
- "Interesting! That's a common intuition."
- ""
- "Many people think staying is just as good as switching."
- ""
- "Let's find out if you're right... through CODE! 🔬"
metadata_add:
initial_intuition: "stay"
next_section_and_step: "probability_prediction:predict_probabilities"
switch:
content_blocks:
- "Aha! You might be onto something! 🤔"
- ""
- "That's actually the counterintuitive answer that most people reject at first."
- ""
- "Let's prove it with code! 💻"
metadata_add:
initial_intuition: "switch"
next_section_and_step: "probability_prediction:predict_probabilities"
same_odds:
content_blocks:
- "That's what most people think! It FEELS like 50/50, right?"
- ""
- "After all, there are two doors left... seems like equal odds."
- ""
- "But prepare to have your mind blown! 🤯"
metadata_add:
initial_intuition: "same_odds"
next_section_and_step: "probability_prediction:predict_probabilities"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "monty_hall_problem:intuition_check"
unsure:
content_blocks:
- "No problem! This is a VERY tricky problem."
- ""
- "Even famous mathematicians got it wrong at first!"
- ""
- "Let's discover the answer together through simulation. 🧪"
metadata_add:
initial_intuition: "unsure"
next_section_and_step: "probability_prediction:predict_probabilities"
- section_id: "probability_prediction"
title: "Probability Prediction"
steps:
- step_id: "predict_probabilities"
title: "Predict the Win Rates"
question: |
Before we code, make a prediction:
If you play this game 1000 times...
- What % of the time will STAYING win?
- What % of the time will SWITCHING win?
Give your prediction (e.g., "50% stay, 50% switch" or "33% stay, 67% switch")
tokens_for_ai: |
The user is predicting the win rates for stay vs switch strategies.
The CORRECT answer is: ~33% stay wins, ~67% switch wins (or 1/3 vs 2/3).
Categorize as 'correct_prediction' if they predict something close to 33/67 or 1/3 vs 2/3.
Categorize as 'incorrect_prediction' for any other prediction (like 50/50).
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'unsure' if they don't want to guess.
buckets: [correct_prediction, incorrect_prediction, set_language, unsure]
transitions:
correct_prediction:
content_blocks:
- "Wow! You predicted correctly! 🎯"
- ""
- "**The answer:** Switching wins ~67% of the time (2/3)!"
- ""
- "Most people find this SHOCKING. Let's prove it with code!"
metadata_add:
prediction: "the-users-response"
predicted_correctly: "true"
next_section_and_step: "implement_stay:explain_stay_strategy"
incorrect_prediction:
content_blocks:
- "Good guess! That's what most people predict."
- ""
- "But here's the truth: **Switching wins ~67% of the time (2/3)!** 🤯"
- ""
- "I know, I know... it seems impossible."
- ""
- "That's why we're going to PROVE it with simulation! Let's code it up! 💻"
metadata_add:
prediction: "the-users-response"
predicted_correctly: "false"
next_section_and_step: "implement_stay:explain_stay_strategy"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "probability_prediction:predict_probabilities"
unsure:
content_blocks:
- "No worries! The math is tricky."
- ""
- "Here's the answer: **Switching wins ~67% of the time (2/3)!**"
- ""
- "Sounds crazy, right? Let's prove it with code! 💻"
metadata_add:
prediction: "unsure"
next_section_and_step: "implement_stay:explain_stay_strategy"
- section_id: "implement_stay"
title: "Implement the Stay Strategy"
steps:
- step_id: "explain_stay_strategy"
title: "Understanding the Stay Strategy"
content_blocks:
- "# Simulating the STAY Strategy 🎲"
- ""
- "Let's start by simulating what happens when you ALWAYS stay with your first choice."
- ""
- "**The Algorithm:**"
- "1. Randomly place the car behind one of 3 doors (1, 2, or 3)"
- "2. Player randomly picks a door (1, 2, or 3)"
- "3. If player's door == car's door, they WIN"
- "4. Otherwise, they LOSE"
- "5. Repeat this 1000 times"
- "6. Calculate: (wins / 1000) × 100 = win percentage"
- ""
- "**Key Concepts:**"
- "- **Random number generation** (pick 1, 2, or 3 randomly)"
- "- **Loop** (repeat 1000 times)"
- "- **Counter** (track wins)"
- "- **Conditional** (if door matches, increment wins)"
- ""
- "Note: We don't need to simulate Monty opening a door for the STAY strategy, because the player never switches!"
- step_id: "code_stay_strategy"
title: "Code the Stay Strategy"
question: |
Write a program that simulates the STAY strategy.
Your program should:
- Run 1000 trials
- In each trial, randomly pick where the car is (1-3) and where the player picks (1-3)
- Count wins when they match
- Print the win percentage
Share your code!
tokens_for_ai: |
The user is writing code to simulate the STAY strategy in Monty Hall.
Their programming language is: metadata.programming_language
Check if their code demonstrates:
1. Random number generation (picking 1-3 for car and player)
2. A loop running many trials (doesn't have to be exactly 1000)
3. A counter for wins
4. Comparison logic (if car_door == player_door, count as win)
5. Calculating/printing win percentage
Categorize as 'correct_code' if they have all 5 elements (even if syntax has minor issues).
Categorize as 'partial_code' if they have 3-4 elements or the right idea but incomplete.
Categorize as 'needs_help' if they're stuck, have major errors, or ask for help.
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'off_topic' if completely unrelated.
feedback_tokens_for_ai: |
The user's programming language is: metadata.programming_language
If they wrote correct code:
- Praise their implementation!
- Point out what they did well (random generation, loop structure, etc.)
- If they ran it, acknowledge their results (should be ~33%)
- Provide a CLEAN, COMPLETE working example in their language showing best practices
- Encourage them: "Great! Now let's implement the SWITCH strategy!"
If they wrote partial code:
- Acknowledge what they got right
- Gently point out what's missing (e.g., "You have the loop, but how do you pick random doors?")
- Give a helpful hint in their specific language
- Encourage them to complete it
If they need help:
- Be encouraging!
- Provide a complete working example in their language
- Explain each part clearly
- Ask them to try running it
buckets: [correct_code, partial_code, needs_help, set_language, off_topic]
transitions:
correct_code:
ai_feedback:
tokens_for_ai: "User wrote correct code - see feedback_tokens_for_ai above"
metadata_add:
stay_strategy_completed: "true"
next_section_and_step: "implement_switch:explain_switch_strategy"
partial_code:
ai_feedback:
tokens_for_ai: "User wrote partial code - see feedback_tokens_for_ai above"
counts_as_attempt: true
next_section_and_step: "implement_stay:code_stay_strategy"
needs_help:
ai_feedback:
tokens_for_ai: "User needs help - see feedback_tokens_for_ai above"
counts_as_attempt: false
next_section_and_step: "implement_stay:code_stay_strategy"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implement_stay:code_stay_strategy"
off_topic:
content_blocks:
- "Let's focus on implementing the stay strategy simulation."
- "Share your code for simulating 1000 trials of staying with your first choice!"
counts_as_attempt: false
next_section_and_step: "implement_stay:code_stay_strategy"
- section_id: "implement_switch"
title: "Implement the Switch Strategy"
steps:
- step_id: "explain_switch_strategy"
title: "Understanding the Switch Strategy"
content_blocks:
- "# Simulating the SWITCH Strategy 🔄"
- ""
- "Now for the interesting part: simulating what happens when you ALWAYS switch!"
- ""
- "**The Algorithm:**"
- "1. Randomly place the car behind one of 3 doors (1, 2, or 3)"
- "2. Player randomly picks a door (1, 2, or 3)"
- "3. Monty opens one of the OTHER doors that has a goat"
- " - Monty won't open the car door"
- " - Monty won't open the player's door"
- "4. Player switches to the remaining unopened door"
- "5. If the switched door has the car, they WIN"
- "6. Repeat 1000 times and calculate win percentage"
- ""
- "**Key Insight:**"
- "When you switch, you win if your FIRST choice was WRONG."
- "Since you're wrong 2/3 of the time initially, switching wins 2/3 of the time!"
- ""
- "**Simplification:**"
- "You can actually implement this without simulating Monty's choice!"
- "Just check: if player_first_choice != car_door, then switching wins."
- "Why? Because if you picked wrong initially, the remaining door MUST have the car!"
- step_id: "code_switch_strategy"
title: "Code the Switch Strategy"
question: |
Write a program that simulates the SWITCH strategy.
Your program should:
- Run 1000 trials
- In each trial, randomly place the car and player's initial choice
- Determine if switching would win (switching wins when initial choice was wrong!)
- Count wins and print the win percentage
Share your code!
tokens_for_ai: |
The user is writing code to simulate the SWITCH strategy in Monty Hall.
Their programming language is: metadata.programming_language
Check if their code demonstrates:
1. Random number generation (picking 1-3 for car and initial player choice)
2. A loop running many trials
3. A counter for wins
4. Logic that switching wins when initial choice != car door
5. Calculating/printing win percentage
They might implement it in two ways:
- Simple: if first_choice != car_door, then win (because switch gets the car)
- Complex: Actually simulate Monty opening a door and switching to remaining door
Both are correct!
Categorize as 'correct_code' if they have the right logic.
Categorize as 'partial_code' if they have the right idea but incomplete.
Categorize as 'needs_help' if they're stuck or have major errors.
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'off_topic' if completely unrelated.
feedback_tokens_for_ai: |
The user's programming language is: metadata.programming_language
If they wrote correct code:
- Celebrate! This is the key insight!
- Praise their implementation
- If they ran it, acknowledge results (should be ~67%)
- Provide a clean, complete working example in their language
- Point out the beautiful insight: "Switching wins when you're initially wrong (2/3 of the time)!"
- Encourage them to compare both strategies
If they wrote partial code:
- Acknowledge what they got right
- Hint: "Remember, switching wins when your FIRST choice was WRONG"
- Help them complete it
If they need help:
- Be encouraging!
- Provide a complete working example
- Explain the key insight clearly
buckets: [correct_code, partial_code, needs_help, set_language, off_topic]
transitions:
correct_code:
ai_feedback:
tokens_for_ai: "User wrote correct code - see feedback_tokens_for_ai above"
metadata_add:
switch_strategy_completed: "true"
next_section_and_step: "run_simulations:compare_results"
partial_code:
ai_feedback:
tokens_for_ai: "User wrote partial code - see feedback_tokens_for_ai above"
counts_as_attempt: true
next_section_and_step: "implement_switch:code_switch_strategy"
needs_help:
ai_feedback:
tokens_for_ai: "User needs help - see feedback_tokens_for_ai above"
counts_as_attempt: false
next_section_and_step: "implement_switch:code_switch_strategy"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implement_switch:code_switch_strategy"
off_topic:
content_blocks:
- "Let's focus on implementing the switch strategy simulation."
- "Share your code for simulating what happens when you always switch!"
counts_as_attempt: false
next_section_and_step: "implement_switch:code_switch_strategy"
- section_id: "run_simulations"
title: "Run and Compare Simulations"
steps:
- step_id: "compare_results"
title: "Compare the Strategies"
question: |
Now run BOTH simulations and compare the results!
Run each simulation with at least 1000 trials (more is better - try 10,000!).
Report back:
- What % does STAY win?
- What % does SWITCH win?
- What do you observe?
tokens_for_ai: |
The user is reporting results from running both simulations.
The expected results are:
- STAY wins ~33% (approximately 1/3)
- SWITCH wins ~67% (approximately 2/3)
Categorize as 'correct_results' if they report something close to these percentages.
Accept anything in ranges: STAY 30-36%, SWITCH 64-70%
Categorize as 'incorrect_results' if their numbers are way off (suggesting bugs in code).
Categorize as 'needs_help' if they couldn't run it or had errors.
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'insightful' if they not only report numbers but also express the "aha!" insight.
buckets: [correct_results, incorrect_results, insightful, needs_help, set_language]
transitions:
correct_results:
content_blocks:
- "**AMAZING!** 🎉"
- ""
- "You've proven it with code:"
- "- STAY wins ~33% (1 out of 3 times)"
- "- SWITCH wins ~67% (2 out of 3 times)"
- ""
- "**Switching DOUBLES your chances of winning!**"
- ""
- "This is the Monty Hall paradox - counterintuitive but mathematically proven!"
metadata_add:
simulations_completed: "true"
next_section_and_step: "reflection:reflect_on_why"
incorrect_results:
content_blocks:
- "Hmm, those numbers don't look quite right."
- ""
- "Expected results:"
- "- STAY should win ~33%"
- "- SWITCH should win ~67%"
- ""
- "There might be a bug in your code. Want to review the logic?"
counts_as_attempt: true
next_section_and_step: "run_simulations:compare_results"
insightful:
content_blocks:
- "**YES! You've got it!** 🤯✨"
- ""
- "You've not only proven it with code, but you UNDERSTAND why!"
- ""
- "**The key insight:**"
- "Switching wins when your first choice was wrong (2/3 of the time)!"
- ""
- "Beautiful work! 🎊"
metadata_add:
simulations_completed: "true"
deep_understanding: "true"
next_section_and_step: "reflection:reflect_on_why"
needs_help:
content_blocks:
- "No problem! Let's troubleshoot."
- ""
- "Make sure both simulations:"
- "1. Run enough trials (1000+)"
- "2. Use proper random number generation"
- "3. Have correct win conditions"
- ""
- "Try running them again, or share any errors you're seeing!"
counts_as_attempt: false
next_section_and_step: "run_simulations:compare_results"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "run_simulations:compare_results"
- section_id: "reflection"
title: "Reflection and Understanding"
steps:
- step_id: "reflect_on_why"
title: "Why Does Switching Win?"
question: |
You've seen the proof in code: switching wins ~67% of the time.
But WHY? Can you explain in your own words why switching is better than staying?
Think about it and share your explanation!
tokens_for_ai: |
The user is explaining why switching wins in the Monty Hall problem.
Good explanations mention:
- Initially, you have a 1/3 chance of picking the car (2/3 chance of picking a goat)
- Monty ALWAYS reveals a goat from the doors you didn't pick
- If you picked a goat initially (2/3 probability), the remaining door MUST have the car
- So switching wins whenever you initially picked a goat (2/3 of the time)
Categorize as 'excellent_explanation' if they demonstrate deep understanding.
Categorize as 'good_explanation' if they get the main idea right.
Categorize as 'partial_explanation' if they're on the right track but missing key insights.
Categorize as 'set_language' if asking to change conversation language.
Categorize as 'needs_help' if they're still confused.
feedback_tokens_for_ai: |
Provide encouraging, detailed feedback on their explanation.
If excellent/good:
- Celebrate their understanding!
- Reinforce the key insights they mentioned
- Add any nuances they might have missed
- Congratulate them on conquering this famous paradox!
If partial:
- Acknowledge what they got right
- Gently fill in the missing pieces
- Use clear examples
If needs help:
- Be patient and encouraging
- Explain step by step:
1. You pick a door (1/3 chance of car, 2/3 chance of goat)
2. Monty opens a goat door from the OTHER two doors
3. If you picked a goat (2/3 probability), the remaining door has the car
4. So switching wins 2/3 of the time!
buckets: [excellent_explanation, good_explanation, partial_explanation, set_language, needs_help]
transitions:
excellent_explanation:
ai_feedback:
tokens_for_ai: "User has excellent understanding - see feedback_tokens_for_ai"
metadata_add:
activity_completed: "true"
understanding_level: "excellent"
next_section_and_step: "reflection:conclusion"
good_explanation:
ai_feedback:
tokens_for_ai: "User has good understanding - see feedback_tokens_for_ai"
metadata_add:
activity_completed: "true"
understanding_level: "good"
next_section_and_step: "reflection:conclusion"
partial_explanation:
ai_feedback:
tokens_for_ai: "User has partial understanding - see feedback_tokens_for_ai"
metadata_add:
activity_completed: "true"
understanding_level: "partial"
next_section_and_step: "reflection:conclusion"
set_language:
content_blocks:
- "Language preference updated."
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "reflection:reflect_on_why"
needs_help:
ai_feedback:
tokens_for_ai: "User needs help understanding - see feedback_tokens_for_ai"
metadata_add:
activity_completed: "true"
understanding_level: "needs_review"
next_section_and_step: "reflection:conclusion"
- step_id: "conclusion"
title: "Congratulations!"
content_blocks:
- "# 🎊 Congratulations! 🎊"
- ""
- "You've conquered the **Monty Hall Paradox** through programming!"
- ""
- "## What You've Learned:"
- ""
- "✅ **Probability can be counterintuitive** - our gut feelings often fail us"
- ""
- "✅ **Simulation proves theory** - running 1000s of trials reveals mathematical truth"
- ""
- "✅ **Programming concepts:**"
- " - Random number generation"
- " - Loops and iteration"
- " - Counters and accumulation"
- " - Conditional logic"
- ""
- "✅ **The Monty Hall insight:** Switching wins 2/3 of the time because you win whenever your initial choice was wrong (which happens 2/3 of the time)!"
- ""
- "## Fun Facts:"
- ""
- "- This problem stumped thousands of people, including many mathematicians!"
- "- It's named after Monty Hall, host of \"Let's Make a Deal\""
- "- Even when shown the math, many people still don't believe it - but your code doesn't lie! 📊"
- ""
- "## Next Steps:"
- ""
- "- Try increasing trials to 100,000 or 1,000,000"
- "- Visualize the results with graphs"
- "- Explore other probability paradoxes"
- "- Share this mind-blowing result with friends!"
- ""
- "**Thank you for exploring this fascinating paradox!** 🚪🐐🚗"
- ""
- "May your code always compile and your probabilities always surprise you! ✨"

View file

@ -0,0 +1,645 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_3" # Use code model for programming feedback
tokens_for_ai_rubric: |
You are teaching the multi-armed bandit algorithm to a student.
The student has chosen their programming language stored in metadata.programming_language.
Always provide feedback in THAT specific language.
Be enthusiastic about the gambling/casino metaphor - it makes statistics fun!
Encourage exploration of the exploration vs exploitation tradeoff.
sections:
- section_id: "introduction"
title: "Welcome to the Casino!"
steps:
- step_id: "welcome"
title: "Welcome"
content_blocks:
- "# 🎰 Welcome to Multi-Armed Bandits! 🎰"
- ""
- "Imagine you're in a casino with multiple slot machines (called 'bandits')."
- "Each machine has a different (unknown) payout rate."
- ""
- "**Your goal:** Maximize your winnings by finding the best machine!"
- ""
- "**The challenge:** You don't know which machine is best until you try them."
- ""
- "Should you keep trying all machines equally (exploration)?"
- "Or focus on the best one you've found so far (exploitation)?"
- ""
- "This is the **exploration vs exploitation tradeoff** - one of the most important problems in machine learning!"
- step_id: "choose_language"
title: "Choose Your Programming Language"
question: "What programming language would you like to use for this activity? (Python, JavaScript, Java, C++, Go, Rust, or any other language you prefer)"
tokens_for_ai: |
Extract the programming language from the user's response.
Accept any reasonable programming language mention.
Categorize as 'language_selected' if they mention a programming language.
Categorize as 'set_language' if they want to change the conversation language.
Categorize as 'unclear' if you can't determine the language.
buckets: [language_selected, set_language, unclear]
transitions:
language_selected:
metadata_add:
programming_language: "the-users-response"
content_blocks:
- "Great choice! We'll use that language throughout this activity."
- ""
- "Let's dive into the problem! 🎰"
next_section_and_step: "problem:casino_scenario"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated. Now, which programming language would you like to use for coding?"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
unclear:
content_blocks:
- "I didn't catch which programming language you'd like to use."
- "Please specify: Python, JavaScript, Java, C++, Ruby, Go, etc."
next_section_and_step: "introduction:choose_language"
- section_id: "problem"
title: "Understanding the Problem"
steps:
- step_id: "casino_scenario"
title: "The Casino Scenario"
content_blocks:
- "# 🎰 The Multi-Armed Bandit Problem"
- ""
- "You're in a casino with **3 slot machines**."
- ""
- "**Machine A:** Unknown win rate (let's say it's actually 30%)"
- "**Machine B:** Unknown win rate (let's say it's actually 50%)"
- "**Machine C:** Unknown win rate (let's say it's actually 20%)"
- ""
- "You have **100 coins** to play."
- "Each pull costs 1 coin and might win you 1 coin back (net zero) or lose it (net -1)."
- ""
- "**The catch:** You DON'T know the true win rates!"
- "You have to learn them by playing."
- ""
- "**Real-world applications:**"
- "- Website A/B testing (which button converts better?)"
- "- Online advertising (which ad gets more clicks?)"
- "- Clinical trials (which treatment works better?)"
- "- Recommendation systems (which content keeps users engaged?)"
- step_id: "understand_problem"
title: "Understanding Check"
question: "In your own words, what is the main challenge of the multi-armed bandit problem?"
tokens_for_ai: |
The student should understand the exploration vs exploitation tradeoff.
Categorize as 'excellent' if they mention:
- Balancing exploration (trying different options) and exploitation (using the best known option)
- Not knowing which option is best initially
- Learning while optimizing
Categorize as 'good' if they mention:
- Finding the best option
- Learning from limited attempts
Categorize as 'set_language' if requesting language change.
Categorize as 'needs_help' otherwise.
buckets: [excellent, good, set_language, needs_help]
transitions:
excellent:
ai_feedback:
tokens_for_ai: |
Enthusiastically praise their understanding!
Highlight the specific insight they showed about exploration vs exploitation.
Get them excited about solving this problem.
Use emojis! 🎰🎯
next_section_and_step: "ab_testing:naive_approach"
good:
ai_feedback:
tokens_for_ai: |
Praise what they got right.
Gently clarify the exploration vs exploitation tradeoff.
Encourage them forward.
next_section_and_step: "ab_testing:naive_approach"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "problem:understand_problem"
needs_help:
content_blocks:
- "**Hint:** Think about the tradeoff between:"
- "- **Exploration:** Trying different machines to learn their rates"
- "- **Exploitation:** Using the best machine you've found so far"
- ""
- "If you only explore, you waste coins on bad machines."
- "If you only exploit, you might miss an even better machine!"
next_section_and_step: "problem:understand_problem"
- section_id: "ab_testing"
title: "Traditional A/B Testing"
steps:
- step_id: "naive_approach"
title: "The Naive Approach"
content_blocks:
- "# 📊 Traditional A/B Testing (The Wasteful Way)"
- ""
- "The traditional approach: **Split traffic evenly!**"
- ""
- "With 100 coins and 3 machines:"
- "- Pull Machine A: 33 times"
- "- Pull Machine B: 33 times"
- "- Pull Machine C: 34 times"
- ""
- "Then analyze results and pick the winner."
- ""
- "**Sounds fair, right?** 🤔"
- ""
- "**But wait...** What if Machine C is terrible (20% win rate)?"
- "You just wasted 34 coins learning what you could have learned after 5 pulls!"
- ""
- "**The problem with A/B testing:**"
- "- Keeps pulling losing arms even after you know they're bad"
- "- Wastes resources (users, ad budget, medical treatments)"
- "- Takes longer to reach optimal decision"
- ""
- "Let's implement this to see the waste in action!"
- step_id: "implement_ab_test"
title: "Implement A/B Test Simulation"
question: |
Write code that simulates a traditional A/B test with 3 slot machines.
Requirements:
- 3 machines with true win rates: [0.3, 0.5, 0.2]
- 100 total pulls, split evenly (33, 33, 34)
- Track wins and losses for each machine
- Calculate and print the estimated win rate for each machine
- Calculate total reward (wins - losses)
Don't worry about perfect code - focus on the logic!
tokens_for_ai: |
The student is implementing a basic A/B test simulation in their chosen language (metadata.programming_language).
Check if their code includes:
- Arrays/lists to track performance
- Random number generation for simulating pulls
- Even split of pulls across machines
- Calculation of win rates
- Total reward tracking
Categorize as 'excellent' if code is complete and correct.
Categorize as 'good_attempt' if logic is mostly right but has minor issues.
Categorize as 'needs_guidance' if they're struggling with the structure.
Categorize as 'set_language' if requesting language change.
Categorize as 'wrong_language' if they used a different programming language than stored in metadata.
feedback_tokens_for_ai: |
Provide feedback in their chosen language: {metadata.programming_language}
If excellent: Praise their implementation! Run through what happens:
- Machine A gets pulled 33 times, wins ~10 times (30%)
- Machine B gets pulled 33 times, wins ~16 times (50%)
- Machine C gets pulled 34 times, wins ~7 times (20%)
- Total reward is negative (you lose money overall)
- Point out: We kept pulling bad machines even after learning they're bad!
If good_attempt: Point out what's good, fix specific issues, provide corrected code.
If needs_guidance: Provide a complete working example with detailed comments.
Explain each part: random simulation, tracking, calculating rates.
If wrong_language: Gently remind them they chose {metadata.programming_language}.
Provide the code in the correct language.
buckets: [excellent, good_attempt, needs_guidance, set_language, wrong_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for excellent case"
metadata_add:
ab_test_completed: "true"
next_section_and_step: "waste:see_the_waste"
good_attempt:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for good_attempt case"
metadata_add:
ab_test_completed: "true"
next_section_and_step: "waste:see_the_waste"
needs_guidance:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for needs_guidance case"
counts_as_attempt: false
next_section_and_step: "ab_testing:implement_ab_test"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "ab_testing:implement_ab_test"
wrong_language:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for wrong_language case"
counts_as_attempt: false
next_section_and_step: "ab_testing:implement_ab_test"
- section_id: "waste"
title: "Understanding the Waste"
steps:
- step_id: "see_the_waste"
title: "The Waste of A/B Testing"
content_blocks:
- "# 💸 The Waste of Traditional A/B Testing"
- ""
- "Let's see what happens in your A/B test simulation:"
- ""
- "**After 10 pulls of each machine, you might observe:**"
- "- Machine A: 3 wins (30% estimated)"
- "- Machine B: 5 wins (50% estimated)"
- "- Machine C: 2 wins (20% estimated)"
- ""
- "**You now know Machine B is best!** 🎯"
- ""
- "**But traditional A/B testing continues:**"
- "- Pulls Machine A: 23 more times (waste!)"
- "- Pulls Machine B: 23 more times (good!)"
- "- Pulls Machine C: 24 more times (waste!)"
- ""
- "You wasted ~47 pulls on machines you KNEW were inferior!"
- ""
- "**Cumulative regret:** The total loss from not always choosing the best option."
- ""
- "In A/B testing: HIGH regret (you keep pulling losing arms)"
- "In bandit algorithms: LOW regret (you adapt and focus on winners)"
- step_id: "understand_regret"
title: "Understanding Regret"
question: "Why does traditional A/B testing accumulate more regret than an adaptive algorithm?"
tokens_for_ai: |
Check if student understands that A/B testing:
- Continues pulling all arms equally even after learning which is best
- Doesn't adapt based on observations
- Wastes resources on known-bad options
Categorize as 'excellent' if they clearly explain the adaptive vs non-adaptive difference.
Categorize as 'good' if they understand but less clearly.
Categorize as 'set_language' if requesting language change.
Categorize as 'needs_clarity' otherwise.
buckets: [excellent, good, set_language, needs_clarity]
transitions:
excellent:
ai_feedback:
tokens_for_ai: |
Celebrate their understanding! 🎉
Emphasize: Adaptive algorithms LEARN and SHIFT resources to winners.
Get them excited to implement epsilon-greedy!
next_section_and_step: "epsilon_greedy:introduce_algorithm"
good:
ai_feedback:
tokens_for_ai: |
Praise their understanding.
Clarify: The key is ADAPTATION - shifting pulls to better arms as you learn.
next_section_and_step: "epsilon_greedy:introduce_algorithm"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "waste:understand_regret"
needs_clarity:
content_blocks:
- "**Think about it this way:**"
- ""
- "**A/B Testing:** Pulls each arm 33 times, no matter what you learn"
- "**Adaptive Algorithm:** Pulls good arms MORE as you learn they're good"
- ""
- "If you learn Machine B is best after 10 pulls, wouldn't you want to pull it MORE than the others?"
next_section_and_step: "waste:understand_regret"
- section_id: "epsilon_greedy"
title: "The Epsilon-Greedy Algorithm"
steps:
- step_id: "introduce_algorithm"
title: "Introducing Epsilon-Greedy"
content_blocks:
- "# 🎯 The Epsilon-Greedy Algorithm"
- ""
- "Now for the smart approach: **Epsilon-Greedy**"
- ""
- "**The algorithm:**"
- "1. Keep track of each machine's estimated win rate"
- "2. With probability **ε** (epsilon): EXPLORE (random machine)"
- "3. With probability **1-ε**: EXPLOIT (best machine so far)"
- "4. Update estimates after each pull"
- ""
- "**Example with ε = 0.1 (10% exploration):**"
- "- 10% of the time: Try a random machine (exploration)"
- "- 90% of the time: Pull the best machine you've found (exploitation)"
- ""
- "**Why this works:**"
- "- Early on: All estimates are uncertain, exploration finds the best"
- "- Later on: Estimates are good, exploitation maximizes reward"
- "- Always a small chance to explore (in case estimates are wrong)"
- ""
- "**Key data structures:**"
- "- Array of pull counts: [0, 0, 0]"
- "- Array of win counts: [0, 0, 0]"
- "- Array of win rates: [0.0, 0.0, 0.0]"
- ""
- "**After each pull:**"
- "- Increment pull count for that machine"
- "- If win: increment win count"
- "- Update win rate = wins / pulls"
- step_id: "implement_epsilon_greedy"
title: "Implement Epsilon-Greedy"
question: |
Implement the epsilon-greedy algorithm!
Requirements:
- 3 machines with true win rates: [0.3, 0.5, 0.2]
- 100 total pulls
- Epsilon = 0.1 (10% exploration)
- Track: pull counts, win counts, estimated win rates
- For each pull:
* Random number < 0.1? Explore (random machine)
* Otherwise: Exploit (best machine so far)
* Simulate the pull (win or lose based on true rate)
* Update statistics
- Print estimated win rates and total reward
Focus on the logic - don't worry about perfect code!
tokens_for_ai: |
The student is implementing epsilon-greedy in their chosen language (metadata.programming_language).
Check if their code includes:
- Arrays/lists for tracking (pull counts, wins, rates)
- Random number generation for epsilon decision AND pull simulation
- Exploration: pick random machine
- Exploitation: pick machine with highest estimated rate (handle ties)
- Update logic: increment counts, recalculate rates
- Loop for 100 pulls
Categorize as 'excellent' if implementation is complete and correct.
Categorize as 'good_attempt' if logic is mostly right but has issues.
Categorize as 'needs_help' if they're struggling with the algorithm.
Categorize as 'set_language' if requesting language change.
Categorize as 'wrong_language' if using different language than metadata.
feedback_tokens_for_ai: |
Provide feedback in their chosen language: {metadata.programming_language}
If excellent: CELEBRATE! 🎉 This is a real machine learning algorithm!
- Explain what should happen: After ~20 pulls, Machine B dominates
- Most pulls go to Machine B (the 50% winner)
- Occasional exploration keeps checking others
- Total reward is MUCH higher than A/B testing
- Regret is MUCH lower
- Provide their code with enthusiastic comments
If good_attempt:
- Praise what works
- Fix specific issues (epsilon logic, argmax, update calculations)
- Provide corrected code
If needs_help:
- Provide complete working implementation with detailed comments
- Explain the epsilon decision (random < 0.1)
- Explain argmax (finding best machine)
- Explain update logic (running average)
If wrong_language: Remind them of their chosen language, provide correct version.
buckets: [excellent, good_attempt, needs_help, set_language, wrong_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for excellent case"
metadata_add:
epsilon_greedy_completed: "true"
next_section_and_step: "comparison:compare_algorithms"
good_attempt:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for good_attempt case"
metadata_add:
epsilon_greedy_completed: "true"
next_section_and_step: "comparison:compare_algorithms"
needs_help:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for needs_help case"
counts_as_attempt: false
next_section_and_step: "epsilon_greedy:implement_epsilon_greedy"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "epsilon_greedy:implement_epsilon_greedy"
wrong_language:
ai_feedback:
tokens_for_ai: "Use feedback_tokens_for_ai instructions for wrong_language case"
counts_as_attempt: false
next_section_and_step: "epsilon_greedy:implement_epsilon_greedy"
- section_id: "comparison"
title: "A/B vs Bandit Comparison"
steps:
- step_id: "compare_algorithms"
title: "The Dramatic Difference"
content_blocks:
- "# 📊 A/B Testing vs Epsilon-Greedy: The Results"
- ""
- "Let's compare what happens with 100 pulls:"
- ""
- "## 🐌 Traditional A/B Testing:"
- "- Machine A (30%): 33 pulls → ~10 wins"
- "- Machine B (50%): 33 pulls → ~16 wins"
- "- Machine C (20%): 34 pulls → ~7 wins"
- "- **Total wins: ~33**"
- "- **Total reward: -34** (you lose money!)"
- "- **Cumulative regret: ~17** (missed wins from not choosing B)"
- ""
- "## 🚀 Epsilon-Greedy (ε=0.1):"
- "- Machine A (30%): ~5 pulls → ~2 wins"
- "- Machine B (50%): ~90 pulls → ~45 wins"
- "- Machine C (20%): ~5 pulls → ~1 win"
- "- **Total wins: ~48**"
- "- **Total reward: -4** (much better!)"
- "- **Cumulative regret: ~2** (way lower!)"
- ""
- "**The difference:**"
- "- Epsilon-greedy wins **45% more** (15 extra wins)"
- "- Epsilon-greedy saves **30 wasted pulls**"
- "- Epsilon-greedy achieves **~88% lower regret**"
- ""
- "**This is why companies like Google, Facebook, and Amazon use bandit algorithms instead of A/B tests!**"
- step_id: "tuning_epsilon"
title: "Understanding Epsilon"
question: "What do you think would happen if we set epsilon to 0.5 (50% exploration) instead of 0.1? Would it be better or worse?"
tokens_for_ai: |
Check if student understands the exploration/exploitation tradeoff.
Higher epsilon = more exploration = MORE waste on bad arms.
The sweet spot is usually 0.01 to 0.2 depending on uncertainty.
Categorize as 'correct' if they say worse/more regret/more waste/less focused.
Categorize as 'set_language' for language changes.
Categorize as 'incorrect' if they think higher epsilon is better.
buckets: [correct, set_language, incorrect]
transitions:
correct:
ai_feedback:
tokens_for_ai: |
Excellent insight! 🎯
Explain: Higher epsilon = more random exploration = wasting pulls on known-bad arms.
Low epsilon (0.01-0.1) = mostly exploit the best, occasionally explore.
Connect to real-world: Early in a campaign, use higher epsilon (more uncertainty).
Later, use lower epsilon (you're confident about the best option).
Some algorithms even DECREASE epsilon over time!
next_section_and_step: "comparison:real_world"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "comparison:tuning_epsilon"
incorrect:
content_blocks:
- "**Think about it:**"
- ""
- "Epsilon = 0.5 means 50% of pulls are RANDOM."
- "Even after you know Machine B is best, half your pulls are wasted on A and C!"
- ""
- "Lower epsilon = more exploitation of the best option."
- "Higher epsilon = more exploration (useful only when very uncertain)."
next_section_and_step: "comparison:tuning_epsilon"
- step_id: "real_world"
title: "Real-World Applications"
content_blocks:
- "# 🌍 Real-World Multi-Armed Bandits"
- ""
- "Companies use bandit algorithms every day:"
- ""
- "## 📱 Website Optimization"
- "**Problem:** Which button color converts better?"
- "**A/B test:** Show red to 50%, blue to 50% for 2 weeks"
- "**Bandit:** Start equal, shift traffic to winner within days"
- "**Result:** 30-50% more conversions during the test period"
- ""
- "## 📰 News Headline Testing"
- "**Problem:** Which headline gets more clicks?"
- "**Bandit:** Show all headlines initially, quickly focus on winners"
- "**Result:** Maximize engagement while learning"
- ""
- "## 💊 Clinical Trials"
- "**Problem:** Which treatment works better?"
- "**A/B test:** Give treatment A to 50%, treatment B to 50%"
- "**Bandit:** Shift MORE patients to effective treatment as you learn"
- "**Result:** More lives saved during the trial (ethical win!)"
- ""
- "## 🎯 Ad Placement"
- "**Problem:** Which ad creative performs best?"
- "**Bandit:** Automatically shift budget to high-performing ads"
- "**Result:** Lower cost per conversion, higher ROI"
- ""
- "## 🎮 Game Design"
- "**Problem:** Which difficulty level keeps players engaged?"
- "**Bandit:** Adapt difficulty to maximize playtime"
- "**Result:** Better player retention"
- ""
- "**Advanced algorithms:**"
- "- **Thompson Sampling:** Bayesian approach, often better than epsilon-greedy"
- "- **UCB (Upper Confidence Bound):** Uses confidence intervals"
- "- **Contextual Bandits:** Different arms for different user types"
- "- **Bayesian Bandits:** Full probability distributions"
- section_id: "conclusion"
title: "Conclusion"
steps:
- step_id: "reflection"
title: "Final Reflection"
question: "In your own words, explain when you would use a bandit algorithm instead of traditional A/B testing, and why."
tokens_for_ai: |
Student should understand:
- Use bandits when you want to minimize regret (wasted resources)
- Use bandits when you can't afford to waste on losing options
- Use bandits when you want faster optimization
- A/B testing is simpler but wastes resources
Categorize as 'excellent' if they clearly explain the efficiency/regret benefit.
Categorize as 'good' if they show understanding but less detailed.
Categorize as 'set_language' for language changes.
Categorize as 'needs_help' if they don't get the key benefit.
buckets: [excellent, good, set_language, needs_help]
transitions:
excellent:
ai_feedback:
tokens_for_ai: |
Celebrate their mastery! 🎉🎰
They now understand a fundamental machine learning algorithm.
Highlight specific insights from their answer.
Encourage them to implement this in real projects.
Mention: This is just the beginning - Thompson Sampling, UCB, contextual bandits are even more powerful!
metadata_add:
activity_completed: "true"
mastery_level: "excellent"
next_section_and_step: "conclusion:goodbye"
good:
ai_feedback:
tokens_for_ai: |
Praise their understanding!
Emphasize the key point: Bandits minimize regret by adapting.
Encourage them to explore more advanced algorithms.
metadata_add:
activity_completed: "true"
mastery_level: "good"
next_section_and_step: "conclusion:goodbye"
set_language:
metadata_add:
language: "the-users-response"
content_blocks:
- "Language preference updated."
counts_as_attempt: false
next_section_and_step: "conclusion:reflection"
needs_help:
content_blocks:
- "**Key insight:**"
- ""
- "Bandit algorithms ADAPT as they learn."
- "A/B testing DOESN'T adapt - it keeps wasting resources on losing options."
- ""
- "**Use bandits when:**"
- "- You can't afford to waste resources (money, users, medical treatments)"
- "- You want to optimize faster"
- "- You want to minimize regret"
- ""
- "Give it another shot! When would you use a bandit algorithm?"
next_section_and_step: "conclusion:reflection"
- step_id: "goodbye"
title: "Congratulations!"
content_blocks:
- "# 🎰🎉 Congratulations! You've Mastered Multi-Armed Bandits! 🎉🎰"
- ""
- "You now understand:"
- "✅ The exploration vs exploitation tradeoff"
- "✅ Why traditional A/B testing is wasteful"
- "✅ How epsilon-greedy minimizes regret"
- "✅ Real-world applications of bandit algorithms"
- "✅ How to implement adaptive learning in code"
- ""
- "**Next steps:**"
- "- Implement Thompson Sampling (Bayesian approach)"
- "- Learn UCB (Upper Confidence Bound) algorithm"
- "- Explore contextual bandits (different arms for different contexts)"
- "- Apply this to a real A/B testing scenario"
- ""
- "**You're now equipped with a powerful ML algorithm used by Google, Facebook, Amazon, and Netflix!**"
- ""
- "Keep exploring, keep exploiting! 🚀"

361
research/activity5.yaml Normal file
View file

@ -0,0 +1,361 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Perimeter Security"
steps:
- step_id: "step_1"
title: "What is Perimeter Security?"
content_blocks:
- "Welcome to the perimeter security training for a presidential speech."
- "Perimeter security involves measures taken to protect the outer boundary of a location to prevent unauthorized access."
tokens_for_ai: "Explain what perimeter security is and its importance in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you understand by perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of perimeter security."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of perimeter security. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on perimeter security."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of perimeter security in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of Perimeter Security for a Presidential Speech"
content_blocks:
- "Perimeter security is crucial for a presidential speech to ensure the safety of the president and attendees."
- "It helps prevent unauthorized access, potential threats, and ensures a controlled environment."
tokens_for_ai: "Explain the importance of perimeter security for a presidential speech in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is perimeter security important for a presidential speech?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of perimeter security for a presidential speech."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of perimeter security."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of perimeter security in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Planning and Preparation"
steps:
- step_id: "step_1"
title: "Site Assessment"
content_blocks:
- "The first step in hardening a perimeter is conducting a thorough site assessment."
- "Identify potential vulnerabilities, entry points, and areas that need reinforcement."
tokens_for_ai: "Explain the importance of site assessment and what it involves in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the purpose of a site assessment in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the purpose of a site assessment."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the site assessment. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the site assessment."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the site assessment in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Security Plan Development"
content_blocks:
- "Develop a comprehensive security plan based on the site assessment."
- "The plan should include security measures, personnel deployment, and emergency response protocols."
tokens_for_ai: "Explain how to develop a security plan and what it should include in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What should be included in a security plan for a presidential speech?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know what should be included in a security plan."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the security plan. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the security plan."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the security plan in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Implementing Security Measures"
steps:
- step_id: "step_1"
title: "Physical Barriers"
content_blocks:
- "Physical barriers such as fences, bollards, and barricades are essential for perimeter security."
- "They help control access and prevent unauthorized entry."
tokens_for_ai: "Explain the role of physical barriers in perimeter security in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the role of physical barriers in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the role of physical barriers."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of physical barriers. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on physical barriers."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of physical barriers in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Access Control"
content_blocks:
- "Access control measures include security checkpoints, ID verification, and controlled entry points."
- "These measures help ensure that only authorized personnel can enter the secured area."
tokens_for_ai: "Explain the importance of access control in perimeter security in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is access control important in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of access control."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of access control. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on access control."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of access control in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Monitoring and Surveillance"
steps:
- step_id: "step_1"
title: "Surveillance Cameras"
content_blocks:
- "Surveillance cameras are essential for monitoring the perimeter and detecting potential threats."
- "They provide real-time video feeds to security personnel."
tokens_for_ai: "Explain the role of surveillance cameras in perimeter security in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the role of surveillance cameras in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the role of surveillance cameras."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of surveillance cameras. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on surveillance cameras."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of surveillance cameras in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Security Personnel"
content_blocks:
- "Security personnel play a crucial role in monitoring the perimeter and responding to incidents."
- "They should be strategically positioned and equipped with communication devices."
tokens_for_ai: "Explain the role of security personnel in perimeter security in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the role of security personnel in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the role of security personnel."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of security personnel. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on security personnel."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of security personnel in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Emergency Response"
steps:
- step_id: "step_1"
title: "Emergency Protocols"
content_blocks:
- "Emergency protocols are essential for responding to incidents quickly and effectively."
- "They should include evacuation plans, communication procedures, and roles and responsibilities."
tokens_for_ai: "Explain the importance of emergency protocols in perimeter security in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why are emergency protocols important in perimeter security?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the importance of emergency protocols."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of emergency protocols. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on emergency protocols."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of emergency protocols in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Communication During Emergencies"
content_blocks:
- "Effective communication is crucial during emergencies to coordinate response efforts."
- "Use radios, phones, and other communication devices to stay in contact with security personnel."
tokens_for_ai: "Explain the importance of communication during emergencies in a friendly and engaging manner suitable for a security professional. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is communication important during emergencies?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of communication during emergencies."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of communication during emergencies. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on communication during emergencies."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of communication during emergencies in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_3"
title: "The End."
content_blocks:
- "The End."

View file

@ -0,0 +1,861 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
You are an enthusiastic evolution scientist teaching genetic algorithms! 🧬
Use the evolution metaphor throughout - "breeding," "survival of the fittest," "mutations."
Be encouraging and celebrate when students grasp concepts.
The user's programming language is stored in metadata.programming_language (if set).
Always provide feedback in their chosen language.
When evaluating code:
- Check if it implements the core concept (not perfect syntax)
- Look for understanding of: fitness, selection, crossover, mutation
- Praise creative approaches
- Guide gently if they're struggling
sections:
- section_id: "introduction"
title: "Welcome to Genetic Algorithms"
steps:
- step_id: "welcome"
title: "Welcome"
content_blocks:
- "# 🧬 Welcome to Genetic Algorithms: Evolution in Code! 🧬"
- ""
- "Ever wondered how nature solves complex optimization problems?"
- ""
- "**Nature's secret**: Evolution! 🌱➡️🌳"
- ""
- "- **Reproduce** the best solutions"
- "- **Combine** traits from parents (crossover)"
- "- **Mutate** randomly for diversity"
- "- **Repeat** for many generations"
- ""
- "Today, you'll build a genetic algorithm that evolves solutions to problems that would take billions of years to solve by brute force!"
- ""
- "Let's start by choosing your programming language..."
- step_id: "choose_language"
title: "Choose Programming Language"
question: "What programming language would you like to use? (Python, JavaScript, Java, C++, Ruby, Go, Rust, or any language you prefer)"
tokens_for_ai: |
Extract the programming language from their response.
Accept ANY language they mention: Python, JavaScript, Java, C++, C#, Ruby, Go, Rust, PHP, Swift, Kotlin, R, etc.
Categorize as 'language_chosen' if they name a specific language.
Categorize as 'unsure' if they seem uncertain or ask for a recommendation.
Categorize as 'off_topic' if completely unrelated.
buckets: [language_chosen, unsure, off_topic, set_language]
transitions:
language_chosen:
metadata_add:
programming_language: "the-users-response"
ai_feedback:
tokens_for_ai: |
Great choice! Celebrate their language selection.
Mention one reason why their language is good for genetic algorithms.
(e.g., Python has great list operations, JavaScript has functional programming, etc.)
next_section_and_step: "concepts:evolution_metaphor"
unsure:
content_blocks:
- "No worries! 😊"
- ""
- "**I recommend Python** for beginners - it's clear and readable."
- "**JavaScript** is great if you're web-focused."
- "**C++** or **Rust** if you want performance."
- ""
- "Pick whichever you're most comfortable with - genetic algorithms work in ANY language!"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
off_topic:
content_blocks:
- "Let's focus on choosing a programming language first! 🎯"
- ""
- "Popular choices: Python, JavaScript, Java, C++, Ruby, Go, Rust"
- ""
- "Which language would you like to use?"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "introduction:choose_language"
- section_id: "concepts"
title: "Understanding Genetic Algorithms"
steps:
- step_id: "evolution_metaphor"
title: "The Evolution Metaphor"
content_blocks:
- "# 🦎 How Evolution Solves Complex Problems 🦎"
- ""
- "Imagine you want to find the **perfect solution** to a problem."
- ""
- "**Brute Force**: Try every possibility ❌"
- "- Problem: 10 variables, 100 values each = 100^10 = 100 trillion trillion possibilities!"
- "- Would take longer than the age of the universe 🌌"
- ""
- "**Genetic Algorithm**: Let solutions evolve ✅"
- "- Start with random guesses (generation 1)"
- "- Keep the best ones"
- "- Breed them together (crossover)"
- "- Add random mutations"
- "- Repeat for 100 generations"
- "- Find excellent solutions in seconds! ⚡"
- ""
- "This is how nature designed complex organisms over millions of years."
- "We'll do it in code in minutes! 🧬"
- step_id: "ga_components"
title: "Genetic Algorithm Components"
content_blocks:
- "# 🧬 The 5 Core Components of Genetic Algorithms"
- ""
- "## 1⃣ **Population** (Pool of Candidates)"
- "- A collection of potential solutions"
- "- Each solution is called a **chromosome**"
- "- Example: Random strings trying to match \"GENETIC\""
- ""
- "## 2⃣ **Fitness Function** (Survival Test)"
- "- Measures how good each solution is"
- "- Better fitness = more likely to survive"
- "- Example: Count matching letters in the string"
- ""
- "## 3⃣ **Selection** (Choose the Best)"
- "- Pick the fittest individuals to reproduce"
- "- Methods: Tournament, Roulette Wheel, Elite Selection"
- "- Survival of the fittest! 💪"
- ""
- "## 4⃣ **Crossover** (Breeding)"
- "- Combine two parent solutions"
- "- Create offspring with mixed traits"
- "- Example: \"GEN\" + \"TIC\" = \"GENIC\""
- ""
- "## 5⃣ **Mutation** (Random Changes)"
- "- Randomly modify some offspring"
- "- Prevents getting stuck in local optima"
- "- Adds diversity to the gene pool 🌈"
- step_id: "understand_components"
title: "Check Understanding"
question: "In your own words, why do we need BOTH crossover AND mutation in genetic algorithms? (Hint: Think about what each one does for the solution space)"
tokens_for_ai: |
Categorize their understanding:
'deep_understanding' if they mention BOTH:
- Crossover combines good traits from parents (exploitation)
- Mutation explores new possibilities and prevents premature convergence (exploration)
'partial_understanding' if they mention ONE of:
- Crossover combines solutions
- Mutation adds randomness/diversity
'creative_thinking' if wrong but shows good reasoning about evolution/optimization
'needs_help' if confused or very brief
'set_language' if changing language preference
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their chosen language from metadata.programming_language.
If deep_understanding: Celebrate! Explain this is the exploration-exploitation tradeoff.
If partial_understanding: Acknowledge what they got right, add the missing piece.
If creative_thinking: Appreciate their reasoning, gently guide to the core concept.
If needs_help: Use an analogy - crossover is like breeding dogs (mix best traits), mutation is like genetic mutations (new random traits).
buckets: [deep_understanding, partial_understanding, creative_thinking, needs_help, set_language, off_topic]
transitions:
deep_understanding:
ai_feedback:
tokens_for_ai: "Celebrate their understanding! Mention the exploration-exploitation tradeoff is key to many optimization algorithms."
next_section_and_step: "problem:define_problem"
partial_understanding:
ai_feedback:
tokens_for_ai: "Acknowledge what they got right. Explain the missing piece (exploration vs exploitation). Be encouraging!"
next_section_and_step: "problem:define_problem"
creative_thinking:
ai_feedback:
tokens_for_ai: "Appreciate their creative thinking! Guide them to the core: crossover=exploit good solutions, mutation=explore new ones."
next_section_and_step: "problem:define_problem"
needs_help:
content_blocks:
- "Let me clarify! 🎯"
- ""
- "**Crossover** = Combine the BEST traits from parents"
- "- Focuses on what's already working"
- "- Exploitation of good solutions"
- ""
- "**Mutation** = Random changes"
- "- Explores NEW possibilities"
- "- Prevents getting stuck"
- ""
- "**Together** = Perfect balance of using what works + trying new things! 🧬"
next_section_and_step: "problem:define_problem"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "concepts:understand_components"
off_topic:
content_blocks:
- "Let's stay focused on genetic algorithms! 🧬"
- ""
- "Think about why we need BOTH crossover (combining solutions) AND mutation (random changes)."
counts_as_attempt: false
next_section_and_step: "concepts:understand_components"
- section_id: "problem"
title: "Define the Problem"
steps:
- step_id: "define_problem"
title: "Our Evolution Challenge"
content_blocks:
- "# 🎯 The String Evolution Challenge"
- ""
- "**Goal**: Evolve random characters into the string \"GENETIC\""
- ""
- "**Starting Point**:"
- "- Population of 100 random 7-letter strings"
- "- Example: \"XQMZPRL\", \"KDJFHGA\", \"BVNCXZM\""
- "- Fitness = 0 (no matching letters)"
- ""
- "**After 100 Generations**:"
- "- Best solution: \"GENETIC\""
- "- Fitness = 7 (perfect match!)"
- "- We'll watch evolution happen! 🧬➡️✨"
- ""
- "**Why This Problem?**"
- "- Easy to understand fitness (count matching letters)"
- "- Brute force: 26^7 = 8 billion possibilities"
- "- GA solves it in ~100 generations with population of 100 = 10,000 evaluations"
- "- **800,000x faster than brute force!** ⚡"
- ""
- "Let's build it step by step..."
- section_id: "implementation"
title: "Build the Genetic Algorithm"
steps:
- step_id: "fitness_function"
title: "Step 1: Fitness Function"
question: "Write a fitness function that takes a candidate string and returns how many letters match \"GENETIC\" in the correct positions. Think about how you'd measure similarity!"
tokens_for_ai: |
Evaluate their fitness function code in their chosen language (metadata.programming_language).
'excellent_implementation' if they:
- Compare each character position
- Count matches
- Handle string comparison correctly
- Code looks reasonable (don't nitpick syntax)
'correct_concept' if they describe the approach correctly even if code has minor issues
'partial_understanding' if they count total matching letters but not position-specific
'needs_guidance' if confused or very incomplete
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If excellent_implementation:
- Celebrate! Show how this fitness function guides evolution.
- Mention: "This is the KEY - fitness drives everything!"
If correct_concept or partial_understanding:
- Acknowledge their understanding
- If not position-specific, explain why positions matter
- Show a working example of the fitness function
If needs_guidance:
- Provide a complete working example
- Explain: loop through each position, count matches
- Walk through: "GXXXXXX" vs "GENETIC" = fitness of 1
buckets: [excellent_implementation, correct_concept, partial_understanding, needs_guidance, set_language, off_topic]
transitions:
excellent_implementation:
ai_feedback:
tokens_for_ai: "Celebrate! Show example: fitness('GXXXXXX') = 1, fitness('GENETIC') = 7. Mention this guides ALL evolution!"
metadata_add:
fitness_complete: "true"
progress_score: "1"
next_section_and_step: "implementation:selection"
correct_concept:
ai_feedback:
tokens_for_ai: "Great concept! Show a polished working version in their language. Explain how it works step-by-step."
metadata_add:
fitness_complete: "true"
progress_score: "1"
next_section_and_step: "implementation:selection"
partial_understanding:
ai_feedback:
tokens_for_ai: "Good start! Explain why POSITION matters. Show corrected version comparing index-by-index."
metadata_add:
fitness_complete: "true"
progress_score: "1"
next_section_and_step: "implementation:selection"
needs_guidance:
ai_feedback:
tokens_for_ai: "No worries! Provide complete working fitness function in their language. Walk through example: 'GXXXXXX' scores 1 because only first 'G' matches."
metadata_add:
fitness_complete: "true"
progress_score: "1"
next_section_and_step: "implementation:selection"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implementation:fitness_function"
off_topic:
content_blocks:
- "Let's focus on the fitness function! 🎯"
- ""
- "Your task: Write code that counts how many letters in a candidate string match \"GENETIC\" at the same positions."
- ""
- "Example: \"GXXXXXX\" should return 1 (only the G matches)"
counts_as_attempt: false
next_section_and_step: "implementation:fitness_function"
- step_id: "selection"
title: "Step 2: Selection (Choose the Fittest)"
question: "Write a selection function that picks the best individuals from the population. Describe your strategy: will you use tournament selection (pick best from random groups), elite selection (just take the top N), or another method?"
tokens_for_ai: |
Evaluate their selection implementation/strategy.
'excellent_implementation' if they:
- Describe a valid selection method (tournament, elite, roulette wheel, etc.)
- Show code or clear algorithm
- Understand it favors higher fitness
'correct_strategy' if they describe a valid approach even without perfect code
'creative_approach' if they invent a reasonable selection method
'needs_guidance' if confused or missing the "favor fitness" concept
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If excellent_implementation:
- Praise their approach!
- Explain why their method works (survival of fittest)
- Show example: population of 100 → select top 50 for breeding
If correct_strategy or creative_approach:
- Validate their thinking
- Show a clean implementation
- Mention: "Selection pressure drives evolution!"
If needs_guidance:
- Explain selection favors fit individuals
- Provide tournament selection example: pick 5 random, take the best, repeat
- Or elite selection: sort by fitness, take top 50%
buckets: [excellent_implementation, correct_strategy, creative_approach, needs_guidance, set_language, off_topic]
transitions:
excellent_implementation:
ai_feedback:
tokens_for_ai: "Fantastic! Explain how their selection method creates selection pressure. Show example with fitnesses [7,5,3,1] → likely picks 7 and 5."
metadata_add:
selection_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:crossover"
correct_strategy:
ai_feedback:
tokens_for_ai: "Great strategy! Polish their idea with clean code example. Emphasize: this is survival of the fittest in action! 💪"
metadata_add:
selection_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:crossover"
creative_approach:
ai_feedback:
tokens_for_ai: "Love the creativity! Validate if their method favors fitness. Show how it compares to standard approaches."
metadata_add:
selection_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:crossover"
needs_guidance:
ai_feedback:
tokens_for_ai: "Let me help! Explain tournament selection: randomly pick 5 individuals, select the fittest, repeat. Show complete code example in their language."
metadata_add:
selection_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:crossover"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implementation:selection"
off_topic:
content_blocks:
- "Let's focus on selection! 🎯"
- ""
- "**Goal**: Pick the best individuals to be parents"
- ""
- "Think about: How do you favor high-fitness individuals while still allowing some diversity?"
counts_as_attempt: false
next_section_and_step: "implementation:selection"
- step_id: "crossover"
title: "Step 3: Crossover (Breeding)"
question: "Write a crossover function that takes two parent strings and creates offspring by combining their genes. How will you mix the parents' traits?"
tokens_for_ai: |
Evaluate their crossover implementation.
'excellent_implementation' if they:
- Show code that combines two parent strings
- Use any valid method (single-point, two-point, uniform)
- Create offspring with mixed traits
'correct_concept' if they describe crossover correctly even with imperfect code
'creative_approach' if they invent a reasonable mixing strategy
'needs_guidance' if confused or doesn't mix parent traits
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If excellent_implementation:
- Celebrate! Show their crossover in action
- Example: parent1="GENXXXX", parent2="XXXETIC" → child="GENETIC" (if lucky!)
- Explain: "This is how good traits combine! 🧬"
If correct_concept or creative_approach:
- Validate their approach
- Show polished implementation
- Demo with example parents
If needs_guidance:
- Explain single-point crossover
- Example: "GEN|XXXX" + "XXX|ETIC" → "GENETIC"
- Provide complete code in their language
buckets: [excellent_implementation, correct_concept, creative_approach, needs_guidance, set_language, off_topic]
transitions:
excellent_implementation:
ai_feedback:
tokens_for_ai: "Perfect! Show their crossover creating offspring. Example: 'GENXXXX' + 'XXXETIC' → 'GENETIC'. This is evolution magic! ✨"
metadata_add:
crossover_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:mutation"
correct_concept:
ai_feedback:
tokens_for_ai: "Great concept! Show refined code. Demo with concrete parent strings. Emphasize: this exploits existing good genes! 🧬"
metadata_add:
crossover_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:mutation"
creative_approach:
ai_feedback:
tokens_for_ai: "Interesting approach! Validate if it mixes parent traits. Compare to standard single-point crossover."
metadata_add:
crossover_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:mutation"
needs_guidance:
ai_feedback:
tokens_for_ai: "Let me show you! Explain single-point crossover with diagram. Provide complete working code in their language."
metadata_add:
crossover_complete: "true"
progress_score: "n+1"
next_section_and_step: "implementation:mutation"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implementation:crossover"
off_topic:
content_blocks:
- "Let's focus on crossover! 🧬"
- ""
- "**Goal**: Combine two parent strings to create offspring"
- ""
- "Think about: How do you mix traits from both parents into a child?"
- "One approach: Take first half from parent1, second half from parent2"
counts_as_attempt: false
next_section_and_step: "implementation:crossover"
- step_id: "mutation"
title: "Step 4: Mutation (Random Changes)"
question: "Write a mutation function that randomly changes some characters in a string with small probability (like 1% per character). How will you add this random diversity?"
tokens_for_ai: |
Evaluate their mutation implementation.
'excellent_implementation' if they:
- Show code that randomly modifies characters
- Use low probability (1-10%)
- Replace with random letters
'correct_concept' if they describe mutation correctly even with imperfect code
'creative_approach' if they use an alternative randomization strategy
'needs_guidance' if confused or mutates too much/little
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If excellent_implementation:
- Praise! Show mutation in action
- Example: "GENETIC" → "GENXTIC" (small random change)
- Explain: "Prevents getting stuck! Explores new possibilities! 🌈"
If correct_concept or creative_approach:
- Validate their understanding
- Show clean implementation with proper probability
- Demo: mutate 'GENETIC' a few times
If needs_guidance:
- Explain: loop through characters, 1% chance each mutates to random letter
- Show complete code in their language
- Warn: too much mutation = random search, too little = stuck
buckets: [excellent_implementation, correct_concept, creative_approach, needs_guidance, set_language, off_topic]
transitions:
excellent_implementation:
ai_feedback:
tokens_for_ai: "Excellent! Demo their mutation. Explain: this is the spark of innovation in evolution! Small random changes = big discoveries. 🌈"
metadata_add:
mutation_complete: "true"
progress_score: "n+1"
next_section_and_step: "execution:main_loop"
correct_concept:
ai_feedback:
tokens_for_ai: "Great understanding! Show polished code with ~1% mutation rate. Demo mutating 'GENETIC' several times."
metadata_add:
mutation_complete: "true"
progress_score: "n+1"
next_section_and_step: "execution:main_loop"
creative_approach:
ai_feedback:
tokens_for_ai: "Creative! Validate their mutation strategy. Compare mutation rate to standard 1-5% per gene."
metadata_add:
mutation_complete: "true"
progress_score: "n+1"
next_section_and_step: "execution:main_loop"
needs_guidance:
ai_feedback:
tokens_for_ai: "Let me guide you! Explain: for each character, 1% chance to replace with random letter A-Z. Provide complete code in their language."
metadata_add:
mutation_complete: "true"
progress_score: "n+1"
next_section_and_step: "execution:main_loop"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "implementation:mutation"
off_topic:
content_blocks:
- "Let's focus on mutation! 🧬"
- ""
- "**Goal**: Randomly change some characters to add diversity"
- ""
- "Think about: For each character, maybe 1% chance to randomly change it to a different letter"
- "Why? Prevents getting stuck in local optima!"
counts_as_attempt: false
next_section_and_step: "implementation:mutation"
- section_id: "execution"
title: "Run the Evolution!"
steps:
- step_id: "main_loop"
title: "Step 5: The Evolution Loop"
question: "Now write the main GA loop that ties everything together: (1) Create random population, (2) For each generation: evaluate fitness, select parents, crossover, mutate, (3) Repeat for 100 generations, (4) Print the best solution. Show me your implementation!"
tokens_for_ai: |
Evaluate their main GA loop implementation.
'complete_implementation' if they:
- Initialize random population
- Have generation loop
- Call fitness, selection, crossover, mutation
- Track/print best solution
'correct_structure' if they describe the algorithm correctly even with incomplete code
'partial_implementation' if missing some components but core loop is there
'needs_guidance' if confused or very incomplete
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If complete_implementation:
- CELEBRATE! They built a complete GA! 🎉
- Show example output:
"Gen 1: Best='XQMZPRL' (fitness=0)
Gen 50: Best='GENXTIX' (fitness=5)
Gen 100: Best='GENETIC' (fitness=7) ✨"
- Explain: "You just implemented evolution in code!"
If correct_structure or partial_implementation:
- Praise their understanding
- Show complete polished version
- Explain the flow: random → loop(fitness, select, breed, mutate) → evolved!
If needs_guidance:
- Provide complete working GA code in their language
- Walk through: "This is the ENTIRE algorithm in ~50 lines!"
- Show sample output across generations
buckets: [complete_implementation, correct_structure, partial_implementation, needs_guidance, set_language, off_topic]
transitions:
complete_implementation:
ai_feedback:
tokens_for_ai: "AMAZING! 🎉 They built a complete genetic algorithm! Show example output with fitness improving over generations. Celebrate: 'You implemented EVOLUTION!' 🧬✨"
metadata_add:
ga_complete: "true"
progress_score: "n+1"
implementation_quality: "complete"
next_section_and_step: "execution:observe_evolution"
correct_structure:
ai_feedback:
tokens_for_ai: "Great structure! Show complete polished version with all components. Explain: this is the heart of evolutionary computation! 💚"
metadata_add:
ga_complete: "true"
progress_score: "n+1"
implementation_quality: "good"
next_section_and_step: "execution:observe_evolution"
partial_implementation:
ai_feedback:
tokens_for_ai: "Good start! Fill in missing pieces. Show complete working version. Emphasize: all the parts work together like an ecosystem! 🌱"
metadata_add:
ga_complete: "true"
progress_score: "n+1"
implementation_quality: "partial"
next_section_and_step: "execution:observe_evolution"
needs_guidance:
ai_feedback:
tokens_for_ai: "Let me show the complete algorithm! Provide full working GA code in their language (~50 lines). Walk through the flow. Show example output."
metadata_add:
ga_complete: "true"
progress_score: "n+1"
implementation_quality: "guided"
next_section_and_step: "execution:observe_evolution"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "execution:main_loop"
off_topic:
content_blocks:
- "Let's focus on the main evolution loop! 🔄"
- ""
- "You need to:"
- "1. Create random population"
- "2. Loop for 100 generations:"
- " - Calculate fitness for all"
- " - Select best individuals"
- " - Create offspring via crossover"
- " - Mutate offspring"
- " - Replace old population"
- "3. Print the best solution found"
counts_as_attempt: false
next_section_and_step: "execution:main_loop"
- step_id: "observe_evolution"
title: "Observe Evolution in Action"
content_blocks:
- "# 🔬 Watch Evolution Happen! 🔬"
- ""
- "If you ran your genetic algorithm, you'd see something AMAZING:"
- ""
- "```"
- "Generation 1: Best='XQMZPRL' Fitness=0 😕"
- "Generation 10: Best='GXXXXXX' Fitness=1 🌱"
- "Generation 25: Best='GENXXXX' Fitness=3 🌿"
- "Generation 50: Best='GENXTIX' Fitness=5 🌳"
- "Generation 75: Best='GENETIX' Fitness=6 🌲"
- "Generation 100: Best='GENETIC' Fitness=7 ✨🎉"
- "```"
- ""
- "**What just happened?**"
- "- Started with pure randomness"
- "- Each generation got BETTER"
- "- Good genes survived and spread"
- "- Mutations found missing letters"
- "- **EVOLUTION WORKED!** 🧬"
- ""
- "**The Math**:"
- "- Brute force: 26^7 = 8,031,810,176 tries"
- "- GA: 100 generations × 100 population = 10,000 tries"
- "- **803,181x faster!** ⚡⚡⚡"
- ""
- "This is the power of evolutionary algorithms! 💪"
- step_id: "when_to_use"
title: "When to Use Genetic Algorithms"
question: "Based on what you learned, when would you use a genetic algorithm versus other optimization methods? Think about problem characteristics that make GAs shine! 🤔"
tokens_for_ai: |
Evaluate their understanding of when GAs are appropriate.
'excellent_insight' if they mention 2+ of:
- Large search spaces (can't brute force)
- No clear gradient/derivative (can't use gradient descent)
- Multiple local optima (need exploration)
- Complex fitness landscapes
- Combinatorial optimization
- Don't need perfect solution, just good enough
'good_understanding' if they mention 1 key insight about search space or optimization landscape
'partial_understanding' if they understand GAs are for hard problems but vague on details
'needs_clarification' if confused or missing the key concepts
'set_language' if changing language
'off_topic' otherwise
feedback_tokens_for_ai: |
Provide feedback in their language (metadata.programming_language).
If excellent_insight:
- CELEBRATE their deep understanding! 🎉
- Mention real applications: scheduling, circuit design, game AI, neural architecture search
- Note: GAs are part of evolutionary computation family
If good_understanding or partial_understanding:
- Validate what they got right
- Add missing pieces:
* HUGE search spaces (can't enumerate)
* Non-differentiable (can't gradient descent)
* Multiple peaks (need exploration)
- Give examples: TSP, job scheduling, game balancing
If needs_clarification:
- Explain: GAs excel when:
* Search space is enormous
* No gradient available
* Many local optima to escape
- Examples: routing problems, game AI, design optimization
buckets: [excellent_insight, good_understanding, partial_understanding, needs_clarification, set_language, off_topic]
transitions:
excellent_insight:
ai_feedback:
tokens_for_ai: "Outstanding! 🌟 List real applications: job scheduling, circuit design, game AI, neural architecture search, traveling salesman. They've mastered when to use GAs!"
metadata_add:
activity_completed: "true"
mastery_level: "excellent"
next_section_and_step: "conclusion:celebrate"
good_understanding:
ai_feedback:
tokens_for_ai: "Great insight! Add: GAs shine on huge search spaces, non-differentiable problems, multiple local optima. Give examples: TSP, scheduling, game AI."
metadata_add:
activity_completed: "true"
mastery_level: "good"
next_section_and_step: "conclusion:celebrate"
partial_understanding:
ai_feedback:
tokens_for_ai: "You're on the right track! Explain: GAs work when search space is huge, no gradient, many peaks. Examples: routing, scheduling, design optimization."
metadata_add:
activity_completed: "true"
mastery_level: "developing"
next_section_and_step: "conclusion:celebrate"
needs_clarification:
content_blocks:
- "Let me clarify when GAs are perfect! 🎯"
- ""
- "**Use Genetic Algorithms When:**"
- ""
- "✅ **Huge search space** (billions of possibilities)"
- "✅ **No gradient** (can't use calculus-based optimization)"
- "✅ **Many local optima** (need to explore, not just climb)"
- "✅ **Combinatorial** (scheduling, routing, packing)"
- "✅ **Good enough is enough** (don't need perfect solution)"
- ""
- "**Examples:**"
- "- Traveling Salesman Problem 🗺️"
- "- Job scheduling 📅"
- "- Game AI balancing ⚔️"
- "- Circuit design 🔌"
- "- Neural architecture search 🧠"
- ""
- "GAs explore intelligently without needing derivatives or exhaustive search!"
metadata_add:
activity_completed: "true"
mastery_level: "developing"
next_section_and_step: "conclusion:celebrate"
set_language:
content_blocks:
- "Language preference updated! 🌍"
metadata_add:
language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "execution:when_to_use"
off_topic:
content_blocks:
- "Let's think about when GAs are the right tool! 🔧"
- ""
- "Consider: What types of problems would benefit from evolutionary search?"
- ""
- "Hints:"
- "- How big is the search space?"
- "- Can you calculate gradients?"
- "- Are there many local optima?"
counts_as_attempt: false
next_section_and_step: "execution:when_to_use"
- section_id: "conclusion"
title: "Conclusion"
steps:
- step_id: "celebrate"
title: "Congratulations!"
content_blocks:
- "# 🎉 Congratulations, Evolution Architect! 🎉"
- ""
- "You just mastered genetic algorithms! Here's what you built:"
- ""
- "✅ **Fitness Function** - Measured solution quality"
- "✅ **Selection** - Survival of the fittest"
- "✅ **Crossover** - Breeding the best traits"
- "✅ **Mutation** - Exploring new possibilities"
- "✅ **Evolution Loop** - Bringing it all together"
- ""
- "**You learned:**"
- "- How nature solves complex optimization problems"
- "- Why evolution is an incredible search algorithm"
- "- When to use GAs vs other optimization methods"
- "- The exploration-exploitation tradeoff"
- ""
- "**Next Steps:**"
- "- Try more complex problems (TSP, knapsack, game AI)"
- "- Experiment with different selection/crossover strategies"
- "- Learn about: Genetic Programming, Evolution Strategies, Neuroevolution"
- "- Apply GAs to real optimization problems in your domain"
- ""
- "**Remember**: Evolution isn't just biology - it's a powerful computational paradigm! 🧬⚡"
- ""
- "Keep evolving your code! 🚀"
- ""
- "— Your Evolution Guide 🦎✨"

View file

@ -0,0 +1,964 @@
default_max_attempts_per_step: 3
classifier_model: "MODEL_1"
feedback_model: "MODEL_1"
tokens_for_ai_rubric: |
Evaluate the student's code and understanding based on:
- Does their code implement the required functionality?
- Is their logic sound, even if syntax has minor issues?
- Do they demonstrate understanding of the underlying concepts?
- For conceptual questions, do they explain the key ideas correctly?
Be encouraging! They're building a real game from scratch.
Always reference their chosen programming language from metadata.programming_language.
sections:
- section_id: "introduction"
title: "Welcome to Connect Four!"
steps:
- step_id: "welcome"
title: "Introduction"
content_blocks:
- "# 🎮 Build Your Own Connect Four Game!"
- ""
- "Connect Four is a classic two-player strategy game where players take turns dropping colored discs into a 7-column, 6-row grid."
- ""
- "**The Goal:** Connect four of your discs in a row - horizontally, vertically, or diagonally - before your opponent does!"
- ""
- "**What You'll Learn:**"
- "- 2D arrays and nested data structures"
- "- Game state management"
- "- Input validation"
- "- Algorithm design (win detection is surprisingly interesting!)"
- "- Modular code with functions"
- ""
- "By the end, you'll have a working Connect Four game you can play!"
- section_id: "language_choice"
title: "Choose Your Programming Language"
steps:
- step_id: "choose_language"
title: "Language Selection"
question: "What programming language would you like to use? (Python, JavaScript, Java, C++, C, Ruby, Go, or any other language you prefer)"
tokens_for_ai: |
The student is selecting their programming language.
Store whatever language they choose in metadata.programming_language.
Categorize as 'language_selected' if they provide any programming language name.
Categorize as 'unclear' if their response is ambiguous or doesn't mention a language.
buckets: [language_selected, unclear]
transitions:
language_selected:
content_blocks:
- "Excellent choice! All code examples and feedback will be tailored to your language."
metadata_add:
programming_language: "the-users-response"
next_section_and_step: "board_representation:explain_board"
unclear:
content_blocks:
- "I didn't catch which language you'd like to use."
- "Please specify a programming language like Python, JavaScript, Java, C++, etc."
next_section_and_step: "language_choice:choose_language"
- section_id: "board_representation"
title: "Step 1: Representing the Board"
steps:
- step_id: "explain_board"
title: "Board Data Structure"
content_blocks:
- "# 📊 Step 1: How Do We Represent the Board?"
- ""
- "Connect Four uses a 7-column by 6-row grid. We need a data structure to store:"
- "- Empty spaces"
- "- Player 1's pieces (let's use 'X')"
- "- Player 2's pieces (let's use 'O')"
- ""
- "**The Key Concept: 2D Arrays**"
- ""
- "A 2D array (or nested list) is like a grid - it has rows and columns. Think of it as a list of lists:"
- "- The outer list contains rows"
- "- Each inner list contains the columns for that row"
- ""
- "For Connect Four, we typically use 6 rows (index 0-5) and 7 columns (index 0-6)."
- ""
- "**Convention:** We'll index from top (row 0) to bottom (row 5), left (column 0) to right (column 6)."
- step_id: "implement_board"
title: "Create the Board"
question: "Write code to create an empty Connect Four board (6 rows, 7 columns). Use a 2D array/list and fill it with empty spaces or a placeholder like '.' or ' '."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
The student should create a 2D array/list representing a 6x7 board.
Categorize as 'excellent' if they:
- Create a 6x7 2D structure (rows x columns)
- Initialize all positions with empty markers
- Use appropriate syntax for their language
Categorize as 'correct' if they:
- Create the right dimensions
- Minor syntax issues but concept is clear
Categorize as 'wrong_dimensions' if they:
- Mix up rows/columns (7x6 instead of 6x7)
- But otherwise have the right idea
Categorize as 'needs_guidance' if they:
- Don't understand 2D arrays
- Need help with the concept
Categorize as 'set_language' if they want to switch languages.
feedback_tokens_for_ai: |
Provide feedback based on their code in metadata.programming_language.
If excellent/correct:
- Praise their implementation
- Show them their code could be used to initialize: board = create_empty_board()
- Mention this is the foundation for everything else
If wrong_dimensions:
- Gently correct: "Close! Remember, 6 ROWS (height) by 7 COLUMNS (width)"
- Explain the difference between board[row][col] indexing
If needs_guidance:
- Show a SMALL example of a 2x3 board (not the full solution!)
- Explain nested lists/arrays conceptually
- Encourage them to try again
buckets: [excellent, correct, wrong_dimensions, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
board_created: "true"
progress_score: "1"
next_section_and_step: "display_board:explain_display"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
board_created: "true"
progress_score: "1"
next_section_and_step: "display_board:explain_display"
wrong_dimensions:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "board_representation:implement_board"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "board_representation:implement_board"
set_language:
content_blocks:
- "Language preference updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "board_representation:implement_board"
- section_id: "display_board"
title: "Step 2: Displaying the Board"
steps:
- step_id: "explain_display"
title: "Print the Board"
content_blocks:
- "# 🖨️ Step 2: Displaying the Board"
- ""
- "Great! You've created the data structure. Now we need to visualize it."
- ""
- "**The Challenge:** Turn your 2D array into a readable game board on screen."
- ""
- "**Concept: Nested Loops**"
- "- Outer loop: iterate through each row"
- "- Inner loop: iterate through each column in that row"
- "- Print each cell, then move to the next line after each row"
- ""
- "**Bonus Points:** Add column numbers (0-6) at the top or bottom to help players choose where to drop!"
- step_id: "implement_display"
title: "Write Display Function"
question: "Write a function called display_board (or similar) that takes your board as a parameter and prints it in a readable format. Show each row and make it clear which positions are empty."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
The student should write a function that displays the board.
Categorize as 'excellent' if they:
- Use nested loops correctly
- Print all rows and columns
- Make it readable (spacing, separators, column labels)
- Proper function syntax
Categorize as 'correct' if they:
- Core logic is right (nested loops)
- Displays the board even if formatting is basic
- Function structure is correct
Categorize as 'partial' if they:
- Have the concept but loops are wrong
- Or miss the function wrapper but logic exists
Categorize as 'needs_help' if they're stuck on nested loops.
Categorize as 'set_language' if switching languages.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent/correct:
- Celebrate: "Your board looks great! 🎨"
- Suggest enhancements like separators between cells: | or borders
- Note this function will be called after every move
If partial:
- Identify what's working
- Guide them on the nested loop structure
- Explain outer loop = rows, inner loop = columns
If needs_help:
- Explain nested loop concept clearly
- Give pseudocode (not full code):
for each row in board:
for each cell in row:
print cell
print newline
- Encourage them to try
buckets: [excellent, correct, partial, needs_help, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
display_implemented: "true"
progress_score: "n+1"
next_section_and_step: "drop_piece:explain_drop"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
display_implemented: "true"
progress_score: "n+1"
next_section_and_step: "drop_piece:explain_drop"
partial:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "display_board:implement_display"
needs_help:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "display_board:implement_display"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "display_board:implement_display"
- section_id: "drop_piece"
title: "Step 3: Dropping a Piece"
steps:
- step_id: "explain_drop"
title: "Understanding Gravity"
content_blocks:
- "# 🪂 Step 3: Dropping a Piece (Gravity!)"
- ""
- "Now for the fun part: actually playing the game!"
- ""
- "**The Physics:** When you drop a piece in a column, it falls to the lowest empty space in that column."
- ""
- "**Algorithm Challenge:**"
- "1. Given a column number (0-6)"
- "2. Start from the BOTTOM row (row 5)"
- "3. Move UP until you find an empty space"
- "4. Place the piece there"
- ""
- "**Think about it:** If column 3 has pieces in rows 5, 4, and 3 (bottom three rows), the next piece drops into row 2."
- ""
- "**Tip:** You can iterate from the bottom up, or from top down and find the first empty, then check the one below is occupied."
- step_id: "implement_drop"
title: "Write Drop Function"
question: "Write a function drop_piece(board, column, player) that drops a player's piece (e.g., 'X' or 'O') into the specified column. It should find the lowest empty row in that column and place the piece there. Return True if successful, False if the column is full."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
The student should implement the drop logic with gravity.
Categorize as 'excellent' if they:
- Iterate through rows correctly (bottom-up or top-down)
- Find the lowest empty space
- Place the piece
- Return True/False or similar success indicator
- Handle full column edge case
Categorize as 'correct' if they:
- Core gravity logic works
- Minor issues with iteration direction
- Concept is clearly understood
Categorize as 'wrong_direction' if they:
- Place pieces at the top instead of letting them fall
- But understand they need to find an empty space
Categorize as 'needs_guidance' if they're struggling with the algorithm.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent/correct:
- Celebrate: "Perfect! Gravity works! 🌍"
- Explain how this function will be called each turn
- Mention: "This is the core game mechanic working!"
- Suggest they could add error checking (invalid column numbers)
If wrong_direction:
- Point out pieces should FALL to the bottom
- Suggest: "Start checking from row 5 (bottom) and move up"
- Or: "Check from row 0 (top) down, but place in the LAST empty row"
If needs_guidance:
- Walk through an example: "Column 2 is empty. Where does the first piece go? Row 5 (bottom)."
- "Second piece? Row 4. Third piece? Row 3."
- Give pseudocode for the loop structure
buckets: [excellent, correct, wrong_direction, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
drop_implemented: "true"
progress_score: "n+1"
next_section_and_step: "validate_moves:explain_validation"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
drop_implemented: "true"
progress_score: "n+1"
next_section_and_step: "validate_moves:explain_validation"
wrong_direction:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "drop_piece:implement_drop"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "drop_piece:implement_drop"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "drop_piece:implement_drop"
- section_id: "validate_moves"
title: "Step 4: Validating Moves"
steps:
- step_id: "explain_validation"
title: "Input Validation"
content_blocks:
- "# ✅ Step 4: Validating Moves"
- ""
- "Before dropping a piece, we need to check if the move is legal!"
- ""
- "**Invalid Moves:**"
- "1. Column number is out of range (< 0 or > 6)"
- "2. Column is already full (all 6 rows occupied)"
- ""
- "**Why This Matters:** Without validation, your game will crash or behave unexpectedly when players make mistakes."
- ""
- "**Good User Experience:** Tell players WHY their move was invalid and let them try again."
- step_id: "implement_validation"
title: "Write Validation Function"
question: "Write a function is_valid_move(board, column) that returns True if the move is valid (column is in range 0-6 and not full), False otherwise. Bonus: Write a function get_player_move() that keeps asking until the player enters a valid column."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
Categorize as 'excellent' if they:
- Check column range (0-6)
- Check if column has any empty space
- Return boolean correctly
- Bonus: Implement get_player_move with retry loop
Categorize as 'correct' if they:
- Have validation logic for both conditions
- Function structure is correct
- Minor syntax issues okay
Categorize as 'partial' if they:
- Only check one condition (range OR fullness)
- Concept understood but incomplete
Categorize as 'needs_help' if struggling with the logic.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent:
- Celebrate: "Excellent validation! Your game is robust! 💪"
- If they did the bonus: "Love the input loop - great UX!"
- Point out how this prevents crashes and improves player experience
If correct:
- Praise: "Great! Your validation works!"
- If they didn't do the bonus, mention it would be a nice addition
If partial:
- Identify what they got right
- Explain what's missing (range check or fullness check)
- Encourage them to add the missing piece
If needs_help:
- Break it down: "Two checks needed:"
- "1. Is 0 <= column <= 6?"
- "2. Is the top row (row 0) of that column empty?"
- Provide pseudocode structure
buckets: [excellent, correct, partial, needs_help, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
validation_implemented: "true"
progress_score: "n+1"
next_section_and_step: "horizontal_win:explain_horizontal"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
validation_implemented: "true"
progress_score: "n+1"
next_section_and_step: "horizontal_win:explain_horizontal"
partial:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "validate_moves:implement_validation"
needs_help:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "validate_moves:implement_validation"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "validate_moves:implement_validation"
- section_id: "horizontal_win"
title: "Step 5: Checking Horizontal Wins"
steps:
- step_id: "explain_horizontal"
title: "Win Detection - Horizontal"
content_blocks:
- "# 🏆 Step 5: Detecting Horizontal Wins"
- ""
- "Now for the game logic - determining when someone wins!"
- ""
- "**Horizontal Win:** 4 identical pieces in a row (same row, consecutive columns)"
- ""
- "**Algorithm Strategy:**"
- "1. For each row (0-5)"
- "2. For each starting column (0-3) - why only 0-3? Because you need 4 consecutive!"
- "3. Check if board[row][col], board[row][col+1], board[row][col+2], board[row][col+3] are all the same player"
- ""
- "**Key Insight:** You only need to check columns 0-3 as starting positions. If you start at column 4, you can't fit 4 pieces!"
- step_id: "implement_horizontal"
title: "Write Horizontal Check"
question: "Write a function check_horizontal_win(board, player) that returns True if the specified player has 4 in a row horizontally, False otherwise. Iterate through all rows and check consecutive columns."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
Categorize as 'excellent' if they:
- Iterate rows (0-5) correctly
- Iterate columns (0-3) as starting positions
- Check 4 consecutive positions
- Compare against player symbol
- Return True when found, False at end
Categorize as 'correct' if they:
- Logic is sound
- Might iterate all columns but still works
- Core concept demonstrated
Categorize as 'wrong_bounds' if they:
- Iterate columns 0-6 (causing index errors)
- But understand the consecutive checking concept
Categorize as 'needs_guidance' if struggling with the nested loops or logic.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent:
- Celebrate: "Perfect! Horizontal wins are detected! 🎉"
- Mention: "Your optimization (only checking columns 0-3) is smart!"
- Hint at what's next: "Vertical and diagonal will use similar patterns"
If correct:
- Praise: "Great logic!"
- If they checked all columns unnecessarily, gently suggest the optimization
- Still move them forward
If wrong_bounds:
- Point out the index error: "Checking column 6 means accessing [row][6+3] which doesn't exist!"
- Explain: "If you start at column 4, you check positions 4,5,6,7 - but column 7 doesn't exist"
- Suggest: "Only iterate columns 0-3"
If needs_guidance:
- Walk through a concrete example
- "Row 2, starting at column 1: check [2][1], [2][2], [2][3], [2][4]"
- Provide pseudocode structure
buckets: [excellent, correct, wrong_bounds, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
horizontal_implemented: "true"
progress_score: "n+1"
next_section_and_step: "vertical_win:explain_vertical"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
horizontal_implemented: "true"
progress_score: "n+1"
next_section_and_step: "vertical_win:explain_vertical"
wrong_bounds:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "horizontal_win:implement_horizontal"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "horizontal_win:implement_horizontal"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "horizontal_win:implement_horizontal"
- section_id: "vertical_win"
title: "Step 6: Checking Vertical Wins"
steps:
- step_id: "explain_vertical"
title: "Win Detection - Vertical"
content_blocks:
- "# 📏 Step 6: Detecting Vertical Wins"
- ""
- "Similar to horizontal, but now we're checking columns instead of rows!"
- ""
- "**Vertical Win:** 4 identical pieces stacked vertically (same column, consecutive rows)"
- ""
- "**Algorithm Strategy:**"
- "1. For each column (0-6)"
- "2. For each starting row (0-2) - why only 0-2? Same reason as before!"
- "3. Check if board[row][col], board[row+1][col], board[row+2][col], board[row+3][col] are all the same player"
- ""
- "**Pattern Recognition:** Notice how this mirrors the horizontal check, just with rows and columns swapped?"
- step_id: "implement_vertical"
title: "Write Vertical Check"
question: "Write a function check_vertical_win(board, player) that returns True if the specified player has 4 in a row vertically. Use the same logic as horizontal, but swap rows and columns."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
Categorize as 'excellent' if they:
- Iterate columns (0-6) correctly
- Iterate rows (0-2) as starting positions
- Check 4 consecutive rows in same column
- Compare against player symbol
- Return boolean correctly
Categorize as 'correct' if they:
- Logic works
- Might iterate all rows but function still works
- Understand the pattern
Categorize as 'wrong_bounds' if they:
- Iterate rows 0-5 (causing index errors on row+3)
- But the checking logic is right
Categorize as 'needs_guidance' if struggling.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent:
- Celebrate: "Vertical wins detected! 📏 You're seeing the patterns!"
- Mention: "Notice how similar this is to horizontal? Same algorithm, different direction!"
- Build anticipation: "Diagonal is the trickiest one next!"
If correct:
- Praise: "Great work!"
- If they checked all rows, gently suggest the optimization
- Acknowledge they're building momentum
If wrong_bounds:
- Explain the index issue with row+3 exceeding bounds
- Suggest: "Only start from rows 0-2"
If needs_guidance:
- Remind them of horizontal logic
- "It's the same pattern, just checking board[row+i][col] instead of board[row][col+i]"
- Provide structure
buckets: [excellent, correct, wrong_bounds, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
vertical_implemented: "true"
progress_score: "n+1"
next_section_and_step: "diagonal_win:explain_diagonal"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
vertical_implemented: "true"
progress_score: "n+1"
next_section_and_step: "diagonal_win:explain_diagonal"
wrong_bounds:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "vertical_win:implement_vertical"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "vertical_win:implement_vertical"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "vertical_win:implement_vertical"
- section_id: "diagonal_win"
title: "Step 7: Checking Diagonal Wins"
steps:
- step_id: "explain_diagonal"
title: "Win Detection - Diagonals"
content_blocks:
- "# ↗️ Step 7: Detecting Diagonal Wins (The Tricky One!)"
- ""
- "Diagonals are the most challenging because there are TWO directions to check!"
- ""
- "**Two Types of Diagonals:**"
- "1. **Down-Right (↘️):** row increases, column increases (row+1, col+1)"
- "2. **Up-Right (↗️):** row decreases, column increases (row-1, col+1)"
- ""
- "**Down-Right Diagonal:**"
- "- Starting row range: 0-2 (need room to go down 3 rows)"
- "- Starting column range: 0-3 (need room to go right 3 columns)"
- "- Check: [row][col], [row+1][col+1], [row+2][col+2], [row+3][col+3]"
- ""
- "**Up-Right Diagonal:**"
- "- Starting row range: 3-5 (need room to go up 3 rows)"
- "- Starting column range: 0-3 (need room to go right 3 columns)"
- "- Check: [row][col], [row-1][col+1], [row-2][col+2], [row-3][col+3]"
- step_id: "implement_diagonal"
title: "Write Diagonal Check"
question: "Write a function check_diagonal_win(board, player) that returns True if the player has 4 in a row diagonally (either direction). You need to check both down-right (↘️) and up-right (↗️) diagonals."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
This is the hardest check! Be generous with partial credit.
Categorize as 'excellent' if they:
- Check BOTH diagonal directions
- Correct row/column bounds for each direction
- Proper indexing (row±i, col+i)
- Return True when found
Categorize as 'correct' if they:
- Have both directions
- Logic is mostly right
- Minor boundary or indexing issues but concept clear
Categorize as 'one_direction' if they:
- Only implement one diagonal direction
- But that direction is implemented correctly
Categorize as 'needs_guidance' if they're struggling with the concept.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent:
- Celebrate enthusiastically: "🎉 You conquered diagonals! This is the hardest part!"
- Praise: "Both directions working correctly - impressive!"
- Mention: "Win detection is now COMPLETE! Your game knows when someone wins!"
If correct:
- Praise: "Great work on the tricky diagonal logic!"
- If minor issues, point them out gently
- Still acknowledge this is hard and they did well
If one_direction:
- Praise what they did: "Excellent work on [direction] diagonals!"
- Explain: "Connect Four needs both directions: ↘️ and ↗️"
- Guide them on the second direction's bounds and indexing
If needs_guidance:
- Break down one diagonal type completely
- "Down-right example: start at [0][0], check [0][0], [1][1], [2][2], [3][3]"
- "Start at [1][2], check [1][2], [2][3], [3][4], [4][5]"
- Provide pseudocode structure
buckets: [excellent, correct, one_direction, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
diagonal_implemented: "true"
progress_score: "n+1"
next_section_and_step: "game_loop:explain_loop"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
diagonal_implemented: "true"
progress_score: "n+1"
next_section_and_step: "game_loop:explain_loop"
one_direction:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "diagonal_win:implement_diagonal"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "diagonal_win:implement_diagonal"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "diagonal_win:implement_diagonal"
- section_id: "game_loop"
title: "Step 8: Building the Game Loop"
steps:
- step_id: "explain_loop"
title: "Putting It All Together"
content_blocks:
- "# 🔄 Step 8: The Game Loop"
- ""
- "You have ALL the pieces! Now let's assemble them into a playable game."
- ""
- "**Game Loop Structure:**"
- "1. Initialize the board"
- "2. Set current player (start with Player 1)"
- "3. **Loop until game ends:**"
- " - Display the board"
- " - Get current player's move (with validation)"
- " - Drop the piece"
- " - Check if current player won (all 3 directions)"
- " - Check if board is full (tie)"
- " - Switch to other player"
- "4. Display final board and announce winner"
- ""
- "**Key Concepts:**"
- "- **Game state:** The board changes each turn"
- "- **Turn alternation:** Switch between players"
- "- **Exit condition:** Win or tie breaks the loop"
- step_id: "implement_loop"
title: "Write Game Loop"
question: "Write the main game loop that brings everything together. Initialize the board, alternate between two players, validate moves, drop pieces, check for wins, and announce the winner. You can write this as a play_game() function or as main program logic."
tokens_for_ai: |
Get the programming language from metadata.programming_language.
They're writing the FULL game now! Be encouraging.
Categorize as 'excellent' if they:
- Initialize board
- Have a game loop (while/for loop until game ends)
- Alternate between players
- Call display, input, validation, drop, and win check functions
- Handle both win and tie conditions
- Announce results
Categorize as 'correct' if they:
- Have the main structure
- Loop with turn alternation
- Call their functions appropriately
- Minor logic issues okay if concept is clear
Categorize as 'partial' if they:
- Have some of the structure
- Missing key parts (like win checking or player switching)
- On the right track but incomplete
Categorize as 'needs_guidance' if they're struggling to put it together.
Categorize as 'set_language' for language changes.
feedback_tokens_for_ai: |
Provide feedback in metadata.programming_language.
If excellent:
- CELEBRATE BIG: "🎉🎮 YOU DID IT! You built a complete Connect Four game!"
- List what they've accomplished:
* Board representation with 2D arrays
* Display with nested loops
* Gravity simulation for dropping pieces
* Input validation
* Win detection in 3 directions
* Full game loop with turn management
- Suggest enhancements: AI opponent, GUI, undo moves, score tracking
- Congratulate them on completing a non-trivial project!
If correct:
- Celebrate: "Your game works! Excellent job! 🎉"
- Point out any minor improvements
- Still emphasize they built something real and playable
If partial:
- Praise what's working
- Identify what's missing
- Guide them: "You have X and Y working. Now add Z to complete the loop."
- Encourage: "You're so close!"
If needs_guidance:
- Break down the loop structure
- "Think of it as: setup -> loop (input, validate, drop, check, switch) -> end"
- Provide high-level pseudocode
- Encourage them to try integrating one piece at a time
buckets: [excellent, correct, partial, needs_guidance, set_language]
transitions:
excellent:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
game_complete: "true"
progress_score: "n+1"
next_section_and_step: "conclusion:reflection"
correct:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
game_complete: "true"
progress_score: "n+1"
next_section_and_step: "conclusion:reflection"
partial:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "game_loop:implement_loop"
needs_guidance:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
next_section_and_step: "game_loop:implement_loop"
set_language:
content_blocks:
- "Language updated!"
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "game_loop:implement_loop"
- section_id: "conclusion"
title: "Conclusion & Reflection"
steps:
- step_id: "reflection"
title: "What You've Learned"
question: "Reflect on what you learned. What was the most challenging part? What concepts (2D arrays, loops, algorithms, etc.) do you feel more confident about now? What would you add to your game next?"
tokens_for_ai: |
This is a reflection question. Accept any thoughtful response.
Categorize as 'thoughtful' if they:
- Reflect on specific challenges (likely diagonals!)
- Mention concepts they learned
- Show understanding of what they built
- Maybe mention enhancements
Categorize as 'brief' if they:
- Give a short but genuine response
- Show they completed the project
Categorize as 'off_topic' if they:
- Don't engage with the reflection
- Are completely off-topic
Categorize as 'set_language' for language changes (though activity is ending).
feedback_tokens_for_ai: |
Provide encouraging, celebratory feedback.
For thoughtful responses:
- Acknowledge their specific insights
- Validate that diagonals ARE the hardest part
- Encourage them to implement their enhancement ideas
- Mention how these concepts (2D arrays, nested loops, algorithms) apply to many other programs
- Celebrate their achievement of building a complete game from scratch
For brief responses:
- Thank them for their time
- Celebrate their completion
- Encourage them to keep coding
For off_topic:
- Gently redirect to the question
- Ask them to reflect on the experience
buckets: [thoughtful, brief, off_topic, set_language]
transitions:
thoughtful:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
activity_completed: "true"
next_section_and_step: "conclusion:goodbye"
brief:
ai_feedback:
tokens_for_ai: "See feedback_tokens_for_ai above"
metadata_add:
activity_completed: "true"
next_section_and_step: "conclusion:goodbye"
off_topic:
content_blocks:
- "Let's take a moment to reflect on what you learned building Connect Four."
next_section_and_step: "conclusion:reflection"
set_language:
content_blocks:
- "Language updated! Though we're at the end of the activity."
metadata_add:
programming_language: "the-users-response"
counts_as_attempt: false
next_section_and_step: "conclusion:reflection"
- step_id: "goodbye"
title: "Congratulations!"
content_blocks:
- "# 🎉 Congratulations! You Built Connect Four! 🎮"
- ""
- "You've successfully created a fully functional Connect Four game from scratch!"
- ""
- "**What You Accomplished:**"
- "✅ Mastered 2D arrays and nested data structures"
- "✅ Implemented game physics (gravity!)"
- "✅ Wrote input validation"
- "✅ Designed win-detection algorithms in 3 directions"
- "✅ Built a complete game loop with state management"
- "✅ Created something you can actually play!"
- ""
- "**Next Steps:**"
- "- Add an AI opponent (minimax algorithm?)"
- "- Create a graphical interface (GUI)"
- "- Add animations for falling pieces"
- "- Implement undo/redo"
- "- Add different board sizes"
- ""
- "Keep building! Every complex program is just these same concepts combined in creative ways. 🚀"
- ""
- "Happy coding!"

290
research/activity6.yaml Normal file
View file

@ -0,0 +1,290 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Cybersecurity"
steps:
- step_id: "step_1"
title: "What is Cybersecurity?"
content_blocks:
- "Welcome to the Cybersecurity Awareness Training."
- "Cybersecurity involves protecting computer systems, networks, and data from digital attacks."
tokens_for_ai: "Explain what cybersecurity is and its importance in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you understand by cybersecurity?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of cybersecurity."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of cybersecurity. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on cybersecurity."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of cybersecurity in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of Cybersecurity"
content_blocks:
- "Cybersecurity is crucial to protect sensitive information and maintain privacy."
- "It helps prevent data breaches, identity theft, and other cyber threats."
tokens_for_ai: "Explain the importance of cybersecurity in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is cybersecurity important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of cybersecurity."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of cybersecurity."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of cybersecurity in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Common Cybersecurity Threats"
steps:
- step_id: "step_1"
title: "Phishing Attacks"
content_blocks:
- "Phishing attacks involve tricking individuals into providing sensitive information by pretending to be a trustworthy entity."
- "These attacks often come in the form of emails or messages that appear legitimate."
tokens_for_ai: "Explain what phishing attacks are and how to recognize them in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is a phishing attack and how can you recognize it?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what phishing attacks are and how to recognize them."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of phishing attacks. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on phishing attacks."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of phishing attacks in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Malware"
content_blocks:
- "Malware is malicious software designed to harm or exploit computer systems."
- "Common types of malware include viruses, worms, and ransomware."
tokens_for_ai: "Explain what malware is and the different types in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is malware and what are some common types?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what malware is and the different types."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of malware. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on malware."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of malware in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Best Practices for Cybersecurity"
steps:
- step_id: "step_1"
title: "Strong Passwords"
content_blocks:
- "Using strong passwords is one of the simplest and most effective ways to protect your accounts."
- "A strong password should be at least 12 characters long and include a mix of letters, numbers, and special characters."
tokens_for_ai: "Explain the importance of strong passwords and how to create them in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why are strong passwords important and how can you create one?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the importance of strong passwords and how to create them."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of strong passwords. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on strong passwords."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of strong passwords in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Two-Factor Authentication"
content_blocks:
- "Two-factor authentication (2FA) adds an extra layer of security to your accounts."
- "It requires you to provide two forms of identification before accessing your account."
tokens_for_ai: "Explain what two-factor authentication is and its benefits in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is two-factor authentication and why is it beneficial?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what two-factor authentication is and its benefits."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of two-factor authentication. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on two-factor authentication."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of two-factor authentication in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Recognizing and Responding to Threats"
steps:
- step_id: "step_1"
title: "Recognizing Phishing Emails"
content_blocks:
- "Phishing emails often have telltale signs such as poor grammar, urgent language, and suspicious links."
- "Always verify the sender's email address and avoid clicking on links or downloading attachments from unknown sources."
tokens_for_ai: "Explain how to recognize phishing emails in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How can you recognize a phishing email?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how to recognize phishing emails."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of recognizing phishing emails. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on recognizing phishing emails."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of recognizing phishing emails in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Responding to a Cyber Attack"
content_blocks:
- "If you suspect a cyber attack, disconnect from the internet and report the incident to your IT department or a cybersecurity professional."
- "Do not attempt to fix the issue yourself as it may cause further damage."
tokens_for_ai: "Explain how to respond to a suspected cyber attack in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What should you do if you suspect a cyber attack?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to respond to a suspected cyber attack."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of responding to a cyber attack. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on responding to a cyber attack."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of responding to a cyber attack in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_3"
title: "The End."
content_blocks:
- "The End."

727
research/activity7.yaml Normal file
View file

@ -0,0 +1,727 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Financial Literacy"
steps:
- step_id: "step_1"
title: "What is Financial Literacy?"
content_blocks:
- "Welcome to the Financial Literacy for Teens course."
- "Financial literacy involves understanding how to manage money, including budgeting, saving, investing, and understanding credit."
tokens_for_ai: "Explain what financial literacy is and its importance in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you understand by financial literacy?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of financial literacy."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of financial literacy. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on financial literacy."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of financial literacy in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of Financial Literacy"
content_blocks:
- "Financial literacy is crucial for making informed decisions about money."
- "It helps you manage your finances, avoid debt, and plan for the future."
tokens_for_ai: "Explain the importance of financial literacy in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is financial literacy important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of financial literacy."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of financial literacy."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of financial literacy in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Budgeting"
steps:
- step_id: "step_1"
title: "What is a Budget?"
content_blocks:
- "A budget is a plan for how you will spend and save your money."
- "It helps you track your income and expenses to ensure you are living within your means."
tokens_for_ai: "Explain what a budget is and its purpose in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is a budget and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what a budget is and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of a budget. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on what a budget is."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of what a budget is in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Creating a Budget"
content_blocks:
- "To create a budget, start by listing your income and expenses."
- "Categorize your expenses into needs (e.g., food, rent) and wants (e.g., entertainment, dining out)."
tokens_for_ai: "Explain how to create a budget in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you create a budget?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to create a budget."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of creating a budget. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on creating a budget."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of creating a budget in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Saving Money"
steps:
- step_id: "step_1"
title: "Why Save Money?"
content_blocks:
- "Saving money is important for achieving financial goals and being prepared for unexpected expenses."
- "It helps you build a financial cushion and avoid debt."
tokens_for_ai: "Explain the importance of saving money in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is it important to save money?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the importance of saving money."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of saving money. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of saving money."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of saving money in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "How to Save Money"
content_blocks:
- "To save money, set aside a portion of your income regularly."
- "Consider opening a savings account to keep your money safe and earn interest."
tokens_for_ai: "Explain how to save money in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How can you save money effectively?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to save money effectively."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of saving money. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on how to save money."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of how to save money in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Investing"
steps:
- step_id: "step_1"
title: "What is Investing?"
content_blocks:
- "Investing involves putting your money into assets like stocks, bonds, or real estate to grow your wealth over time."
- "It carries some risk, but it can also offer higher returns than saving alone."
tokens_for_ai: "Explain what investing is and its purpose in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is investing and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what investing is and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of investing. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on what investing is."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of what investing is in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Types of Investments"
content_blocks:
- "Common types of investments include stocks, bonds, mutual funds, and real estate."
- "Each type of investment has its own risk and return profile."
tokens_for_ai: "Explain the different types of investments in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What are some common types of investments?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know the different types of investments."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the types of investments. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the types of investments."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the types of investments in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Understanding Credit"
steps:
- step_id: "step_1"
title: "What is Credit?"
content_blocks:
- "Credit is the ability to borrow money with the promise to repay it later."
- "It allows you to make purchases or access funds that you may not have immediately available."
tokens_for_ai: "Explain what credit is and its purpose in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is credit and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what credit is and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of credit. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on what credit is."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of what credit is in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Credit Scores"
content_blocks:
- "A credit score is a numerical representation of your creditworthiness."
- "It is based on your credit history and helps lenders determine the risk of lending to you."
tokens_for_ai: "Explain what a credit score is and its importance in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is a credit score and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what a credit score is and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of credit scores. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on credit scores."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of credit scores in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "Avoiding Debt"
steps:
- step_id: "step_1"
title: "What is Debt?"
content_blocks:
- "Debt is money that you owe to others, typically as a result of borrowing."
- "It can come from loans, credit cards, or other forms of borrowing."
tokens_for_ai: "Explain what debt is and its implications in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is debt and why is it important to manage it?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what debt is and why it's important to manage it."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of debt. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on what debt is."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of what debt is in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Managing Debt"
content_blocks:
- "To manage debt, make sure to pay your bills on time and avoid taking on more debt than you can handle."
- "Create a plan to pay off existing debt and prioritize high-interest debt first."
tokens_for_ai: "Explain how to manage debt effectively in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How can you manage debt effectively?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to manage debt effectively."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of managing debt. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on managing debt."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of managing debt in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_7"
title: "Planning for the Future"
steps:
- step_id: "step_1"
title: "Setting Financial Goals"
content_blocks:
- "Setting financial goals helps you plan for the future and stay motivated to save and invest."
- "Your goals can be short-term (e.g., saving for a new phone) or long-term (e.g., saving for college)."
tokens_for_ai: "Explain the importance of setting financial goals and how to set them in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is it important to set financial goals and how can you set them?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the importance of setting financial goals and how to set them."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of setting financial goals. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on setting financial goals."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of setting financial goals in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Building an Emergency Fund"
content_blocks:
- "An emergency fund is money set aside to cover unexpected expenses, such as medical bills or car repairs."
- "Aim to save at least three to six months' worth of living expenses in your emergency fund."
tokens_for_ai: "Explain the importance of an emergency fund and how to build one in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is an emergency fund and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what an emergency fund is and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of an emergency fund. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the emergency fund."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the emergency fund in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_8"
title: "Understanding Taxes"
steps:
- step_id: "step_1"
title: "What are Taxes?"
content_blocks:
- "Taxes are mandatory contributions to government revenue, collected from individuals and businesses."
- "They fund public services such as education, healthcare, and infrastructure."
tokens_for_ai: "Explain what taxes are and their purpose in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What are taxes and why are they important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what taxes are and why they're important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of taxes. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on taxes."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of taxes in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Filing Taxes"
content_blocks:
- "Filing taxes involves submitting a tax return to report your income and calculate the taxes you owe."
- "It's important to file your taxes accurately and on time to avoid penalties."
tokens_for_ai: "Explain how to file taxes and the importance of doing so in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you file taxes and why is it important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand how to file taxes and why it's important."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of filing taxes. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on filing taxes."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of filing taxes in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_9"
title: "Smart Spending"
steps:
- step_id: "step_1"
title: "Needs vs. Wants"
content_blocks:
- "Understanding the difference between needs and wants is crucial for smart spending."
- "Needs are essential for living (e.g., food, shelter), while wants are things you desire but can live without (e.g., new gadgets, dining out)."
tokens_for_ai: "Explain the difference between needs and wants in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the difference between needs and wants?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand the difference between needs and wants."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of needs and wants. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on needs and wants."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of needs and wants in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Making Smart Purchases"
content_blocks:
- "To make smart purchases, compare prices, read reviews, and consider the long-term value of the item."
- "Avoid impulse buying and stick to your budget."
tokens_for_ai: "Explain how to make smart purchases in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How can you make smart purchases?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to make smart purchases."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of making smart purchases. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on making smart purchases."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of making smart purchases in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_10"
title: "Protecting Your Finances"
steps:
- step_id: "step_1"
title: "Avoiding Scams"
content_blocks:
- "Scams are fraudulent schemes designed to steal your money or personal information."
- "Be cautious of unsolicited emails, phone calls, or messages asking for your financial information."
tokens_for_ai: "Explain how to recognize and avoid scams in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How can you recognize and avoid scams?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how to recognize and avoid scams."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of avoiding scams. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on avoiding scams."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of avoiding scams in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Identity Theft"
content_blocks:
- "Identity theft occurs when someone steals your personal information to commit fraud."
- "Protect your personal information by using strong passwords and being cautious about sharing your details online."
tokens_for_ai: "Explain what identity theft is and how to protect against it in a friendly and engaging manner suitable for teens. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is identity theft and how can you protect against it?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand what identity theft is and how to protect against it."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of identity theft. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on identity theft."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of identity theft in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_11"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Financial Literacy for Teens course!"
- "You have learned valuable skills and knowledge that will help you manage your finances effectively."
- "Remember, financial literacy is a lifelong journey, and the skills you've gained here will serve you well in the future."
- "Keep practicing what you've learned, stay curious, and continue to build your financial knowledge."
- "We are proud of your dedication and hard work. Well done!"
- step_id: "step_3"
title: "The End."
content_blocks:
- "The End."

372
research/activity8.yaml Normal file
View file

@ -0,0 +1,372 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Cooking"
steps:
- step_id: "step_1"
title: "What is Cooking?"
content_blocks:
- "Welcome to the Basic Cooking Skills course."
- "Cooking is the process of preparing food by combining, mixing, and heating ingredients."
tokens_for_ai: "Explain what cooking is and its importance in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you understand by cooking?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You have a good understanding of cooking."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of cooking. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on cooking."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of cooking in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Importance of Cooking"
content_blocks:
- "Cooking is important because it allows you to control what goes into your food."
- "It helps you make healthier choices and can be a fun and creative activity."
tokens_for_ai: "Explain the importance of cooking in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Why is cooking important?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the importance of cooking."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of the importance. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on the importance of cooking."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of the importance of cooking in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Basic Cooking Techniques"
steps:
- step_id: "step_1"
title: "Chopping and Slicing"
content_blocks:
- "Chopping and slicing are fundamental cooking techniques."
- "Use a sharp knife and a cutting board. Keep your fingers tucked in to avoid cuts."
tokens_for_ai: "Explain how to chop and slice ingredients safely in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you chop and slice ingredients safely?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how to chop and slice ingredients safely."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of chopping and slicing. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on chopping and slicing."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of chopping and slicing in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Boiling and Simmering"
content_blocks:
- "Boiling and simmering are techniques used to cook food in water or broth."
- "Boiling involves cooking at a high temperature, while simmering is done at a lower temperature."
tokens_for_ai: "Explain the difference between boiling and simmering and how to do them in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is the difference between boiling and simmering, and how do you do them?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the difference between boiling and simmering and how to do them."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of boiling and simmering. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on boiling and simmering."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of boiling and simmering in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Simple Recipes"
steps:
- step_id: "step_1"
title: "Scrambled Eggs"
content_blocks:
- "Scrambled eggs are a simple and nutritious breakfast option."
- "Ingredients: 2 eggs, salt, pepper, butter."
- "Instructions: Crack the eggs into a bowl, add a pinch of salt and pepper, and whisk. Melt butter in a pan over medium heat, pour in the eggs, and stir until cooked."
tokens_for_ai: "Explain how to make scrambled eggs in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you make scrambled eggs?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how to make scrambled eggs."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of making scrambled eggs. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on making scrambled eggs."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of making scrambled eggs in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Pasta with Tomato Sauce"
content_blocks:
- "Pasta with tomato sauce is a simple and delicious meal."
- "Ingredients: 200g pasta, 1 can of tomato sauce, garlic, olive oil, salt, pepper, basil."
- "Instructions: Cook the pasta according to the package instructions. In a pan, heat olive oil, add minced garlic, and cook until fragrant. Add tomato sauce, salt, pepper, and basil. Simmer for 10 minutes. Mix with the cooked pasta."
tokens_for_ai: "Explain how to make pasta with tomato sauce in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you make pasta with tomato sauce?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to make pasta with tomato sauce."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of making pasta with tomato sauce. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on making pasta with tomato sauce."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of making pasta with tomato sauce in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Baking Basics"
steps:
- step_id: "step_1"
title: "Baking Cookies"
content_blocks:
- "Baking cookies is a fun and rewarding activity."
- "Ingredients: 1 cup butter, 1 cup sugar, 2 cups flour, 1 egg, 1 tsp vanilla extract, 1 tsp baking soda, a pinch of salt."
- "Instructions: Preheat the oven to 350°F (175°C). Cream the butter and sugar together. Add the egg and vanilla extract. Mix in the flour, baking soda, and salt. Drop spoonfuls of dough onto a baking sheet and bake for 10-12 minutes."
tokens_for_ai: "Explain how to bake cookies in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you bake cookies?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know how to bake cookies."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of baking cookies. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on baking cookies."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of baking cookies in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Baking Bread"
content_blocks:
- "Baking bread is a rewarding and delicious skill to learn."
- "Ingredients: 3 cups flour, 1 packet yeast, 1 cup warm water, 1 tbsp sugar, 1 tsp salt."
- "Instructions: Dissolve the yeast and sugar in warm water and let it sit for 5 minutes. Mix in the flour and salt to form a dough. Knead the dough for 10 minutes, then let it rise for 1 hour. Preheat the oven to 375°F (190°C). Shape the dough into a loaf and bake for 25-30 minutes."
tokens_for_ai: "Explain how to bake bread in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "How do you bake bread?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know how to bake bread."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of baking bread. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on baking bread."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of baking bread in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Cooking Safety"
steps:
- step_id: "step_1"
title: "Kitchen Safety Tips"
content_blocks:
- "Safety in the kitchen is crucial to prevent accidents and injuries."
- "Always use oven mitts when handling hot items, keep knives sharp and handle them carefully, and clean up spills immediately to avoid slips."
tokens_for_ai: "Explain important kitchen safety tips in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What are some important kitchen safety tips?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand important kitchen safety tips."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of kitchen safety tips. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on kitchen safety tips."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of kitchen safety tips in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Food Safety"
content_blocks:
- "Food safety is essential to prevent foodborne illnesses."
- "Always wash your hands before handling food, cook meat to the proper temperature, and store leftovers in the refrigerator promptly."
tokens_for_ai: "Explain important food safety practices in a friendly and engaging manner. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What are some important food safety practices?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand important food safety practices."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of food safety practices. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on food safety practices."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of food safety practices in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Basic Cooking Skills course!"
- "You have learned valuable skills and techniques that will help you in the kitchen."
- "Remember, cooking is a skill that improves with practice, so keep experimenting and trying new recipes."
- "We are proud of your dedication and hard work. Well done!"

652
research/activity9.yaml Normal file
View file

@ -0,0 +1,652 @@
default_max_attempts_per_step: 3
sections:
- section_id: "section_1"
title: "Introduction to Minecraft"
steps:
- step_id: "step_1"
title: "What is Minecraft?"
content_blocks:
- "Welcome to the Minecraft Trivia game!"
- "Minecraft is a popular sandbox video game where players can build, explore, and survive in a blocky, procedurally-generated 3D world."
tokens_for_ai: "Explain what Minecraft is in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What do you know about Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know what Minecraft is."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Minecraft. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Minecraft."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Minecraft in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Minecraft Gameplay"
content_blocks:
- "In Minecraft, players can explore a blocky world, gather resources, craft items, and build structures."
- "The game has different modes, including Survival, Creative, Adventure, and Spectator."
tokens_for_ai: "Explain the basic gameplay of Minecraft in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe the basic gameplay of Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You understand the basic gameplay of Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Minecraft gameplay. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Minecraft gameplay."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Minecraft gameplay in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_2"
title: "Minecraft Mobs"
steps:
- step_id: "step_1"
title: "Friendly Mobs"
content_blocks:
- "Minecraft has various friendly mobs, such as cows, pigs, and chickens."
- "These mobs can be found in different biomes and can be used for resources like food and materials."
tokens_for_ai: "Explain what friendly mobs are in Minecraft in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some friendly mobs in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about friendly mobs in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about friendly mobs. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on friendly mobs."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of friendly mobs in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Hostile Mobs"
content_blocks:
- "Minecraft also has hostile mobs, such as zombies, skeletons, and creepers."
- "These mobs attack players and can be found in dark areas or at night."
tokens_for_ai: "Explain what hostile mobs are in Minecraft in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some hostile mobs in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about hostile mobs in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about hostile mobs. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on hostile mobs."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of hostile mobs in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_3"
title: "Minecraft Biomes"
steps:
- step_id: "step_1"
title: "Overworld Biomes"
content_blocks:
- "The Overworld in Minecraft has various biomes, such as forests, deserts, and plains."
- "Each biome has unique features, resources, and mobs."
tokens_for_ai: "Explain what biomes are in Minecraft and describe some Overworld biomes in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some Overworld biomes in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about Overworld biomes in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Overworld biomes. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Overworld biomes."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Overworld biomes in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Nether Biomes"
content_blocks:
- "The Nether is a dangerous dimension in Minecraft with unique biomes, such as Nether Wastes, Crimson Forest, and Warped Forest."
- "These biomes have unique resources and hostile mobs."
tokens_for_ai: "Explain what Nether biomes are in Minecraft and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some Nether biomes in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about Nether biomes in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Nether biomes. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Nether biomes."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Nether biomes in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_4"
title: "Minecraft Items and Blocks"
steps:
- step_id: "step_1"
title: "Common Blocks"
content_blocks:
- "Minecraft has many common blocks, such as dirt, stone, and wood."
- "These blocks are used for building and crafting."
tokens_for_ai: "Explain what common blocks are in Minecraft and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some common blocks in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about common blocks in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about common blocks. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on common blocks."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of common blocks in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Crafting Items"
content_blocks:
- "Crafting is an essential part of Minecraft, allowing players to create items like tools, weapons, and armor."
- "Common crafting items include sticks, planks, and ingots."
tokens_for_ai: "Explain what crafting items are in Minecraft and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some crafting items in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about crafting items in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about crafting items. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on crafting items."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of crafting items in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_5"
title: "Minecraft Structures"
steps:
- step_id: "step_1"
title: "Villages"
content_blocks:
- "Villages are structures in Minecraft where villagers live and work."
- "They have houses, farms, and other buildings."
tokens_for_ai: "Explain what villages are in Minecraft and describe their features in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe what a village is in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know what a village is in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about villages. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on villages."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of villages in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Strongholds"
content_blocks:
- "Strongholds are underground structures in Minecraft that contain the End Portal."
- "They are made of stone bricks and have various rooms and corridors."
tokens_for_ai: "Explain what strongholds are in Minecraft and describe their features in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe what a stronghold is in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know what a stronghold is in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about strongholds. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on strongholds."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of strongholds in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_6"
title: "Minecraft Achievements"
steps:
- step_id: "step_1"
title: "Common Achievements"
content_blocks:
- "Minecraft has various achievements that players can earn by completing specific tasks."
- "Common achievements include 'Taking Inventory,' 'Getting Wood,' and 'Benchmarking.'"
tokens_for_ai: "Explain what achievements are in Minecraft and describe some common ones in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some common achievements in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about common achievements in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about common achievements. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on common achievements."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of common achievements in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Rare Achievements"
content_blocks:
- "Minecraft also has rare achievements that are more challenging to earn."
- "Rare achievements include 'The End,' 'Beaconator,' and 'Adventuring Time.'"
tokens_for_ai: "Explain what rare achievements are in Minecraft and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some rare achievements in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about rare achievements in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about rare achievements. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on rare achievements."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of rare achievements in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_7"
title: "Minecraft Redstone"
steps:
- step_id: "step_1"
title: "What is Redstone?"
content_blocks:
- "Redstone is a special material in Minecraft that can be used to create circuits and machines."
- "It allows players to build complex contraptions like doors, traps, and automated farms."
tokens_for_ai: "Explain what Redstone is in Minecraft and its uses in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "What is Redstone and what can you do with it in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You understand what Redstone is and its uses in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of Redstone. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Redstone."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Redstone in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Basic Redstone Contraptions"
content_blocks:
- "Some basic Redstone contraptions include pressure plates, levers, and buttons."
- "These can be used to create simple machines like doors that open automatically or lights that turn on with a switch."
tokens_for_ai: "Explain some basic Redstone contraptions in Minecraft and their uses in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some basic Redstone contraptions and their uses in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about basic Redstone contraptions and their uses in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of basic Redstone contraptions. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on basic Redstone contraptions."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of basic Redstone contraptions in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_8"
title: "Minecraft Updates"
steps:
- step_id: "step_1"
title: "Major Updates"
content_blocks:
- "Minecraft receives regular updates that add new features, blocks, and mobs to the game."
- "Some major updates include the 'Nether Update,' 'Caves & Cliffs Update,' and 'Village & Pillage Update.'"
tokens_for_ai: "Explain what major updates are in Minecraft and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you name some major updates in Minecraft?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know about major updates in Minecraft."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about major updates. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on major updates."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of major updates in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "New Features"
content_blocks:
- "Each major update introduces new features to Minecraft, such as new biomes, mobs, and blocks."
- "These features enhance the gameplay experience and provide new challenges and opportunities for players."
tokens_for_ai: "Explain what new features are introduced in Minecraft updates and describe some of them in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe some new features introduced in Minecraft updates?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know about new features introduced in Minecraft updates."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of new features. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on new features."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of new features in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_9"
title: "Minecraft Community"
steps:
- step_id: "step_1"
title: "Minecraft Servers"
content_blocks:
- "Minecraft servers are online multiplayer worlds where players can join and play together."
- "Servers offer various game modes, mini-games, and custom content created by the community."
tokens_for_ai: "Explain what Minecraft servers are and their features in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe what Minecraft servers are and their features?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Great! You know what Minecraft servers are and their features."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You know a little about Minecraft servers. Let's learn more!"
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Minecraft servers."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Minecraft servers in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's answer them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- step_id: "step_2"
title: "Minecraft Mods"
content_blocks:
- "Minecraft mods are modifications made by the community that add new features, items, and gameplay mechanics to the game."
- "Mods can be downloaded and installed to enhance the Minecraft experience."
tokens_for_ai: "Explain what Minecraft mods are and their uses in a friendly and engaging manner suitable for 7 to 13-year-olds. If any part of the user's answer is correct and on-topic, categorize it as 'correct'."
question: "Can you describe what Minecraft mods are and their uses?"
buckets:
- correct
- partial_understanding
- off_topic
- asking_clarifying_questions
transitions:
correct:
content_blocks:
- "Excellent! You know what Minecraft mods are and their uses."
ai_feedback:
tokens_for_ai: "Provide positive reinforcement and encourage the user to continue learning."
partial_understanding:
content_blocks:
- "You have a partial understanding of Minecraft mods. Let's clarify a few points."
ai_feedback:
tokens_for_ai: "Provide additional information to clarify the user's understanding in a friendly and supportive manner."
off_topic:
content_blocks:
- "It seems like your response is off-topic. Let's try to stay focused on Minecraft mods."
ai_feedback:
tokens_for_ai: "Gently guide the user back to the topic of Minecraft mods in a supportive manner."
asking_clarifying_questions:
content_blocks:
- "I see you have some questions. Let's address them."
ai_feedback:
tokens_for_ai: "Answer the user's clarifying questions and provide additional information in a friendly and engaging manner."
- section_id: "section_10"
title: "Congratulations!"
steps:
- step_id: "step_1"
title: "Well Done!"
content_blocks:
- "Congratulations on completing the Minecraft Trivia game!"
- "You have learned a lot about Minecraft, including its gameplay, mobs, biomes, items, structures, achievements, Redstone, updates, and community."
- "Remember, Minecraft is a game of creativity and exploration, so keep playing, building, and discovering new things."
- "We are proud of your dedication and hard work. Well done!"

866
research/guarded_ai.py Normal file
View file

@ -0,0 +1,866 @@
import argparse
import yaml
import json
import random
import os
import sys
from openai import OpenAI
# Add parent directory to path to import activity_utils
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Import activity utilities for v2.0 features
from activity_utils import (
render_template,
check_conditions,
filter_content_blocks,
resolve_conditional_navigation,
select_weighted_random,
get_progressive_hint,
create_template_context,
)
# Global model-client mapping
MODEL_CLIENT_MAP = {}
def get_client_for_endpoint(endpoint, api_key):
"""Create OpenAI client for any endpoint"""
return OpenAI(api_key=api_key, base_url=endpoint)
def initialize_model_map():
"""Initialize the model-client mapping from environment variables"""
# Load endpoints from environment variables
for i in range(1000): # Support up to 1000 endpoints
endpoint_key = f"MODEL_ENDPOINT_{i}"
api_key_key = f"MODEL_API_KEY_{i}"
endpoint = os.getenv(endpoint_key)
api_key = os.getenv(api_key_key)
if endpoint and api_key:
try:
client = get_client_for_endpoint(endpoint, api_key)
# Query endpoint for available models
try:
response = client.models.list()
model_list = response.data
print(
f"[DEBUG] {endpoint} returned models: {[m.id for m in model_list]}"
)
for m in model_list:
model_id = m.id
if model_id and model_id not in MODEL_CLIENT_MAP:
MODEL_CLIENT_MAP[model_id] = (client, endpoint)
except Exception as e:
print(
f"Warning: Could not list models for endpoint '{endpoint}': {e}"
)
except Exception as e:
print(f"Warning: Failed to initialize endpoint {endpoint}: {e}")
def get_openai_client_and_model(model_name=None):
"""Get OpenAI client and model name
Supports both direct model names and MODEL_X environment variable references.
If model_name is MODEL_1, MODEL_2, etc., looks up from environment.
"""
# Handle MODEL_X references
if model_name and model_name.startswith("MODEL_"):
# Extract the number from MODEL_X
try:
model_num = model_name.split("_")[1]
endpoint_key = f"MODEL_ENDPOINT_{model_num}"
api_key_key = f"MODEL_API_KEY_{model_num}"
endpoint = os.getenv(endpoint_key)
api_key = os.getenv(api_key_key)
if endpoint and api_key:
client = get_client_for_endpoint(endpoint, api_key)
# Look up actual model name from MODEL_CLIENT_MAP for this endpoint
actual_model = None
for model_id, (registered_client, base_url) in MODEL_CLIENT_MAP.items():
if base_url == endpoint:
actual_model = model_id
break
if actual_model:
return client, actual_model
else:
# Fallback: query endpoint for models if not in map yet
try:
response = client.models.list()
if response.data:
actual_model = response.data[0].id
print(
f"[DEBUG] Using first model from {endpoint}: {actual_model}"
)
return client, actual_model
except Exception as e:
print(f"Warning: Could not query models from {endpoint}: {e}")
# Final fallback
print(
f"Warning: No models found for {endpoint}, using 'model' as fallback"
)
return client, "model"
except Exception as e:
print(f"Warning: Failed to load {model_name}: {e}, falling back to default")
# Default to MODEL_1 (Hermes)
if not model_name:
return get_openai_client_and_model("MODEL_1")
# Try to find client for specific model name
for stored_model, (client, base_url) in MODEL_CLIENT_MAP.items():
if model_name in stored_model or stored_model == model_name:
return client, model_name
# Fallback to first available client
if MODEL_CLIENT_MAP:
client, _ = next(iter(MODEL_CLIENT_MAP.values()))
return client, model_name
# Final fallback to environment or default OpenAI
api_key = os.getenv("OPENAI_API_KEY", "dummy-key")
endpoint = os.getenv("MODEL_ENDPOINT_0", "https://api.openai.com/v1")
client = get_client_for_endpoint(endpoint, api_key)
return client, model_name
# Initialize the model mapping on startup
initialize_model_map()
# Load the YAML activity file
def load_yaml_activity(file_path):
with open(file_path, "r") as file:
return yaml.safe_load(file)
# Categorize the user's response
def categorize_response(question, response, buckets, tokens_for_ai, model="MODEL_1"):
bucket_list = ", ".join([str(bucket) for bucket in buckets])
messages = [
{
"role": "system",
"content": f"{tokens_for_ai} Categorize the following response into one of the following buckets: {bucket_list}. Return ONLY a bucket label.",
},
{
"role": "user",
"content": f"Question: {question}\nResponse: {response}\n\nCategory:",
},
]
try:
client, model_name = get_openai_client_and_model(model)
completion = client.chat.completions.create(
model=model_name,
messages=messages,
max_tokens=5,
temperature=0,
)
category = (
completion.choices[0].message.content.strip().lower().replace(" ", "_")
)
return category
except Exception as e:
return f"Error: {e}"
# Generate AI feedback
def generate_ai_feedback(
category, question, user_response, tokens_for_ai, metadata, model="MODEL_1"
):
messages = [
{
"role": "system",
"content": f"{tokens_for_ai} Generate a human-readable feedback message based on the following:",
},
{
"role": "user",
"content": f"Question: {question}\nResponse: {user_response}\nCategory: {category},\nMetadata: {metadata}",
},
]
try:
client, model_name = get_openai_client_and_model(model)
completion = client.chat.completions.create(
model=model_name, messages=messages, max_tokens=250, temperature=0.7
)
feedback = completion.choices[0].message.content.strip()
return feedback
except Exception as e:
return f"Error: {e}"
# Provide feedback based on the category (legacy single feedback system)
def provide_feedback(
transition,
category,
question,
user_response,
user_language,
tokens_for_ai,
metadata,
model="MODEL_1",
):
feedback = ""
if "ai_feedback" in transition:
tokens_for_ai += f" Provide the feedback in {user_language}. {transition['ai_feedback'].get('tokens_for_ai', '')}."
# Filter metadata for feedback if metadata_feedback_filter is specified
feedback_metadata = metadata
if "metadata_feedback_filter" in transition:
filter_keys = transition["metadata_feedback_filter"]
feedback_metadata = {k: v for k, v in metadata.items() if k in filter_keys}
ai_feedback = generate_ai_feedback(
category, question, user_response, tokens_for_ai, feedback_metadata, model
)
feedback += f"\n\nAI Feedback: {ai_feedback}"
return feedback
# Provide feedback using multiple prompts (new system)
def provide_feedback_prompts(
transition,
category,
question,
feedback_prompts,
user_response,
user_language,
metadata,
legacy_tokens_for_ai="",
model="MODEL_1",
):
"""Generate feedback from multiple prompts"""
feedback_messages = []
# Add user_response to metadata for filtering purposes
full_metadata = metadata.copy()
full_metadata["user_response"] = user_response
for prompt in feedback_prompts:
prompt_name = prompt.get("name", "unnamed")
tokens_for_ai = prompt.get("tokens_for_ai", "")
# Apply per-prompt metadata filtering if specified
prompt_metadata = full_metadata
if "metadata_filter" in prompt:
filter_keys = prompt["metadata_filter"]
prompt_metadata = {
k: v for k, v in full_metadata.items() if k in filter_keys
}
# Combine legacy tokens with prompt-specific tokens
if legacy_tokens_for_ai:
tokens_for_ai = legacy_tokens_for_ai + " " + tokens_for_ai
# Add language instruction
tokens_for_ai += f" Provide the feedback in {user_language}."
# Add transition-specific AI feedback if present
if "ai_feedback" in transition:
tokens_for_ai += f" {transition['ai_feedback'].get('tokens_for_ai', '')}"
# Determine user_response for this prompt based on metadata filtering
filtered_user_response = user_response
if (
"metadata_filter" in prompt
and "user_response" not in prompt["metadata_filter"]
):
filtered_user_response = "" # Remove user response if not in filter
ai_feedback = generate_ai_feedback(
category,
question,
filtered_user_response,
tokens_for_ai,
prompt_metadata,
model,
)
# Only add feedback if it has content and isn't exactly the STFU token
if ai_feedback and ai_feedback.strip() and ai_feedback.strip() != "STFU":
feedback_messages.append(
{"name": prompt_name, "content": ai_feedback.strip()}
)
return feedback_messages
def execute_processing_script(metadata, script):
# Prepare the environment for the script
# Use the same dict for both globals and locals to support comprehensions
script_env = {
"__builtins__": __builtins__,
"metadata": metadata,
"script_result": None,
}
# Execute the script
exec(script, script_env, script_env)
# Return the result from the script
return script_env["script_result"]
def get_next_section_and_step(activity_content, current_section_id, current_step_id):
for section in activity_content["sections"]:
if section["section_id"] == current_section_id:
for i, step in enumerate(section["steps"]):
if step["step_id"] == current_step_id:
if i + 1 < len(section["steps"]):
return section["section_id"], section["steps"][i + 1]["step_id"]
else:
# Move to the next section
next_section_index = (
activity_content["sections"].index(section) + 1
)
if next_section_index < len(activity_content["sections"]):
next_section = activity_content["sections"][
next_section_index
]
return (
next_section["section_id"],
next_section["steps"][0]["step_id"],
)
return None, None
def translate_text(text, target_language, model="MODEL_1"):
# Guard clause for default language
if target_language.lower() == "english":
return text
messages = [
{
"role": "system",
"content": f"Translate the following text to {target_language}:",
},
{
"role": "user",
"content": text,
},
]
try:
client, model_name = get_openai_client_and_model(model)
completion = client.chat.completions.create(
model=model_name, messages=messages, max_tokens=500, temperature=0.7
)
translation = completion.choices[0].message.content.strip()
return translation
except Exception as e:
return f"Error: {e}"
def simulate_activity(yaml_file_path):
yaml_content = load_yaml_activity(yaml_file_path)
max_attempts = yaml_content.get("default_max_attempts_per_step", 3)
# Get activity-level model defaults (default to MODEL_1 - Hermes)
default_classifier_model = yaml_content.get("classifier_model", "MODEL_1")
default_feedback_model = yaml_content.get("feedback_model", "MODEL_1")
current_section_id = yaml_content["sections"][0]["section_id"]
current_step_id = yaml_content["sections"][0]["steps"][0]["step_id"]
metadata = {"language": "English"} # Default language
while current_section_id and current_step_id:
print(
f"\n\nCurrent section: {current_section_id}, Current step: {current_step_id}\n\n"
)
section = next(
(
s
for s in yaml_content["sections"]
if s["section_id"] == current_section_id
),
None,
)
step = next(
(s for s in section["steps"] if s["step_id"] == current_step_id), None
)
# Get step-level model overrides (if specified), otherwise use activity defaults
classifier_model = step.get("classifier_model", default_classifier_model)
feedback_model = step.get("feedback_model", default_feedback_model)
# Get the user's language preference from metadata
user_language = metadata.get("language", "English")
# Initialize attempts and max_attempts for this step
attempts = 0
step_max_attempts = step.get("max_attempts_per_step", max_attempts)
# Create template context for rendering
context = create_template_context(
metadata=metadata,
current_attempt=attempts,
max_attempts=step_max_attempts,
current_section=current_section_id,
current_step=current_step_id,
username="User",
)
# Translate and print all content blocks once per step (v2.0 with templates & conditionals)
if "content_blocks" in step:
# Filter and render content blocks
filtered_blocks = filter_content_blocks(
step["content_blocks"], metadata, context
)
if filtered_blocks:
content = "\n\n".join(filtered_blocks)
translated_content = translate_text(
content, user_language, feedback_model
)
print(translated_content)
# Skip classification and feedback if there's no question
if "question" not in step:
current_section_id, current_step_id = get_next_section_and_step(
yaml_content, current_section_id, current_step_id
)
continue
# Render template variables in question (v2.0)
question = render_template(step["question"], context)
translated_question = translate_text(question, user_language, feedback_model)
print(f"\nQuestion: {translated_question}")
while attempts < step_max_attempts:
# Update context with current attempt
context = create_template_context(
metadata=metadata,
current_attempt=attempts + 1, # 1-indexed for display
max_attempts=step_max_attempts,
current_section=current_section_id,
current_step=current_step_id,
username="User",
)
user_response = input("\nYour Response: ")
# Roll for random buckets BEFORE categorization
triggered_random_buckets = []
if "random_buckets" in step:
for bucket_name, config in step["random_buckets"].items():
probability = config.get("probability", 0)
roll = random.random()
if roll < probability:
triggered_random_buckets.append(bucket_name)
print(
f"🎲 [RANDOM EVENT] '{bucket_name}' triggered! (rolled {roll:.3f} < {probability})"
)
else:
print(
f"🎲 [RANDOM CHECK] '{bucket_name}' not triggered (rolled {roll:.3f} >= {probability})"
)
# Execute pre-script if it exists (runs before categorization, with user_response available)
if "pre_script" in step:
print(f"DEBUG: Executing pre-script")
# Add user_response to a temporary copy of metadata for pre_script
temp_metadata = metadata.copy()
temp_metadata["user_response"] = user_response
pre_result = execute_processing_script(
temp_metadata, step["pre_script"]
)
# Update metadata with pre-script results
for key, value in pre_result.get("metadata", {}).items():
metadata[key] = value
print(f"DEBUG: Pre-script completed, updated metadata")
category = categorize_response(
question,
user_response,
step["buckets"],
step["tokens_for_ai"],
classifier_model,
)
print(f"\nCategory: {category}")
# Combine user's category with triggered random buckets
# User's response is processed FIRST, then random events
all_active_buckets = [category] + triggered_random_buckets
print(f"📋 Processing buckets in order: {all_active_buckets}")
# Find transitions for all active buckets
active_transitions = []
for bucket in all_active_buckets:
transition = None
if bucket in step["transitions"]:
transition = step["transitions"][bucket]
elif str(bucket).isdigit() and int(bucket) in step["transitions"]:
transition = step["transitions"][int(bucket)]
else:
# Try boolean conversion
if str(bucket).lower() in ["yes", "true"]:
bucket = True
elif str(bucket).lower() in ["no", "false"]:
bucket = False
if bucket in step["transitions"]:
transition = step["transitions"][bucket]
if transition:
active_transitions.append((bucket, transition))
else:
print(f"⚠️ Warning: No transition found for bucket '{bucket}'")
# If no valid transitions found at all (not even for user's category), error
if not active_transitions:
print(
f"\nError: No valid transition found for category '{category}'. Please try again."
)
continue
print(f"✓ Found {len(active_transitions)} transition(s) to process")
# Track temporary metadata keys across all transitions
metadata_tmp_keys = []
# Track the final navigation target (use LAST transition's next_section_and_step)
final_next_section_and_step = None
# Track counts_as_attempt (if ANY transition counts, then it counts)
any_counts_as_attempt = False
# Process ALL active transitions in order
for bucket_name, transition in active_transitions:
print(f"\n{'='*60}")
print(f"Processing transition for bucket: '{bucket_name}'")
print(f"{'='*60}")
# Check metadata conditions (v2.0 advanced conditions)
if "metadata_conditions" in transition:
conditions_met = check_conditions(
metadata, transition["metadata_conditions"]
)
if not conditions_met:
print(
f"⚠️ Skipping '{bucket_name}' - metadata conditions not met"
)
print(f"Current Metadata: {json.dumps(metadata, indent=2)}")
continue
# Print transition content blocks if they exist (v2.0 with templates & conditionals)
if "content_blocks" in transition:
# Create template context
context = create_template_context(
metadata=metadata,
current_attempt=attempts,
max_attempts=max_attempts,
current_section=current_section_id,
current_step=current_step_id,
username="User",
)
# Filter and render content blocks (supports conditional blocks and templates)
filtered_blocks = filter_content_blocks(
transition["content_blocks"], metadata, context
)
if filtered_blocks:
transition_content = "\n\n".join(filtered_blocks)
translated_transition_content = translate_text(
transition_content, user_language, feedback_model
)
print(translated_transition_content)
# Update metadata based on user actions
if "metadata_add" in transition:
for key, value in transition["metadata_add"].items():
if value == "the-users-response":
value = user_response
elif isinstance(value, str):
if value.startswith("n+random(") and value.endswith(")"):
# Extract the range and apply the random increment
range_values = value[9:-1].split(",")
if len(range_values) == 2:
x, y = map(int, range_values)
value = metadata.get(key, 0) + random.randint(x, y)
elif value.startswith("n+") or value.startswith("n-"):
# Check if this is string concatenation (n+,value) or numeric operation (n+5)
if value.startswith("n+,") or value.startswith("n-,"):
# String concatenation: append/remove from existing value
operation = value[:2] # "n+" or "n-"
suffix = value[
3:
] # Everything after "n+," or "n-,"
existing_value = metadata.get(key, "")
if operation == "n+":
# Append with comma separator if existing value is non-empty
if existing_value:
value = f"{existing_value},{suffix}"
else:
value = suffix
elif operation == "n-":
# Remove suffix from existing value
if existing_value:
parts = existing_value.split(",")
parts = [p for p in parts if p != suffix]
value = ",".join(parts)
else:
value = existing_value
else:
# Numeric operation: extract the numeric part c and apply the operation +/-
try:
c = int(value[2:])
if value.startswith("n+"):
value = metadata.get(key, 0) + c
elif value.startswith("n-"):
value = metadata.get(key, 0) - c
except ValueError:
print(
f"Warning: Invalid numeric operation '{value}' for key '{key}'"
)
# Leave value as-is if parsing fails
metadata[key] = value
if "metadata_tmp_add" in transition:
for key, value in transition["metadata_tmp_add"].items():
if value == "the-users-response":
value = user_response
elif isinstance(value, str):
if value.startswith("n+random(") and value.endswith(")"):
# Extract the range and apply the random increment
range_values = value[9:-1].split(",")
if len(range_values) == 2:
x, y = map(int, range_values)
value = random.randint(x, y)
elif value.startswith("n+") or value.startswith("n-"):
# Check if this is string concatenation (n+,value) or numeric operation (n+5)
if value.startswith("n+,") or value.startswith("n-,"):
# String concatenation: append/remove from existing value
operation = value[:2] # "n+" or "n-"
suffix = value[
3:
] # Everything after "n+," or "n-,"
existing_value = metadata.get(key, "")
if operation == "n+":
# Append with comma separator if existing value is non-empty
if existing_value:
value = f"{existing_value},{suffix}"
else:
value = suffix
elif operation == "n-":
# Remove suffix from existing value
if existing_value:
parts = existing_value.split(",")
parts = [p for p in parts if p != suffix]
value = ",".join(parts)
else:
value = existing_value
else:
# Numeric operation: extract the numeric part c and apply the operation +/-
try:
c = int(value[2:])
if value.startswith("n+"):
value = metadata.get(key, 0) + c
elif value.startswith("n-"):
value = metadata.get(key, 0) - c
except ValueError:
print(
f"Warning: Invalid numeric operation '{value}' for key '{key}'"
)
# Leave value as-is if parsing fails
metadata[key] = value
metadata_tmp_keys.append(key) # Track temporary keys
if "metadata_remove" in transition:
for key in transition["metadata_remove"]:
if key in metadata:
del metadata[key]
# Handle metadata_clear - clear all metadata if set to True
if (
"metadata_clear" in transition
and transition["metadata_clear"] == True
):
metadata.clear()
# Handle metadata_random
if "metadata_random" in transition:
random_key = random.choice(
list(transition["metadata_random"].keys())
)
random_value = transition["metadata_random"][random_key]
metadata[random_key] = random_value
if "metadata_tmp_random" in transition:
random_key = random.choice(
list(transition["metadata_tmp_random"].keys())
)
random_value = random.choice(
transition["metadata_tmp_random"][random_key]
)
metadata[random_key] = random_value
metadata_tmp_keys.append(random_key) # Track temporary keys
# Handle metadata_weighted_random (v2.0)
if "metadata_weighted_random" in transition:
for key, weighted_options in transition[
"metadata_weighted_random"
].items():
selected_value = select_weighted_random(weighted_options)
metadata[key] = selected_value
# Handle metadata_tmp_weighted_random (v2.0)
if "metadata_tmp_weighted_random" in transition:
for key, weighted_options in transition[
"metadata_tmp_weighted_random"
].items():
selected_value = select_weighted_random(weighted_options)
metadata[key] = selected_value
metadata_tmp_keys.append(key)
# Execute the processing script if it exists
if "processing_script" in step and transition.get(
"run_processing_script", False
):
# Add user_response to metadata temporarily for processing script
temp_metadata = metadata.copy()
temp_metadata["user_response"] = user_response
result = execute_processing_script(
temp_metadata, step["processing_script"]
)
# Copy any changes back to main metadata (except user_response)
for key, value in temp_metadata.items():
if key != "user_response":
metadata[key] = value
metadata["processing_script_result"] = result
metadata_tmp_keys.append("processing_script_result")
# Update metadata with results from the processing script
for key, value in result.get("metadata", {}).items():
metadata[key] = value
print(
f"\n[Metadata after '{bucket_name}']: {json.dumps(metadata, indent=2)}"
)
# Provide feedback for THIS bucket
if "feedback_prompts" in step:
# New multi-prompt system - legacy tokens get combined with each prompt
multi_feedback_messages = provide_feedback_prompts(
transition,
bucket_name, # Use bucket_name instead of category
question,
step["feedback_prompts"],
user_response,
user_language,
metadata,
step.get(
"feedback_tokens_for_ai", ""
), # Pass legacy tokens to be combined
feedback_model,
)
# Display feedback immediately for this bucket
for feedback_msg in multi_feedback_messages:
print(f"\n{feedback_msg['name']}: {feedback_msg['content']}")
elif step.get("feedback_tokens_for_ai"):
# Legacy single feedback system - only if no feedback_prompts
feedback = provide_feedback(
transition,
bucket_name, # Use bucket_name instead of category
question,
user_response,
user_language,
step.get("feedback_tokens_for_ai", ""),
metadata,
feedback_model,
)
if feedback and feedback.strip():
print(f"\nFeedback: {feedback}")
# Track navigation (LAST transition's next_section_and_step wins)
if "next_section_and_step" in transition:
final_next_section_and_step = transition["next_section_and_step"]
print(f"🎯 Navigation target set to: {final_next_section_and_step}")
# Track counts_as_attempt (if ANY transition counts, it counts)
if transition.get("counts_as_attempt", True):
any_counts_as_attempt = True
# End of multi-bucket processing loop
# Check for progressive hints (v2.0)
if "hints" in step:
hint_context = create_template_context(
metadata=metadata,
current_attempt=attempts + 1, # Next attempt
max_attempts=step_max_attempts,
current_section=current_section_id,
current_step=current_step_id,
username="User",
)
hint = get_progressive_hint(step["hints"], attempts + 1, hint_context)
if hint:
translated_hint = translate_text(
hint["text"], user_language, feedback_model
)
print(f"\n💡 Hint: {translated_hint}")
# If hint doesn't count as attempt, adjust counting
if not hint["counts_as_attempt"]:
any_counts_as_attempt = False
# Check if we should break or continue attempting
if category not in [
"partial_understanding",
"limited_effort",
"asking_clarifying_questions",
"set_language",
"off_topic",
]:
break
# Increment attempts if ANY transition counted
if any_counts_as_attempt:
attempts += 1
if attempts == step_max_attempts:
print("\nMaximum attempts reached. Moving to the next step.")
# Remove temporary metadata at the end of the step
for key in metadata_tmp_keys:
if key in metadata:
del metadata[key]
# Use the final navigation target (from LAST processed transition)
# v2.0: Resolve conditional navigation
if final_next_section_and_step:
resolved_navigation = resolve_conditional_navigation(
final_next_section_and_step, metadata
)
if resolved_navigation:
current_section_id, current_step_id = resolved_navigation.split(":")
else:
# No navigation specified, move to next step automatically
current_section_id, current_step_id = get_next_section_and_step(
yaml_content, current_section_id, current_step_id
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Simulate an activity.")
parser.add_argument(
"yaml_file_path",
type=str,
help="Path to the activity YAML file",
default="activity0.yaml",
)
args = parser.parse_args()
simulate_activity(args.yaml_file_path)

1440
static/css/style.css Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

12
static/js/utils.js Normal file
View file

@ -0,0 +1,12 @@
/**
* Utility functions for the OpenCompletion application
*/
/**
* Convert a string to a URL-friendly slug
* @param {string} str - The string to slugify
* @returns {string} - The slugified string
*/
function slugify(str) {
return str.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '');
}

288
templates/auth.html Normal file
View file

@ -0,0 +1,288 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign In - OpenCompletion</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: grid;
place-items: center;
min-height: 100vh;
margin: 0;
padding: 20px;
}
.auth-container {
background-color: #ffffff;
border-radius: 10px;
padding: 40px;
width: 100%;
max-width: 450px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}
.logo {
text-align: center;
margin-bottom: 30px;
}
.logo h1 {
color: #667eea;
margin: 0;
font-size: 32px;
}
.logo p {
color: #666;
margin: 5px 0 0 0;
font-size: 14px;
}
.auth-step {
display: none;
}
.auth-step.active {
display: block;
}
.auth-step h2 {
margin-top: 0;
color: #333;
text-align: center;
}
.auth-step p {
color: #666;
text-align: center;
margin-bottom: 25px;
}
.auth-step input {
width: 100%;
padding: 14px;
margin-bottom: 15px;
border: 2px solid #e1e1e1;
border-radius: 5px;
font-size: 16px;
box-sizing: border-box;
}
.auth-step input:focus {
outline: none;
border-color: #667eea;
}
.auth-step button {
width: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
padding: 14px;
font-size: 16px;
cursor: pointer;
transition: transform 0.2s;
margin-bottom: 10px;
}
.auth-step button:hover {
transform: translateY(-2px);
}
.auth-step button.secondary-btn {
background: #6c757d;
}
.error-message {
color: #dc3545;
font-size: 14px;
margin-top: -10px;
margin-bottom: 15px;
text-align: center;
}
.back-link {
text-align: center;
margin-top: 20px;
}
.back-link a {
color: #667eea;
text-decoration: none;
font-weight: bold;
}
.back-link a:hover {
text-decoration: underline;
}
.success-icon {
text-align: center;
font-size: 64px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="auth-container">
<div class="logo">
<h1>🚀 OpenCompletion</h1>
<p>Machine Learning Powered Collaboration</p>
</div>
<!-- Step 1: Enter email -->
<div id="auth-step-email" class="auth-step active">
<h2>Sign In / Sign Up</h2>
<p>Enter your email to receive a verification code</p>
<input type="email" id="auth-email" placeholder="your@email.com" />
<button onclick="sendOTP()">Send Code</button>
<div id="auth-email-error" class="error-message"></div>
</div>
<!-- Step 2: Enter OTP -->
<div id="auth-step-otp" class="auth-step">
<h2>Enter Verification Code</h2>
<p>We sent a 6-digit code to <strong><span id="auth-email-display"></span></strong></p>
<input type="text" id="auth-otp" placeholder="123456" maxlength="6" />
<button onclick="verifyOTP()">Verify</button>
<button class="secondary-btn" onclick="backToEmailStep()">Back</button>
<div id="auth-otp-error" class="error-message"></div>
</div>
<!-- Step 3: Claim display name (new users only) -->
<div id="auth-step-name" class="auth-step">
<h2>Choose Display Name</h2>
<p>Pick a unique display name (3-50 characters)</p>
<input type="text" id="auth-display-name" placeholder="username" maxlength="50" />
<button onclick="claimName()">Complete Sign Up</button>
<div id="auth-name-error" class="error-message"></div>
</div>
<!-- Success -->
<div id="auth-step-success" class="auth-step">
<div class="success-icon"></div>
<h2>Success!</h2>
<p>Welcome, <strong><span id="auth-success-name"></span></strong>!</p>
<button onclick="redirectToChatRooms()">Go to Chat Rooms</button>
</div>
<div class="back-link">
<a href="/">← Back to Home</a>
</div>
</div>
<script>
let pendingEmail = '';
function showAuthStep(step) {
document.querySelectorAll('.auth-step').forEach(el => el.classList.remove('active'));
document.getElementById('auth-step-' + step).classList.add('active');
clearAuthErrors();
}
function clearAuthErrors() {
document.querySelectorAll('.error-message').forEach(el => el.textContent = '');
}
function backToEmailStep() {
showAuthStep('email');
}
function redirectToChatRooms() {
window.location.href = '/chat/general';
}
async function sendOTP() {
const email = document.getElementById('auth-email').value.trim();
const errorEl = document.getElementById('auth-email-error');
if (!email) {
errorEl.textContent = 'Please enter your email';
return;
}
try {
const response = await fetch('/auth/send-otp', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email})
});
const data = await response.json();
if (response.ok) {
pendingEmail = email;
document.getElementById('auth-email-display').textContent = email;
showAuthStep('otp');
} else {
errorEl.textContent = data.error || 'Failed to send code';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
async function verifyOTP() {
const otpCode = document.getElementById('auth-otp').value.trim();
const errorEl = document.getElementById('auth-otp-error');
if (!otpCode) {
errorEl.textContent = 'Please enter the code';
return;
}
try {
const response = await fetch('/auth/verify-otp', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: pendingEmail, otp_code: otpCode})
});
const data = await response.json();
if (response.ok) {
if (data.needs_display_name) {
showAuthStep('name');
} else {
document.getElementById('auth-success-name').textContent = data.user.display_name;
showAuthStep('success');
}
} else {
errorEl.textContent = data.error || 'Invalid code';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
async function claimName() {
const displayName = document.getElementById('auth-display-name').value.trim();
const errorEl = document.getElementById('auth-name-error');
if (!displayName) {
errorEl.textContent = 'Please enter a display name';
return;
}
try {
const response = await fetch('/auth/claim-name', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({display_name: displayName})
});
const data = await response.json();
if (response.ok) {
document.getElementById('auth-success-name').textContent = data.user.display_name;
showAuthStep('success');
} else {
errorEl.textContent = data.error || 'Failed to claim name';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
// Allow Enter key to submit on each step
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('auth-email').addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendOTP();
});
document.getElementById('auth-otp').addEventListener('keypress', function(e) {
if (e.key === 'Enter') verifyOTP();
});
document.getElementById('auth-display-name').addEventListener('keypress', function(e) {
if (e.key === 'Enter') claimName();
});
});
</script>
</body>
</html>

679
templates/base.html Normal file
View file

@ -0,0 +1,679 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Chatroom{% endblock %}</title>
<!-- Meta description for SEO -->
<meta name="description" content="{{ og_description|default('OpenCompletion - AI-powered collaborative chat rooms for machine learning') }}">
<!-- Open Graph meta tags for social sharing (Facebook, Discord, LinkedIn, etc.) -->
<meta property="og:type" content="website">
<meta property="og:title" content="{{ og_title|default('OpenCompletion - AI-Powered Chat Rooms') }}">
<meta property="og:description" content="{{ og_description|default('OpenCompletion - AI-powered collaborative chat rooms for machine learning') }}">
<meta property="og:site_name" content="OpenCompletion">
{% if og_image %}
<meta property="og:image" content="{{ og_image }}">
<meta property="og:image:alt" content="Preview image for {{ og_title|default('OpenCompletion') }}">
{% else %}
<meta property="og:image" content="{{ url_for('static', filename='images/og-default.png', _external=True) }}">
<meta property="og:image:alt" content="OpenCompletion logo">
{% endif %}
<!-- Twitter Card meta tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ og_title|default('OpenCompletion - AI-Powered Chat Rooms') }}">
<meta name="twitter:description" content="{{ og_description|default('OpenCompletion - AI-powered collaborative chat rooms for machine learning') }}">
{% if og_image %}
<meta name="twitter:image" content="{{ og_image }}">
{% else %}
<meta name="twitter:image" content="{{ url_for('static', filename='images/og-default.png', _external=True) }}">
{% endif %}
<script>
// Set theme immediately to prevent flash
(function() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
})();
</script>
<!-- Include highlight.js library for syntax highlighting -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<!-- Include highlight.js themes for light and dark modes -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github.min.css" id="highlight-theme-light">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github-dark.min.css" id="highlight-theme-dark" disabled>
<!-- Include socket.io for real-time bidirectional event-based communication -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
<!-- Include marked.js for markdown parsing -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/marked/9.1.2/marked.min.js"
integrity="sha512-rfX4p3RNnxdwLT3wWP1K0NR3ztTobn+sISlT9WhxDDK00zNYbQ6MCHA5OHm0hqKAzEMXYCgFrp8iY/ER5MkXqA=="
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
<!-- Include DOMPurify to sanitize HTML and prevent XSS attacks -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@2/dist/purify.min.js"></script>
<!-- Include utility functions -->
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
<script>
// Connect to the server using socket.io
const socket = io();
</script>
<!-- Link to the favicon -->
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<!-- Link to external stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<!-- Hamburger button for mobile -->
<button id="hamburger-button"></button>
<!-- Modal for room list and utility belt -->
<div id="room-list-modal">
<div id="room-list-modal-content">
<button id="close-modal-button" onclick="closeModal()">×</button>
<div id="utility-belt-mobile" class="utility-belt">
<div id="model-chooser-mobile">
<label for="model-select-mobile">Choose Model:</label>
<select id="model-select-mobile">
<option value="None">None</option>
</select>
</div>
<div id="voice-chooser-mobile">
<label for="voice-select-mobile">Choose Voice:</label>
<select id="voice-select-mobile">
<option value="onyx">Onyx</option>
<option value="alloy">Alloy</option>
<option value="echo">Echo</option>
<option value="fable">Fable</option>
<option value="nova">Nova</option>
<option value="shimmer">Shimmer</option>
</select>
</div>
<div id="theme-toggle-mobile">
<button id="theme-toggle-btn-mobile" onclick="toggleTheme()" style="width: 100%; margin-top: 10px; background-color: #555; color: white; border: none; padding: 8px; border-radius: 4px; cursor: pointer;">
Dark Mode
</button>
</div>
<div id="auto-play-tts-mobile">
<button id="auto-play-tts-btn-mobile" onclick="toggleAutoPlayTTS()" style="width: 100%; margin-top: 10px; background-color: #f44336; color: white; border: none; padding: 8px; border-radius: 4px; cursor: pointer;">
Auto-Play TTS: OFF
</button>
</div>
<div id="show-thinking-mobile">
<button id="show-thinking-btn-mobile" onclick="toggleShowThinking()" style="width: 100%; margin-top: 10px; background-color: #4CAF50; color: white; border: none; padding: 8px; border-radius: 4px; cursor: pointer;">
Thinking: ON
</button>
</div>
<div id="activity-controls-mobile">
<h3>Activities</h3>
<div id="current-activity-info-mobile" style="display: none;">
<p>Current Activity: <span id="current-activity-name-mobile"></span></p>
<button id="cancel-activity-btn-mobile" onclick="cancelActivity()">Cancel Activity</button>
</div>
<div id="activity-list-section-mobile">
<div style="display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 5px; margin-bottom: 5px;">
<select id="activity-select-mobile" style="width: 100%; max-width: 100%; box-sizing: border-box;">
<option value="">-- Select an Activity --</option>
</select>
<button id="refresh-activities-btn-mobile" onclick="refreshActivityList()">🔄</button>
</div>
<button id="load-activity-btn-mobile" onclick="loadSelectedActivityMobile()" style="margin-top: 5px;">Load Activity</button>
</div>
</div>
<div id="user-lists-mobile">
<div id="active-users-list">
<h3>Active Users</h3>
<ul id="active-users-mobile">
<!-- Active users will be dynamically populated here -->
</ul>
</div>
<div id="inactive-users-list">
<h3>Inactive Users</h3>
<ul id="inactive-users-mobile">
<!-- Inactive users will be dynamically populated here -->
</ul>
</div>
</div>
</div>
<div id="rooms-list-modal-content">
<!-- Room list will be cloned here for mobile view -->
</div>
</div>
</div>
<!-- Chatroom list -->
<div class="main-container">
<div id="rooms-list">
<!-- Create Room button with grid layout -->
<div id="create-room-section" style="display: grid; gap: 10px; margin-bottom: 15px;">
<a href="/">
<button id="create-room-btn">Create Room</button>
</a>
</div>
<!-- Room tabs with dynamic active state based on current room -->
<div id="room-tabs">
<div class="room-tab {% if not current_room or not current_room.is_private %}active{% endif %}" id="public-rooms-tab" onclick="switchRoomTab('public')">
🌍 Public
</div>
<div class="room-tab {% if current_room and current_room.is_private %}active{% endif %}" id="private-rooms-tab" onclick="switchRoomTab('private')">
🔐 Private
</div>
</div>
<!-- Private rooms section (show if viewing a private room) -->
<div id="private-rooms-section" class="room-section" style="display: {% if current_room and current_room.is_private %}block{% else %}none{% endif %};">
<div id="private-rooms-content">
{% if user %}
{% if private_rooms %}
<ul class="rooms-list">
{% for room in private_rooms %}
<a href="{{ url_for('chat', room_name=room.name) }}">
<li data-room-id="{{ room.id }}" class="private-room">
<b>{{ room.name }}</b>
{% if room.title %}
<br />{{ room.title }}
{% endif %}
{% if room.get_active_users()|length %}
<br /> {{ room.get_active_users()|length }} users
{% endif %}
</li>
</a>
{% endfor %}
</ul>
{% else %}
<p class="empty-state">No private rooms yet. Create one to get started!</p>
{% endif %}
{% else %}
<div class="auth-prompt">
<p>🔒 Private rooms are only visible to you</p>
<p>Sign in to create and access private rooms</p>
<button class="auth-btn" onclick="showAuthModal()">Sign In / Sign Up</button>
</div>
{% endif %}
</div>
</div>
<!-- Public rooms section (show if viewing a public room or no room) -->
<div id="public-rooms-section" class="room-section" style="display: {% if not current_room or not current_room.is_private %}block{% else %}none{% endif %};">
<ul id="rooms-list-ul" class="rooms-list">
<!-- Loop through public rooms and create list items for each room -->
{% for room in public_rooms %}
<a href="{{ url_for('chat', room_name=room.name) }}">
<li data-room-id="{{ room.id }}" class="public-room">
<!-- Display the room title if available, otherwise the room name -->
<b>{{ room.name }}</b>
{% if room.title %}
<br />{{ room.title }}
{% endif %}
{% if room.get_active_users()|length %}
<br /> {{ room.get_active_users()|length }} users
{% endif %}
{% if user and room.owner_id == user.id %}
<span class="owner-badge">👑 Owner</span>
{% endif %}
</li>
</a>
{% endfor %}
</ul>
</div>
</div>
{% block content %}{% endblock %}
</div>
<!-- Authentication Modal -->
<div id="auth-modal" class="modal" style="display: none;">
<div class="modal-content-auth">
<button class="close-btn" onclick="closeAuthModal()">×</button>
<!-- Step 1: Enter email -->
<div id="auth-step-email" class="auth-step">
<h2>Sign In / Sign Up</h2>
<p>Enter your email to receive a verification code</p>
<input type="email" id="auth-email" placeholder="your@email.com" />
<button onclick="sendOTP()">Send Code</button>
<div id="auth-email-error" class="error-message"></div>
</div>
<!-- Step 2: Enter OTP -->
<div id="auth-step-otp" class="auth-step" style="display: none;">
<h2>Enter Verification Code</h2>
<p>We sent a 6-digit code to <span id="auth-email-display"></span></p>
<input type="text" id="auth-otp" placeholder="123456" maxlength="6" />
<button onclick="verifyOTP()">Verify</button>
<button class="secondary-btn" onclick="backToEmailStep()">Back</button>
<div id="auth-otp-error" class="error-message"></div>
</div>
<!-- Step 3: Claim display name (new users only) -->
<div id="auth-step-name" class="auth-step" style="display: none;">
<h2>Choose Display Name</h2>
<p>Pick a unique display name (3-50 characters)</p>
<input type="text" id="auth-display-name" placeholder="username" maxlength="50" />
<button onclick="claimName()">Complete Sign Up</button>
<div id="auth-name-error" class="error-message"></div>
</div>
<!-- Success -->
<div id="auth-step-success" class="auth-step" style="display: none;">
<h2>✅ Success!</h2>
<p>Welcome, <span id="auth-success-name"></span>!</p>
<button onclick="closeAuthModalAndReload()">Continue</button>
</div>
</div>
</div>
<script>
// Function to perform the search
function performSearch() {
const keywords = document.getElementById("search-keywords").value;
if (!keywords) {
alert("Please enter keywords to search.");
return;
}
// Navigate to the search results page with the keywords as a query parameter
window.location.href = `/search?keywords=${encodeURIComponent(keywords)}`;
}
// Add event listener for keyword search the "Enter" key
document.getElementById("search-keywords").addEventListener("keydown", function(event) {
if (event.key === "Enter") {
event.preventDefault();
performSearch();
}
});
// Function to open the modal
function openModal() {
const modal = document.getElementById("room-list-modal");
const modalContent = document.getElementById("room-list-modal-content");
const closeButton = document.getElementById("close-modal-button");
// Clone the create room section and rooms list
const createRoomSection = document.getElementById("create-room-section").cloneNode(true);
const roomsList = document.getElementById("rooms-list-ul").cloneNode(true);
// Clear previous content and add all sections
document.getElementById("rooms-list-modal-content").innerHTML = '';
document.getElementById("rooms-list-modal-content").appendChild(createRoomSection);
document.getElementById("rooms-list-modal-content").appendChild(roomsList);
modal.style.display = "flex";
modalContent.style.display = "block";
closeButton.style.display = "block";
}
// Function to close the modal
function closeModal() {
const modal = document.getElementById("room-list-modal");
const modalContent = document.getElementById("room-list-modal-content");
const closeButton = document.getElementById("close-modal-button");
modal.style.display = "none";
modalContent.style.display = "none";
closeButton.style.display = "none";
}
// Function to update all room links (no query parameters needed)
function updateRoomLinksWithCurrentParams() {
// No longer needed - links don't use username in query string
// Keeping function for compatibility
}
// Add event listener to the hamburger button
document.getElementById("hamburger-button").addEventListener("click", openModal);
// Theme switching functionality
function toggleTheme() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
// Update the data-theme attribute
html.setAttribute('data-theme', newTheme);
// Save to localStorage
localStorage.setItem('theme', newTheme);
// Update button text for both desktop and mobile
updateThemeButtonText(newTheme);
// Switch highlight.js theme
updateHighlightTheme(newTheme);
}
function updateHighlightTheme(theme) {
const lightTheme = document.getElementById('highlight-theme-light');
const darkTheme = document.getElementById('highlight-theme-dark');
if (theme === 'dark') {
lightTheme.disabled = true;
darkTheme.disabled = false;
} else {
lightTheme.disabled = false;
darkTheme.disabled = true;
}
}
function updateThemeButtonText(theme) {
// Label shows the mode a click switches to.
const label = theme === 'dark' ? 'Light Mode' : 'Dark Mode';
const btn = document.getElementById('theme-toggle-btn');
const btnMobile = document.getElementById('theme-toggle-btn-mobile');
if (btn) btn.textContent = label;
if (btnMobile) btnMobile.textContent = label;
}
// Apply saved theme on page load
function applySavedTheme() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
updateThemeButtonText(savedTheme);
updateHighlightTheme(savedTheme);
}
// Apply theme immediately (before DOMContentLoaded to prevent flash)
applySavedTheme();
// Populate the mobile model dropdown dynamically
document.addEventListener('DOMContentLoaded', (event) => {
const modelSelectMobile = document.getElementById("model-select-mobile");
// Ensure theme button text is correct on page load
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
updateThemeButtonText(currentTheme);
// Function to populate the dropdown
function populateModelDropdown(models) {
while (modelSelectMobile.options.length > 1) {
modelSelectMobile.remove(1);
}
models.forEach(modelId => {
const option = document.createElement('option');
option.value = modelId;
option.textContent = modelId;
modelSelectMobile.appendChild(option);
});
}
// Memoization with localStorage (1-minute cache)
const cacheKey = 'modelList';
const cacheExpirationKey = 'modelListExpiration';
const cacheDuration = 60 * 1000; // 1 minute in milliseconds
const cachedData = localStorage.getItem(cacheKey);
const cachedExpiration = localStorage.getItem(cacheExpirationKey);
if (cachedData && cachedExpiration && Date.now() < parseInt(cachedExpiration)) {
const models = JSON.parse(cachedData);
populateModelDropdown(models);
} else {
fetch('/models')
.then(response => response.json())
.then(data => {
const models = data.models;
populateModelDropdown(models);
localStorage.setItem(cacheKey, JSON.stringify(models));
localStorage.setItem(cacheExpirationKey, Date.now() + cacheDuration);
})
.catch(error => console.error("Error fetching models:", error));
}
});
// Room tab switching
function switchRoomTab(tab) {
const publicTab = document.getElementById('public-rooms-tab');
const privateTab = document.getElementById('private-rooms-tab');
const publicSection = document.getElementById('public-rooms-section');
const privateSection = document.getElementById('private-rooms-section');
if (tab === 'public') {
publicTab.classList.add('active');
privateTab.classList.remove('active');
publicSection.style.display = 'block';
privateSection.style.display = 'none';
} else {
privateTab.classList.add('active');
publicTab.classList.remove('active');
privateSection.style.display = 'block';
publicSection.style.display = 'none';
}
}
// Authentication modal functions
let pendingEmail = '';
function showAuthModal() {
document.getElementById('auth-modal').style.display = 'flex';
showAuthStep('email');
}
function closeAuthModal() {
document.getElementById('auth-modal').style.display = 'none';
clearAuthErrors();
}
function closeAuthModalAndReload() {
closeAuthModal();
window.location.reload();
}
function showAuthStep(step) {
document.querySelectorAll('.auth-step').forEach(el => el.style.display = 'none');
document.getElementById('auth-step-' + step).style.display = 'block';
clearAuthErrors();
}
function clearAuthErrors() {
document.querySelectorAll('.error-message').forEach(el => el.textContent = '');
}
function backToEmailStep() {
showAuthStep('email');
}
async function sendOTP() {
const email = document.getElementById('auth-email').value.trim();
const errorEl = document.getElementById('auth-email-error');
if (!email) {
errorEl.textContent = 'Please enter your email';
return;
}
try {
const response = await fetch('/auth/send-otp', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email})
});
const data = await response.json();
if (response.ok) {
pendingEmail = email;
document.getElementById('auth-email-display').textContent = email;
showAuthStep('otp');
} else {
errorEl.textContent = data.error || 'Failed to send code';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
async function verifyOTP() {
const otpCode = document.getElementById('auth-otp').value.trim();
const errorEl = document.getElementById('auth-otp-error');
if (!otpCode) {
errorEl.textContent = 'Please enter the code';
return;
}
try {
const response = await fetch('/auth/verify-otp', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: pendingEmail, otp_code: otpCode})
});
const data = await response.json();
if (response.ok) {
if (data.needs_display_name) {
showAuthStep('name');
} else {
document.getElementById('auth-success-name').textContent = data.user.display_name;
showAuthStep('success');
}
} else {
errorEl.textContent = data.error || 'Invalid code';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
async function claimName() {
const displayName = document.getElementById('auth-display-name').value.trim();
const errorEl = document.getElementById('auth-name-error');
if (!displayName) {
errorEl.textContent = 'Please enter a display name';
return;
}
try {
const response = await fetch('/auth/claim-name', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({display_name: displayName})
});
const data = await response.json();
if (response.ok) {
document.getElementById('auth-success-name').textContent = data.user.display_name;
showAuthStep('success');
} else {
errorEl.textContent = data.error || 'Failed to claim name';
}
} catch (error) {
errorEl.textContent = 'Network error. Please try again.';
}
}
// Room management functions
async function forkRoom(roomId) {
const makePrivate = confirm('Fork as private room? (Cancel for public)');
try {
const response = await fetch(`/api/rooms/${roomId}/fork`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({private: makePrivate})
});
const data = await response.json();
if (response.ok) {
window.location.href = `/chat/${data.room.name}`;
} else {
alert(data.error || 'Failed to fork room');
}
} catch (error) {
alert('Network error. Please try again.');
}
}
async function archiveRoom(roomId) {
if (!confirm('Archive this room? It will be hidden but not deleted.')) {
return;
}
try {
const response = await fetch(`/api/rooms/${roomId}/archive`, {
method: 'POST',
headers: {'Content-Type': 'application/json'}
});
const data = await response.json();
if (response.ok) {
alert('Room archived successfully!');
window.location.reload();
} else {
alert(data.error || 'Failed to archive room');
}
} catch (error) {
alert('Network error. Please try again.');
}
}
async function deleteRoom(roomId) {
if (!confirm('Delete this room permanently? This cannot be undone!')) {
return;
}
// Determine if current room is private by checking if we're in private section
const currentRoomElement = document.querySelector(`[data-room-id="${roomId}"]`);
const isPrivate = currentRoomElement ? currentRoomElement.classList.contains('private-room') : false;
try {
const response = await fetch(`/api/rooms/${roomId}/delete`, {
method: 'DELETE',
headers: {'Content-Type': 'application/json'}
});
const data = await response.json();
if (response.ok) {
// Navigate to the top room of the appropriate list (public or private)
const roomList = isPrivate
? document.querySelectorAll('#private-rooms-section .rooms-list li')
: document.querySelectorAll('#public-rooms-section .rooms-list li');
// Find first room that isn't the deleted one
let targetRoom = null;
for (let room of roomList) {
if (room.getAttribute('data-room-id') != roomId) {
targetRoom = room;
break;
}
}
if (targetRoom) {
// Navigate to the first available room in the list
const link = targetRoom.closest('a');
if (link) {
window.location.href = link.href;
} else {
window.location.href = '/';
}
} else {
// No other rooms available, go to home
window.location.href = '/';
}
} else {
alert(data.error || 'Failed to delete room');
}
} catch (error) {
alert('Network error. Please try again.');
}
}
</script>
</body>
</html>

301
templates/browse.html Normal file
View file

@ -0,0 +1,301 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Browse Rooms - OpenCompletion</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script>
// Set theme immediately to prevent flash
(function() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
})();
</script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<style>
body {
font-family: Arial, sans-serif;
background-color: var(--bg-page);
color: var(--text-primary);
margin: 0;
padding: 20px;
transition: background-color 0.3s ease, color 0.3s ease;
}
.header {
max-width: 1400px;
margin: 0 auto 30px;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 15px;
}
.header h1 {
color: var(--text-primary);
margin: 0;
transition: color 0.3s ease;
}
.header-actions {
display: grid;
grid-auto-flow: column;
gap: 10px;
}
.btn {
background: linear-gradient(135deg, var(--gradient-start) 0%, var(--gradient-end) 100%);
color: white;
border: none;
border-radius: 5px;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
text-decoration: none;
display: inline-block;
transition: transform 0.2s;
}
.btn:hover {
transform: translateY(-2px);
}
.btn-secondary {
background: #6c757d;
}
.room-tabs {
max-width: 1400px;
margin: 0 auto 20px;
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
gap: 10px;
border-bottom: 2px solid #e1e1e1;
}
.room-tab {
background: none;
border: none;
padding: 12px 24px;
font-size: 16px;
cursor: pointer;
color: var(--text-secondary);
border-bottom: 3px solid transparent;
transition: all 0.3s;
}
.room-tab:hover {
color: var(--button-primary);
}
.room-tab:focus {
outline: none;
background: none;
}
.room-tab.active {
color: var(--button-primary);
border-bottom-color: var(--button-primary);
font-weight: bold;
}
.rooms-container {
max-width: 1400px;
margin: 0 auto;
}
.room-section {
display: none;
}
.room-section.active {
display: block;
}
.rooms-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.room-card {
background: var(--bg-card);
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s, background-color 0.3s ease;
cursor: pointer;
text-decoration: none;
color: inherit;
display: block;
}
.room-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.room-card-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
margin-bottom: 10px;
}
.room-name {
font-size: 20px;
font-weight: bold;
color: var(--button-primary);
margin: 0 0 5px 0;
}
.room-title {
color: var(--text-secondary);
font-size: 14px;
margin: 8px 0;
line-height: 1.4;
transition: color 0.3s ease;
}
.room-meta {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
gap: 15px;
margin-top: 12px;
font-size: 14px;
color: var(--text-muted);
transition: color 0.3s ease;
}
.room-meta-item {
display: grid;
grid-auto-flow: column;
align-items: center;
gap: 5px;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-muted);
transition: color 0.3s ease;
}
.empty-state h3 {
color: var(--text-secondary);
margin-bottom: 10px;
transition: color 0.3s ease;
}
.auth-prompt {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 8px;
padding: 20px;
text-align: center;
margin-bottom: 20px;
}
.auth-prompt button {
margin-top: 10px;
}
@media (max-width: 768px) {
.rooms-grid {
grid-template-columns: 1fr;
}
.header {
grid-template-columns: 1fr;
}
.header-actions {
grid-auto-flow: row;
}
}
</style>
</head>
<body>
<div class="header">
<h1>🚀 Browse Rooms</h1>
<div class="header-actions">
<a href="/" class="btn">🏠 Home</a>
{% if user %}
<a href="/profile" class="btn btn-secondary">👤 {{ user.display_name }}</a>
{% else %}
<a href="/auth" class="btn btn-secondary">🔐 Sign In</a>
{% endif %}
</div>
</div>
<div class="room-tabs">
<button class="room-tab active" onclick="switchTab('public', this)">
🌍 Public Rooms
</button>
<button class="room-tab" onclick="switchTab('private', this)">
🔐 Private Rooms
</button>
</div>
<div class="rooms-container">
<!-- Public Rooms -->
<div id="public-section" class="room-section active">
{% if public_rooms %}
<div class="rooms-grid">
{% for room in public_rooms %}
<a href="{{ url_for('chat', room_name=room.name) }}" class="room-card">
<div class="room-card-header">
<h3 class="room-name">{{ room.name }}</h3>
<span class="badge badge-public">Public</span>
</div>
{% if room.title %}
<p class="room-title">{{ room.title }}</p>
{% endif %}
<div class="room-meta">
<span class="room-meta-item">
👥 {{ room.get_active_users()|length }} active
</span>
</div>
</a>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<h3>No public rooms yet</h3>
<p>Be the first to create one!</p>
<a href="/" class="btn">Create a Room</a>
</div>
{% endif %}
</div>
<!-- Private Rooms -->
<div id="private-section" class="room-section">
{% if user %}
{% if private_rooms %}
<div class="rooms-grid">
{% for room in private_rooms %}
<a href="{{ url_for('chat', room_name=room.name) }}" class="room-card">
<div class="room-card-header">
<h3 class="room-name">{{ room.name }}</h3>
<span class="badge badge-private">Private</span>
</div>
{% if room.title %}
<p class="room-title">{{ room.title }}</p>
{% endif %}
<div class="room-meta">
<span class="room-meta-item">
👥 {{ room.get_active_users()|length }} active
</span>
</div>
</a>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<h3>No private rooms yet</h3>
<p>Create your first private room!</p>
<a href="/" class="btn">Create a Room</a>
</div>
{% endif %}
{% else %}
<div class="auth-prompt">
<h3>🔒 Private rooms are only visible to you</h3>
<p>Sign in to create and access your private rooms</p>
<a href="/auth" class="btn">Sign In / Sign Up</a>
</div>
{% endif %}
</div>
</div>
<script>
function switchTab(tab, element) {
// Update tab buttons
document.querySelectorAll('.room-tab').forEach(btn => {
btn.classList.remove('active');
});
element.classList.add('active');
// Update sections
document.querySelectorAll('.room-section').forEach(section => {
section.classList.remove('active');
});
document.getElementById(tab + '-section').classList.add('active');
}
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more