Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 30 additions & 18 deletions apps/website/content/docs/chat/a2ui/catalog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,15 @@ A tabbed container that shows one child panel at a time based on the selected ta
```json
{
"id": "info-tabs",
"component": "Tabs",
"tabs": [
{"label": "Overview", "childKeys": ["overview-content"]},
{"label": "Details", "childKeys": ["detail-list"]}
],
"selected": {"path": "/activeTab"}
"component": {
"Tabs": {
"tabs": [
{"label": "Overview", "childKeys": ["overview-content"]},
{"label": "Details", "childKeys": ["detail-list"]}
],
"selected": {"path": "/activeTab"}
}
}
}
```

Expand All @@ -365,11 +368,14 @@ A dialog overlay that renders child content when open. Supports an optional titl
```json
{
"id": "confirm-dialog",
"component": "Modal",
"title": "Confirm Action",
"open": {"path": "/showConfirm"},
"childKeys": ["confirm-message", "confirm-buttons"],
"dismissible": true
"component": {
"Modal": {
"title": {"literalString": "Confirm Action"},
"open": {"path": "/showConfirm"},
"childKeys": ["confirm-message", "confirm-buttons"],
"dismissible": true
}
}
}
```

Expand All @@ -393,10 +399,13 @@ Renders an HTML5 `<video>` element.
```json
{
"id": "intro-video",
"component": "Video",
"url": "https://example.com/intro.mp4",
"poster": "https://example.com/poster.jpg",
"controls": true
"component": {
"Video": {
"url": {"literalString": "https://example.com/intro.mp4"},
"poster": {"literalString": "https://example.com/poster.jpg"},
"controls": true
}
}
}
```

Expand All @@ -417,9 +426,12 @@ Renders an HTML5 `<audio>` element.
```json
{
"id": "podcast",
"component": "AudioPlayer",
"url": "https://example.com/episode.mp3",
"controls": true
"component": {
"AudioPlayer": {
"url": {"literalString": "https://example.com/episode.mp3"},
"controls": true
}
}
}
```

Expand Down
26 changes: 21 additions & 5 deletions apps/website/content/docs/chat/components/chat-trace.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,15 @@ When `state` transitions from any value to `'running'`, the trace automatically
### Full component example

```typescript
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { Component, ChangeDetectionStrategy, computed, signal } from '@angular/core';
import { injectAgent, provideAgent } from '@threadplane/langgraph';
import { ChatTraceComponent, ChatMessageListComponent } from '@threadplane/chat';
import type { ToolCallStatus, TraceState } from '@threadplane/chat';

function toTraceState(status: ToolCallStatus): TraceState {
// 'pending' | 'running' | 'error' carry over; only 'complete' is renamed.
return status === 'complete' ? 'done' : status;
}

@Component({
selector: 'app-traced-chat',
Expand All @@ -106,10 +112,10 @@ import { ChatTraceComponent, ChatMessageListComponent } from '@threadplane/chat'
<chat-message-list [agent]="chatAgent">
<ng-template chatMessageTemplate="ai" let-message>
<!-- Show tool traces before the AI message -->
@for (step of chatAgent.steps(); track step.id) {
<chat-trace [state]="step.state">
<span traceLabel>{{ step.name }}</span>
<pre>{{ step.output | json }}</pre>
@for (trace of traces(); track trace.id) {
<chat-trace [state]="trace.state">
<span traceLabel>{{ trace.name }}</span>
<pre>{{ trace.args | json }}</pre>
</chat-trace>
}
<div>{{ message.content }}</div>
Expand All @@ -120,6 +126,16 @@ import { ChatTraceComponent, ChatMessageListComponent } from '@threadplane/chat'
})
export class TracedChatComponent {
protected readonly chatAgent = injectAgent();

// The agent's toolCalls() signal is the real source for trace rows.
protected readonly traces = computed(() =>
this.chatAgent.toolCalls().map((call) => ({
id: call.id,
name: call.name,
args: call.args,
state: toTraceState(call.status),
})),
);
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export const appConfig: ApplicationConfig = {
provideZonelessChangeDetection(),
provideAgent({
apiUrl: environment.langgraphApiUrl, // e.g. 'http://localhost:2024'
assistantId: 'chat', // The graph/agent ID exposed by your backend
}),
provideChat({
license: environment.threadplaneLicense,
Expand Down
20 changes: 9 additions & 11 deletions apps/website/content/docs/chat/getting-started/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ npm install @threadplane/chat marked

```ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { ApplicationConfig, signal } from '@angular/core';
import { provideAgent } from '@threadplane/langgraph';
import { provideChat } from '@threadplane/chat';

export const appConfig: ApplicationConfig = {
providers: [
provideAgent({ apiUrl: 'http://localhost:2024' }),
provideAgent({
assistantId: 'chat',
apiUrl: 'http://localhost:2024',
threadId: signal(null),
}),
provideChat({ assistantName: 'Assistant' }),
],
};
Expand All @@ -45,29 +49,23 @@ export const appConfig: ApplicationConfig = {

```ts
// chat-page.component.ts
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { injectAgent, provideAgent } from '@threadplane/langgraph';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { injectAgent } from '@threadplane/langgraph';
import { ChatComponent } from '@threadplane/chat';

@Component({
selector: 'app-chat-page',
standalone: true,
imports: [ChatComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
provideAgent({
assistantId: 'chat',
threadId: signal(null),
}),
],
template: `<div style="height: 100vh"><chat [agent]="chatAgent" /></div>`,
})
export class ChatPageComponent {
protected readonly chatAgent = injectAgent();
}
```

The second `provideAgent()` isn't a duplicate. Angular's hierarchical DI merges it with the root provider from Step 2: `apiUrl` comes from the root, `assistantId` and `threadId` come from this component-level call. Splitting config this way lets one app host several `<chat>` surfaces that share a backend URL but target different graphs. See the [Multiple agents](/docs/chat/getting-started/installation) note in Installation for the full pattern.
`injectAgent()` returns the singleton wired up in Step 2 — no extra provider needed here. To host several `<chat>` surfaces that share a backend URL but target different graphs, re-provide `provideAgent({...})` in a component's `providers: []` array; Angular's hierarchical DI scopes that override to the subtree. See the [Multiple agents](/docs/chat/getting-started/installation) note in Installation for the full pattern.

</Step>
</Steps>
Expand Down
Loading