Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
329 commits
Select commit Hold shift + click to select a range
08cd43a
fix: Update prompt to guide llm to provide valid gradient everytime
surajshetty3416 Apr 1, 2026
f77af65
refactor: Option to attach image as context
surajshetty3416 Apr 2, 2026
24055c5
fix: Update prompt to avoid adding emojis
surajshetty3416 Apr 4, 2026
4f7a2ec
fix: Increase throttle duration for streaming
surajshetty3416 Apr 4, 2026
1fedb75
Merge branch 'develop' into ai-driven-page-builder
surajshetty3416 Apr 6, 2026
33149dc
feat: Session based AI page editor
surajshetty3416 Apr 6, 2026
41cc3c0
fix: Use setInnerHTML to maintain reactivity on update via tool
surajshetty3416 Apr 6, 2026
909e4ad
feat: Add ability to add scripts
surajshetty3416 Apr 7, 2026
8446fc2
Merge branch 'develop' into ai-session
surajshetty3416 Apr 7, 2026
60b7661
refactor: Split code into logically isolated files to improve readabi…
surajshetty3416 Apr 8, 2026
76c6489
fix: Update message styling
surajshetty3416 Apr 8, 2026
2d268cd
feat: Add tools that could fetch script on demand and update the exis…
surajshetty3416 Apr 8, 2026
b4461f7
fix: Move atrributes to customAttributes that are not editable via ed…
surajshetty3416 Apr 9, 2026
d6c38d2
feat: List all the blocks that were updated during a conversation
surajshetty3416 Apr 9, 2026
14a5a14
feat: Get chat summary in MD and render md to HTML in chat panel
surajshetty3416 Apr 9, 2026
05d582b
feat: Option to send selected block id as context
surajshetty3416 Apr 9, 2026
faa5c49
feat: Option to add image as context
surajshetty3416 Apr 10, 2026
691c733
fix: Misc
surajshetty3416 Apr 10, 2026
618a816
feat: Show selected block and image shared with the chat as chips
surajshetty3416 Apr 11, 2026
9156e95
fix: Improve alignment and spacing
surajshetty3416 Apr 11, 2026
6d305fb
refactor: Remove AI generator modal references and enhance logging
surajshetty3416 Apr 12, 2026
3aeffa2
feat: Add clarification handling
surajshetty3416 Apr 12, 2026
f44cda9
fix: Update clarification handling to use JSON and improve prompt for…
surajshetty3416 Apr 12, 2026
5935b87
fix: Improve add_block tool's definition schema
surajshetty3416 Apr 12, 2026
92d672f
fix: Use correct model id for Gemini 3.1 Pro
surajshetty3416 Apr 13, 2026
f2ca398
fix: Misc
surajshetty3416 Apr 13, 2026
500e262
fix: Add shortcuts to left panel option for quick switch
surajshetty3416 Apr 13, 2026
62eba55
fix: Impove model selection and add style preset functionality
surajshetty3416 Apr 13, 2026
060c808
fix: Consider block as HTML block if it has html in innerHTML
surajshetty3416 Apr 13, 2026
9ec6362
fix: Pass details of used component as context
surajshetty3416 Apr 20, 2026
ada1864
Merge branch 'develop' into ai-session
surajshetty3416 Apr 22, 2026
fe4263e
fix(BuilderAIChatPanel): Show description of selected block
surajshetty3416 Apr 27, 2026
dfd8554
Merge branch 'develop' into ai-session
surajshetty3416 Apr 27, 2026
3607db9
Merge branch 'develop' into ai-session
surajshetty3416 Apr 28, 2026
1c963b4
Merge branch 'develop' into ai-session
surajshetty3416 Apr 29, 2026
0efa613
Merge branch 'develop' into ai-session
surajshetty3416 May 2, 2026
a6e8272
Merge branch 'develop' into ai-session
surajshetty3416 May 5, 2026
dfac6a4
Merge branch 'develop' into ai-session
surajshetty3416 May 8, 2026
2e63c83
Merge branch 'develop' into ai-session
surajshetty3416 May 8, 2026
f615bab
Merge branch 'develop' into ai-session
surajshetty3416 May 8, 2026
8c33c7d
Merge branch 'develop' into ai-session
surajshetty3416 May 20, 2026
115f60b
refactor: Update AI chat icon
surajshetty3416 May 21, 2026
b727f85
fix: Sanitize AI response using DOMPurify
surajshetty3416 May 21, 2026
6035310
feat(ai): increase agent loops and token limits
surajshetty3416 May 21, 2026
4858b66
fix(ai): reduce false positives in clarification detection
surajshetty3416 May 21, 2026
996bf53
feat(ai): prevent concurrent AI requests per session
surajshetty3416 May 21, 2026
778a47a
feat(ai): style preset injection, metadata persistence, post-gen nudge
surajshetty3416 May 21, 2026
50f0401
Merge branch 'develop' into ai-session
surajshetty3416 May 22, 2026
949a1c6
Merge branch 'develop' into ai-session
surajshetty3416 May 24, 2026
6b2e0ae
chore: update caniuse-lite
surajshetty3416 May 24, 2026
36b231d
Merge branch 'develop' into ai-session
surajshetty3416 May 26, 2026
af3bdfb
fix: Incorrect import source
surajshetty3416 May 26, 2026
f0010e2
fix: Increase loop threshold for better results
surajshetty3416 May 27, 2026
9497dc9
feat: Enhance clarification handling and add plan summary support
surajshetty3416 May 28, 2026
a6b6501
refactor: Use single agentic loop for all flows
surajshetty3416 May 28, 2026
76ae07e
fix: Break off from the loop to stream the page
surajshetty3416 May 28, 2026
2bfc3e2
feat: Option to pause the streaming
surajshetty3416 May 28, 2026
33c2fce
refactor: Simplify model resolution and fix fallback handling in comp…
surajshetty3416 May 29, 2026
3c9cb5f
refactor: Improve clarification options layout and styling in chat panel
surajshetty3416 May 29, 2026
4b242b7
Merge branch 'develop' into ai-session
surajshetty3416 May 29, 2026
e6b3acf
feat: Migrate AI session messages to new Builder AI Message doctype a…
surajshetty3416 May 29, 2026
73a6463
feat: Implement artifact generation for full-page YAML streaming and …
surajshetty3416 May 29, 2026
9aa5d36
fix: Update prompts to generate consitent and high quality pages
surajshetty3416 May 30, 2026
aab50ba
feat: Add cancellation state to AIChatController and show UI feedback…
surajshetty3416 May 30, 2026
0c875fe
feat: Make AI use lucid icons instead of emojis
surajshetty3416 May 31, 2026
e86ded9
feat: Add new AI models and input price calculation to ModelRegistry
surajshetty3416 May 31, 2026
35a13b9
fix: Improve design direction options in conversation tools
surajshetty3416 Jun 1, 2026
4361d45
perf: Update propmt so that AI could use repeater
surajshetty3416 Jun 1, 2026
1d4795a
Merge branch 'develop' into ai-session
surajshetty3416 Jun 5, 2026
56919ac
Merge branch 'develop' into ai-session
surajshetty3416 Jun 19, 2026
f96927b
fix: prevent malformed repeater dataKey from crashing page render
surajshetty3416 Jun 19, 2026
8c29fa0
feat(ai): live multi-round agent edits with per-turn revert
surajshetty3416 Jun 19, 2026
2a190be
feat(ai): sharpen page-generation brief and prompts
surajshetty3416 Jun 19, 2026
21a4038
fix(ai): honour Anthropic cache_control on the content block
surajshetty3416 Jun 19, 2026
b5ee8a0
perf(ai): bound streaming-YAML reparse to the last lines
surajshetty3416 Jun 19, 2026
f5e0efc
chore: regenerate components.d.ts
surajshetty3416 Jun 19, 2026
ec78a80
feat(ai): selector + batch bulk-edit (query_blocks, update_blocks)
surajshetty3416 Jun 20, 2026
5610275
feat(ai): tiered page context — skeleton + read_block for large pages
surajshetty3416 Jun 20, 2026
4cdc67e
fix(ai): make query_blocks text_only a shape-based leaf predicate
surajshetty3416 Jun 20, 2026
ee21dd1
feat(ai): per-turn token + timing telemetry
surajshetty3416 Jun 20, 2026
7206746
feat(ai): show per-turn token/latency under each assistant message
surajshetty3416 Jun 20, 2026
67c3066
fix(ai): keep propose_plan tool-call JSON valid (single-quote copy)
surajshetty3416 Jun 20, 2026
a2a09b2
feat(ai): add GLM-5.2 model option
surajshetty3416 Jun 20, 2026
45a8ec8
feat(ai): cached-token + per-call breakdown in turn telemetry
surajshetty3416 Jun 20, 2026
ed34c26
feat(ai): guard against hallucinated success (no-op action claims)
surajshetty3416 Jun 20, 2026
ef52be6
fix(ai): tolerant tool-arg parsing + plan-as-string; richer debug sig…
surajshetty3416 Jun 20, 2026
94ed03d
feat(ai): log generation quality (finish_reason, size, sections)
surajshetty3416 Jun 20, 2026
c536e03
fix(ai): stop one-block-per-token code/inline text (stacks vertically)
surajshetty3416 Jun 20, 2026
cad8eb6
fix(ai): don't camelCase CSS values (spaceBetween -> space-between)
surajshetty3416 Jun 20, 2026
e22a770
fix(ai): normalize model CSS slips in code, not the prompt
surajshetty3416 Jun 20, 2026
46690c9
feat(ai): validate client tool ops server-side and log corrections
surajshetty3416 Jun 20, 2026
f9ffd28
perf(ai): cache the page context, not just the system prompt
surajshetty3416 Jun 20, 2026
1fbc57a
feat(ai): raise round cap to 40 + surface incomplete-turn cutoff
surajshetty3416 Jun 20, 2026
e23a791
feat(block): add "summary" to TEXT_ELEMENTS set
surajshetty3416 Jun 20, 2026
d687ea1
fix(builder): update autoname format and naming rule for Builder Snap…
surajshetty3416 Jun 20, 2026
507bb43
fix(ai): cap per-call rows in the token tooltip
surajshetty3416 Jun 20, 2026
d1292c2
feat(ai): retry a streaming round on transient failure
surajshetty3416 Jun 20, 2026
13fbff4
feat(ai): turn debugger panel (Track D)
surajshetty3416 Jun 20, 2026
50c933c
feat(ai): stream per-round narration instead of static "Applying N"
surajshetty3416 Jun 20, 2026
7eaf908
feat(ai): redesign the turn debugger panel
surajshetty3416 Jun 20, 2026
afb8813
fix(ai): debugger polish — drop duplicate round numbers, dark mode, c…
surajshetty3416 Jun 20, 2026
a125ae1
refactor(ai): debugger uses semantic color tokens (auto dark mode)
surajshetty3416 Jun 20, 2026
51cccfa
fix(ai): inline line shows only human-readable time; fix pale debug c…
surajshetty3416 Jun 20, 2026
bfc96a2
refactor: replace FeatherIcons with Lucide icons
surajshetty3416 Jun 20, 2026
a31413e
refactor: update layout and styling for AIAffectedItems and AIDebugPa…
surajshetty3416 Jun 20, 2026
a63c5cd
feat(ai): one unified revert for blocks + scripts; drop separate undo
surajshetty3416 Jun 20, 2026
9d79a53
fix(ai): regenerate script file on revert so publish uses reverted sc…
surajshetty3416 Jun 20, 2026
9435571
refactor: update text styles for improved readability
surajshetty3416 Jun 20, 2026
1a96540
fix(ai): strip stray quotes from CSS values in normalizeStyles
surajshetty3416 Jun 20, 2026
721dcdf
feat(ai): give AI-created scripts a descriptive name
surajshetty3416 Jun 20, 2026
2493a9c
Merge branch 'develop' into ai-session
surajshetty3416 Jun 21, 2026
9bd2d79
Merge branch 'develop' into ai-session
surajshetty3416 Jun 26, 2026
6e1b44e
Merge branch 'develop' into ai-session
surajshetty3416 Jun 28, 2026
d430f22
Merge branch 'develop' into ai-session
surajshetty3416 Jun 30, 2026
6f05baf
refactor: Simplify code
surajshetty3416 Jun 30, 2026
2dd71ef
feat(ai): foundation for AI-first multi-page site builder
surajshetty3416 Jul 1, 2026
d04bc1e
feat(ai): site orchestrator, SiteSpec, and generation endpoints
surajshetty3416 Jul 1, 2026
a716b5b
feat(ai): data-layer + settings agent tools with confirm-gating
surajshetty3416 Jul 1, 2026
268d0fe
feat(ai): teach the agent when to use data-layer and settings tools
surajshetty3416 Jul 1, 2026
cadb0ff
feat(ai): dashboard "Build with AI" entry + live site progress screen
surajshetty3416 Jul 1, 2026
e943c61
feat(ai): in-chat confirm card for sensitive agent actions
surajshetty3416 Jul 1, 2026
713aee1
feat(ai): make generated pages reference theme variables, not raw hex
surajshetty3416 Jul 1, 2026
3f75b38
feat(ai): full-page AI build chat with live inline progress + session…
surajshetty3416 Jul 1, 2026
61f55bd
refactor(ai): general dashboard agent chat + generic parallel sub-agents
surajshetty3416 Jul 1, 2026
80a1991
feat(ai): @page mentions + composer polish in the dashboard chat
surajshetty3416 Jul 1, 2026
e3094d8
refactor(ai): use frappe-ui Autocomplete for the @page picker
surajshetty3416 Jul 1, 2026
f575a4d
feat(ai): generic get_document reader instead of a getter-per-setting
surajshetty3416 Jul 1, 2026
14466b7
feat(ai): inline @page references in the dashboard chat
surajshetty3416 Jul 1, 2026
5cfa71b
fix(ai): disambiguate @page references when titles collide
surajshetty3416 Jul 1, 2026
b4307ba
feat(ai): make the dashboard agent fully capable - read, create, edit…
surajshetty3416 Jul 2, 2026
c6cefde
fix(ai): polish the dashboard chat - markdown, coalesced activity, op…
surajshetty3416 Jul 2, 2026
68866b4
feat(ai): clickable links in the dashboard chat
surajshetty3416 Jul 2, 2026
469c5f4
feat(ai): high-fidelity reference pages via copy_page_design; screens…
surajshetty3416 Jul 3, 2026
9f594c3
fix(ai): let the page doc own its preview thumbnail
surajshetty3416 Jul 3, 2026
e51bc62
feat(ai): dashboard chat parity with the editor chat + calmer activit…
surajshetty3416 Jul 3, 2026
b2c300e
fix(ai): page lifecycle tool + data-script mutation guard + tool-synt…
surajshetty3416 Jul 3, 2026
aca5f41
fix(ai): confirmed actions leave a durable outcome in the conversation
surajshetty3416 Jul 3, 2026
6fd718f
fix(ai): readable confirm cards - no duplicate title, no raw JSON dump
surajshetty3416 Jul 3, 2026
bdca174
feat(ai): resume the task after an Apply/Skip decision; soften empty …
surajshetty3416 Jul 3, 2026
024eb19
fix(ai): data-driven repeaters - reserved data keys guarded, DB-bound…
surajshetty3416 Jul 3, 2026
bf1c0a8
feat(ai): real data bindings from the edit tools - bind param + repea…
surajshetty3416 Jul 3, 2026
feffa1f
fix(ai): normalize binding keys at the core - prefixes stripped, expr…
surajshetty3416 Jul 3, 2026
7cea1d2
fix(ai): server-tool turns are real work; page scripts work headlessly
surajshetty3416 Jul 3, 2026
ee6a682
feat(ai): terminal tools can decline; safe_exec + repeater-bind guards
surajshetty3416 Jul 3, 2026
f098c56
fix(ai): moustache text in attributes/content crashes published pages…
surajshetty3416 Jul 3, 2026
076a4b6
refactor(ai): server-authoritative turns - one apply path, canvas as …
surajshetty3416 Jul 3, 2026
82f0975
feat(ai): event-driven fan-out - spawning ends the turn, the last chi…
surajshetty3416 Jul 3, 2026
15871f3
fix(ui): dropdown triggers broken by the frappe-ui slot API change
surajshetty3416 Jul 3, 2026
1159dbf
fix(ai): text-only models can't take screenshots; autosave races the …
surajshetty3416 Jul 4, 2026
9091b34
fix(ai): teach the model the theme-variable handle that actually reso…
surajshetty3416 Jul 4, 2026
3f43c8a
style(ui): dashboard chat on the frappe-ui scale — bigger type, real …
surajshetty3416 Jul 4, 2026
f2e0400
feat(ai): watch a page assemble live from the dashboard chat
surajshetty3416 Jul 4, 2026
c3583b2
feat: Primitives-only AI agent — run_python, source access, generic U…
surajshetty3416 Jul 4, 2026
e381363
feat: Font specimens on option cards + personal-details step in the d…
surajshetty3416 Jul 4, 2026
ba0c07d
feat: Split layout and typography into separate decision cards
surajshetty3416 Jul 4, 2026
f5f8c43
feat: Creative option cards — concept layouts, deep-catalogue fonts, …
surajshetty3416 Jul 4, 2026
c117eb3
feat: merge ai-codebase-context — primitives + design flow onto the f…
surajshetty3416 Jul 4, 2026
54e5332
feat: fan-out progress in the editor chat — task-group card, batch tr…
surajshetty3416 Jul 4, 2026
30fb16e
refactor: drop the standalone dashboard AI chat — the editor agent is…
surajshetty3416 Jul 4, 2026
b7a620d
fix(ui): AI card inputs/buttons on frappe-ui, and fewer em dashes fro…
surajshetty3416 Jul 4, 2026
59616b7
feat(ui): calmer AI cards — compact reply chips, flat option lists, f…
surajshetty3416 Jul 4, 2026
5040502
feat(ui): visual-first plan card and picture-only layout options
surajshetty3416 Jul 4, 2026
d20242c
feat(ai): staged page builds — tokens, data, layout, scripts in one s…
surajshetty3416 Jul 4, 2026
89c71d0
feat(ai): real photo search + user-picked imagery
surajshetty3416 Jul 4, 2026
3e257dc
fix(ai): generation survives canvas autosaves; code-as-blocks strippe…
surajshetty3416 Jul 4, 2026
36b30c9
feat(ai): parallel chat sessions per page — VS Code-style switcher
surajshetty3416 Jul 4, 2026
d1d1972
fix(ai): no box around option cards; JS and CSS are separate scripts
surajshetty3416 Jul 4, 2026
cb0d9d3
feat(ai): parallel layout+scripts on a class contract; live editor re…
surajshetty3416 Jul 4, 2026
3dfd421
feat(ai): per-turn cost (in the site's currency) and context-window u…
surajshetty3416 Jul 4, 2026
14a7d15
refactor(ai): curated model shortlist + live metadata from OpenRouter
surajshetty3416 Jul 4, 2026
9d440ef
feat(ai): refresh the curated models — Claude Sonnet 5 default, Fable…
surajshetty3416 Jul 4, 2026
236b8d4
fix(ai): single-weight font specimens load; card-as-text gets a corre…
surajshetty3416 Jul 4, 2026
d8236ca
fix(ai): builds land on the page the user has open — no more orphan-p…
surajshetty3416 Jul 4, 2026
2289e73
feat(ai): art-direction overhaul — brief-led generation over a craft …
surajshetty3416 Jul 4, 2026
393d872
fix(ai): compact cards — say the question once, no filler, no redunda…
surajshetty3416 Jul 4, 2026
9290e87
fix(ai): don't leak instruction vocabulary into user-facing card copy
surajshetty3416 Jul 4, 2026
a3cf0d0
fix(ai): off-page builds are visible and linked; empty-canvas guard s…
surajshetty3416 Jul 4, 2026
3e67633
fix: text edits no longer wrap block content in a stray <p>
surajshetty3416 Jul 4, 2026
42ac42b
fix: canvas text wrapper no longer shatters inline blocks
surajshetty3416 Jul 4, 2026
d1dc422
fix: inline text survives selection; hide all-empty property sections
surajshetty3416 Jul 4, 2026
58309d7
fix: show grid-child layout controls; robust paragraph unwrap
surajshetty3416 Jul 4, 2026
a30291b
fix(ai): off-canvas builds can't hijack the open page; streams surviv…
surajshetty3416 Jul 4, 2026
a9b76e3
fix(ui): cap session titles in the chat-history dropdown
surajshetty3416 Jul 4, 2026
76ec711
fix(ai): stalled runs fail visibly and cancel always resolves
surajshetty3416 Jul 4, 2026
7869f54
fix(ai): salvage bad generation YAML; dead previews resync the canvas
surajshetty3416 Jul 5, 2026
def733b
fix(ui): form cards submit ALL answers; stranded cards get a button; …
surajshetty3416 Jul 5, 2026
5e46f74
fix(ui): form questions render as real field labels, not body text
surajshetty3416 Jul 5, 2026
638a392
fix(ai): salvage tool calls weaker models emit as plain-text JSON
surajshetty3416 Jul 5, 2026
9b7dfc9
feat(ai): LLM record/replay cassettes — test full agent turns for free
surajshetty3416 Jul 5, 2026
7c629b6
fix(ai): unquoted var() fallbacks no longer break published pages; or…
surajshetty3416 Jul 5, 2026
5f7ff32
feat(ai): cassette record/replay UI in the chat panel
surajshetty3416 Jul 5, 2026
1f4c958
fix(ai): site-consistent additional pages; visible build pill; drop c…
surajshetty3416 Jul 5, 2026
8b6d087
fix: editor-to-editor navigation switches pages; create_page enforces…
surajshetty3416 Jul 5, 2026
6cfc252
fix(ai): design-direction cards are structurally blocked on designed …
surajshetty3416 Jul 5, 2026
874a8d1
fix(ai): off-page build pill survives navigation; guaranteed page lin…
surajshetty3416 Jul 5, 2026
df50a49
refactor!: rename Builder Variable to Builder Token
surajshetty3416 Jul 5, 2026
f47bfa1
feat: Font design tokens — fontFamily can be var(--token)
surajshetty3416 Jul 5, 2026
928df75
feat: Design System manager — token tabs for Colors, Fonts, Dimensions
surajshetty3416 Jul 5, 2026
da75592
feat(ai): token-first generation — the design system is the build's f…
surajshetty3416 Jul 5, 2026
490c314
feat(ai): sessions name themselves after the first completed turn
surajshetty3416 Jul 5, 2026
feb3c52
feat(ai): empty chat opens with 'Describe your site' suggestion pills
surajshetty3416 Jul 5, 2026
53a3d5a
feat(ai): persistent agent memory — Bob remembers durable facts acros…
surajshetty3416 Jul 5, 2026
47b4e8b
feat(ai): smart component reuse — extract built sections into shared …
surajshetty3416 Jul 5, 2026
4497ac8
perf(ai): agent-v2 cache scheme ported — pinned Anthropic route, roll…
surajshetty3416 Jul 5, 2026
cf0e4f6
fix(ai): childless component instances repair themselves; route chang…
surajshetty3416 Jul 5, 2026
41b653a
fix(ai): questions with options written as prose get the corrective r…
surajshetty3416 Jul 5, 2026
26756ea
feat(ai): plan cards preview as a rendered mini-page, not a model-dra…
surajshetty3416 Jul 5, 2026
8767925
feat(ai): layout options name an archetype; the card draws the wirefr…
surajshetty3416 Jul 5, 2026
b5e6d42
revert(ai): layout options draw their own SVG sketches again
surajshetty3416 Jul 5, 2026
222e690
fix(ai): no more dead cards on empty options; motion tier is the agen…
surajshetty3416 Jul 5, 2026
d4386a5
fix(ai): scripts apply server-side; class-contract check; user color …
surajshetty3416 Jul 5, 2026
837632b
fix(ai): font token handles survive normalization (was dropping the c…
surajshetty3416 Jul 5, 2026
6f786b3
style(ai): tighten the empty-chat state to frappe-ui's compact scale
surajshetty3416 Jul 5, 2026
faa7ec0
style(ai): empty-state suggestions read as chips, not bare text
surajshetty3416 Jul 5, 2026
16c7a0e
style(ai): empty-state pills — bigger sparkle, no icon, larger text, …
surajshetty3416 Jul 5, 2026
9b68a5e
chore(ai): remove the LLM cassette record/replay layer
surajshetty3416 Jul 5, 2026
88083f9
fix(ai): catch 'More options' typography cards leaked as prose bullets
surajshetty3416 Jul 5, 2026
a407ae1
feat(ai): color picker uses labelled role slots + Builder's inbuilt p…
surajshetty3416 Jul 5, 2026
99b4b18
feat(builder): token count pill on each Design System tab
surajshetty3416 Jul 5, 2026
daf1580
feat(builder): copy button on each token row — copies its var(--id) h…
surajshetty3416 Jul 5, 2026
884ddfe
fix(ai): stop serving the same three fonts every build
surajshetty3416 Jul 5, 2026
1d416b3
feat(ai): richer, rotating empty-state suggestions
surajshetty3416 Jul 5, 2026
d5ac7da
feat(ai): suggestion pills prefill a full brief, not a terse label
surajshetty3416 Jul 5, 2026
b7e3d3d
fix(ai): fewer design-flow questions + drop the plan card
surajshetty3416 Jul 5, 2026
b5a12a7
fix(ai): name the page from the brand on build (title + route + meta)
surajshetty3416 Jul 5, 2026
e212c40
feat(ai): connect_form — forms save to a real DocType, viewable in Desk
surajshetty3416 Jul 5, 2026
811fb5b
fix(builder): paint html/body with the page's root background
surajshetty3416 Jul 5, 2026
e518346
fix(builder): put page background on the <html> tag so overscroll isn…
surajshetty3416 Jul 5, 2026
feba30b
fix(ai): connect_form handles reserved fieldnames (name/parent/…)
surajshetty3416 Jul 5, 2026
89b9fee
style(ai): empty-state suggestions use frappe-ui Button
surajshetty3416 Jul 5, 2026
68059d1
fix(ai): connect_form actually wires the form (find + positional map …
surajshetty3416 Jul 5, 2026
eeb8a3f
fix(ai): catch a build that minted the design system but never genera…
surajshetty3416 Jul 5, 2026
6531f83
fix(ai): answer 'where are the submissions?' instead of duplicating t…
surajshetty3416 Jul 5, 2026
ed57a03
style(ai): redesign the Turn debug panel
surajshetty3416 Jul 5, 2026
d9af356
style(ai): debug panel — lighter timeline dots + status pill
surajshetty3416 Jul 5, 2026
f3e1b87
fix(ai): debug status dot renders (bg-ink-*-5 isn't a token; use surf…
surajshetty3416 Jul 5, 2026
a57c966
feat(tokens): Font Family field mirrors the color input
surajshetty3416 Jul 6, 2026
a7d0d43
fix(ai): show AI cost in the site currency reliably
surajshetty3416 Jul 6, 2026
ad1fd0d
feat(ai): tasteful build UX — canvas aura, shader orb, live tool status
surajshetty3416 Jul 6, 2026
21914a6
Merge branch 'develop' into ai-delight-demo
surajshetty3416 Jul 10, 2026
88afe71
Merge branch 'develop' into ai-delight-demo
surajshetty3416 Jul 15, 2026
347dfce
feat: search_videos tool for stock motion footage via Pexels
surajshetty3416 Jul 15, 2026
3069080
Merge branch 'develop' into ai-delight-demo
surajshetty3416 Jul 20, 2026
6ed1a62
feat: route Builder AI through OpenCode Zen free models
surajshetty3416 Jul 21, 2026
6af5bfa
fix: stop generated pages exposing white gaps and faking tokens in CSS
surajshetty3416 Jul 21, 2026
8f221ad
feat: add OpenCode Go (Kimi) models to Builder AI
surajshetty3416 Jul 22, 2026
f3ab075
fix: make Bob avoid em/en dashes whenever an alternative exists
surajshetty3416 Jul 22, 2026
e589cdb
feat: prefill the design-flow colour slots with curated presets
surajshetty3416 Jul 22, 2026
e509564
fix: catch every card-atom marker when a model writes a card as text
surajshetty3416 Jul 22, 2026
ae4fc25
Merge branch 'develop' into ai-delight-demo
surajshetty3416 Aug 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
257 changes: 257 additions & 0 deletions builder/ai/agent/artifact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
"""Artifact generators — produce a large streamed artifact for a tool.

An *artifact tool* (one that sets `artifact=` on its `Tool`) delegates its
execution to a generator here. The generator runs on the user's selected *heavy*
model and streams the artifact to the client as plain content — reliable, unlike
tool-call argument streaming, which providers buffer (the canvas would stay
blank for the whole completion). After streaming, it returns the canonical
client op(s) for the loop to emit so the frontend applies the authoritative,
fully-parsed result.

The agent calling the tool is the only trigger: when the fast conversational
model decides to build the page, it calls `generate_page(brief=…)` and the loop
hands off here. No DB status or out-of-band heuristic gates generation.
"""

import base64
import logging
import re

import frappe

from builder.ai import llm
from builder.ai.block_codec import BlockCodec
from builder.ai.models import ModelRegistry
from builder.ai.prompts import Prompts
from builder.ai.session import AISession

logger = frappe.logger("builder.ai.agent.artifact")
logger.setLevel(logging.INFO)

# Brief marker lines the design flow emits for images the generator should SEE
# (not just place): the user's reference and the chosen hero shot.
IMAGE_MARKER_RE = re.compile(r"(?:REFERENCE|HERO) IMAGE:\s*(\S+)", re.IGNORECASE)
MAX_ATTACHED_IMAGES = 2
MAX_IMAGE_BYTES = 3 * 1024 * 1024


def brief_image_parts(brief: str) -> list[dict]:
"""Resolve the brief's image markers into message image parts. https URLs are
attached directly (the provider fetches them); /files/ paths are read from the
site and inlined as data URLs. The marker lines always stay in the brief text,
so the model still knows the exact URLs to place in blocks."""
parts = []
for url in IMAGE_MARKER_RE.findall(brief or ""):
if len(parts) >= MAX_ATTACHED_IMAGES:
break
if url.startswith("https://"):
parts.append({"type": "image_url", "image_url": {"url": url}})
elif url.startswith("/files/"):
data_url = read_site_image(url)
if data_url:
parts.append({"type": "image_url", "image_url": {"url": data_url}})
return parts


def read_site_image(file_url: str) -> str | None:
try:
name = frappe.db.get_value("File", {"file_url": file_url}, "name")
if not name:
return None
content = frappe.get_doc("File", name).get_content()
if isinstance(content, str):
content = content.encode()
if not content or len(content) > MAX_IMAGE_BYTES:
return None
ext = (file_url.rsplit(".", 1)[-1] or "png").lower()
mime = {"jpg": "jpeg", "jpeg": "jpeg", "png": "png", "webp": "webp", "gif": "gif"}.get(ext)
if not mime:
return None
return f"data:image/{mime};base64,{base64.b64encode(content).decode()}"
except Exception as e:
logger.warning(f"read_site_image failed for {file_url}: {e}")
return None


def log_generation_quality(model: str, finish_reason: str | None, yaml_text: str) -> None:
"""Make the generation path debuggable: log model, finish_reason, YAML size, parse
result, and top-level section count. A thin/broken page shows up here as a 'length'
finish, a parse error, or very few sections — distinguishing a weak model from a
pipeline bug."""
chars = len(yaml_text)
sections = -1 # -1 = did not parse
try:
from builder.ai.page_writer import parse_generation_yaml, unwrap_root

# The same salvaging parser persist_page uses — telemetry must agree with
# what actually lands on the page (a salvaged parse is not a failed one).
root = unwrap_root(parse_generation_yaml(yaml_text))
if isinstance(root, dict):
sections = len(root.get("c") or [])
except Exception as e:
logger.warning("generate_page: YAML did not parse (model=%s): %s", model, e)

level = logging.WARNING if (finish_reason == "length" or sections in (-1, 0, 1)) else logging.INFO
logger.log(
level,
"generate_page quality | model=%s finish_reason=%s yaml_chars=%d top_sections=%s",
model,
finish_reason,
chars,
sections,
)
if sections in (-1, 0):
# A no-blocks generation costs a full retry — capture enough of the actual
# output to diagnose WHAT didn't parse (bad quoting, prose preamble, …).
logger.warning("generate_page unparsed head:\n%s", yaml_text[:800])
logger.warning("generate_page unparsed tail:\n%s", yaml_text[-400:])


def stream_buffer_key(page_id: str) -> str:
return f"builder_ai_page_stream:{page_id}"


def save_stream_buffer(ctx, yaml_content: str) -> None:
"""Keep the in-flight generation stream in Redis so an editor that loads (or
refreshes) mid-build can replay the preview instead of showing a stale draft."""
frappe.cache().set_value(
stream_buffer_key(ctx.page_id),
frappe.as_json(
{"yaml": yaml_content, "session_id": ctx.session_id, "origin_page": ctx.canvas_page_id}
),
expires_in_sec=600,
)


def clear_stream_buffer(page_id: str | None) -> None:
if page_id:
frappe.cache().delete_value(stream_buffer_key(page_id))


def generate_page_yaml(ctx, args: dict) -> list[dict]:
"""Stream a complete page of YAML on the heavy model, persist it to the page
(the server is authoritative), and return a `generate_page` client op carrying
the expanded block tree — the canvas applies that, so both sides share block ids.

`ctx` is the AgentRunner. `args["brief"]` is the concise spec the
conversational model assembled from the approved plan / conversation.
Streams `kind="page_yaml"` chunks to the canvas as the model writes them
(live preview only — the returned op is the final word).
Returns [] if the model produced nothing usable.
"""
brief = (args.get("brief") or "").strip()

messages: list[dict] = [
# 1h TTL: the generation system prompt is identical across every build on
# the site, so it stays a cache read from one page build to the next.
{
"role": "system",
"content": Prompts.GENERATION_YAML,
"cache_control": {"type": "ephemeral", "ttl": "1h"},
},
]
# Prior conversation (incl. the approved plan) as proper role-tagged turns.
messages.extend(AISession.build_context_messages_from_id(ctx.session_id))
# The approved wireframes (plan strip + chosen layout sketch) as plain SVG text.
# Cards replay as text where svg degrades to '[sketch]', so without this the
# generator never sees the composition the user actually approved.
if svgs := AISession.collect_design_svgs(ctx.session_id):
messages.append(
{
"role": "user",
"content": "Approved wireframes (abstract layout sketches — match this composition and "
"rhythm, not the literal shapes):\n" + "\n".join(svgs),
}
)
if brief:
build_text = f"Build this page now:\n{brief}"
# Vision models get the reference/hero images themselves, not just their
# URLs: the user's attached image for THIS turn, plus the brief's marker
# images. Text-only models keep working from the marker URLs.
image_parts: list[dict] = []
if ModelRegistry.supports_vision(ctx.model):
if ctx.image_url:
image_parts.append({"type": "image_url", "image_url": {"url": ctx.image_url}})
image_parts.extend(brief_image_parts(brief))
if image_parts:
messages.append({"role": "user", "content": [{"type": "text", "text": build_text}, *image_parts]})
else:
messages.append({"role": "user", "content": build_text})

ctx.emit("progress", message="Building the page…")

yaml_content = ""
finish_reason = None
buffered_at = 0
stream = llm.complete(
ctx.model, # heavy model — generation quality
messages,
llm.TASK_PARAMS["complex"],
stream=True,
api_key=ctx.api_key,
)
try:
for chunk in stream:
if ctx.is_cancelled():
try:
stream.close()
except Exception:
pass
from builder.ai.agent.loop import CancelledError

raise CancelledError
ctx.record_usage(chunk, model=ctx.model) # generation streams on the heavy model
if not chunk.choices:
continue
if fr := chunk.choices[0].finish_reason:
finish_reason = fr
delta = chunk.choices[0].delta.content
if delta:
# offset = position of this chunk in the full stream, so a client that
# replayed the buffer (mid-build refresh) can drop duplicates / detect gaps.
offset = len(yaml_content)
yaml_content += delta
# Every event names its TARGET page (ctx.page_id): the canvas renders the
# stream only when it is showing that page — an off-canvas build must
# never paint (and get autosaved) over a page it wasn't meant for.
if not ctx.headless:
ctx.emit("stream", chunk=delta, kind="page_yaml", offset=offset)
if ctx.headless or ctx.page_id != ctx.canvas_page_id:
# An editor open on the target page is the live viewport ("watch it
# build") — headless chats have no canvas, editor chats may have
# focused a different page than the one on their canvas.
ctx.emit_page("stream", chunk=delta, kind="page_yaml", offset=offset)
if len(yaml_content) - buffered_at >= 512:
buffered_at = len(yaml_content)
save_stream_buffer(ctx, yaml_content)
finally:
# The buffer only serves mid-build refreshes; once this function returns the
# draft is persisted (or the turn failed/cancelled) and the DB is the truth.
clear_stream_buffer(ctx.page_id)

yaml_text = BlockCodec.strip_fences(yaml_content)
# Generation was a blind spot — log enough to explain a thin/broken/truncated page:
# the model, finish_reason (="length" → ran out of tokens mid-page), the YAML size,
# whether it parses, and how many top-level sections (root.c) it actually produced.
log_generation_quality(ctx.model, finish_reason, yaml_text)
if not yaml_text or not ctx.page_id:
logger.warning("generate_page_yaml: nothing to persist (model=%s, page=%s)", ctx.model, ctx.page_id)
return []

from builder.ai import page_writer

root, data_script = page_writer.persist_page(ctx.page_id, yaml_text)
if root is None:
# A discarded generation is paid-for work — keep the raw text for diagnosis
# (the parse error itself is logged by parse_generation_yaml with line info).
dump = frappe.get_site_path("private", "files", f"ai-failed-generation-{ctx.page_id}.yaml")
try:
with open(dump, "w") as f:
f.write(yaml_text)
except OSError:
dump = "<unwritable>"
logger.warning(
"generate_page_yaml: YAML produced no blocks (model=%s), raw saved to %s", ctx.model, dump
)
return []
return [{"tool_name": "generate_page", "args": {"blocks": [root], "data_script": data_script}}]
Loading
Loading