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
42 changes: 39 additions & 3 deletions cockpit/chat/interrupts/angular/src/app/interrupts.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
// SPDX-License-Identifier: MIT
import { Component, computed } from '@angular/core';
import { JsonPipe } from '@angular/common';
import { ChatComponent, ChatInterruptPanelComponent } from '@ngaf/chat';
import {
ChatComponent,
ChatInterruptPanelComponent,
ChatWelcomeSuggestionComponent,
} from '@ngaf/chat';
import type { InterruptAction } from '@ngaf/chat';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { agent } from '@ngaf/langgraph';
import { environment } from '../environments/environment';

const SUGGESTIONS = [
// values match cockpit/chat/interrupts/angular/e2e/c-interrupts.spec.ts.
// Confirm flow: book + Accept → "Booked …"
{ label: 'Book UA123 (confirm)', value: 'Book me on UA123.' },
// Cancel flow: book + Ignore → "Booking cancelled."
{ label: 'Book AA404 (cancel)', value: 'Book me on AA404.' },
] as const;

/**
* InterruptsComponent demonstrates human-in-the-loop approval gates
* using ChatComponent and ChatInterruptPanelComponent.
Expand All @@ -16,14 +28,33 @@ import { environment } from '../environments/environment';
* Accept → resume('confirm') — the book_flight tool returns Booked …
* Ignore → resume('cancel') — the book_flight tool returns Booking cancelled.
* Edit / Respond are not wired for this demo's single-decision booking flow.
*
* Welcome chips let users one-click into either recorded aimock flow.
* Chip labels hint at the modal action that produces the recorded path.
*/
@Component({
selector: 'app-interrupts',
standalone: true,
imports: [ChatComponent, ChatInterruptPanelComponent, JsonPipe, ExampleChatLayoutComponent],
imports: [
ChatComponent,
ChatInterruptPanelComponent,
ChatWelcomeSuggestionComponent,
JsonPipe,
ExampleChatLayoutComponent,
],
template: `
<example-chat-layout sidebarWidth="w-80">
<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>
<div sidebar class="p-4 space-y-4" style="background: var(--ngaf-chat-bg); color: var(--ngaf-chat-text);">
<h3 class="text-xs font-semibold uppercase tracking-wide"
style="color: var(--ngaf-chat-text-muted);">Interrupt Panel</h3>
Expand All @@ -44,6 +75,7 @@ export class InterruptsComponent {
});

protected readonly streamStatus = computed(() => this.agent.status());
protected readonly suggestions = SUGGESTIONS;

protected onInterruptAction(action: InterruptAction): void {
if (action === 'accept') {
Expand All @@ -53,4 +85,8 @@ export class InterruptsComponent {
}
// 'edit' and 'respond' are intentionally unhandled for the booking flow.
}

protected send(text: string): void {
void this.agent.submit({ message: text });
}
}
34 changes: 32 additions & 2 deletions cockpit/chat/subagents/angular/src/app/subagents.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,47 @@ import {
ChatComponent,
ChatSubagentsComponent,
ChatSubagentCardComponent,
ChatWelcomeSuggestionComponent,
} from '@ngaf/chat';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { agent } from '@ngaf/langgraph';
import { environment } from '../environments/environment';

const SUGGESTIONS = [
// value matches cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts PROMPT.
{ label: 'Plan a trip', value: 'Plan a trip from LAX to JFK' },
] as const;

/**
* SubagentsComponent demonstrates subagent orchestration with
* ChatComponent and a sidebar showing ChatSubagentsComponent /
* ChatSubagentCardComponent for tracking active subagents.
*
* Welcome chip lets users one-click into the cap's recorded aimock flow.
*/
@Component({
selector: 'app-subagents',
standalone: true,
imports: [ChatComponent, ChatSubagentsComponent, ChatSubagentCardComponent, ExampleChatLayoutComponent],
imports: [
ChatComponent,
ChatSubagentsComponent,
ChatSubagentCardComponent,
ChatWelcomeSuggestionComponent,
ExampleChatLayoutComponent,
],
template: `
<example-chat-layout sidebarWidth="w-80">
<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>
<div sidebar class="p-4 space-y-4" style="background: var(--ngaf-chat-bg); color: var(--ngaf-chat-text);">
<h3 class="text-xs font-semibold uppercase tracking-wide"
style="color: var(--ngaf-chat-text-muted);">Active Subagents</h3>
Expand All @@ -44,4 +68,10 @@ export class SubagentsComponent {
apiUrl: environment.langGraphApiUrl,
assistantId: environment.streamingAssistantId,
});

protected readonly suggestions = SUGGESTIONS;

protected send(text: string): void {
void this.agent.submit({ message: text });
}
}
34 changes: 32 additions & 2 deletions cockpit/chat/tool-calls/angular/src/app/tool-calls.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,46 @@ import {
ChatComponent,
ChatToolCallsComponent,
ChatToolCallCardComponent,
ChatWelcomeSuggestionComponent,
} from '@ngaf/chat';
import { ExampleChatLayoutComponent } from '@ngaf/example-layouts';
import { agent } from '@ngaf/langgraph';
import { environment } from '../environments/environment';

const SUGGESTIONS = [
// value matches cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts PROMPT.
{ label: 'Look up flight UA123', value: "What's the status of UA123?" },
] as const;

/**
* ToolCallsComponent demonstrates tool calling with ChatComponent
* and a sidebar showing ChatToolCallsComponent / ChatToolCallCardComponent.
*
* Welcome chip lets users one-click into the cap's recorded aimock flow.
*/
@Component({
selector: 'app-tool-calls',
standalone: true,
imports: [ChatComponent, ChatToolCallsComponent, ChatToolCallCardComponent, ExampleChatLayoutComponent],
imports: [
ChatComponent,
ChatToolCallsComponent,
ChatToolCallCardComponent,
ChatWelcomeSuggestionComponent,
ExampleChatLayoutComponent,
],
template: `
<example-chat-layout sidebarWidth="w-80">
<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>
<div sidebar class="p-4 space-y-4" style="background: var(--ngaf-chat-bg); color: var(--ngaf-chat-text);">
<h3 class="text-xs font-semibold uppercase tracking-wide"
style="color: var(--ngaf-chat-text-muted);">Tool Calls</h3>
Expand All @@ -42,4 +66,10 @@ export class ToolCallsComponent {
apiUrl: environment.langGraphApiUrl,
assistantId: environment.streamingAssistantId,
});

protected readonly suggestions = SUGGESTIONS;

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