feat: client-tools — frontend-declared, frontend-executed tools (foundation)#642
Open
blove wants to merge 28 commits into
Open
feat: client-tools — frontend-declared, frontend-executed tools (foundation)#642blove wants to merge 28 commits into
blove wants to merge 28 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Design for a new client-tools capability: tools declared in the Angular app (name + description + Standard Schema) that the model calls, routed back to the client to execute as an async function, a rendered view, or an interactive (HITL) component. Covers the render-lib component contract (schema/description metadata + typed injectRenderHost result channel), chat-lib tools()/action/ view/ask + executor + Agent.clientTools, both adapters unified on end+re-run (no interrupt()), and a published Python LangGraph middleware. TS LangGraph.js middleware deferred to a fast-follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Decompose client-tools into six dependency-ordered, independently-testable plans. Plan 01 (render foundation) is full TDD detail: RenderViewEntry schema/description, RenderResultEvent, and an element-scoped injectRenderHost() (set/emit/result) added alongside the legacy emit so each step stays green; the a2ui:datamodel: removal + catalog migration is isolated in plan 01b. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task 1 now vendors the Standard Schema type instead of npm-installing @standard-schema/spec, per the repo rule against regenerating package-lock.json on macOS (drops Linux @next/swc-* bindings, breaks CI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…space lint The upstream Standard Schema vendoring snippet uses a TS namespace, which this repo forbids (@typescript-eslint/no-namespace, enforced as error). Flatten the nested types to top-level StandardSchema* aliases; the StandardSchemaV1 interface (the only consumed symbol so far) is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l string protocol) - Rewrite emitBinding() to accept RenderHost and call host.set(path, value) with the typed value instead of emitting a2ui:datamodel: strings - Update 5 catalog components (text-field, check-box, slider, date-time-input, multiple-choice): inject injectRenderHost(), remove emit input, swap call sites - multiple-choice onCheckChange now passes the actual string[] array to host.set instead of JSON.stringify (no more string coercion needed) - Update all 6 specs (emit-binding + 5 component specs) to assert against host.set([path, value]) pairs with typed values Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Now that all catalog components write via RenderHost.set(), the legacy a2ui:datamodel: string intercept in emitFn is dead code. Remove: - A2UI_DATAMODEL_PREFIX constant - applyDatamodelWrite() method (path/value splitting + store write) - coerceValue() helper (no longer needed; host.set receives typed values) - The if (event.startsWith(PREFIX)) branch in emitFn emitFn now simply delegates all events to invokeHandlers(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace references to the old magic-string emit protocol with the new injectRenderHost().set() description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…N-schema derivation) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the ClientToolsCapability interface (pending signal + setCatalog/resolve), wires it as optional onto the Agent contract, and implements the pure execute helpers (validateArgs / executeFunctionTool) plus startClientToolExecutor which auto-dispatches pending function-tool calls via an Angular effect while leaving view/ask tools for the rendering layer. Covered by TDD specs (execute.spec.ts and client-tool-executor.spec.ts) — all pass, 0 lint errors, build green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…essage/re-run) Adds ClientToolsCapability to the AgUiAgent via a testable createClientToolsCapability factory. Threads the catalog into all runAgent calls (submit, resume, regenerate). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… ToolMessage re-run) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…aged publish) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A client tool call is marked status='complete' once its args finish streaming, but it still has no result and needs the browser to execute it. The executor's `tc.status === 'complete'` guard wrongly skipped these, so function tools never ran end-to-end (caught via the live ag-ui/client-tools example). Drop the guard (pending already excludes resolved/result-present calls; inFlight prevents double-dispatch). Regression test now uses status='complete'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…2e + wiring Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0b5bf50 to
5afb3c3
Compare
…ublish (cacheplane org) + name reservation Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-client-tools Switch both example backends off the local path source onto the published PyPI package (threadplane-client-tools>=0.0.1, resolved to 0.0.1). Regenerated uv.lock + requirements.txt. ag-ui e2e re-verified 3/3 green against the PyPI-sourced backend; deploys now resolve the middleware. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-ui/core peer dep Cockpit example apps compile the lib sources with strict:false, where the ClientToolResult / StandardSchemaResult discriminated-union narrowing didn't narrow — failing every example's production build (and cascading to ~all cockpit/chat e2e). Read those fields via explicit casts (runtime-identical; public discriminated-union types unchanged, so strict consumers still narrow). Also add @ag-ui/core to @threadplane/ag-ui peerDependencies (nx dependency-checks). Verified: ag-ui tool-views + langgraph streaming example production builds now green; ag-ui lint clean; chat/ag-ui/langgraph tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Client Tools — frontend-declared, frontend-executed tools
Tools declared in the Angular app (name + description + a Standard Schema) that the model calls and the browser executes — as an async function, a rendered view, or an interactive ask (HITL) component. Per the approved spec (
docs/superpowers/specs/2026-06-08-client-tools-design.md).What's implemented (all green; TDD + reviewed; two examples e2e-verified)
@threadplane/render—RenderViewEntry.schema/description,RenderResultEvent, element-scopedinjectRenderHost()(set/emit/result); a2ui catalog migrated off the legacya2ui:datamodel:string protocol (removed).@threadplane/chat—tools()+action/view/ask; Standard-Schema→JSON-Schema (Zod viazod/v4);Agent.clientTools; function-tool executor;ClientToolsCoordinator; wired intoChatComponent([clientTools]).@threadplane/ag-ui—clientToolsover nativeRunAgentInput.tools+addMessage(ToolMessage)/re-run.@threadplane/langgraph—clientToolsviainput.client_tools+ ToolMessage re-run on the same thread.packages/threadplane-client-tools(Python) — LangGraph middleware (bind client stubs fromstate["tools"], route client calls → END). Stagedworkflow_dispatch-only PyPI publish (dry-run default; no live publish).cockpit/ag-ui/client-toolsandcockpit/langgraph/client-tools, each demoing function/view/ask, with docs + registry/ports/manifest wiring.Verification
status==='complete'bug —7a15b15a— was caught).Before merging (your calls)
threadplane-client-toolsto PyPI (the stagedworkflow_dispatch). The example backends consume it via a local path source, which is fine for the monorepo + e2e but won't resolve in the deployed (Railway/LangGraph) builds until it's on PyPI. Merging before publishing would land example backends that can't deploy.main. Base is currentlyclaude/ag-ui-example-guides(for a clean diff).The unrelated cockpit
next.config.tsturbopack change is intentionally not included.🤖 Generated with Claude Code