Master PDF · v1

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.

Tip: Browser's print dialog → "Save as PDF" produces the file. Use per-section "Print" to export sub-PDFs.

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.

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.json

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"] }

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);
};

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;
}

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.`;

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.
`;

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']
};

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 }]);
};

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
});

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.`;

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."
}

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 });
  }
});

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.

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.
End of Master PDF · Kaspa Creative Agent Blueprint · 2026-10-15