Class: PromptObjects::Universal::RenderArtifact

Inherits:
Primitive show all
Defined in:
lib/prompt_objects/universal/render_artifact.rb

Overview

Universal capability to render interactive HTML in the UI artifact panel. Artifacts are environment-wide — any PO can create or update any artifact.

Modes:

replace (default) — updates existing artifact with the same title in place
version — always creates a new artifact entry

The frontend renders artifacts in a sandboxed iframe with React 18, Tailwind CSS, and Babel (for JSX) available.

Artifacts are bidirectional (BURP — Bidirectional UI Rendering Protocol): a PromptObjects.send(message) function is injected into every artifact. Calling it sends a natural-language message back to the PO that rendered the artifact (provenance "artifact:"), so POs can build UIs the human interacts with instead of chatting.</p> </div> </div> <div class="tags"> </div> <h2>Instance Attribute Summary</h2> <h3 class="inherited">Attributes inherited from <span class='object_link'><a href="../Capability.html" title="PromptObjects::Capability (class)">Capability</a></span></h3> <p class="inherited"><span class='object_link'><a href="../Capability.html#state-instance_method" title="PromptObjects::Capability#state (method)">#state</a></span></p> <h2> Instance Method Summary <small><a href="#" class="summary_toggle">collapse</a></small> </h2> <ul class="summary"> <li class="public "> <span class="summary_signature"> <a href="#description-instance_method" title="#description (instance method)">#<strong>description</strong> ⇒ Object </a> </span> <span class="summary_desc"><div class='inline'></div></span> </li> <li class="public "> <span class="summary_signature"> <a href="#name-instance_method" title="#name (instance method)">#<strong>name</strong> ⇒ Object </a> </span> <span class="summary_desc"><div class='inline'></div></span> </li> <li class="public "> <span class="summary_signature"> <a href="#parameters-instance_method" title="#parameters (instance method)">#<strong>parameters</strong> ⇒ Object </a> </span> <span class="summary_desc"><div class='inline'></div></span> </li> <li class="public "> <span class="summary_signature"> <a href="#receive-instance_method" title="#receive (instance method)">#<strong>receive</strong>(message, context:) ⇒ Object </a> </span> <span class="summary_desc"><div class='inline'></div></span> </li> </ul> <h3 class="inherited">Methods inherited from <span class='object_link'><a href="../Primitive.html" title="PromptObjects::Primitive (class)">Primitive</a></span></h3> <p class="inherited"><span class='object_link'><a href="../Primitive.html#initialize-instance_method" title="PromptObjects::Primitive#initialize (method)">#initialize</a></span></p> <h3 class="inherited">Methods inherited from <span class='object_link'><a href="../Capability.html" title="PromptObjects::Capability (class)">Capability</a></span></h3> <p class="inherited"><span class='object_link'><a href="../Capability.html#descriptor-instance_method" title="PromptObjects::Capability#descriptor (method)">#descriptor</a></span>, <span class='object_link'><a href="../Capability.html#execution_policy-class_method" title="PromptObjects::Capability.execution_policy (method)">execution_policy</a></span>, <span class='object_link'><a href="../Capability.html#execution_policy_definition-class_method" title="PromptObjects::Capability.execution_policy_definition (method)">execution_policy_definition</a></span>, <span class='object_link'><a href="../Capability.html#execution_policy_definition-instance_method" title="PromptObjects::Capability#execution_policy_definition (method)">#execution_policy_definition</a></span>, <span class='object_link'><a href="../Capability.html#execution_policy_signature-instance_method" title="PromptObjects::Capability#execution_policy_signature (method)">#execution_policy_signature</a></span>, <span class='object_link'><a href="../Capability.html#initialize-instance_method" title="PromptObjects::Capability#initialize (method)">#initialize</a></span>, <span class='object_link'><a href="../Capability.html#resolved_execution_policy-instance_method" title="PromptObjects::Capability#resolved_execution_policy (method)">#resolved_execution_policy</a></span></p> <div id="constructor_details" class="method_details_list"> <h2>Constructor Details</h2> <p class="notice">This class inherits a constructor from <span class='object_link'><a href="../Primitive.html#initialize-instance_method" title="PromptObjects::Primitive#initialize (method)">PromptObjects::Primitive</a></span></p> </div> <div id="instance_method_details" class="method_details_list"> <h2>Instance Method Details</h2> <div class="method_details first"> <h3 class="signature first" id="description-instance_method"> #<strong>description</strong> ⇒ <tt>Object</tt> </h3><table class="source_code"> <tr> <td> <pre class="lines"> 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48</pre> </td> <td> <pre class="code"><span class="info file"># File 'lib/prompt_objects/universal/render_artifact.rb', line 34</span> <span class='kw'>def</span> <span class='id identifier rubyid_description'>description</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Render an interactive HTML/JSX artifact in the UI panel. The sandboxed iframe ALREADY provides </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>React 18, ReactDOM, Babel, and Tailwind, plus a <div id='root'> mount point. </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>IMPORTANT: send ONLY your component markup — do NOT include <html>/<head>/<body> wrappers or your </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>own <script src=...> CDN tags for React/Babel/Tailwind (the iframe provides them; your own copies </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>conflict). Do NOT use `import` or `export` (it is not an ES module; those silently fail to render). </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Put JSX in <script type='text/babel'>, define a component, and you MUST mount it yourself with: </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>ReactDOM.createRoot(document.getElementById('root')).render(<App />); </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>BIDIRECTIONAL: PromptObjects.send('...') is available inside the artifact — wire it to </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>buttons/forms/controls so the human can talk back to YOU through the UI instead of chatting </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>(messages arrive from 'artifact:<title>'). Respond to them by re-rendering this artifact </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>(mode 'replace') with the updated UI. A re-render resets the artifact's local JS state, so </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>bake the current state into the HTML you render. </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Default mode is 'replace' — same title updates in place. Use mode 'version' for a new entry each time.</span><span class='tstring_end'>"</span></span> <span class='kw'>end</span></pre> </td> </tr> </table> </div> <div class="method_details "> <h3 class="signature " id="name-instance_method"> #<strong>name</strong> ⇒ <tt>Object</tt> </h3><table class="source_code"> <tr> <td> <pre class="lines"> 30 31 32</pre> </td> <td> <pre class="code"><span class="info file"># File 'lib/prompt_objects/universal/render_artifact.rb', line 30</span> <span class='kw'>def</span> <span class='id identifier rubyid_name'>name</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>render_artifact</span><span class='tstring_end'>"</span></span> <span class='kw'>end</span></pre> </td> </tr> </table> </div> <div class="method_details "> <h3 class="signature " id="parameters-instance_method"> #<strong>parameters</strong> ⇒ <tt>Object</tt> </h3><table class="source_code"> <tr> <td> <pre class="lines"> 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74</pre> </td> <td> <pre class="code"><span class="info file"># File 'lib/prompt_objects/universal/render_artifact.rb', line 50</span> <span class='kw'>def</span> <span class='id identifier rubyid_parameters'>parameters</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>object</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='label'>properties:</span> <span class='lbrace'>{</span> <span class='label'>title:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>string</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='label'>description:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Short title for the artifact tab. In replace mode, this is the unique identifier — same title overwrites the previous version.</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>html:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>string</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='label'>description:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Your component markup only — NOT a full page. React 18/ReactDOM/Babel/Tailwind </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>and a <div id='root'> are already provided by the iframe; do NOT add <html>/<head>/<body> </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>or your own <script src=...> CDN tags. No `import`/`export`. Put JSX in <script type='text/babel'> </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>and END with a mount, e.g.: function App(){return <div className='p-4'>…</div>} </span><span class='tstring_end'>"</span></span> \ <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>ReactDOM.createRoot(document.getElementById('root')).render(<App />); — without that mount nothing shows.</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>mode:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>string</span><span class='tstring_end'>"</span></span><span class='comma'>,</span> <span class='label'>enum:</span> <span class='qwords_beg'>%w[</span><span class='tstring_content'>replace</span><span class='words_sep'> </span><span class='tstring_content'>version</span><span class='tstring_end'>]</span></span><span class='comma'>,</span> <span class='label'>description:</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>replace (default): update existing artifact with same title. version: always create a new artifact entry.</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>required:</span> <span class='qwords_beg'>%w[</span><span class='tstring_content'>title</span><span class='words_sep'> </span><span class='tstring_content'>html</span><span class='tstring_end'>]</span></span> <span class='rbrace'>}</span> <span class='kw'>end</span></pre> </td> </tr> </table> </div> <div class="method_details "> <h3 class="signature " id="receive-instance_method"> #<strong>receive</strong>(message, context:) ⇒ <tt>Object</tt> </h3><table class="source_code"> <tr> <td> <pre class="lines"> 76 77 78 79 80 81 82 83 84 85 86 87 88</pre> </td> <td> <pre class="code"><span class="info file"># File 'lib/prompt_objects/universal/render_artifact.rb', line 76</span> <span class='kw'>def</span> <span class='id identifier rubyid_receive'>receive</span><span class='lparen'>(</span><span class='id identifier rubyid_message'>message</span><span class='comma'>,</span> <span class='label'>context:</span><span class='rparen'>)</span> <span class='id identifier rubyid_title'>title</span> <span class='op'>=</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='symbol'>:title</span><span class='rbracket'>]</span> <span class='op'>||</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>title</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='id identifier rubyid_html'>html</span> <span class='op'>=</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='symbol'>:html</span><span class='rbracket'>]</span> <span class='op'>||</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>html</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='id identifier rubyid_mode'>mode</span> <span class='op'>=</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='symbol'>:mode</span><span class='rbracket'>]</span> <span class='op'>||</span> <span class='id identifier rubyid_message'>message</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>mode</span><span class='tstring_end'>"</span></span><span class='rbracket'>]</span> <span class='op'>||</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>replace</span><span class='tstring_end'>"</span></span> <span class='kw'>return</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Error: 'title' is required</span><span class='tstring_end'>"</span></span> <span class='kw'>unless</span> <span class='id identifier rubyid_title'>title</span> <span class='kw'>return</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Error: 'html' is required</span><span class='tstring_end'>"</span></span> <span class='kw'>unless</span> <span class='id identifier rubyid_html'>html</span> <span class='kw'>return</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Error: artifact persistence is unavailable</span><span class='tstring_end'>"</span></span> <span class='kw'>unless</span> <span class='id identifier rubyid_context'>context</span><span class='period'>.</span><span class='id identifier rubyid_env'>env</span><span class='period'>.</span><span class='id identifier rubyid_respond_to?'>respond_to?</span><span class='lparen'>(</span><span class='symbol'>:persist_artifact</span><span class='rparen'>)</span> <span class='id identifier rubyid_context'>context</span><span class='period'>.</span><span class='id identifier rubyid_env'>env</span><span class='period'>.</span><span class='id identifier rubyid_persist_artifact'>persist_artifact</span><span class='lparen'>(</span><span class='label'>title:</span> <span class='id identifier rubyid_title'>title</span><span class='comma'>,</span> <span class='label'>html:</span> <span class='id identifier rubyid_html'>html</span><span class='comma'>,</span> <span class='label'>mode:</span> <span class='id identifier rubyid_mode'>mode</span><span class='comma'>,</span> <span class='label'>context:</span> <span class='id identifier rubyid_context'>context</span><span class='rparen'>)</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Artifact '</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_title'>title</span><span class='embexpr_end'>}</span><span class='tstring_content'>' rendered (</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_mode'>mode</span><span class='embexpr_end'>}</span><span class='tstring_content'>) in the UI.</span><span class='tstring_end'>"</span></span> <span class='kw'>end</span></pre> </td> </tr> </table> </div> </div> </div> <div id="footer"> Generated on Sun Jul 12 03:19:16 2026 by <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a> 0.9.44 (ruby-4.0.2). </div> </div> </body> </html>