Skip to content

FE-1448: Let Petrinaut hosts render interactive chat tools - #9249

Draft
lunelson wants to merge 2 commits into
mainfrom
ln/fe-1448-host-interactive-tools
Draft

FE-1448: Let Petrinaut hosts render interactive chat tools#9249
lunelson wants to merge 2 commits into
mainfrom
ln/fe-1448-host-interactive-tools

Conversation

@lunelson

@lunelson lunelson commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

🌟 What is the purpose of this PR?

Brunch — the elicitation agent being integrated with Petrinaut — needs to ask its questions inline in Petrinaut's chat panel, but the panel could only render its own built-in interactive tool, and @hashintel/petrinaut must stay free of Brunch-specific code. This PR adds a public, typed extension point through which an embedding application registers its own interactive chat tools: a registered tool renders inline, collects exactly one submitted answer, and returns it to the assistant through the same follow-up path the built-in tools use.

🔗 Related links

🚫 Blocked by

Nothing.

🔍 What does this change?

Before this change, the chat panel's interactive-tool registry was private and hard-coded to Petrinaut's own applyAutoLayout confirmation widget, so any other dynamic tool call was rejected before a host could render or handle it. The panel now accepts host-registered tools through the public aiAssistant configuration: a host defines a tool with definePetrinautAiInteractiveTool — a tool name, input and output parsers, and a React component — and the panel renders it inline, keeps it visible as a read-only record after submission, and sends exactly one output back to the assistant. Built-in tools keep their behavior, and a dynamic tool that no host registered still fails loudly.

🏗️ Agent notes

Public API and type erasure

  • definePetrinautAiInteractiveTool and the PetrinautAiInteractiveTool* types are exported from @hashintel/petrinaut; hosts pass registrations through aiAssistant.interactiveTools.
  • The definition type preserves the relationship between the input/output schemas and the component's props; registration erases those generics behind a symbol-keyed opaque type so heterogeneous host tools share one registry without any.
  • Parsers are structural ({ parse(value: unknown): Value }), so Zod, Valibot, or hand-written parsers all fit without a validation-library choice leaking into the public API.

Lifecycle

  • Widget props are a discriminated union over state: "awaiting" | "submitted", with a stable AI SDK toolCallId; submit accepts exactly one output — duplicate submissions are ignored and produce exactly one automatic follow-up through the existing addToolOutput path.
  • A submission the output parser rejects leaves the widget retryable rather than wedged half-submitted.

Verification

  • Registry tests cover merging built-in and host tools and the loud unknown-tool failure.
  • Lifecycle tests drive the real AiAssistantPanel through submission, duplicate submission, and rejected-then-retried submission, asserting exactly one follow-up request; the synthetic test transport's steps are delimited to prevent repeated follow-ups.
  • The Petrinaut / WithHostInteractiveAiTool story registers a visible synthetic host tool, styled with Panda.

Commits

  • 57913da2bb adds the host interactive-tool API and registry routing.
  • 720c6b1097 proves the follow-up lifecycle against the real panel and adds the visible story.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • I am unsure / need advice

@hashintel/petrinaut is npm-publishable and this branch carries no changeset; the changeset for this extension point currently lives on #9274, so whether this branch needs its own depends on merge order — see Known issues.

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR

The end-user AI assistant guide now describes host-provided inline tools, and the package README documents the public API.

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

PR #9274 (FE-1437, the Brunch monorepo import) carries an evolved variant of this extension point together with a real host tool (brunch_ask in apps/petrinaut-website) and the @hashintel/petrinaut changeset. The two branches' Petrinaut trees have diverged, so whichever merges second must be reconciled against the first; merge order is an open sequencing decision.

🐾 Next steps

FE-1449 (already done) built on this mechanism to prove that a structured Brunch question suspends and resumes through the real panel; that work now travels with the FE-1437 import branch (#9274). The remaining step for this PR is the reconciliation described under Known issues.

🛡 What tests cover this?

  • Interactive-tool registry tests: built-in and host tools merge, and an unregistered dynamic tool fails loudly.
  • AiAssistantPanel lifecycle tests: submission, duplicate submission, and rejected-then-retried submission, with exactly one follow-up request.
  • The visible WithHostInteractiveAiTool Storybook story exercising a synthetic host tool.

❓ How to test this?

  1. Run turbo run test:unit --filter '@hashintel/petrinaut'.
  2. Open the Storybook story Petrinaut / WithHostInteractiveAiTool.
  3. Trigger the synthetic host tool, submit it, and confirm the widget moves from awaiting to a read-only submitted record with a single assistant follow-up and no duplicate question.

📹 Demo

The WithHostInteractiveAiTool story is the runnable demo surface: it shows the synthetic host tool inline in the chat panel, before and after submission.

🤖 Generated with Claude Code

Exercise the real AiAssistantPanel and AI SDK addToolOutput path, including exactly one automatic follow-up after duplicate submits.

Keep rejected submissions retryable, use Panda styles in the visible story, and delimit the synthetic transport steps to prevent repeated follow-ups.
@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 19, 2026 12:59pm
petrinaut Ready Ready Preview Aug 19, 2026 12:59pm
petrinaut-docs Ready Ready Preview Aug 19, 2026 12:59pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 19, 2026 12:59pm

@github-actions github-actions Bot added 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 area/apps > hash.design Affects the `hash.design` design site (app) labels Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@lunelson lunelson changed the title FE-1448: add host interactive AI tools FE-1448: Petrinaut hosts render their own interactive chat tools Aug 19, 2026
@lunelson lunelson changed the title FE-1448: Petrinaut hosts render their own interactive chat tools FE-1448: Let Petrinaut hosts render interactive chat tools Aug 23, 2026
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/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

Development

Successfully merging this pull request may close these issues.

1 participant