Skip to content

FE-1776: Add assistant plugins and move chat into the website - #9914

Closed
kube wants to merge 13 commits into
mainfrom
claude/plugin-v1-petrinaut-ai-in-website
Closed

kube wants to merge 13 commits into
mainfrom
claude/plugin-v1-petrinaut-ai-in-website

Conversation

@kube

@kube kube commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Before this PR, hosts passed the AI assistant through the aiAssistant prop. @hashintel/petrinaut rendered the chat itself: transcript, composer, tools and Voice. Website switched that one configuration object between the stock assistant and Brunch.

This PR makes the assistant a plugin. A plugin declares assistant in its manifest and returns its whole UI as assistant.view, which draws the library's PetrinautAssistantWindow around its transcript. Chat moves to the website's plugins/_shared/chat, where Petrinaut AI, Brunch and the AI experiments demo render it through the plugin api. An editor without an assistant plugin shows no AI entry point.

Links

Changes

Library

  • Manifest assistant provides an assistant or extends one

    { label } provides one, whose hook returns its view, tabs and startActions under assistant.
    { extends } adds tabs and start actions to that plugin's assistant and runs only while that plugin runs.

  • Editor shows one assistant at a time

    Stored aiAssistantId wins while its plugin runs, otherwise the first running assistant shows.
    Once two run, User settings > General > AI assistant and palette commands switch between them.

  • api.assistant.isActive tells a plugin whether its assistant is shown
  • PetrinautAssistantWindow frames an assistant's view

    Window owns header, tabs, docking, floating, compact layout and tab attention.
    usePetrinautAssistantWindow reads the window's state from inside the view.
    PetrinautAssistantWindowPreview hosts a view outside an editor.

  • View and each tab fail alone

    A failed view leaves a window that says so. A tab reusing a taken id is left out and reported.

  • Empty-net prompt offers the assistant's first start action

    Replaces the built-in Voice button.

  • Plugins section tags the assistant a plugin provides or extends

    An extension whose assistant is not running shows Needs ….

  • aiAssistant prop and every chat export removed

    ai, @ai-sdk/react and react-markdown leave the library's dependencies.
    Core drops createPetrinautAiWritableCallbacks, whose only caller this PR deletes.

  • Pending changesets for the moved chat removed

    Mixed changesets keep their library part.
    Changelog's hand-written Unreleased block goes too.

Website

  • Chat kit lives in plugins/_shared/chat

    Chat view, transcripts, tools, transports and Voice session move from the library as renames, tests included.
    @ai-sdk/react, @ark-ui/react and vscode-languageserver-types join the website's dependencies.

  • AssistantChat reaches the editor only through the plugin api

    Edits run through document.edit and diagnostics through document.diagnose().
    Experiments run through experiments.run, and tool cards reveal through editor.reveal.

  • Petrinaut AI is the website.petrinaut-ai plugin

    Renders the chat over /api/chat and saves each document's transcript in local storage.

  • Brunch renders through the website.brunch bridge plugin

    Shell still builds Brunch's chat and Ledger tab and hands them over through BrunchBridgeContext.
    With Use Brunch on, the shell passes brunchDemoPlugins in place of demoPlugins.

  • /ai-experiments passes its scripted assistant as a plugin
  • Chat applies stored messages only until it first reports a transcript

    Petrinaut AI passes its saved transcript back a commit behind the chat.
    Applied later, it would undo a fast tool continuation.

  • Tests compile the shared chat with the React Compiler

    React Compiler lint rules are errors under plugins/_shared/chat.
    vitest.setup.ts shims matchMedia for jsdom.

Known issues

  • Website tests compile only the shared chat with the React Compiler

    App compiles every website module.

Next steps

  • Split the chat's "stock" | "brunch" presentation into its plugins

    Stock transcript, Brunch transcript and voice dock move to plugins/petrinaut-ai/, plugins/brunch/ and plugins/voice/.

Test coverage

  • plugin-assistant.test.tsx:

    Resolution and stored choice, failed assistants and parents, failing or clashing tabs, failing views, switch commands and canvas insets.

  • assistant-window.test.tsx, tab-attention.test.ts:

    Chat stays mounted through dock, close and reopen, plus tab fallback, attention badges and announcements, focus and the preview.

  • plugin-statuses.test.ts, define-petrinaut-plugin.test.ts:

    Extension status, resolveActiveAssistantId, and type tests for the assistant manifest.

  • user-settings.test.tsx, ai-cta-modal.test.tsx:

    Needs … chip, assistant selector and the prompt's start action.

  • petrinaut-ai/plugin.test.tsx:

    Empty-net prompt starts a chat in the real editor that edits the net and saves the transcript under the document's id.

  • Moved suites under plugins/_shared/chat:

    Run the chat against a test plugin api.

