@threadplane/chat 0.0.49 → 0.0.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,57 @@
1
- import * as _angular_core from '@angular/core';
2
- import { InjectionToken, Signal, TemplateRef, Type, WritableSignal } from '@angular/core';
3
1
  import * as _threadplane_render from '@threadplane/render';
4
- import { AngularRegistry, RenderEvent, ViewRegistry, RenderViewEntry } from '@threadplane/render';
5
- export { ViewRegistry, toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
6
- import { Observable } from 'rxjs';
7
- import * as _json_render_core from '@json-render/core';
8
- import { StateStore, Spec } from '@json-render/core';
2
+ import { StandardSchemaV1, StandardSchemaInferOutput, AngularRegistry, RenderEvent, ViewRegistry, RenderViewEntry, RenderHost } from '@threadplane/render';
3
+ export { StandardSchemaInferInput, StandardSchemaInferOutput, StandardSchemaV1, ViewRegistry, toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
9
4
  import { A2uiComponentDef, A2uiSurface, A2uiMessage, A2uiActionMessage } from '@threadplane/a2ui';
10
5
  export { A2uiAction, A2uiActionContextEntry, A2uiActionMessage, A2uiChildren, A2uiClientDataModel, A2uiComponent, A2uiComponentDef, A2uiSurface, A2uiTheme, DynamicBoolean, DynamicNumber, DynamicString, isLiteralBoolean, isLiteralNumber, isLiteralString, isPathRef } from '@threadplane/a2ui';
6
+ import * as _angular_core from '@angular/core';
7
+ import { Type, InjectionToken, Signal, TemplateRef, WritableSignal, InputSignal, InputSignalWithTransform } from '@angular/core';
8
+ import * as _json_render_core from '@json-render/core';
9
+ import { StateStore, Spec } from '@json-render/core';
10
+ import { Observable } from 'rxjs';
11
+ import * as _threadplane_chat from '@threadplane/chat';
11
12
  import { PartialJsonParser } from '@cacheplane/partial-json';
12
13
  import { BaseMessage } from '@langchain/core/messages';
13
14
  import * as _cacheplane_partial_markdown from '@cacheplane/partial-markdown';
14
15
  import { CitationDefinition, MarkdownDocumentNode, MarkdownNode, MarkdownParagraphNode, MarkdownHeadingNode, MarkdownBlockquoteNode, MarkdownListNode, MarkdownListItemNode, MarkdownCodeBlockNode, MarkdownThematicBreakNode, MarkdownTextNode, MarkdownEmphasisNode, MarkdownStrongNode, MarkdownStrikethroughNode, MarkdownInlineCodeNode, MarkdownLinkNode, MarkdownAutolinkNode, MarkdownImageNode, MarkdownSoftBreakNode, MarkdownHardBreakNode, MarkdownCitationReferenceNode, MarkdownTableNode, MarkdownTableRowNode, MarkdownTableCellNode } from '@cacheplane/partial-markdown';
15
- import * as _threadplane_chat from '@threadplane/chat';
16
+ import { NavigationExtras } from '@angular/router';
16
17
  import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
17
18
 
19
+ /** Precise authored function tool — what `action()` returns. Carries the schema
20
+ * `S` and the handler's resolved return type `R`. */
21
+ interface FunctionToolDef<S extends StandardSchemaV1 = StandardSchemaV1, R = unknown> {
22
+ readonly kind: 'function';
23
+ readonly description: string;
24
+ readonly schema: S;
25
+ readonly handler: (args: StandardSchemaInferOutput<S>) => R | Promise<R>;
26
+ }
27
+ /** Bivariant union member used only for registry storage/iteration. The handler
28
+ * param is `any` (NOT `never`): `any` is simultaneously a supertype any precise
29
+ * `FunctionToolDef<S,R>` is assignable to under `strictFunctionTypes`, AND
30
+ * callable by internal code that has narrowed by `kind` and parsed runtime args.
31
+ * A `never` param would satisfy the former but break the latter. */
32
+ interface AnyFunctionToolDef {
33
+ readonly kind: 'function';
34
+ readonly description: string;
35
+ readonly schema: StandardSchemaV1;
36
+ readonly handler: (args: any) => unknown | Promise<unknown>;
37
+ }
38
+ interface ViewToolDef<S extends StandardSchemaV1 = StandardSchemaV1, C = unknown> {
39
+ readonly kind: 'view';
40
+ readonly description: string;
41
+ readonly schema: S;
42
+ readonly component: Type<C>;
43
+ }
44
+ interface AskToolDef<S extends StandardSchemaV1 = StandardSchemaV1, C = unknown> {
45
+ readonly kind: 'ask';
46
+ readonly description: string;
47
+ readonly schema: S;
48
+ readonly component: Type<C>;
49
+ }
50
+ /** A client tool the model can call; executed in the browser. */
51
+ type ClientToolDef = AnyFunctionToolDef | ViewToolDef | AskToolDef;
52
+ /** A frozen, name-keyed registry of client tools. */
53
+ type ClientToolRegistry = Readonly<Record<string, ClientToolDef>>;
54
+
18
55
  interface ChatConfig {
19
56
  /** Shared render registry for consumers that read CHAT_CONFIG. */
20
57
  renderRegistry?: AngularRegistry;
@@ -39,6 +76,46 @@ interface ChatConfig {
39
76
  __licensePublicKey?: Uint8Array;
40
77
  }
41
78
  declare const CHAT_CONFIG: InjectionToken<ChatConfig>;
79
+ /**
80
+ * Bootstrap `@threadplane/chat` in an Angular application or standalone
81
+ * component tree.
82
+ *
83
+ * Call this once inside `bootstrapApplication` (or the `providers` array of a
84
+ * root `ApplicationConfig`). It registers the shared {@link ChatConfig} token
85
+ * so every chat component in the tree can read the render registry, avatar
86
+ * label, and assistant display name without explicit prop threading.
87
+ *
88
+ * A license check is fired asynchronously on every call (it never throws; a
89
+ * watermark is shown in non-commercial builds when no valid token is supplied).
90
+ *
91
+ * @param config Options bag that controls the chat feature set:
92
+ * - `renderRegistry` — shared {@link AngularRegistry} wiring tool-view
93
+ * components to their names; pass the value returned by
94
+ * `defineAngularRegistry` from `\@threadplane/render`.
95
+ * - `avatarLabel` — short label shown in the AI avatar bubble (default `"A"`).
96
+ * - `assistantName` — display name shown above assistant messages
97
+ * (default `"Assistant"`).
98
+ * - `license` — signed token from threadplane.ai; omit in development.
99
+ * @returns An `EnvironmentProviders` value suitable for the `providers` array
100
+ * of `bootstrapApplication` or `ApplicationConfig`.
101
+ * @example
102
+ * ```ts
103
+ * // main.ts
104
+ * import { bootstrapApplication } from '@angular/platform-browser';
105
+ * import { provideChat } from '@threadplane/chat';
106
+ * import { defineAngularRegistry, provideRender } from '@threadplane/render';
107
+ * import { DayCardComponent } from './day-card.component';
108
+ *
109
+ * const registry = defineAngularRegistry({ day_card: DayCardComponent });
110
+ *
111
+ * bootstrapApplication(AppComponent, {
112
+ * providers: [
113
+ * provideChat({ renderRegistry: registry, avatarLabel: 'AI' }),
114
+ * provideRender({ registry }),
115
+ * ],
116
+ * });
117
+ * ```
118
+ */
42
119
  declare function provideChat(config: ChatConfig): _angular_core.EnvironmentProviders;
43
120
 
44
121
  type MessageTemplateType = 'human' | 'ai' | 'tool' | 'system' | 'function';
@@ -166,6 +243,12 @@ interface Subagent {
166
243
  name?: string;
167
244
  status: Signal<SubagentStatus>;
168
245
  messages: Signal<Message[]>;
246
+ /**
247
+ * The subagent's own tool calls (name/args/result), referenced by
248
+ * `Message.toolCallIds` in `messages`. Optional: adapters that don't surface
249
+ * subagent tool calls omit it; consumers default to `[]`.
250
+ */
251
+ toolCalls?: Signal<ToolCall[]>;
169
252
  state: Signal<Record<string, unknown>>;
170
253
  }
171
254
 
@@ -210,6 +293,96 @@ interface AgentSubmitOptions {
210
293
  signal?: AbortSignal;
211
294
  }
212
295
 
296
+ /** A client tool spec as shipped to the model / AG-UI RunAgentInput.tools. */
297
+ interface ClientToolSpec {
298
+ readonly name: string;
299
+ readonly description: string;
300
+ readonly parameters: Record<string, unknown>;
301
+ }
302
+ /**
303
+ * Convert a Standard Schema to a JSON Schema for the model's `parameters`.
304
+ * Uses Zod's converter; throws a clear error for non-Zod validators (callers
305
+ * should supply a Zod schema — see the client-tools docs).
306
+ */
307
+ declare function deriveJsonSchema(toolName: string, schema: StandardSchemaV1): Record<string, unknown>;
308
+
309
+ /** The outcome of running a client tool. */
310
+ type ClientToolResult = {
311
+ readonly ok: true;
312
+ readonly value: unknown;
313
+ } | {
314
+ readonly ok: false;
315
+ readonly error: string;
316
+ };
317
+ /**
318
+ * Optional Agent capability that lets the client declare tools to the model
319
+ * and return their results. Implemented per-transport by each adapter
320
+ * (AG-UI: native RunAgentInput.tools + addMessage/re-run; LangGraph: catalog
321
+ * via run input + ToolMessage re-run).
322
+ */
323
+ interface ClientToolsCapability {
324
+ /** Ship the client tool catalog to the model at run start. */
325
+ setCatalog(specs: readonly ClientToolSpec[]): void;
326
+ /** Tool calls the model made for client tools that await a client result. */
327
+ readonly pending: Signal<readonly ToolCall[]>;
328
+ /** Return a client tool's result (or error) and continue the run. */
329
+ resolve(toolCallId: string, result: ClientToolResult): void;
330
+ }
331
+
332
+ /**
333
+ * The failure class of an {@link AgentError}, used to drive UI and retry logic:
334
+ *
335
+ * - `connection` — offline / DNS / connection refused / `fetch` failed. Retryable.
336
+ * - `auth` — `401` / `403`; credentials or API key are wrong. Not retryable.
337
+ * - `server` — a `5xx` (retryable) or a non-auth `4xx` like `400`/`404`/`429` (not retryable).
338
+ * - `interrupted` — the stream closed mid-response after a run had started. Retryable.
339
+ * - `aborted` — the user pressed stop; treated as a graceful idle, not surfaced as an error.
340
+ */
341
+ type AgentErrorKind = 'connection' | 'auth' | 'server' | 'interrupted' | 'aborted';
342
+ /**
343
+ * Structured, classified failure surfaced on `Agent.error`. Extends `Error`, so
344
+ * existing `.message` / `instanceof Error` reads keep working — but adds a
345
+ * machine-readable {@link AgentErrorKind}, a `retryable` flag, an optional HTTP
346
+ * `status`, and the original `cause`.
347
+ *
348
+ * You rarely construct one yourself; adapters normalize raw failures via
349
+ * {@link toAgentError}. Read it off the agent to render legible, cause-specific UI:
350
+ *
351
+ * @example
352
+ * ```ts
353
+ * const err = agent.error(); // AgentError | undefined
354
+ * if (err) {
355
+ * console.warn(err.message); // legible, per-kind copy
356
+ * if (err.kind === 'auth') showApiKeyHelp();
357
+ * if (err.retryable) showRetryButton(); // → agent.retry()
358
+ * }
359
+ * ```
360
+ */
361
+ declare class AgentError extends Error {
362
+ /** The classified failure type. See {@link AgentErrorKind}. */
363
+ readonly kind: AgentErrorKind;
364
+ /** Whether retrying the same request could plausibly succeed:
365
+ * `connection` | `server` (5xx) | `interrupted` → true; `auth` | `aborted` | non-auth `4xx` → false. */
366
+ readonly retryable: boolean;
367
+ /** The HTTP status code when the failure came from an HTTP response. */
368
+ readonly status?: number;
369
+ /** The original raw error this was classified from, preserved for debugging/telemetry. */
370
+ readonly cause: unknown;
371
+ constructor(init: {
372
+ kind: AgentErrorKind;
373
+ message: string;
374
+ retryable: boolean;
375
+ status?: number;
376
+ cause?: unknown;
377
+ });
378
+ }
379
+ /**
380
+ * Default, human-facing copy per {@link AgentErrorKind}. Used as the message when
381
+ * a classified error has no better text. Override by mapping `error.kind` to your
382
+ * own strings in a custom error component.
383
+ */
384
+ declare const AGENT_ERROR_MESSAGES: Record<AgentErrorKind, string>;
385
+
213
386
  /**
214
387
  * Runtime-neutral contract chat primitives consume.
215
388
  *
@@ -223,15 +396,18 @@ interface AgentSubmitOptions {
223
396
  * Invariant: state lives on signals; `events$` carries only things that are
224
397
  * not derivable from signals.
225
398
  */
226
- interface Agent {
399
+ interface Agent<TState = Record<string, unknown>> {
227
400
  messages: Signal<Message[]>;
228
401
  status: Signal<AgentStatus>;
229
402
  isLoading: Signal<boolean>;
230
- error: Signal<unknown>;
403
+ error: Signal<AgentError | undefined>;
231
404
  toolCalls: Signal<ToolCall[]>;
232
- state: Signal<Record<string, unknown>>;
405
+ state: Signal<TState>;
233
406
  submit: (input: AgentSubmitInput, opts?: AgentSubmitOptions) => Promise<void>;
234
407
  stop: () => Promise<void>;
408
+ /** Re-run the last submitted input after a failure. No-op if a run is already
409
+ * in flight or there is nothing to retry. Clears `error` and sets loading. */
410
+ retry: () => Promise<void>;
235
411
  /**
236
412
  * Discards the assistant message at the given index AND all messages after
237
413
  * it, then re-runs the agent against the trimmed conversation tail. The
@@ -244,9 +420,42 @@ interface Agent {
244
420
  regenerate: (assistantMessageIndex: number) => Promise<void>;
245
421
  interrupt?: Signal<AgentInterrupt | undefined>;
246
422
  subagents?: Signal<Map<string, Subagent>>;
423
+ /** Optional: client-declared, client-executed tools (see ClientToolsCapability). */
424
+ clientTools?: ClientToolsCapability;
247
425
  events$: Observable<AgentEvent>;
248
426
  }
249
427
 
428
+ /**
429
+ * Whether `raw` represents an abort (a `DOMException`/`Error` named `AbortError`,
430
+ * or an abort-ish message). Shared by the runtime adapters and {@link toAgentError}
431
+ * so a user-requested stop settles to idle instead of surfacing as an error.
432
+ *
433
+ * @param raw Any thrown/rejected value.
434
+ * @returns `true` if it looks like an abort.
435
+ */
436
+ declare function isAbortError(raw: unknown): boolean;
437
+ /**
438
+ * Classify any raw error into a structured {@link AgentError}.
439
+ *
440
+ * Resolution order (first match wins): an existing `AgentError` is returned
441
+ * unchanged (idempotent) → a user abort → a structured `status`/`cause.status`
442
+ * → network/connection markers → an HTTP-shaped status in the message → a
443
+ * `server` + retryable fallback. The original error is always preserved on
444
+ * `cause`. Runtime adapters call this before setting `Agent.error`; custom
445
+ * backends can call it too (or throw an `AgentError` directly).
446
+ *
447
+ * @param raw Any thrown/rejected value — an `Error`, a `{ status }` object, a string, etc.
448
+ * @returns The classified {@link AgentError} (kind, retryable, status?, cause).
449
+ * @example
450
+ * ```ts
451
+ * const e = toAgentError(new Error('HTTP 500: Internal Server Error'));
452
+ * e.kind; // 'server'
453
+ * e.retryable; // true
454
+ * e.status; // 500
455
+ * ```
456
+ */
457
+ declare function toAgentError(raw: unknown): AgentError;
458
+
250
459
  /**
251
460
  * Runtime-neutral snapshot of a point in an agent's execution history.
252
461
  *
@@ -270,7 +479,7 @@ interface AgentCheckpoint {
270
479
  * implement this. Pure request/response runtimes that don't have checkpoints
271
480
  * should implement plain Agent.
272
481
  */
273
- interface AgentWithHistory extends Agent {
482
+ interface AgentWithHistory<TState = Record<string, unknown>> extends Agent<TState> {
274
483
  history: Signal<AgentCheckpoint[]>;
275
484
  /**
276
485
  * Optional reactive map of `messageId → checkpointId`, computed by
@@ -282,6 +491,27 @@ interface AgentWithHistory extends Agent {
282
491
  messageCheckpoints?: Signal<ReadonlyMap<string, string>>;
283
492
  }
284
493
 
494
+ /** A typed handle that threads a state shape through Angular DI from
495
+ * `provideAgent(ref, …)` to `injectAgent(ref)` without per-call-site
496
+ * restatement of the generic. */
497
+ interface AgentRef<TState> {
498
+ readonly token: InjectionToken<Agent<TState>>;
499
+ }
500
+ /**
501
+ * Create a typed agent handle.
502
+ *
503
+ * @param debugName Optional name shown in Angular DI error messages.
504
+ * @returns An {@link AgentRef} carrying a state-typed `InjectionToken`.
505
+ * @example
506
+ * ```ts
507
+ * interface TripState { day: number; places: string[]; }
508
+ * export const TRIP = createAgentRef<TripState>('trip');
509
+ * // app.config.ts: provideAgent(TRIP, { assistantId: 'trip' })
510
+ * // component: const agent = injectAgent(TRIP); // LangGraphAgent<TripState>
511
+ * ```
512
+ */
513
+ declare function createAgentRef<TState>(debugName?: string): AgentRef<TState>;
514
+
285
515
  type AgentRuntimeTelemetryEvent = 'ngaf:runtime_instance_created' | 'ngaf:runtime_request_created' | 'ngaf:stream_started' | 'ngaf:stream_ended' | 'ngaf:stream_errored';
286
516
  interface AgentRuntimeTelemetryProperties {
287
517
  transport: 'langgraph' | 'ag-ui' | 'custom' | string;
@@ -311,7 +541,7 @@ declare class MessageTemplateDirective {
311
541
  */
312
542
  declare function getMessageType(message: Message): MessageTemplateType;
313
543
  declare class ChatMessageListComponent {
314
- readonly agent: _angular_core.InputSignal<Agent>;
544
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
315
545
  readonly messageTemplates: _angular_core.Signal<readonly MessageTemplateDirective[]>;
316
546
  readonly messages: _angular_core.Signal<Message[]>;
317
547
  readonly getMessageType: typeof getMessageType;
@@ -446,7 +676,7 @@ declare class ChatSuggestionsComponent {
446
676
  */
447
677
  declare function submitMessage(agent: Agent, text: string): string | null;
448
678
  declare class ChatInputComponent {
449
- readonly agent: _angular_core.InputSignal<Agent>;
679
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
450
680
  readonly submitOnEnter: _angular_core.InputSignal<boolean>;
451
681
  readonly placeholder: _angular_core.InputSignal<string>;
452
682
  /** When true (default), shows a stop button while the agent is streaming. */
@@ -472,6 +702,11 @@ declare class ChatInputComponent {
472
702
  constructor();
473
703
  focusTextarea(): void;
474
704
  onSubmit(): void;
705
+ /** Sync the textarea's value into the signal on user input. A direct
706
+ * [value]/(input) pair is used instead of ngModel: NgModel does not
707
+ * reliably write a programmatic clear back to the view under zoneless
708
+ * + OnPush, leaving sent text visible in the composer (audit F1). */
709
+ protected onInput(event: Event): void;
475
710
  /** Abort the current streaming response (if the adapter supports it). */
476
711
  onStop(): void;
477
712
  onKeydown(event: KeyboardEvent): void;
@@ -481,7 +716,7 @@ declare class ChatInputComponent {
481
716
 
482
717
  declare function isTyping(agent: Agent): boolean;
483
718
  declare class ChatTypingIndicatorComponent {
484
- readonly agent: _angular_core.InputSignal<Agent>;
719
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
485
720
  readonly visible: _angular_core.Signal<boolean>;
486
721
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatTypingIndicatorComponent, never>;
487
722
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatTypingIndicatorComponent, "chat-typing-indicator", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -577,15 +812,14 @@ declare class ChatScrollBubbleComponent {
577
812
 
578
813
  declare function extractErrorMessage(error: unknown): string | null;
579
814
  declare class ChatErrorComponent {
580
- readonly agent: _angular_core.InputSignal<Agent>;
581
- readonly errorMessage: _angular_core.Signal<string | null>;
815
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
582
816
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatErrorComponent, never>;
583
817
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatErrorComponent, "chat-error", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
584
818
  }
585
819
 
586
820
  declare function getInterrupt(agent: Agent): AgentInterrupt | undefined;
587
821
  declare class ChatInterruptComponent {
588
- readonly agent: _angular_core.InputSignal<Agent>;
822
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
589
823
  readonly templateRef: _angular_core.Signal<TemplateRef<any> | undefined>;
590
824
  readonly interrupt: _angular_core.Signal<AgentInterrupt | undefined>;
591
825
  defaultText(i: AgentInterrupt): string;
@@ -654,7 +888,7 @@ interface Group {
654
888
  templateRef?: ChatToolCallTemplateDirective;
655
889
  }
656
890
  declare class ChatToolCallsComponent {
657
- readonly agent: _angular_core.InputSignal<Agent>;
891
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
658
892
  readonly message: _angular_core.InputSignal<Message | undefined>;
659
893
  readonly grouping: _angular_core.InputSignal<"auto" | "none">;
660
894
  readonly groupSummary: _angular_core.InputSignal<((name: string, count: number) => string) | undefined>;
@@ -693,7 +927,8 @@ declare class ChatToolCallsComponent {
693
927
  * (and a `status` a component chooses not to declare) are harmless.
694
928
  */
695
929
  declare class ChatToolViewsComponent {
696
- readonly agent: _angular_core.InputSignal<Agent>;
930
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
931
+ readonly events: _angular_core.OutputEmitterRef<RenderEvent>;
697
932
  readonly message: _angular_core.InputSignal<Message | undefined>;
698
933
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
699
934
  readonly store: _angular_core.InputSignal<StateStore | undefined>;
@@ -705,11 +940,11 @@ declare class ChatToolViewsComponent {
705
940
  spec: Spec;
706
941
  }[]>;
707
942
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatToolViewsComponent, never>;
708
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatToolViewsComponent, "chat-tool-views", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "store": { "alias": "store"; "required": false; "isSignal": true; }; "handlers": { "alias": "handlers"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
943
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatToolViewsComponent, "chat-tool-views", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "store": { "alias": "store"; "required": false; "isSignal": true; }; "handlers": { "alias": "handlers"; "required": false; "isSignal": true; }; }, { "events": "events"; }, never, never, true, never>;
709
944
  }
710
945
 
711
946
  declare class ChatSubagentsComponent {
712
- readonly agent: _angular_core.InputSignal<Agent>;
947
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
713
948
  readonly templateRef: _angular_core.Signal<TemplateRef<any> | undefined>;
714
949
  readonly activeSubagents: _angular_core.Signal<Subagent[]>;
715
950
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatSubagentsComponent, never>;
@@ -915,7 +1150,7 @@ declare class ChatGenuiSkeletonComponent {
915
1150
  }
916
1151
 
917
1152
  declare class ChatTimelineComponent {
918
- readonly agent: _angular_core.InputSignal<AgentWithHistory>;
1153
+ readonly agent: _angular_core.InputSignal<AgentWithHistory<Record<string, unknown>>>;
919
1154
  readonly checkpointSelected: _angular_core.OutputEmitterRef<AgentCheckpoint>;
920
1155
  readonly templateRef: _angular_core.Signal<TemplateRef<any> | undefined>;
921
1156
  readonly history: _angular_core.Signal<AgentCheckpoint[]>;
@@ -931,6 +1166,17 @@ declare class ChatGenerativeUiComponent {
931
1166
  readonly handlers: _angular_core.InputSignal<Record<string, (params: Record<string, unknown>) => unknown | Promise<unknown>> | undefined>;
932
1167
  readonly loading: _angular_core.InputSignal<boolean>;
933
1168
  readonly events: _angular_core.OutputEmitterRef<RenderEvent>;
1169
+ /** The bound spec with schema-documented `{ statePath }` prop refs
1170
+ * rewritten to engine-native `{ $bindState }` + `_bindings` so values
1171
+ * resolve against the state store instead of interpolating as
1172
+ * "[object Object]" (F4). */
1173
+ protected readonly normalizedSpec: _angular_core.Signal<Spec | null>;
1174
+ /** Last value this component seeded per state path. Lets the seeding
1175
+ * effect distinguish "still the value we wrote (possibly a partial
1176
+ * chunk from streaming — safe to overwrite with the newer one)" from
1177
+ * "user edited it via a bound control — leave it alone". */
1178
+ private readonly seeded;
1179
+ constructor();
934
1180
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatGenerativeUiComponent, never>;
935
1181
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatGenerativeUiComponent, "chat-generative-ui", never, { "spec": { "alias": "spec"; "required": false; "isSignal": true; }; "registry": { "alias": "registry"; "required": false; "isSignal": true; }; "store": { "alias": "store"; "required": false; "isSignal": true; }; "handlers": { "alias": "handlers"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, { "events": "events"; }, never, never, true, never>;
936
1182
  }
@@ -958,14 +1204,17 @@ declare class ChatWelcomeComponent {
958
1204
  declare class ChatWelcomeSuggestionComponent {
959
1205
  readonly label: _angular_core.InputSignal<string>;
960
1206
  readonly value: _angular_core.InputSignal<string>;
1207
+ /** Optional short description, surfaced as a hover/focus tooltip on the chip. */
1208
+ readonly description: _angular_core.InputSignal<string | undefined>;
961
1209
  readonly selected: _angular_core.OutputEmitterRef<string>;
962
1210
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatWelcomeSuggestionComponent, never>;
963
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatWelcomeSuggestionComponent, "chat-welcome-suggestion", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, { "selected": "selected"; }, never, ["[chatWelcomeSuggestionIcon]"], true, never>;
1211
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatWelcomeSuggestionComponent, "chat-welcome-suggestion", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; "description": { "alias": "description"; "required": false; "isSignal": true; }; }, { "selected": "selected"; }, never, ["[chatWelcomeSuggestionIcon]"], true, never>;
964
1212
  }
965
1213
 
966
1214
  interface ChatSelectOption {
967
1215
  value: string;
968
1216
  label: string;
1217
+ description?: string;
969
1218
  disabled?: boolean;
970
1219
  }
971
1220
  /**
@@ -1046,6 +1295,35 @@ declare class ChatCitationsCardComponent {
1046
1295
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatCitationsCardComponent, "chat-citations-card", never, { "citation": { "alias": "citation"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
1047
1296
  }
1048
1297
 
1298
+ interface ThreadRoutingConfig {
1299
+ /** The app-owned source-of-truth signal for the active thread id. */
1300
+ threadId: WritableSignal<string | null>;
1301
+ /** Router commands for a thread id (or the bare/welcome path when null).
1302
+ * Default: `(id) => (id ? ['/', id] : ['/'])`. */
1303
+ toCommands?: (id: string | null) => unknown[];
1304
+ /** Extract the thread id from a URL (null = bare). Default: last non-empty path segment. */
1305
+ threadIdFromUrl?: (url: string) => string | null;
1306
+ /** Optional async validity check; on `false` the helper redirects to the bare path
1307
+ * (`replaceUrl: true`). LangGraph apps pass `id => threads.getThread(id).then(Boolean)`. */
1308
+ validate?: (id: string) => Promise<boolean>;
1309
+ /** Extras merged into every navigate (default `{ queryParamsHandling: 'preserve' }`). */
1310
+ navigationExtras?: NavigationExtras;
1311
+ }
1312
+ /**
1313
+ * Bind an app-owned `activeThreadId` signal to the URL — restore on load, stamp on change,
1314
+ * validate-or-redirect, with a bare URL meaning "no thread" (welcome). URL is the source of
1315
+ * truth; nothing is written to localStorage. Must be called in an injection context.
1316
+ *
1317
+ * @example
1318
+ * ```ts
1319
+ * export const ACTIVE_THREAD = signal<string | null>(null);
1320
+ * // providers: provideAgent({ threadId: ACTIVE_THREAD, onThreadId: id => ACTIVE_THREAD.set(id) })
1321
+ * const threads = inject(LangGraphThreadsAdapter);
1322
+ * injectThreadRouting({ threadId: ACTIVE_THREAD, validate: id => threads.getThread(id).then(Boolean) });
1323
+ * ```
1324
+ */
1325
+ declare function injectThreadRouting(config: ThreadRoutingConfig): void;
1326
+
1049
1327
  interface ChatLifecycle {
1050
1328
  /** True after `<chat>` initializes with a non-null agent binding. */
1051
1329
  readonly componentReady: Signal<boolean>;
@@ -1159,8 +1437,16 @@ interface ChatRenderEvent {
1159
1437
  }
1160
1438
 
1161
1439
  declare class ChatComponent {
1162
- readonly agent: _angular_core.InputSignal<Agent>;
1440
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
1163
1441
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1442
+ /**
1443
+ * Client-declared tools (`view`/`ask`/`function`) the model may call. When
1444
+ * provided, a coordinator ships their catalog to the agent, runs `function`
1445
+ * tools in the browser, and renders/resolves `view`/`ask` tools through the
1446
+ * same tool-views pipeline as `views`. Additive — leave undefined for the
1447
+ * classic server-tools-only experience.
1448
+ */
1449
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1164
1450
  readonly store: _angular_core.InputSignal<StateStore | undefined>;
1165
1451
  readonly handlers: _angular_core.InputSignal<Record<string, (params: Record<string, unknown>) => unknown | Promise<unknown>>>;
1166
1452
  readonly threads: _angular_core.InputSignal<Thread[]>;
@@ -1209,10 +1495,26 @@ declare class ChatComponent {
1209
1495
  }>;
1210
1496
  private readonly _internalStore;
1211
1497
  readonly resolvedStore: _angular_core.Signal<StateStore | undefined>;
1498
+ /**
1499
+ * Lazily-built client-tools coordinator, memoized on the `clientTools`
1500
+ * registry input. Undefined when no client tools are declared. The
1501
+ * coordinator owns the catalog/executor wiring and the view/ask render
1502
+ * registry; the composition merges and connects it below.
1503
+ */
1504
+ private readonly coordinator;
1505
+ /**
1506
+ * The view registry actually used for rendering tool-views and for
1507
+ * excluding view-backed tool names from default tool-call cards. Merges
1508
+ * the coordinator's `view`/`ask` components (keyed by tool name) into the
1509
+ * user-supplied `views()` so client-declared component tools render through
1510
+ * the same pipeline. Falls back to `views()` when no client tools exist.
1511
+ */
1512
+ protected readonly effectiveViews: _angular_core.Signal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1212
1513
  readonly renderRegistry: _angular_core.Signal<_threadplane_render.AngularRegistry | undefined>;
1213
- /** Tool names that have a registered view (keys of the `views` registry).
1214
- * These render as inline tool-views and are excluded from the default
1215
- * tool-call card so they don't render twice. */
1514
+ /** Tool names that have a registered view (keys of the effective view
1515
+ * registry, including client-declared view/ask tools). These render as
1516
+ * inline tool-views and are excluded from the default tool-call card so
1517
+ * they don't render twice. */
1216
1518
  readonly viewToolNames: _angular_core.Signal<readonly string[]>;
1217
1519
  /** Union of GenUI dispatcher tool names and registered view tool names. */
1218
1520
  readonly excludedToolNames: _angular_core.Signal<readonly string[]>;
@@ -1242,6 +1544,7 @@ declare class ChatComponent {
1242
1544
  protected isReasoningStreaming(message: Message, index: number): boolean;
1243
1545
  private readonly classifiers;
1244
1546
  private readonly destroyRef;
1547
+ private readonly injector;
1245
1548
  private readonly lifecycle;
1246
1549
  private eventsSubscribed;
1247
1550
  /**
@@ -1323,6 +1626,13 @@ declare class ChatComponent {
1323
1626
  }): ContentClassifier;
1324
1627
  clearClassifiers(): void;
1325
1628
  onSpecEvent(event: RenderEvent, messageIndex: number): void;
1629
+ /**
1630
+ * Forwards a render event bubbled up from a `<chat-tool-views>` component
1631
+ * (a client-declared `view`/`ask` tool's rendered UI) to the client-tools
1632
+ * coordinator. The coordinator resolves the matching pending `ask` tool call
1633
+ * when the event is a `result`. No-op when no client tools are wired.
1634
+ */
1635
+ protected onClientToolEvent(event: RenderEvent): void;
1326
1636
  onA2uiAction(message: A2uiActionMessage): void;
1327
1637
  onA2uiEvent(event: RenderEvent, messageIndex: number, surfaceId: string): void;
1328
1638
  /** Regenerate the assistant response at the given message index. */
@@ -1330,15 +1640,17 @@ declare class ChatComponent {
1330
1640
  onRate(message: unknown, value: 'up' | 'down'): void;
1331
1641
  onCopy(message: unknown, content: string): void;
1332
1642
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatComponent, never>;
1333
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatComponent, "chat", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "store": { "alias": "store"; "required": false; "isSignal": true; }; "handlers": { "alias": "handlers"; "required": false; "isSignal": true; }; "threads": { "alias": "threads"; "required": false; "isSignal": true; }; "activeThreadId": { "alias": "activeThreadId"; "required": false; "isSignal": true; }; "welcomeDisabled": { "alias": "welcomeDisabled"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "modelPickerPlaceholder": { "alias": "modelPickerPlaceholder"; "required": false; "isSignal": true; }; "genuiToolNames": { "alias": "genuiToolNames"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "threadSelected": "threadSelected"; "renderEvent": "renderEvent"; "regenerate": "regenerate"; "rate": "rate"; "messageCopy": "messageCopy"; }, never, ["[chatWelcomeSuggestions]", "[chatHeader]", "[chatToolCallTemplate]", "[chatInputModelSelect]"], true, never>;
1643
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatComponent, "chat", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "clientTools": { "alias": "clientTools"; "required": false; "isSignal": true; }; "store": { "alias": "store"; "required": false; "isSignal": true; }; "handlers": { "alias": "handlers"; "required": false; "isSignal": true; }; "threads": { "alias": "threads"; "required": false; "isSignal": true; }; "activeThreadId": { "alias": "activeThreadId"; "required": false; "isSignal": true; }; "welcomeDisabled": { "alias": "welcomeDisabled"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "modelPickerPlaceholder": { "alias": "modelPickerPlaceholder"; "required": false; "isSignal": true; }; "genuiToolNames": { "alias": "genuiToolNames"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "threadSelected": "threadSelected"; "renderEvent": "renderEvent"; "regenerate": "regenerate"; "rate": "rate"; "messageCopy": "messageCopy"; }, never, ["[chatWelcomeSuggestions]", "[chatHeader]", "[chatToolCallTemplate]", "[chatInputModelSelect]"], true, never>;
1334
1644
  }
1335
1645
 
1336
1646
  declare class ChatPopupComponent {
1337
- readonly agent: _angular_core.InputSignal<Agent>;
1647
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
1338
1648
  /** A2UI component catalog forwarded to the inner <chat>. Without it,
1339
1649
  * messages classified as A2UI parse correctly but never mount a
1340
1650
  * surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
1341
1651
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1652
+ /** Frontend-declared client tools forwarded to the inner `<chat>`. */
1653
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1342
1654
  /** Forwarded to the inner <chat>. When non-empty, a model picker pill
1343
1655
  * renders in the chat-input chrome. */
1344
1656
  readonly modelOptions: _angular_core.InputSignal<readonly ChatSelectOption[]>;
@@ -1368,15 +1680,17 @@ declare class ChatPopupComponent {
1368
1680
  openWindow(): void;
1369
1681
  closeWindow(): void;
1370
1682
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatPopupComponent, never>;
1371
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatPopupComponent, "chat-popup", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "shortcut": { "alias": "shortcut"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "open": "openChange"; }, never, ["[chatHeader]", "[chatWelcomeSuggestions]"], true, never>;
1683
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatPopupComponent, "chat-popup", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "clientTools": { "alias": "clientTools"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "shortcut": { "alias": "shortcut"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "open": "openChange"; }, never, ["[chatHeader]", "[chatWelcomeSuggestions]"], true, never>;
1372
1684
  }
1373
1685
 
1374
1686
  declare class ChatSidebarComponent {
1375
- readonly agent: _angular_core.InputSignal<Agent>;
1687
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
1376
1688
  /** A2UI component catalog forwarded to the inner <chat>. Without it,
1377
1689
  * messages classified as A2UI parse correctly but never mount a
1378
1690
  * surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
1379
1691
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1692
+ /** Frontend-declared client tools forwarded to the inner `<chat>`. */
1693
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1380
1694
  /** Forwarded to the inner <chat>. When non-empty, a model picker pill
1381
1695
  * renders in the chat-input chrome. */
1382
1696
  readonly modelOptions: _angular_core.InputSignal<readonly ChatSelectOption[]>;
@@ -1400,11 +1714,11 @@ declare class ChatSidebarComponent {
1400
1714
  openWindow(): void;
1401
1715
  closeWindow(): void;
1402
1716
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatSidebarComponent, never>;
1403
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatSidebarComponent, "chat-sidebar", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "pushContent": { "alias": "pushContent"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "open": "openChange"; }, never, ["*", "[chatSidebarPanelTitle]", "[chatHeader]", "[chatWelcomeSuggestions]"], true, never>;
1717
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatSidebarComponent, "chat-sidebar", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "views": { "alias": "views"; "required": false; "isSignal": true; }; "clientTools": { "alias": "clientTools"; "required": false; "isSignal": true; }; "modelOptions": { "alias": "modelOptions"; "required": false; "isSignal": true; }; "showModelPicker": { "alias": "showModelPicker"; "required": false; "isSignal": true; }; "selectedModel": { "alias": "selectedModel"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "pushContent": { "alias": "pushContent"; "required": false; "isSignal": true; }; }, { "selectedModel": "selectedModelChange"; "open": "openChange"; }, never, ["*", "[chatSidebarPanelTitle]", "[chatHeader]", "[chatWelcomeSuggestions]"], true, never>;
1404
1718
  }
1405
1719
 
1406
1720
  declare class ChatTimelineSliderComponent {
1407
- readonly agent: _angular_core.InputSignal<AgentWithHistory>;
1721
+ readonly agent: _angular_core.InputSignal<AgentWithHistory<Record<string, unknown>>>;
1408
1722
  readonly selectedIndex: _angular_core.WritableSignal<number>;
1409
1723
  readonly history: _angular_core.Signal<AgentCheckpoint[]>;
1410
1724
  readonly replayRequested: _angular_core.OutputEmitterRef<string>;
@@ -1426,7 +1740,7 @@ declare class ChatSidenavComponent {
1426
1740
  readonly projects: _angular_core.InputSignal<Project[] | null>;
1427
1741
  readonly selectedProjectId: _angular_core.InputSignal<string | null>;
1428
1742
  readonly projectActions: _angular_core.InputSignal<ProjectActionAdapter | null>;
1429
- readonly agent: _angular_core.InputSignal<Agent | AgentWithHistory | null>;
1743
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>> | AgentWithHistory<Record<string, unknown>> | null>;
1430
1744
  readonly debug: _angular_core.InputSignal<boolean>;
1431
1745
  readonly newChat: _angular_core.OutputEmitterRef<void>;
1432
1746
  readonly threadSelected: _angular_core.OutputEmitterRef<string>;
@@ -1477,7 +1791,7 @@ declare class ChatSidenavScrimComponent {
1477
1791
 
1478
1792
  type InterruptAction = 'accept' | 'edit' | 'respond' | 'ignore';
1479
1793
  declare class ChatInterruptPanelComponent {
1480
- readonly agent: _angular_core.InputSignal<Agent>;
1794
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
1481
1795
  readonly action: _angular_core.OutputEmitterRef<InterruptAction>;
1482
1796
  readonly interrupt: _angular_core.Signal<AgentInterrupt | undefined>;
1483
1797
  readonly interruptReason: _angular_core.Signal<string>;
@@ -1487,7 +1801,7 @@ declare class ChatInterruptPanelComponent {
1487
1801
 
1488
1802
  type ChatApprovalAction = 'approve' | 'edit' | 'cancel';
1489
1803
  declare class ChatApprovalCardComponent {
1490
- readonly agent: _angular_core.InputSignal<Agent>;
1804
+ readonly agent: _angular_core.InputSignal<Agent<Record<string, unknown>>>;
1491
1805
  readonly matchKind: _angular_core.InputSignal<string | undefined>;
1492
1806
  readonly title: _angular_core.InputSignal<string>;
1493
1807
  readonly showEdit: _angular_core.InputSignal<boolean>;
@@ -1517,7 +1831,9 @@ declare function statusColor(status: SubagentStatus): string;
1517
1831
  declare class ChatSubagentCardComponent {
1518
1832
  readonly subagent: _angular_core.InputSignal<Subagent>;
1519
1833
  readonly state: _angular_core.Signal<TraceState>;
1520
- readonly latestMessageContent: _angular_core.Signal<string>;
1834
+ protected textOf(m: Message): string;
1835
+ protected toolCallsFor(m: Message): ToolCall[];
1836
+ protected toToolCallInfo(tc: ToolCall): ToolCallInfo;
1521
1837
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatSubagentCardComponent, never>;
1522
1838
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatSubagentCardComponent, "chat-subagent-card", never, { "subagent": { "alias": "subagent"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
1523
1839
  }
@@ -1583,9 +1899,9 @@ declare const MARKDOWN_VIEW_REGISTRY: InjectionToken<Readonly<Record<string, _an
1583
1899
  * registry. Each child's `type` is looked up in the registry; the resolved
1584
1900
  * component is rendered with `[node]` bound to that child.
1585
1901
  *
1586
- * Identity-preserving: `track $any(child)` keys on the JS reference of the
1587
- * child node. Because @cacheplane/partial-markdown preserves node identity
1588
- * across pushes, unchanged subtrees never re-render.
1902
+ * Position-stable: `track $index` avoids NG0956 re-creation warnings that
1903
+ * occur when the markdown pipeline re-parses content on every stream delta,
1904
+ * producing new child object references even for unchanged nodes.
1589
1905
  */
1590
1906
  declare class MarkdownChildrenComponent {
1591
1907
  readonly parent: _angular_core.InputSignal<MarkdownNode>;
@@ -1916,14 +2232,15 @@ declare function buildA2uiActionMessage(params: Record<string, unknown>, surface
1916
2232
 
1917
2233
  declare function a2uiBasicCatalog(): ViewRegistry;
1918
2234
 
1919
- /** Emits a data model binding event if the prop has a binding path. */
1920
- declare function emitBinding(emit: (event: string) => void, bindings: Record<string, string> | undefined, prop: string, value: unknown): void;
2235
+ /** Writes a typed value to the render state store if the prop has a binding path. */
2236
+ declare function emitBinding(host: RenderHost, bindings: Record<string, string> | undefined, prop: string, value: unknown): void;
1921
2237
 
1922
2238
  /** v1 textFieldType values from A2uiTextField. */
1923
2239
  type TextFieldType = 'date' | 'longText' | 'number' | 'shortText' | 'obscured';
1924
2240
  declare class A2uiTextFieldComponent {
1925
2241
  private static _idCounter;
1926
2242
  protected readonly _inputId: string;
2243
+ private readonly host;
1927
2244
  readonly label: _angular_core.InputSignal<string>;
1928
2245
  /** v1 prop: text (resolved string value). */
1929
2246
  readonly text: _angular_core.InputSignal<string>;
@@ -1933,7 +2250,6 @@ declare class A2uiTextFieldComponent {
1933
2250
  readonly textFieldType: _angular_core.InputSignal<TextFieldType>;
1934
2251
  readonly validationRegexp: _angular_core.InputSignal<string>;
1935
2252
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1936
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1937
2253
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1938
2254
  readonly loading: _angular_core.InputSignal<boolean>;
1939
2255
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1941,17 +2257,17 @@ declare class A2uiTextFieldComponent {
1941
2257
  protected readonly htmlInputType: _angular_core.Signal<string>;
1942
2258
  onInput(event: Event): void;
1943
2259
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiTextFieldComponent, never>;
1944
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiTextFieldComponent, "a2ui-text-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "text": { "alias": "text"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "textFieldType": { "alias": "textFieldType"; "required": false; "isSignal": true; }; "validationRegexp": { "alias": "validationRegexp"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2260
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiTextFieldComponent, "a2ui-text-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "text": { "alias": "text"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "textFieldType": { "alias": "textFieldType"; "required": false; "isSignal": true; }; "validationRegexp": { "alias": "validationRegexp"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1945
2261
  }
1946
2262
 
1947
2263
  declare class A2uiCheckBoxComponent {
2264
+ private readonly host;
1948
2265
  readonly label: _angular_core.InputSignal<string>;
1949
2266
  /** v1 canonical prop: boolean checked state. */
1950
2267
  readonly value: _angular_core.InputSignal<boolean | undefined>;
1951
2268
  /** Pre-v1 alias retained for back-compat. */
1952
2269
  readonly checked: _angular_core.InputSignal<boolean>;
1953
2270
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1954
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1955
2271
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1956
2272
  readonly loading: _angular_core.InputSignal<boolean>;
1957
2273
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1959,7 +2275,7 @@ declare class A2uiCheckBoxComponent {
1959
2275
  protected readonly effectiveValue: _angular_core.Signal<boolean>;
1960
2276
  onChange(event: Event): void;
1961
2277
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiCheckBoxComponent, never>;
1962
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiCheckBoxComponent, "a2ui-check-box", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2278
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiCheckBoxComponent, "a2ui-check-box", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1963
2279
  }
1964
2280
 
1965
2281
  declare class A2uiButtonComponent {
@@ -1982,6 +2298,7 @@ interface ResolvedOption {
1982
2298
  value: string;
1983
2299
  }
1984
2300
  declare class A2uiMultipleChoiceComponent {
2301
+ private readonly host;
1985
2302
  readonly label: _angular_core.InputSignal<string>;
1986
2303
  /** Resolved current selections from surface-to-spec. Normalized in
1987
2304
  * `selectionsArray` because LLMs sometimes seed the data model with a
@@ -1994,7 +2311,6 @@ declare class A2uiMultipleChoiceComponent {
1994
2311
  /** When ≤ 1 — render as single-select <select>; otherwise multi-select checkboxes. */
1995
2312
  readonly maxAllowedSelections: _angular_core.InputSignal<number>;
1996
2313
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1997
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1998
2314
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1999
2315
  readonly loading: _angular_core.InputSignal<boolean>;
2000
2316
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -2004,12 +2320,13 @@ declare class A2uiMultipleChoiceComponent {
2004
2320
  onSelectChange(event: Event): void;
2005
2321
  onCheckChange(value: string, event: Event): void;
2006
2322
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiMultipleChoiceComponent, never>;
2007
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiMultipleChoiceComponent, "a2ui-multiple-choice", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "selections": { "alias": "selections"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "maxAllowedSelections": { "alias": "maxAllowedSelections"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2323
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiMultipleChoiceComponent, "a2ui-multiple-choice", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "selections": { "alias": "selections"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "maxAllowedSelections": { "alias": "maxAllowedSelections"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2008
2324
  }
2009
2325
 
2010
2326
  declare class A2uiSliderComponent {
2011
2327
  private static _idCounter;
2012
2328
  protected readonly _inputId: string;
2329
+ private readonly host;
2013
2330
  readonly label: _angular_core.InputSignal<string>;
2014
2331
  /** v1 prop: value (resolved DynamicNumber). */
2015
2332
  readonly value: _angular_core.InputSignal<number>;
@@ -2019,19 +2336,19 @@ declare class A2uiSliderComponent {
2019
2336
  readonly maxValue: _angular_core.InputSignal<number>;
2020
2337
  readonly step: _angular_core.InputSignal<number>;
2021
2338
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
2022
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
2023
2339
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
2024
2340
  readonly loading: _angular_core.InputSignal<boolean>;
2025
2341
  readonly childKeys: _angular_core.InputSignal<string[]>;
2026
2342
  readonly spec: _angular_core.InputSignal<Spec | undefined>;
2027
2343
  onInput(event: Event): void;
2028
2344
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiSliderComponent, never>;
2029
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiSliderComponent, "a2ui-slider", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "minValue": { "alias": "minValue"; "required": false; "isSignal": true; }; "maxValue": { "alias": "maxValue"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2345
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiSliderComponent, "a2ui-slider", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "minValue": { "alias": "minValue"; "required": false; "isSignal": true; }; "maxValue": { "alias": "maxValue"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2030
2346
  }
2031
2347
 
2032
2348
  declare class A2uiDateTimeInputComponent {
2033
2349
  private static _idCounter;
2034
2350
  protected readonly _inputId: string;
2351
+ private readonly host;
2035
2352
  readonly label: _angular_core.InputSignal<string>;
2036
2353
  /** v1 prop: value (resolved DynamicString). */
2037
2354
  readonly value: _angular_core.InputSignal<string>;
@@ -2040,7 +2357,6 @@ declare class A2uiDateTimeInputComponent {
2040
2357
  /** v1 prop: enableTime — include time portion. */
2041
2358
  readonly enableTime: _angular_core.InputSignal<boolean>;
2042
2359
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
2043
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
2044
2360
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
2045
2361
  readonly loading: _angular_core.InputSignal<boolean>;
2046
2362
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -2049,7 +2365,7 @@ declare class A2uiDateTimeInputComponent {
2049
2365
  protected readonly htmlInputType: _angular_core.Signal<string>;
2050
2366
  onChange(event: Event): void;
2051
2367
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiDateTimeInputComponent, never>;
2052
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiDateTimeInputComponent, "a2ui-date-time-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "enableDate": { "alias": "enableDate"; "required": false; "isSignal": true; }; "enableTime": { "alias": "enableTime"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2368
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiDateTimeInputComponent, "a2ui-date-time-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "enableDate": { "alias": "enableDate"; "required": false; "isSignal": true; }; "enableTime": { "alias": "enableTime"; "required": false; "isSignal": true; }; "_bindings": { "alias": "_bindings"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2053
2369
  }
2054
2370
 
2055
2371
  type UsageHint = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'caption' | 'body';
@@ -2257,11 +2573,203 @@ declare class A2uiVideoComponent {
2257
2573
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<A2uiVideoComponent, "a2ui-video", never, { "url": { "alias": "url"; "required": false; "isSignal": true; }; "autoPlay": { "alias": "autoPlay"; "required": false; "isSignal": true; }; "controls": { "alias": "controls"; "required": false; "isSignal": true; }; "bindings": { "alias": "bindings"; "required": false; "isSignal": true; }; "emit": { "alias": "emit"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "childKeys": { "alias": "childKeys"; "required": false; "isSignal": true; }; "spec": { "alias": "spec"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2258
2574
  }
2259
2575
 
2576
+ /**
2577
+ * @internal
2578
+ * Identity mapped type that flattens an object type so editor quick-info shows
2579
+ * the expanded shape instead of a raw conditional/mapped-type expression.
2580
+ */
2581
+ type Prettify<T> = {
2582
+ [K in keyof T]: T[K];
2583
+ } & {};
2584
+
2585
+ /** Value type carried by an Angular signal input. */
2586
+ type InputValue<P> = P extends InputSignal<infer T> ? T : P extends InputSignalWithTransform<infer T, infer _U> ? T : never;
2587
+ /** A component instance's declared signal inputs, as a plain prop bag.
2588
+ *
2589
+ * Implementation note: Angular's `InputSignal` and `InputSignalWithTransform`
2590
+ * use `InputSignalNode` in an invariant position, making them invariant in their
2591
+ * type parameters under TypeScript's structural system. `InputSignal<number>`
2592
+ * does NOT extend `InputSignal<unknown>`. We therefore use `any` in the filter
2593
+ * predicate — `any` is a two-way assignability wildcard that correctly subsumes
2594
+ * all concrete instantiations without widening the extracted value type. */
2595
+ type ComponentInputs<C> = {
2596
+ [K in keyof C as C[K] extends InputSignal<any> | InputSignalWithTransform<any, any> ? K : never]: InputValue<C[K]>;
2597
+ };
2598
+ /** STRICT: every prop the schema PRODUCES must be a declared input with an
2599
+ * assignable type. FLEXIBLE: the component may declare extra inputs the schema
2600
+ * doesn't fill. A schema key absent from `Inputs` maps to `never`, so its
2601
+ * (non-never) value fails assignment and the error pins to that prop.
2602
+ *
2603
+ * This mapped type is homomorphic over `keyof Out`, so it preserves the
2604
+ * optionality (`?`) of each schema prop. A consequence: an OPTIONAL schema prop
2605
+ * is accepted against a `required` component input — the compiler cannot know
2606
+ * the model will actually supply it. That residual case (required input not
2607
+ * guaranteed by the schema) is caught at runtime by the schema-readiness mount
2608
+ * gate, which holds the fallback until the streamed props validate. Compile
2609
+ * time blocks structural mismatches; runtime blocks missing-but-required props. */
2610
+ type CompatibleProps<Out, Inputs> = {
2611
+ [K in keyof Out]: K extends keyof Inputs ? Inputs[K] : never;
2612
+ };
2613
+ /** The accepted `component` parameter type for `view`/`ask`: the real component
2614
+ * `Type<C>` when the schema output is compatible, else a labelled error tuple
2615
+ * that surfaces both shapes in the compiler message.
2616
+ *
2617
+ * Implementation note: `C extends ...` (distributive over C) lets TypeScript
2618
+ * infer `C` from the `Type<C>` arm first, then verify the constraint. A bare
2619
+ * conditional on the param type blocks inference when C appears only on the
2620
+ * right-hand side of the inner `extends`. */
2621
+ type AcceptComponent<S extends StandardSchemaV1, C> = C extends (StandardSchemaInferOutput<S> extends CompatibleProps<StandardSchemaInferOutput<S>, ComponentInputs<C>> ? C : never) ? Type<C> : readonly [
2622
+ 'Schema output is not assignable to this component\'s inputs',
2623
+ StandardSchemaInferOutput<S>,
2624
+ ComponentInputs<C>
2625
+ ];
2626
+ /** Reverse helper: derive a component's input prop types FROM a schema, so a
2627
+ * component authored straight from the schema is guaranteed compatible. */
2628
+ type ViewProps<S extends StandardSchemaV1> = Prettify<StandardSchemaInferOutput<S>>;
2629
+
2630
+ /**
2631
+ * Declare an async function tool the model can call; its resolved return value
2632
+ * becomes the tool result shipped back to the model.
2633
+ *
2634
+ * @param description Natural-language description the model sees.
2635
+ * @param schema Standard Schema (e.g. a Zod object) for the arguments; the
2636
+ * handler's argument type is inferred from it.
2637
+ * @param handler Runs in the browser when the model calls the tool; its return
2638
+ * type `R` is carried on the resulting {@link FunctionToolDef}.
2639
+ * @returns A {@link FunctionToolDef} for inclusion in {@link tools}.
2640
+ * @example
2641
+ * ```ts
2642
+ * const move = action('Move a stop', z.object({ fromDay: z.number() }), (a) => a.fromDay);
2643
+ * const registry = tools({ move_stop: move });
2644
+ * ```
2645
+ */
2646
+ declare function action<S extends StandardSchemaV1, R>(description: string, schema: S, handler: (args: StandardSchemaInferOutput<S>) => R | Promise<R>): FunctionToolDef<S, R>;
2647
+ /**
2648
+ * Render-only component tool — the model fills the component's props from the
2649
+ * schema's output; the tool call is auto-acknowledged once the component mounts.
2650
+ *
2651
+ * The component's signal inputs are checked against the schema output type
2652
+ * (strict-but-flexible: every schema key must be a declared input with an
2653
+ * assignable type; the component may declare extra inputs the schema doesn't fill).
2654
+ * Author the component with `ViewProps<typeof schema>` as the input type set to
2655
+ * guarantee the shapes stay aligned.
2656
+ *
2657
+ * @param description Natural-language description the model sees.
2658
+ * @param schema Standard Schema defining the props the model must supply.
2659
+ * @param component Angular component whose signal inputs must be compatible with
2660
+ * the schema output. A type-level error is reported here when they diverge.
2661
+ * @returns A {@link ViewToolDef} for inclusion in {@link tools}.
2662
+ * @example
2663
+ * ```ts
2664
+ * const schema = z.object({ label: z.string(), day: z.number() });
2665
+ * type Inputs = ViewProps<typeof schema>; // { label: string; day: number }
2666
+ *
2667
+ * \@Component({ ... })
2668
+ * class DayCardComponent {
2669
+ * label = input.required<string>();
2670
+ * day = input.required<number>();
2671
+ * }
2672
+ *
2673
+ * const dayCard = view('Show a day card', schema, DayCardComponent);
2674
+ * const registry = tools({ day_card: dayCard });
2675
+ * ```
2676
+ */
2677
+ declare function view<S extends StandardSchemaV1, C>(description: string, schema: S, component: AcceptComponent<S, C>): ViewToolDef<S, C>;
2678
+ /**
2679
+ * Interactive (human-in-the-loop) component tool — the model fills the
2680
+ * component's props from the schema's output; the value the component emits
2681
+ * back to the framework becomes the tool result sent to the model.
2682
+ *
2683
+ * The component's signal inputs are checked against the schema output type
2684
+ * (strict-but-flexible: every schema key must be a declared input with an
2685
+ * assignable type; the component may declare extra inputs the schema doesn't
2686
+ * fill). Author the component with `ViewProps<typeof schema>` to derive input
2687
+ * prop types directly from the schema.
2688
+ *
2689
+ * @param description Natural-language description the model sees.
2690
+ * @param schema Standard Schema defining the props the model must supply.
2691
+ * @param component Angular component whose signal inputs must be compatible with
2692
+ * the schema output. A type-level error is reported here when they diverge.
2693
+ * @returns An {@link AskToolDef} for inclusion in {@link tools}.
2694
+ * @example
2695
+ * ```ts
2696
+ * const schema = z.object({ question: z.string(), options: z.array(z.string()) });
2697
+ * type Inputs = ViewProps<typeof schema>;
2698
+ *
2699
+ * \@Component({ ... })
2700
+ * class ChoiceCardComponent {
2701
+ * question = input.required<string>();
2702
+ * options = input.required<string[]>();
2703
+ * // Emits the chosen option back to the model.
2704
+ * }
2705
+ *
2706
+ * const choice = ask('Ask the user to choose', schema, ChoiceCardComponent);
2707
+ * const registry = tools({ pick_option: choice });
2708
+ * ```
2709
+ */
2710
+ declare function ask<S extends StandardSchemaV1, C>(description: string, schema: S, component: AcceptComponent<S, C>): AskToolDef<S, C>;
2711
+ /**
2712
+ * Collect named client tools into a frozen, name-keyed registry.
2713
+ *
2714
+ * The overload is generic over the entire map (`const M`) so that each tool's
2715
+ * precise type ({@link FunctionToolDef}`<S,R>`, {@link ViewToolDef}`<S,C>`, or
2716
+ * {@link AskToolDef}`<S,C>`) and every literal key are preserved in the
2717
+ * {@link ClientToolRegistry} passed to `provideChat`. This lets downstream
2718
+ * consumers look up individual tools without losing generic information.
2719
+ *
2720
+ * @param map An object literal mapping tool names to tool definitions created
2721
+ * by {@link action}, {@link view}, or {@link ask}.
2722
+ * @returns A frozen `Readonly<M>` where `M` is the exact inferred map shape.
2723
+ * @example
2724
+ * ```ts
2725
+ * const move = action('Move a stop', z.object({ fromDay: z.number() }), (a) => a.fromDay);
2726
+ * const dayCard = view('Show a day card', z.object({ label: z.string() }), DayCardComponent);
2727
+ *
2728
+ * const registry = tools({ move_stop: move, day_card: dayCard });
2729
+ * // registry.move_stop is FunctionToolDef<...>
2730
+ * // registry.day_card is ViewToolDef<...>
2731
+ * ```
2732
+ */
2733
+ declare function tools<const M extends Record<string, ClientToolDef>>(map: M): Readonly<M>;
2734
+
2735
+ /** Validate raw model args against a Standard Schema. */
2736
+ declare function validateArgs(schema: StandardSchemaV1, args: unknown): Promise<{
2737
+ ok: true;
2738
+ value: unknown;
2739
+ } | {
2740
+ ok: false;
2741
+ error: string;
2742
+ }>;
2743
+ /** Validate args, run the handler, and normalize the outcome to a ClientToolResult. */
2744
+ declare function executeFunctionTool(def: AnyFunctionToolDef, rawArgs: unknown): Promise<ClientToolResult>;
2745
+
2746
+ /**
2747
+ * Watches the agent's pending client tool calls and auto-runs FUNCTION tools,
2748
+ * resolving each with its result. View/ask (component) tools are handled by the
2749
+ * rendering layer, not here. No-op if the agent lacks the clientTools
2750
+ * capability. MUST be called in an injection context (sets up an effect).
2751
+ */
2752
+ declare function startClientToolExecutor(agent: Agent, registry: ClientToolRegistry): void;
2753
+
2754
+ interface ClientToolsCoordinator {
2755
+ /** Components for `view`/`ask` tools, keyed by tool name — merge into the chat `views`. */
2756
+ readonly viewRegistry: ViewRegistry;
2757
+ /** Wire the coordinator to an agent: ship the catalog, run function tools, auto-ack view tools.
2758
+ * MUST be called inside an injection context (sets up effects). Safe no-op if the agent lacks
2759
+ * the clientTools capability. */
2760
+ connect(agent: Agent): void;
2761
+ /** Handle a render event bubbled up from a mounted view/ask component (resolves `ask` results). */
2762
+ handleRenderEvent(agent: Agent, event: RenderEvent): void;
2763
+ }
2764
+ /** Build the catalog spec list shipped to the model. */
2765
+ declare function toClientToolSpecs(registry: ClientToolRegistry): ClientToolSpec[];
2766
+ declare function createClientToolsCoordinator(registry: ClientToolRegistry): ClientToolsCoordinator;
2767
+
2260
2768
  interface MockAgent extends Agent {
2261
2769
  messages: WritableSignal<Message[]>;
2262
2770
  status: WritableSignal<AgentStatus>;
2263
2771
  isLoading: WritableSignal<boolean>;
2264
- error: WritableSignal<unknown>;
2772
+ error: WritableSignal<AgentError | undefined>;
2265
2773
  toolCalls: WritableSignal<ToolCall[]>;
2266
2774
  state: WritableSignal<Record<string, unknown>>;
2267
2775
  interrupt?: WritableSignal<AgentInterrupt | undefined>;
@@ -2298,7 +2806,7 @@ interface MockAgentOptions {
2298
2806
  messages?: Message[];
2299
2807
  status?: AgentStatus;
2300
2808
  isLoading?: boolean;
2301
- error?: unknown;
2809
+ error?: AgentError;
2302
2810
  toolCalls?: ToolCall[];
2303
2811
  state?: Record<string, unknown>;
2304
2812
  withInterrupt?: boolean;
@@ -2308,5 +2816,8 @@ interface MockAgentOptions {
2308
2816
  }
2309
2817
  declare function mockAgent(opts?: MockAgentOptions): MockAgent;
2310
2818
 
2311
- export { A2uiAudioPlayerComponent, A2uiButtonComponent, A2uiCardComponent, A2uiCheckBoxComponent, A2uiColumnComponent, A2uiDateTimeInputComponent, A2uiDividerComponent, A2uiIconComponent, A2uiImageComponent, A2uiListComponent, A2uiModalComponent, A2uiMultipleChoiceComponent, A2uiRowComponent, A2uiSliderComponent, A2uiSurfaceComponent, A2uiTabsComponent, A2uiTextComponent, A2uiTextFieldComponent, A2uiVideoComponent, CHAT_CONFIG, CHAT_LIFECYCLE, CHAT_MARKDOWN_STYLES, ChatApprovalCardComponent, ChatCitationCardTemplateDirective, ChatCitationsCardComponent, ChatCitationsComponent, ChatComponent, ChatConfirmDialogComponent, ChatErrorComponent, ChatGenerativeUiComponent, ChatGenuiSkeletonComponent, ChatHistorySearchPaletteComponent, ChatInputComponent, ChatInterruptComponent, ChatInterruptPanelComponent, ChatLauncherButtonComponent, ChatMessageActionsComponent, ChatMessageComponent, ChatMessageListComponent, ChatOverflowMenuComponent, ChatPopupComponent, ChatProjectListComponent, ChatReasoningComponent, ChatScrollBubbleComponent, ChatSelectComponent, ChatSidebarComponent, ChatSidenavComponent, ChatSidenavScrimComponent, ChatStreamingMdComponent, ChatSubagentCardComponent, ChatSubagentsComponent, ChatSuggestionsComponent, ChatThreadListComponent, ChatTimelineComponent, ChatTimelineSliderComponent, ChatToolCallCardComponent, ChatToolCallTemplateDirective, ChatToolCallsComponent, ChatToolViewsComponent, ChatTraceComponent, ChatTypingIndicatorComponent, ChatWelcomeComponent, ChatWelcomeSuggestionComponent, ChatWindowComponent, CitationsResolverService, ICON_AGENT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CHEVRON_UP, ICON_SEND, ICON_TOOL, ICON_WARNING, IS_HEADER_ROW, MARKDOWN_VIEW_REGISTRY, MarkdownAutolinkComponent, MarkdownBlockquoteComponent, MarkdownChildrenComponent, MarkdownCitationReferenceComponent, MarkdownCodeBlockComponent, MarkdownDocumentComponent, MarkdownEmphasisComponent, MarkdownHardBreakComponent, MarkdownHeadingComponent, MarkdownImageComponent, MarkdownInlineCodeComponent, MarkdownLinkComponent, MarkdownListComponent, MarkdownListItemComponent, MarkdownParagraphComponent, MarkdownSoftBreakComponent, MarkdownStrikethroughComponent, MarkdownStrongComponent, MarkdownTableCellComponent, MarkdownTableComponent, MarkdownTableRowComponent, MarkdownTextComponent, MarkdownThematicBreakComponent, MessageTemplateDirective, a2uiBasicCatalog, buildA2uiActionMessage, cacheplaneMarkdownViews, createA2uiSurfaceStore, createContentClassifier, createParseTreeStore, createPartialArgsBridge, emitBinding, extractErrorMessage, formatDuration, getInterrupt, getMessageType, isAssistantMessage, isSystemMessage, isToolMessage, isTyping, isUserMessage, messageContent, mockAgent, normalizeEnvelopeArgs, normalizeViewEntry, provideChat, renderMarkdown, statusColor, submitMessage, surfaceToSpec };
2312
- export type { A2uiComponentView, A2uiSurfaceState, A2uiSurfaceStore, A2uiViewEntry, A2uiViews, Agent, AgentCheckpoint, AgentCustomEvent, AgentEvent, AgentInterrupt, AgentRuntimeTelemetryEvent, AgentRuntimeTelemetryPayload, AgentRuntimeTelemetryProperties, AgentRuntimeTelemetrySink, AgentStateUpdateEvent, AgentStatus, AgentSubmitInput, AgentSubmitOptions, AgentWithHistory, ChatApprovalAction, ChatConfig, ChatLifecycle, ChatMessageRole, ChatRenderEvent, ChatScrollBubbleMode, ChatSelectOption, ChatSidenavMode, ChatToolCallTemplateContext, Citation, ContentBlock, ContentClassifier, ContentType, ElementAccumulationState, InterruptAction, Message, MessageTemplateType, MockAgent, MockAgentOptions, OverflowMenuItem, ParseTreeStore, PartialArgsBridge, Project, ProjectActionAdapter, ResolvedCitation, Role, Subagent, SubagentStatus, Thread, ThreadActionAdapter, ThreadMatch, ToolCall, ToolCallInfo, ToolCallStatus, TraceState };
2819
+ /** Inferred argument type for a schema (alias of StandardSchemaInferOutput). */
2820
+ type ToolArgs<S extends StandardSchemaV1> = StandardSchemaInferOutput<S>;
2821
+
2822
+ 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 };
2823
+ export type { A2uiComponentView, A2uiSurfaceState, A2uiSurfaceStore, A2uiViewEntry, A2uiViews, Agent, AgentCheckpoint, AgentCustomEvent, AgentErrorKind, AgentEvent, AgentInterrupt, AgentRef, AgentRuntimeTelemetryEvent, AgentRuntimeTelemetryPayload, AgentRuntimeTelemetryProperties, AgentRuntimeTelemetrySink, AgentStateUpdateEvent, AgentStatus, AgentSubmitInput, AgentSubmitOptions, AgentWithHistory, AnyFunctionToolDef, AskToolDef, ChatApprovalAction, ChatConfig, ChatLifecycle, ChatMessageRole, ChatRenderEvent, ChatScrollBubbleMode, ChatSelectOption, ChatSidenavMode, ChatToolCallTemplateContext, Citation, ClientToolDef, ClientToolRegistry, ClientToolResult, ClientToolSpec, ClientToolsCapability, ClientToolsCoordinator, ContentBlock, ContentClassifier, ContentType, ElementAccumulationState, FunctionToolDef, InterruptAction, Message, MessageTemplateType, MockAgent, MockAgentOptions, OverflowMenuItem, ParseTreeStore, PartialArgsBridge, Project, ProjectActionAdapter, ResolvedCitation, Role, Subagent, SubagentStatus, Thread, ThreadActionAdapter, ThreadMatch, ThreadRoutingConfig, ToolArgs, ToolCall, ToolCallInfo, ToolCallStatus, TraceState, ViewProps, ViewToolDef };