1import {
2  ChangeDetectionStrategy,
3  Component,
4  computed,
5  inject,
6  Injector,
7  signal,
8} from "@angular/core";
9import { ActivatedRoute } from "@angular/router";
10import { connectAgentContext, CopilotKit } from "@copilotkit/angular";
11
12import { agentIdForRoute } from "../../feature-agent";
13import { FeatureHeaderComponent } from "../feature-header.component";
14import { ShowcaseChatHostComponent } from "../showcase-chat-host.component";
15import {
16  AgentConfigCardComponent,
17  AuthCardComponent,
18  DEFAULT_AGENT_CONFIG,
19} from "./app-settings-cards";
20import type {
21  AgentConfig,
22  Expertise,
23  ResponseLength,
24  Tone,
25} from "./app-settings-cards";
26
27const DEMO_AUTH_HEADERS: Readonly<Record<string, string>> = {
28  Authorization: "Bearer demo-token-123",
29};
30
31@Component({
32  selector: "showcase-app-settings-feature",
33  imports: [
34    AgentConfigCardComponent,
35    AuthCardComponent,
36    FeatureHeaderComponent,
37    ShowcaseChatHostComponent,
38  ],
39  changeDetection: ChangeDetectionStrategy.OnPush,
40  host: { class: "feature-page" },
41  template: `
42    <showcase-feature-header />
43    @if (feature === "auth" && !signedIn()) {
44      <main class="sign-in-page">
45        <showcase-auth-card [authenticated]="false" (signIn)="signIn()" />
46      </main>
47    } @else {
48      <main class="settings-page">
49        <section class="settings-panel">
50          @if (feature === "auth") {
51            <showcase-auth-card [authenticated]="true" (signOut)="signOut()" />
52          } @else {
53            <showcase-agent-config-card
54              [config]="config()"
55              (toneChange)="setTone($event)"
56              (expertiseChange)="setExpertise($event)"
57              (responseLengthChange)="setResponseLength($event)"
58            />
59          }
60        </section>
61        <section class="chat-surface" aria-label="CopilotKit assistant">
62          <showcase-chat-host
63            [agentId]="agentId"
64            [headers]="feature === 'auth' ? authHeaders : undefined"
65          />
66        </section>
67      </main>
68    }
69  `,
70  styles: `
71    .sign-in-page {
72      display: grid;
73      min-height: 0;
74      place-items: center;
75      padding: 1.5rem;
76      background: radial-gradient(circle at 50% 20%, #eef2ff, #eef3f7 55%);
77    }
78    .settings-page {
79      display: grid;
80      min-height: 0;
81      grid-template-rows: auto minmax(0, 1fr);
82      gap: 1rem;
83      padding: 1rem;
84      background: #eef3f7;
85    }
86    .settings-panel {
87      min-width: 0;
88    }
89    .chat-surface {
90      min-height: 0;
91      overflow: hidden;
92      border: 1px solid #d8e0ea;
93      border-radius: 1rem;
94      background: #fff;
95    }
96  `,
97})
98export class AppSettingsFeatureComponent {
99  private readonly route = inject(ActivatedRoute);
100  private readonly injector = inject(Injector);
101  protected readonly feature =
102    (this.route.snapshot.data["feature"] as string | undefined) ??
103    "agent-config";
104  protected readonly signedIn = signal(false);
105  protected readonly config = signal<AgentConfig>({ ...DEFAULT_AGENT_CONFIG });
106  protected readonly authHeaders = DEMO_AUTH_HEADERS;
107  protected readonly agentId = agentIdForRoute(this.feature, this.route);
108  private readonly configContext = computed(() => ({
109    description:
110      "Agent response preferences. Apply tone, expertise level, and response length to every reply.",
111    value: JSON.stringify(this.config()),
112  }));
113
114  constructor() {
115    if (this.feature === "agent-config") {
116      connectAgentContext(this.configContext);
117    }
118  }
119
120  protected signIn(): void {
121    this.signedIn.set(true);
122  }
123
124  protected signOut(): void {
125    this.injector.get(CopilotKit).updateRuntime({ headers: {} });
126    this.signedIn.set(false);
127  }
128
129  protected setTone(tone: Tone): void {
130    this.updateConfig({ tone });
131  }
132
133  protected setExpertise(expertise: Expertise): void {
134    this.updateConfig({ expertise });
135  }
136
137  protected setResponseLength(responseLength: ResponseLength): void {
138    this.updateConfig({ responseLength });
139  }
140
141  private updateConfig(patch: Partial<AgentConfig>): void {
142    this.config.update((current) => ({ ...current, ...patch }));
143  }
144}
145
4a65196ee
CopilotKit Showcase