How to test

Petrinaut AI

  • Open Petrinaut preview on Vercel
  • Menu > New

    Expect empty-net prompt

  • Submit Build an SIR model in prompt

    Expect window open and net built

  • Float AI assistant
  • Dock AI assistant
  • Close AI assistant
  • Press ⌘⇧K

    Expect conversation kept and focus in composer

  • Menu > User settings > Plugins > Petrinaut AI

    Expect Assistant tag naming Petrinaut

  • Switch Petrinaut AI off

    Expect no Show AI assistant button in bottom bar

AI experiments demo

  • Open AI experiments demo on Vercel
  • Bottom bar > Show AI assistant
  • Send run

    Expect experiment progress, then result card

@kube kube self-assigned this Oct 5, 2026
@vercel

vercel Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Oct 12, 2026 7:57pm UTC
petrinaut Ready Ready Preview Oct 12, 2026 7:57pm UTC
petrinaut-docs Ready Ready Preview Oct 12, 2026 7:57pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Oct 12, 2026 7:57pm UTC

Request Review

@CLAassistant

CLAassistant commented Oct 5, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/apps > hash* Affects HASH (a `hash-*` app) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team area/apps labels Oct 5, 2026
@kube
kube added this pull request to stack #9915 October 5, 2026 01:29
@kube kube changed the title Move Petrinaut AI into the website plugin and remove it from the HASH app Move the AI chat into the website plugins and remove Petrinaut AI from the HASH app Oct 5, 2026
@github-actions github-actions Bot added the area/apps > hash.design Affects the `hash.design` design site (app) label Oct 5, 2026
@kube
kube force-pushed the claude/plugin-v1-petrinaut-ai-in-website branch from a287b93 to f6f307e Compare October 5, 2026 12:28
@kube
kube force-pushed the claude/plugin-v1-hash-embed-chrome branch from 8f102fe to 00b60b0 Compare October 5, 2026 12:28
@kube
kube removed this pull request from stack #9915 October 7, 2026 17:11
@kube
kube force-pushed the claude/plugin-v1-petrinaut-ai-in-website branch from f6f307e to 76e663d Compare October 7, 2026 17:12
@kube
kube force-pushed the claude/plugin-v1-hash-embed-chrome branch from 00b60b0 to 5ebadbe Compare October 7, 2026 17:12
@github-actions github-actions Bot removed the area/apps > hash* Affects HASH (a `hash-*` app) label Oct 7, 2026
@kube
kube force-pushed the claude/plugin-v1-petrinaut-ai-in-website branch from e7fc133 to 19ebd53 Compare October 8, 2026 22:00
@kube
kube added this pull request to stack #9937 October 8, 2026 22:01
@kube kube changed the title Add assistant plugins and move Petrinaut AI into a website plugin FE-1776: Add assistant plugins and move chat into the website Oct 9, 2026
@kube
kube force-pushed the claude/plugin-v1-hash-embed-chrome branch from c6d099f to 3023386 Compare October 9, 2026 02:42
@kube
kube force-pushed the claude/plugin-v1-petrinaut-ai-in-website branch from 19ebd53 to 2567041 Compare October 9, 2026 02:42
@kube
kube force-pushed the claude/plugin-v1-petrinaut-ai-in-website branch from 2567041 to 458f3d4 Compare October 9, 2026 09:45
@cursor

cursor Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

PR Summary

High Risk
Breaking change to Petrinaut embedding: removes the built-in assistant and aiAssistant API in favor of plugins, with chat/tool execution paths rewritten around document.edit.

Overview
Replaces the built-in aiAssistant prop with assistant plugins and moves the full chat stack (transcript, composer, tools, Voice) out of @hashintel/petrinaut into the website’s plugins/_shared/chat as AssistantChat, which talks to the editor only through the plugin api (document.edit, experiments.run, editor.reveal, notifications).

Hosts register assistants via manifest assistant and render inside PetrinautAssistantWindow; the demo wires Petrinaut AI (website.petrinaut-ai), Brunch (website.brunch + BrunchBridgeContext), and AI experiments as plugins instead of passing one aiAssistant object. Tool execution drops executeMutation / writable callbacks and uses edit on the plugin boundary; core removes createPetrinautAiWritableCallbacks.

Tests and docs follow the plugin model (assistant probing, PetrinautAssistantWindowPreview, React Compiler lint on shared chat). Many pending changesets are deleted or narrowed to match the slimmer library surface.

Reviewed by Cursor Bugbot for commit 15b91de. Bugbot is set up for automated code reviews on this repo. Configure here.

