feat: TypeScript DX pass — strict-safe tools/view/ask + typed agent DI#685
feat: TypeScript DX pass — strict-safe tools/view/ask + typed agent DI#685blove wants to merge 32 commits into
Conversation
Five-workstream plan to fix the @threadplane public-surface DX defects the audit found: the critical strict-mode tools() rejection + key/value widening, absent view/ask schema<->component linkage, agent generics not flowing through DI, action return type, hover readability, and JSDoc. Core type machinery for WS1 (variance-safe tools()) and WS2 (strict-but-flexible view/ask) verified compiling under strict:true. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ions Add a four-tier validation strategy that uses the cockpit client-tools examples and the canonical langgraph + ag-ui examples as forcing functions: Tier 1 migrates the client-tools apps + canonical examples/ag-ui to the typed APIs AND flips them to strict:true (the flag that hid the original bug); Tier 2 builds all ~35 provideAgent/injectAgent apps as a non-breaking net for the Agent<TState> genericization; Tier 3 live-smokes the client-tools + canonical apps; Tier 4 keeps the unit type-spec gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
18 tasks across the five workstreams + the four-tier example validation (forcing functions). Each lib change is gated by a strict:true type-spec; the cockpit client-tools apps + canonical examples/ag-ui are flipped to strict:true and migrated to the typed APIs. Also corrects the spec's WS1 variance sketch (any-param bivariant member, verified to support internal handler calls). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rget) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…iant AnyFunctionToolDef) Adds a precise `FunctionToolDef<S,R>` for authoring (carries schema + return type) and a bivariant `AnyFunctionToolDef` as the union member in `ClientToolDef`, so typed `action()` results are assignable into the registry under `strictFunctionTypes`. Updates `executeFunctionTool` to accept `AnyFunctionToolDef`; exports `AnyFunctionToolDef` from the public index. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…key + literal-key types `action<S,R>()` now infers the handler return type R and carries it in `FunctionToolDef<S,R>`. `tools<const M>()` is generic over the map so literal keys and per-entry tool types survive into the registry type. WS1 type-spec in tools.type-spec.ts covers arg-inference, return-type inference, union assignability, literal keys, and per-key type preservation; all assertions pass under strict + strictFunctionTypes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sk linkage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nent input linkage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ult Record<string,unknown>) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…c-api export Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…state through DI Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Ref overloads Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…Props/AnyFunctionToolDef Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…drop removed bare-generic injectAgent<T>() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eneric; bag at inject site
…k (forcing function) Flip strict: false → strict: true in the example app's tsconfig (the flag that previously masked function-type variance bugs). The app was already using the new generic action/view/ask/tools API, so no call-site changes were needed; the build passed clean immediately. Migrate the view/ask components to anchor their input types to the shared schemas via ViewProps<typeof schema>, so a schema change is a compile error on the component rather than a silent runtime mismatch. Extract schemas to schemas.ts so both the registry call site and the components reference the same schema object. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…w/ask + createAgentRef typed state (forcing function) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ols + createAgentRef (forcing function) - Flip tsconfig.json to strict:true (build green immediately — no fallout) - Add ItineraryState interface + ITINERARY_AGENT createAgentRef<ItineraryState> in client-tools.ts - Wire provideAgent(ITINERARY_AGENT, …) in app.config.ts; injectAgent(ITINERARY_AGENT) in AgUiShell — removes state cast in submit wrapper - Co-locate DAY_CARD_SCHEMA with DayCardComponent; anchor inputs via ViewProps<typeof DAY_CARD_SCHEMA> — the headline forcing-function proof that compile-time view/ask linkage guards the NG0950 class of bug - Export CLEAR_DAY_SCHEMA from client-tools for symmetry Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rations Migrate three apps to the typed-agent `createAgentRef` DI pattern as Tier-2 forcing functions proving the typed path works across app types: - cockpit/langgraph/streaming/angular: STREAMING_AGENT ref, StreamingState - cockpit/chat/messages/angular: MESSAGES_AGENT ref, MessagesState - examples/chat/angular: DEMO_AGENT_REF ref, DemoState (model/reasoning_effort/gen_ui_mode) Each app gets a new agent-ref.ts, provideAgent(ref, config), injectAgent(ref), and a typed read exercising state assignability. All three nx builds pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pass # Conflicts: # examples/chat/angular/src/app/shell/demo-shell.component.ts
…istantId, drop dead link) + document CompatibleProps optional→required edge Final-review follow-ups: the inject-agent API page showed provideAgent configs missing the required assistantId (throws at runtime) and linked to a non-existent create-agent-ref page. Also document the one CompatibleProps soundness edge (optional schema prop vs required input) — caught by the runtime readiness gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
…gentRef/ToolArgs/ViewProps/AnyFunctionToolDef) + adapter ref overloads Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pass # Conflicts: # libs/chat/project.json # libs/chat/src/public-api.ts # libs/chat/src/testing/type-assert.ts # libs/chat/tsconfig.type-tests.json
…ng e2e #685 replaced the raw failure text with friendly AGENT_ERROR_MESSAGES copy ("Can't reach the server. Check your connection and try again."), which no longer contains "fail"/"error". Mirror the chat example's assertion so the ag-ui error-handling spec asserts the actual classified copy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pass # Conflicts: # examples/ag-ui/angular/src/app/app.config.ts
|
Claude encountered an error after 4m 53s —— View job PR Review — TypeScript DX Pass
This is a well-structured PR. The variance reasoning ( 1. Unnecessary
|
|
Claude finished @blove's task in 3m 24s —— View job PR Review — TypeScript DX Pass
This is a well-structured PR. The variance reasoning ( 1. Unnecessary
|
|
Claude finished @blove's task in 3m 20s —— View job PR Review — TypeScript DX Pass (Synchronize)
The synchronize event is a merge of The variance reasoning ( 1. Unnecessary
|
The required 'Vercel – threadplane' check never posted after repeated branch updates (known Vercel-stall-on-rebase). Empty commit to retrigger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @blove's task in 1m 14s —— View job PR Review — TypeScript DX Pass (Follow-up)
The latest synchronize event ( 1. Unnecessary
|
Summary
A comprehensive TypeScript DX pass on the
@threadplane/*public surface, fixing the developer-facing type defects surfaced by the published-stack audit. The goal: hero primitives that infer correctly understrict: true, link schemas to handler args / component inputs, carry agent state through DI, and read cleanly on hover — validated against the cockpit + canonical examples as forcing functions.The headline bug
tools(map: Record<string, ClientToolDef>)took a non-generic union, so understrictFunctionTypesa typedaction()was not assignable —tools({ move: action(...) })failed to compile for any real Angular CLI consumer. It was masked because every example compiled withstrict: false.Changes (5 workstreams)
tools()/action():tools<const M extends Record<string, ClientToolDef>>(map): Readonly<M>preserves per-key tool types and literal keys;action<S,R>now carries the handler return type. TheClientToolDeffunction member is a bivariantAnyFunctionToolDef(handler: (args: any)) so a preciseFunctionToolDef<S,R>assigns in under strict and internaldef.handler(args)calls still type-check.view()/ask(): strict-but-flexible schema↔component-input linkage (ComponentInputs/CompatibleProps/AcceptComponent). The model-filled props are checked against the component's Angular signal inputs at the call site;ViewProps<typeof schema>derives input types from a schema. A real mismatch (typo prop, wrong type, unrelated component) is a compile error.Agent<TState = Record<string,unknown>>+AgentWithHistory<TState>(default keeps everything non-breaking);createAgentRef<TState>()typed DI handle;provideAgent(ref, cfg)/injectAgent(ref)overloads in both the LangGraph and AG-UI adapters, so state types flow without per-call-site restatement.Prettify<T>for clean quick-info; re-exportsStandardSchema*,ToolArgs,ViewProps,AnyFunctionToolDef,AgentRef,createAgentReffrom@threadplane/chat;@param/@returns/@exampleJSDoc on the hero exports.Equal/Expect*.type-spec.tsfiles compiled under dedicatedstrict: truetsconfigs (type-testsnx target) in chat, langgraph, ag-ui.Plus docs: the langgraph guides were migrated off the now-removed bare-generic
injectAgent<T>()to thecreateAgentRefpattern.Validation (examples as forcing functions)
strict: true+ typed-API migration:cockpit/ag-ui/client-tools,cockpit/langgraph/client-tools, and the canonicalexamples/ag-uiitinerary. Each builds green under full strict; a deliberately-injected schema↔component mismatch was confirmed to fail the strict build (the linkage has teeth).Agent<TState>default contains the genericization ripple. PluscreateAgentRefmigrations inexamples/chat+ two cockpit apps.examples/ag-uie2e 21/21 includingday_cardview render,move_stoppanel mutation, and theclear_dayask chain (the NG0950 path);examples/chate2e green (one known streaming flake, passes in isolation).Final whole-implementation review: no blocking issues; the variance soundness,
view/asklinkage, and agent genericization were all adversarially verified.Design spec and TDD plan are under
docs/superpowers/. No backwards-compatibility constraint (pre-1.0); flat named exports kept.🤖 Generated with Claude Code