`:
+- Label: tool icon + monospace `{toolName}` + status word.
+- Expanded: stacked `Inputs` / `Output` sections, each with 11px UPPERCASE label, `` body using `--ngaf-chat-font-mono` and `--ngaf-chat-font-size-xs`, `whitespace: pre-wrap`. No background fill.
+
+`` headless primitive renders one card per tool call by default.
+
+In assistant turns containing `tool_use` blocks, traces stack **above** the markdown body, inside the assistant message wrapper.
+
+#### Subagents
+`` renders ``:
+- Label: agent icon + "Subagent" + monospace tool-call id chip + status pill.
+- Pill colors: pending=neutral, running=warning + pulse, complete=success, error=error.
+- Expanded: message count line + "Latest message" block matching tool-call layout.
+
+`` headless primitive default-renders these cards.
+
+Active (non-complete, non-error) subagents render stacked above the assistant turn currently producing them.
+
+#### Timeline
+`` becomes a vertical history walk:
+- Each checkpoint = a ``-shaped entry: chevron + timestamp + short summary, indented continuation showing state diff when expanded.
+- A single shared left-border runs through all checkpoints (container `border-left`).
+- Active checkpoint: primary-color chevron + bold label.
+- Hover/click emits `checkpointSelected`.
+- Optional 32px footer below the list with text-button controls (jump-to-latest, replay).
+- Horizontal-slider variant **dropped**.
+
+#### Thread list
+`` data API kept; default projected template restyled:
+- 36px row, `padding: 8px 12px; border-radius: var(--ngaf-chat-radius-button); cursor: pointer`.
+- Active: `background: var(--ngaf-chat-surface-alt); font-weight: 500`.
+- Hover: `background: color-mix(in srgb, var(--ngaf-chat-text) 5%, transparent)`.
+- Single-line ellipsis. No outer borders, no chevrons.
+- Optional "+ New thread" button at top: full-width, dashed border, primary-color text, hover-fills.
+
+In ``, optional collapsed thread-list slot (above the message body), labeled "Threads ▾".
+
+#### Interrupt panel
+`` becomes a content card matching trace aesthetic:
+- `--ngaf-chat-warning-bg`, `border-left: 3px solid var(--ngaf-chat-warning-text)`, `padding: 12px 16px; border-radius: var(--ngaf-chat-radius-card)`.
+- Title row: warning icon + "Agent paused" + dismiss-X.
+- Body: interrupt prompt.
+- Action row: content-projected buttons (Resume / Cancel defaults).
+
+#### Debug composition
+`` keeps its public surface. Inner cards (`debug-checkpoint-card`, `debug-controls`, `debug-detail`, `debug-state-diff`, `debug-state-inspector`, `debug-summary`, `debug-timeline`) all rewritten to use trace pattern + new tokens. Tailwind utility classes removed throughout.
+
+### Migration & downstream updates
+
+#### Version
+`@ngaf/chat@0.0.3` (patch only, per project policy). Other libs only bump if their source changed.
+
+#### Public API breaking changes (changelog)
+- `` template/visual API changed: no avatar slot; asymmetric message layout; slot names `chatEmptyState` / `chatMessageControls`.
+- `` selector + `ChatMessagesComponent` class renamed to `` / `ChatMessageListComponent`. Old name removed.
+- `` template restyled (visual change only, no API change).
+- `chat-timeline-slider` — horizontal-slider input/output API removed; vertical only.
+- `CHAT_THEME_STYLES` and `CHAT_MARKDOWN_STYLES` removed from public API. Migration: override `--ngaf-chat-*` custom properties or `import '@ngaf/chat/chat.css'`.
+- All Tailwind utility classes removed from chat output. Consumers without Tailwind setup (which were already broken on 0.0.2) now render correctly.
+
+#### Cockpit demos updated (19)
+- `cockpit/chat/{messages,input,threads,tool-calls,subagents,timeline,interrupts,theming,debug,generative-ui,a2ui}/angular`
+- `cockpit/langgraph/{streaming,persistence,memory,interrupts,durable-execution,time-travel,subgraphs,deployment-runtime}/angular`
+
+For each: replace Tailwind classes in local templates, swap `` → ``, drop dependence on `CHAT_THEME_STYLES` / `CHAT_MARKDOWN_STYLES`, regenerate any demo screenshots referenced by the website.
+
+#### libs/example-layouts
+- `example-chat-layout.component` and `example-split-layout.component` rewritten: Tailwind classes (`flex flex-col md:flex-row`, `border-gray-800`, `w-72`) replaced with hand-written CSS in `styles`, using `--ngaf-chat-*` tokens for colors/borders.
+
+#### Smoke app + PR #157 docs revert
+- The Tailwind-required documentation added in PR #157 is **superseded** by this redesign. As part of this work:
+ - Revert `apps/website/content/docs/chat/getting-started/installation.mdx` Tailwind section.
+ - Revert quickstart.mdx Tailwind step.
+ - New installation.mdx flow: `npm install @ngaf/chat`. Done.
+ - Optional consumer step: `import '@ngaf/chat/chat.css'` in global styles.
+
+#### Website docs
+- `getting-started/installation.mdx` — remove Tailwind section; add Theming section (CSS custom properties + optional global stylesheet).
+- `getting-started/quickstart.mdx` — remove Tailwind step.
+- `guides/theming.mdx` — rewrite to document `--ngaf-chat-*` tokens, light/dark modes, attribute override, optional layer-3 stylesheet.
+- Component reference pages — regenerated to match new APIs.
+- New pages: `components/chat-popup.mdx`, `components/chat-sidebar.mdx`, `components/chat-trace.mdx`, `guides/layout-modes.mdx`.
+
+#### Tests
+- All `*.component.spec.ts` for restructured/renamed components updated. Visual specs (computed style assertions) refreshed against new tokens.
+- New specs: ``, ``, ``, ``, asymmetric message templates.
+- Conformance tests against the public chat API kept passing.
+- `cockpit/chat/footprint.spec.ts` and `cockpit/chat/matrix.spec.ts` updated.
+
+## Risks & mitigations
+
+| Risk | Mitigation |
+|---|---|
+| Breaking-change blast radius across 19 demos + docs + tests is large; high merge-conflict risk if work is split. | Land as a single coordinated PR. Sequence within the PR: tokens → primitives → compositions → demos → docs. |
+| Removing Tailwind from chat library means cockpit demos that *also* use Tailwind elsewhere keep working, but `libs/example-layouts` cannot rely on Tailwind anymore. | `example-layouts` is the only remaining Tailwind-heavy first-party consumer; rewriting both layouts in the same PR contains the change. |
+| CSS custom property `--ngaf-chat-*` rename breaks any consumer overriding `--chat-*` from 0.0.2. | Document in changelog. Consumers running on 0.0.2 had a broken render anyway; this is a real but low-cost rename. |
+| Asymmetric message layout removes the assistant avatar consumers may expect. | Documented behavior change. Avatar can be re-added by a consumer via the `chatMessageControls` / `chatEmptyState` slots if needed. |
+| The new `chat-trace` indented-content pattern may not handle very long tool outputs gracefully. | Content has `max-height: 250px` and internal scroll, matching copilotkit. |
+| `field-sizing: content` for textarea autosize lacks support in older browsers. | JS fallback observing scrollHeight is part of the input rewrite. |
+
+## Out of scope (explicit)
+
+- Voice / push-to-talk (CSS hooks only, no integration).
+- Attachments upload pipeline (UI scaffold only).
+- Smart suggestion auto-generation.
+- Code-block syntax highlighting beyond base styling + copy button.
+- RTL layout support.
+- Header chrome beyond title + close-X.
+- Modifying the minting service (proprietary, excluded).
+
+## Approval gate
+
+Once this spec is approved, hand off to the `superpowers:writing-plans` skill to produce the implementation plan. The plan will sequence the work as: design tokens → primitive rewrites → composition rewrites → cockpit demo updates → docs → tests → release notes.
diff --git a/libs/chat/ng-package.json b/libs/chat/ng-package.json
index 738d653d4..7f50f48d1 100644
--- a/libs/chat/ng-package.json
+++ b/libs/chat/ng-package.json
@@ -3,5 +3,9 @@
"dest": "../../dist/libs/chat",
"lib": {
"entryFile": "src/public-api.ts"
- }
+ },
+ "allowedNonPeerDependencies": [],
+ "assets": [
+ { "input": "src/lib/styles", "glob": "chat.css", "output": "." }
+ ]
}
diff --git a/libs/chat/package.json b/libs/chat/package.json
index c0a267691..4a39e2f34 100644
--- a/libs/chat/package.json
+++ b/libs/chat/package.json
@@ -1,6 +1,17 @@
{
"name": "@ngaf/chat",
- "version": "0.0.2",
+ "version": "0.0.3",
+ "exports": {
+ ".": {
+ "types": "./index.d.ts",
+ "default": "./fesm2022/ngaf-chat.mjs"
+ },
+ "./testing": {
+ "types": "./testing.d.ts",
+ "default": "./fesm2022/ngaf-chat-testing.mjs"
+ },
+ "./chat.css": "./chat.css"
+ },
"peerDependencies": {
"@angular/core": "^20.0.0 || ^21.0.0",
"@angular/common": "^20.0.0 || ^21.0.0",
diff --git a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts
index f21b2bba6..574beecb3 100644
--- a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts
+++ b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts
@@ -12,14 +12,14 @@ import {
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import type { AgentWithHistory } from '../../agent';
-import { ChatMessagesComponent } from '../../primitives/chat-messages/chat-messages.component';
-import { MessageTemplateDirective } from '../../primitives/chat-messages/message-template.directive';
+import { ChatMessageListComponent } from '../../primitives/chat-message-list/chat-message-list.component';
+import { MessageTemplateDirective } from '../../primitives/chat-message-list/message-template.directive';
import { ChatInputComponent } from '../../primitives/chat-input/chat-input.component';
import { ChatTypingIndicatorComponent } from '../../primitives/chat-typing-indicator/chat-typing-indicator.component';
import { ChatErrorComponent } from '../../primitives/chat-error/chat-error.component';
import { messageContent } from '../shared/message-utils';
-import { CHAT_THEME_STYLES } from '../../styles/chat-theme';
-import { CHAT_MARKDOWN_STYLES, renderMarkdown } from '../../styles/chat-markdown';
+import { CHAT_HOST_TOKENS } from '../../styles/chat-tokens';
+import { renderMarkdown } from '../../streaming/markdown-render';
import { DebugTimelineComponent } from './debug-timeline.component';
import { DebugDetailComponent } from './debug-detail.component';
import { DebugControlsComponent } from './debug-controls.component';
@@ -31,7 +31,7 @@ import { toDebugCheckpoint, extractStateValues } from './debug-utils';
selector: 'chat-debug',
standalone: true,
imports: [
- ChatMessagesComponent,
+ ChatMessageListComponent,
MessageTemplateDirective,
ChatInputComponent,
ChatTypingIndicatorComponent,
@@ -42,40 +42,233 @@ import { toDebugCheckpoint, extractStateValues } from './debug-utils';
DebugSummaryComponent,
],
changeDetection: ChangeDetectionStrategy.OnPush,
- styles: [CHAT_THEME_STYLES, CHAT_MARKDOWN_STYLES],
+ styles: [
+ CHAT_HOST_TOKENS,
+ `
+ :host {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: hidden;
+ background: var(--ngaf-chat-bg);
+ }
+
+ /* Layout */
+ .chat-debug__layout { display: flex; height: 100%; }
+
+ /* Chat column */
+ .chat-debug__chat { display: flex; flex-direction: column; flex: 1; min-width: 0; }
+ .chat-debug__messages {
+ flex: 1;
+ overflow-y: auto;
+ padding: var(--ngaf-chat-space-6) var(--ngaf-chat-space-5);
+ }
+ .chat-debug__messages-inner {
+ max-width: var(--ngaf-chat-max-width);
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ gap: var(--ngaf-chat-space-5);
+ }
+
+ /* Message templates */
+ .chat-debug__msg-human { display: flex; justify-content: flex-end; }
+ .chat-debug__msg-human__bubble {
+ max-width: 75%;
+ padding: 10px 16px;
+ font-size: var(--ngaf-chat-font-size);
+ line-height: var(--ngaf-chat-line-height);
+ word-break: break-words;
+ border-radius: var(--ngaf-chat-radius-bubble) var(--ngaf-chat-radius-bubble) 6px var(--ngaf-chat-radius-bubble);
+ background: var(--ngaf-chat-surface-alt);
+ color: var(--ngaf-chat-text);
+ border: 1px solid var(--ngaf-chat-separator);
+ }
+
+ .chat-debug__msg-ai { display: flex; gap: 12px; }
+ .chat-debug__msg-ai__avatar {
+ width: 28px;
+ height: 28px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: var(--ngaf-chat-font-size-xs);
+ font-weight: 600;
+ flex-shrink: 0;
+ margin-top: 2px;
+ border-radius: 8px;
+ background: var(--ngaf-chat-surface-alt);
+ color: var(--ngaf-chat-text-muted);
+ }
+ .chat-debug__msg-ai__content {
+ flex: 1;
+ min-width: 0;
+ word-break: break-words;
+ font-size: var(--ngaf-chat-font-size);
+ line-height: var(--ngaf-chat-line-height);
+ color: var(--ngaf-chat-text);
+ }
+
+ .chat-debug__msg-tool {
+ padding: 10px 14px;
+ font-family: var(--ngaf-chat-font-mono);
+ font-size: 13px;
+ word-break: break-words;
+ white-space: pre-wrap;
+ border-radius: var(--ngaf-chat-radius-card);
+ border: 1px solid var(--ngaf-chat-separator);
+ background: var(--ngaf-chat-surface-alt);
+ color: var(--ngaf-chat-text);
+ }
+
+ .chat-debug__msg-system { display: flex; justify-content: center; }
+ .chat-debug__msg-system__text {
+ font-size: var(--ngaf-chat-font-size-xs);
+ font-style: italic;
+ color: var(--ngaf-chat-text-muted);
+ }
+
+ /* Input bar */
+ .chat-debug__input-bar {
+ border-top: 1px solid var(--ngaf-chat-separator);
+ padding: var(--ngaf-chat-space-4) var(--ngaf-chat-space-5);
+ }
+ .chat-debug__input-inner {
+ max-width: var(--ngaf-chat-max-width);
+ margin: 0 auto;
+ }
+
+ /* Debug panel toggle */
+ .chat-debug__toggle-btn {
+ width: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: none;
+ border-left: 1px solid var(--ngaf-chat-separator);
+ cursor: pointer;
+ transition: background 150ms ease;
+ background: var(--ngaf-chat-surface-alt);
+ color: var(--ngaf-chat-text-muted);
+ }
+ .chat-debug__toggle-btn:hover {
+ background: color-mix(in srgb, var(--ngaf-chat-text) 5%, transparent);
+ }
+
+ /* Debug panel */
+ .chat-debug__panel {
+ width: 320px;
+ border-left: 1px solid var(--ngaf-chat-separator);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ flex-shrink: 0;
+ background: var(--ngaf-chat-bg);
+ }
+ .chat-debug__panel-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 12px;
+ border-bottom: 1px solid var(--ngaf-chat-separator);
+ }
+ .chat-debug__panel-title {
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ margin: 0;
+ color: var(--ngaf-chat-text-muted);
+ }
+ .chat-debug__panel-close {
+ font-size: var(--ngaf-chat-font-size-xs);
+ background: transparent;
+ border: 0;
+ cursor: pointer;
+ color: var(--ngaf-chat-text-muted);
+ transition: color 150ms ease;
+ }
+ .chat-debug__panel-close:hover { color: var(--ngaf-chat-text); }
+
+ .chat-debug__panel-section {
+ padding: 8px 12px;
+ border-bottom: 1px solid var(--ngaf-chat-separator);
+ }
+ .chat-debug__panel-timeline {
+ flex: 1;
+ overflow-y: auto;
+ padding: 8px 12px;
+ }
+ .chat-debug__panel-detail {
+ border-top: 1px solid var(--ngaf-chat-separator);
+ padding: 8px 12px;
+ max-height: 256px;
+ overflow-y: auto;
+ }
+
+ /* Markdown rendering */
+ :host ::ng-deep .chat-md p { margin: 0 0 0.75em; }
+ :host ::ng-deep .chat-md p:last-child { margin-bottom: 0; }
+ :host ::ng-deep .chat-md code {
+ background: var(--ngaf-chat-surface-alt);
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-size: 0.875em;
+ font-family: var(--ngaf-chat-font-mono);
+ }
+ :host ::ng-deep .chat-md pre {
+ background: var(--ngaf-chat-surface-alt);
+ padding: 12px 16px;
+ border-radius: var(--ngaf-chat-radius-card);
+ overflow-x: auto;
+ margin: 0.75em 0;
+ }
+ :host ::ng-deep .chat-md pre code { background: none; padding: 0; }
+ :host ::ng-deep .chat-md ul, :host ::ng-deep .chat-md ol { margin: 0.5em 0; padding-left: 1.5em; }
+ :host ::ng-deep .chat-md li { margin: 0.25em 0; }
+ :host ::ng-deep .chat-md a { color: var(--ngaf-chat-text); text-decoration: underline; }
+ :host ::ng-deep .chat-md strong { font-weight: 600; }
+ :host ::ng-deep .chat-md blockquote {
+ border-left: 3px solid var(--ngaf-chat-separator);
+ padding-left: 12px;
+ margin: 0.75em 0;
+ color: var(--ngaf-chat-text-muted);
+ }
+ :host ::ng-deep .chat-md h1, :host ::ng-deep .chat-md h2, :host ::ng-deep .chat-md h3, :host ::ng-deep .chat-md h4 { margin: 1em 0 0.5em; font-weight: 600; }
+ :host ::ng-deep .chat-md h1 { font-size: 1.25em; }
+ :host ::ng-deep .chat-md h2 { font-size: 1.125em; }
+ :host ::ng-deep .chat-md h3 { font-size: 1em; }
+ :host ::ng-deep .chat-md table { border-collapse: collapse; width: 100%; margin: 0.75em 0; }
+ :host ::ng-deep .chat-md th, :host ::ng-deep .chat-md td { border: 1px solid var(--ngaf-chat-separator); padding: 6px 12px; text-align: left; }
+ :host ::ng-deep .chat-md th { background: var(--ngaf-chat-surface-alt); font-weight: 600; font-size: 0.875em; }
+ `,
+ ],
template: `
-
+
-
+
-
-
+
+
-
-
{{ messageContent(message) }}
+
+
{{ messageContent(message) }}
-
-
A
+
@@ -83,21 +276,16 @@ import { toDebugCheckpoint, extractStateValues } from './debug-utils';
- {{ messageContent(message) }}
+ {{ messageContent(message) }}
-
-
- {{ messageContent(message) }}
-
+
+ {{ messageContent(message) }}
-
+
@@ -106,8 +294,8 @@ import { toDebugCheckpoint, extractStateValues } from './debug-utils';
-