@threadplane/chat 0.0.51 → 0.0.52
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/fesm2022/threadplane-chat.mjs +246 -119
- package/fesm2022/threadplane-chat.mjs.map +1 -1
- package/package.json +1 -1
- package/types/threadplane-chat.d.ts +141 -21
|
@@ -174,15 +174,55 @@ function toAgentError(raw) {
|
|
|
174
174
|
return make('server', true, raw, undefined, msg);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Type guard narrowing a {@link Message} to `role: 'user'`.
|
|
179
|
+
*
|
|
180
|
+
* @param m The message to test.
|
|
181
|
+
* @returns `true` (and narrows `m`) when the message was sent by the user.
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* const userTurns = agent.messages().filter(isUserMessage);
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
177
187
|
function isUserMessage(m) {
|
|
178
188
|
return m.role === 'user';
|
|
179
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Type guard narrowing a {@link Message} to `role: 'assistant'`.
|
|
192
|
+
*
|
|
193
|
+
* @param m The message to test.
|
|
194
|
+
* @returns `true` (and narrows `m`) when the message came from the assistant.
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* const reply = agent.messages().findLast(isAssistantMessage);
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
180
200
|
function isAssistantMessage(m) {
|
|
181
201
|
return m.role === 'assistant';
|
|
182
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Type guard narrowing a {@link Message} to `role: 'tool'` (a tool result turn).
|
|
205
|
+
*
|
|
206
|
+
* @param m The message to test.
|
|
207
|
+
* @returns `true` (and narrows `m`) when the message is a tool result.
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* if (isToolMessage(m)) console.log(m.toolCallId);
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
183
213
|
function isToolMessage(m) {
|
|
184
214
|
return m.role === 'tool';
|
|
185
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Type guard narrowing a {@link Message} to `role: 'system'`.
|
|
218
|
+
*
|
|
219
|
+
* @param m The message to test.
|
|
220
|
+
* @returns `true` (and narrows `m`) when the message is a system message.
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* const visible = agent.messages().filter((m) => !isSystemMessage(m));
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
186
226
|
function isSystemMessage(m) {
|
|
187
227
|
return m.role === 'system';
|
|
188
228
|
}
|
|
@@ -3148,6 +3188,18 @@ const CHAT_TYPING_INDICATOR_STYLES = `
|
|
|
3148
3188
|
|
|
3149
3189
|
// libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts
|
|
3150
3190
|
// SPDX-License-Identifier: MIT
|
|
3191
|
+
/**
|
|
3192
|
+
* Whether the agent should show a "typing" indicator — it is loading and has
|
|
3193
|
+
* not yet started streaming the assistant's reply.
|
|
3194
|
+
*
|
|
3195
|
+
* @param agent The agent to inspect.
|
|
3196
|
+
* @returns `true` while the agent is awaiting a response but no assistant text
|
|
3197
|
+
* has streamed yet; `false` once tokens arrive or the agent is idle.
|
|
3198
|
+
* @example
|
|
3199
|
+
* ```ts
|
|
3200
|
+
* \@if (isTyping(agent)) { <chat-typing-indicator [agent]="agent" /> }
|
|
3201
|
+
* ```
|
|
3202
|
+
*/
|
|
3151
3203
|
function isTyping(agent) {
|
|
3152
3204
|
if (!agent.isLoading())
|
|
3153
3205
|
return false;
|
|
@@ -4118,6 +4170,18 @@ const CHAT_INTERRUPT_STYLES = `
|
|
|
4118
4170
|
|
|
4119
4171
|
// libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.ts
|
|
4120
4172
|
// SPDX-License-Identifier: MIT
|
|
4173
|
+
/**
|
|
4174
|
+
* Read the agent's current human-in-the-loop interrupt, if any.
|
|
4175
|
+
*
|
|
4176
|
+
* @param agent The agent to inspect.
|
|
4177
|
+
* @returns The pending {@link AgentInterrupt}, or `undefined` when the agent is
|
|
4178
|
+
* not currently waiting on an interrupt.
|
|
4179
|
+
* @example
|
|
4180
|
+
* ```ts
|
|
4181
|
+
* const interrupt = getInterrupt(agent);
|
|
4182
|
+
* if (interrupt) agent.resume('approved');
|
|
4183
|
+
* ```
|
|
4184
|
+
*/
|
|
4121
4185
|
function getInterrupt(agent) {
|
|
4122
4186
|
return agent.interrupt?.();
|
|
4123
4187
|
}
|
|
@@ -4298,6 +4362,99 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
4298
4362
|
`, styles: [":host{font-family:var(--ngaf-chat-font-family);color:var(--ngaf-chat-text)}\n", ":host{display:block}.tcc__name{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-sm, 13px);color:var(--ngaf-chat-text-muted);font-weight:400;padding-left:2px}.tcc__pill{display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:9999px;background:var(--ngaf-chat-surface-alt);color:var(--ngaf-chat-text-muted);font-size:10px;font-weight:500;margin-left:6px;line-height:1.4}.tcc__pill svg{width:10px;height:10px}.tcc__pill[data-status=running] svg{animation:tcc-spin .8s linear infinite}@keyframes tcc-spin{to{transform:rotate(360deg)}}.tcc__section{padding:8px 0}.tcc__section+.tcc__section{border-top:1px solid var(--ngaf-chat-separator)}.tcc__section-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--ngaf-chat-text-muted);margin:0 0 4px}.tcc__section-body{font-family:var(--ngaf-chat-font-mono);font-size:var(--ngaf-chat-font-size-xs);color:var(--ngaf-chat-text);white-space:pre-wrap;overflow-x:auto;margin:0}\n"] }]
|
|
4299
4363
|
}], propDecorators: { toolCall: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolCall", required: true }] }], defaultCollapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultCollapsed", required: false }] }] } });
|
|
4300
4364
|
|
|
4365
|
+
// libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts
|
|
4366
|
+
// SPDX-License-Identifier: MIT
|
|
4367
|
+
/**
|
|
4368
|
+
* Returns a CSS style string for a subagent's status badge.
|
|
4369
|
+
* Kept exported for backward compatibility with existing consumers; the
|
|
4370
|
+
* preferred way to style status visually is via the `data-status` attribute
|
|
4371
|
+
* + CSS selectors (see component styles below).
|
|
4372
|
+
*/
|
|
4373
|
+
function statusColor(status) {
|
|
4374
|
+
switch (status) {
|
|
4375
|
+
case 'pending': return 'background: var(--ngaf-chat-surface-alt); color: var(--ngaf-chat-text-muted);';
|
|
4376
|
+
case 'running': return 'background: var(--ngaf-chat-warning-bg); color: var(--ngaf-chat-warning-text);';
|
|
4377
|
+
case 'complete': return 'color: var(--ngaf-chat-success);';
|
|
4378
|
+
case 'error': return 'background: var(--ngaf-chat-error-bg); color: var(--ngaf-chat-error-text);';
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
function statusToTraceState(s) {
|
|
4382
|
+
switch (s) {
|
|
4383
|
+
case 'pending': return 'pending';
|
|
4384
|
+
case 'running': return 'running';
|
|
4385
|
+
case 'complete': return 'done';
|
|
4386
|
+
case 'error': return 'error';
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
class ChatSubagentCardComponent {
|
|
4390
|
+
subagent = input.required(...(ngDevMode ? [{ debugName: "subagent" }] : []));
|
|
4391
|
+
state = computed(() => statusToTraceState(this.subagent().status()), ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
4392
|
+
textOf(m) {
|
|
4393
|
+
const c = m.content;
|
|
4394
|
+
return typeof c === 'string' ? c : '';
|
|
4395
|
+
}
|
|
4396
|
+
toolCallsFor(m) {
|
|
4397
|
+
const ids = m.toolCallIds ?? [];
|
|
4398
|
+
if (ids.length === 0)
|
|
4399
|
+
return [];
|
|
4400
|
+
const all = this.subagent().toolCalls?.() ?? [];
|
|
4401
|
+
return ids.map((id) => all.find((tc) => tc.id === id)).filter((tc) => !!tc);
|
|
4402
|
+
}
|
|
4403
|
+
toToolCallInfo(tc) {
|
|
4404
|
+
return { id: tc.id, name: tc.name, args: tc.args, result: tc.result, status: tc.status };
|
|
4405
|
+
}
|
|
4406
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4407
|
+
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: `
|
|
4408
|
+
<chat-trace [state]="state()">
|
|
4409
|
+
<span traceLabel>
|
|
4410
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4411
|
+
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4412
|
+
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4413
|
+
</span>
|
|
4414
|
+
<div class="sac__count" traceMeta>{{ subagent().messages().length }} message(s)</div>
|
|
4415
|
+
@for (m of subagent().messages(); track m.id) {
|
|
4416
|
+
<div class="sac__msg" [attr.data-role]="m.role">
|
|
4417
|
+
@if (m.reasoning) {
|
|
4418
|
+
<div class="sac__reasoning">{{ m.reasoning }}</div>
|
|
4419
|
+
}
|
|
4420
|
+
@if (textOf(m); as t) {
|
|
4421
|
+
<chat-streaming-md [content]="t" />
|
|
4422
|
+
}
|
|
4423
|
+
@for (tc of toolCallsFor(m); track tc.id) {
|
|
4424
|
+
<chat-tool-call-card [toolCall]="toToolCallInfo(tc)" />
|
|
4425
|
+
}
|
|
4426
|
+
</div>
|
|
4427
|
+
}
|
|
4428
|
+
</chat-trace>
|
|
4429
|
+
`, 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 });
|
|
4430
|
+
}
|
|
4431
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, decorators: [{
|
|
4432
|
+
type: Component,
|
|
4433
|
+
args: [{ selector: 'chat-subagent-card', standalone: true, imports: [ChatTraceComponent, ChatToolCallCardComponent, ChatStreamingMdComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4434
|
+
<chat-trace [state]="state()">
|
|
4435
|
+
<span traceLabel>
|
|
4436
|
+
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4437
|
+
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4438
|
+
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4439
|
+
</span>
|
|
4440
|
+
<div class="sac__count" traceMeta>{{ subagent().messages().length }} message(s)</div>
|
|
4441
|
+
@for (m of subagent().messages(); track m.id) {
|
|
4442
|
+
<div class="sac__msg" [attr.data-role]="m.role">
|
|
4443
|
+
@if (m.reasoning) {
|
|
4444
|
+
<div class="sac__reasoning">{{ m.reasoning }}</div>
|
|
4445
|
+
}
|
|
4446
|
+
@if (textOf(m); as t) {
|
|
4447
|
+
<chat-streaming-md [content]="t" />
|
|
4448
|
+
}
|
|
4449
|
+
@for (tc of toolCallsFor(m); track tc.id) {
|
|
4450
|
+
<chat-tool-call-card [toolCall]="toToolCallInfo(tc)" />
|
|
4451
|
+
}
|
|
4452
|
+
</div>
|
|
4453
|
+
}
|
|
4454
|
+
</chat-trace>
|
|
4455
|
+
`, 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"] }]
|
|
4456
|
+
}], propDecorators: { subagent: [{ type: i0.Input, args: [{ isSignal: true, alias: "subagent", required: true }] }] } });
|
|
4457
|
+
|
|
4301
4458
|
// libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-call-template.directive.ts
|
|
4302
4459
|
// SPDX-License-Identifier: MIT
|
|
4303
4460
|
/**
|
|
@@ -4426,14 +4583,23 @@ class ChatToolCallsComponent {
|
|
|
4426
4583
|
groups = computed(() => {
|
|
4427
4584
|
const excludeSet = new Set(this.excludeToolNames());
|
|
4428
4585
|
const calls = this.toolCalls().filter(tc => !excludeSet.has(tc.name));
|
|
4586
|
+
const subs = this.agent().subagents?.() ?? new Map();
|
|
4429
4587
|
const groupingMode = this.grouping();
|
|
4430
4588
|
const registry = this.templateRegistry();
|
|
4431
4589
|
const wildcard = registry.get('*');
|
|
4432
4590
|
const out = [];
|
|
4433
4591
|
for (const tc of calls) {
|
|
4592
|
+
// A tool call that spawned a subagent renders as a standalone subagent
|
|
4593
|
+
// card anchored to that call. It never groups with adjacent calls, on
|
|
4594
|
+
// either side: it is its own group and carries a `subagent`, so the next
|
|
4595
|
+
// call can't append to it (a subagent group is never a group target).
|
|
4596
|
+
if (subs.has(tc.id)) {
|
|
4597
|
+
out.push({ name: tc.name, calls: [tc], subagent: subs.get(tc.id) });
|
|
4598
|
+
continue;
|
|
4599
|
+
}
|
|
4434
4600
|
const tpl = registry.get(tc.name) ?? wildcard;
|
|
4435
4601
|
const last = out[out.length - 1];
|
|
4436
|
-
const sameName = last && last.name === tc.name;
|
|
4602
|
+
const sameName = last && !last.subagent && last.name === tc.name;
|
|
4437
4603
|
const canGroup = groupingMode === 'auto' && sameName;
|
|
4438
4604
|
if (canGroup) {
|
|
4439
4605
|
last.calls.push(tc);
|
|
@@ -4467,7 +4633,9 @@ class ChatToolCallsComponent {
|
|
|
4467
4633
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatToolCallsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4468
4634
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ChatToolCallsComponent, isStandalone: true, selector: "chat-tool-calls", inputs: { agent: { classPropertyName: "agent", publicName: "agent", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, grouping: { classPropertyName: "grouping", publicName: "grouping", isSignal: true, isRequired: false, transformFunction: null }, groupSummary: { classPropertyName: "groupSummary", publicName: "groupSummary", isSignal: true, isRequired: false, transformFunction: null }, excludeToolNames: { classPropertyName: "excludeToolNames", publicName: "excludeToolNames", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "templates", predicate: ChatToolCallTemplateDirective, isSignal: true }], ngImport: i0, template: `
|
|
4469
4635
|
@for (group of groups(); track $index) {
|
|
4470
|
-
@if (group.
|
|
4636
|
+
@if (group.subagent) {
|
|
4637
|
+
<chat-subagent-card [subagent]="group.subagent" />
|
|
4638
|
+
} @else if (group.calls.length > 1 && !group.templateRef) {
|
|
4471
4639
|
<!-- Default grouped strip -->
|
|
4472
4640
|
@let expanded = expandedGroups().has($index);
|
|
4473
4641
|
<div class="ctc__group" [attr.data-group]="true" [attr.data-expanded]="expanded">
|
|
@@ -4498,13 +4666,15 @@ class ChatToolCallsComponent {
|
|
|
4498
4666
|
}
|
|
4499
4667
|
}
|
|
4500
4668
|
}
|
|
4501
|
-
`, isInline: true, styles: [":host{display:block;margin-bottom:20px}.ctc__group{border:1px solid var(--ngaf-chat-separator);border-radius:var(--ngaf-chat-radius-card);margin:0 0 4px}.ctc__group-header{display:flex;align-items:center;gap:.5rem;width:100%;padding:8px 12px;background:transparent;border:0;font:inherit;color:var(--ngaf-chat-text);cursor:pointer;text-align:left}.ctc__group-chevron{width:10px;height:10px;transition:transform .12s ease}.ctc__group[data-expanded=true] .ctc__group-chevron{transform:rotate(90deg)}.ctc__group-body{padding:0 12px 8px;border-top:1px solid var(--ngaf-chat-separator)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ChatToolCallCardComponent, selector: "chat-tool-call-card", inputs: ["toolCall", "defaultCollapsed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4669
|
+
`, isInline: true, styles: [":host{display:block;margin-bottom:20px}.ctc__group{border:1px solid var(--ngaf-chat-separator);border-radius:var(--ngaf-chat-radius-card);margin:0 0 4px}.ctc__group-header{display:flex;align-items:center;gap:.5rem;width:100%;padding:8px 12px;background:transparent;border:0;font:inherit;color:var(--ngaf-chat-text);cursor:pointer;text-align:left}.ctc__group-chevron{width:10px;height:10px;transition:transform .12s ease}.ctc__group[data-expanded=true] .ctc__group-chevron{transform:rotate(90deg)}.ctc__group-body{padding:0 12px 8px;border-top:1px solid var(--ngaf-chat-separator)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ChatToolCallCardComponent, selector: "chat-tool-call-card", inputs: ["toolCall", "defaultCollapsed"] }, { kind: "component", type: ChatSubagentCardComponent, selector: "chat-subagent-card", inputs: ["subagent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4502
4670
|
}
|
|
4503
4671
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatToolCallsComponent, decorators: [{
|
|
4504
4672
|
type: Component,
|
|
4505
|
-
args: [{ selector: 'chat-tool-calls', standalone: true, imports: [NgTemplateOutlet, ChatToolCallCardComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4673
|
+
args: [{ selector: 'chat-tool-calls', standalone: true, imports: [NgTemplateOutlet, ChatToolCallCardComponent, ChatSubagentCardComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4506
4674
|
@for (group of groups(); track $index) {
|
|
4507
|
-
@if (group.
|
|
4675
|
+
@if (group.subagent) {
|
|
4676
|
+
<chat-subagent-card [subagent]="group.subagent" />
|
|
4677
|
+
} @else if (group.calls.length > 1 && !group.templateRef) {
|
|
4508
4678
|
<!-- Default grouped strip -->
|
|
4509
4679
|
@let expanded = expandedGroups().has($index);
|
|
4510
4680
|
<div class="ctc__group" [attr.data-group]="true" [attr.data-expanded]="expanded">
|
|
@@ -4778,99 +4948,6 @@ function isRecord$2(v) {
|
|
|
4778
4948
|
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
4779
4949
|
}
|
|
4780
4950
|
|
|
4781
|
-
// libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts
|
|
4782
|
-
// SPDX-License-Identifier: MIT
|
|
4783
|
-
/**
|
|
4784
|
-
* Returns a CSS style string for a subagent's status badge.
|
|
4785
|
-
* Kept exported for backward compatibility with existing consumers; the
|
|
4786
|
-
* preferred way to style status visually is via the `data-status` attribute
|
|
4787
|
-
* + CSS selectors (see component styles below).
|
|
4788
|
-
*/
|
|
4789
|
-
function statusColor(status) {
|
|
4790
|
-
switch (status) {
|
|
4791
|
-
case 'pending': return 'background: var(--ngaf-chat-surface-alt); color: var(--ngaf-chat-text-muted);';
|
|
4792
|
-
case 'running': return 'background: var(--ngaf-chat-warning-bg); color: var(--ngaf-chat-warning-text);';
|
|
4793
|
-
case 'complete': return 'color: var(--ngaf-chat-success);';
|
|
4794
|
-
case 'error': return 'background: var(--ngaf-chat-error-bg); color: var(--ngaf-chat-error-text);';
|
|
4795
|
-
}
|
|
4796
|
-
}
|
|
4797
|
-
function statusToTraceState(s) {
|
|
4798
|
-
switch (s) {
|
|
4799
|
-
case 'pending': return 'pending';
|
|
4800
|
-
case 'running': return 'running';
|
|
4801
|
-
case 'complete': return 'done';
|
|
4802
|
-
case 'error': return 'error';
|
|
4803
|
-
}
|
|
4804
|
-
}
|
|
4805
|
-
class ChatSubagentCardComponent {
|
|
4806
|
-
subagent = input.required(...(ngDevMode ? [{ debugName: "subagent" }] : []));
|
|
4807
|
-
state = computed(() => statusToTraceState(this.subagent().status()), ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
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
|
-
}
|
|
4822
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
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: `
|
|
4824
|
-
<chat-trace [state]="state()">
|
|
4825
|
-
<span traceLabel>
|
|
4826
|
-
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4827
|
-
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4828
|
-
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4829
|
-
</span>
|
|
4830
|
-
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
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>
|
|
4843
|
-
}
|
|
4844
|
-
</chat-trace>
|
|
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 });
|
|
4846
|
-
}
|
|
4847
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatSubagentCardComponent, decorators: [{
|
|
4848
|
-
type: Component,
|
|
4849
|
-
args: [{ selector: 'chat-subagent-card', standalone: true, imports: [ChatTraceComponent, ChatToolCallCardComponent, ChatStreamingMdComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
4850
|
-
<chat-trace [state]="state()">
|
|
4851
|
-
<span traceLabel>
|
|
4852
|
-
<span class="sac__name">{{ subagent().name ?? 'Subagent' }}</span>
|
|
4853
|
-
<span class="sac__id">{{ subagent().toolCallId }}</span>
|
|
4854
|
-
<span class="sac__pill" [attr.data-status]="subagent().status()">{{ subagent().status() }}</span>
|
|
4855
|
-
</span>
|
|
4856
|
-
<div class="sac__count">{{ subagent().messages().length }} message(s)</div>
|
|
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>
|
|
4869
|
-
}
|
|
4870
|
-
</chat-trace>
|
|
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"] }]
|
|
4872
|
-
}], propDecorators: { subagent: [{ type: i0.Input, args: [{ isSignal: true, alias: "subagent", required: true }] }] } });
|
|
4873
|
-
|
|
4874
4951
|
// libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts
|
|
4875
4952
|
// SPDX-License-Identifier: MIT
|
|
4876
4953
|
function activeSubagentsFromAgent(agent) {
|
|
@@ -7441,6 +7518,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
7441
7518
|
}], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], catalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalog", required: true }] }], handlers: [{ type: i0.Input, args: [{ isSignal: true, alias: "handlers", required: false }] }], surfaceFallback: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceFallback", required: false }] }], events: [{ type: i0.Output, args: ["events"] }], action: [{ type: i0.Output, args: ["action"] }] } });
|
|
7442
7519
|
|
|
7443
7520
|
// SPDX-License-Identifier: MIT
|
|
7521
|
+
/**
|
|
7522
|
+
* Create a {@link ParseTreeStore} — feeds streamed JSON chunks through a
|
|
7523
|
+
* partial-JSON parser and exposes the progressively-materialized spec and
|
|
7524
|
+
* per-element accumulation state as signals, so a generative-UI surface can
|
|
7525
|
+
* render while the spec is still arriving.
|
|
7526
|
+
*
|
|
7527
|
+
* @param parser The partial-JSON parser used to incrementally materialize chunks.
|
|
7528
|
+
* @returns A {@link ParseTreeStore}; call `push(chunk)` as bytes stream in.
|
|
7529
|
+
* @example
|
|
7530
|
+
* ```ts
|
|
7531
|
+
* const store = createParseTreeStore(parser);
|
|
7532
|
+
* store.push('{"type":"Car');
|
|
7533
|
+
* store.spec(); // best-effort Spec | null
|
|
7534
|
+
* ```
|
|
7535
|
+
*/
|
|
7444
7536
|
function createParseTreeStore(parser) {
|
|
7445
7537
|
const specSignal = signal(null, ...(ngDevMode ? [{ debugName: "specSignal" }] : []));
|
|
7446
7538
|
const elementStatesSignal = signal(new Map(), ...(ngDevMode ? [{ debugName: "elementStatesSignal" }] : []));
|
|
@@ -7581,6 +7673,19 @@ function resolveProps(value, dataModel) {
|
|
|
7581
7673
|
}
|
|
7582
7674
|
return value;
|
|
7583
7675
|
}
|
|
7676
|
+
/**
|
|
7677
|
+
* Create an {@link A2uiSurfaceStore} — the per-conversation store that buffers
|
|
7678
|
+
* streamed A2UI surface updates, tracks each surface's data model + lifecycle
|
|
7679
|
+
* state, and exposes them as signals for rendering. One store backs a chat
|
|
7680
|
+
* thread's A2UI surfaces.
|
|
7681
|
+
*
|
|
7682
|
+
* @returns A fresh, empty {@link A2uiSurfaceStore}.
|
|
7683
|
+
* @example
|
|
7684
|
+
* ```ts
|
|
7685
|
+
* const store = createA2uiSurfaceStore();
|
|
7686
|
+
* const surfaces = store.surfaces; // Signal<Map<string, A2uiSurface>>
|
|
7687
|
+
* ```
|
|
7688
|
+
*/
|
|
7584
7689
|
function createA2uiSurfaceStore() {
|
|
7585
7690
|
const surfacesSignal = signal(new Map(), ...(ngDevMode ? [{ debugName: "surfacesSignal" }] : []));
|
|
7586
7691
|
const surfaceStatesSignal = signal(new Map(), ...(ngDevMode ? [{ debugName: "surfaceStatesSignal" }] : []));
|
|
@@ -7802,6 +7907,19 @@ function trace(...args) {
|
|
|
7802
7907
|
|
|
7803
7908
|
// SPDX-License-Identifier: MIT
|
|
7804
7909
|
const A2UI_PREFIX = '---a2ui_JSON---';
|
|
7910
|
+
/**
|
|
7911
|
+
* Create a {@link ContentClassifier} — the streaming accumulator that inspects
|
|
7912
|
+
* an assistant message's content as it arrives and classifies it (markdown vs a
|
|
7913
|
+
* generative-UI/A2UI spec), exposing the parsed result and per-element state as
|
|
7914
|
+
* signals so the renderer can switch modes mid-stream.
|
|
7915
|
+
*
|
|
7916
|
+
* @returns A fresh {@link ContentClassifier}; call `dispose()` when done.
|
|
7917
|
+
* @example
|
|
7918
|
+
* ```ts
|
|
7919
|
+
* const cc = createContentClassifier();
|
|
7920
|
+
* effect(() => console.log(cc.type())); // 'pending' | 'markdown' | 'spec'
|
|
7921
|
+
* ```
|
|
7922
|
+
*/
|
|
7805
7923
|
function createContentClassifier() {
|
|
7806
7924
|
const typeSignal = signal('pending', ...(ngDevMode ? [{ debugName: "typeSignal" }] : []));
|
|
7807
7925
|
const markdownSignal = signal('', ...(ngDevMode ? [{ debugName: "markdownSignal" }] : []));
|
|
@@ -9252,7 +9370,6 @@ class ChatComponent {
|
|
|
9252
9370
|
[handlers]="handlers()"
|
|
9253
9371
|
(events)="onClientToolEvent($event)"
|
|
9254
9372
|
/>
|
|
9255
|
-
<chat-subagents [agent]="agent()" />
|
|
9256
9373
|
@if (classified.markdown(); as md) {
|
|
9257
9374
|
<chat-streaming-md [content]="md" [streaming]="agent().isLoading() && i === agent().messages().length - 1" />
|
|
9258
9375
|
}
|
|
@@ -9340,7 +9457,7 @@ class ChatComponent {
|
|
|
9340
9457
|
</div>
|
|
9341
9458
|
</div>
|
|
9342
9459
|
}
|
|
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:
|
|
9460
|
+
`, 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: 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 });
|
|
9344
9461
|
}
|
|
9345
9462
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
9346
9463
|
type: Component,
|
|
@@ -9349,7 +9466,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
9349
9466
|
ChatWindowComponent, ChatMessageListComponent, MessageTemplateDirective, ChatMessageComponent,
|
|
9350
9467
|
ChatInputComponent, ChatTypingIndicatorComponent, ChatErrorComponent,
|
|
9351
9468
|
ChatThreadListComponent, ChatGenerativeUiComponent,
|
|
9352
|
-
ChatStreamingMdComponent, ChatToolCallsComponent, ChatToolViewsComponent,
|
|
9469
|
+
ChatStreamingMdComponent, ChatToolCallsComponent, ChatToolViewsComponent, A2uiSurfaceComponent,
|
|
9353
9470
|
ChatMessageActionsComponent, ChatWelcomeComponent, ChatSelectComponent, ChatReasoningComponent,
|
|
9354
9471
|
ChatScrollBubbleComponent,
|
|
9355
9472
|
], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
@@ -9422,7 +9539,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
9422
9539
|
[handlers]="handlers()"
|
|
9423
9540
|
(events)="onClientToolEvent($event)"
|
|
9424
9541
|
/>
|
|
9425
|
-
<chat-subagents [agent]="agent()" />
|
|
9426
9542
|
@if (classified.markdown(); as md) {
|
|
9427
9543
|
<chat-streaming-md [content]="md" [streaming]="agent().isLoading() && i === agent().messages().length - 1" />
|
|
9428
9544
|
}
|
|
@@ -11179,22 +11295,6 @@ function renderMarkdownToString(content, sanitizer) {
|
|
|
11179
11295
|
return plainTextToHtml(content);
|
|
11180
11296
|
}
|
|
11181
11297
|
|
|
11182
|
-
// SPDX-License-Identifier: MIT
|
|
11183
|
-
/** Chevron down (▼ replacement). 12x12, stroke-based. */
|
|
11184
|
-
const ICON_CHEVRON_DOWN = `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 4.5L6 7.5L9 4.5"/></svg>`;
|
|
11185
|
-
/** Chevron up (▲ replacement). 12x12, stroke-based. */
|
|
11186
|
-
const ICON_CHEVRON_UP = `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7.5L6 4.5L9 7.5"/></svg>`;
|
|
11187
|
-
/** Gear icon (⚙ replacement). 14x14. */
|
|
11188
|
-
const ICON_TOOL = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>`;
|
|
11189
|
-
/** Warning triangle (⚠ replacement). 18x18. */
|
|
11190
|
-
const ICON_WARNING = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>`;
|
|
11191
|
-
/** Robot/agent icon (replacement). 14x14. */
|
|
11192
|
-
const ICON_AGENT = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><line x1="8" y1="16" x2="8" y2="16"/><line x1="16" y1="16" x2="16" y2="16"/></svg>`;
|
|
11193
|
-
/** Check mark replacement. 12x12. */
|
|
11194
|
-
const ICON_CHECK = `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 6L5 8.5L9.5 3.5"/></svg>`;
|
|
11195
|
-
/** Send arrow (for chat input). 16x16. */
|
|
11196
|
-
const ICON_SEND = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 12V4M8 4L4 8M8 4L12 8"/></svg>`;
|
|
11197
|
-
|
|
11198
11298
|
/** Normalize a catalog entry to the `A2uiViewEntry` shape. Bare
|
|
11199
11299
|
* `Type<unknown>` entries are wrapped as `{ component }`; entries
|
|
11200
11300
|
* already in the discriminated shape are returned unchanged. */
|
|
@@ -12222,6 +12322,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
12222
12322
|
}], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], autoPlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoPlay", required: false }] }], controls: [{ type: i0.Input, args: [{ isSignal: true, alias: "controls", required: false }] }], 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 }] }], childKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "childKeys", required: false }] }], spec: [{ type: i0.Input, args: [{ isSignal: true, alias: "spec", required: false }] }] } });
|
|
12223
12323
|
|
|
12224
12324
|
// SPDX-License-Identifier: MIT
|
|
12325
|
+
/**
|
|
12326
|
+
* Build the built-in A2UI component catalog — a {@link ViewRegistry} mapping
|
|
12327
|
+
* the standard A2UI element types (Card, Button, TextField, Image, AudioPlayer,
|
|
12328
|
+
* Video, …) to their Angular renderers. Spread it into `provideViews` (with any
|
|
12329
|
+
* of your own views) so an agent's A2UI surface specs render.
|
|
12330
|
+
*
|
|
12331
|
+
* @returns A {@link ViewRegistry} of the standard A2UI components.
|
|
12332
|
+
* @example
|
|
12333
|
+
* ```ts
|
|
12334
|
+
* providers: [provideViews({ ...a2uiBasicCatalog(), MyWidget: MyWidgetComponent })]
|
|
12335
|
+
* ```
|
|
12336
|
+
*/
|
|
12225
12337
|
function a2uiBasicCatalog() {
|
|
12226
12338
|
return views({
|
|
12227
12339
|
AudioPlayer: A2uiAudioPlayerComponent,
|
|
@@ -12359,6 +12471,21 @@ function tools(map) {
|
|
|
12359
12471
|
}
|
|
12360
12472
|
|
|
12361
12473
|
// SPDX-License-Identifier: MIT
|
|
12474
|
+
/**
|
|
12475
|
+
* Build an in-memory {@link Agent} for tests and stories — no transport, no
|
|
12476
|
+
* network. Every field is a writable signal so a test can drive UI states
|
|
12477
|
+
* (loading, error, interrupts, tool calls, subagents) deterministically.
|
|
12478
|
+
*
|
|
12479
|
+
* @param opts Initial values for the mock's signals; all optional.
|
|
12480
|
+
* @returns A {@link MockAgent} satisfying the full `Agent` contract.
|
|
12481
|
+
* @example
|
|
12482
|
+
* ```ts
|
|
12483
|
+
* const agent = mockAgent({
|
|
12484
|
+
* messages: [{ id: '1', role: 'assistant', content: 'Hi' }],
|
|
12485
|
+
* isLoading: true,
|
|
12486
|
+
* });
|
|
12487
|
+
* ```
|
|
12488
|
+
*/
|
|
12362
12489
|
function mockAgent(opts = {}) {
|
|
12363
12490
|
const messages = signal(opts.messages ?? [], ...(ngDevMode ? [{ debugName: "messages" }] : []));
|
|
12364
12491
|
const status = signal(opts.status ?? 'idle', ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
@@ -12410,5 +12537,5 @@ function mockAgent(opts = {}) {
|
|
|
12410
12537
|
* Generated bundle index. Do not edit.
|
|
12411
12538
|
*/
|
|
12412
12539
|
|
|
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,
|
|
12540
|
+
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, 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, 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, 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, toAgentError, toClientToolSpecs, tools, validateArgs, view };
|
|
12414
12541
|
//# sourceMappingURL=threadplane-chat.mjs.map
|