@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.
@@ -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.calls.length > 1 && !group.templateRef) {
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.calls.length > 1 && !group.templateRef) {
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: ChatSubagentsComponent, selector: "chat-subagents", inputs: ["agent"] }, { kind: "component", type: A2uiSurfaceComponent, selector: "a2ui-surface", inputs: ["surface", "state", "catalog", "handlers", "surfaceFallback"], outputs: ["events", "action"] }, { kind: "component", type: ChatMessageActionsComponent, selector: "chat-message-actions", inputs: ["content", "disabled"], outputs: ["regenerate", "rate", "contentCopied"] }, { kind: "component", type: ChatWelcomeComponent, selector: "chat-welcome" }, { kind: "component", type: ChatSelectComponent, selector: "chat-select", inputs: ["options", "value", "placeholder", "disabled", "menuLabel"], outputs: ["valueChange"] }, { kind: "component", type: ChatReasoningComponent, selector: "chat-reasoning", inputs: ["content", "isStreaming", "durationMs", "label", "defaultExpanded"] }, { kind: "component", type: ChatScrollBubbleComponent, selector: "chat-scroll-bubble", inputs: ["mode"], outputs: ["clicked"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
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, ChatSubagentsComponent, A2uiSurfaceComponent,
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, 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 };
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