Kaspa Creative Agent — Build Blueprint
A single document containing every prompt, schema, component, and architectural note needed to reconstruct the ~2000-line Agent page from scratch. Each section is a self-contained "sub-PDF" you can print individually, or print everything as one master document.
Contents
- Project Overview & Goals· README
- File Map & Component Tree· STRUCTURE
- Core Entity Schemas· SCHEMA
- handleSend — The Main Send Loop· CORE LOGIC
- Intent Routers — tryResearchIntent· INTENT
- Cinematic Video Prompt Template· PROMPT
- HyperFrames HTML Prompt Template· PROMPT
- Slide Editor Edit Prompt + Schema· PROMPT
- Parallel Acknowledgment Prompt· PROMPT
- Story + Voice Narration Prompt· PROMPT
- Whitepaper / Doc Prompt· PROMPT
- kaspa_creative_agent — Agent Config· AGENT
- Plan Mode (planAgentTask)· BACKEND
- Fullscreen Editor Overlay· UI
- Rebuild Checklist — Step by Step· CHECKLIST
1. Project Overview & Goals
High-level summary of what the Agent page is, who it serves, and what success looks like.
Kaspa Creative Agent — a single-page chat-first creative studio where a user can:
• Generate images, videos, slides, and HyperFrames (self-contained animated HTML) via natural language.
• Use a video-editor-style fullscreen overlay on the live preview (timeline, layers, send-edit).
• Plan tasks before execution (Plan / Hyper / Edit gemstone modes).
• Persist every thought/action/result in an Agent Notebook (NotebookEntry entity).
• Pay 1 KAS per video via a generated Kaspa wallet (gates GenerateVideo calls).
• Pull through specialized flows: Slide Builder, Storyboard, Agent6ix, Script Builder, Explainer,
Timeline Studio, Multi-clip Editor, Drawing Canvas, Video Upscaler, Voice Agent.
Architectural pillars:
1. Single source-of-truth chat in pages/Agent.jsx (≈2000 lines, near hard cap).
2. Intent routers — each user message is classified (study, competitor, keyword, landing,
claymation, script, slide-deck, whitepaper, video, image, HTML) before LLM dispatch.
3. Branded vs neutral output gated by KaspaBrandToggle + brandContext (sessionStorage).
4. Bridge layer (lib/agentBridge.js) so Agent 1 and Agent 2 (AE workspace) can swap scenes.
5. All long-running work shows a Progress + Kaspa facts ticker. No silent waits.2. File Map & Component Tree
Exact file layout and which file owns which responsibility.
pages/
Agent.jsx ← THE page (chat, intent routers, plan, send loop). ~2000 lines.
AgentV2.jsx ← AE workspace (separate page; bridge keeps them in sync).
AgentBlueprintPDF.jsx ← THIS document.
components/
AgentMessageBubble.jsx ← Renders one chat row (user or assistant + media + markdown).
AgentAvatar.jsx ← Circular agent avatar with pulse when busy.
AgentToolCallPreview.jsx ← Compact tool-call card (function name + status + args).
AgentToggle.jsx ← Switch between Agent 1 ↔ Agent 2.
AgentV2LivePreview.jsx ← Floating pill showing Agent 2's current scene from inside Agent 1.
InlineThoughtStream.jsx ← Live timeline of notebook entries inside chat.
NotebookAutoLogger.jsx ← Side-effect component, no UI — auto-logs messages.
useAgentNotebook.js ← Hook: list/create/subscribe to NotebookEntry.
HtmlSlidePreview.jsx ← iframe live preview + fullscreen portal + editor overlay mount.
FullscreenEditorOverlay.jsx ← Floating video-editor UI: timeline, transport, tools, send-edit.
GemstonePyramid.jsx ← Plan / Hyper / Edit + Draw gemstone selector.
PlanningStage.jsx ← Plan approval card (steps + run/cancel).
KaspaWalletModal.jsx ← Generate / show / disconnect Kaspa wallet.
KaspaBrandToggle.jsx ← Toggle teal Kaspa branding vs neutral.
KaspaFactsTicker.jsx ← Rotating Kaspa facts during loading.
MicInputButton.jsx ← Web Speech API + Whisper fallback.
VideoIconButton.jsx ← Video-thumbnail-icon style action button.
CreationHistory.jsx ← Drawer of past Logo records.
TryAskingPills.jsx ← Inline grid of starter prompts.
TemplatesPicker.jsx ← Tesla/Web3/CapCut/Prophecy template modal.
HFMotionPicker.jsx ← HyperFrames block library.
TimelineStudio.jsx ← Full timeline-based editor modal.
MultiClipTimeline.jsx ← Multi-clip NLE.
VideoTimeline.jsx ← Auto-analyze + auto-prompt from MP4.
InlineSlideBuilder.jsx ← Slide-deck editor with target-locking.
Agent6ix.jsx ← Fullscreen 1-Shot scene canvas.
ScriptBuilderPipeline.jsx ← Multi-stage script interview + storyboard + TTS.
ExplainerVideoBuilder.jsx ← Multi-scene cinematic explainer.
ProductAdScripter.jsx ← Product ad script generator.
DesignBoard.jsx ← Freeform-style sketch storyboard.
DrawSlideCanvas.jsx ← Draw → upload → new scene.
VoiceAgent.jsx ← Voice-driven creative loop.
LearnFlashcards.jsx ← Study flashcards UI.
ClaymationBuilder.jsx ← Stop-motion ad builder.
LiveLandingBuilder.jsx ← Cinematic landing page builder.
CompetitorResearchCard.jsx, KeywordPlannerCard.jsx, StudyAutoCard.jsx ← Research result cards.
lib/
agentBridge.js ← Cross-agent scene + edit queue.
brandContext.js ← shouldAskBrand + isKaspaBrand + persisted brand toggle.
competitorIntent.js, keywordIntent.js, studyIntent.js,
landingIntent.js, claymationIntent.js, scriptIntent.js, routeToA2.js
← Intent detectors + extractors. KEEP SIMPLE regexes.
persistAgentConversation.js ← Survives refresh.
entities/
NotebookEntry.json, TrainingMemory.json, Logo.json, ApiKey.json,
VideoCredit.json, OrchestratorRun.json, OrchestratorEvent.json,
SlashCommand.json, AssetDraft.json, Asset.json, DirectorMemory.json3. Core Entity Schemas
The four schemas the Agent page reads/writes constantly. Copy verbatim.
// entities/NotebookEntry.json
{
"name": "NotebookEntry",
"type": "object",
"properties": {
"kind": { "type": "string", "enum": ["thought","action","result","note","system","user"], "default": "thought" },
"title": { "type": "string" },
"body": { "type": "string" },
"tags": { "type": "array", "items": { "type": "string" } },
"media_url": { "type": "string" },
"session_id": { "type": "string" },
"pinned": { "type": "boolean", "default": false }
},
"required": ["kind","body"],
"rls": { "create": { "created_by_id": "{{user.id}}" }, "read": { "created_by_id": "{{user.id}}" },
"update": { "created_by_id": "{{user.id}}" }, "delete": { "created_by_id": "{{user.id}}" } }
}
// entities/Logo.json — every generated media auto-saves here
{
"name": "Logo",
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"media_url": { "type": "string" },
"media_type": { "type": "string", "enum": ["image","video"], "default": "image" },
"tags": { "type": "array", "items": { "type": "string" } },
"is_shared": { "type": "boolean", "default": false },
"is_ai_generated": { "type": "boolean", "default": false },
"generation_prompt": { "type": "string" },
"kaspa_address": { "type": "string" }
},
"required": ["title","media_url","media_type"]
}
// entities/VideoCredit.json — 1 KAS per video gate
{ "name":"VideoCredit","type":"object",
"properties":{ "tx_hash":{"type":"string"}, "user_email":{"type":"string"},
"amount_kas":{"type":"number"}, "consumed":{"type":"boolean","default":false},
"consumed_at":{"type":"string","format":"date-time"} },
"required":["tx_hash","user_email","amount_kas"] }
// entities/TrainingMemory.json — distilled learnings the agent rereads
{ "name":"TrainingMemory","type":"object",
"properties":{ "source_type":{"type":"string","enum":["url","image","video","text","instruction","feedback"]},
"source_ref":{"type":"string"}, "title":{"type":"string"},
"summary":{"type":"string"}, "key_facts":{"type":"array","items":{"type":"string"}},
"tags":{"type":"array","items":{"type":"string"}},
"weight":{"type":"number","default":1}, "is_active":{"type":"boolean","default":true} },
"required":["source_type","summary"] }4. handleSend — The Main Send Loop
This is the brain of the page. Order of checks matters — keep them in this exact order.
const handleSend = async (skipPaymentCheck = false) => {
if ((!input.trim() && selectedFiles.length === 0) || loading || planLoading || planExecuting) return;
// 1. Expand slash command (/deep, /story, …)
const slashHit = resolveSlash(input);
const userMessage = slashHit ? slashHit.expanded : input;
// 2. Research / specialty intents — each returns true if it handled the message
if (tryResearchIntent({ userMessage, selectedFiles, setInput, setSelectedFiles, setMessages })) return;
// 3. Brand gate — ask once whether output is for Kaspa or neutral
if (shouldAskBrand(userMessage)) {
setPendingBrandRequest({ content: userMessage, files: selectedFiles });
setMessages(prev => [...prev,
{ role:'user', content:userMessage, file_urls:selectedFiles.map(f=>f.url) },
{ role:'assistant', _brandAsk:true,
content:"Quick check — is this for **Kaspa**, or a different brand?", file_urls:[] }]);
setInput('');
return;
}
if (!brandContext) {
const inferred = detectBrandFromMessage(userMessage);
if (inferred) { const ctx = { brand: inferred, at: Date.now() };
setBrandContext(ctx); setBrandContextState(ctx); }
}
// 4. Script / narrative video → open ScriptBuilderPipeline
const { wantsScript, isNarrativeVideo } = detectScriptIntent(userMessage);
if ((wantsScript || isNarrativeVideo) && !showSlideBuilder) { /* open pipeline */ return; }
rememberLastRequest(userMessage, selectedFiles);
// 5. Parallel ack LLM (always fires, never blocks)
if (userMessage.trim()) { fireAcknowledgment(userMessage, selectedFiles.length > 0); }
// 6. Cross-agent route to Agent 2
if (userMessage.trim() && shouldRouteToA2(userMessage)) { routeToA2(userMessage); /* nav */ return; }
// 7. Slide Builder open → AI-edit the slides instead of generating
if (showSlideBuilder && userMessage.trim()) { handleEditSlidesViaChat(scopedMsg); return; }
// 8. Video gate — 1 KAS unless admin/unlimited or already paid
const wantsSlideDeck = /\b(slide deck|hyperframes|html slide)\b/i.test(userMessage);
const wantsVideo = !wantsSlideDeck && /\b(video|animate|motion|clip|reel)\b/i.test(userMessage);
const isUnlimited = user?.role === 'admin' || user?.email === 'mrzeku12@gmail.com';
if (wantsVideo && !skipPaymentCheck && !isUnlimited) {
try { const r = await base44.functions.invoke('consumeVideoCredit', {});
if (!r.data?.ok) throw new Error(); }
catch { setPendingVideoMessage({ content:userMessage, files:selectedFiles });
setShowPaymentModal(true); return; }
}
setInput(''); setSelectedFiles([]);
// 9. No agent → plan first (planAgentTask), then execute. Agent flow streams via subscribeToConversation.
if (!conversation) { /* planMode check → planAgentTask → executeRequest */ return; }
setLoading(true);
await base44.agents.addMessage(conversation, {
role: 'user', content: userMessage, file_urls: selectedFiles.map(f => f.url)
});
setLoading(false);
};5. Intent Routers — tryResearchIntent
Each intent detector returns true if it owns the message. Add new intents here, not inside handleSend.
// components/useResearchIntents.js
import { detectCompetitorIntent, extractNiche } from '@/lib/competitorIntent';
import { detectKeywordIntent, extractSeedKeyword } from '@/lib/keywordIntent';
import { tryStudyIntent } from './useStudyIntent';
import { detectStudyIntent } from '@/lib/studyIntent';
import { detectLandingIntent, extractLandingTheme } from '@/lib/landingIntent';
import { detectClaymationIntent, extractClaymationSubject } from '@/lib/claymationIntent';
export function tryResearchIntent({ userMessage, selectedFiles, setInput, setSelectedFiles, setMessages }) {
if (detectClaymationIntent(userMessage)) {
const subject = extractClaymationSubject(userMessage);
setInput(''); setSelectedFiles([]);
setMessages(prev => [...prev,
{ role:'user', content:userMessage, file_urls:selectedFiles.map(f=>f.url) },
{ role:'assistant', _claymation:{ subject }, content:'', file_urls:[] }]);
return true;
}
if (detectLandingIntent(userMessage)) {
const theme = extractLandingTheme(userMessage);
const brandName = theme.split(/\s+/).slice(0,2).map(w => w[0].toUpperCase()+w.slice(1)).join('');
setMessages(prev => [...prev,
{ role:'user', content:userMessage, file_urls:selectedFiles.map(f=>f.url) },
{ role:'assistant', _liveLanding:{ theme, brandName }, content:'', file_urls:[] }]);
setInput(''); setSelectedFiles([]); return true;
}
if (detectStudyIntent(userMessage).match) {
tryStudyIntent({ userMessage, showSlideBuilder:false, setInput, setSelectedFiles, setMessages });
return true;
}
if (detectKeywordIntent(userMessage)) {
const seed = extractSeedKeyword(userMessage) || userMessage;
setMessages(prev => [...prev,
{ role:'user', content:userMessage, file_urls:selectedFiles.map(f=>f.url) },
{ role:'assistant', _keywordPlanner:{ seed, extraContext:userMessage },
content:`🔍 Researching keywords for **${seed}**`, file_urls:[] }]);
setInput(''); setSelectedFiles([]); return true;
}
if (detectCompetitorIntent(userMessage)) {
const niche = extractNiche(userMessage) || userMessage;
setMessages(prev => [...prev,
{ role:'user', content:userMessage, file_urls:selectedFiles.map(f=>f.url) },
{ role:'assistant', _competitorResearch:{ niche, extraContext:userMessage },
content:`🔎 Researching **${niche}**`, file_urls:[] }]);
setInput(''); setSelectedFiles([]); return true;
}
return false;
}6. Cinematic Video Prompt Template
Verbatim prompt prepended to every GenerateVideo call. Locks the output into keynote-grade cinematography.
// Prepend this to the user prompt before calling GenerateVideo const CINEMATIC_VIDEO_SUFFIX = ` CINEMATOGRAPHY (REQUIRED): - ARRI Alexa 65 look — wide dynamic range, soft highlight roll-off, deep filmic blacks. - Anamorphic 2.39:1 framing where appropriate; otherwise 16:9 with shallow DOF. - Lighting: motivated practicals + soft key + rim. NO flat overhead fluorescents. - Camera motion: slow dolly, controlled push-in, or locked tripod. NO whip pans, NO zoom snaps. - Color: graded teal-and-orange OR neutral-with-pastel-accent. Never oversaturated. - Pacing: one idea per shot. Hold frames long enough to breathe. PROHIBITED (will be rejected): - Generic AI motion-graphics (rotating cubes, particle swarms, neon grids without purpose). - Cartoonish "AI" smoothness — preserve micro-imperfections, hand-held breath. - Stock-footage tropes (server rooms, neural-network visualizations, Olympic-style runners). AUDIO (REQUIRED — Veo renders silent by default unless asked): - Cinematic sound design: room tone, motion whooshes, low-end impact on key beats. - Modern uplifting synth bed at moderate volume. - If on-screen text or characters speak, include broadcast-quality VO that reads it naturally. - Light reverb tail, satisfying button-hit on the final frame.`; // Image prompt suffix (single frame, editorial) const EDITORIAL_IMAGE_SUFFIX = ` EDITORIAL STANDARDS: - Phase One IQ4 or Hasselblad H6D-100c quality. - Natural light or single-source studio strobe with large softbox. - Composition: rule of thirds OR centered with negative space. NO chaotic compositions. - Color: muted, considered palette. Brand color used as accent (≤15% of frame). - Typography (if any): Space Grotesk, tight tracking, generous leading. - Output: 16:9 unless user specifies otherwise.`;
7. HyperFrames HTML Prompt Template
The system prompt that turns any user request into a self-contained, animated HTML deck.
// Used when intent is HTML / slide-deck / HyperFrames
const HYPERFRAMES_SYSTEM = (userMessage, { isKaspa }) => `
You are a premium UI/UX engineer producing a SELF-CONTAINED HTML document for the user's brief.
USER BRIEF: "${userMessage}"
ABSOLUTE RULES:
1. Return ONLY a single \`\`\`html code block. NO preamble, NO explanation.
2. Single HTML file: <!DOCTYPE html> + <head> with inline <style> + <body> + inline <script>.
3. NO external dependencies except Google Fonts via @import url(...).
4. Typography: Space Grotesk for headings, Inter for body. Load via Google Fonts.
5. Use the EXACT image / video URLs from the brief — never substitute.
6. ${isKaspa ? 'Kaspa teal #4ECDC4 as primary accent, dark gradient background.' :
'Brand-neutral palette chosen to match the brief subject.'}
VISUAL STANDARDS:
- Auto-advance scenes every 4s with smooth 600ms cross-fade.
- Dot navigation pinned bottom-center, active dot scales 1.3 and changes to accent color.
- Subtle Ken Burns zoom on background images. Looping video backgrounds use object-fit: cover.
- Dark gradient overlay (rgba(0,0,0,0.45) → rgba(0,0,0,0.7)) over media for legibility.
- Eyebrow (bold uppercase, 10–11px, 2px letter-spacing) → Title (48–72px, 700 weight) →
Body (16–18px, 1.6 line-height) → optional pill CTA.
- Generous padding (40px+). No content within 24px of viewport edge.
PROHIBITED:
- Lorem ipsum. Stock corporate icons. Bootstrap. Tailwind via CDN. jQuery.
- text-shadow blur > 8px. drop-shadow box-shadow > 0 12px 32px.
- More than 3 fonts. More than 5 accent colors.
`;8. Slide Editor Edit Prompt + Schema
When the Slide Builder is open, every chat message is routed through this LLM call. The JSON schema forces a clean diff.
// components/slideEditorPrompt.js
export function buildSlideEditorPrompt(currentSlidesJSON, instruction) {
return `You are editing a Kaspa slide deck. Current state:
${currentSlidesJSON}
User instruction: "${instruction}"
RULES:
- Return the FULL updated slides array (not a diff) wrapped in { "slides": [...] }.
- Preserve any field the user didn't ask to change.
- ANIMATIONS: textAnim, titleAnim, eyebrowAnim, bodyAnim, ctaAnim ∈
['fade','typewriter','slide-up','slide-left','scale','glow','pulse','shimmer','none'].
- CAMERA: cameraMotion ∈ ['none','ken-burns','zoom-in','zoom-out','pan-left','pan-right'].
- COLORS: titleColor / eyebrowColor / bodyColor / ctaColor — accept named (red, gold, rainbow)
or hex (#ff0080). Map "rainbow" → linear-gradient via inline style.
- DURATION: 1–60 seconds. LOOP: boolean.
- TARGET LOCK: if instruction is prefixed [TARGET LOCKED → Scene N FIELD], apply ONLY to that
field on that scene. Do NOT touch anything else.
- AGENT 6IX prefix: apply only to specified scene; map slide-wide animation requests onto
textAnim AND every per-field anim.`;
}
export const SLIDE_EDITOR_SCHEMA = {
type: 'object',
properties: {
slides: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string' },
eyebrow: { type: 'string' }, title: { type: 'string' },
body: { type: 'string' }, cta: { type: 'string' },
mediaUrl: { type: 'string' }, mediaType: { type: 'string' },
textAnim: { type: 'string' }, cameraMotion: { type: 'string' },
eyebrowAnim: { type: 'string' }, titleAnim: { type: 'string' },
bodyAnim: { type: 'string' }, ctaAnim: { type: 'string' },
eyebrowColor: { type: 'string' }, titleColor: { type: 'string' },
bodyColor: { type: 'string' }, ctaColor: { type: 'string' },
loop: { type: 'boolean' }, duration: { type: 'number' }
},
required: ['id']
}
}
},
required: ['slides']
};9. Parallel Acknowledgment Prompt
Fires the moment the user sends a message — guarantees instant feedback even before heavy work starts.
const fireAcknowledgment = async (userMessage, hasFile) => {
const res = await base44.integrations.Core.InvokeLLM({
prompt: `You are the Kaspa Creative Agent acknowledging a user's request.
Respond in ONE short sentence (max 20 words) that:
1. Confirms you understood what they want (briefly restate it).
2. Says you're working on it.
Be warm, direct, on-brand. NO emojis. NO preamble like "Got it!".
User said: "${userMessage}"${hasFile ? ' (they also attached a file)' : ''}
Examples:
- "Building your glass apple input box with typewriter and hover effects now."
- "On it — cloning that 1:1 with your text swapped in."
- "Drafting the Kaspa motion ad with the starburst background, one moment."
Respond with just the acknowledgment sentence, nothing else.`,
});
const ack = (typeof res === 'string' ? res : res?.text || res?.content || '')
.trim().replace(/^["']|["']$/g, '');
if (ack) setMessages(prev => [...prev,
{ role:'assistant', content:ack, file_urls:[], _isAck:true }]);
};10. Story + Voice Narration Prompt
When the user wants a "tell me a story / narrate" output — written then read aloud with GenerateSpeech.
// Detect
const isStory = /\b(tell (me )?a story|write (me )?a story|story about|narrate|narration|voice ?over|voiceover|read (it )?aloud|spoken word|short story|bedtime story)\b/i.test(userMessage);
// 1) Write
const scriptRes = await base44.integrations.Core.InvokeLLM({
prompt: `You are a master storyteller. Write a short, vivid, cinematic story (250–450 words)
based on the user's request below. The story will be read ALOUD by a TTS voice, so:
- NO markdown, NO headings, NO emoji, NO stage directions.
- Short paragraphs separated by blank lines.
- Generous punctuation (commas, periods, ellipses) so the voice breathes naturally.
- Strong hook in the first sentence. Build, then land an emotional or surprising ending.
- Do NOT mention Olympics, AI labs, server rooms, neural networks, or generic tech tropes
unless the user explicitly asks.
User request: "${userMessage}"
Return ONLY the story text — no title, no preamble.`,
file_urls: allFileUrls,
});
// 2) Narrate
const safeText = storyText.slice(0, 4800); // GenerateSpeech caps at 5000 chars
const { url: audioUrl } = await base44.integrations.Core.GenerateSpeech({
text: safeText,
voice: 'honey', // warm, soft — best for narration
});11. Whitepaper / Doc Prompt
Generates editable Google-Docs-style whitepapers inside chat (rendered by WhitepaperDoc).
const WHITEPAPER_PROMPT = (userMessage) => `You are an expert technical writer producing
a polished, Google-Docs-style WHITEPAPER for the user's brief.
USER BRIEF: "${userMessage}"
OUTPUT RULES (STRICT):
- Return ONLY a fenced block:
\`\`\`whitepaper:<Short Title Here>
<body HTML here>
\`\`\`
- Body HTML is plain semantic HTML — no <html>, <head>, <body>, <style>, <script>.
- Use <h1> once for title, <h2> for sections, <h3> for subsections, <p>, <ul>/<ol>/<li>,
<blockquote>, <table>/<tr>/<th>/<td>, <strong>/<em>, <hr>, <code>.
- Structure: Abstract → Introduction → Background → Approach/Architecture → Details →
Use Cases → Risks/Considerations → Roadmap → Conclusion → References.
- 800–1500 words. Real substance, not filler. Professional tone. No emojis.
- User edits result directly in browser.`;12. kaspa_creative_agent — Agent Config
The conversational agent backing pages/Agent.jsx. Drop this into agents/kaspa_creative_agent.json.
{
"description": "Kaspa Creative Agent — branded media creation. Generates images, videos, slide decks, HyperFrames, scripts, and answers brand questions.",
"instructions": "You are the Kaspa Creative Agent. You help users create on-brand media for the Kaspa cryptocurrency (teal #4ECDC4, modern, premium). When users ask for non-Kaspa work, drop the teal accents and watermark.\n\nWORKFLOW:\n1. Briefly acknowledge what the user wants.\n2. Pick the right tool: GenerateImage, GenerateVideo, InvokeLLM (for HTML / answers), GenerateSpeech (narration), UploadFile (intermediate).\n3. For HTML output, ALWAYS return a single self-contained \`\`\`html code block.\n4. For video output, include the cinematic suffix and explicit AUDIO instructions.\n5. Save every result to the Logo entity with title + generation_prompt + tags.\n6. Persist key decisions to TrainingMemory when the user gives feedback.\n\nNEVER:\n- Use generic AI motion-graphics clichés.\n- Output Lorem ipsum.\n- Charge twice for the same video (check VideoCredit first).\n- Mention Olympics, neural networks, server rooms unless asked.",
"tool_configs": [
{ "entity_name": "Logo", "allowed_operations": ["create","update","read"] },
{ "entity_name": "TrainingMemory", "allowed_operations": ["create","update","read"] },
{ "entity_name": "NotebookEntry", "allowed_operations": ["create","read"] },
{ "entity_name": "VideoCredit", "allowed_operations": ["read","update"] }
],
"whatsapp_greeting": "Hey — Kaspa Creative Agent here. Send me a brief and I'll build it.",
"telegram_greeting": "Hey — Kaspa Creative Agent here. Send me a brief and I'll build it."
}13. Plan Mode (planAgentTask)
When PlanMode is on, the agent first calls a backend function to produce a step list the user can approve.
// functions/planAgentTask.js — returns { plan: { summary, steps: [{ title, icon }] } }
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.31';
Deno.serve(async (req) => {
try {
const base44 = createClientFromRequest(req);
const user = await base44.auth.me();
if (!user) return Response.json({ error:'Unauthorized' }, { status:401 });
const { user_message, has_file } = await req.json();
const res = await base44.integrations.Core.InvokeLLM({
prompt: `Plan the steps to fulfill this user request as a short list (2–5 steps).
Each step has a short title and one of these icons: search, write, image, video, slides, code, voice, deliver.
Return JSON: { "summary": "...", "steps": [{ "title": "...", "icon": "..." }] }.
Request: "${user_message}"${has_file ? ' (file attached)' : ''}`,
response_json_schema: {
type: 'object',
properties: {
summary: { type:'string' },
steps: { type:'array', items: {
type:'object',
properties:{ title:{type:'string'}, icon:{type:'string'} },
required:['title','icon'] } }
},
required:['summary','steps']
}
});
return Response.json({ plan: res });
} catch (err) {
return Response.json({ error: err.message }, { status:500 });
}
});14. Fullscreen Editor Overlay
Floating video-editor UI mounted in the fullscreen portal of HtmlSlidePreview. See components/FullscreenEditorOverlay.jsx for the full file — this is the contract.
<FullscreenEditorOverlay
onExit={exitFullscreen}
onReload={handleReload}
onSendEdit={(text) => {
try { sessionStorage.setItem('kaspa_agent_pending_input', text); } catch {}
window.dispatchEvent(new CustomEvent('kaspa-agent-edit', { detail: text }));
}}
durationGuess={12}
/>
// On the Agent page, a one-line useEffect picks up the edit and runs handleSend:
useEffect(() => {
const onEdit = (e) => {
const t = e.detail;
if (typeof t === 'string' && t.trim()) {
setInput(t);
setTimeout(() => handleSend(), 80);
}
};
window.addEventListener('kaspa-agent-edit', onEdit);
return () => window.removeEventListener('kaspa-agent-edit', onEdit);
}, []);
// Features (locked):
// - Auto-hides after 3.5s idle, wiggle to reveal.
// - Top bar: layers · reload · export · hide UI · exit.
// - Bottom dock: timeline scrubber (clickable), transport (skip/play/skip),
// tool pills (Text · Media · Audio · Cut · FX) that prefill the edit field,
// Apply input wired to onSendEdit.15. Rebuild Checklist — Step by Step
Follow in order. Each step is one merge.
[ ] 1. Create entities: NotebookEntry, Logo, VideoCredit, TrainingMemory.
[ ] 2. Add agent config: agents/kaspa_creative_agent.json (see Sub-PDF "AGENT").
[ ] 3. Backend functions: planAgentTask, consumeVideoCredit, verifyKaspaPayment,
generateKaspaWallet, analyzeImageForMotion. (Reuse existing — listed in dev comments.)
[ ] 4. Drop lib/ intent detectors (one file each — keep regexes simple).
[ ] 5. Build components from "File Map" — each in its own file. Most are 60–250 lines.
[ ] 6. Create pages/Agent.jsx with this skeleton:
- State: messages, input, selectedFiles, plan, planLoading, planExecuting,
conversation, user, brandContext, builderSlides, lockedTarget, etc.
- useEffect on mount: base44.agents.createConversation + subscribeToConversation.
- useEffect persist messages via lib/persistAgentConversation.js.
- useEffect listen for 'kaspa-agent-edit' window event → setInput + handleSend.
- useEffect auto-save every generated media URL to Logo (dedupe via Set ref).
- handleSend (see Sub-PDF "CORE LOGIC").
- executeRequest (story / whitepaper / slide-deck / video / image / HTML branches).
- Render: sticky sub-header, messages list, planning stage, loader,
input bar with GemstonePyramid, MicInputButton, VideoIconButton,
plus every modal (TemplatesPicker, HFMotionPicker, etc.) at the bottom.
[ ] 7. Wire App.jsx route: <Route path="/agent" element={<Agent />} />.
[ ] 8. Smoke test: send "build a glass apple input with typewriter" → expect HTML preview
+ fullscreen editor working + edit button feeding back into chat.
[ ] 9. Smoke test: send "make a 6s cinematic Kaspa ad" → expect VideoCredit gate, then video.
[ ] 10. Smoke test: open Notebook drawer → expect every thought/action/result persisted.