From 30411789ca7426bfad51cfae81e6dade856a9630 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:36:22 -0400 Subject: [PATCH 01/32] feat(documents): interactive widget blocks A widget is an AI-authored, self-contained HTML fragment that runs in an opaque-origin iframe (allow-scripts, no allow-same-origin) and lives as a block inside a document. A document holding nothing but a widget is the standalone case, so there is no separate item type to read, edit, create and render. Reads elide a widget's source to an empty placeholder carrying its ref and title, because one widget runs to kilobytes and would crowd the prose out of a chunk. workspace_read_items gains mode "block" to fetch that source back in full. Elision alone would be data loss, since overwrite echoes a read back by design, so the parser takes a resolveWidgetSource hook and an empty widget with a known ref keeps what is already there. replace_text joins the document edit vocabulary with a ref, so it targets text inside any block: a widget's source or a paragraph's markup. It fails rather than replacing every occurrence when a find matches more than once. replace_all is renamed overwrite so it cannot be read as "replace all instances of a find". Also here, because the surfaces had drifted apart: - Documents degrade unsupported markup instead of rejecting the write. A probe of realistic model output found 12 of 20 snippets refused outright, each costing a whole document to save formatting we can flatten. ProseMirror's DOMParser already normalises HTML, which removed the hand-rolled allowlist. - Math, chemistry and units are one contract across documents and widgets, both being HTML. Chat keeps the $-delimited Markdown form. sub/sup become math rather than failing, and money is written plainly. - KaTeX is served from the app's own origin and injected only when a widget contains math. Widget source stays out of search and previews: the markdown projection drops it, and a preview shows the widget's title instead. --- .gitignore | 3 + eval/__reports__/math-authoring.md | 88 ++++++++ eval/datasets/math-authoring.cases.ts | 154 ++++++++++++++ eval/datasets/workspace-tools.cases.ts | 84 ++++++++ eval/math-authoring.eval.ts | 139 +++++++++++++ eval/support/harness.ts | 87 ++++++-- eval/support/scorers.ts | 80 ++++++- eval/workspace-tools.eval.ts | 12 +- package.json | 3 +- pnpm-lock.yaml | 29 ++- scripts/copy-widget-libs.mjs | 43 ++++ .../workspaces/ai/ai-thread-soul-prompt.ts | 3 +- src/features/workspaces/ai/ai-thread.ts | 9 + .../ai/skills/widget-authoring/SKILL.md | 134 ++++++++++++ .../ai/workspace-tool-result-adapters.ts | 5 +- src/features/workspaces/cache-keys.ts | 4 + src/features/workspaces/cache-page.ts | 13 +- .../components/WorkspaceCreateMenu.tsx | 8 +- .../components/WorkspaceItemToolbarSlot.tsx | 25 ++- .../components/ai-chat/AiChatPromptInput.tsx | 6 + .../ai-chat/ai-chat-tool-receipts.ts | 13 +- .../ai-chat/useConsumeComposerPrompt.ts | 52 +++++ .../document-editor/DocumentEditorSurface.tsx | 4 + .../document-editor/DocumentToolbar.tsx | 91 +++++--- .../widget/WorkspaceAddWidgetDialog.tsx | 111 ++++++++++ .../widget/WorkspaceWidgetSandbox.tsx | 118 +++++++++++ .../workspace-widget-sandbox-document.test.ts | 30 +++ .../workspace-widget-sandbox-document.ts | 196 ++++++++++++++++++ .../composer/workspace-composer-actions.ts | 29 +++ .../workspace-content-contract.test.ts | 2 + .../content/workspace-content-contract.ts | 21 ++ .../content/workspace-content-reader.test.ts | 58 +++++- .../content/workspace-content-reader.ts | 39 +++- .../content/workspace-read-references.ts | 4 +- .../documents/document-ai-edits.test.ts | 6 +- .../workspaces/documents/document-ai-edits.ts | 136 +++++++++++- .../documents/document-ai-html.test.ts | 72 ++++++- .../workspaces/documents/document-ai-html.ts | 176 +++++++++------- .../documents/document-preview-text.test.ts | 38 ++++ .../documents/document-preview-text.ts | 4 + .../workspaces/documents/document-session.ts | 39 +++- .../documents/document-widget-node.tsx | 44 ++++ .../workspaces/documents/tiptap-extensions.ts | 2 + .../workspaces/documents/tiptap-schema.ts | 55 ++++- .../kernel/workspace-kernel-access.ts | 21 +- .../kernel/workspace-kernel-files.ts | 5 +- .../kernel/workspace-kernel-item-commands.ts | 54 +++-- .../kernel/workspace-kernel-types.ts | 11 - .../workspaces/kernel/workspace-kernel.ts | 19 +- src/features/workspaces/model/item-display.ts | 11 +- .../model/use-workspace-item-path.ts | 26 +++ .../model/workspace-ai-context-reference.ts | 9 +- .../workspace-tool-surface.test.ts.snap | 63 +++++- .../workspaces/operations/create-items.ts | 5 +- .../operations/workspace-tool-definitions.ts | 6 +- .../operations/workspace-tool-schemas.ts | 42 +++- src/features/workspaces/query-options.ts | 19 +- src/features/workspaces/server/functions.ts | 11 + .../workspace-ai-composer-draft-store.ts | 55 ++++- .../workspaces/workspace-item-registry.ts | 35 +++- src/styles.css | 74 +++++++ 61 files changed, 2501 insertions(+), 234 deletions(-) create mode 100644 eval/__reports__/math-authoring.md create mode 100644 eval/datasets/math-authoring.cases.ts create mode 100644 eval/math-authoring.eval.ts create mode 100644 scripts/copy-widget-libs.mjs create mode 100644 src/features/workspaces/ai/skills/widget-authoring/SKILL.md create mode 100644 src/features/workspaces/components/ai-chat/useConsumeComposerPrompt.ts create mode 100644 src/features/workspaces/components/widget/WorkspaceAddWidgetDialog.tsx create mode 100644 src/features/workspaces/components/widget/WorkspaceWidgetSandbox.tsx create mode 100644 src/features/workspaces/components/widget/workspace-widget-sandbox-document.test.ts create mode 100644 src/features/workspaces/components/widget/workspace-widget-sandbox-document.ts create mode 100644 src/features/workspaces/documents/document-preview-text.test.ts create mode 100644 src/features/workspaces/documents/document-widget-node.tsx create mode 100644 src/features/workspaces/model/use-workspace-item-path.ts diff --git a/.gitignore b/.gitignore index b3216757a..7cea18f11 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ references # Local eval scratch output tmp-eval/ + +# Vendored browser builds for widget sandboxes (generated by scripts/copy-widget-libs.mjs) +public/widget-libs/ diff --git a/eval/__reports__/math-authoring.md b/eval/__reports__/math-authoring.md new file mode 100644 index 000000000..85fb008b6 --- /dev/null +++ b/eval/__reports__/math-authoring.md @@ -0,0 +1,88 @@ +case | claude-sonnet| claude-haiku | gpt-luna | gemini-pro +-------------------------------------------------------------------------------------------------------- + +document: study sheet with formulas | PASS | PASS | PASS | PASS +document: exponents and subscripts in prose | PASS | PASS | PASS | PASS +document: chemistry equation | FAIL | PASS | PASS | PASS +document: prices only (currency must stay pl| PASS | PASS | PASS | PASS +document: money AND math together (opposite | PASS | FAIL | PASS | PASS +chat: explain a formula | PASS | PASS | PASS | PASS +chat: money question | PASS | PASS | PASS | PASS +chat: money and math in one answer | PASS | PASS | FAIL | FAIL +widget: interactive with a formula | PASS | PASS | PASS | PASS +document: user types dollar math in the prom| PASS | PASS | PASS | PASS +document: user types bracket math in the pro| PASS | PASS | PASS | PASS +document: editing an existing doc adds an eq| FAIL tool✗ | FAIL tool✗ | FAIL tool✗ | FAIL tool✗ + +claude-sonnet 10/12 content rules satisfied +claude-haiku 10/12 content rules satisfied +gpt-luna 10/12 content rules satisfied +gemini-pro 10/12 content rules satisfied + +document 26/32 across all models +chat 10/12 across all models +widget 4/4 across all models + +failures + +[claude-sonnet] document: chemistry equation +must not contain / tags +--- wrote: document +/Methane Combustion +

Methane Combustion

Methane (CH) is the simplest hydrocarbon and the main component of natural gas. When it burns, it reacts with oxygen in a process called combustion, releasing energy as heat and light.

Complete Combustion

With plentiful oxygen, methane burns completely to form carbon dioxide and water vapor:

This reaction is exothermic, meaning it releases energy. This is why methane (natural gas) is used as a f… + +[claude-haiku] document: money AND math together (opposite dollar rules) +must not contain backslash-escaped \$ +--- wrote: document +/Compound Interest Guide +

Compound Interest

+ +

What is Compound Interest?

+

Compound interest is interest earned on both the principal amount and the accumulated interest from previous periods. This creates exponential growth over time, making it a powerful tool for long-term investments and savings.

+ +

The Compound Interest Formula

+

The standard formula for compound interest is:

+
+ +

Where:

+