1import type { AfterViewInit } from "@angular/core";
2import {
3 ChangeDetectionStrategy,
4 Component,
5 DestroyRef,
6 Injector,
7 ViewContainerRef,
8 inject,
9 input,
10 inputBinding,
11} from "@angular/core";
12import {
13 CopilotChat,
14 provideCopilotChatConfiguration,
15} from "@copilotkit/angular";
16
17import { agentIdForCurrentIntegration } from "../feature-agent";
18import { FeatureHeaderComponent } from "./feature-header.component";
19import {
20 createDynamicComponent,
21 renderDynamicComponent,
22} from "./render-dynamic-component";
23
24interface SlotMessage {
25 id: string;
26 role: "assistant";
27 content?: string;
28}
29
30@Component({
31 selector: "showcase-custom-assistant-message",
32 changeDetection: ChangeDetectionStrategy.OnPush,
33 host: {
34 class: "custom-assistant-message",
35 "data-testid": "custom-assistant-message",
36 "data-slot-label": "MessageView.AssistantMessage",
37 "data-message-role": "assistant",
38 },
39 template: `
40 <p class="feature-eyebrow">Custom Angular assistant slot</p>
41 <div>{{ message().content }}</div>
42 `,
43})
44export class CustomAssistantMessageComponent {
45 readonly message = input.required<SlotMessage>();
46}
47
48@Component({
49 selector: "showcase-chat-slots-feature",
50 imports: [FeatureHeaderComponent],
51 changeDetection: ChangeDetectionStrategy.OnPush,
52 host: { class: "feature-page" },
53 template: `
54 <showcase-feature-header />
55 <main class="chat-surface" aria-label="Customized CopilotKit chat">
56 <ng-container #chatHost />
57 </main>
58 `,
59})
60export class ChatSlotsFeatureComponent implements AfterViewInit {
61 private readonly chatHost = inject(ViewContainerRef);
62 private readonly injector = inject(Injector);
63 private readonly destroyRef = inject(DestroyRef);
64
65 ngAfterViewInit(): void {
66 const agentId = agentIdForCurrentIntegration("chat-slots");
67 const childInjector = Injector.create({
68 parent: this.injector,
69 providers: [...provideCopilotChatConfiguration({ agentId })],
70 });
71 this.destroyRef.onDestroy(() => childInjector.destroy());
72 const chat = createDynamicComponent(this.chatHost, CopilotChat, {
73 injector: childInjector,
74 bindings: [
75 inputBinding("agentId", () => agentId),
76 inputBinding(
77 "assistantMessageComponent",
78 () => CustomAssistantMessageComponent,
79 ),
80 ],
81 });
82 renderDynamicComponent(chat);
83 }
84}
85