@threadplane/chat 0.0.50 → 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.
|
@@ -1,17 +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
5
|
import { views, RenderSpecComponent, toRenderRegistry, signalStateStore, withViews, RenderElementComponent, injectRenderHost } from '@threadplane/render';
|
|
6
6
|
export { toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
|
|
7
7
|
import { runLicenseCheck, inferNoncommercial, LICENSE_PUBLIC_KEY } from '@threadplane/licensing';
|
|
8
|
-
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';
|
|
9
11
|
import { toJSONSchema } from 'zod/v4';
|
|
10
12
|
import { resolveDynamic, getByPointer, isPathRef, setByPointer, createA2uiMessageParser } from '@threadplane/a2ui';
|
|
11
13
|
export { isLiteralBoolean, isLiteralNumber, isLiteralString, isPathRef } from '@threadplane/a2ui';
|
|
12
14
|
import { materialize as materialize$1, createPartialJsonParser } from '@cacheplane/partial-json';
|
|
13
15
|
import { fromEvent, EMPTY } from 'rxjs';
|
|
14
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
|
+
|
|
15
177
|
function isUserMessage(m) {
|
|
16
178
|
return m.role === 'user';
|
|
17
179
|
}
|
|
@@ -25,6 +187,24 @@ function isSystemMessage(m) {
|
|
|
25
187
|
return m.role === 'system';
|
|
26
188
|
}
|
|
27
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
|
+
|
|
28
208
|
// SPDX-License-Identifier: MIT
|
|
29
209
|
class MessageTemplateDirective {
|
|
30
210
|
chatMessageTemplate = input.required(...(ngDevMode ? [{ debugName: "chatMessageTemplate" }] : []));
|
|
@@ -3852,6 +4032,26 @@ const CHAT_ERROR_STYLES = `
|
|
|
3852
4032
|
}
|
|
3853
4033
|
.chat-error__icon { flex-shrink: 0; width: 16px; height: 16px; margin-top: 2px; }
|
|
3854
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
|
+
}
|
|
3855
4055
|
`;
|
|
3856
4056
|
|
|
3857
4057
|
// libs/chat/src/lib/primitives/chat-error/chat-error.component.ts
|
|
@@ -3867,31 +4067,36 @@ function extractErrorMessage(error) {
|
|
|
3867
4067
|
}
|
|
3868
4068
|
class ChatErrorComponent {
|
|
3869
4069
|
agent = input.required(...(ngDevMode ? [{ debugName: "agent" }] : []));
|
|
3870
|
-
errorMessage = computed(() => extractErrorMessage(this.agent().error()), ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
3871
4070
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3872
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: `
|
|
3873
|
-
@if (
|
|
4072
|
+
@if (agent().error(); as err) {
|
|
3874
4073
|
<div class="chat-error" role="alert">
|
|
3875
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">
|
|
3876
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"/>
|
|
3877
4076
|
</svg>
|
|
3878
|
-
<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
|
+
}
|
|
3879
4081
|
</div>
|
|
3880
4082
|
}
|
|
3881
|
-
`, 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 });
|
|
3882
4084
|
}
|
|
3883
4085
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatErrorComponent, decorators: [{
|
|
3884
4086
|
type: Component,
|
|
3885
4087
|
args: [{ selector: 'chat-error', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
3886
|
-
@if (
|
|
4088
|
+
@if (agent().error(); as err) {
|
|
3887
4089
|
<div class="chat-error" role="alert">
|
|
3888
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">
|
|
3889
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"/>
|
|
3890
4092
|
</svg>
|
|
3891
|
-
<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
|
+
}
|
|
3892
4097
|
</div>
|
|
3893
4098
|
}
|
|
3894
|
-
`, 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"] }]
|
|
3895
4100
|
}], propDecorators: { agent: [{ type: i0.Input, args: [{ isSignal: true, alias: "agent", required: true }] }] } });
|
|
3896
4101
|
|
|
3897
4102
|
// SPDX-License-Identifier: MIT
|
|
@@ -4600,46 +4805,70 @@ function statusToTraceState(s) {
|
|
|
4600
4805
|
class ChatSubagentCardComponent {
|
|
4601
4806
|
subagent = input.required(...(ngDevMode ? [{ debugName: "subagent" }] : []));
|
|
4602
4807
|
state = computed(() => statusToTraceState(this.subagent().status()), ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
4603
|
-
|
|
4604
|
-
const
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
const
|
|
4609
|
-
|
|
4610
|
-
|
|
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
|
+
}
|
|
4611
4822
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4612
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: `
|
|
4613
4824
|
<chat-trace [state]="state()">
|
|
4614
4825
|
<span traceLabel>
|
|
4615
|
-
<span class="sac__name">Subagent</span>
|
|
4826
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4616
4827
|
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4617
4828
|
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4618
4829
|
</span>
|
|
4619
4830
|
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
4620
|
-
@
|
|
4621
|
-
<
|
|
4622
|
-
|
|
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>
|
|
4623
4843
|
}
|
|
4624
4844
|
</chat-trace>
|
|
4625
|
-
`, 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 });
|
|
4626
4846
|
}
|
|
4627
4847
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, decorators: [{
|
|
4628
4848
|
type: Component,
|
|
4629
|
-
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: `
|
|
4630
4850
|
<chat-trace [state]="state()">
|
|
4631
4851
|
<span traceLabel>
|
|
4632
|
-
<span class="sac__name">Subagent</span>
|
|
4852
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4633
4853
|
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4634
4854
|
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4635
4855
|
</span>
|
|
4636
4856
|
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
4637
|
-
@
|
|
4638
|
-
<
|
|
4639
|
-
|
|
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>
|
|
4640
4869
|
}
|
|
4641
4870
|
</chat-trace>
|
|
4642
|
-
`, 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"] }]
|
|
4643
4872
|
}], propDecorators: { subagent: [{ type: i0.Input, args: [{ isSignal: true, alias: "subagent", required: true }] }] } });
|
|
4644
4873
|
|
|
4645
4874
|
// libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts
|
|
@@ -6193,10 +6422,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
6193
6422
|
class ChatWelcomeSuggestionComponent {
|
|
6194
6423
|
label = input.required(...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
6195
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" }] : []));
|
|
6196
6427
|
selected = output();
|
|
6197
6428
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatWelcomeSuggestionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6198
|
-
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: `
|
|
6199
|
-
<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
|
+
>
|
|
6200
6437
|
<ng-content select="[chatWelcomeSuggestionIcon]" />
|
|
6201
6438
|
<span class="chat-welcome-suggestion__label">{{ label() }}</span>
|
|
6202
6439
|
<span class="chat-welcome-suggestion__chevron" aria-hidden="true">›</span>
|
|
@@ -6206,13 +6443,19 @@ class ChatWelcomeSuggestionComponent {
|
|
|
6206
6443
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatWelcomeSuggestionComponent, decorators: [{
|
|
6207
6444
|
type: Component,
|
|
6208
6445
|
args: [{ selector: 'chat-welcome-suggestion', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
6209
|
-
<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
|
+
>
|
|
6210
6453
|
<ng-content select="[chatWelcomeSuggestionIcon]" />
|
|
6211
6454
|
<span class="chat-welcome-suggestion__label">{{ label() }}</span>
|
|
6212
6455
|
<span class="chat-welcome-suggestion__chevron" aria-hidden="true">›</span>
|
|
6213
6456
|
</button>
|
|
6214
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"] }]
|
|
6215
|
-
}], 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"] }] } });
|
|
6216
6459
|
|
|
6217
6460
|
// libs/chat/src/lib/styles/chat-select.styles.ts
|
|
6218
6461
|
// SPDX-License-Identifier: MIT
|
|
@@ -6268,7 +6511,10 @@ const CHAT_SELECT_STYLES = `
|
|
|
6268
6511
|
z-index: 10;
|
|
6269
6512
|
}
|
|
6270
6513
|
.chat-select__option {
|
|
6271
|
-
display:
|
|
6514
|
+
display: flex;
|
|
6515
|
+
flex-direction: column;
|
|
6516
|
+
align-items: flex-start;
|
|
6517
|
+
gap: 2px;
|
|
6272
6518
|
width: 100%;
|
|
6273
6519
|
text-align: left;
|
|
6274
6520
|
border: 0;
|
|
@@ -6280,6 +6526,12 @@ const CHAT_SELECT_STYLES = `
|
|
|
6280
6526
|
font-size: var(--ngaf-chat-font-size-sm);
|
|
6281
6527
|
cursor: pointer;
|
|
6282
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
|
+
}
|
|
6283
6535
|
.chat-select__option:hover:not(:disabled),
|
|
6284
6536
|
.chat-select__option:focus-visible {
|
|
6285
6537
|
background: var(--ngaf-chat-surface-alt);
|
|
@@ -6458,12 +6710,15 @@ class ChatSelectComponent {
|
|
|
6458
6710
|
[attr.aria-selected]="opt.value === value()"
|
|
6459
6711
|
(click)="selectOption(opt)"
|
|
6460
6712
|
>
|
|
6461
|
-
{{ 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
|
+
}
|
|
6462
6717
|
</button>
|
|
6463
6718
|
}
|
|
6464
6719
|
</div>
|
|
6465
6720
|
}
|
|
6466
|
-
`, 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 });
|
|
6467
6722
|
}
|
|
6468
6723
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSelectComponent, decorators: [{
|
|
6469
6724
|
type: Component,
|
|
@@ -6501,17 +6756,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
6501
6756
|
[attr.aria-selected]="opt.value === value()"
|
|
6502
6757
|
(click)="selectOption(opt)"
|
|
6503
6758
|
>
|
|
6504
|
-
{{ 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
|
+
}
|
|
6505
6763
|
</button>
|
|
6506
6764
|
}
|
|
6507
6765
|
</div>
|
|
6508
6766
|
}
|
|
6509
|
-
`, 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"] }]
|
|
6510
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 }] }] } });
|
|
6511
6769
|
|
|
6512
6770
|
// SPDX-License-Identifier: MIT
|
|
6513
6771
|
const PACKAGE_NAME = '@threadplane/chat';
|
|
6514
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
|
+
*/
|
|
6515
6813
|
function provideChat(config) {
|
|
6516
6814
|
void runLicenseCheck({
|
|
6517
6815
|
package: PACKAGE_NAME,
|
|
@@ -6524,6 +6822,65 @@ function provideChat(config) {
|
|
|
6524
6822
|
]);
|
|
6525
6823
|
}
|
|
6526
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
|
+
|
|
6527
6884
|
// SPDX-License-Identifier: MIT
|
|
6528
6885
|
const CHAT_LIFECYCLE = new InjectionToken('CHAT_LIFECYCLE');
|
|
6529
6886
|
|
|
@@ -11888,19 +12245,115 @@ function a2uiBasicCatalog() {
|
|
|
11888
12245
|
});
|
|
11889
12246
|
}
|
|
11890
12247
|
|
|
11891
|
-
/**
|
|
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
|
+
*/
|
|
11892
12264
|
function action(description, schema, handler) {
|
|
11893
12265
|
return { kind: 'function', description, schema, handler };
|
|
11894
12266
|
}
|
|
11895
|
-
/**
|
|
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
|
+
*/
|
|
11896
12297
|
function view(description, schema, component) {
|
|
11897
|
-
return { kind: 'view', description, schema, component };
|
|
12298
|
+
return { kind: 'view', description, schema, component: component };
|
|
11898
12299
|
}
|
|
11899
|
-
/**
|
|
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
|
+
*/
|
|
11900
12332
|
function ask(description, schema, component) {
|
|
11901
|
-
return { kind: 'ask', description, schema, component };
|
|
12333
|
+
return { kind: 'ask', description, schema, component: component };
|
|
11902
12334
|
}
|
|
11903
|
-
/**
|
|
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
|
+
*/
|
|
11904
12357
|
function tools(map) {
|
|
11905
12358
|
return Object.freeze({ ...map });
|
|
11906
12359
|
}
|
|
@@ -11910,7 +12363,7 @@ function mockAgent(opts = {}) {
|
|
|
11910
12363
|
const messages = signal(opts.messages ?? [], ...(ngDevMode ? [{ debugName: "messages" }] : []));
|
|
11911
12364
|
const status = signal(opts.status ?? 'idle', ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
11912
12365
|
const isLoading = signal(opts.isLoading ?? false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
11913
|
-
const error = signal(opts.error ??
|
|
12366
|
+
const error = signal(opts.error ?? undefined, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
11914
12367
|
const toolCalls = signal(opts.toolCalls ?? [], ...(ngDevMode ? [{ debugName: "toolCalls" }] : []));
|
|
11915
12368
|
const state = signal(opts.state ?? {}, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
11916
12369
|
const interrupt = opts.withInterrupt
|
|
@@ -11935,6 +12388,7 @@ function mockAgent(opts = {}) {
|
|
|
11935
12388
|
events$: opts.events$ ?? EMPTY,
|
|
11936
12389
|
submit: async (input, submitOpts) => { submitCalls.push({ input, opts: submitOpts }); },
|
|
11937
12390
|
stop: async () => { stopCount++; },
|
|
12391
|
+
retry: async () => { return; },
|
|
11938
12392
|
regenerate: async (assistantMessageIndex) => {
|
|
11939
12393
|
// Truncate messages [N..end] and record the call as a synthetic submit so
|
|
11940
12394
|
// tests can assert regenerate behavior via the same submitCalls log.
|
|
@@ -11956,5 +12410,5 @@ function mockAgent(opts = {}) {
|
|
|
11956
12410
|
* Generated bundle index. Do not edit.
|
|
11957
12411
|
*/
|
|
11958
12412
|
|
|
11959
|
-
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, action, ask, buildA2uiActionMessage, cacheplaneMarkdownViews, createA2uiSurfaceStore, createClientToolsCoordinator, createContentClassifier, createParseTreeStore, createPartialArgsBridge, deriveJsonSchema, emitBinding, executeFunctionTool, extractErrorMessage, formatDuration, getInterrupt, getMessageType, isAssistantMessage, isSystemMessage, isToolMessage, isTyping, isUserMessage, messageContent, mockAgent, normalizeEnvelopeArgs, normalizeViewEntry, provideChat, renderMarkdown, startClientToolExecutor, statusColor, submitMessage, surfaceToSpec, toClientToolSpecs, tools, validateArgs, view };
|
|
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 };
|
|
11960
12414
|
//# sourceMappingURL=threadplane-chat.mjs.map
|