Skip to content

feat(widgets): shim show_widget html onto upstream HtmlRender - #408

Merged
johnnyelwailer merged 1 commit into
mainfrom
nexi/html-show-widget-shim
Oct 7, 2026
Merged

johnnyelwailer merged 1 commit into
mainfrom
nexi/html-show-widget-shim

Conversation

@johnnyelwailer

Copy link
Copy Markdown
Owner

Summary

Implements Phil's HARD decision (2026-10-06): t3_show_widget format: "html" becomes a shim onto upstream HtmlRender.publish, so there is one HTML renderer. Upstream html_preview / html_render and fork t3_show_widget both stay. Other formats (svg, mdx/tsx, …) stay on the widget tier.

Issues: hive/nx-nexi#31 · pj/nexi-distribution#611

Flow

intent → builder → widgetCode(format) → html: HtmlRender shim | other: widget tier
Raw widget_code bypasses the builder (required for deterministic workflow replay).

What changed

  • Server: html format wraps the fragment (widget CSP connect-src 'none') and calls HtmlRender.publish; attachment keeps fragment + optional htmlRender ref. Svg unchanged. HtmlRender provided to the tool broker layer.
  • Builder seam: intent accepted; intent-only hits authorWidgetFromIntent (not model-wired yet — clear error, no invented HTML). widget_code bypasses.
  • Web: T3TeamWidgetBlock uses HtmlRenderFrame when htmlRender is present and there is no tool allowlist (bridge stays on srcdoc). Legacy html without htmlRender still uses srcdoc.
  • Guidance / MCP schema / catalog: describe html delegation + intent preference.

Out of scope

  • Full builder subagent loop (reuse→draft→typecheck→preview→fix) — seam only
  • Stop-cascade / other overlap decisions
  • publicProxy (intentionally not used)

Tests

  • html → HtmlRender.publish mock (CSP + fragment preserved + htmlRender on attachment)
  • svg does not call publish
  • publish failure degrades to srcdoc
  • intent-only → builder error; widget_code bypasses
  • web routing: htmlRender shim vs legacy vs tools bridge
  • existing widgetBlock / guidance / MCP schema / workflow broker tests green

Packs

No pack pin PRs in this change — packs already pin fork main (b6b9bfb1). They pick this up on the next pin after merge.

Do not merge until Phil says go.

Phil decision 2026-10-06 (hive/nx-nexi#31, pj/nexi-distribution#611):
- format=html publishes via HtmlRender.publish (one HTML renderer) while
  keeping the fragment on the widget attachment for back-compat
- svg and other formats stay on the widget tier
- accept intent (builder seam; not yet model-wired) with widget_code bypass
- preserve widget CSP connect-src 'none'; do not use publicProxy
- web: HtmlRenderFrame when htmlRender present and no tool bridge
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 9c53fe8.

This comment will update automatically after the next completed run.

@johnnyelwailer
johnnyelwailer marked this pull request as ready for review October 7, 2026 06:24
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T06:28:40.528786Z 9c53fe8 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@johnnyelwailer
johnnyelwailer merged commit a2bdcc6 into main Oct 7, 2026
26 of 27 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c53fe8a16

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +41 to +44
export function authorWidgetFromIntent(
_input: AuthorWidgetFromIntentInput,
): Effect.Effect<AuthorWidgetFromIntentResult, string> {
return Effect.fail(T3TEAM_WIDGET_BUILDER_UNAVAILABLE);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not advertise an intent path that always fails

Any caller following the new model-facing recommendation to provide only intent reaches this function, which unconditionally returns T3TEAM_WIDGET_BUILDER_UNAVAILABLE; consequently the newly preferred/default path can never display a widget. Either keep intent out of the MCP/catalog/workflow contracts until the builder exists, or implement the builder before directing agents to use it.

Useful? React with 👍 / 👎.

Comment on lines +21 to +23
// Keep the srcdoc + postMessage bridge when the widget can call tools.
const tools = widget.capabilities?.tools ?? [];
return tools.length === 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the widget runtime on the HTML shim path

For the common HTML widget with no tool allowlist, this selects HtmlRenderFrame instead of the widget srcdoc, but the upstream HTML bootstrap provides neither sendPrompt nor the t3w-icon-* sprite. Newly published widgets that use the documented sendPrompt(...) API therefore throw at interaction time, and the explicitly recommended sprite icons render blank; checking only capabilities.tools does not establish that the widget is static. The shim must inject/preserve those widget facilities or retain the widget renderer for markup that depends on them.

Useful? React with 👍 / 👎.

Comment on lines +164 to +169
if (parsed.format === "html" && deps.htmlRender) {
htmlRenderRef = yield* publishHtmlShim({
threadId: deps.threadId,
parsed,
htmlRender: deps.htmlRender,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Register shim attachments for thread cleanup

A successful publish writes an .html file into the thread attachment store, but thread/project deletion discovers HTML files only from ProjectionStore.getThreadAttachmentIds via threadHtmlRenderAttachmentIds, whose htmlRenderFromToolItem filter accepts html_render tool calls—not these t3_show_widget artifacts. Thus every shimmed widget leaves its file behind after thread deletion; a subsequent recordArtifact failure also leaks the just-published file immediately. Include these artifact references in attachment discovery or remove the published file when the artifact cannot be recorded.

Useful? React with 👍 / 👎.

Comment on lines +43 to +46
<HtmlRenderFrame
environmentId={threadRef.environmentId}
htmlRender={htmlRender}
onOpen={onOpenHtmlRender ?? (() => undefined)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wire or hide the HTML render open action

All current T3TeamWidgetBlock call sites omit onOpenHtmlRender, so every shimmed widget passes a no-op to HtmlRenderFrame. The frame still renders its “Open in panel” button, but clicking it does nothing for every widget. Thread the existing file-preview callback into these rows, or suppress the control when opening is unsupported.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant