@threadplane/chat 0.0.49 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/README.md +0 -1
- package/fesm2022/threadplane-chat.mjs +932 -113
- package/fesm2022/threadplane-chat.mjs.map +1 -1
- package/package.json +3 -2
- package/types/threadplane-chat.d.ts +568 -57
|
@@ -1,18 +1,179 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, TemplateRef, Directive, contentChildren, computed, ChangeDetectionStrategy, Component, signal, Injectable, ContentChild, effect, output, DOCUMENT,
|
|
2
|
+
import { InjectionToken, input, inject, TemplateRef, Directive, contentChildren, computed, ChangeDetectionStrategy, Component, signal, Injectable, ContentChild, effect, output, DOCUMENT, ViewEncapsulation, viewChild, model, contentChild, untracked, ElementRef, DestroyRef, makeEnvironmentProviders, Injector, runInInjectionContext, ViewContainerRef, SecurityContext } from '@angular/core';
|
|
3
3
|
import { NgTemplateOutlet, NgComponentOutlet, KeyValuePipe } from '@angular/common';
|
|
4
4
|
import { createPartialMarkdownParser, materialize } from '@cacheplane/partial-markdown';
|
|
5
|
-
import { views, RenderSpecComponent, toRenderRegistry, signalStateStore, RenderElementComponent } from '@threadplane/render';
|
|
5
|
+
import { views, RenderSpecComponent, toRenderRegistry, signalStateStore, withViews, RenderElementComponent, injectRenderHost } from '@threadplane/render';
|
|
6
6
|
export { toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
|
|
7
|
-
import * as i1 from '@angular/forms';
|
|
8
|
-
import { FormsModule } from '@angular/forms';
|
|
9
7
|
import { runLicenseCheck, inferNoncommercial, LICENSE_PUBLIC_KEY } from '@threadplane/licensing';
|
|
10
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
|
+
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
|
+
import { Router, NavigationEnd } from '@angular/router';
|
|
10
|
+
import { filter, map, startWith } from 'rxjs/operators';
|
|
11
|
+
import { toJSONSchema } from 'zod/v4';
|
|
11
12
|
import { resolveDynamic, getByPointer, isPathRef, setByPointer, createA2uiMessageParser } from '@threadplane/a2ui';
|
|
12
13
|
export { isLiteralBoolean, isLiteralNumber, isLiteralString, isPathRef } from '@threadplane/a2ui';
|
|
13
14
|
import { materialize as materialize$1, createPartialJsonParser } from '@cacheplane/partial-json';
|
|
14
15
|
import { fromEvent, EMPTY } from 'rxjs';
|
|
15
16
|
|
|
17
|
+
// SPDX-License-Identifier: MIT
|
|
18
|
+
/**
|
|
19
|
+
* Structured, classified failure surfaced on `Agent.error`. Extends `Error`, so
|
|
20
|
+
* existing `.message` / `instanceof Error` reads keep working — but adds a
|
|
21
|
+
* machine-readable {@link AgentErrorKind}, a `retryable` flag, an optional HTTP
|
|
22
|
+
* `status`, and the original `cause`.
|
|
23
|
+
*
|
|
24
|
+
* You rarely construct one yourself; adapters normalize raw failures via
|
|
25
|
+
* {@link toAgentError}. Read it off the agent to render legible, cause-specific UI:
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const err = agent.error(); // AgentError | undefined
|
|
30
|
+
* if (err) {
|
|
31
|
+
* console.warn(err.message); // legible, per-kind copy
|
|
32
|
+
* if (err.kind === 'auth') showApiKeyHelp();
|
|
33
|
+
* if (err.retryable) showRetryButton(); // → agent.retry()
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
class AgentError extends Error {
|
|
38
|
+
/** The classified failure type. See {@link AgentErrorKind}. */
|
|
39
|
+
kind;
|
|
40
|
+
/** Whether retrying the same request could plausibly succeed:
|
|
41
|
+
* `connection` | `server` (5xx) | `interrupted` → true; `auth` | `aborted` | non-auth `4xx` → false. */
|
|
42
|
+
retryable;
|
|
43
|
+
/** The HTTP status code when the failure came from an HTTP response. */
|
|
44
|
+
status;
|
|
45
|
+
/** The original raw error this was classified from, preserved for debugging/telemetry. */
|
|
46
|
+
cause;
|
|
47
|
+
constructor(init) {
|
|
48
|
+
super(init.message);
|
|
49
|
+
this.name = 'AgentError';
|
|
50
|
+
this.kind = init.kind;
|
|
51
|
+
this.retryable = init.retryable;
|
|
52
|
+
this.status = init.status;
|
|
53
|
+
this.cause = init.cause;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Default, human-facing copy per {@link AgentErrorKind}. Used as the message when
|
|
58
|
+
* a classified error has no better text. Override by mapping `error.kind` to your
|
|
59
|
+
* own strings in a custom error component.
|
|
60
|
+
*/
|
|
61
|
+
const AGENT_ERROR_MESSAGES = {
|
|
62
|
+
connection: "Can't reach the server. Check your connection and try again.",
|
|
63
|
+
auth: 'Authentication failed. Check your API key or credentials.',
|
|
64
|
+
server: 'The server ran into an error. You can try again.',
|
|
65
|
+
interrupted: 'The response was interrupted. Try again.',
|
|
66
|
+
aborted: 'Stopped.',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// SPDX-License-Identifier: MIT
|
|
70
|
+
/**
|
|
71
|
+
* Whether `raw` represents an abort (a `DOMException`/`Error` named `AbortError`,
|
|
72
|
+
* or an abort-ish message). Shared by the runtime adapters and {@link toAgentError}
|
|
73
|
+
* so a user-requested stop settles to idle instead of surfacing as an error.
|
|
74
|
+
*
|
|
75
|
+
* @param raw Any thrown/rejected value.
|
|
76
|
+
* @returns `true` if it looks like an abort.
|
|
77
|
+
*/
|
|
78
|
+
function isAbortError(raw) {
|
|
79
|
+
return raw instanceof Error && (raw.name === 'AbortError' || /\babort/i.test(raw.message));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Reads a numeric status from `raw.status` or `raw.cause.status` only.
|
|
83
|
+
* No text parsing — structured fields only.
|
|
84
|
+
*/
|
|
85
|
+
function structuredStatus(raw) {
|
|
86
|
+
const obj = raw;
|
|
87
|
+
const direct = typeof obj?.status === 'number' ? obj.status : undefined;
|
|
88
|
+
const viaCause = typeof obj?.cause?.status === 'number' ? obj.cause.status : undefined;
|
|
89
|
+
if (direct !== undefined)
|
|
90
|
+
return direct;
|
|
91
|
+
if (viaCause !== undefined)
|
|
92
|
+
return viaCause;
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
function isConnectionError(raw) {
|
|
96
|
+
if (!(raw instanceof Error))
|
|
97
|
+
return false;
|
|
98
|
+
return /failed to fetch|networkerror|econnrefused|enotfound|network request failed|load failed/i.test(`${raw.name} ${raw.message}`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Extracts an HTTP status code from a message string, but ONLY when the token
|
|
102
|
+
* is unambiguously HTTP-shaped:
|
|
103
|
+
* - `HTTP/502`, `HTTP 404`, `HTTP404`
|
|
104
|
+
* - `status: 503`, `status=503`, `code: 404`
|
|
105
|
+
*
|
|
106
|
+
* Bare 3-digit numbers (e.g. model version strings like "gpt-500") are NOT matched.
|
|
107
|
+
*/
|
|
108
|
+
function httpStatusFromMessage(raw) {
|
|
109
|
+
const msg = raw instanceof Error ? raw.message : typeof raw === 'string' ? raw : '';
|
|
110
|
+
if (!msg)
|
|
111
|
+
return undefined;
|
|
112
|
+
// "HTTP 500", "HTTP/500", "HTTP500"
|
|
113
|
+
const httpToken = /\bHTTP[ /]?(\d{3})\b/i.exec(msg);
|
|
114
|
+
if (httpToken)
|
|
115
|
+
return Number(httpToken[1]);
|
|
116
|
+
// "status: 503", "status=503", "status 503" (up to 4 non-digit chars between keyword and digits)
|
|
117
|
+
// Also matches "code: 404", "code=404", etc.
|
|
118
|
+
const prefixed = /\b(?:status|code)\b\D{0,4}(\d{3})\b/i.exec(msg);
|
|
119
|
+
if (prefixed)
|
|
120
|
+
return Number(prefixed[1]);
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
function make(kind, retryable, raw, status, message) {
|
|
124
|
+
return new AgentError({ kind, retryable, status, cause: raw, message: message ?? AGENT_ERROR_MESSAGES[kind] });
|
|
125
|
+
}
|
|
126
|
+
function classifyByStatus(status, raw) {
|
|
127
|
+
if (status === 401 || status === 403)
|
|
128
|
+
return make('auth', false, raw, status);
|
|
129
|
+
if (status >= 500)
|
|
130
|
+
return make('server', true, raw, status);
|
|
131
|
+
if (status >= 400)
|
|
132
|
+
return make('server', false, raw, status, `The request was rejected (HTTP ${status}).`);
|
|
133
|
+
// Stray 2xx/3xx from a status field — treat as unknown transient failure, no status.
|
|
134
|
+
return make('server', true, raw, undefined, 'Something went wrong. You can try again.');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Classify any raw error into a structured {@link AgentError}.
|
|
138
|
+
*
|
|
139
|
+
* Resolution order (first match wins): an existing `AgentError` is returned
|
|
140
|
+
* unchanged (idempotent) → a user abort → a structured `status`/`cause.status`
|
|
141
|
+
* → network/connection markers → an HTTP-shaped status in the message → a
|
|
142
|
+
* `server` + retryable fallback. The original error is always preserved on
|
|
143
|
+
* `cause`. Runtime adapters call this before setting `Agent.error`; custom
|
|
144
|
+
* backends can call it too (or throw an `AgentError` directly).
|
|
145
|
+
*
|
|
146
|
+
* @param raw Any thrown/rejected value — an `Error`, a `{ status }` object, a string, etc.
|
|
147
|
+
* @returns The classified {@link AgentError} (kind, retryable, status?, cause).
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* const e = toAgentError(new Error('HTTP 500: Internal Server Error'));
|
|
151
|
+
* e.kind; // 'server'
|
|
152
|
+
* e.retryable; // true
|
|
153
|
+
* e.status; // 500
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
function toAgentError(raw) {
|
|
157
|
+
if (raw instanceof AgentError)
|
|
158
|
+
return raw;
|
|
159
|
+
if (isAbortError(raw))
|
|
160
|
+
return make('aborted', false, raw);
|
|
161
|
+
// 1. Structured status (authoritative): raw.status or raw.cause.status.
|
|
162
|
+
const structured = structuredStatus(raw);
|
|
163
|
+
if (structured !== undefined)
|
|
164
|
+
return classifyByStatus(structured, raw);
|
|
165
|
+
// 2. Network/connection markers are definitive — before any loose text parsing.
|
|
166
|
+
if (isConnectionError(raw))
|
|
167
|
+
return make('connection', true, raw);
|
|
168
|
+
// 3. Best-effort: only an HTTP-shaped status token in the message counts.
|
|
169
|
+
const httpStatus = httpStatusFromMessage(raw);
|
|
170
|
+
if (httpStatus !== undefined)
|
|
171
|
+
return classifyByStatus(httpStatus, raw);
|
|
172
|
+
// 4. Fallback: unknown failure, assume transient.
|
|
173
|
+
const msg = raw instanceof Error && raw.message ? raw.message : 'Something went wrong. You can try again.';
|
|
174
|
+
return make('server', true, raw, undefined, msg);
|
|
175
|
+
}
|
|
176
|
+
|
|
16
177
|
function isUserMessage(m) {
|
|
17
178
|
return m.role === 'user';
|
|
18
179
|
}
|
|
@@ -26,6 +187,24 @@ function isSystemMessage(m) {
|
|
|
26
187
|
return m.role === 'system';
|
|
27
188
|
}
|
|
28
189
|
|
|
190
|
+
// SPDX-License-Identifier: MIT
|
|
191
|
+
/**
|
|
192
|
+
* Create a typed agent handle.
|
|
193
|
+
*
|
|
194
|
+
* @param debugName Optional name shown in Angular DI error messages.
|
|
195
|
+
* @returns An {@link AgentRef} carrying a state-typed `InjectionToken`.
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* interface TripState { day: number; places: string[]; }
|
|
199
|
+
* export const TRIP = createAgentRef<TripState>('trip');
|
|
200
|
+
* // app.config.ts: provideAgent(TRIP, { assistantId: 'trip' })
|
|
201
|
+
* // component: const agent = injectAgent(TRIP); // LangGraphAgent<TripState>
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
function createAgentRef(debugName) {
|
|
205
|
+
return { token: new InjectionToken(debugName ?? 'ThreadplaneAgent') };
|
|
206
|
+
}
|
|
207
|
+
|
|
29
208
|
// SPDX-License-Identifier: MIT
|
|
30
209
|
class MessageTemplateDirective {
|
|
31
210
|
chatMessageTemplate = input.required(...(ngDevMode ? [{ debugName: "chatMessageTemplate" }] : []));
|
|
@@ -1598,9 +1777,9 @@ const MARKDOWN_VIEW_REGISTRY = new InjectionToken('MARKDOWN_VIEW_REGISTRY');
|
|
|
1598
1777
|
* registry. Each child's `type` is looked up in the registry; the resolved
|
|
1599
1778
|
* component is rendered with `[node]` bound to that child.
|
|
1600
1779
|
*
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1780
|
+
* Position-stable: `track $index` avoids NG0956 re-creation warnings that
|
|
1781
|
+
* occur when the markdown pipeline re-parses content on every stream delta,
|
|
1782
|
+
* producing new child object references even for unchanged nodes.
|
|
1604
1783
|
*/
|
|
1605
1784
|
class MarkdownChildrenComponent {
|
|
1606
1785
|
parent = input.required(...(ngDevMode ? [{ debugName: "parent" }] : []));
|
|
@@ -1620,7 +1799,7 @@ class MarkdownChildrenComponent {
|
|
|
1620
1799
|
}
|
|
1621
1800
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: MarkdownChildrenComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1622
1801
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: MarkdownChildrenComponent, isStandalone: true, selector: "chat-md-children", inputs: { parent: { classPropertyName: "parent", publicName: "parent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
1623
|
-
@for (child of children(); track $
|
|
1802
|
+
@for (child of children(); track $index) {
|
|
1624
1803
|
@let comp = resolve(child);
|
|
1625
1804
|
@if (comp) {
|
|
1626
1805
|
<ng-container *ngComponentOutlet="comp; inputs: { node: child }" />
|
|
@@ -1636,7 +1815,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
1636
1815
|
imports: [NgComponentOutlet],
|
|
1637
1816
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1638
1817
|
template: `
|
|
1639
|
-
@for (child of children(); track $
|
|
1818
|
+
@for (child of children(); track $index) {
|
|
1640
1819
|
@let comp = resolve(child);
|
|
1641
1820
|
@if (comp) {
|
|
1642
1821
|
<ng-container *ngComponentOutlet="comp; inputs: { node: child }" />
|
|
@@ -2193,7 +2372,7 @@ class MarkdownTableComponent {
|
|
|
2193
2372
|
}
|
|
2194
2373
|
</thead>
|
|
2195
2374
|
<tbody>
|
|
2196
|
-
@for (row of bodyRows(); track $
|
|
2375
|
+
@for (row of bodyRows(); track $index) {
|
|
2197
2376
|
<chat-md-table-row [node]="row" />
|
|
2198
2377
|
}
|
|
2199
2378
|
</tbody>
|
|
@@ -2215,7 +2394,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
2215
2394
|
}
|
|
2216
2395
|
</thead>
|
|
2217
2396
|
<tbody>
|
|
2218
|
-
@for (row of bodyRows(); track $
|
|
2397
|
+
@for (row of bodyRows(); track $index) {
|
|
2219
2398
|
<chat-md-table-row [node]="row" />
|
|
2220
2399
|
}
|
|
2221
2400
|
</tbody>
|
|
@@ -2793,9 +2972,19 @@ class ChatInputComponent {
|
|
|
2793
2972
|
if (submitted !== null) {
|
|
2794
2973
|
this.submitted.emit(submitted);
|
|
2795
2974
|
this.messageText.set('');
|
|
2975
|
+
const el = this.textareaEl()?.nativeElement;
|
|
2976
|
+
if (el)
|
|
2977
|
+
el.value = '';
|
|
2796
2978
|
requestAnimationFrame(() => this.textareaEl()?.nativeElement.focus());
|
|
2797
2979
|
}
|
|
2798
2980
|
}
|
|
2981
|
+
/** Sync the textarea's value into the signal on user input. A direct
|
|
2982
|
+
* [value]/(input) pair is used instead of ngModel: NgModel does not
|
|
2983
|
+
* reliably write a programmatic clear back to the view under zoneless
|
|
2984
|
+
* + OnPush, leaving sent text visible in the composer (audit F1). */
|
|
2985
|
+
onInput(event) {
|
|
2986
|
+
this.messageText.set(event.target.value);
|
|
2987
|
+
}
|
|
2799
2988
|
/** Abort the current streaming response (if the adapter supports it). */
|
|
2800
2989
|
onStop() {
|
|
2801
2990
|
const a = this.agent();
|
|
@@ -2826,15 +3015,15 @@ class ChatInputComponent {
|
|
|
2826
3015
|
<textarea
|
|
2827
3016
|
#textareaEl
|
|
2828
3017
|
class="chat-input__textarea"
|
|
2829
|
-
[
|
|
2830
|
-
(
|
|
2831
|
-
name="messageText"
|
|
3018
|
+
[value]="messageText()"
|
|
3019
|
+
(input)="onInput($event)"
|
|
2832
3020
|
[placeholder]="placeholder()"
|
|
2833
3021
|
(keydown.enter)="onKeydown($any($event))"
|
|
2834
3022
|
(compositionstart)="composing.set(true)"
|
|
2835
3023
|
(compositionend)="composing.set(false)"
|
|
2836
3024
|
(focus)="focused.set(true)"
|
|
2837
3025
|
(blur)="focused.set(false)"
|
|
3026
|
+
name="messageText"
|
|
2838
3027
|
rows="1"
|
|
2839
3028
|
aria-label="Type a message"
|
|
2840
3029
|
></textarea>
|
|
@@ -2871,11 +3060,11 @@ class ChatInputComponent {
|
|
|
2871
3060
|
</div>
|
|
2872
3061
|
<ng-content select="[chatInputFooter]" />
|
|
2873
3062
|
</div>
|
|
2874
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block;width:100%;padding:0 var(--ngaf-chat-edge-pad);box-sizing:border-box}.chat-input__container{width:100%;max-width:var(--ngaf-chat-max-width);margin:0 auto}.chat-input__pill{display:flex;align-items:center;gap:8px;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:9999px;padding:8px 8px 8px 16px;min-height:56px;box-sizing:border-box}.chat-input__textarea{flex:1 1 auto;border:0;outline:none;resize:none;background:transparent;color:var(--ngaf-chat-text);font:inherit;font-size:1rem;line-height:1.5;padding:0;field-sizing:content;overflow-y:auto}.chat-input__textarea::placeholder{color:var(--ngaf-chat-text-muted)}.chat-input__textarea::-webkit-scrollbar{width:4px}.chat-input__textarea::-webkit-scrollbar-thumb{background:var(--ngaf-chat-separator);border-radius:4px}.chat-input__controls{display:flex;align-items:center;gap:4px;flex:none}.chat-input__send,.chat-input__send--stop{width:36px;height:36px;border-radius:50%;border:0;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s ease,transform .15s ease,background .15s ease;padding:0}.chat-input__send{background:var(--ngaf-chat-text);color:var(--ngaf-chat-bg)}.chat-input__send:disabled{opacity:.35;cursor:not-allowed;background:var(--ngaf-chat-text-muted)}.chat-input__send:not(:disabled):hover{transform:scale(1.05)}.chat-input__send svg{width:16px;height:16px}.chat-input__send--stop{background:var(--ngaf-chat-text-muted);color:var(--ngaf-chat-bg)}.chat-input__send--stop:hover{transform:scale(1.05)}.chat-input__send--stop svg{width:14px;height:14px}\n"],
|
|
3063
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block;width:100%;padding:0 var(--ngaf-chat-edge-pad);box-sizing:border-box}.chat-input__container{width:100%;max-width:var(--ngaf-chat-max-width);margin:0 auto}.chat-input__pill{display:flex;align-items:center;gap:8px;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:9999px;padding:8px 8px 8px 16px;min-height:56px;box-sizing:border-box}.chat-input__textarea{flex:1 1 auto;border:0;outline:none;resize:none;background:transparent;color:var(--ngaf-chat-text);font:inherit;font-size:1rem;line-height:1.5;padding:0;field-sizing:content;overflow-y:auto}.chat-input__textarea::placeholder{color:var(--ngaf-chat-text-muted)}.chat-input__textarea::-webkit-scrollbar{width:4px}.chat-input__textarea::-webkit-scrollbar-thumb{background:var(--ngaf-chat-separator);border-radius:4px}.chat-input__controls{display:flex;align-items:center;gap:4px;flex:none}.chat-input__send,.chat-input__send--stop{width:36px;height:36px;border-radius:50%;border:0;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:opacity .15s ease,transform .15s ease,background .15s ease;padding:0}.chat-input__send{background:var(--ngaf-chat-text);color:var(--ngaf-chat-bg)}.chat-input__send:disabled{opacity:.35;cursor:not-allowed;background:var(--ngaf-chat-text-muted)}.chat-input__send:not(:disabled):hover{transform:scale(1.05)}.chat-input__send svg{width:16px;height:16px}.chat-input__send--stop{background:var(--ngaf-chat-text-muted);color:var(--ngaf-chat-bg)}.chat-input__send--stop:hover{transform:scale(1.05)}.chat-input__send--stop svg{width:14px;height:14px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2875
3064
|
}
|
|
2876
3065
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatInputComponent, decorators: [{
|
|
2877
3066
|
type: Component,
|
|
2878
|
-
args: [{ selector: 'chat-input', standalone: true, imports: [
|
|
3067
|
+
args: [{ selector: 'chat-input', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
2879
3068
|
<div class="chat-input__container">
|
|
2880
3069
|
<ng-content select="[chatInputBanner]" />
|
|
2881
3070
|
<ng-content select="[chatInputAttachments]" />
|
|
@@ -2884,15 +3073,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
2884
3073
|
<textarea
|
|
2885
3074
|
#textareaEl
|
|
2886
3075
|
class="chat-input__textarea"
|
|
2887
|
-
[
|
|
2888
|
-
(
|
|
2889
|
-
name="messageText"
|
|
3076
|
+
[value]="messageText()"
|
|
3077
|
+
(input)="onInput($event)"
|
|
2890
3078
|
[placeholder]="placeholder()"
|
|
2891
3079
|
(keydown.enter)="onKeydown($any($event))"
|
|
2892
3080
|
(compositionstart)="composing.set(true)"
|
|
2893
3081
|
(compositionend)="composing.set(false)"
|
|
2894
3082
|
(focus)="focused.set(true)"
|
|
2895
3083
|
(blur)="focused.set(false)"
|
|
3084
|
+
name="messageText"
|
|
2896
3085
|
rows="1"
|
|
2897
3086
|
aria-label="Type a message"
|
|
2898
3087
|
></textarea>
|
|
@@ -3843,6 +4032,26 @@ const CHAT_ERROR_STYLES = `
|
|
|
3843
4032
|
}
|
|
3844
4033
|
.chat-error__icon { flex-shrink: 0; width: 16px; height: 16px; margin-top: 2px; }
|
|
3845
4034
|
.chat-error__msg { flex: 1; min-width: 0; word-break: break-word; }
|
|
4035
|
+
.chat-error__retry {
|
|
4036
|
+
flex-shrink: 0;
|
|
4037
|
+
background: transparent;
|
|
4038
|
+
color: var(--ngaf-chat-error-text);
|
|
4039
|
+
border: 1px solid var(--ngaf-chat-error-border);
|
|
4040
|
+
border-radius: var(--ngaf-chat-radius-card);
|
|
4041
|
+
padding: 2px 10px;
|
|
4042
|
+
font-size: var(--ngaf-chat-font-size-sm);
|
|
4043
|
+
cursor: pointer;
|
|
4044
|
+
transition: background 150ms ease, color 150ms ease;
|
|
4045
|
+
white-space: nowrap;
|
|
4046
|
+
}
|
|
4047
|
+
.chat-error__retry:hover {
|
|
4048
|
+
background: var(--ngaf-chat-error-border);
|
|
4049
|
+
color: var(--ngaf-chat-error-text);
|
|
4050
|
+
}
|
|
4051
|
+
.chat-error__retry:focus-visible {
|
|
4052
|
+
outline: 2px solid var(--ngaf-chat-error-border);
|
|
4053
|
+
outline-offset: 2px;
|
|
4054
|
+
}
|
|
3846
4055
|
`;
|
|
3847
4056
|
|
|
3848
4057
|
// libs/chat/src/lib/primitives/chat-error/chat-error.component.ts
|
|
@@ -3858,31 +4067,36 @@ function extractErrorMessage(error) {
|
|
|
3858
4067
|
}
|
|
3859
4068
|
class ChatErrorComponent {
|
|
3860
4069
|
agent = input.required(...(ngDevMode ? [{ debugName: "agent" }] : []));
|
|
3861
|
-
errorMessage = computed(() => extractErrorMessage(this.agent().error()), ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
3862
4070
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3863
4071
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatErrorComponent, isStandalone: true, selector: "chat-error", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
3864
|
-
@if (
|
|
4072
|
+
@if (agent().error(); as err) {
|
|
3865
4073
|
<div class="chat-error" role="alert">
|
|
3866
4074
|
<svg class="chat-error__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
3867
4075
|
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
|
|
3868
4076
|
</svg>
|
|
3869
|
-
<span class="chat-error__msg">{{
|
|
4077
|
+
<span class="chat-error__msg">{{ err.message }}</span>
|
|
4078
|
+
@if (err.retryable) {
|
|
4079
|
+
<button type="button" class="chat-error__retry" (click)="agent().retry()">Retry</button>
|
|
4080
|
+
}
|
|
3870
4081
|
</div>
|
|
3871
4082
|
}
|
|
3872
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-error{display:flex;align-items:flex-start;gap:.5rem;background:var(--ngaf-chat-error-bg);border:1px solid var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text);border-radius:var(--ngaf-chat-radius-card);padding:8px 12px;font-size:var(--ngaf-chat-font-size-sm);margin:0 var(--ngaf-chat-space-6) var(--ngaf-chat-space-2)}.chat-error__icon{flex-shrink:0;width:16px;height:16px;margin-top:2px}.chat-error__msg{flex:1;min-width:0;word-break:break-word}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4083
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-error{display:flex;align-items:flex-start;gap:.5rem;background:var(--ngaf-chat-error-bg);border:1px solid var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text);border-radius:var(--ngaf-chat-radius-card);padding:8px 12px;font-size:var(--ngaf-chat-font-size-sm);margin:0 var(--ngaf-chat-space-6) var(--ngaf-chat-space-2)}.chat-error__icon{flex-shrink:0;width:16px;height:16px;margin-top:2px}.chat-error__msg{flex:1;min-width:0;word-break:break-word}.chat-error__retry{flex-shrink:0;background:transparent;color:var(--ngaf-chat-error-text);border:1px solid var(--ngaf-chat-error-border);border-radius:var(--ngaf-chat-radius-card);padding:2px 10px;font-size:var(--ngaf-chat-font-size-sm);cursor:pointer;transition:background .15s ease,color .15s ease;white-space:nowrap}.chat-error__retry:hover{background:var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text)}.chat-error__retry:focus-visible{outline:2px solid var(--ngaf-chat-error-border);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3873
4084
|
}
|
|
3874
4085
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatErrorComponent, decorators: [{
|
|
3875
4086
|
type: Component,
|
|
3876
4087
|
args: [{ selector: 'chat-error', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
3877
|
-
@if (
|
|
4088
|
+
@if (agent().error(); as err) {
|
|
3878
4089
|
<div class="chat-error" role="alert">
|
|
3879
4090
|
<svg class="chat-error__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
3880
4091
|
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
|
|
3881
4092
|
</svg>
|
|
3882
|
-
<span class="chat-error__msg">{{
|
|
4093
|
+
<span class="chat-error__msg">{{ err.message }}</span>
|
|
4094
|
+
@if (err.retryable) {
|
|
4095
|
+
<button type="button" class="chat-error__retry" (click)="agent().retry()">Retry</button>
|
|
4096
|
+
}
|
|
3883
4097
|
</div>
|
|
3884
4098
|
}
|
|
3885
|
-
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-error{display:flex;align-items:flex-start;gap:.5rem;background:var(--ngaf-chat-error-bg);border:1px solid var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text);border-radius:var(--ngaf-chat-radius-card);padding:8px 12px;font-size:var(--ngaf-chat-font-size-sm);margin:0 var(--ngaf-chat-space-6) var(--ngaf-chat-space-2)}.chat-error__icon{flex-shrink:0;width:16px;height:16px;margin-top:2px}.chat-error__msg{flex:1;min-width:0;word-break:break-word}\n"] }]
|
|
4099
|
+
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-error{display:flex;align-items:flex-start;gap:.5rem;background:var(--ngaf-chat-error-bg);border:1px solid var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text);border-radius:var(--ngaf-chat-radius-card);padding:8px 12px;font-size:var(--ngaf-chat-font-size-sm);margin:0 var(--ngaf-chat-space-6) var(--ngaf-chat-space-2)}.chat-error__icon{flex-shrink:0;width:16px;height:16px;margin-top:2px}.chat-error__msg{flex:1;min-width:0;word-break:break-word}.chat-error__retry{flex-shrink:0;background:transparent;color:var(--ngaf-chat-error-text);border:1px solid var(--ngaf-chat-error-border);border-radius:var(--ngaf-chat-radius-card);padding:2px 10px;font-size:var(--ngaf-chat-font-size-sm);cursor:pointer;transition:background .15s ease,color .15s ease;white-space:nowrap}.chat-error__retry:hover{background:var(--ngaf-chat-error-border);color:var(--ngaf-chat-error-text)}.chat-error__retry:focus-visible{outline:2px solid var(--ngaf-chat-error-border);outline-offset:2px}\n"] }]
|
|
3886
4100
|
}], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }] } });
|
|
3887
4101
|
|
|
3888
4102
|
// SPDX-License-Identifier: MIT
|
|
@@ -4342,6 +4556,54 @@ const CHAT_GENERATIVE_UI_STYLES = `
|
|
|
4342
4556
|
}
|
|
4343
4557
|
`;
|
|
4344
4558
|
|
|
4559
|
+
function isStatePathRef(value) {
|
|
4560
|
+
return (typeof value === 'object' &&
|
|
4561
|
+
value !== null &&
|
|
4562
|
+
!Array.isArray(value) &&
|
|
4563
|
+
typeof value['statePath'] === 'string' &&
|
|
4564
|
+
Object.keys(value).length === 1);
|
|
4565
|
+
}
|
|
4566
|
+
/** Rewrites schema-documented `{ statePath }` prop refs to `$bindState` +
|
|
4567
|
+
* `_bindings`. Returns the input reference unchanged when no rewriting is
|
|
4568
|
+
* needed (keeps downstream memoization intact). */
|
|
4569
|
+
function normalizeJsonRenderSpec(spec) {
|
|
4570
|
+
const sourceElements = (spec.elements ?? {});
|
|
4571
|
+
let specChanged = false;
|
|
4572
|
+
const elements = {};
|
|
4573
|
+
for (const [id, el] of Object.entries(sourceElements)) {
|
|
4574
|
+
const rawProps = el?.props;
|
|
4575
|
+
if (!rawProps) {
|
|
4576
|
+
elements[id] = el;
|
|
4577
|
+
continue;
|
|
4578
|
+
}
|
|
4579
|
+
let elementChanged = false;
|
|
4580
|
+
const props = {};
|
|
4581
|
+
const bindings = {};
|
|
4582
|
+
for (const [key, value] of Object.entries(rawProps)) {
|
|
4583
|
+
if (isStatePathRef(value)) {
|
|
4584
|
+
props[key] = { $bindState: value.statePath };
|
|
4585
|
+
bindings[key] = value.statePath;
|
|
4586
|
+
elementChanged = true;
|
|
4587
|
+
}
|
|
4588
|
+
else {
|
|
4589
|
+
props[key] = value;
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
if (elementChanged) {
|
|
4593
|
+
// Merge with any model-emitted `_bindings` (never observed, but cheap
|
|
4594
|
+
// to preserve) — rewritten paths win.
|
|
4595
|
+
const existing = (rawProps['_bindings'] ?? {});
|
|
4596
|
+
props['_bindings'] = { ...existing, ...bindings };
|
|
4597
|
+
elements[id] = { ...el, props };
|
|
4598
|
+
specChanged = true;
|
|
4599
|
+
}
|
|
4600
|
+
else {
|
|
4601
|
+
elements[id] = el;
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
return specChanged ? { ...spec, elements } : spec;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4345
4607
|
// libs/chat/src/lib/primitives/chat-generative-ui/chat-generative-ui.component.ts
|
|
4346
4608
|
// SPDX-License-Identifier: MIT
|
|
4347
4609
|
class ChatGenerativeUiComponent {
|
|
@@ -4351,11 +4613,58 @@ class ChatGenerativeUiComponent {
|
|
|
4351
4613
|
handlers = input(undefined, ...(ngDevMode ? [{ debugName: "handlers" }] : []));
|
|
4352
4614
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
4353
4615
|
events = output();
|
|
4616
|
+
/** The bound spec with schema-documented `{ statePath }` prop refs
|
|
4617
|
+
* rewritten to engine-native `{ $bindState }` + `_bindings` so values
|
|
4618
|
+
* resolve against the state store instead of interpolating as
|
|
4619
|
+
* "[object Object]" (F4). */
|
|
4620
|
+
normalizedSpec = computed(() => {
|
|
4621
|
+
const s = this.spec();
|
|
4622
|
+
return s ? normalizeJsonRenderSpec(s) : null;
|
|
4623
|
+
}, ...(ngDevMode ? [{ debugName: "normalizedSpec" }] : []));
|
|
4624
|
+
/** Last value this component seeded per state path. Lets the seeding
|
|
4625
|
+
* effect distinguish "still the value we wrote (possibly a partial
|
|
4626
|
+
* chunk from streaming — safe to overwrite with the newer one)" from
|
|
4627
|
+
* "user edited it via a bound control — leave it alone". */
|
|
4628
|
+
seeded = new Map();
|
|
4629
|
+
constructor() {
|
|
4630
|
+
// Seed `spec.state` (the schema's "initial state model") into an
|
|
4631
|
+
// EXPLICIT consumer-provided store, which is typically EMPTY at first —
|
|
4632
|
+
// without this, statePath/$bindState props would resolve to undefined.
|
|
4633
|
+
// A consumer-provided store intentionally has shared/live semantics
|
|
4634
|
+
// across surfaces: every surface bound to it reads (and writes) the same
|
|
4635
|
+
// state, so the first surface to seed a path wins. When NO store input
|
|
4636
|
+
// is given, this effect is a no-op and render-spec self-seeds its own
|
|
4637
|
+
// per-instance internal store from spec.state, keeping surfaces with
|
|
4638
|
+
// overlapping state keys isolated from each other (a2ui parity).
|
|
4639
|
+
effect(() => {
|
|
4640
|
+
const s = this.spec();
|
|
4641
|
+
const store = this.store();
|
|
4642
|
+
const state = s?.state;
|
|
4643
|
+
if (!state || !store)
|
|
4644
|
+
return;
|
|
4645
|
+
// Untracked: store reads/writes must not become dependencies — the
|
|
4646
|
+
// effect re-runs on spec/store-identity changes only, not on every
|
|
4647
|
+
// write to the (possibly shared) store.
|
|
4648
|
+
untracked(() => {
|
|
4649
|
+
for (const [key, value] of Object.entries(state)) {
|
|
4650
|
+
const path = key.startsWith('/') ? key : `/${key}`;
|
|
4651
|
+
const current = store.get(path);
|
|
4652
|
+
const untouched = current === undefined ||
|
|
4653
|
+
(this.seeded.has(path) && current === this.seeded.get(path));
|
|
4654
|
+
if (untouched) {
|
|
4655
|
+
if (current !== value)
|
|
4656
|
+
store.set(path, value);
|
|
4657
|
+
this.seeded.set(path, value);
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
});
|
|
4661
|
+
});
|
|
4662
|
+
}
|
|
4354
4663
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatGenerativeUiComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4355
4664
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatGenerativeUiComponent, isStandalone: true, selector: "chat-generative-ui", inputs: { spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null }, registry: { classPropertyName: "registry", publicName: "registry", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { events: "events" }, ngImport: i0, template: `
|
|
4356
|
-
@if (
|
|
4665
|
+
@if (normalizedSpec()) {
|
|
4357
4666
|
<render-spec
|
|
4358
|
-
[spec]="
|
|
4667
|
+
[spec]="normalizedSpec()"
|
|
4359
4668
|
[registry]="registry()"
|
|
4360
4669
|
[store]="store()"
|
|
4361
4670
|
[handlers]="handlers()"
|
|
@@ -4368,9 +4677,9 @@ class ChatGenerativeUiComponent {
|
|
|
4368
4677
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatGenerativeUiComponent, decorators: [{
|
|
4369
4678
|
type: Component,
|
|
4370
4679
|
args: [{ selector: 'chat-generative-ui', standalone: true, imports: [RenderSpecComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4371
|
-
@if (
|
|
4680
|
+
@if (normalizedSpec()) {
|
|
4372
4681
|
<render-spec
|
|
4373
|
-
[spec]="
|
|
4682
|
+
[spec]="normalizedSpec()"
|
|
4374
4683
|
[registry]="registry()"
|
|
4375
4684
|
[store]="store()"
|
|
4376
4685
|
[handlers]="handlers()"
|
|
@@ -4379,7 +4688,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
4379
4688
|
/>
|
|
4380
4689
|
}
|
|
4381
4690
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block;color:var(--ngaf-chat-text);font-size:var(--ngaf-chat-font-size);line-height:var(--ngaf-chat-line-height)}.chat-generative-ui__error{color:var(--ngaf-chat-error-text);background:var(--ngaf-chat-error-bg);border:1px solid var(--ngaf-chat-error-border);border-radius:var(--ngaf-chat-radius-card);padding:8px 12px;font-size:var(--ngaf-chat-font-size-sm)}\n"] }]
|
|
4382
|
-
}], propDecorators: { spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }], registry: [{ type: i0.Input, args: [{ isSignal: true, alias: "registry", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], events: [{ type: i0.Output, args: ["events"] }] } });
|
|
4691
|
+
}], ctorParameters: () => [], propDecorators: { spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }], registry: [{ type: i0.Input, args: [{ isSignal: true, alias: "registry", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], events: [{ type: i0.Output, args: ["events"] }] } });
|
|
4383
4692
|
|
|
4384
4693
|
// libs/chat/src/lib/primitives/chat-tool-views/chat-tool-views.component.ts
|
|
4385
4694
|
// SPDX-License-Identifier: MIT
|
|
@@ -4398,6 +4707,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
4398
4707
|
*/
|
|
4399
4708
|
class ChatToolViewsComponent {
|
|
4400
4709
|
agent = input.required(...(ngDevMode ? [{ debugName: "agent" }] : []));
|
|
4710
|
+
events = output();
|
|
4401
4711
|
message = input(undefined, ...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
4402
4712
|
views = input(undefined, ...(ngDevMode ? [{ debugName: "views" }] : []));
|
|
4403
4713
|
store = input(undefined, ...(ngDevMode ? [{ debugName: "store" }] : []));
|
|
@@ -4416,7 +4726,7 @@ class ChatToolViewsComponent {
|
|
|
4416
4726
|
.map((tc) => ({ id: tc.id, loading: tc.status === 'running', spec: toToolViewSpec(tc) }));
|
|
4417
4727
|
}, ...(ngDevMode ? [{ debugName: "toolViews" }] : []));
|
|
4418
4728
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatToolViewsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4419
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatToolViewsComponent, isStandalone: true, selector: "chat-tool-views", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
4729
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatToolViewsComponent, isStandalone: true, selector: "chat-tool-views", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { events: "events" }, ngImport: i0, template: `
|
|
4420
4730
|
@for (view of toolViews(); track view.id) {
|
|
4421
4731
|
<chat-generative-ui
|
|
4422
4732
|
[spec]="view.spec"
|
|
@@ -4424,6 +4734,7 @@ class ChatToolViewsComponent {
|
|
|
4424
4734
|
[store]="store()"
|
|
4425
4735
|
[handlers]="handlers()"
|
|
4426
4736
|
[loading]="view.loading"
|
|
4737
|
+
(events)="events.emit($event)"
|
|
4427
4738
|
/>
|
|
4428
4739
|
}
|
|
4429
4740
|
`, isInline: true, dependencies: [{ kind: "component", type: ChatGenerativeUiComponent, selector: "chat-generative-ui", inputs: ["spec", "registry", "store", "handlers", "loading"], outputs: ["events"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
@@ -4443,11 +4754,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
4443
4754
|
[store]="store()"
|
|
4444
4755
|
[handlers]="handlers()"
|
|
4445
4756
|
[loading]="view.loading"
|
|
4757
|
+
(events)="events.emit($event)"
|
|
4446
4758
|
/>
|
|
4447
4759
|
}
|
|
4448
4760
|
`,
|
|
4449
4761
|
}]
|
|
4450
|
-
}], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }] } });
|
|
4762
|
+
}], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], events: [{ type: i0.Output, args: ["events"] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }] } });
|
|
4451
4763
|
/** Wraps a tool call into a synthetic single-element render spec. */
|
|
4452
4764
|
function toToolViewSpec(tc) {
|
|
4453
4765
|
const args = isRecord$2(tc.args) ? tc.args : {};
|
|
@@ -4493,46 +4805,70 @@ function statusToTraceState(s) {
|
|
|
4493
4805
|
class ChatSubagentCardComponent {
|
|
4494
4806
|
subagent = input.required(...(ngDevMode ? [{ debugName: "subagent" }] : []));
|
|
4495
4807
|
state = computed(() => statusToTraceState(this.subagent().status()), ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
4496
|
-
|
|
4497
|
-
const
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
const
|
|
4502
|
-
|
|
4503
|
-
|
|
4808
|
+
textOf(m) {
|
|
4809
|
+
const c = m.content;
|
|
4810
|
+
return typeof c === 'string' ? c : '';
|
|
4811
|
+
}
|
|
4812
|
+
toolCallsFor(m) {
|
|
4813
|
+
const ids = m.toolCallIds ?? [];
|
|
4814
|
+
if (ids.length === 0)
|
|
4815
|
+
return [];
|
|
4816
|
+
const all = this.subagent().toolCalls?.() ?? [];
|
|
4817
|
+
return ids.map((id) => all.find((tc) => tc.id === id)).filter((tc) => !!tc);
|
|
4818
|
+
}
|
|
4819
|
+
toToolCallInfo(tc) {
|
|
4820
|
+
return { id: tc.id, name: tc.name, args: tc.args, result: tc.result, status: tc.status };
|
|
4821
|
+
}
|
|
4504
4822
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4505
4823
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatSubagentCardComponent, isStandalone: true, selector: "chat-subagent-card", inputs: { subagent: { classPropertyName: "subagent", publicName: "subagent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
4506
4824
|
<chat-trace [state]="state()">
|
|
4507
4825
|
<span traceLabel>
|
|
4508
|
-
<span class="sac__name">Subagent</span>
|
|
4826
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4509
4827
|
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4510
4828
|
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4511
4829
|
</span>
|
|
4512
4830
|
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
4513
|
-
@
|
|
4514
|
-
<
|
|
4515
|
-
|
|
4831
|
+
@for (m of subagent().messages(); track m.id) {
|
|
4832
|
+
<div class="sac__msg" [attr.data-role]="m.role">
|
|
4833
|
+
@if (m.reasoning) {
|
|
4834
|
+
<div class="sac__reasoning">{{ m.reasoning }}</div>
|
|
4835
|
+
}
|
|
4836
|
+
@if (textOf(m); as t) {
|
|
4837
|
+
<chat-streaming-md [content]="t" />
|
|
4838
|
+
}
|
|
4839
|
+
@for (tc of toolCallsFor(m); track tc.id) {
|
|
4840
|
+
<chat-tool-call-card [toolCall]="toToolCallInfo(tc)" />
|
|
4841
|
+
}
|
|
4842
|
+
</div>
|
|
4516
4843
|
}
|
|
4517
4844
|
</chat-trace>
|
|
4518
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.sac__name{color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.sac__id{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);margin-left:4px}.sac__pill{padding:1px 8px;border-radius:9999px;font-size:11px;font-weight:500;margin-left:4px}.sac__pill[data-status=pending]{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text-muted)}.sac__pill[data-status=running]{background:var(--ngaf-chat-warning-bg);color:var(--ngaf-chat-warning-text)}.sac__pill[data-status=complete]{color:var(--ngaf-chat-success)}.sac__pill[data-status=error]{background:var(--ngaf-chat-error-bg);color:var(--ngaf-chat-error-text)}.sac__count{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted)}.
|
|
4845
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.sac__name{color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.sac__id{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);margin-left:4px}.sac__pill{padding:1px 8px;border-radius:9999px;font-size:11px;font-weight:500;margin-left:4px}.sac__pill[data-status=pending]{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text-muted)}.sac__pill[data-status=running]{background:var(--ngaf-chat-warning-bg);color:var(--ngaf-chat-warning-text)}.sac__pill[data-status=complete]{color:var(--ngaf-chat-success)}.sac__pill[data-status=error]{background:var(--ngaf-chat-error-bg);color:var(--ngaf-chat-error-text)}.sac__count{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted)}.sac__msg{padding:6px 0}.sac__msg+.sac__msg{border-top:1px solid var(--ngaf-chat-separator)}.sac__reasoning{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);font-style:italic;margin-bottom:4px}\n"], dependencies: [{ kind: "component", type: ChatTraceComponent, selector: "chat-trace", inputs: ["state", "defaultExpanded"] }, { kind: "component", type: ChatToolCallCardComponent, selector: "chat-tool-call-card", inputs: ["toolCall", "defaultCollapsed"] }, { kind: "component", type: ChatStreamingMdComponent, selector: "chat-streaming-md", inputs: ["content", "streaming", "viewRegistry"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4519
4846
|
}
|
|
4520
4847
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, decorators: [{
|
|
4521
4848
|
type: Component,
|
|
4522
|
-
args: [{ selector: 'chat-subagent-card', standalone: true, imports: [ChatTraceComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4849
|
+
args: [{ selector: 'chat-subagent-card', standalone: true, imports: [ChatTraceComponent, ChatToolCallCardComponent, ChatStreamingMdComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4523
4850
|
<chat-trace [state]="state()">
|
|
4524
4851
|
<span traceLabel>
|
|
4525
|
-
<span class="sac__name">Subagent</span>
|
|
4852
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4526
4853
|
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4527
4854
|
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4528
4855
|
</span>
|
|
4529
4856
|
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
4530
|
-
@
|
|
4531
|
-
<
|
|
4532
|
-
|
|
4857
|
+
@for (m of subagent().messages(); track m.id) {
|
|
4858
|
+
<div class="sac__msg" [attr.data-role]="m.role">
|
|
4859
|
+
@if (m.reasoning) {
|
|
4860
|
+
<div class="sac__reasoning">{{ m.reasoning }}</div>
|
|
4861
|
+
}
|
|
4862
|
+
@if (textOf(m); as t) {
|
|
4863
|
+
<chat-streaming-md [content]="t" />
|
|
4864
|
+
}
|
|
4865
|
+
@for (tc of toolCallsFor(m); track tc.id) {
|
|
4866
|
+
<chat-tool-call-card [toolCall]="toToolCallInfo(tc)" />
|
|
4867
|
+
}
|
|
4868
|
+
</div>
|
|
4533
4869
|
}
|
|
4534
4870
|
</chat-trace>
|
|
4535
|
-
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.sac__name{color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.sac__id{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);margin-left:4px}.sac__pill{padding:1px 8px;border-radius:9999px;font-size:11px;font-weight:500;margin-left:4px}.sac__pill[data-status=pending]{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text-muted)}.sac__pill[data-status=running]{background:var(--ngaf-chat-warning-bg);color:var(--ngaf-chat-warning-text)}.sac__pill[data-status=complete]{color:var(--ngaf-chat-success)}.sac__pill[data-status=error]{background:var(--ngaf-chat-error-bg);color:var(--ngaf-chat-error-text)}.sac__count{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted)}.
|
|
4871
|
+
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.sac__name{color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.sac__id{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);margin-left:4px}.sac__pill{padding:1px 8px;border-radius:9999px;font-size:11px;font-weight:500;margin-left:4px}.sac__pill[data-status=pending]{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text-muted)}.sac__pill[data-status=running]{background:var(--ngaf-chat-warning-bg);color:var(--ngaf-chat-warning-text)}.sac__pill[data-status=complete]{color:var(--ngaf-chat-success)}.sac__pill[data-status=error]{background:var(--ngaf-chat-error-bg);color:var(--ngaf-chat-error-text)}.sac__count{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted)}.sac__msg{padding:6px 0}.sac__msg+.sac__msg{border-top:1px solid var(--ngaf-chat-separator)}.sac__reasoning{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);font-style:italic;margin-bottom:4px}\n"] }]
|
|
4536
4872
|
}], propDecorators: { subagent: [{ type: i0.Input, args: [{ isSignal: true, alias: "subagent", required: true }] }] } });
|
|
4537
4873
|
|
|
4538
4874
|
// libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts
|
|
@@ -6086,10 +6422,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
6086
6422
|
class ChatWelcomeSuggestionComponent {
|
|
6087
6423
|
label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
6088
6424
|
value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
6425
|
+
/** Optional short description, surfaced as a hover/focus tooltip on the chip. */
|
|
6426
|
+
description = input(...(ngDevMode ? [undefined, { debugName: "description" }] : []));
|
|
6089
6427
|
selected = output();
|
|
6090
6428
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatWelcomeSuggestionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6091
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatWelcomeSuggestionComponent, isStandalone: true, selector: "chat-welcome-suggestion", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selected: "selected" }, ngImport: i0, template: `
|
|
6092
|
-
<button
|
|
6429
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatWelcomeSuggestionComponent, isStandalone: true, selector: "chat-welcome-suggestion", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, ngImport: i0, template: `
|
|
6430
|
+
<button
|
|
6431
|
+
type="button"
|
|
6432
|
+
class="chat-welcome-suggestion"
|
|
6433
|
+
[attr.title]="description() || null"
|
|
6434
|
+
[attr.aria-description]="description() || null"
|
|
6435
|
+
(click)="selected.emit(value())"
|
|
6436
|
+
>
|
|
6093
6437
|
<ng-content select="[chatWelcomeSuggestionIcon]" />
|
|
6094
6438
|
<span class="chat-welcome-suggestion__label">{{ label() }}</span>
|
|
6095
6439
|
<span class="chat-welcome-suggestion__chevron" aria-hidden="true">›</span>
|
|
@@ -6099,13 +6443,19 @@ class ChatWelcomeSuggestionComponent {
|
|
|
6099
6443
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatWelcomeSuggestionComponent, decorators: [{
|
|
6100
6444
|
type: Component,
|
|
6101
6445
|
args: [{ selector: 'chat-welcome-suggestion', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
6102
|
-
<button
|
|
6446
|
+
<button
|
|
6447
|
+
type="button"
|
|
6448
|
+
class="chat-welcome-suggestion"
|
|
6449
|
+
[attr.title]="description() || null"
|
|
6450
|
+
[attr.aria-description]="description() || null"
|
|
6451
|
+
(click)="selected.emit(value())"
|
|
6452
|
+
>
|
|
6103
6453
|
<ng-content select="[chatWelcomeSuggestionIcon]" />
|
|
6104
6454
|
<span class="chat-welcome-suggestion__label">{{ label() }}</span>
|
|
6105
6455
|
<span class="chat-welcome-suggestion__chevron" aria-hidden="true">›</span>
|
|
6106
6456
|
</button>
|
|
6107
6457
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:inline-block}.chat-welcome-suggestion{display:inline-flex;align-items:center;gap:.5rem;padding:10px 16px;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:9999px;color:var(--ngaf-chat-text);font-family:inherit;font-size:var(--ngaf-chat-font-size-sm);text-align:center;cursor:pointer;transition:background .15s ease,border-color .15s ease,transform .12s ease}.chat-welcome-suggestion:hover{background:var(--ngaf-chat-surface-alt);border-color:var(--ngaf-chat-text-muted)}.chat-welcome-suggestion:active{transform:scale(.98)}.chat-welcome-suggestion:focus-visible{outline:2px solid var(--ngaf-chat-text-muted);outline-offset:2px}.chat-welcome-suggestion__label{white-space:nowrap}.chat-welcome-suggestion__chevron{display:none}\n"] }]
|
|
6108
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
|
|
6458
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
|
|
6109
6459
|
|
|
6110
6460
|
// libs/chat/src/lib/styles/chat-select.styles.ts
|
|
6111
6461
|
// SPDX-License-Identifier: MIT
|
|
@@ -6161,7 +6511,10 @@ const CHAT_SELECT_STYLES = `
|
|
|
6161
6511
|
z-index: 10;
|
|
6162
6512
|
}
|
|
6163
6513
|
.chat-select__option {
|
|
6164
|
-
display:
|
|
6514
|
+
display: flex;
|
|
6515
|
+
flex-direction: column;
|
|
6516
|
+
align-items: flex-start;
|
|
6517
|
+
gap: 2px;
|
|
6165
6518
|
width: 100%;
|
|
6166
6519
|
text-align: left;
|
|
6167
6520
|
border: 0;
|
|
@@ -6173,6 +6526,12 @@ const CHAT_SELECT_STYLES = `
|
|
|
6173
6526
|
font-size: var(--ngaf-chat-font-size-sm);
|
|
6174
6527
|
cursor: pointer;
|
|
6175
6528
|
}
|
|
6529
|
+
.chat-select__option-desc {
|
|
6530
|
+
font-size: var(--ngaf-chat-font-size-xs);
|
|
6531
|
+
color: var(--ngaf-chat-text-muted);
|
|
6532
|
+
line-height: 1.3;
|
|
6533
|
+
white-space: normal;
|
|
6534
|
+
}
|
|
6176
6535
|
.chat-select__option:hover:not(:disabled),
|
|
6177
6536
|
.chat-select__option:focus-visible {
|
|
6178
6537
|
background: var(--ngaf-chat-surface-alt);
|
|
@@ -6351,12 +6710,15 @@ class ChatSelectComponent {
|
|
|
6351
6710
|
[attr.aria-selected]="opt.value === value()"
|
|
6352
6711
|
(click)="selectOption(opt)"
|
|
6353
6712
|
>
|
|
6354
|
-
{{ opt.label }}
|
|
6713
|
+
<span class="chat-select__option-label">{{ opt.label }}</span>
|
|
6714
|
+
@if (opt.description) {
|
|
6715
|
+
<span class="chat-select__option-desc">{{ opt.description }}</span>
|
|
6716
|
+
}
|
|
6355
6717
|
</button>
|
|
6356
6718
|
}
|
|
6357
6719
|
</div>
|
|
6358
6720
|
}
|
|
6359
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:inline-block;position:relative}.chat-select__trigger{height:32px;padding:0 10px;border:0;border-radius:9999px;background:transparent;color:var(--ngaf-chat-text-muted);font:inherit;font-size:var(--ngaf-chat-font-size-sm);display:inline-flex;align-items:center;gap:4px;cursor:pointer;transition:background .12s ease,color .12s ease}.chat-select__trigger:hover:not(:disabled){background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-select__trigger:disabled{opacity:.5;cursor:not-allowed}.chat-select__chevron{width:12px;height:12px;transition:transform .12s ease;flex:none}.chat-select__trigger.is-open .chat-select__chevron{transform:rotate(180deg)}.chat-select__menu{position:absolute;bottom:calc(100% + 8px);right:0;min-width:180px;max-height:320px;overflow-y:auto;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:12px;box-shadow:var(--ngaf-chat-shadow-lg);padding:4px;z-index:10}.chat-select__option{display:
|
|
6721
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:inline-block;position:relative}.chat-select__trigger{height:32px;padding:0 10px;border:0;border-radius:9999px;background:transparent;color:var(--ngaf-chat-text-muted);font:inherit;font-size:var(--ngaf-chat-font-size-sm);display:inline-flex;align-items:center;gap:4px;cursor:pointer;transition:background .12s ease,color .12s ease}.chat-select__trigger:hover:not(:disabled){background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-select__trigger:disabled{opacity:.5;cursor:not-allowed}.chat-select__chevron{width:12px;height:12px;transition:transform .12s ease;flex:none}.chat-select__trigger.is-open .chat-select__chevron{transform:rotate(180deg)}.chat-select__menu{position:absolute;bottom:calc(100% + 8px);right:0;min-width:180px;max-height:320px;overflow-y:auto;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:12px;box-shadow:var(--ngaf-chat-shadow-lg);padding:4px;z-index:10}.chat-select__option{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;border:0;background:transparent;padding:8px 10px;border-radius:8px;color:var(--ngaf-chat-text);font:inherit;font-size:var(--ngaf-chat-font-size-sm);cursor:pointer}.chat-select__option-desc{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);line-height:1.3;white-space:normal}.chat-select__option:hover:not(:disabled),.chat-select__option:focus-visible{background:var(--ngaf-chat-surface-alt);outline:none}.chat-select__option.is-active{background:var(--ngaf-chat-surface-alt);font-weight:500}.chat-select__option:disabled{opacity:.4;cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6360
6722
|
}
|
|
6361
6723
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSelectComponent, decorators: [{
|
|
6362
6724
|
type: Component,
|
|
@@ -6394,17 +6756,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
6394
6756
|
[attr.aria-selected]="opt.value === value()"
|
|
6395
6757
|
(click)="selectOption(opt)"
|
|
6396
6758
|
>
|
|
6397
|
-
{{ opt.label }}
|
|
6759
|
+
<span class="chat-select__option-label">{{ opt.label }}</span>
|
|
6760
|
+
@if (opt.description) {
|
|
6761
|
+
<span class="chat-select__option-desc">{{ opt.description }}</span>
|
|
6762
|
+
}
|
|
6398
6763
|
</button>
|
|
6399
6764
|
}
|
|
6400
6765
|
</div>
|
|
6401
6766
|
}
|
|
6402
|
-
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:inline-block;position:relative}.chat-select__trigger{height:32px;padding:0 10px;border:0;border-radius:9999px;background:transparent;color:var(--ngaf-chat-text-muted);font:inherit;font-size:var(--ngaf-chat-font-size-sm);display:inline-flex;align-items:center;gap:4px;cursor:pointer;transition:background .12s ease,color .12s ease}.chat-select__trigger:hover:not(:disabled){background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-select__trigger:disabled{opacity:.5;cursor:not-allowed}.chat-select__chevron{width:12px;height:12px;transition:transform .12s ease;flex:none}.chat-select__trigger.is-open .chat-select__chevron{transform:rotate(180deg)}.chat-select__menu{position:absolute;bottom:calc(100% + 8px);right:0;min-width:180px;max-height:320px;overflow-y:auto;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:12px;box-shadow:var(--ngaf-chat-shadow-lg);padding:4px;z-index:10}.chat-select__option{display:
|
|
6767
|
+
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:inline-block;position:relative}.chat-select__trigger{height:32px;padding:0 10px;border:0;border-radius:9999px;background:transparent;color:var(--ngaf-chat-text-muted);font:inherit;font-size:var(--ngaf-chat-font-size-sm);display:inline-flex;align-items:center;gap:4px;cursor:pointer;transition:background .12s ease,color .12s ease}.chat-select__trigger:hover:not(:disabled){background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-select__trigger:disabled{opacity:.5;cursor:not-allowed}.chat-select__chevron{width:12px;height:12px;transition:transform .12s ease;flex:none}.chat-select__trigger.is-open .chat-select__chevron{transform:rotate(180deg)}.chat-select__menu{position:absolute;bottom:calc(100% + 8px);right:0;min-width:180px;max-height:320px;overflow-y:auto;background:var(--ngaf-chat-surface);border:1px solid var(--ngaf-chat-separator);border-radius:12px;box-shadow:var(--ngaf-chat-shadow-lg);padding:4px;z-index:10}.chat-select__option{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;border:0;background:transparent;padding:8px 10px;border-radius:8px;color:var(--ngaf-chat-text);font:inherit;font-size:var(--ngaf-chat-font-size-sm);cursor:pointer}.chat-select__option-desc{font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text-muted);line-height:1.3;white-space:normal}.chat-select__option:hover:not(:disabled),.chat-select__option:focus-visible{background:var(--ngaf-chat-surface-alt);outline:none}.chat-select__option.is-active{background:var(--ngaf-chat-surface-alt);font-weight:500}.chat-select__option:disabled{opacity:.4;cursor:not-allowed}\n"] }]
|
|
6403
6768
|
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], menuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuLabel", required: false }] }] } });
|
|
6404
6769
|
|
|
6405
6770
|
// SPDX-License-Identifier: MIT
|
|
6406
6771
|
const PACKAGE_NAME = '@threadplane/chat';
|
|
6407
6772
|
const CHAT_CONFIG = new InjectionToken('CHAT_CONFIG');
|
|
6773
|
+
/**
|
|
6774
|
+
* Bootstrap `@threadplane/chat` in an Angular application or standalone
|
|
6775
|
+
* component tree.
|
|
6776
|
+
*
|
|
6777
|
+
* Call this once inside `bootstrapApplication` (or the `providers` array of a
|
|
6778
|
+
* root `ApplicationConfig`). It registers the shared {@link ChatConfig} token
|
|
6779
|
+
* so every chat component in the tree can read the render registry, avatar
|
|
6780
|
+
* label, and assistant display name without explicit prop threading.
|
|
6781
|
+
*
|
|
6782
|
+
* A license check is fired asynchronously on every call (it never throws; a
|
|
6783
|
+
* watermark is shown in non-commercial builds when no valid token is supplied).
|
|
6784
|
+
*
|
|
6785
|
+
* @param config Options bag that controls the chat feature set:
|
|
6786
|
+
* - `renderRegistry` — shared {@link AngularRegistry} wiring tool-view
|
|
6787
|
+
* components to their names; pass the value returned by
|
|
6788
|
+
* `defineAngularRegistry` from `\@threadplane/render`.
|
|
6789
|
+
* - `avatarLabel` — short label shown in the AI avatar bubble (default `"A"`).
|
|
6790
|
+
* - `assistantName` — display name shown above assistant messages
|
|
6791
|
+
* (default `"Assistant"`).
|
|
6792
|
+
* - `license` — signed token from threadplane.ai; omit in development.
|
|
6793
|
+
* @returns An `EnvironmentProviders` value suitable for the `providers` array
|
|
6794
|
+
* of `bootstrapApplication` or `ApplicationConfig`.
|
|
6795
|
+
* @example
|
|
6796
|
+
* ```ts
|
|
6797
|
+
* // main.ts
|
|
6798
|
+
* import { bootstrapApplication } from '@angular/platform-browser';
|
|
6799
|
+
* import { provideChat } from '@threadplane/chat';
|
|
6800
|
+
* import { defineAngularRegistry, provideRender } from '@threadplane/render';
|
|
6801
|
+
* import { DayCardComponent } from './day-card.component';
|
|
6802
|
+
*
|
|
6803
|
+
* const registry = defineAngularRegistry({ day_card: DayCardComponent });
|
|
6804
|
+
*
|
|
6805
|
+
* bootstrapApplication(AppComponent, {
|
|
6806
|
+
* providers: [
|
|
6807
|
+
* provideChat({ renderRegistry: registry, avatarLabel: 'AI' }),
|
|
6808
|
+
* provideRender({ registry }),
|
|
6809
|
+
* ],
|
|
6810
|
+
* });
|
|
6811
|
+
* ```
|
|
6812
|
+
*/
|
|
6408
6813
|
function provideChat(config) {
|
|
6409
6814
|
void runLicenseCheck({
|
|
6410
6815
|
package: PACKAGE_NAME,
|
|
@@ -6417,9 +6822,205 @@ function provideChat(config) {
|
|
|
6417
6822
|
]);
|
|
6418
6823
|
}
|
|
6419
6824
|
|
|
6825
|
+
// SPDX-License-Identifier: MIT
|
|
6826
|
+
const defaultFromUrl = (url) => {
|
|
6827
|
+
const seg = url.split('?')[0].split('#')[0].split('/').filter(Boolean);
|
|
6828
|
+
return seg.length ? seg[seg.length - 1] : null;
|
|
6829
|
+
};
|
|
6830
|
+
const defaultToCommands = (id) => (id ? ['/', id] : ['/']);
|
|
6831
|
+
/**
|
|
6832
|
+
* Bind an app-owned `activeThreadId` signal to the URL — restore on load, stamp on change,
|
|
6833
|
+
* validate-or-redirect, with a bare URL meaning "no thread" (welcome). URL is the source of
|
|
6834
|
+
* truth; nothing is written to localStorage. Must be called in an injection context.
|
|
6835
|
+
*
|
|
6836
|
+
* @example
|
|
6837
|
+
* ```ts
|
|
6838
|
+
* export const ACTIVE_THREAD = signal<string | null>(null);
|
|
6839
|
+
* // providers: provideAgent({ threadId: ACTIVE_THREAD, onThreadId: id => ACTIVE_THREAD.set(id) })
|
|
6840
|
+
* const threads = inject(LangGraphThreadsAdapter);
|
|
6841
|
+
* injectThreadRouting({ threadId: ACTIVE_THREAD, validate: id => threads.getThread(id).then(Boolean) });
|
|
6842
|
+
* ```
|
|
6843
|
+
*/
|
|
6844
|
+
function injectThreadRouting(config) {
|
|
6845
|
+
const router = inject(Router);
|
|
6846
|
+
const fromUrl = config.threadIdFromUrl ?? defaultFromUrl;
|
|
6847
|
+
const toCommands = config.toCommands ?? defaultToCommands;
|
|
6848
|
+
const extras = config.navigationExtras ?? { queryParamsHandling: 'preserve' };
|
|
6849
|
+
const urlThreadId = toSignal(router.events.pipe(filter((e) => e instanceof NavigationEnd), map((e) => fromUrl(e.urlAfterRedirects)), startWith(fromUrl(router.url))), { initialValue: fromUrl(router.url) });
|
|
6850
|
+
// Seed the signal from the URL once.
|
|
6851
|
+
config.threadId.set(urlThreadId());
|
|
6852
|
+
// URL → signal.
|
|
6853
|
+
effect(() => {
|
|
6854
|
+
const urlId = urlThreadId();
|
|
6855
|
+
if (urlId !== untracked(() => config.threadId()))
|
|
6856
|
+
config.threadId.set(urlId);
|
|
6857
|
+
});
|
|
6858
|
+
// signal → URL.
|
|
6859
|
+
effect(() => {
|
|
6860
|
+
const id = config.threadId();
|
|
6861
|
+
const urlId = untracked(() => urlThreadId());
|
|
6862
|
+
if (id !== urlId)
|
|
6863
|
+
void router.navigate(toCommands(id), extras);
|
|
6864
|
+
});
|
|
6865
|
+
// validate stale ids → redirect to bare. Memoize the last id checked so
|
|
6866
|
+
// re-visiting the same thread (A → B → A) doesn't re-hit the backend.
|
|
6867
|
+
if (config.validate) {
|
|
6868
|
+
const validate = config.validate;
|
|
6869
|
+
let lastValidated = null;
|
|
6870
|
+
effect(() => {
|
|
6871
|
+
const id = urlThreadId();
|
|
6872
|
+
if (!id || id === lastValidated)
|
|
6873
|
+
return;
|
|
6874
|
+
lastValidated = id;
|
|
6875
|
+
void validate(id).then((ok) => {
|
|
6876
|
+
if (!ok && untracked(() => urlThreadId()) === id) {
|
|
6877
|
+
void router.navigate(toCommands(null), { ...extras, replaceUrl: true });
|
|
6878
|
+
}
|
|
6879
|
+
});
|
|
6880
|
+
});
|
|
6881
|
+
}
|
|
6882
|
+
}
|
|
6883
|
+
|
|
6420
6884
|
// SPDX-License-Identifier: MIT
|
|
6421
6885
|
const CHAT_LIFECYCLE = new InjectionToken('CHAT_LIFECYCLE');
|
|
6422
6886
|
|
|
6887
|
+
// SPDX-License-Identifier: MIT
|
|
6888
|
+
/**
|
|
6889
|
+
* Convert a Standard Schema to a JSON Schema for the model's `parameters`.
|
|
6890
|
+
* Uses Zod's converter; throws a clear error for non-Zod validators (callers
|
|
6891
|
+
* should supply a Zod schema — see the client-tools docs).
|
|
6892
|
+
*/
|
|
6893
|
+
function deriveJsonSchema(toolName, schema) {
|
|
6894
|
+
try {
|
|
6895
|
+
return toJSONSchema(schema);
|
|
6896
|
+
}
|
|
6897
|
+
catch (err) {
|
|
6898
|
+
throw new Error(`client tool "${toolName}": could not derive a JSON Schema from its schema. ` +
|
|
6899
|
+
`Use a Zod schema (recommended) or an already-JSON-Schema-compatible validator. ` +
|
|
6900
|
+
`Underlying error: ${err instanceof Error ? err.message : String(err)}`);
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6903
|
+
|
|
6904
|
+
/** Validate raw model args against a Standard Schema. */
|
|
6905
|
+
async function validateArgs(schema, args) {
|
|
6906
|
+
const res = await schema['~standard'].validate(args);
|
|
6907
|
+
if (res.issues) {
|
|
6908
|
+
return { ok: false, error: res.issues.map((i) => i.message).join('; ') };
|
|
6909
|
+
}
|
|
6910
|
+
// Cast rather than rely on discriminant narrowing: the cockpit example apps
|
|
6911
|
+
// compile this source with `strictNullChecks: false`, where the
|
|
6912
|
+
// `issues?: undefined` discriminant doesn't narrow `res` to the success type.
|
|
6913
|
+
return { ok: true, value: res.value };
|
|
6914
|
+
}
|
|
6915
|
+
/** Validate args, run the handler, and normalize the outcome to a ClientToolResult. */
|
|
6916
|
+
async function executeFunctionTool(def, rawArgs) {
|
|
6917
|
+
const v = await validateArgs(def.schema, rawArgs);
|
|
6918
|
+
if (!v.ok)
|
|
6919
|
+
return { ok: false, error: `invalid arguments: ${v.error}` };
|
|
6920
|
+
try {
|
|
6921
|
+
const value = await def.handler(v.value);
|
|
6922
|
+
return { ok: true, value };
|
|
6923
|
+
}
|
|
6924
|
+
catch (err) {
|
|
6925
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
|
|
6929
|
+
// SPDX-License-Identifier: MIT
|
|
6930
|
+
/**
|
|
6931
|
+
* Watches the agent's pending client tool calls and auto-runs FUNCTION tools,
|
|
6932
|
+
* resolving each with its result. View/ask (component) tools are handled by the
|
|
6933
|
+
* rendering layer, not here. No-op if the agent lacks the clientTools
|
|
6934
|
+
* capability. MUST be called in an injection context (sets up an effect).
|
|
6935
|
+
*/
|
|
6936
|
+
function startClientToolExecutor(agent, registry) {
|
|
6937
|
+
const cap = agent.clientTools;
|
|
6938
|
+
if (!cap)
|
|
6939
|
+
return;
|
|
6940
|
+
const inFlight = new Set();
|
|
6941
|
+
effect(() => {
|
|
6942
|
+
for (const tc of cap.pending()) {
|
|
6943
|
+
const def = registry[tc.name];
|
|
6944
|
+
if (!def || def.kind !== 'function')
|
|
6945
|
+
continue; // non-function handled elsewhere
|
|
6946
|
+
// NB: do NOT skip on `tc.status === 'complete'`. A client tool call is
|
|
6947
|
+
// marked 'complete' once its args finish streaming, yet it still has no
|
|
6948
|
+
// result and needs the browser to execute it. `pending` already excludes
|
|
6949
|
+
// calls that have a result or were resolved; `inFlight` prevents a
|
|
6950
|
+
// double-dispatch within a render cycle.
|
|
6951
|
+
if (inFlight.has(tc.id))
|
|
6952
|
+
continue;
|
|
6953
|
+
inFlight.add(tc.id);
|
|
6954
|
+
void executeFunctionTool(def, tc.args).then((result) => {
|
|
6955
|
+
cap.resolve(tc.id, result);
|
|
6956
|
+
inFlight.delete(tc.id);
|
|
6957
|
+
});
|
|
6958
|
+
}
|
|
6959
|
+
});
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6962
|
+
// SPDX-License-Identifier: MIT
|
|
6963
|
+
/** Build the catalog spec list shipped to the model. */
|
|
6964
|
+
function toClientToolSpecs(registry) {
|
|
6965
|
+
return Object.entries(registry).map(([name, def]) => ({
|
|
6966
|
+
name,
|
|
6967
|
+
description: def.description,
|
|
6968
|
+
parameters: deriveJsonSchema(name, def.schema),
|
|
6969
|
+
}));
|
|
6970
|
+
}
|
|
6971
|
+
/** Map each view/ask tool to a RenderViewEntry that carries its schema, so the
|
|
6972
|
+
* render lib can gate the real component's mount on schema-readiness (showing
|
|
6973
|
+
* the fallback skeleton while a streaming tool call's args are still
|
|
6974
|
+
* incomplete) instead of mounting a required-input component too early. */
|
|
6975
|
+
function viewComponents(registry) {
|
|
6976
|
+
const out = {};
|
|
6977
|
+
for (const [name, def] of Object.entries(registry)) {
|
|
6978
|
+
if (def.kind === 'view' || def.kind === 'ask') {
|
|
6979
|
+
out[name] = { component: def.component, schema: def.schema };
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6982
|
+
return out;
|
|
6983
|
+
}
|
|
6984
|
+
function createClientToolsCoordinator(registry) {
|
|
6985
|
+
const viewRegistry = views(viewComponents(registry));
|
|
6986
|
+
const ackedViews = new Set();
|
|
6987
|
+
return {
|
|
6988
|
+
viewRegistry,
|
|
6989
|
+
connect(agent) {
|
|
6990
|
+
const cap = agent.clientTools;
|
|
6991
|
+
if (!cap)
|
|
6992
|
+
return;
|
|
6993
|
+
cap.setCatalog(toClientToolSpecs(registry));
|
|
6994
|
+
startClientToolExecutor(agent, registry); // function tools
|
|
6995
|
+
// Auto-ack `view` tools: they render but produce no user value.
|
|
6996
|
+
effect(() => {
|
|
6997
|
+
for (const tc of cap.pending()) {
|
|
6998
|
+
const def = registry[tc.name];
|
|
6999
|
+
if (!def || def.kind !== 'view')
|
|
7000
|
+
continue;
|
|
7001
|
+
if (ackedViews.has(tc.id))
|
|
7002
|
+
continue;
|
|
7003
|
+
ackedViews.add(tc.id);
|
|
7004
|
+
cap.resolve(tc.id, { ok: true, value: { shown: true } });
|
|
7005
|
+
}
|
|
7006
|
+
});
|
|
7007
|
+
},
|
|
7008
|
+
handleRenderEvent(agent, event) {
|
|
7009
|
+
if (event.type !== 'result')
|
|
7010
|
+
return;
|
|
7011
|
+
const cap = agent.clientTools;
|
|
7012
|
+
if (!cap)
|
|
7013
|
+
return;
|
|
7014
|
+
// elementKey is the tool NAME in the tool-view spec; resolve the pending `ask`
|
|
7015
|
+
// call for that name with the component's emitted value.
|
|
7016
|
+
const name = event.elementKey;
|
|
7017
|
+
const pending = cap.pending().find((tc) => tc.name === name && registry[tc.name]?.kind === 'ask');
|
|
7018
|
+
if (pending)
|
|
7019
|
+
cap.resolve(pending.id, { ok: true, value: event.value });
|
|
7020
|
+
},
|
|
7021
|
+
};
|
|
7022
|
+
}
|
|
7023
|
+
|
|
6423
7024
|
const RESERVED_PROP_KEYS = new Set(['child', 'children', 'action', 'tabItems', 'entryPointChild', 'contentChild']);
|
|
6424
7025
|
/** Pull the (single) component-type key + its props from a v1 ComponentDef wrapper. */
|
|
6425
7026
|
function unwrapComponentDef(def) {
|
|
@@ -6485,9 +7086,8 @@ function surfaceToSpec(surface) {
|
|
|
6485
7086
|
// snapshot taken at conversion time and never reflects user
|
|
6486
7087
|
// input writes back into the store. The `_bindings` map below
|
|
6487
7088
|
// tells the catalog component which prop names map to which
|
|
6488
|
-
// paths so its
|
|
6489
|
-
//
|
|
6490
|
-
// render-element's emitFn intercepts.
|
|
7089
|
+
// paths so its injectRenderHost().set(path, value) call can
|
|
7090
|
+
// write the typed value back to the render state store.
|
|
6491
7091
|
const path = value.path;
|
|
6492
7092
|
bindings[key] = path;
|
|
6493
7093
|
resolvedProps[key] = { $bindState: path };
|
|
@@ -7926,6 +8526,14 @@ function isPinned(scrollHeight, scrollTop, clientHeight, tolerance = 150) {
|
|
|
7926
8526
|
class ChatComponent {
|
|
7927
8527
|
agent = input.required(...(ngDevMode ? [{ debugName: "agent" }] : []));
|
|
7928
8528
|
views = input(undefined, ...(ngDevMode ? [{ debugName: "views" }] : []));
|
|
8529
|
+
/**
|
|
8530
|
+
* Client-declared tools (`view`/`ask`/`function`) the model may call. When
|
|
8531
|
+
* provided, a coordinator ships their catalog to the agent, runs `function`
|
|
8532
|
+
* tools in the browser, and renders/resolves `view`/`ask` tools through the
|
|
8533
|
+
* same tool-views pipeline as `views`. Additive — leave undefined for the
|
|
8534
|
+
* classic server-tools-only experience.
|
|
8535
|
+
*/
|
|
8536
|
+
clientTools = input(undefined, ...(ngDevMode ? [{ debugName: "clientTools" }] : []));
|
|
7929
8537
|
store = input(undefined, ...(ngDevMode ? [{ debugName: "store" }] : []));
|
|
7930
8538
|
handlers = input({}, ...(ngDevMode ? [{ debugName: "handlers" }] : []));
|
|
7931
8539
|
threads = input([], ...(ngDevMode ? [{ debugName: "threads" }] : []));
|
|
@@ -7982,18 +8590,45 @@ class ChatComponent {
|
|
|
7982
8590
|
const explicit = this.store();
|
|
7983
8591
|
if (explicit)
|
|
7984
8592
|
return explicit;
|
|
7985
|
-
|
|
8593
|
+
// A render store is needed whenever there's any view registry to render
|
|
8594
|
+
// through — user-supplied `views()` OR client-tool view/ask components.
|
|
8595
|
+
if (this.effectiveViews())
|
|
7986
8596
|
return this._internalStore;
|
|
7987
8597
|
return undefined;
|
|
7988
8598
|
}, ...(ngDevMode ? [{ debugName: "resolvedStore" }] : []));
|
|
8599
|
+
/**
|
|
8600
|
+
* Lazily-built client-tools coordinator, memoized on the `clientTools`
|
|
8601
|
+
* registry input. Undefined when no client tools are declared. The
|
|
8602
|
+
* coordinator owns the catalog/executor wiring and the view/ask render
|
|
8603
|
+
* registry; the composition merges and connects it below.
|
|
8604
|
+
*/
|
|
8605
|
+
coordinator = computed(() => {
|
|
8606
|
+
const reg = this.clientTools();
|
|
8607
|
+
return reg ? createClientToolsCoordinator(reg) : undefined;
|
|
8608
|
+
}, ...(ngDevMode ? [{ debugName: "coordinator" }] : []));
|
|
8609
|
+
/**
|
|
8610
|
+
* The view registry actually used for rendering tool-views and for
|
|
8611
|
+
* excluding view-backed tool names from default tool-call cards. Merges
|
|
8612
|
+
* the coordinator's `view`/`ask` components (keyed by tool name) into the
|
|
8613
|
+
* user-supplied `views()` so client-declared component tools render through
|
|
8614
|
+
* the same pipeline. Falls back to `views()` when no client tools exist.
|
|
8615
|
+
*/
|
|
8616
|
+
effectiveViews = computed(() => {
|
|
8617
|
+
const base = this.views();
|
|
8618
|
+
const coord = this.coordinator();
|
|
8619
|
+
if (!coord)
|
|
8620
|
+
return base;
|
|
8621
|
+
return base ? withViews(base, coord.viewRegistry) : coord.viewRegistry;
|
|
8622
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveViews" }] : []));
|
|
7989
8623
|
renderRegistry = computed(() => {
|
|
7990
8624
|
const v = this.views();
|
|
7991
8625
|
return v ? toRenderRegistry(v) : undefined;
|
|
7992
8626
|
}, ...(ngDevMode ? [{ debugName: "renderRegistry" }] : []));
|
|
7993
|
-
/** Tool names that have a registered view (keys of the
|
|
7994
|
-
*
|
|
7995
|
-
* tool-
|
|
7996
|
-
|
|
8627
|
+
/** Tool names that have a registered view (keys of the effective view
|
|
8628
|
+
* registry, including client-declared view/ask tools). These render as
|
|
8629
|
+
* inline tool-views and are excluded from the default tool-call card so
|
|
8630
|
+
* they don't render twice. */
|
|
8631
|
+
viewToolNames = computed(() => Object.keys(this.effectiveViews() ?? {}), ...(ngDevMode ? [{ debugName: "viewToolNames" }] : []));
|
|
7997
8632
|
/** Union of GenUI dispatcher tool names and registered view tool names. */
|
|
7998
8633
|
excludedToolNames = computed(() => [
|
|
7999
8634
|
...this.genuiToolNames(),
|
|
@@ -8040,6 +8675,7 @@ class ChatComponent {
|
|
|
8040
8675
|
}
|
|
8041
8676
|
classifiers = new Map();
|
|
8042
8677
|
destroyRef = inject(DestroyRef);
|
|
8678
|
+
injector = inject(Injector);
|
|
8043
8679
|
// Resolved against the component's own `providers` in normal use. The fallback
|
|
8044
8680
|
// is for tests that construct ChatComponent via `new` inside a bare injection
|
|
8045
8681
|
// context (no element injector, so component-level providers are skipped).
|
|
@@ -8261,6 +8897,35 @@ class ChatComponent {
|
|
|
8261
8897
|
}
|
|
8262
8898
|
this.partialEventsLastIndex = events.length;
|
|
8263
8899
|
});
|
|
8900
|
+
// Connect the client-tools coordinator to the agent. connect() ships the
|
|
8901
|
+
// tool catalog, starts the function-tool executor, and installs the view
|
|
8902
|
+
// auto-ack effect. Those installs create effect()s of their own, which
|
|
8903
|
+
// Angular forbids from *within* a running effect (NG0602). So this effect
|
|
8904
|
+
// only detects readiness (both coordinator + agent present) and defers the
|
|
8905
|
+
// actual connect() to a microtask that runs OUTSIDE the reactive context,
|
|
8906
|
+
// re-entering the component's injection context so the coordinator's
|
|
8907
|
+
// effects bind to this component's lifecycle. `connected` guards against
|
|
8908
|
+
// re-running per coordinator identity (a new clientTools registry yields a
|
|
8909
|
+
// new coordinator and re-connects; the old one's effects are abandoned).
|
|
8910
|
+
let connected;
|
|
8911
|
+
effect(() => {
|
|
8912
|
+
const coord = this.coordinator();
|
|
8913
|
+
let agentRef;
|
|
8914
|
+
try {
|
|
8915
|
+
agentRef = this.agent();
|
|
8916
|
+
}
|
|
8917
|
+
catch {
|
|
8918
|
+
return;
|
|
8919
|
+
}
|
|
8920
|
+
if (!coord || !agentRef)
|
|
8921
|
+
return;
|
|
8922
|
+
if (connected === coord)
|
|
8923
|
+
return;
|
|
8924
|
+
connected = coord;
|
|
8925
|
+
queueMicrotask(() => {
|
|
8926
|
+
runInInjectionContext(this.injector, () => coord.connect(agentRef));
|
|
8927
|
+
});
|
|
8928
|
+
});
|
|
8264
8929
|
effect(() => {
|
|
8265
8930
|
// janitor: drop classifiers for messages no longer in the agent's list
|
|
8266
8931
|
let liveIds;
|
|
@@ -8478,6 +9143,25 @@ class ChatComponent {
|
|
|
8478
9143
|
onSpecEvent(event, messageIndex) {
|
|
8479
9144
|
this.renderEvent.emit({ messageIndex, event });
|
|
8480
9145
|
}
|
|
9146
|
+
/**
|
|
9147
|
+
* Forwards a render event bubbled up from a `<chat-tool-views>` component
|
|
9148
|
+
* (a client-declared `view`/`ask` tool's rendered UI) to the client-tools
|
|
9149
|
+
* coordinator. The coordinator resolves the matching pending `ask` tool call
|
|
9150
|
+
* when the event is a `result`. No-op when no client tools are wired.
|
|
9151
|
+
*/
|
|
9152
|
+
onClientToolEvent(event) {
|
|
9153
|
+
const coord = this.coordinator();
|
|
9154
|
+
if (!coord)
|
|
9155
|
+
return;
|
|
9156
|
+
let agentRef;
|
|
9157
|
+
try {
|
|
9158
|
+
agentRef = this.agent();
|
|
9159
|
+
}
|
|
9160
|
+
catch {
|
|
9161
|
+
return;
|
|
9162
|
+
}
|
|
9163
|
+
coord.handleRenderEvent(agentRef, event);
|
|
9164
|
+
}
|
|
8481
9165
|
onA2uiAction(message) {
|
|
8482
9166
|
void this.agent().submit({ message: JSON.stringify(message) });
|
|
8483
9167
|
}
|
|
@@ -8498,7 +9182,7 @@ class ChatComponent {
|
|
|
8498
9182
|
this.messageCopy.emit({ messageIndex: idx, content });
|
|
8499
9183
|
}
|
|
8500
9184
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8501
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatComponent, isStandalone: true, selector: "chat", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null }, threads: { classPropertyName: "threads", publicName: "threads", isSignal: true, isRequired: false, transformFunction: null }, activeThreadId: { classPropertyName: "activeThreadId", publicName: "activeThreadId", isSignal: true, isRequired: false, transformFunction: null }, welcomeDisabled: { classPropertyName: "welcomeDisabled", publicName: "welcomeDisabled", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, modelPickerPlaceholder: { classPropertyName: "modelPickerPlaceholder", publicName: "modelPickerPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, genuiToolNames: { classPropertyName: "genuiToolNames", publicName: "genuiToolNames", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", threadSelected: "threadSelected", renderEvent: "renderEvent", regenerate: "regenerate", rate: "rate", messageCopy: "messageCopy" }, providers: [
|
|
9185
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatComponent, isStandalone: true, selector: "chat", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, clientTools: { classPropertyName: "clientTools", publicName: "clientTools", isSignal: true, isRequired: false, transformFunction: null }, store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: false, transformFunction: null }, handlers: { classPropertyName: "handlers", publicName: "handlers", isSignal: true, isRequired: false, transformFunction: null }, threads: { classPropertyName: "threads", publicName: "threads", isSignal: true, isRequired: false, transformFunction: null }, activeThreadId: { classPropertyName: "activeThreadId", publicName: "activeThreadId", isSignal: true, isRequired: false, transformFunction: null }, welcomeDisabled: { classPropertyName: "welcomeDisabled", publicName: "welcomeDisabled", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, modelPickerPlaceholder: { classPropertyName: "modelPickerPlaceholder", publicName: "modelPickerPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, genuiToolNames: { classPropertyName: "genuiToolNames", publicName: "genuiToolNames", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", threadSelected: "threadSelected", renderEvent: "renderEvent", regenerate: "regenerate", rate: "rate", messageCopy: "messageCopy" }, providers: [
|
|
8502
9186
|
{ provide: CHAT_LIFECYCLE, useFactory: createChatLifecycle },
|
|
8503
9187
|
], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
8504
9188
|
@if (showWelcome()) {
|
|
@@ -8563,19 +9247,26 @@ class ChatComponent {
|
|
|
8563
9247
|
<chat-tool-views
|
|
8564
9248
|
[agent]="agent()"
|
|
8565
9249
|
[message]="message"
|
|
8566
|
-
[views]="
|
|
9250
|
+
[views]="effectiveViews()"
|
|
8567
9251
|
[store]="resolvedStore()"
|
|
8568
9252
|
[handlers]="handlers()"
|
|
9253
|
+
(events)="onClientToolEvent($event)"
|
|
8569
9254
|
/>
|
|
8570
9255
|
<chat-subagents [agent]="agent()" />
|
|
8571
9256
|
@if (classified.markdown(); as md) {
|
|
8572
9257
|
<chat-streaming-md [content]="md" [streaming]="agent().isLoading() && i === agent().messages().length - 1" />
|
|
8573
9258
|
}
|
|
8574
9259
|
@if (classified.spec(); as spec) {
|
|
9260
|
+
<!-- Pass ONLY the explicit consumer store (may be
|
|
9261
|
+
undefined) — never the conversation-wide internal
|
|
9262
|
+
fallback. Without a consumer store, render-spec
|
|
9263
|
+
self-seeds a per-instance store from spec.state so
|
|
9264
|
+
same-key dashboards across messages stay isolated
|
|
9265
|
+
(a2ui parity). -->
|
|
8575
9266
|
<chat-generative-ui
|
|
8576
9267
|
[spec]="spec"
|
|
8577
9268
|
[registry]="renderRegistry()"
|
|
8578
|
-
[store]="
|
|
9269
|
+
[store]="store()"
|
|
8579
9270
|
[handlers]="handlers()"
|
|
8580
9271
|
[loading]="agent().isLoading()"
|
|
8581
9272
|
(events)="onSpecEvent($event, i)"
|
|
@@ -8649,7 +9340,7 @@ class ChatComponent {
|
|
|
8649
9340
|
</div>
|
|
8650
9341
|
</div>
|
|
8651
9342
|
}
|
|
8652
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;max-height:100%;overflow:hidden;background:var(--ngaf-chat-bg)}:host>chat-welcome{display:flex;flex:1 1 auto;width:100%}.chat-shell{display:flex;flex:1;min-height:0;overflow:hidden}.chat-shell__sidebar{width:240px;flex-shrink:0;border-right:1px solid var(--ngaf-chat-separator);background:var(--ngaf-chat-surface-alt);overflow-y:auto;display:none}@media(min-width:768px){.chat-shell__sidebar{display:block}}.chat-shell__main{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}.chat-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:60px 20px;color:var(--ngaf-chat-text-muted);text-align:center;flex:1;min-height:0}.chat-empty[hidden]{display:none}.chat-empty__title{font-size:1.125rem;font-weight:500;color:var(--ngaf-chat-text);margin:0}.chat-empty__sub{margin:0;font-size:var(--ngaf-chat-font-size-sm)}.chat-scroll{flex:1;min-height:0;overflow-y:auto;padding-top:var(--ngaf-chat-edge-pad)}.chat-scroll::-webkit-scrollbar{width:6px}.chat-scroll::-webkit-scrollbar-thumb{background:var(--ngaf-chat-separator);border-radius:10px}[chatFooter]{padding-bottom:var(--ngaf-chat-edge-pad)}.chat-footer-wrap{position:relative}\n"], dependencies: [{ kind: "component", type: ChatWindowComponent, selector: "chat-window" }, { kind: "component", type: ChatMessageListComponent, selector: "chat-message-list", inputs: ["agent"] }, { kind: "directive", type: MessageTemplateDirective, selector: "ng-template[chatMessageTemplate]", inputs: ["chatMessageTemplate"] }, { kind: "component", type: ChatMessageComponent, selector: "chat-message", inputs: ["role", "current", "streaming", "prevRole", "message"] }, { kind: "component", type: ChatInputComponent, selector: "chat-input", inputs: ["agent", "submitOnEnter", "placeholder", "showStopButton"], outputs: ["submitted", "stopped"] }, { kind: "component", type: ChatTypingIndicatorComponent, selector: "chat-typing-indicator", inputs: ["agent"] }, { kind: "component", type: ChatErrorComponent, selector: "chat-error", inputs: ["agent"] }, { kind: "component", type: ChatThreadListComponent, selector: "chat-thread-list", inputs: ["threads", "activeThreadId", "showNewThreadButton", "actions", "mode", "projects"], outputs: ["threadSelected", "newThreadRequested"] }, { kind: "component", type: ChatGenerativeUiComponent, selector: "chat-generative-ui", inputs: ["spec", "registry", "store", "handlers", "loading"], outputs: ["events"] }, { kind: "component", type: ChatStreamingMdComponent, selector: "chat-streaming-md", inputs: ["content", "streaming", "viewRegistry"] }, { kind: "component", type: ChatToolCallsComponent, selector: "chat-tool-calls", inputs: ["agent", "message", "grouping", "groupSummary", "excludeToolNames"] }, { kind: "component", type: ChatToolViewsComponent, selector: "chat-tool-views", inputs: ["agent", "message", "views", "store", "handlers"] }, { kind: "component", type: ChatSubagentsComponent, selector: "chat-subagents", inputs: ["agent"] }, { kind: "component", type: A2uiSurfaceComponent, selector: "a2ui-surface", inputs: ["surface", "state", "catalog", "handlers", "surfaceFallback"], outputs: ["events", "action"] }, { kind: "component", type: ChatMessageActionsComponent, selector: "chat-message-actions", inputs: ["content", "disabled"], outputs: ["regenerate", "rate", "contentCopied"] }, { kind: "component", type: ChatWelcomeComponent, selector: "chat-welcome" }, { kind: "component", type: ChatSelectComponent, selector: "chat-select", inputs: ["options", "value", "placeholder", "disabled", "menuLabel"], outputs: ["valueChange"] }, { kind: "component", type: ChatReasoningComponent, selector: "chat-reasoning", inputs: ["content", "isStreaming", "durationMs", "label", "defaultExpanded"] }, { kind: "component", type: ChatScrollBubbleComponent, selector: "chat-scroll-bubble", inputs: ["mode"], outputs: ["clicked"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9343
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;max-height:100%;overflow:hidden;background:var(--ngaf-chat-bg)}:host>chat-welcome{display:flex;flex:1 1 auto;width:100%}.chat-shell{display:flex;flex:1;min-height:0;overflow:hidden}.chat-shell__sidebar{width:240px;flex-shrink:0;border-right:1px solid var(--ngaf-chat-separator);background:var(--ngaf-chat-surface-alt);overflow-y:auto;display:none}@media(min-width:768px){.chat-shell__sidebar{display:block}}.chat-shell__main{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}.chat-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:60px 20px;color:var(--ngaf-chat-text-muted);text-align:center;flex:1;min-height:0}.chat-empty[hidden]{display:none}.chat-empty__title{font-size:1.125rem;font-weight:500;color:var(--ngaf-chat-text);margin:0}.chat-empty__sub{margin:0;font-size:var(--ngaf-chat-font-size-sm)}.chat-scroll{flex:1;min-height:0;overflow-y:auto;padding-top:var(--ngaf-chat-edge-pad)}.chat-scroll::-webkit-scrollbar{width:6px}.chat-scroll::-webkit-scrollbar-thumb{background:var(--ngaf-chat-separator);border-radius:10px}[chatFooter]{padding-bottom:var(--ngaf-chat-edge-pad)}.chat-footer-wrap{position:relative}\n"], dependencies: [{ kind: "component", type: ChatWindowComponent, selector: "chat-window" }, { kind: "component", type: ChatMessageListComponent, selector: "chat-message-list", inputs: ["agent"] }, { kind: "directive", type: MessageTemplateDirective, selector: "ng-template[chatMessageTemplate]", inputs: ["chatMessageTemplate"] }, { kind: "component", type: ChatMessageComponent, selector: "chat-message", inputs: ["role", "current", "streaming", "prevRole", "message"] }, { kind: "component", type: ChatInputComponent, selector: "chat-input", inputs: ["agent", "submitOnEnter", "placeholder", "showStopButton"], outputs: ["submitted", "stopped"] }, { kind: "component", type: ChatTypingIndicatorComponent, selector: "chat-typing-indicator", inputs: ["agent"] }, { kind: "component", type: ChatErrorComponent, selector: "chat-error", inputs: ["agent"] }, { kind: "component", type: ChatThreadListComponent, selector: "chat-thread-list", inputs: ["threads", "activeThreadId", "showNewThreadButton", "actions", "mode", "projects"], outputs: ["threadSelected", "newThreadRequested"] }, { kind: "component", type: ChatGenerativeUiComponent, selector: "chat-generative-ui", inputs: ["spec", "registry", "store", "handlers", "loading"], outputs: ["events"] }, { kind: "component", type: ChatStreamingMdComponent, selector: "chat-streaming-md", inputs: ["content", "streaming", "viewRegistry"] }, { kind: "component", type: ChatToolCallsComponent, selector: "chat-tool-calls", inputs: ["agent", "message", "grouping", "groupSummary", "excludeToolNames"] }, { kind: "component", type: ChatToolViewsComponent, selector: "chat-tool-views", inputs: ["agent", "message", "views", "store", "handlers"], outputs: ["events"] }, { kind: "component", type: ChatSubagentsComponent, selector: "chat-subagents", inputs: ["agent"] }, { kind: "component", type: A2uiSurfaceComponent, selector: "a2ui-surface", inputs: ["surface", "state", "catalog", "handlers", "surfaceFallback"], outputs: ["events", "action"] }, { kind: "component", type: ChatMessageActionsComponent, selector: "chat-message-actions", inputs: ["content", "disabled"], outputs: ["regenerate", "rate", "contentCopied"] }, { kind: "component", type: ChatWelcomeComponent, selector: "chat-welcome" }, { kind: "component", type: ChatSelectComponent, selector: "chat-select", inputs: ["options", "value", "placeholder", "disabled", "menuLabel"], outputs: ["valueChange"] }, { kind: "component", type: ChatReasoningComponent, selector: "chat-reasoning", inputs: ["content", "isStreaming", "durationMs", "label", "defaultExpanded"] }, { kind: "component", type: ChatScrollBubbleComponent, selector: "chat-scroll-bubble", inputs: ["mode"], outputs: ["clicked"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8653
9344
|
}
|
|
8654
9345
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
8655
9346
|
type: Component,
|
|
@@ -8726,19 +9417,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
8726
9417
|
<chat-tool-views
|
|
8727
9418
|
[agent]="agent()"
|
|
8728
9419
|
[message]="message"
|
|
8729
|
-
[views]="
|
|
9420
|
+
[views]="effectiveViews()"
|
|
8730
9421
|
[store]="resolvedStore()"
|
|
8731
9422
|
[handlers]="handlers()"
|
|
9423
|
+
(events)="onClientToolEvent($event)"
|
|
8732
9424
|
/>
|
|
8733
9425
|
<chat-subagents [agent]="agent()" />
|
|
8734
9426
|
@if (classified.markdown(); as md) {
|
|
8735
9427
|
<chat-streaming-md [content]="md" [streaming]="agent().isLoading() && i === agent().messages().length - 1" />
|
|
8736
9428
|
}
|
|
8737
9429
|
@if (classified.spec(); as spec) {
|
|
9430
|
+
<!-- Pass ONLY the explicit consumer store (may be
|
|
9431
|
+
undefined) — never the conversation-wide internal
|
|
9432
|
+
fallback. Without a consumer store, render-spec
|
|
9433
|
+
self-seeds a per-instance store from spec.state so
|
|
9434
|
+
same-key dashboards across messages stay isolated
|
|
9435
|
+
(a2ui parity). -->
|
|
8738
9436
|
<chat-generative-ui
|
|
8739
9437
|
[spec]="spec"
|
|
8740
9438
|
[registry]="renderRegistry()"
|
|
8741
|
-
[store]="
|
|
9439
|
+
[store]="store()"
|
|
8742
9440
|
[handlers]="handlers()"
|
|
8743
9441
|
[loading]="agent().isLoading()"
|
|
8744
9442
|
(events)="onSpecEvent($event, i)"
|
|
@@ -8813,7 +9511,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
8813
9511
|
</div>
|
|
8814
9512
|
}
|
|
8815
9513
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;max-height:100%;overflow:hidden;background:var(--ngaf-chat-bg)}:host>chat-welcome{display:flex;flex:1 1 auto;width:100%}.chat-shell{display:flex;flex:1;min-height:0;overflow:hidden}.chat-shell__sidebar{width:240px;flex-shrink:0;border-right:1px solid var(--ngaf-chat-separator);background:var(--ngaf-chat-surface-alt);overflow-y:auto;display:none}@media(min-width:768px){.chat-shell__sidebar{display:block}}.chat-shell__main{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}.chat-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:60px 20px;color:var(--ngaf-chat-text-muted);text-align:center;flex:1;min-height:0}.chat-empty[hidden]{display:none}.chat-empty__title{font-size:1.125rem;font-weight:500;color:var(--ngaf-chat-text);margin:0}.chat-empty__sub{margin:0;font-size:var(--ngaf-chat-font-size-sm)}.chat-scroll{flex:1;min-height:0;overflow-y:auto;padding-top:var(--ngaf-chat-edge-pad)}.chat-scroll::-webkit-scrollbar{width:6px}.chat-scroll::-webkit-scrollbar-thumb{background:var(--ngaf-chat-separator);border-radius:10px}[chatFooter]{padding-bottom:var(--ngaf-chat-edge-pad)}.chat-footer-wrap{position:relative}\n"] }]
|
|
8816
|
-
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }], threads: [{ type: i0.Input, args: [{ isSignal: true, alias: "threads", required: false }] }], activeThreadId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeThreadId", required: false }] }], welcomeDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "welcomeDisabled", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], modelPickerPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelPickerPlaceholder", required: false }] }], genuiToolNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "genuiToolNames", required: false }] }], threadSelected: [{ type: i0.Output, args: ["threadSelected"] }], renderEvent: [{ type: i0.Output, args: ["renderEvent"] }], regenerate: [{ type: i0.Output, args: ["regenerate"] }], rate: [{ type: i0.Output, args: ["rate"] }], messageCopy: [{ type: i0.Output, args: ["messageCopy"] }], scrollContainer: [{ type: i0.ViewChild, args: ['scrollContainer', { isSignal: true }] }] } });
|
|
9514
|
+
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], clientTools: [{ type: i0.Input, args: [{ isSignal: true, alias: "clientTools", required: false }] }], store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: false }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }], threads: [{ type: i0.Input, args: [{ isSignal: true, alias: "threads", required: false }] }], activeThreadId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeThreadId", required: false }] }], welcomeDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "welcomeDisabled", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], modelPickerPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelPickerPlaceholder", required: false }] }], genuiToolNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "genuiToolNames", required: false }] }], threadSelected: [{ type: i0.Output, args: ["threadSelected"] }], renderEvent: [{ type: i0.Output, args: ["renderEvent"] }], regenerate: [{ type: i0.Output, args: ["regenerate"] }], rate: [{ type: i0.Output, args: ["rate"] }], messageCopy: [{ type: i0.Output, args: ["messageCopy"] }], scrollContainer: [{ type: i0.ViewChild, args: ['scrollContainer', { isSignal: true }] }] } });
|
|
8817
9515
|
|
|
8818
9516
|
// libs/chat/src/lib/compositions/chat-popup/chat-popup.component.ts
|
|
8819
9517
|
// SPDX-License-Identifier: MIT
|
|
@@ -8823,6 +9521,8 @@ class ChatPopupComponent {
|
|
|
8823
9521
|
* messages classified as A2UI parse correctly but never mount a
|
|
8824
9522
|
* surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
|
|
8825
9523
|
views = input(undefined, ...(ngDevMode ? [{ debugName: "views" }] : []));
|
|
9524
|
+
/** Frontend-declared client tools forwarded to the inner `<chat>`. */
|
|
9525
|
+
clientTools = input(undefined, ...(ngDevMode ? [{ debugName: "clientTools" }] : []));
|
|
8826
9526
|
/** Forwarded to the inner <chat>. When non-empty, a model picker pill
|
|
8827
9527
|
* renders in the chat-input chrome. */
|
|
8828
9528
|
modelOptions = input([], ...(ngDevMode ? [{ debugName: "modelOptions" }] : []));
|
|
@@ -8877,7 +9577,7 @@ class ChatPopupComponent {
|
|
|
8877
9577
|
openWindow() { this.open.set(true); }
|
|
8878
9578
|
closeWindow() { this.open.set(false); }
|
|
8879
9579
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8880
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatPopupComponent, isStandalone: true, selector: "chat-popup", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", open: "openChange" }, ngImport: i0, template: `
|
|
9580
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatPopupComponent, isStandalone: true, selector: "chat-popup", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, clientTools: { classPropertyName: "clientTools", publicName: "clientTools", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", open: "openChange" }, ngImport: i0, template: `
|
|
8881
9581
|
<div class="chat-popup__launcher">
|
|
8882
9582
|
<chat-launcher-button (clicked)="toggle()" />
|
|
8883
9583
|
</div>
|
|
@@ -8888,6 +9588,7 @@ class ChatPopupComponent {
|
|
|
8888
9588
|
<chat
|
|
8889
9589
|
[agent]="agent()"
|
|
8890
9590
|
[views]="views()"
|
|
9591
|
+
[clientTools]="clientTools()"
|
|
8891
9592
|
[modelOptions]="modelOptions()"
|
|
8892
9593
|
[showModelPicker]="showModelPicker()"
|
|
8893
9594
|
[selectedModel]="selectedModel()"
|
|
@@ -8897,7 +9598,7 @@ class ChatPopupComponent {
|
|
|
8897
9598
|
<ng-content select="[chatWelcomeSuggestions]" chatWelcomeSuggestions />
|
|
8898
9599
|
</chat>
|
|
8899
9600
|
</div>
|
|
8900
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{position:fixed;bottom:1rem;right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30)}.chat-popup__launcher{position:relative}.chat-popup__window{position:fixed;bottom:5rem;right:1rem;width:24rem;height:600px;max-height:calc(100vh - 6rem);background:var(--ngaf-chat-bg);border:1px solid var(--ngaf-chat-separator);border-radius:.75rem;box-shadow:0 5px 40px #00000029;transform-origin:bottom right;transform:scale(.95) translateY(20px);opacity:0;pointer-events:none;transition:transform .2s ease-out,opacity .1s ease-out;overflow:hidden;display:flex;flex-direction:column}.chat-popup__window[data-open=true]{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}@media(max-width:640px){.chat-popup__window{inset:0 auto auto 0;width:100vw;height:100vh;max-height:100vh;border-radius:0}}.chat-popup__close{position:absolute;top:8px;right:8px;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;z-index:1;display:flex;align-items:center;justify-content:center}.chat-popup__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}\n"], dependencies: [{ kind: "component", type: ChatComponent, selector: "chat", inputs: ["agent", "views", "store", "handlers", "threads", "activeThreadId", "welcomeDisabled", "modelOptions", "showModelPicker", "selectedModel", "modelPickerPlaceholder", "genuiToolNames"], outputs: ["selectedModelChange", "threadSelected", "renderEvent", "regenerate", "rate", "messageCopy"] }, { kind: "component", type: ChatLauncherButtonComponent, selector: "chat-launcher-button", outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9601
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{position:fixed;bottom:1rem;right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30)}.chat-popup__launcher{position:relative}.chat-popup__window{position:fixed;bottom:5rem;right:1rem;width:24rem;height:600px;max-height:calc(100vh - 6rem);background:var(--ngaf-chat-bg);border:1px solid var(--ngaf-chat-separator);border-radius:.75rem;box-shadow:0 5px 40px #00000029;transform-origin:bottom right;transform:scale(.95) translateY(20px);opacity:0;pointer-events:none;transition:transform .2s ease-out,opacity .1s ease-out;overflow:hidden;display:flex;flex-direction:column}.chat-popup__window[data-open=true]{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}@media(max-width:640px){.chat-popup__window{inset:0 auto auto 0;width:100vw;height:100vh;max-height:100vh;border-radius:0}}.chat-popup__close{position:absolute;top:8px;right:8px;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;z-index:1;display:flex;align-items:center;justify-content:center}.chat-popup__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}\n"], dependencies: [{ kind: "component", type: ChatComponent, selector: "chat", inputs: ["agent", "views", "clientTools", "store", "handlers", "threads", "activeThreadId", "welcomeDisabled", "modelOptions", "showModelPicker", "selectedModel", "modelPickerPlaceholder", "genuiToolNames"], outputs: ["selectedModelChange", "threadSelected", "renderEvent", "regenerate", "rate", "messageCopy"] }, { kind: "component", type: ChatLauncherButtonComponent, selector: "chat-launcher-button", outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8901
9602
|
}
|
|
8902
9603
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatPopupComponent, decorators: [{
|
|
8903
9604
|
type: Component,
|
|
@@ -8912,6 +9613,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
8912
9613
|
<chat
|
|
8913
9614
|
[agent]="agent()"
|
|
8914
9615
|
[views]="views()"
|
|
9616
|
+
[clientTools]="clientTools()"
|
|
8915
9617
|
[modelOptions]="modelOptions()"
|
|
8916
9618
|
[showModelPicker]="showModelPicker()"
|
|
8917
9619
|
[selectedModel]="selectedModel()"
|
|
@@ -8922,7 +9624,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
8922
9624
|
</chat>
|
|
8923
9625
|
</div>
|
|
8924
9626
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{position:fixed;bottom:1rem;right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30)}.chat-popup__launcher{position:relative}.chat-popup__window{position:fixed;bottom:5rem;right:1rem;width:24rem;height:600px;max-height:calc(100vh - 6rem);background:var(--ngaf-chat-bg);border:1px solid var(--ngaf-chat-separator);border-radius:.75rem;box-shadow:0 5px 40px #00000029;transform-origin:bottom right;transform:scale(.95) translateY(20px);opacity:0;pointer-events:none;transition:transform .2s ease-out,opacity .1s ease-out;overflow:hidden;display:flex;flex-direction:column}.chat-popup__window[data-open=true]{transform:scale(1) translateY(0);opacity:1;pointer-events:auto}@media(max-width:640px){.chat-popup__window{inset:0 auto auto 0;width:100vw;height:100vh;max-height:100vh;border-radius:0}}.chat-popup__close{position:absolute;top:8px;right:8px;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;z-index:1;display:flex;align-items:center;justify-content:center}.chat-popup__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}\n"] }]
|
|
8925
|
-
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }] } });
|
|
9627
|
+
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], clientTools: [{ type: i0.Input, args: [{ isSignal: true, alias: "clientTools", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }] } });
|
|
8926
9628
|
|
|
8927
9629
|
// libs/chat/src/lib/compositions/chat-sidebar/chat-sidebar.component.ts
|
|
8928
9630
|
// SPDX-License-Identifier: MIT
|
|
@@ -8932,6 +9634,8 @@ class ChatSidebarComponent {
|
|
|
8932
9634
|
* messages classified as A2UI parse correctly but never mount a
|
|
8933
9635
|
* surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
|
|
8934
9636
|
views = input(undefined, ...(ngDevMode ? [{ debugName: "views" }] : []));
|
|
9637
|
+
/** Frontend-declared client tools forwarded to the inner `<chat>`. */
|
|
9638
|
+
clientTools = input(undefined, ...(ngDevMode ? [{ debugName: "clientTools" }] : []));
|
|
8935
9639
|
/** Forwarded to the inner <chat>. When non-empty, a model picker pill
|
|
8936
9640
|
* renders in the chat-input chrome. */
|
|
8937
9641
|
modelOptions = input([], ...(ngDevMode ? [{ debugName: "modelOptions" }] : []));
|
|
@@ -8985,7 +9689,7 @@ class ChatSidebarComponent {
|
|
|
8985
9689
|
openWindow() { this.open.set(true); }
|
|
8986
9690
|
closeWindow() { this.open.set(false); }
|
|
8987
9691
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8988
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatSidebarComponent, isStandalone: true, selector: "chat-sidebar", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, pushContent: { classPropertyName: "pushContent", publicName: "pushContent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", open: "openChange" }, host: { properties: { "attr.data-push": "pushContent() ? \"true\" : \"false\"", "attr.data-open": "open() ? \"true\" : \"false\"" } }, ngImport: i0, template: `
|
|
9692
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: ChatSidebarComponent, isStandalone: true, selector: "chat-sidebar", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, views: { classPropertyName: "views", publicName: "views", isSignal: true, isRequired: false, transformFunction: null }, clientTools: { classPropertyName: "clientTools", publicName: "clientTools", isSignal: true, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: true, isRequired: false, transformFunction: null }, showModelPicker: { classPropertyName: "showModelPicker", publicName: "showModelPicker", isSignal: true, isRequired: false, transformFunction: null }, selectedModel: { classPropertyName: "selectedModel", publicName: "selectedModel", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, pushContent: { classPropertyName: "pushContent", publicName: "pushContent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedModel: "selectedModelChange", open: "openChange" }, host: { properties: { "attr.data-push": "pushContent() ? \"true\" : \"false\"", "attr.data-open": "open() ? \"true\" : \"false\"" } }, ngImport: i0, template: `
|
|
8989
9693
|
<div class="chat-sidebar__content"><ng-content /></div>
|
|
8990
9694
|
<div class="chat-sidebar__launcher">
|
|
8991
9695
|
<chat-launcher-button (clicked)="toggle()" />
|
|
@@ -9002,6 +9706,7 @@ class ChatSidebarComponent {
|
|
|
9002
9706
|
<chat
|
|
9003
9707
|
[agent]="agent()"
|
|
9004
9708
|
[views]="views()"
|
|
9709
|
+
[clientTools]="clientTools()"
|
|
9005
9710
|
[modelOptions]="modelOptions()"
|
|
9006
9711
|
[showModelPicker]="showModelPicker()"
|
|
9007
9712
|
[selectedModel]="selectedModel()"
|
|
@@ -9011,7 +9716,7 @@ class ChatSidebarComponent {
|
|
|
9011
9716
|
<ng-content select="[chatWelcomeSuggestions]" chatWelcomeSuggestions />
|
|
9012
9717
|
</chat>
|
|
9013
9718
|
</aside>
|
|
9014
|
-
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-sidebar__content{transition:margin-right .3s ease;min-height:100vh}:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:28rem}@media(max-width:640px){:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:0}}.chat-sidebar__panel{position:fixed;top:0;right:0;bottom:var(--ngaf-chat-debug-claim-bottom, 0);width:28rem;background:var(--ngaf-chat-bg);border-left:1px solid var(--ngaf-chat-separator);box-shadow:-8px 0 32px #00000014;transform:translate(100%);transition:transform .2s ease-out,bottom .2s ease-out;z-index:var(--ngaf-chat-z-overlay-content, 30);display:flex;flex-direction:column}.chat-sidebar__panel[data-open=true]{transform:translate(0)}@media(max-width:640px){.chat-sidebar__panel{width:100vw}}.chat-sidebar__panel-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 12px;border-bottom:1px solid var(--ngaf-chat-separator);min-height:48px}.chat-sidebar__panel-title{min-width:0;flex:1 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.chat-sidebar__close{flex:0 0 auto;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;display:flex;align-items:center;justify-content:center}.chat-sidebar__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-sidebar__launcher{position:fixed;bottom:calc(1rem + var(--ngaf-chat-debug-claim-bottom, 0));right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30);transition:bottom .2s ease-out}:host([data-open=\"true\"]) .chat-sidebar__launcher{display:none}\n"], dependencies: [{ kind: "component", type: ChatComponent, selector: "chat", inputs: ["agent", "views", "store", "handlers", "threads", "activeThreadId", "welcomeDisabled", "modelOptions", "showModelPicker", "selectedModel", "modelPickerPlaceholder", "genuiToolNames"], outputs: ["selectedModelChange", "threadSelected", "renderEvent", "regenerate", "rate", "messageCopy"] }, { kind: "component", type: ChatLauncherButtonComponent, selector: "chat-launcher-button", outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9719
|
+
`, isInline: true, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-sidebar__content{transition:margin-right .3s ease;min-height:100vh}:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:28rem}@media(max-width:640px){:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:0}}.chat-sidebar__panel{position:fixed;top:0;right:0;bottom:var(--ngaf-chat-debug-claim-bottom, 0);width:28rem;background:var(--ngaf-chat-bg);border-left:1px solid var(--ngaf-chat-separator);box-shadow:-8px 0 32px #00000014;transform:translate(100%);transition:transform .2s ease-out,bottom .2s ease-out;z-index:var(--ngaf-chat-z-overlay-content, 30);display:flex;flex-direction:column}.chat-sidebar__panel[data-open=true]{transform:translate(0)}@media(max-width:640px){.chat-sidebar__panel{width:100vw}}.chat-sidebar__panel-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 12px;border-bottom:1px solid var(--ngaf-chat-separator);min-height:48px}.chat-sidebar__panel-title{min-width:0;flex:1 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.chat-sidebar__close{flex:0 0 auto;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;display:flex;align-items:center;justify-content:center}.chat-sidebar__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-sidebar__launcher{position:fixed;bottom:calc(1rem + var(--ngaf-chat-debug-claim-bottom, 0));right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30);transition:bottom .2s ease-out}:host([data-open=\"true\"]) .chat-sidebar__launcher{display:none}\n"], dependencies: [{ kind: "component", type: ChatComponent, selector: "chat", inputs: ["agent", "views", "clientTools", "store", "handlers", "threads", "activeThreadId", "welcomeDisabled", "modelOptions", "showModelPicker", "selectedModel", "modelPickerPlaceholder", "genuiToolNames"], outputs: ["selectedModelChange", "threadSelected", "renderEvent", "regenerate", "rate", "messageCopy"] }, { kind: "component", type: ChatLauncherButtonComponent, selector: "chat-launcher-button", outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9015
9720
|
}
|
|
9016
9721
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSidebarComponent, decorators: [{
|
|
9017
9722
|
type: Component,
|
|
@@ -9035,6 +9740,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
9035
9740
|
<chat
|
|
9036
9741
|
[agent]="agent()"
|
|
9037
9742
|
[views]="views()"
|
|
9743
|
+
[clientTools]="clientTools()"
|
|
9038
9744
|
[modelOptions]="modelOptions()"
|
|
9039
9745
|
[showModelPicker]="showModelPicker()"
|
|
9040
9746
|
[selectedModel]="selectedModel()"
|
|
@@ -9045,7 +9751,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
9045
9751
|
</chat>
|
|
9046
9752
|
</aside>
|
|
9047
9753
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.chat-sidebar__content{transition:margin-right .3s ease;min-height:100vh}:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:28rem}@media(max-width:640px){:host([data-push=\"true\"][data-open=\"true\"]) .chat-sidebar__content{margin-right:0}}.chat-sidebar__panel{position:fixed;top:0;right:0;bottom:var(--ngaf-chat-debug-claim-bottom, 0);width:28rem;background:var(--ngaf-chat-bg);border-left:1px solid var(--ngaf-chat-separator);box-shadow:-8px 0 32px #00000014;transform:translate(100%);transition:transform .2s ease-out,bottom .2s ease-out;z-index:var(--ngaf-chat-z-overlay-content, 30);display:flex;flex-direction:column}.chat-sidebar__panel[data-open=true]{transform:translate(0)}@media(max-width:640px){.chat-sidebar__panel{width:100vw}}.chat-sidebar__panel-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 12px;border-bottom:1px solid var(--ngaf-chat-separator);min-height:48px}.chat-sidebar__panel-title{min-width:0;flex:1 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--ngaf-chat-text);font-weight:500;font-size:var(--ngaf-chat-font-size-sm)}.chat-sidebar__close{flex:0 0 auto;width:32px;height:32px;background:transparent;border:0;cursor:pointer;color:var(--ngaf-chat-text-muted);border-radius:50%;display:flex;align-items:center;justify-content:center}.chat-sidebar__close:hover{background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text)}.chat-sidebar__launcher{position:fixed;bottom:calc(1rem + var(--ngaf-chat-debug-claim-bottom, 0));right:1rem;z-index:var(--ngaf-chat-z-overlay-content, 30);transition:bottom .2s ease-out}:host([data-open=\"true\"]) .chat-sidebar__launcher{display:none}\n"] }]
|
|
9048
|
-
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], pushContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "pushContent", required: false }] }] } });
|
|
9754
|
+
}], ctorParameters: () => [], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }], views: [{ type: i0.Input, args: [{ isSignal: true, alias: "views", required: false }] }], clientTools: [{ type: i0.Input, args: [{ isSignal: true, alias: "clientTools", required: false }] }], modelOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "modelOptions", required: false }] }], showModelPicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showModelPicker", required: false }] }], selectedModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedModel", required: false }] }, { type: i0.Output, args: ["selectedModelChange"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], pushContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "pushContent", required: false }] }] } });
|
|
9049
9755
|
|
|
9050
9756
|
// libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.ts
|
|
9051
9757
|
// SPDX-License-Identifier: MIT
|
|
@@ -10615,24 +11321,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
10615
11321
|
`, styles: [".a2ui-card{display:flex;flex-direction:column;gap:var(--a2ui-spacing-2);border-radius:var(--a2ui-shape-medium);border:1px solid var(--a2ui-outline);background:var(--a2ui-surface);padding:var(--a2ui-spacing-4);box-shadow:var(--a2ui-elevation-1)}\n"] }]
|
|
10616
11322
|
}], propDecorators: { childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: true }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], emit: [{ type: i0.Input, args: [{ isSignal: true, alias: "emit", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
|
|
10617
11323
|
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
function emitBinding(emit, bindings, prop, value) {
|
|
11324
|
+
/** Writes a typed value to the render state store if the prop has a binding path. */
|
|
11325
|
+
function emitBinding(host, bindings, prop, value) {
|
|
10621
11326
|
const path = bindings?.[prop];
|
|
10622
11327
|
if (path) {
|
|
10623
|
-
|
|
11328
|
+
host.set(path, value);
|
|
10624
11329
|
}
|
|
10625
11330
|
}
|
|
10626
11331
|
|
|
10627
11332
|
// SPDX-License-Identifier: MIT
|
|
10628
11333
|
class A2uiCheckBoxComponent {
|
|
11334
|
+
host = injectRenderHost();
|
|
10629
11335
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
10630
11336
|
/** v1 canonical prop: boolean checked state. */
|
|
10631
11337
|
value = input(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
10632
11338
|
/** Pre-v1 alias retained for back-compat. */
|
|
10633
11339
|
checked = input(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
|
|
10634
11340
|
_bindings = input({}, ...(ngDevMode ? [{ debugName: "_bindings" }] : []));
|
|
10635
|
-
emit = input(() => { }, ...(ngDevMode ? [{ debugName: "emit" }] : []));
|
|
10636
11341
|
// Framework inputs required by the render harness.
|
|
10637
11342
|
bindings = input({}, ...(ngDevMode ? [{ debugName: "bindings" }] : []));
|
|
10638
11343
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
@@ -10645,14 +11350,14 @@ class A2uiCheckBoxComponent {
|
|
|
10645
11350
|
// `value`; pre-v1 used `checked`.
|
|
10646
11351
|
const bound = this._bindings();
|
|
10647
11352
|
if (bound['value']) {
|
|
10648
|
-
emitBinding(this.
|
|
11353
|
+
emitBinding(this.host, bound, 'value', val);
|
|
10649
11354
|
}
|
|
10650
11355
|
else {
|
|
10651
|
-
emitBinding(this.
|
|
11356
|
+
emitBinding(this.host, bound, 'checked', val);
|
|
10652
11357
|
}
|
|
10653
11358
|
}
|
|
10654
11359
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: A2uiCheckBoxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10655
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: A2uiCheckBoxComponent, isStandalone: true, selector: "a2ui-check-box", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null },
|
|
11360
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: A2uiCheckBoxComponent, isStandalone: true, selector: "a2ui-check-box", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null }, bindings: { classPropertyName: "bindings", publicName: "bindings", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, childKeys: { classPropertyName: "childKeys", publicName: "childKeys", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
10656
11361
|
<label class="a2ui-cb">
|
|
10657
11362
|
<input type="checkbox" [checked]="effectiveValue()" (change)="onChange($event)" class="a2ui-cb__input" />
|
|
10658
11363
|
{{ label() }}
|
|
@@ -10667,7 +11372,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
10667
11372
|
{{ label() }}
|
|
10668
11373
|
</label>
|
|
10669
11374
|
`, styles: [".a2ui-cb{display:flex;align-items:center;gap:var(--a2ui-spacing-2);font-size:var(--a2ui-typography-body-size);cursor:pointer}.a2ui-cb__input{width:16px;height:16px;border-radius:var(--a2ui-shape-extra-small);cursor:pointer;accent-color:var(--a2ui-primary)}\n"] }]
|
|
10670
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }],
|
|
11375
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
10671
11376
|
|
|
10672
11377
|
// SPDX-License-Identifier: MIT
|
|
10673
11378
|
const ALIGN_MAP = {
|
|
@@ -10710,6 +11415,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
10710
11415
|
class A2uiDateTimeInputComponent {
|
|
10711
11416
|
static _idCounter = 0;
|
|
10712
11417
|
_inputId = `a2ui-date-time-input-${++A2uiDateTimeInputComponent._idCounter}`;
|
|
11418
|
+
host = injectRenderHost();
|
|
10713
11419
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
10714
11420
|
/** v1 prop: value (resolved DynamicString). */
|
|
10715
11421
|
value = input('', ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
@@ -10718,7 +11424,6 @@ class A2uiDateTimeInputComponent {
|
|
|
10718
11424
|
/** v1 prop: enableTime — include time portion. */
|
|
10719
11425
|
enableTime = input(false, ...(ngDevMode ? [{ debugName: "enableTime" }] : []));
|
|
10720
11426
|
_bindings = input({}, ...(ngDevMode ? [{ debugName: "_bindings" }] : []));
|
|
10721
|
-
emit = input(() => { }, ...(ngDevMode ? [{ debugName: "emit" }] : []));
|
|
10722
11427
|
// Framework inputs required by the render harness.
|
|
10723
11428
|
bindings = input({}, ...(ngDevMode ? [{ debugName: "bindings" }] : []));
|
|
10724
11429
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
@@ -10736,10 +11441,10 @@ class A2uiDateTimeInputComponent {
|
|
|
10736
11441
|
}, ...(ngDevMode ? [{ debugName: "htmlInputType" }] : []));
|
|
10737
11442
|
onChange(event) {
|
|
10738
11443
|
const val = event.target.value;
|
|
10739
|
-
emitBinding(this.
|
|
11444
|
+
emitBinding(this.host, this._bindings(), 'value', val);
|
|
10740
11445
|
}
|
|
10741
11446
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: A2uiDateTimeInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10742
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiDateTimeInputComponent, isStandalone: true, selector: "a2ui-date-time-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enableDate: { classPropertyName: "enableDate", publicName: "enableDate", isSignal: true, isRequired: false, transformFunction: null }, enableTime: { classPropertyName: "enableTime", publicName: "enableTime", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null },
|
|
11447
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiDateTimeInputComponent, isStandalone: true, selector: "a2ui-date-time-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enableDate: { classPropertyName: "enableDate", publicName: "enableDate", isSignal: true, isRequired: false, transformFunction: null }, enableTime: { classPropertyName: "enableTime", publicName: "enableTime", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null }, bindings: { classPropertyName: "bindings", publicName: "bindings", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, childKeys: { classPropertyName: "childKeys", publicName: "childKeys", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
10743
11448
|
<div class="a2ui-dti">
|
|
10744
11449
|
@if (label()) {
|
|
10745
11450
|
<label [htmlFor]="_inputId" class="a2ui-dti__label">{{ label() }}</label>
|
|
@@ -10770,7 +11475,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
10770
11475
|
/>
|
|
10771
11476
|
</div>
|
|
10772
11477
|
`, styles: [".a2ui-dti{display:flex;flex-direction:column;gap:var(--a2ui-spacing-1)}.a2ui-dti__label{font-size:var(--a2ui-typography-label-size);font-weight:var(--a2ui-typography-label-weight);color:var(--a2ui-label)}.a2ui-dti__input{padding:var(--a2ui-spacing-2) var(--a2ui-spacing-3);font-size:var(--a2ui-typography-body-size);border-radius:var(--a2ui-shape-small);background:var(--a2ui-input-bg);color:var(--a2ui-on-surface);border:1px solid var(--a2ui-outline);outline:none;transition:border-color var(--a2ui-motion-duration-short) var(--a2ui-motion-easing-standard)}.a2ui-dti__input:focus{outline:var(--a2ui-focus-ring-width) solid var(--a2ui-focus-ring-color);outline-offset:2px;border-color:var(--a2ui-primary)}\n"] }]
|
|
10773
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], enableDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableDate", required: false }] }], enableTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableTime", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }],
|
|
11478
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], enableDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableDate", required: false }] }], enableTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableTime", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
10774
11479
|
|
|
10775
11480
|
// SPDX-License-Identifier: MIT
|
|
10776
11481
|
class A2uiDividerComponent {
|
|
@@ -11061,6 +11766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
11061
11766
|
|
|
11062
11767
|
// SPDX-License-Identifier: MIT
|
|
11063
11768
|
class A2uiMultipleChoiceComponent {
|
|
11769
|
+
host = injectRenderHost();
|
|
11064
11770
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11065
11771
|
/** Resolved current selections from surface-to-spec. Normalized in
|
|
11066
11772
|
* `selectionsArray` because LLMs sometimes seed the data model with a
|
|
@@ -11080,7 +11786,6 @@ class A2uiMultipleChoiceComponent {
|
|
|
11080
11786
|
/** When ≤ 1 — render as single-select <select>; otherwise multi-select checkboxes. */
|
|
11081
11787
|
maxAllowedSelections = input(1, ...(ngDevMode ? [{ debugName: "maxAllowedSelections" }] : []));
|
|
11082
11788
|
_bindings = input({}, ...(ngDevMode ? [{ debugName: "_bindings" }] : []));
|
|
11083
|
-
emit = input(() => { }, ...(ngDevMode ? [{ debugName: "emit" }] : []));
|
|
11084
11789
|
// Framework inputs required by the render harness.
|
|
11085
11790
|
bindings = input({}, ...(ngDevMode ? [{ debugName: "bindings" }] : []));
|
|
11086
11791
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
@@ -11092,7 +11797,7 @@ class A2uiMultipleChoiceComponent {
|
|
|
11092
11797
|
}
|
|
11093
11798
|
onSelectChange(event) {
|
|
11094
11799
|
const val = event.target.value;
|
|
11095
|
-
emitBinding(this.
|
|
11800
|
+
emitBinding(this.host, this._bindings(), 'selections', val);
|
|
11096
11801
|
}
|
|
11097
11802
|
onCheckChange(value, event) {
|
|
11098
11803
|
const checked = event.target.checked;
|
|
@@ -11104,11 +11809,11 @@ class A2uiMultipleChoiceComponent {
|
|
|
11104
11809
|
else if (!checked && idx !== -1) {
|
|
11105
11810
|
current.splice(idx, 1);
|
|
11106
11811
|
}
|
|
11107
|
-
//
|
|
11108
|
-
emitBinding(this.
|
|
11812
|
+
// Pass the updated selections array directly (typed value, no JSON stringification needed).
|
|
11813
|
+
emitBinding(this.host, this._bindings(), 'selections', current);
|
|
11109
11814
|
}
|
|
11110
11815
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: A2uiMultipleChoiceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11111
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiMultipleChoiceComponent, isStandalone: true, selector: "a2ui-multiple-choice", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, maxAllowedSelections: { classPropertyName: "maxAllowedSelections", publicName: "maxAllowedSelections", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null },
|
|
11816
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiMultipleChoiceComponent, isStandalone: true, selector: "a2ui-multiple-choice", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, maxAllowedSelections: { classPropertyName: "maxAllowedSelections", publicName: "maxAllowedSelections", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null }, bindings: { classPropertyName: "bindings", publicName: "bindings", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, childKeys: { classPropertyName: "childKeys", publicName: "childKeys", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11112
11817
|
<div class="a2ui-mc">
|
|
11113
11818
|
@if (label()) {
|
|
11114
11819
|
<span class="a2ui-mc__label">{{ label() }}</span>
|
|
@@ -11173,7 +11878,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
11173
11878
|
}
|
|
11174
11879
|
</div>
|
|
11175
11880
|
`, styles: [".a2ui-mc{display:flex;flex-direction:column;gap:var(--a2ui-spacing-1)}.a2ui-mc__label{font-size:var(--a2ui-typography-label-size);font-weight:var(--a2ui-typography-label-weight);color:var(--a2ui-label)}.a2ui-mc__select{padding:var(--a2ui-spacing-2) var(--a2ui-spacing-3);font-size:var(--a2ui-typography-body-size);border-radius:var(--a2ui-shape-small);background:var(--a2ui-input-bg);color:var(--a2ui-on-surface);border:1px solid var(--a2ui-outline);outline:none;transition:border-color var(--a2ui-motion-duration-short) var(--a2ui-motion-easing-standard)}.a2ui-mc__select:focus{outline:var(--a2ui-focus-ring-width) solid var(--a2ui-focus-ring-color);outline-offset:2px;border-color:var(--a2ui-primary)}.a2ui-mc__checks{display:flex;flex-direction:column;gap:var(--a2ui-spacing-2)}.a2ui-mc__check-row{display:flex;align-items:center;gap:var(--a2ui-spacing-2);font-size:var(--a2ui-typography-body-size);cursor:pointer}.a2ui-mc__checkbox{width:16px;height:16px;border-radius:var(--a2ui-shape-extra-small);cursor:pointer;accent-color:var(--a2ui-primary)}\n"] }]
|
|
11176
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], selections: [{ type: i0.Input, args: [{ isSignal: true, alias: "selections", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], maxAllowedSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxAllowedSelections", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }],
|
|
11881
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], selections: [{ type: i0.Input, args: [{ isSignal: true, alias: "selections", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], maxAllowedSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxAllowedSelections", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
11177
11882
|
|
|
11178
11883
|
// SPDX-License-Identifier: MIT
|
|
11179
11884
|
const ROW_ALIGN_MAP = {
|
|
@@ -11231,6 +11936,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
11231
11936
|
class A2uiSliderComponent {
|
|
11232
11937
|
static _idCounter = 0;
|
|
11233
11938
|
_inputId = `a2ui-slider-${++A2uiSliderComponent._idCounter}`;
|
|
11939
|
+
host = injectRenderHost();
|
|
11234
11940
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11235
11941
|
/** v1 prop: value (resolved DynamicNumber). */
|
|
11236
11942
|
value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
@@ -11240,7 +11946,6 @@ class A2uiSliderComponent {
|
|
|
11240
11946
|
maxValue = input(100, ...(ngDevMode ? [{ debugName: "maxValue" }] : []));
|
|
11241
11947
|
step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
|
|
11242
11948
|
_bindings = input({}, ...(ngDevMode ? [{ debugName: "_bindings" }] : []));
|
|
11243
|
-
emit = input(() => { }, ...(ngDevMode ? [{ debugName: "emit" }] : []));
|
|
11244
11949
|
// Framework inputs required by the render harness.
|
|
11245
11950
|
bindings = input({}, ...(ngDevMode ? [{ debugName: "bindings" }] : []));
|
|
11246
11951
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
@@ -11248,10 +11953,10 @@ class A2uiSliderComponent {
|
|
|
11248
11953
|
spec = input(undefined, ...(ngDevMode ? [{ debugName: "spec" }] : []));
|
|
11249
11954
|
onInput(event) {
|
|
11250
11955
|
const val = Number(event.target.value);
|
|
11251
|
-
emitBinding(this.
|
|
11956
|
+
emitBinding(this.host, this._bindings(), 'value', val);
|
|
11252
11957
|
}
|
|
11253
11958
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: A2uiSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11254
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiSliderComponent, isStandalone: true, selector: "a2ui-slider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null },
|
|
11959
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiSliderComponent, isStandalone: true, selector: "a2ui-slider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null }, bindings: { classPropertyName: "bindings", publicName: "bindings", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, childKeys: { classPropertyName: "childKeys", publicName: "childKeys", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11255
11960
|
<div class="a2ui-slider">
|
|
11256
11961
|
@if (label()) {
|
|
11257
11962
|
<label [htmlFor]="_inputId" class="a2ui-slider__label">{{ label() }}: {{ value() }}</label>
|
|
@@ -11288,7 +11993,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
11288
11993
|
/>
|
|
11289
11994
|
</div>
|
|
11290
11995
|
`, styles: [".a2ui-slider{display:flex;flex-direction:column;gap:var(--a2ui-spacing-1)}.a2ui-slider__label{font-size:var(--a2ui-typography-label-size);font-weight:var(--a2ui-typography-label-weight);color:var(--a2ui-label)}.a2ui-slider__input{width:100%;cursor:pointer;accent-color:var(--a2ui-primary)}\n"] }]
|
|
11291
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }],
|
|
11996
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
11292
11997
|
|
|
11293
11998
|
// SPDX-License-Identifier: MIT
|
|
11294
11999
|
class A2uiTabsComponent {
|
|
@@ -11395,6 +12100,7 @@ const TYPE_MAP = {
|
|
|
11395
12100
|
class A2uiTextFieldComponent {
|
|
11396
12101
|
static _idCounter = 0;
|
|
11397
12102
|
_inputId = `a2ui-text-field-${++A2uiTextFieldComponent._idCounter}`;
|
|
12103
|
+
host = injectRenderHost();
|
|
11398
12104
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
11399
12105
|
/** v1 prop: text (resolved string value). */
|
|
11400
12106
|
text = input('', ...(ngDevMode ? [{ debugName: "text" }] : []));
|
|
@@ -11404,7 +12110,6 @@ class A2uiTextFieldComponent {
|
|
|
11404
12110
|
textFieldType = input('shortText', ...(ngDevMode ? [{ debugName: "textFieldType" }] : []));
|
|
11405
12111
|
validationRegexp = input('', ...(ngDevMode ? [{ debugName: "validationRegexp" }] : []));
|
|
11406
12112
|
_bindings = input({}, ...(ngDevMode ? [{ debugName: "_bindings" }] : []));
|
|
11407
|
-
emit = input(() => { }, ...(ngDevMode ? [{ debugName: "emit" }] : []));
|
|
11408
12113
|
// Framework inputs required by the render harness.
|
|
11409
12114
|
bindings = input({}, ...(ngDevMode ? [{ debugName: "bindings" }] : []));
|
|
11410
12115
|
loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
@@ -11416,14 +12121,14 @@ class A2uiTextFieldComponent {
|
|
|
11416
12121
|
// Emit on 'text' binding (v1 prop name); also try 'value' for compat.
|
|
11417
12122
|
const bound = this._bindings();
|
|
11418
12123
|
if (bound['text']) {
|
|
11419
|
-
emitBinding(this.
|
|
12124
|
+
emitBinding(this.host, bound, 'text', val);
|
|
11420
12125
|
}
|
|
11421
12126
|
else {
|
|
11422
|
-
emitBinding(this.
|
|
12127
|
+
emitBinding(this.host, bound, 'value', val);
|
|
11423
12128
|
}
|
|
11424
12129
|
}
|
|
11425
12130
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: A2uiTextFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11426
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiTextFieldComponent, isStandalone: true, selector: "a2ui-text-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, textFieldType: { classPropertyName: "textFieldType", publicName: "textFieldType", isSignal: true, isRequired: false, transformFunction: null }, validationRegexp: { classPropertyName: "validationRegexp", publicName: "validationRegexp", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null },
|
|
12131
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: A2uiTextFieldComponent, isStandalone: true, selector: "a2ui-text-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, textFieldType: { classPropertyName: "textFieldType", publicName: "textFieldType", isSignal: true, isRequired: false, transformFunction: null }, validationRegexp: { classPropertyName: "validationRegexp", publicName: "validationRegexp", isSignal: true, isRequired: false, transformFunction: null }, _bindings: { classPropertyName: "_bindings", publicName: "_bindings", isSignal: true, isRequired: false, transformFunction: null }, bindings: { classPropertyName: "bindings", publicName: "bindings", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, childKeys: { classPropertyName: "childKeys", publicName: "childKeys", isSignal: true, isRequired: false, transformFunction: null }, spec: { classPropertyName: "spec", publicName: "spec", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11427
12132
|
<div class="a2ui-tf">
|
|
11428
12133
|
@if (label()) {
|
|
11429
12134
|
<label [htmlFor]="_inputId" class="a2ui-tf__label">{{ label() }}</label>
|
|
@@ -11480,7 +12185,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
11480
12185
|
}
|
|
11481
12186
|
</div>
|
|
11482
12187
|
`, styles: [".a2ui-tf{display:flex;flex-direction:column;gap:var(--a2ui-spacing-1)}.a2ui-tf__label{font-size:var(--a2ui-typography-label-size);font-weight:var(--a2ui-typography-label-weight);color:var(--a2ui-label)}.a2ui-tf__input{padding:var(--a2ui-spacing-2) var(--a2ui-spacing-3);font-size:var(--a2ui-typography-body-size);border-radius:var(--a2ui-shape-small);background:var(--a2ui-input-bg);color:var(--a2ui-on-surface);border:1px solid var(--a2ui-outline);outline:none;transition:border-color var(--a2ui-motion-duration-short) var(--a2ui-motion-easing-standard);resize:vertical}.a2ui-tf__input:focus{outline:var(--a2ui-focus-ring-width) solid var(--a2ui-focus-ring-color);outline-offset:2px;border-color:var(--a2ui-primary)}\n"] }]
|
|
11483
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], textFieldType: [{ type: i0.Input, args: [{ isSignal: true, alias: "textFieldType", required: false }] }], validationRegexp: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRegexp", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }],
|
|
12188
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], textFieldType: [{ type: i0.Input, args: [{ isSignal: true, alias: "textFieldType", required: false }] }], validationRegexp: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationRegexp", required: false }] }], _bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "_bindings", required: false }] }], bindings: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindings", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
11484
12189
|
|
|
11485
12190
|
// SPDX-License-Identifier: MIT
|
|
11486
12191
|
class A2uiVideoComponent {
|
|
@@ -11540,12 +12245,125 @@ function a2uiBasicCatalog() {
|
|
|
11540
12245
|
});
|
|
11541
12246
|
}
|
|
11542
12247
|
|
|
12248
|
+
/**
|
|
12249
|
+
* Declare an async function tool the model can call; its resolved return value
|
|
12250
|
+
* becomes the tool result shipped back to the model.
|
|
12251
|
+
*
|
|
12252
|
+
* @param description Natural-language description the model sees.
|
|
12253
|
+
* @param schema Standard Schema (e.g. a Zod object) for the arguments; the
|
|
12254
|
+
* handler's argument type is inferred from it.
|
|
12255
|
+
* @param handler Runs in the browser when the model calls the tool; its return
|
|
12256
|
+
* type `R` is carried on the resulting {@link FunctionToolDef}.
|
|
12257
|
+
* @returns A {@link FunctionToolDef} for inclusion in {@link tools}.
|
|
12258
|
+
* @example
|
|
12259
|
+
* ```ts
|
|
12260
|
+
* const move = action('Move a stop', z.object({ fromDay: z.number() }), (a) => a.fromDay);
|
|
12261
|
+
* const registry = tools({ move_stop: move });
|
|
12262
|
+
* ```
|
|
12263
|
+
*/
|
|
12264
|
+
function action(description, schema, handler) {
|
|
12265
|
+
return { kind: 'function', description, schema, handler };
|
|
12266
|
+
}
|
|
12267
|
+
/**
|
|
12268
|
+
* Render-only component tool — the model fills the component's props from the
|
|
12269
|
+
* schema's output; the tool call is auto-acknowledged once the component mounts.
|
|
12270
|
+
*
|
|
12271
|
+
* The component's signal inputs are checked against the schema output type
|
|
12272
|
+
* (strict-but-flexible: every schema key must be a declared input with an
|
|
12273
|
+
* assignable type; the component may declare extra inputs the schema doesn't fill).
|
|
12274
|
+
* Author the component with `ViewProps<typeof schema>` as the input type set to
|
|
12275
|
+
* guarantee the shapes stay aligned.
|
|
12276
|
+
*
|
|
12277
|
+
* @param description Natural-language description the model sees.
|
|
12278
|
+
* @param schema Standard Schema defining the props the model must supply.
|
|
12279
|
+
* @param component Angular component whose signal inputs must be compatible with
|
|
12280
|
+
* the schema output. A type-level error is reported here when they diverge.
|
|
12281
|
+
* @returns A {@link ViewToolDef} for inclusion in {@link tools}.
|
|
12282
|
+
* @example
|
|
12283
|
+
* ```ts
|
|
12284
|
+
* const schema = z.object({ label: z.string(), day: z.number() });
|
|
12285
|
+
* type Inputs = ViewProps<typeof schema>; // { label: string; day: number }
|
|
12286
|
+
*
|
|
12287
|
+
* \@Component({ ... })
|
|
12288
|
+
* class DayCardComponent {
|
|
12289
|
+
* label = input.required<string>();
|
|
12290
|
+
* day = input.required<number>();
|
|
12291
|
+
* }
|
|
12292
|
+
*
|
|
12293
|
+
* const dayCard = view('Show a day card', schema, DayCardComponent);
|
|
12294
|
+
* const registry = tools({ day_card: dayCard });
|
|
12295
|
+
* ```
|
|
12296
|
+
*/
|
|
12297
|
+
function view(description, schema, component) {
|
|
12298
|
+
return { kind: 'view', description, schema, component: component };
|
|
12299
|
+
}
|
|
12300
|
+
/**
|
|
12301
|
+
* Interactive (human-in-the-loop) component tool — the model fills the
|
|
12302
|
+
* component's props from the schema's output; the value the component emits
|
|
12303
|
+
* back to the framework becomes the tool result sent to the model.
|
|
12304
|
+
*
|
|
12305
|
+
* The component's signal inputs are checked against the schema output type
|
|
12306
|
+
* (strict-but-flexible: every schema key must be a declared input with an
|
|
12307
|
+
* assignable type; the component may declare extra inputs the schema doesn't
|
|
12308
|
+
* fill). Author the component with `ViewProps<typeof schema>` to derive input
|
|
12309
|
+
* prop types directly from the schema.
|
|
12310
|
+
*
|
|
12311
|
+
* @param description Natural-language description the model sees.
|
|
12312
|
+
* @param schema Standard Schema defining the props the model must supply.
|
|
12313
|
+
* @param component Angular component whose signal inputs must be compatible with
|
|
12314
|
+
* the schema output. A type-level error is reported here when they diverge.
|
|
12315
|
+
* @returns An {@link AskToolDef} for inclusion in {@link tools}.
|
|
12316
|
+
* @example
|
|
12317
|
+
* ```ts
|
|
12318
|
+
* const schema = z.object({ question: z.string(), options: z.array(z.string()) });
|
|
12319
|
+
* type Inputs = ViewProps<typeof schema>;
|
|
12320
|
+
*
|
|
12321
|
+
* \@Component({ ... })
|
|
12322
|
+
* class ChoiceCardComponent {
|
|
12323
|
+
* question = input.required<string>();
|
|
12324
|
+
* options = input.required<string[]>();
|
|
12325
|
+
* // Emits the chosen option back to the model.
|
|
12326
|
+
* }
|
|
12327
|
+
*
|
|
12328
|
+
* const choice = ask('Ask the user to choose', schema, ChoiceCardComponent);
|
|
12329
|
+
* const registry = tools({ pick_option: choice });
|
|
12330
|
+
* ```
|
|
12331
|
+
*/
|
|
12332
|
+
function ask(description, schema, component) {
|
|
12333
|
+
return { kind: 'ask', description, schema, component: component };
|
|
12334
|
+
}
|
|
12335
|
+
/**
|
|
12336
|
+
* Collect named client tools into a frozen, name-keyed registry.
|
|
12337
|
+
*
|
|
12338
|
+
* The overload is generic over the entire map (`const M`) so that each tool's
|
|
12339
|
+
* precise type ({@link FunctionToolDef}`<S,R>`, {@link ViewToolDef}`<S,C>`, or
|
|
12340
|
+
* {@link AskToolDef}`<S,C>`) and every literal key are preserved in the
|
|
12341
|
+
* {@link ClientToolRegistry} passed to `provideChat`. This lets downstream
|
|
12342
|
+
* consumers look up individual tools without losing generic information.
|
|
12343
|
+
*
|
|
12344
|
+
* @param map An object literal mapping tool names to tool definitions created
|
|
12345
|
+
* by {@link action}, {@link view}, or {@link ask}.
|
|
12346
|
+
* @returns A frozen `Readonly<M>` where `M` is the exact inferred map shape.
|
|
12347
|
+
* @example
|
|
12348
|
+
* ```ts
|
|
12349
|
+
* const move = action('Move a stop', z.object({ fromDay: z.number() }), (a) => a.fromDay);
|
|
12350
|
+
* const dayCard = view('Show a day card', z.object({ label: z.string() }), DayCardComponent);
|
|
12351
|
+
*
|
|
12352
|
+
* const registry = tools({ move_stop: move, day_card: dayCard });
|
|
12353
|
+
* // registry.move_stop is FunctionToolDef<...>
|
|
12354
|
+
* // registry.day_card is ViewToolDef<...>
|
|
12355
|
+
* ```
|
|
12356
|
+
*/
|
|
12357
|
+
function tools(map) {
|
|
12358
|
+
return Object.freeze({ ...map });
|
|
12359
|
+
}
|
|
12360
|
+
|
|
11543
12361
|
// SPDX-License-Identifier: MIT
|
|
11544
12362
|
function mockAgent(opts = {}) {
|
|
11545
12363
|
const messages = signal(opts.messages ?? [], ...(ngDevMode ? [{ debugName: "messages" }] : []));
|
|
11546
12364
|
const status = signal(opts.status ?? 'idle', ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
11547
12365
|
const isLoading = signal(opts.isLoading ?? false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
11548
|
-
const error = signal(opts.error ??
|
|
12366
|
+
const error = signal(opts.error ?? undefined, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
11549
12367
|
const toolCalls = signal(opts.toolCalls ?? [], ...(ngDevMode ? [{ debugName: "toolCalls" }] : []));
|
|
11550
12368
|
const state = signal(opts.state ?? {}, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
11551
12369
|
const interrupt = opts.withInterrupt
|
|
@@ -11570,6 +12388,7 @@ function mockAgent(opts = {}) {
|
|
|
11570
12388
|
events$: opts.events$ ?? EMPTY,
|
|
11571
12389
|
submit: async (input, submitOpts) => { submitCalls.push({ input, opts: submitOpts }); },
|
|
11572
12390
|
stop: async () => { stopCount++; },
|
|
12391
|
+
retry: async () => { return; },
|
|
11573
12392
|
regenerate: async (assistantMessageIndex) => {
|
|
11574
12393
|
// Truncate messages [N..end] and record the call as a synthetic submit so
|
|
11575
12394
|
// tests can assert regenerate behavior via the same submitCalls log.
|
|
@@ -11591,5 +12410,5 @@ function mockAgent(opts = {}) {
|
|
|
11591
12410
|
* Generated bundle index. Do not edit.
|
|
11592
12411
|
*/
|
|
11593
12412
|
|
|
11594
|
-
export { A2uiAudioPlayerComponent, A2uiButtonComponent, A2uiCardComponent, A2uiCheckBoxComponent, A2uiColumnComponent, A2uiDateTimeInputComponent, A2uiDividerComponent, A2uiIconComponent, A2uiImageComponent, A2uiListComponent, A2uiModalComponent, A2uiMultipleChoiceComponent, A2uiRowComponent, A2uiSliderComponent, A2uiSurfaceComponent, A2uiTabsComponent, A2uiTextComponent, A2uiTextFieldComponent, A2uiVideoComponent, CHAT_CONFIG, CHAT_LIFECYCLE, CHAT_MARKDOWN_STYLES, ChatApprovalCardComponent, ChatCitationCardTemplateDirective, ChatCitationsCardComponent, ChatCitationsComponent, ChatComponent, ChatConfirmDialogComponent, ChatErrorComponent, ChatGenerativeUiComponent, ChatGenuiSkeletonComponent, ChatHistorySearchPaletteComponent, ChatInputComponent, ChatInterruptComponent, ChatInterruptPanelComponent, ChatLauncherButtonComponent, ChatMessageActionsComponent, ChatMessageComponent, ChatMessageListComponent, ChatOverflowMenuComponent, ChatPopupComponent, ChatProjectListComponent, ChatReasoningComponent, ChatScrollBubbleComponent, ChatSelectComponent, ChatSidebarComponent, ChatSidenavComponent, ChatSidenavScrimComponent, ChatStreamingMdComponent, ChatSubagentCardComponent, ChatSubagentsComponent, ChatSuggestionsComponent, ChatThreadListComponent, ChatTimelineComponent, ChatTimelineSliderComponent, ChatToolCallCardComponent, ChatToolCallTemplateDirective, ChatToolCallsComponent, ChatToolViewsComponent, ChatTraceComponent, ChatTypingIndicatorComponent, ChatWelcomeComponent, ChatWelcomeSuggestionComponent, ChatWindowComponent, CitationsResolverService, ICON_AGENT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CHEVRON_UP, ICON_SEND, ICON_TOOL, ICON_WARNING, IS_HEADER_ROW, MARKDOWN_VIEW_REGISTRY, MarkdownAutolinkComponent, MarkdownBlockquoteComponent, MarkdownChildrenComponent, MarkdownCitationReferenceComponent, MarkdownCodeBlockComponent, MarkdownDocumentComponent, MarkdownEmphasisComponent, MarkdownHardBreakComponent, MarkdownHeadingComponent, MarkdownImageComponent, MarkdownInlineCodeComponent, MarkdownLinkComponent, MarkdownListComponent, MarkdownListItemComponent, MarkdownParagraphComponent, MarkdownSoftBreakComponent, MarkdownStrikethroughComponent, MarkdownStrongComponent, MarkdownTableCellComponent, MarkdownTableComponent, MarkdownTableRowComponent, MarkdownTextComponent, MarkdownThematicBreakComponent, MessageTemplateDirective, a2uiBasicCatalog, buildA2uiActionMessage, cacheplaneMarkdownViews, createA2uiSurfaceStore, createContentClassifier, createParseTreeStore, createPartialArgsBridge, emitBinding, extractErrorMessage, formatDuration, getInterrupt, getMessageType, isAssistantMessage, isSystemMessage, isToolMessage, isTyping, isUserMessage, messageContent, mockAgent, normalizeEnvelopeArgs, normalizeViewEntry, provideChat, renderMarkdown, statusColor, submitMessage, surfaceToSpec };
|
|
12413
|
+
export { A2uiAudioPlayerComponent, A2uiButtonComponent, A2uiCardComponent, A2uiCheckBoxComponent, A2uiColumnComponent, A2uiDateTimeInputComponent, A2uiDividerComponent, A2uiIconComponent, A2uiImageComponent, A2uiListComponent, A2uiModalComponent, A2uiMultipleChoiceComponent, A2uiRowComponent, A2uiSliderComponent, A2uiSurfaceComponent, A2uiTabsComponent, A2uiTextComponent, A2uiTextFieldComponent, A2uiVideoComponent, AGENT_ERROR_MESSAGES, AgentError, CHAT_CONFIG, CHAT_LIFECYCLE, CHAT_MARKDOWN_STYLES, ChatApprovalCardComponent, ChatCitationCardTemplateDirective, ChatCitationsCardComponent, ChatCitationsComponent, ChatComponent, ChatConfirmDialogComponent, ChatErrorComponent, ChatGenerativeUiComponent, ChatGenuiSkeletonComponent, ChatHistorySearchPaletteComponent, ChatInputComponent, ChatInterruptComponent, ChatInterruptPanelComponent, ChatLauncherButtonComponent, ChatMessageActionsComponent, ChatMessageComponent, ChatMessageListComponent, ChatOverflowMenuComponent, ChatPopupComponent, ChatProjectListComponent, ChatReasoningComponent, ChatScrollBubbleComponent, ChatSelectComponent, ChatSidebarComponent, ChatSidenavComponent, ChatSidenavScrimComponent, ChatStreamingMdComponent, ChatSubagentCardComponent, ChatSubagentsComponent, ChatSuggestionsComponent, ChatThreadListComponent, ChatTimelineComponent, ChatTimelineSliderComponent, ChatToolCallCardComponent, ChatToolCallTemplateDirective, ChatToolCallsComponent, ChatToolViewsComponent, ChatTraceComponent, ChatTypingIndicatorComponent, ChatWelcomeComponent, ChatWelcomeSuggestionComponent, ChatWindowComponent, CitationsResolverService, ICON_AGENT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CHEVRON_UP, ICON_SEND, ICON_TOOL, ICON_WARNING, IS_HEADER_ROW, MARKDOWN_VIEW_REGISTRY, MarkdownAutolinkComponent, MarkdownBlockquoteComponent, MarkdownChildrenComponent, MarkdownCitationReferenceComponent, MarkdownCodeBlockComponent, MarkdownDocumentComponent, MarkdownEmphasisComponent, MarkdownHardBreakComponent, MarkdownHeadingComponent, MarkdownImageComponent, MarkdownInlineCodeComponent, MarkdownLinkComponent, MarkdownListComponent, MarkdownListItemComponent, MarkdownParagraphComponent, MarkdownSoftBreakComponent, MarkdownStrikethroughComponent, MarkdownStrongComponent, MarkdownTableCellComponent, MarkdownTableComponent, MarkdownTableRowComponent, MarkdownTextComponent, MarkdownThematicBreakComponent, MessageTemplateDirective, a2uiBasicCatalog, action, ask, buildA2uiActionMessage, cacheplaneMarkdownViews, createA2uiSurfaceStore, createAgentRef, createClientToolsCoordinator, createContentClassifier, createParseTreeStore, createPartialArgsBridge, deriveJsonSchema, emitBinding, executeFunctionTool, extractErrorMessage, formatDuration, getInterrupt, getMessageType, injectThreadRouting, isAbortError, isAssistantMessage, isSystemMessage, isToolMessage, isTyping, isUserMessage, messageContent, mockAgent, normalizeEnvelopeArgs, normalizeViewEntry, provideChat, renderMarkdown, startClientToolExecutor, statusColor, submitMessage, surfaceToSpec, toAgentError, toClientToolSpecs, tools, validateArgs, view };
|
|
11595
12414
|
//# sourceMappingURL=threadplane-chat.mjs.map
|