5.3 KiB
5.3 KiB
Strudel AI Integration Plan
Overview
Add an AI assistant to strudel.html that lets the user describe music in natural language and have the AI write/modify Strudel code in the editor.
Confirmed Design Decisions
- API format: OpenAI-compatible endpoint (covers OpenAI, OpenRouter, Ollama, etc.)
- AI behavior: Auto-detect whether to modify existing code or write new code
- Chat panel: Always visible, below the editor
- Conversation history: Kept in memory per session; "Clear Chat" button in sidenav resets it
- API key storage: localStorage (visible, acceptable for personal use)
- Auto-play after AI edit: No — user presses Play/Reload manually
- System prompt size: ~500 tokens (modern models already know Strudel)
Layout
strudel-container
├── strudel-controls (Play/Reload buttons) ← top
├── strudel-editor-section (Strudel editor)
└── strudel-ai-panel (AI chat) ← always visible, below editor
├── strudelAIHistory (scrollable, messages grow upward)
└── strudelAIInput (textarea + Send button, pinned to bottom)
divSideNav
├── divSideNavHeader
├── divSideNavBody
│ └── divAISettings ← NEW
│ ├── API URL input
│ ├── API Key input (password)
│ ├── Model name input
│ ├── Save button
│ └── Clear Chat button
├── divRelaySection
└── divVersionBar
Files to Create/Modify
New: www/js/strudel-ai.mjs
Exports:
getAISettings()— reads from localStoragesaveAISettings(url, key, model)— writes to localStoragebuildMessages(history, currentCode, userInput)— constructs messages array for APIcallAI(messages, settings)— fetch to OpenAI-compatible endpointextractCode(responseText)— detects and extracts Strudel code from responseisCodeResponse(text)— returns true if response looks like Strudel code
Modified: www/strudel.html
- Sidenav — add
divAISettingssection indivSideNavBody - Body — add
strudelAIPaneldiv belowstrudel-editor-section - JavaScript — import
strudel-ai.mjs, wire up chat input, handle responses
Modified: www/css/strudel.css
Add styles for:
.strudel-ai-panel— container, flex column.strudel-ai-history— scrollable, flex-grow.strudel-ai-input— row with textarea and button.ai-message— base message style.ai-message-user— right-aligned or distinct style.ai-message-assistant— left-aligned or distinct style.ai-message-error— red error messages#divAISettings— sidenav section styling
System Prompt
You are a Strudel live coding assistant. Strudel is a JavaScript port of TidalCycles for making music in the browser.
Rules:
- If the user asks you to create or modify music/sounds, respond with ONLY valid Strudel JavaScript code. No markdown fences, no explanation.
- If the user asks a question or wants an explanation, respond in plain text only. Do not include code.
- When modifying, preserve the overall structure unless asked to change it completely.
Current code in the editor:
{{CURRENT_CODE}}
Code Detection Logic
A response is treated as Strudel code if it contains any of:
note(,s(,sound(,stack(,samples(,n(,chord(.sound(,.s(,.note(setcps(,setCps(
Otherwise treated as a text response (shown in chat only, editor unchanged).
API Call
fetch(`${apiUrl}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: model,
messages: messages, // [{role, content}, ...]
temperature: 0.7,
max_tokens: 1000
})
})
Conversation History Format
// In-memory array, reset by "Clear Chat"
let conversationHistory = [];
// Each exchange adds two entries:
conversationHistory.push({ role: 'user', content: userInput });
conversationHistory.push({ role: 'assistant', content: aiResponse });
// buildMessages() prepends the system message:
[
{ role: 'system', content: systemPrompt },
...conversationHistory,
{ role: 'user', content: currentUserInput }
]
localStorage Keys
strudel-ai-url— API base URL (e.g.https://api.openai.com/v1)strudel-ai-key— API keystrudel-ai-model— model name (e.g.gpt-4o,claude-3-5-sonnet)
Error Handling
- Network error → show in chat as error message, keep current editor code
- API error (4xx/5xx) → show error message with status code in chat
- Invalid/empty response → show "AI returned an empty response" in chat
- Code injection error → show error in chat, keep previous code
Implementation Steps
- Create
www/js/strudel-ai.mjswith all helper functions - Add AI settings HTML to sidenav
divSideNavBody - Add AI chat panel HTML below editor in
divBody - Add CSS for chat panel and sidenav settings
- Import
strudel-ai.mjsin strudel.html script - Initialize AI settings from localStorage on page load
- Wire Save button in sidenav
- Wire Clear Chat button (resets
conversationHistoryarray, clears chat UI) - Wire Send button and Enter key on textarea
- Implement send handler: build messages → call AI → handle response
- Commit and push