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
61 changes: 61 additions & 0 deletions apps/website/content/docs/chat/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,12 @@
"description": "",
"optional": false
},
{
"name": "forkRequested",
"type": "OutputEmitterRef<string>",
"description": "Bubbled from chat-message gutter markers when the user requests a checkpoint fork.",
"optional": false
},
{
"name": "handlers",
"type": "InputSignal<Record<string, object>>",
Expand Down Expand Up @@ -1611,6 +1617,12 @@
"description": "",
"optional": false
},
{
"name": "replayRequested",
"type": "OutputEmitterRef<string>",
"description": "Bubbled from chat-message gutter markers when the user requests a checkpoint replay.",
"optional": false
},
{
"name": "resolvedStore",
"type": "Signal<StateStore | undefined>",
Expand Down Expand Up @@ -1661,6 +1673,19 @@
}
],
"methods": [
{
"name": "checkpointFor",
"signature": "checkpointFor(msg: Message)",
"description": "Returns the checkpoint id associated with an AI message, if the\n underlying agent exposes messageCheckpoints().",
"params": [
{
"name": "msg",
"type": "Message",
"description": "",
"optional": false
}
]
},
{
"name": "classifyMessage",
"signature": "classifyMessage(content: string, message: object)",
Expand Down Expand Up @@ -1853,6 +1878,12 @@
"description": "",
"optional": false
},
{
"name": "forkRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "messageContent",
"type": "object",
Expand All @@ -1865,6 +1896,12 @@
"description": "",
"optional": false
},
{
"name": "replayRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "selectedCheckpointIndex",
"type": "WritableSignal<number>",
Expand Down Expand Up @@ -2406,12 +2443,24 @@
"description": "Close the popup on Escape (default true).",
"optional": false
},
{
"name": "forkRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "open",
"type": "ModelSignal<boolean>",
"description": "",
"optional": false
},
{
"name": "replayRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "shortcut",
"type": "InputSignal<string | null>",
Expand Down Expand Up @@ -2628,6 +2677,12 @@
"description": "",
"optional": false
},
{
"name": "forkRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "open",
"type": "ModelSignal<boolean>",
Expand All @@ -2640,6 +2695,12 @@
"description": "",
"optional": false
},
{
"name": "replayRequested",
"type": "OutputEmitterRef<string>",
"description": "",
"optional": false
},
{
"name": "views",
"type": "InputSignal<Readonly<Record<string, Type<unknown>>> | undefined>",
Expand Down
9 changes: 8 additions & 1 deletion examples/chat/angular/src/app/modes/embed-mode.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { ChatComponent, ChatWelcomeSuggestionComponent, a2uiBasicCatalog } from '@ngaf/chat';
import { DemoShell } from '../shell/demo-shell.component';
import { DEMO_AGENT } from '../shell/shell-tokens';
import { WELCOME_SUGGESTIONS } from './welcome-suggestions';

Expand All @@ -10,7 +11,12 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
imports: [ChatComponent, ChatWelcomeSuggestionComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<chat [agent]="agent" [views]="catalog">
<chat
[agent]="agent"
[views]="catalog"
(replayRequested)="shell.onTimelineReplay($event)"
(forkRequested)="shell.onTimelineFork($event)"
>
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
Expand All @@ -28,6 +34,7 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
})
export class EmbedMode {
protected readonly agent = inject(DEMO_AGENT);
protected readonly shell = inject(DemoShell);
protected readonly suggestions = WELCOME_SUGGESTIONS;
// Phase 4: catalog of A2UI components the chat composition uses to
// render <a2ui-surface> when an AI message content begins with the
Expand Down
9 changes: 8 additions & 1 deletion examples/chat/angular/src/app/modes/popup-mode.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { ChatPopupComponent, ChatWelcomeSuggestionComponent, a2uiBasicCatalog } from '@ngaf/chat';
import { DemoShell } from '../shell/demo-shell.component';
import { DEMO_AGENT } from '../shell/shell-tokens';
import { WELCOME_SUGGESTIONS } from './welcome-suggestions';

Expand All @@ -15,7 +16,12 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
Click the launcher button (bottom-right) to open the chat.
</p>
</div>
<chat-popup [agent]="agent" [views]="catalog">
<chat-popup
[agent]="agent"
[views]="catalog"
(replayRequested)="shell.onTimelineReplay($event)"
(forkRequested)="shell.onTimelineFork($event)"
>
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
Expand All @@ -40,6 +46,7 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
})
export class PopupMode {
protected readonly agent = inject(DEMO_AGENT);
protected readonly shell = inject(DemoShell);
protected readonly suggestions = WELCOME_SUGGESTIONS;
// Phase 4: A2UI component catalog forwarded to <chat-popup>.
protected readonly catalog = a2uiBasicCatalog();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { ChatSidebarComponent, ChatWelcomeSuggestionComponent, a2uiBasicCatalog } from '@ngaf/chat';
import { DemoShell } from '../shell/demo-shell.component';
import { DEMO_AGENT } from '../shell/shell-tokens';
import { WELCOME_SUGGESTIONS } from './welcome-suggestions';

Expand All @@ -15,7 +16,12 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
Click the launcher button (right edge) to slide in the chat panel.
</p>
</div>
<chat-sidebar [agent]="agent" [views]="catalog">
<chat-sidebar
[agent]="agent"
[views]="catalog"
(replayRequested)="shell.onTimelineReplay($event)"
(forkRequested)="shell.onTimelineFork($event)"
>
<div chatWelcomeSuggestions>
@for (s of suggestions; track s.value) {
<chat-welcome-suggestion
Expand All @@ -40,6 +46,7 @@ import { WELCOME_SUGGESTIONS } from './welcome-suggestions';
})
export class SidebarMode {
protected readonly agent = inject(DEMO_AGENT);
protected readonly shell = inject(DemoShell);
protected readonly suggestions = WELCOME_SUGGESTIONS;
// Phase 4: A2UI component catalog forwarded to <chat-sidebar>.
protected readonly catalog = a2uiBasicCatalog();
Expand Down
22 changes: 0 additions & 22 deletions examples/chat/angular/src/app/shell/control-palette.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,6 @@
<span>Debug {{ debugOpen() ? 'on' : 'off' }}</span>
</button>

<button
type="button"
class="palette__toggle"
[class.is-on]="timelineOpen()"
[attr.aria-pressed]="timelineOpen()"
(click)="toggleTimeline()"
>
<span class="palette__toggle-dot"></span>
<span>Timeline {{ timelineOpen() ? 'on' : 'off' }}</span>
</button>

<button
type="button"
class="palette__toggle"
[class.is-on]="threadsOpen()"
[attr.aria-pressed]="threadsOpen()"
(click)="toggleThreads()"
>
<span class="palette__toggle-dot"></span>
<span>Threads {{ threadsOpen() ? 'on' : 'off' }}</span>
</button>

<button
type="button"
class="palette__action"
Expand Down
12 changes: 0 additions & 12 deletions examples/chat/angular/src/app/shell/control-palette.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,13 @@ export class ControlPalette {
readonly theme = input.required<string>();
readonly themeOptions = input.required<readonly { value: string; label: string }[]>();
readonly debugOpen = input.required<boolean>();
readonly timelineOpen = input.required<boolean>();
readonly threadsOpen = input.required<boolean>();

readonly modeChange = output<DemoMode>();
readonly modelChange = output<string>();
readonly effortChange = output<string>();
readonly genUiModeChange = output<string>();
readonly themeChange = output<string>();
readonly debugOpenChange = output<boolean>();
readonly timelineOpenChange = output<boolean>();
readonly threadsOpenChange = output<boolean>();
readonly newConversation = output<void>();

protected readonly collapsed = signal<boolean>(this.persistence.read('collapsed') ?? false);
Expand Down Expand Up @@ -84,14 +80,6 @@ export class ControlPalette {
this.debugOpenChange.emit(!this.debugOpen());
}

protected toggleTimeline(): void {
this.timelineOpenChange.emit(!this.timelineOpen());
}

protected toggleThreads(): void {
this.threadsOpenChange.emit(!this.threadsOpen());
}

protected emitNewConversation(): void {
this.newConversation.emit();
}
Expand Down
91 changes: 36 additions & 55 deletions examples/chat/angular/src/app/shell/demo-shell.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,42 @@
height: 100%;
}

.demo-shell__hamburger {
position: fixed;
top: 12px;
left: 12px;
z-index: 1100;
width: 36px;
height: 36px;
border: 1px solid #303540;
background: #1a1d23;
color: #e6e9ef;
border-radius: 6px;
font-size: 18px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.3);
}
.demo-shell__hamburger:hover { background: #232730; }

@media (max-width: 767px) {
.demo-shell__hamburger { width: 44px; height: 44px; }
}

.demo-shell__main {
height: 100%;
transition: padding-left 200ms ease;
padding-left: 0;
}
.demo-shell__main--push {
padding-left: 280px;
}
@media (max-width: 1023px) {
.demo-shell__main--push { padding-left: 0; }
}

.demo-shell__debug {
position: fixed;
left: 0;
Expand Down Expand Up @@ -46,58 +82,3 @@
flex-direction: column;
gap: 8px;
}

.demo-shell__timeline-panel {
position: fixed;
right: 16px;
top: 80px;
bottom: 96px;
width: 280px;
background: #1a1d23;
border: 1px solid #303540;
border-radius: 10px;
overflow-y: auto;
z-index: 996;
padding: 8px 0;
}

.demo-shell__threads-panel {
position: fixed;
left: 0;
top: 80px;
bottom: 96px;
width: 240px;
padding: 12px 8px;
background: #1a1d23;
border-right: 1px solid #303540;
overflow-y: auto;
z-index: 996;
display: flex;
flex-direction: column;
gap: 8px;
}

/* Narrow the side panels at tablet widths so the chat column keeps a usable
minimum (~480px) when both panels are open. */
@media (max-width: 1024px) {
.demo-shell__threads-panel { width: 200px; }
.demo-shell__timeline-panel { width: 240px; }
}

/* Below tablet the fixed side panels would steal too much of the chat
surface. Promote them to a centered overlay sheet — still toggle-driven,
but full-width modulo gutter, and they stack above the chat instead of
crowding it. */
@media (max-width: 768px) {
.demo-shell__threads-panel,
.demo-shell__timeline-panel {
left: 16px;
right: 16px;
width: auto;
top: 72px;
bottom: 112px;
border: 1px solid #303540;
border-radius: 10px;
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}
}
Loading
Loading