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
4 changes: 2 additions & 2 deletions apps/website/content/docs/chat/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@
{
"name": "spec",
"type": "Signal<Spec | null>",
"description": "Convert the A2UI surface to a json-render Spec for rendering.\n Prefers `state().surface` (the progressively-built wire surface)\n over the legacy `surface` input. surfaceToSpec handles\n children-id-list → spec.children translation + reserved-key\n filtering + path-ref → $bindState rewriting; the rendered tree\n then uses render-element's standard input-mapping\n (`childKeys: el.children`) so catalog components receive the\n inputs they actually declare.\n\n This supersedes the earlier slot-based progressive renderer,\n which mounted root components but never populated their\n childKeys inputleaving Columns/Rows/etc. with no children.",
"description": "Convert the A2UI surface to a json-render Spec for rendering.\n Prefers `state().surface` (the progressively-built wire surface)\n over the legacy `surface` input. surfaceToSpec handles\n children-id-list → spec.children translation + reserved-key\n filtering + path-ref → $bindState rewriting; the rendered tree\n then uses render-element's standard input-mapping\n (`childKeys: el.children`) so catalog components receive the\n inputs they actually declare.\n\n An earlier slot-based progressive renderer mounted root components\n but never populated their childKeys input, leaving Columns/Rows/etc.\n with no children; the spec conversion replaced it.",
"optional": false
},
{
Expand Down Expand Up @@ -9211,7 +9211,7 @@
"description": ""
},
"examples": [
"```ts\nconst interrupt = getInterrupt(agent);\nif (interrupt) agent.resume('approved');\n```"
"```ts\nconst interrupt = getInterrupt(agent);\nif (interrupt) agent.submit({ resume: 'approved' });\n```"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions apps/website/content/docs/chat/concepts/message-model.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ The assistant template is the only one that reads `delivery`. `streaming` on `<c

### The input strip

The typing indicator and the input both take the agent and need nothing else. `<chat-input>` calls `agent.submit()` itself and then emits `submitted` with the same trimmed text, which is what turns a keystroke into a `user` message in the list above.
The typing indicator and the input both take the agent and need nothing else. `<chat-input>` calls `agent.submit()` itself, which is what turns a keystroke into a `user` message in the list above, and then emits `submitted` with the same trimmed text.

<ExampleCode file="messages.component.ts" region="input-strip" title="messages.component.ts — the input strip" />

<Callout type="warning" title="Do not submit from (submitted)">
The output fires after the message has already been sent. A handler that calls `submit()` again posts the user message twice. The demo itself does this: its `(submitted)` handler submits a second time after `<chat-input>` has already submitted, which is a defect in the example. Your own application should bind `(submitted)` only for side effects such as analytics, not for submission.
The output fires after the message has already been sent. A handler that calls `submit()` again posts the user message twice. The demo binds nothing to it; bind `(submitted)` only for side effects such as analytics, never for submission.
</Callout>

### The component class
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/chat/guides/thread-routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Never generate a thread id in the browser. Use the value handed to `onThreadId`,

### The sidebar and the thread list

The `<chat>` composition owns the transcript, the input, and the loading and error states. It also renders its own `<chat-thread-list>` in a sidebar, shown at widths of 768px and up whenever the `[threads]` input it receives is non-empty. The same `[threads]` and `[activeThreadId]` inputs that feed the template's explicit list also feed that built-in one, which is why `<chat>` re-emits `threadSelected` — it is passing along the selection its own internal list produced. Because the demo passes `[threads]` to both `<chat>` and the explicit `<chat-thread-list>` in the template, a desktop viewport shows two thread lists side by side; that is a defect in the example, not a pattern to copy.
The `<chat>` composition owns the transcript, the input, and the loading and error states, so the template adds the list beside it. `<chat>` can also render a `<chat-thread-list>` of its own, in a sidebar shown at widths of 768px and up whenever its `[threads]` input is non-empty, and it re-emits that list's `threadSelected`. The demo leaves those inputs unbound and mounts one explicit list instead, so that the list can carry the row actions shown below.

<ExampleCode file="threads.component.ts" region="chat-and-sidebar" title="threads.component.ts — the template" />

Expand Down
6 changes: 1 addition & 5 deletions cockpit/chat/messages/angular/src/app/messages.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ import { MESSAGES_AGENT, type MessagesState } from './agent-ref';
<div class="input-strip">
<!-- #region input-strip -->
<chat-typing-indicator [agent]="agent" />
<chat-input [agent]="agent" (submitted)="submitMessage($event)" />
<chat-input [agent]="agent" />
<!-- #endregion -->
</div>
</section>
Expand Down Expand Up @@ -165,8 +165,4 @@ export class MessagesComponent {
protected readonly messageContent = messageContent;
protected readonly markdownDocument = markdownDocument;
// #endregion

submitMessage(content: string) {
this.agent.submit({ message: content });
}
}
7 changes: 1 addition & 6 deletions cockpit/chat/threads/angular/src/app/threads.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ export const activeThreadIdState = signal<string | null>(null);
template: `
<!-- #region chat-and-sidebar -->
<example-chat-layout sidebarPosition="left" sidebarWidth="16rem">
<chat main
[agent]="agent"
[threads]="threadsSvc.threads()"
[activeThreadId]="activeThreadId() ?? ''"
(threadSelected)="onThreadSelected($event)"
class="flex-1 min-w-0" />
<chat main [agent]="agent" class="flex-1 min-w-0" />
<div sidebar class="panel">
<div class="panel-header">
<h3 class="cap">Threads</h3>
Expand Down
5 changes: 0 additions & 5 deletions libs/chat/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
"glob": "development-install.*",
"output": ".install-collector"
},
{
"input": "src/lib/styles",
"glob": "chat.css",
"output": "."
},
{
"input": "src/themes",
"glob": "*.css",
Expand Down
87 changes: 0 additions & 87 deletions libs/chat/src/lib/a2ui/a2ui-slot.directive.spec.ts

This file was deleted.

75 changes: 0 additions & 75 deletions libs/chat/src/lib/a2ui/a2ui-slot.directive.ts

This file was deleted.

11 changes: 6 additions & 5 deletions libs/chat/src/lib/a2ui/surface.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ import type { A2uiViews } from './views';
})
/**
* Renders an A2UI surface. Supports two input shapes:
* - `state` (preferred): chat-side `A2uiSurfaceState` driving progressive
* per-component rendering via `a2uiSlot` + readiness gates.
* - `state` (preferred): chat-side `A2uiSurfaceState`, converted to a
* json-render spec whose `$bindState` props defer each component until
* its data has arrived.
* - `surface` (legacy): wire-format `A2uiSurface` fed into `<render-spec>`;
* kept for backwards compatibility.
*
Expand Down Expand Up @@ -172,9 +173,9 @@ export class A2uiSurfaceComponent {
* (`childKeys: el.children`) so catalog components receive the
* inputs they actually declare.
*
* This supersedes the earlier slot-based progressive renderer,
* which mounted root components but never populated their
* childKeys input — leaving Columns/Rows/etc. with no children. */
* An earlier slot-based progressive renderer mounted root components
* but never populated their childKeys input, leaving Columns/Rows/etc.
* with no children; the spec conversion replaced it. */
readonly spec = computed(() => {
const surf = this.state()?.surface ?? this.surface();
return surf && surf.components.size > 0 ? surfaceToSpec(surf) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { CHAT_INTERRUPT_STYLES } from '../../styles/chat-interrupt.styles';
* @example
* ```ts
* const interrupt = getInterrupt(agent);
* if (interrupt) agent.resume('approved');
* if (interrupt) agent.submit({ resume: 'approved' });
* ```
*/
export function getInterrupt(agent: Agent): AgentInterrupt | undefined {
Expand Down
1 change: 0 additions & 1 deletion libs/cockpit-shell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"private": true,
"dependencies": {
"@threadplane/cockpit-registry": "*",
"marked": "^15.0.0",
"shiki": "^4.0.2"
}
}
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"jsdom": "^29.0.0",
"jsonc-eslint-parser": "^2.1.0",
"katex": "^0.17.0",
"marked": "^15.0.0",
"msw": "^2.4.9",
"ng-packagr": "~21.1.0",
"nx": "22.5.1",
Expand Down
Loading