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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
import { Component } from '@angular/core';
import { ChatComponent, views } from '@ngaf/chat';
import { ChatComponent, ChatWelcomeSuggestionComponent, views } from '@ngaf/chat';
import { agent } from '@ngaf/langgraph';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { environment } from '../environments/environment';
Expand All @@ -21,13 +21,28 @@ const dashboardViews = views({
data_grid: DataGridComponent,
});

const WELCOME_SUGGESTIONS = [
{ label: 'Render a dashboard', value: 'Show me a Q3 sales dashboard with three metrics.' },
{ label: 'Render a form', value: 'Create a contact form with name, email, and message.' },
] as const;

@Component({
selector: 'app-generative-ui',
standalone: true,
imports: [ChatComponent, ExampleChatLayoutComponent],
imports: [ChatComponent, ChatWelcomeSuggestionComponent, ExampleChatLayoutComponent],
template: `
<example-chat-layout>
<chat main [agent]="agent" [views]="dashboardViews" class="flex-1 min-w-0" />
<chat main [agent]="agent" [views]="dashboardViews" class="flex-1 min-w-0">
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
[label]="s.label"
[value]="s.value"
(selected)="send($event)"
/>
}
</div>
</chat>
</example-chat-layout>
`,
})
Expand All @@ -37,4 +52,9 @@ export class GenerativeUiComponent {
assistantId: environment.generativeUiAssistantId,
});
protected readonly dashboardViews = dashboardViews;
protected readonly suggestions = WELCOME_SUGGESTIONS;

protected send(text: string): void {
void this.agent.submit({ message: text });
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: MIT
import { Component } from '@angular/core';
import { ChatComponent, ChatInterruptPanelComponent, views, type InterruptAction } from '@ngaf/chat';
import { ChatComponent, ChatInterruptPanelComponent, ChatWelcomeSuggestionComponent, views, type InterruptAction } from '@ngaf/chat';
import { agent } from '@ngaf/langgraph';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { signalStateStore } from '@ngaf/render';
import { environment } from '../environments/environment';
import { ApprovalCardComponent } from './views/approval-card.component';

const WELCOME_SUGGESTIONS = [
{ label: 'Approve a tool call', value: 'Book a flight to Paris for next Tuesday.' },
] as const;

/**
* InterruptsComponent demonstrates human-in-the-loop with `agent()`.
*
Expand All @@ -22,11 +26,21 @@ import { ApprovalCardComponent } from './views/approval-card.component';
@Component({
selector: 'app-interrupts',
standalone: true,
imports: [ChatComponent, ChatInterruptPanelComponent, ExampleChatLayoutComponent],
imports: [ChatComponent, ChatInterruptPanelComponent, ChatWelcomeSuggestionComponent, ExampleChatLayoutComponent],
template: `
<example-chat-layout>
<div main class="flex flex-col h-full">
<chat [agent]="agent" [views]="ui" [store]="uiStore" class="flex-1 min-w-0" />
<chat [agent]="agent" [views]="ui" [store]="uiStore" class="flex-1 min-w-0">
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
[label]="s.label"
[value]="s.value"
(selected)="send($event)"
/>
}
</div>
</chat>
@if (agent.interrupt()) {
<div class="p-4" style="border-top: 1px solid var(--ngaf-chat-separator);">
<chat-interrupt-panel [agent]="agent" (action)="onInterruptAction($event)" />
Expand All @@ -39,6 +53,11 @@ import { ApprovalCardComponent } from './views/approval-card.component';
export class InterruptsComponent {
readonly ui = views({ 'approval-card': ApprovalCardComponent });
readonly uiStore = signalStateStore({});
protected readonly suggestions = WELCOME_SUGGESTIONS;

protected send(text: string): void {
void this.agent.submit({ message: text });
}

/**
* The streaming resource with interrupt support.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// SPDX-License-Identifier: MIT
import { Component, signal } from '@angular/core';
import { ChatComponent } from '@ngaf/chat';
import { ChatComponent, ChatWelcomeSuggestionComponent } from '@ngaf/chat';
import { agent } from '@ngaf/langgraph';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { environment } from '../environments/environment';

const WELCOME_SUGGESTIONS = [
{ label: 'Save this thread for later', value: 'Help me draft a project brief I can revisit.' },
] as const;

interface Thread {
id: string;
label: string;
Expand All @@ -23,10 +28,20 @@ interface Thread {
@Component({
selector: 'app-persistence',
standalone: true,
imports: [ChatComponent, ExampleChatLayoutComponent],
imports: [ChatComponent, ChatWelcomeSuggestionComponent, ExampleChatLayoutComponent],
template: `
<example-chat-layout sidebarWidth="w-56">
<chat main [agent]="agent" class="block flex-1 min-w-0" />
<chat main [agent]="agent" class="block flex-1 min-w-0">
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
[label]="s.label"
[value]="s.value"
(selected)="send($event)"
/>
}
</div>
</chat>

<div sidebar
class="flex flex-col"
Expand Down Expand Up @@ -72,9 +87,14 @@ interface Thread {
export class PersistenceComponent {
protected readonly threads = signal<Thread[]>([]);
protected readonly activeThreadId = signal<string | null>(null);
protected readonly suggestions = WELCOME_SUGGESTIONS;

private threadCounter = 0;

protected send(text: string): void {
void this.agent.submit({ message: text });
}

/**
* The streaming resource with thread persistence.
*
Expand Down
26 changes: 23 additions & 3 deletions cockpit/langgraph/streaming/angular/src/app/streaming.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// SPDX-License-Identifier: MIT
import { Component } from '@angular/core';
import { ChatComponent } from '@ngaf/chat';
import { ChatComponent, ChatWelcomeSuggestionComponent } from '@ngaf/chat';
import { agent } from '@ngaf/langgraph';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { environment } from '../environments/environment';

const WELCOME_SUGGESTIONS = [
{ label: 'Stream a long answer', value: 'Explain LangGraph checkpointing in 200 words.' },
{ label: 'Walk me through agent tool calls', value: 'Show me how an agent decides which tool to use.' },
] as const;

/**
* Streaming demo — simplest possible @ngaf/chat integration.
*
Expand All @@ -15,10 +20,20 @@ import { environment } from '../environments/environment';
@Component({
selector: 'app-streaming',
standalone: true,
imports: [ChatComponent, ExampleChatLayoutComponent],
imports: [ChatComponent, ChatWelcomeSuggestionComponent, ExampleChatLayoutComponent],
template: `
<example-chat-layout>
<chat main [agent]="agent" class="flex-1 min-w-0" />
<chat main [agent]="agent" class="flex-1 min-w-0">
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
[label]="s.label"
[value]="s.value"
(selected)="send($event)"
/>
}
</div>
</chat>
</example-chat-layout>
`,
})
Expand All @@ -27,4 +42,9 @@ export class StreamingComponent {
apiUrl: environment.langGraphApiUrl,
assistantId: environment.streamingAssistantId,
});
protected readonly suggestions = WELCOME_SUGGESTIONS;

protected send(text: string): void {
void this.agent.submit({ message: text });
}
}
Loading
Loading