chat reasoning + tool-call templates (chat 0.0.19, langgraph 0.0.11, ag-ui 0.0.3)#192
Merged
Merged
Conversation
Optional fields on the shared Message contract. Adapters populate them from provider-agnostic sources (LangGraph reasoning/thinking content blocks, AG-UI REASONING_MESSAGE_* events). UI primitives consume the fields without provider-specific knowledge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders millisecond durations as compact human-readable labels: <1s, Ns, Nm Ms. Powers the chat-reasoning 'Thought for Ns' pill. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pill-shaped header with chevron + animated pulse dot for the streaming state, expanded body with thin left border (matches the blockquote pattern). Muted text throughout so reasoning content recedes next to the response. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders model reasoning content as a compact pill. Three visual states (streaming with pulse + auto-expand, idle with 'Thought for Ns', idle with 'Show reasoning' fallback). User toggle wins over auto logic for the lifetime of the instance. Body re-uses chat-streaming-md so markdown in reasoning output renders consistently with the response. Adds @analogjs/vite-plugin-angular to the chat library's vite config (with pool: 'forks' to preserve existing test isolation) so that Angular signal inputs resolve correctly in vitest HostComponent specs. Also adds tsconfig.spec.json required by the Angular compiler plugin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mendments Phase 2 review found three issues. Behavioral fix: re-add the constructor effect that resets the manual expanded-override to null when isStreaming transitions false→true (spec §3.3 bullet 3 — same component instance reused across follow-up turns auto-expands when the next reasoning phase begins). The previous "preserves user choice" test conflated two scenarios; replace with one test asserting bullet 2 (no force-collapse on true→false), one test asserting user collapse persists, and one test asserting auto-reset on false→true. Spec drift: amend §3.1 so the content input defaults to '' (matching the shipped pragmatic API; pairs cleanly with data-has-content="false" hide-when-empty styling). Drop the unused [chatReasoningLabel] slot from §3.1 — the [label] string input covers the common case. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per-tool-name template registry consumed by <chat-tool-calls>. A '*' wildcard registers a catch-all for any unmapped tool name. Also extends DebugElement.prototype.queryAll in test-setup to traverse DebugNode (comment) children so directive-on-ng-template specs can use the injector-predicate pattern under Angular 21. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original spec used DebugElement.queryAll to enumerate directive instances, which doesn't traverse comment nodes (where ng-template compiles). The previous workaround monkey-patched DebugElement.prototype.queryAll across the whole chat library — too broad. Use viewChildren(ChatToolCallTemplateDirective) on the host component instead; it picks up directives on ng-template nodes naturally and needs no test-infrastructure changes. Revert the monkey-patch in test-setup.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sequential same-name tool calls auto-group into a collapsible strip
with a sensible default summary ('Searched N sites'). Consumers can
register per-tool-name templates via chatToolCallTemplate to fully
replace the default card UX, plus a '*' wildcard for any unmapped
name. [grouping]='none' opts out of the auto-collapse behavior;
[groupSummary] lets callers override the default registry.
Also widens ToolCallInfo to carry an optional status — Phase 5 will
use this to drive the at-a-glance status pill on chat-tool-call-card.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tool-call cards now render a consistent status pill (spinner / checkmark / error glyph) regardless of state, and default to collapsed when complete. Running and errored cards stay expanded so progress and failures are visible without clicks. User toggle wins for the lifetime of the card. Adds defaultExpanded input to chat-trace; drops the unused 200ms auto-collapse-on-done timeout in favor of explicit defaults driven by consumers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walks complex-content arrays for {type:'reasoning'}/{type:'thinking'}
blocks (provider-agnostic between OpenAI Responses API and
Anthropic). Same accumulator semantics as accumulateContent: superset
takes priority for final-id swap, prefix-match keeps the longer side,
otherwise pure-delta append. Returns string so downstream code never
sees the raw block array. Exports _internalsForTesting for conformance
tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ming
mergeMessages now reads incoming reasoning content (from
{type:'reasoning'|'thinking'} blocks or an explicit Message.reasoning
field) and accumulates it into the merged slot alongside response
text. A per-message reasoningTimingMap captures when reasoning chunks
first arrive and when response text first overlaps; the manager
exposes getReasoningDurationMs(id) so the agent.fn projection can
populate Message.reasoningDurationMs. Map is cleared on thread
switch and bridge teardown.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ationMs agent.fn's toMessage projection reads the bridge's accumulated reasoning string and asks the manager for the per-message duration. Both fields land as undefined when no reasoning was emitted, so existing consumers see no shape change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
REASONING_MESSAGE_START creates (or finds) an assistant slot with an empty reasoning string and starts a per-message timing entry. REASONING_MESSAGE_CONTENT/CHUNK appends to it. REASONING_MESSAGE_END records the end timestamp and writes Message.reasoningDurationMs onto the slot. TEXT_MESSAGE_START is now idempotent so a follow-up text stream on the same messageId reuses the existing slot rather than splitting reasoning + response into separate messages. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Optional reasoningTokens?: string[] constructor argument that, when provided, emits a REASONING_MESSAGE_START → CONTENT × N → END sequence before the existing text-message stream. provideFakeAgUiAgent plumbs the new option through. Lets demo apps and integration tests exercise the reasoning UI end-to-end without a real model. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Defines a canonical abstract event sequence (reasoning start → three chunks → end → text start → three chunks → end) and an assertReasoningFixtureMessages() helper that both adapter conformance suites use to verify identical Message[] output. Keeps the populating logic for Message.reasoning + reasoningDurationMs honest across implementations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Translates the shared @ngaf/chat/testing fixture sequence into AG-UI wire format and asserts the reducer produces the expected Message[] shape (single assistant message with full reasoning, full content, and a non-negative reasoningDurationMs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Translates the shared @ngaf/chat/testing fixture sequence into
LangGraph AIMessageChunk shape (complex-content arrays with
{type:'reasoning'} and {type:'text'} blocks) and asserts the bridge's
mergeMessages + toMessage projection produces the same Message[]
shape AG-UI does. One fixture, two adapters — keeps both honest.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Array.prototype.map passes (value, index, array) to its callback. Passing toMessage directly caused TypeScript to infer that the optional second parameter (getReasoningDurationMs: (id: string) => number | undefined) could receive the numeric index, producing TS2345. Wrapping it in an arrow function makes the call explicit and type-safe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mplate When an assistant Message carries a non-empty reasoning string, the chat composition automatically renders <chat-reasoning> above the response markdown. The pill streams visibly while reasoning content is arriving (tail message + agent loading + no response text yet), then collapses to 'Thought for Ns' once response tokens begin. Consumers projecting <ng-template chatToolCallTemplate='search_web'> directly into <chat> have those templates forwarded into the inner <chat-tool-calls> via the same outer-content re-projection pattern used for [chatInputModelSelect] and [chatWelcomeSuggestions]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hangelog Six new/updated MDX pages covering Phase B2 surface: - New chat-reasoning.mdx — primitive reference (states, inputs, slot) - New chat-tool-call-template.mdx — directive reference + dispatch order - New chat-tool-calls.mdx — grouping inputs + default summaries + template extension - Updated chat-tool-call-card.mdx — status pill table + default-collapsed - Updated chat.mdx — reasoning subsection + tool-call template projection example - New getting-started/changelog.mdx — 0.0.19 entry Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Add @analogjs/vite-plugin-angular to ignoredDependencies in the chat project's eslint config — it is used only in vite.config.mts for test setup and must not appear in the published package dependencies. Co-Authored-By: Claude Opus 4.7 (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.
Summary
Stacks on top of #191 (chat 0.0.18 + langgraph 0.0.10).
Reasoning (new)
<chat-reasoning>primitive renders model reasoning content as a collapsible "Thinking…" / "Thought for Ns" pill above the assistant response. Auto-rendered by<chat>whenMessage.reasoningis populated.Message.reasoning+Message.reasoningDurationMsoptional fields on the shared agent contract. Both adapters populate them from provider-agnostic sources: LangGraph{type:'reasoning'|'thinking'}blocks, AG-UIREASONING_MESSAGE_*events.assertReasoningFixtureMessagesconformance test ensures both adapters produce identical Message[] from the same abstract event sequence.Tool-call extension surface
chatToolCallTemplatedirective registers per-tool-name templates inside<chat-tool-calls>. A"*"wildcard catches unmapped names.<chat-tool-calls>auto-groups sequential same-name calls into a labeled strip ("Searched 5 sites").[grouping]="'none'"opts out.<chat-tool-call-card>defaults to collapsed whencomplete; running and errored cards stay expanded. Status pill (spinner / check / error glyph) replaces inline plaintext.<chat>re-projectschatToolCallTemplatedirectives into the inner<chat-tool-calls>.FakeAgent
FakeAgentgains an optionalreasoningTokensconstructor option for offline demos and integration tests.Docs
chat-reasoning.mdx,chat-tool-call-template.mdx,chat-tool-calls.mdx.chat-tool-call-card.mdx,chat.mdx.Infra
@analogjs/vite-plugin-angular+tsconfig.spec.jsoninto the chat library so vitest can run Angular component specs (TestBed, signal inputs).Bumps
@ngaf/chat0.0.18 → 0.0.19,@ngaf/langgraph0.0.10 → 0.0.11,@ngaf/ag-ui0.0.2 → 0.0.3.Test plan
~/tmp/ngaf+ LangGraphlanggraph dev+ gpt-5-mini atreasoning.effort='minimal': reasoning pill appears + collapses after streaming.reasoning.effort='high': reasoning streams visibly while pill says "Thinking…", collapses on text start.chatToolCallTemplate="search_web"in the smoke app; verify it replaces the default card.🤖 Generated with Claude Code