kube added 13 commits October 12, 2026 19:42
The frame, header, tab strip, tabs, docking, focus and tab attention move
out of the chat view into PetrinautAssistantWindow, which the chat draws
around its transcript. The editor keeps the shown tab, start requests and
focus requests above the chat, which reads them through
usePetrinautAssistantWindow. PetrinautAssistantWindowPreview hosts a chat
outside an editor for stories and tests.
Renames only: the AI panel, its chat view, tools, transports, voice
session and the chat types move from the library to
apps/petrinaut-website/src/main/app/plugins/_shared/chat. Imports are not
updated here, so this commit does not build alone; the next commits adapt
the library and the kit.
A plugin with `assistant: { label }` provides the editor's AI assistant; one with `assistant: { extends }` adds tabs and start actions to another plugin's. The provider resolves the active assistant once, from the stored `aiAssistantId` or the first running assistant, and User settings -> General -> AI assistant and the palette's switch commands change it. An extension whose parent is missing or off shows "Needs ..." in the Plugins section.

The library drops the `aiAssistant` prop, its chat types and stories, and the AI SDK and react-markdown dependencies, which move to the website with the chat kit.
`AssistantChat` takes the assistant plugin's `api` (document and experiments, write access) and holds it in a kit-owned context, so the chat reads the net, edits it, runs experiments and reports errors through the plugin api instead of the editor's internals. Refused edits come back as blocked tool output. Each chat renders its own Voice session.

`executePetrinautAiMutation` and the automatic tools take `edit`. Core drops `createPetrinautAiWritableCallbacks`, which nothing uses any more.
`website.petrinaut-ai` renders the shared chat as its assistant view and keeps each document's transcript in this browser; the `/ai-experiments` route passes its scripted assistant as `website.ai-experiments-demo`. While Brunch is the selected assistant, the shell passes `website.brunch`, a bridge plugin that renders the Brunch chat and Ledger tab the shell still builds.

Website imports of the chat kit come from `plugins/_shared/chat`, and the Brunch tools edit through the plugin api.
The website's unit and integration tests load a `matchMedia` shim for jsdom, the shared chat's components compile with the React Compiler under test, and the React Compiler lint rules apply to `plugins/_shared/chat`.
Adds the Assistant plugins and host-tools pages, the assistant window diagram, the assistant rows of the plugin usage manual and the demo site's assistant plugins, and points the README's AI section and the user guide at them. The user guide describes the AI assistant setting and the Needs chip.

Pending @hashintel/petrinaut changesets whose subject moved to the website with the chat (Brunch, Voice, chat and tool UI) are deleted; mixed ones keep the part that stays in the library. The changelog's hand-written Unreleased block, which announced the same chat and Voice APIs, goes too.
The Brunch bridge offers Voice's start action in the empty-net prompt again while its chat has Voice mode. The assistant window leaves out a tab that reuses the chat tab's id or another tab's and reports it under that plugin's id, instead of throwing outside every plugin boundary. The chat tab falls back to the plugin's assistant label, as the user guide now says. The browser-storage helpers move to app/shared, so Petrinaut AI no longer imports from the demo shell.

Review cleanups: one list of running assistants, one select style in User settings, the preview built on the standalone host, the auto-layout output in one helper, an empty test instance for the kit tests, type tests for the assistant manifest, and no dead exports, aliases, stale names or blank-line-only hunks.

Docs: the user guide calls the stock assistant Petrinaut AI and describes assistants in the Plugins section; the plugin pages, diagrams and the AI-experiments, snapshot-diagnostics and testing notes describe the assistant runtime as built.
Assistant tab activity identities are strings, so the attention state keeps them as given. The user guide drops the removed host mutation check, the experiment chat page names the chat as the dispatcher, and the moved kit's comments name the chat rather than the library. The changesets name the added assistant API and the removed exports, and keep the release notes for the assistant window's clearance and auto-layout framing. The AI experiments demo names its plugin, the jsdom shim leaves matchMedia to the vitest setup, and new tests cover Petrinaut AI in the real editor and the canvas insets of a window whose assistant is off.
Petrinaut AI passes its saved transcript back through the plugin a commit
after the chat's own state, so the first idle render after a fast tool
continuation restored the step before it. The chat now applies the stored
transcript only until it first reports one. The plugin test preloads the
language server worker, whose cold import made diagnose() slow under load.
@kube

kube commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #10103, #10104, #10105 and #10106, which split this change into four PRs: the assistant panel API, Petrinaut AI on the website's chat, Brunch on the website's chat, and the removal of the built-in chat. The branch stays.

This branch was successfully deployed

3 active deployments
Preview – hash — 15b91de4 Deployed Oct 12, 2026 by vercel[bot]
Preview – petrinaut-docs — 15b91de4 Deployed Oct 12, 2026 by vercel[bot]
Preview – petrinaut — 15b91de4 Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/apps area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants