@threadplane/chat 0.0.47 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadplane/chat",
3
- "version": "0.0.47",
3
+ "version": "0.0.50",
4
4
  "exports": {
5
5
  "./chat.css": "./chat.css",
6
6
  "./themes/default-dark.css": "./themes/default-dark.css",
@@ -30,9 +30,9 @@
30
30
  "@threadplane/telemetry": "*"
31
31
  },
32
32
  "peerDependencies": {
33
+ "zod": "^3.25.0",
33
34
  "@angular/core": "^20.0.0 || ^21.0.0",
34
35
  "@angular/common": "^20.0.0 || ^21.0.0",
35
- "@angular/forms": "^20.0.0 || ^21.0.0",
36
36
  "@angular/platform-browser": "^20.0.0 || ^21.0.0",
37
37
  "@threadplane/licensing": "*",
38
38
  "@threadplane/render": "*",
@@ -1,5 +1,19 @@
1
1
  import { Agent, AgentCheckpoint, AgentWithHistory, Message } from '@threadplane/chat';
2
2
 
3
+ /**
4
+ * Shared config for the adapters' `provideFakeAgent()` helpers
5
+ * (@threadplane/langgraph and @threadplane/ag-ui). Drives an in-process
6
+ * fake backend that streams a canned assistant reply.
7
+ */
8
+ interface FakeAgentConfig {
9
+ /** Assistant reply, streamed token-by-token. */
10
+ tokens?: string[];
11
+ /** Optional reasoning chunks emitted before the text reply. */
12
+ reasoningTokens?: string[];
13
+ /** Milliseconds between successive token emissions. */
14
+ delayMs?: number;
15
+ }
16
+
3
17
  /**
4
18
  * Runs a suite of contract conformance assertions against a factory that
5
19
  * produces a fresh Agent. Adapter packages should call this in their
@@ -36,4 +50,4 @@ declare const REASONING_FIXTURE_EVENTS: AbstractEvent[];
36
50
  declare function assertReasoningFixtureMessages(messages: readonly Message[]): void;
37
51
 
38
52
  export { REASONING_FIXTURE_EVENTS, REASONING_FIXTURE_MESSAGE_ID, REASONING_FIXTURE_REASONING, REASONING_FIXTURE_RESPONSE, assertReasoningFixtureMessages, runAgentConformance, runAgentWithHistoryConformance };
39
- export type { AbstractEvent };
53
+ export type { AbstractEvent, FakeAgentConfig };
@@ -1,18 +1,18 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { InjectionToken, Signal, TemplateRef, Type, WritableSignal } from '@angular/core';
3
3
  import * as _threadplane_render from '@threadplane/render';
4
- import { AngularRegistry, RenderEvent, ViewRegistry, RenderViewEntry } from '@threadplane/render';
5
- export { VIEW_REGISTRY, ViewRegistry, provideViews, toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
4
+ import { AngularRegistry, StandardSchemaV1, RenderEvent, ViewRegistry, RenderViewEntry, RenderHost, StandardSchemaInferOutput } from '@threadplane/render';
5
+ export { ViewRegistry, toRenderRegistry, views, withViews, withoutViews } from '@threadplane/render';
6
6
  import { Observable } from 'rxjs';
7
7
  import * as _json_render_core from '@json-render/core';
8
- import { Spec, StateStore } from '@json-render/core';
8
+ import { StateStore, Spec } from '@json-render/core';
9
+ import * as _threadplane_chat from '@threadplane/chat';
9
10
  import { A2uiComponentDef, A2uiSurface, A2uiMessage, A2uiActionMessage } from '@threadplane/a2ui';
10
11
  export { A2uiAction, A2uiActionContextEntry, A2uiActionMessage, A2uiChildren, A2uiClientDataModel, A2uiComponent, A2uiComponentDef, A2uiSurface, A2uiTheme, DynamicBoolean, DynamicNumber, DynamicString, isLiteralBoolean, isLiteralNumber, isLiteralString, isPathRef } from '@threadplane/a2ui';
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
16
  import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
17
17
 
18
18
  interface ChatConfig {
@@ -210,6 +210,42 @@ interface AgentSubmitOptions {
210
210
  signal?: AbortSignal;
211
211
  }
212
212
 
213
+ /** A client tool spec as shipped to the model / AG-UI RunAgentInput.tools. */
214
+ interface ClientToolSpec {
215
+ readonly name: string;
216
+ readonly description: string;
217
+ readonly parameters: Record<string, unknown>;
218
+ }
219
+ /**
220
+ * Convert a Standard Schema to a JSON Schema for the model's `parameters`.
221
+ * Uses Zod's converter; throws a clear error for non-Zod validators (callers
222
+ * should supply a Zod schema — see the client-tools docs).
223
+ */
224
+ declare function deriveJsonSchema(toolName: string, schema: StandardSchemaV1): Record<string, unknown>;
225
+
226
+ /** The outcome of running a client tool. */
227
+ type ClientToolResult = {
228
+ readonly ok: true;
229
+ readonly value: unknown;
230
+ } | {
231
+ readonly ok: false;
232
+ readonly error: string;
233
+ };
234
+ /**
235
+ * Optional Agent capability that lets the client declare tools to the model
236
+ * and return their results. Implemented per-transport by each adapter
237
+ * (AG-UI: native RunAgentInput.tools + addMessage/re-run; LangGraph: catalog
238
+ * via run input + ToolMessage re-run).
239
+ */
240
+ interface ClientToolsCapability {
241
+ /** Ship the client tool catalog to the model at run start. */
242
+ setCatalog(specs: readonly ClientToolSpec[]): void;
243
+ /** Tool calls the model made for client tools that await a client result. */
244
+ readonly pending: Signal<readonly ToolCall[]>;
245
+ /** Return a client tool's result (or error) and continue the run. */
246
+ resolve(toolCallId: string, result: ClientToolResult): void;
247
+ }
248
+
213
249
  /**
214
250
  * Runtime-neutral contract chat primitives consume.
215
251
  *
@@ -244,6 +280,8 @@ interface Agent {
244
280
  regenerate: (assistantMessageIndex: number) => Promise<void>;
245
281
  interrupt?: Signal<AgentInterrupt | undefined>;
246
282
  subagents?: Signal<Map<string, Subagent>>;
283
+ /** Optional: client-declared, client-executed tools (see ClientToolsCapability). */
284
+ clientTools?: ClientToolsCapability;
247
285
  events$: Observable<AgentEvent>;
248
286
  }
249
287
 
@@ -472,6 +510,11 @@ declare class ChatInputComponent {
472
510
  constructor();
473
511
  focusTextarea(): void;
474
512
  onSubmit(): void;
513
+ /** Sync the textarea's value into the signal on user input. A direct
514
+ * [value]/(input) pair is used instead of ngModel: NgModel does not
515
+ * reliably write a programmatic clear back to the view under zoneless
516
+ * + OnPush, leaving sent text visible in the composer (audit F1). */
517
+ protected onInput(event: Event): void;
475
518
  /** Abort the current streaming response (if the adapter supports it). */
476
519
  onStop(): void;
477
520
  onKeydown(event: KeyboardEvent): void;
@@ -679,6 +722,36 @@ declare class ChatToolCallsComponent {
679
722
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatToolCallsComponent, "chat-tool-calls", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "grouping": { "alias": "grouping"; "required": false; "isSignal": true; }; "groupSummary": { "alias": "groupSummary"; "required": false; "isSignal": true; }; "excludeToolNames": { "alias": "excludeToolNames"; "required": false; "isSignal": true; }; }, {}, ["templates"], never, true, never>;
680
723
  }
681
724
 
725
+ /**
726
+ * Renders a frontend component for a tool call by reusing the chat
727
+ * composition's `views` registry. A tool call whose `name` matches a
728
+ * registry key is bridged into a synthetic one-element render spec
729
+ * (`{ root: name, elements: { [name]: { type: name, props } } }`) and
730
+ * rendered through the existing render-spec pipeline.
731
+ *
732
+ * Props merge the live `args` (present while the call streams) with the
733
+ * `result` (on completion) and always include `status`, so a view
734
+ * component can show its own loading/empty/error states. `RenderElement`
735
+ * filters props down to the component's declared inputs, so extra keys
736
+ * (and a `status` a component chooses not to declare) are harmless.
737
+ */
738
+ declare class ChatToolViewsComponent {
739
+ readonly agent: _angular_core.InputSignal<Agent>;
740
+ readonly events: _angular_core.OutputEmitterRef<RenderEvent>;
741
+ readonly message: _angular_core.InputSignal<Message | undefined>;
742
+ readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
743
+ readonly store: _angular_core.InputSignal<StateStore | undefined>;
744
+ readonly handlers: _angular_core.InputSignal<Record<string, (params: Record<string, unknown>) => unknown | Promise<unknown>>>;
745
+ readonly registry: _angular_core.Signal<_threadplane_render.AngularRegistry | undefined>;
746
+ readonly toolViews: _angular_core.Signal<{
747
+ id: string;
748
+ loading: boolean;
749
+ spec: Spec;
750
+ }[]>;
751
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatToolViewsComponent, never>;
752
+ 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>;
753
+ }
754
+
682
755
  declare class ChatSubagentsComponent {
683
756
  readonly agent: _angular_core.InputSignal<Agent>;
684
757
  readonly templateRef: _angular_core.Signal<TemplateRef<any> | undefined>;
@@ -902,6 +975,17 @@ declare class ChatGenerativeUiComponent {
902
975
  readonly handlers: _angular_core.InputSignal<Record<string, (params: Record<string, unknown>) => unknown | Promise<unknown>> | undefined>;
903
976
  readonly loading: _angular_core.InputSignal<boolean>;
904
977
  readonly events: _angular_core.OutputEmitterRef<RenderEvent>;
978
+ /** The bound spec with schema-documented `{ statePath }` prop refs
979
+ * rewritten to engine-native `{ $bindState }` + `_bindings` so values
980
+ * resolve against the state store instead of interpolating as
981
+ * "[object Object]" (F4). */
982
+ protected readonly normalizedSpec: _angular_core.Signal<Spec | null>;
983
+ /** Last value this component seeded per state path. Lets the seeding
984
+ * effect distinguish "still the value we wrote (possibly a partial
985
+ * chunk from streaming — safe to overwrite with the newer one)" from
986
+ * "user edited it via a bound control — leave it alone". */
987
+ private readonly seeded;
988
+ constructor();
905
989
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatGenerativeUiComponent, never>;
906
990
  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>;
907
991
  }
@@ -1132,6 +1216,14 @@ interface ChatRenderEvent {
1132
1216
  declare class ChatComponent {
1133
1217
  readonly agent: _angular_core.InputSignal<Agent>;
1134
1218
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1219
+ /**
1220
+ * Client-declared tools (`view`/`ask`/`function`) the model may call. When
1221
+ * provided, a coordinator ships their catalog to the agent, runs `function`
1222
+ * tools in the browser, and renders/resolves `view`/`ask` tools through the
1223
+ * same tool-views pipeline as `views`. Additive — leave undefined for the
1224
+ * classic server-tools-only experience.
1225
+ */
1226
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1135
1227
  readonly store: _angular_core.InputSignal<StateStore | undefined>;
1136
1228
  readonly handlers: _angular_core.InputSignal<Record<string, (params: Record<string, unknown>) => unknown | Promise<unknown>>>;
1137
1229
  readonly threads: _angular_core.InputSignal<Thread[]>;
@@ -1180,7 +1272,29 @@ declare class ChatComponent {
1180
1272
  }>;
1181
1273
  private readonly _internalStore;
1182
1274
  readonly resolvedStore: _angular_core.Signal<StateStore | undefined>;
1275
+ /**
1276
+ * Lazily-built client-tools coordinator, memoized on the `clientTools`
1277
+ * registry input. Undefined when no client tools are declared. The
1278
+ * coordinator owns the catalog/executor wiring and the view/ask render
1279
+ * registry; the composition merges and connects it below.
1280
+ */
1281
+ private readonly coordinator;
1282
+ /**
1283
+ * The view registry actually used for rendering tool-views and for
1284
+ * excluding view-backed tool names from default tool-call cards. Merges
1285
+ * the coordinator's `view`/`ask` components (keyed by tool name) into the
1286
+ * user-supplied `views()` so client-declared component tools render through
1287
+ * the same pipeline. Falls back to `views()` when no client tools exist.
1288
+ */
1289
+ protected readonly effectiveViews: _angular_core.Signal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1183
1290
  readonly renderRegistry: _angular_core.Signal<_threadplane_render.AngularRegistry | undefined>;
1291
+ /** Tool names that have a registered view (keys of the effective view
1292
+ * registry, including client-declared view/ask tools). These render as
1293
+ * inline tool-views and are excluded from the default tool-call card so
1294
+ * they don't render twice. */
1295
+ readonly viewToolNames: _angular_core.Signal<readonly string[]>;
1296
+ /** Union of GenUI dispatcher tool names and registered view tool names. */
1297
+ readonly excludedToolNames: _angular_core.Signal<readonly string[]>;
1184
1298
  readonly messageContent: typeof messageContent;
1185
1299
  /**
1186
1300
  * Renderable content for a human-role message bubble. Most human
@@ -1189,7 +1303,7 @@ declare class ChatComponent {
1189
1303
  * on a rendered surface) flow through the same submit channel and
1190
1304
  * land in the message stream as a HumanMessage whose content is a
1191
1305
  * JSON-serialized `A2uiActionMessage`. Showing the raw JSON as if
1192
- * the user typed it leaks the protocol; per the A2UI v0.9 spec
1306
+ * the user typed it leaks the protocol; per the A2UI spec
1193
1307
  * those events resemble tool calls more than user utterances.
1194
1308
  *
1195
1309
  * `a2uiActionLabel` returns a short human-readable label for
@@ -1207,6 +1321,7 @@ declare class ChatComponent {
1207
1321
  protected isReasoningStreaming(message: Message, index: number): boolean;
1208
1322
  private readonly classifiers;
1209
1323
  private readonly destroyRef;
1324
+ private readonly injector;
1210
1325
  private readonly lifecycle;
1211
1326
  private eventsSubscribed;
1212
1327
  /**
@@ -1288,6 +1403,13 @@ declare class ChatComponent {
1288
1403
  }): ContentClassifier;
1289
1404
  clearClassifiers(): void;
1290
1405
  onSpecEvent(event: RenderEvent, messageIndex: number): void;
1406
+ /**
1407
+ * Forwards a render event bubbled up from a `<chat-tool-views>` component
1408
+ * (a client-declared `view`/`ask` tool's rendered UI) to the client-tools
1409
+ * coordinator. The coordinator resolves the matching pending `ask` tool call
1410
+ * when the event is a `result`. No-op when no client tools are wired.
1411
+ */
1412
+ protected onClientToolEvent(event: RenderEvent): void;
1291
1413
  onA2uiAction(message: A2uiActionMessage): void;
1292
1414
  onA2uiEvent(event: RenderEvent, messageIndex: number, surfaceId: string): void;
1293
1415
  /** Regenerate the assistant response at the given message index. */
@@ -1295,7 +1417,7 @@ declare class ChatComponent {
1295
1417
  onRate(message: unknown, value: 'up' | 'down'): void;
1296
1418
  onCopy(message: unknown, content: string): void;
1297
1419
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatComponent, never>;
1298
- 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>;
1420
+ 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>;
1299
1421
  }
1300
1422
 
1301
1423
  declare class ChatPopupComponent {
@@ -1304,6 +1426,8 @@ declare class ChatPopupComponent {
1304
1426
  * messages classified as A2UI parse correctly but never mount a
1305
1427
  * surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
1306
1428
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1429
+ /** Frontend-declared client tools forwarded to the inner `<chat>`. */
1430
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1307
1431
  /** Forwarded to the inner <chat>. When non-empty, a model picker pill
1308
1432
  * renders in the chat-input chrome. */
1309
1433
  readonly modelOptions: _angular_core.InputSignal<readonly ChatSelectOption[]>;
@@ -1333,7 +1457,7 @@ declare class ChatPopupComponent {
1333
1457
  openWindow(): void;
1334
1458
  closeWindow(): void;
1335
1459
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatPopupComponent, never>;
1336
- 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>;
1460
+ 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>;
1337
1461
  }
1338
1462
 
1339
1463
  declare class ChatSidebarComponent {
@@ -1342,6 +1466,8 @@ declare class ChatSidebarComponent {
1342
1466
  * messages classified as A2UI parse correctly but never mount a
1343
1467
  * surface. Pass `a2uiBasicCatalog()` from `@threadplane/chat`. */
1344
1468
  readonly views: _angular_core.InputSignal<Readonly<Record<string, _angular_core.Type<unknown> | _threadplane_render.RenderViewEntry>> | undefined>;
1469
+ /** Frontend-declared client tools forwarded to the inner `<chat>`. */
1470
+ readonly clientTools: _angular_core.InputSignal<Readonly<Record<string, _threadplane_chat.ClientToolDef>> | undefined>;
1345
1471
  /** Forwarded to the inner <chat>. When non-empty, a model picker pill
1346
1472
  * renders in the chat-input chrome. */
1347
1473
  readonly modelOptions: _angular_core.InputSignal<readonly ChatSelectOption[]>;
@@ -1365,7 +1491,7 @@ declare class ChatSidebarComponent {
1365
1491
  openWindow(): void;
1366
1492
  closeWindow(): void;
1367
1493
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatSidebarComponent, never>;
1368
- 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>;
1494
+ 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>;
1369
1495
  }
1370
1496
 
1371
1497
  declare class ChatTimelineSliderComponent {
@@ -1450,6 +1576,28 @@ declare class ChatInterruptPanelComponent {
1450
1576
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatInterruptPanelComponent, "chat-interrupt-panel", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; }, { "action": "action"; }, never, never, true, never>;
1451
1577
  }
1452
1578
 
1579
+ type ChatApprovalAction = 'approve' | 'edit' | 'cancel';
1580
+ declare class ChatApprovalCardComponent {
1581
+ readonly agent: _angular_core.InputSignal<Agent>;
1582
+ readonly matchKind: _angular_core.InputSignal<string | undefined>;
1583
+ readonly title: _angular_core.InputSignal<string>;
1584
+ readonly showEdit: _angular_core.InputSignal<boolean>;
1585
+ readonly action: _angular_core.OutputEmitterRef<ChatApprovalAction>;
1586
+ protected readonly bodyTemplate: _angular_core.Signal<TemplateRef<unknown> | undefined>;
1587
+ private readonly dialogRef;
1588
+ private readonly interrupt;
1589
+ protected readonly payload: _angular_core.Signal<{
1590
+ kind?: unknown;
1591
+ } | undefined>;
1592
+ constructor();
1593
+ protected emit(action: ChatApprovalAction): void;
1594
+ protected onCancelEvent(ev: Event): void;
1595
+ private closeDialog;
1596
+ protected onDialogClose(): void;
1597
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChatApprovalCardComponent, never>;
1598
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChatApprovalCardComponent, "chat-approval-card", never, { "agent": { "alias": "agent"; "required": true; "isSignal": true; }; "matchKind": { "alias": "matchKind"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "showEdit": { "alias": "showEdit"; "required": false; "isSignal": true; }; }, { "action": "action"; }, ["bodyTemplate"], never, true, never>;
1599
+ }
1600
+
1453
1601
  /**
1454
1602
  * Returns a CSS style string for a subagent's status badge.
1455
1603
  * Kept exported for backward compatibility with existing consumers; the
@@ -1526,9 +1674,9 @@ declare const MARKDOWN_VIEW_REGISTRY: InjectionToken<Readonly<Record<string, _an
1526
1674
  * registry. Each child's `type` is looked up in the registry; the resolved
1527
1675
  * component is rendered with `[node]` bound to that child.
1528
1676
  *
1529
- * Identity-preserving: `track $any(child)` keys on the JS reference of the
1530
- * child node. Because @cacheplane/partial-markdown preserves node identity
1531
- * across pushes, unchanged subtrees never re-render.
1677
+ * Position-stable: `track $index` avoids NG0956 re-creation warnings that
1678
+ * occur when the markdown pipeline re-parses content on every stream delta,
1679
+ * producing new child object references even for unchanged nodes.
1532
1680
  */
1533
1681
  declare class MarkdownChildrenComponent {
1534
1682
  readonly parent: _angular_core.InputSignal<MarkdownNode>;
@@ -1859,14 +2007,15 @@ declare function buildA2uiActionMessage(params: Record<string, unknown>, surface
1859
2007
 
1860
2008
  declare function a2uiBasicCatalog(): ViewRegistry;
1861
2009
 
1862
- /** Emits a data model binding event if the prop has a binding path. */
1863
- declare function emitBinding(emit: (event: string) => void, bindings: Record<string, string> | undefined, prop: string, value: unknown): void;
2010
+ /** Writes a typed value to the render state store if the prop has a binding path. */
2011
+ declare function emitBinding(host: RenderHost, bindings: Record<string, string> | undefined, prop: string, value: unknown): void;
1864
2012
 
1865
2013
  /** v1 textFieldType values from A2uiTextField. */
1866
2014
  type TextFieldType = 'date' | 'longText' | 'number' | 'shortText' | 'obscured';
1867
2015
  declare class A2uiTextFieldComponent {
1868
2016
  private static _idCounter;
1869
2017
  protected readonly _inputId: string;
2018
+ private readonly host;
1870
2019
  readonly label: _angular_core.InputSignal<string>;
1871
2020
  /** v1 prop: text (resolved string value). */
1872
2021
  readonly text: _angular_core.InputSignal<string>;
@@ -1876,7 +2025,6 @@ declare class A2uiTextFieldComponent {
1876
2025
  readonly textFieldType: _angular_core.InputSignal<TextFieldType>;
1877
2026
  readonly validationRegexp: _angular_core.InputSignal<string>;
1878
2027
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1879
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1880
2028
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1881
2029
  readonly loading: _angular_core.InputSignal<boolean>;
1882
2030
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1884,17 +2032,17 @@ declare class A2uiTextFieldComponent {
1884
2032
  protected readonly htmlInputType: _angular_core.Signal<string>;
1885
2033
  onInput(event: Event): void;
1886
2034
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiTextFieldComponent, never>;
1887
- 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>;
2035
+ 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>;
1888
2036
  }
1889
2037
 
1890
2038
  declare class A2uiCheckBoxComponent {
2039
+ private readonly host;
1891
2040
  readonly label: _angular_core.InputSignal<string>;
1892
2041
  /** v1 canonical prop: boolean checked state. */
1893
2042
  readonly value: _angular_core.InputSignal<boolean | undefined>;
1894
2043
  /** Pre-v1 alias retained for back-compat. */
1895
2044
  readonly checked: _angular_core.InputSignal<boolean>;
1896
2045
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1897
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1898
2046
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1899
2047
  readonly loading: _angular_core.InputSignal<boolean>;
1900
2048
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1902,7 +2050,7 @@ declare class A2uiCheckBoxComponent {
1902
2050
  protected readonly effectiveValue: _angular_core.Signal<boolean>;
1903
2051
  onChange(event: Event): void;
1904
2052
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiCheckBoxComponent, never>;
1905
- 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>;
2053
+ 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>;
1906
2054
  }
1907
2055
 
1908
2056
  declare class A2uiButtonComponent {
@@ -1925,6 +2073,7 @@ interface ResolvedOption {
1925
2073
  value: string;
1926
2074
  }
1927
2075
  declare class A2uiMultipleChoiceComponent {
2076
+ private readonly host;
1928
2077
  readonly label: _angular_core.InputSignal<string>;
1929
2078
  /** Resolved current selections from surface-to-spec. Normalized in
1930
2079
  * `selectionsArray` because LLMs sometimes seed the data model with a
@@ -1937,7 +2086,6 @@ declare class A2uiMultipleChoiceComponent {
1937
2086
  /** When ≤ 1 — render as single-select <select>; otherwise multi-select checkboxes. */
1938
2087
  readonly maxAllowedSelections: _angular_core.InputSignal<number>;
1939
2088
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1940
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1941
2089
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1942
2090
  readonly loading: _angular_core.InputSignal<boolean>;
1943
2091
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1947,12 +2095,13 @@ declare class A2uiMultipleChoiceComponent {
1947
2095
  onSelectChange(event: Event): void;
1948
2096
  onCheckChange(value: string, event: Event): void;
1949
2097
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiMultipleChoiceComponent, never>;
1950
- 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>;
2098
+ 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>;
1951
2099
  }
1952
2100
 
1953
2101
  declare class A2uiSliderComponent {
1954
2102
  private static _idCounter;
1955
2103
  protected readonly _inputId: string;
2104
+ private readonly host;
1956
2105
  readonly label: _angular_core.InputSignal<string>;
1957
2106
  /** v1 prop: value (resolved DynamicNumber). */
1958
2107
  readonly value: _angular_core.InputSignal<number>;
@@ -1962,19 +2111,19 @@ declare class A2uiSliderComponent {
1962
2111
  readonly maxValue: _angular_core.InputSignal<number>;
1963
2112
  readonly step: _angular_core.InputSignal<number>;
1964
2113
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1965
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1966
2114
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1967
2115
  readonly loading: _angular_core.InputSignal<boolean>;
1968
2116
  readonly childKeys: _angular_core.InputSignal<string[]>;
1969
2117
  readonly spec: _angular_core.InputSignal<Spec | undefined>;
1970
2118
  onInput(event: Event): void;
1971
2119
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiSliderComponent, never>;
1972
- 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>;
2120
+ 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>;
1973
2121
  }
1974
2122
 
1975
2123
  declare class A2uiDateTimeInputComponent {
1976
2124
  private static _idCounter;
1977
2125
  protected readonly _inputId: string;
2126
+ private readonly host;
1978
2127
  readonly label: _angular_core.InputSignal<string>;
1979
2128
  /** v1 prop: value (resolved DynamicString). */
1980
2129
  readonly value: _angular_core.InputSignal<string>;
@@ -1983,7 +2132,6 @@ declare class A2uiDateTimeInputComponent {
1983
2132
  /** v1 prop: enableTime — include time portion. */
1984
2133
  readonly enableTime: _angular_core.InputSignal<boolean>;
1985
2134
  readonly _bindings: _angular_core.InputSignal<Record<string, string>>;
1986
- readonly emit: _angular_core.InputSignal<(event: string) => void>;
1987
2135
  readonly bindings: _angular_core.InputSignal<Record<string, string>>;
1988
2136
  readonly loading: _angular_core.InputSignal<boolean>;
1989
2137
  readonly childKeys: _angular_core.InputSignal<string[]>;
@@ -1992,7 +2140,7 @@ declare class A2uiDateTimeInputComponent {
1992
2140
  protected readonly htmlInputType: _angular_core.Signal<string>;
1993
2141
  onChange(event: Event): void;
1994
2142
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<A2uiDateTimeInputComponent, never>;
1995
- 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>;
2143
+ 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>;
1996
2144
  }
1997
2145
 
1998
2146
  type UsageHint = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'caption' | 'body';
@@ -2200,6 +2348,71 @@ declare class A2uiVideoComponent {
2200
2348
  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>;
2201
2349
  }
2202
2350
 
2351
+ /** A client tool the model can call; executed in the browser. */
2352
+ type ClientToolDef = FunctionToolDef | ViewToolDef | AskToolDef;
2353
+ interface FunctionToolDef<S extends StandardSchemaV1 = StandardSchemaV1> {
2354
+ readonly kind: 'function';
2355
+ readonly description: string;
2356
+ readonly schema: S;
2357
+ readonly handler: (args: StandardSchemaInferOutput<S>) => unknown | Promise<unknown>;
2358
+ }
2359
+ interface ViewToolDef {
2360
+ readonly kind: 'view';
2361
+ readonly description: string;
2362
+ readonly schema: StandardSchemaV1;
2363
+ readonly component: Type<unknown>;
2364
+ }
2365
+ interface AskToolDef {
2366
+ readonly kind: 'ask';
2367
+ readonly description: string;
2368
+ readonly schema: StandardSchemaV1;
2369
+ readonly component: Type<unknown>;
2370
+ }
2371
+ /** A frozen, name-keyed registry of client tools. */
2372
+ type ClientToolRegistry = Readonly<Record<string, ClientToolDef>>;
2373
+
2374
+ /** Async function tool — its resolved return value becomes the tool result. */
2375
+ declare function action<S extends StandardSchemaV1>(description: string, schema: S, handler: (args: StandardSchemaInferOutput<S>) => unknown | Promise<unknown>): FunctionToolDef<S>;
2376
+ /** Render-only component tool — the model fills its props; auto-acknowledged. */
2377
+ declare function view(description: string, schema: StandardSchemaV1, component: Type<unknown>): ClientToolDef;
2378
+ /** Interactive (HITL) component tool — the value it emits becomes the result. */
2379
+ declare function ask(description: string, schema: StandardSchemaV1, component: Type<unknown>): ClientToolDef;
2380
+ /** Collect named client tools into a frozen registry (the key is the tool name). */
2381
+ declare function tools(map: Record<string, ClientToolDef>): ClientToolRegistry;
2382
+
2383
+ /** Validate raw model args against a Standard Schema. */
2384
+ declare function validateArgs(schema: StandardSchemaV1, args: unknown): Promise<{
2385
+ ok: true;
2386
+ value: unknown;
2387
+ } | {
2388
+ ok: false;
2389
+ error: string;
2390
+ }>;
2391
+ /** Validate args, run the handler, and normalize the outcome to a ClientToolResult. */
2392
+ declare function executeFunctionTool(def: FunctionToolDef, rawArgs: unknown): Promise<ClientToolResult>;
2393
+
2394
+ /**
2395
+ * Watches the agent's pending client tool calls and auto-runs FUNCTION tools,
2396
+ * resolving each with its result. View/ask (component) tools are handled by the
2397
+ * rendering layer, not here. No-op if the agent lacks the clientTools
2398
+ * capability. MUST be called in an injection context (sets up an effect).
2399
+ */
2400
+ declare function startClientToolExecutor(agent: Agent, registry: ClientToolRegistry): void;
2401
+
2402
+ interface ClientToolsCoordinator {
2403
+ /** Components for `view`/`ask` tools, keyed by tool name — merge into the chat `views`. */
2404
+ readonly viewRegistry: ViewRegistry;
2405
+ /** Wire the coordinator to an agent: ship the catalog, run function tools, auto-ack view tools.
2406
+ * MUST be called inside an injection context (sets up effects). Safe no-op if the agent lacks
2407
+ * the clientTools capability. */
2408
+ connect(agent: Agent): void;
2409
+ /** Handle a render event bubbled up from a mounted view/ask component (resolves `ask` results). */
2410
+ handleRenderEvent(agent: Agent, event: RenderEvent): void;
2411
+ }
2412
+ /** Build the catalog spec list shipped to the model. */
2413
+ declare function toClientToolSpecs(registry: ClientToolRegistry): ClientToolSpec[];
2414
+ declare function createClientToolsCoordinator(registry: ClientToolRegistry): ClientToolsCoordinator;
2415
+
2203
2416
  interface MockAgent extends Agent {
2204
2417
  messages: WritableSignal<Message[]>;
2205
2418
  status: WritableSignal<AgentStatus>;
@@ -2251,5 +2464,5 @@ interface MockAgentOptions {
2251
2464
  }
2252
2465
  declare function mockAgent(opts?: MockAgentOptions): MockAgent;
2253
2466
 
2254
- 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, 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, 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 };
2255
- export type { A2uiComponentView, A2uiSurfaceState, A2uiSurfaceStore, A2uiViewEntry, A2uiViews, Agent, AgentCheckpoint, AgentCustomEvent, AgentEvent, AgentInterrupt, AgentRuntimeTelemetryEvent, AgentRuntimeTelemetryPayload, AgentRuntimeTelemetryProperties, AgentRuntimeTelemetrySink, AgentStateUpdateEvent, AgentStatus, AgentSubmitInput, AgentSubmitOptions, AgentWithHistory, 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 };
2467
+ export { A2uiAudioPlayerComponent, A2uiButtonComponent, A2uiCardComponent, A2uiCheckBoxComponent, A2uiColumnComponent, A2uiDateTimeInputComponent, A2uiDividerComponent, A2uiIconComponent, A2uiImageComponent, A2uiListComponent, A2uiModalComponent, A2uiMultipleChoiceComponent, A2uiRowComponent, A2uiSliderComponent, A2uiSurfaceComponent, A2uiTabsComponent, A2uiTextComponent, A2uiTextFieldComponent, A2uiVideoComponent, CHAT_CONFIG, CHAT_LIFECYCLE, CHAT_MARKDOWN_STYLES, ChatApprovalCardComponent, ChatCitationCardTemplateDirective, ChatCitationsCardComponent, ChatCitationsComponent, ChatComponent, ChatConfirmDialogComponent, ChatErrorComponent, ChatGenerativeUiComponent, ChatGenuiSkeletonComponent, ChatHistorySearchPaletteComponent, ChatInputComponent, ChatInterruptComponent, ChatInterruptPanelComponent, ChatLauncherButtonComponent, ChatMessageActionsComponent, ChatMessageComponent, ChatMessageListComponent, ChatOverflowMenuComponent, ChatPopupComponent, ChatProjectListComponent, ChatReasoningComponent, ChatScrollBubbleComponent, ChatSelectComponent, ChatSidebarComponent, ChatSidenavComponent, ChatSidenavScrimComponent, ChatStreamingMdComponent, ChatSubagentCardComponent, ChatSubagentsComponent, ChatSuggestionsComponent, ChatThreadListComponent, ChatTimelineComponent, ChatTimelineSliderComponent, ChatToolCallCardComponent, ChatToolCallTemplateDirective, ChatToolCallsComponent, ChatToolViewsComponent, ChatTraceComponent, ChatTypingIndicatorComponent, ChatWelcomeComponent, ChatWelcomeSuggestionComponent, ChatWindowComponent, CitationsResolverService, ICON_AGENT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CHEVRON_UP, ICON_SEND, ICON_TOOL, ICON_WARNING, IS_HEADER_ROW, MARKDOWN_VIEW_REGISTRY, MarkdownAutolinkComponent, MarkdownBlockquoteComponent, MarkdownChildrenComponent, MarkdownCitationReferenceComponent, MarkdownCodeBlockComponent, MarkdownDocumentComponent, MarkdownEmphasisComponent, MarkdownHardBreakComponent, MarkdownHeadingComponent, MarkdownImageComponent, MarkdownInlineCodeComponent, MarkdownLinkComponent, MarkdownListComponent, MarkdownListItemComponent, MarkdownParagraphComponent, MarkdownSoftBreakComponent, MarkdownStrikethroughComponent, MarkdownStrongComponent, MarkdownTableCellComponent, MarkdownTableComponent, MarkdownTableRowComponent, MarkdownTextComponent, MarkdownThematicBreakComponent, MessageTemplateDirective, a2uiBasicCatalog, action, ask, buildA2uiActionMessage, cacheplaneMarkdownViews, createA2uiSurfaceStore, createClientToolsCoordinator, createContentClassifier, createParseTreeStore, createPartialArgsBridge, deriveJsonSchema, emitBinding, executeFunctionTool, extractErrorMessage, formatDuration, getInterrupt, getMessageType, isAssistantMessage, isSystemMessage, isToolMessage, isTyping, isUserMessage, messageContent, mockAgent, normalizeEnvelopeArgs, normalizeViewEntry, provideChat, renderMarkdown, startClientToolExecutor, statusColor, submitMessage, surfaceToSpec, toClientToolSpecs, tools, validateArgs, view };
2468
+ export type { A2uiComponentView, A2uiSurfaceState, A2uiSurfaceStore, A2uiViewEntry, A2uiViews, Agent, AgentCheckpoint, AgentCustomEvent, AgentEvent, AgentInterrupt, AgentRuntimeTelemetryEvent, AgentRuntimeTelemetryPayload, AgentRuntimeTelemetryProperties, AgentRuntimeTelemetrySink, AgentStateUpdateEvent, AgentStatus, AgentSubmitInput, AgentSubmitOptions, AgentWithHistory, 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, ToolCall, ToolCallInfo, ToolCallStatus, TraceState, ViewToolDef };