@tylertech/forge-ai 0.14.0 → 0.15.1

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.
Files changed (47) hide show
  1. package/custom-elements.json +417 -153
  2. package/dist/ai-agent-selector/ai-agent-selector.mjs +1 -1
  3. package/dist/ai-chat-header/ai-chat-header.d.ts +5 -0
  4. package/dist/ai-chat-header/ai-chat-header.mjs +9 -3
  5. package/dist/ai-chat-header/ai-chat-header.scss.mjs +1 -1
  6. package/dist/ai-chatbot/agent-adapter.d.ts +1 -0
  7. package/dist/ai-chatbot/ai-chatbot-base.mjs +0 -1
  8. package/dist/ai-chatbot/ai-chatbot.d.ts +5 -1
  9. package/dist/ai-chatbot/ai-chatbot.mjs +18 -5
  10. package/dist/ai-chatbot/index.d.ts +1 -0
  11. package/dist/ai-chatbot/index.mjs +4 -1
  12. package/dist/ai-chatbot/message-state-controller.d.ts +8 -11
  13. package/dist/ai-chatbot/message-state-controller.mjs +7 -129
  14. package/dist/ai-chatbot/request-serialization.d.ts +33 -0
  15. package/dist/ai-chatbot/request-serialization.mjs +31 -0
  16. package/dist/ai-chatbot/types.d.ts +0 -73
  17. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.d.ts +14 -2
  18. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.mjs +86 -12
  19. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.scss.mjs +1 -1
  20. package/dist/ai-conversations-panel/ai-conversations-panel.d.ts +10 -0
  21. package/dist/ai-conversations-panel/ai-conversations-panel.mjs +68 -7
  22. package/dist/ai-conversations-panel/ai-conversations-panel.scss.mjs +1 -1
  23. package/dist/ai-dialog/ai-dialog.mjs +1 -1
  24. package/dist/ai-dropdown-menu/ai-dropdown-menu.mjs +1 -1
  25. package/dist/ai-dropdown-menu/index.d.ts +1 -1
  26. package/dist/ai-edit-thread/ai-edit-thread.d.ts +5 -0
  27. package/dist/ai-edit-thread/ai-edit-thread.mjs +16 -9
  28. package/dist/ai-error-message/ai-error-message.d.ts +7 -1
  29. package/dist/ai-error-message/ai-error-message.mjs +40 -5
  30. package/dist/ai-error-message/ai-error-message.scss.mjs +1 -1
  31. package/dist/ai-error-message/index.d.ts +1 -0
  32. package/dist/ai-fab/ai-fab.d.ts +2 -0
  33. package/dist/ai-fab/ai-fab.mjs +5 -1
  34. package/dist/ai-icon-button/ai-icon-button.mjs +4 -1
  35. package/dist/ai-message-thread/ai-message-thread.mjs +1 -1
  36. package/dist/ai-sidebar/ai-sidebar.mjs +2 -2
  37. package/dist/ai-thread-actions-menu/ai-thread-actions-menu.d.ts +5 -0
  38. package/dist/ai-thread-actions-menu/ai-thread-actions-menu.mjs +6 -2
  39. package/dist/ai-threads-search/ai-threads-search.d.ts +26 -2
  40. package/dist/ai-threads-search/ai-threads-search.mjs +155 -35
  41. package/dist/ai-threads-search/ai-threads-search.scss.mjs +1 -1
  42. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.scss.mjs +1 -1
  43. package/dist/ai-voice-input/ai-voice-input.mjs +2 -2
  44. package/dist/core/chatbot-core-controller.mjs +6 -8
  45. package/dist/core/popover/popover.mjs +3 -0
  46. package/dist/index.mjs +4 -1
  47. package/package.json +1 -1
@@ -58,7 +58,7 @@ class MessageStateController {
58
58
  this.#updateResponseInItems();
59
59
  this.#notifyStateChange();
60
60
  }
61
- addTextToResponse(messageId, content, event) {
61
+ addTextToResponse(messageId, content) {
62
62
  const response = this._activeResponse ?? this.startResponse();
63
63
  response.isThinking = false;
64
64
  const lastChild = response.children[response.children.length - 1];
@@ -68,18 +68,10 @@ class MessageStateController {
68
68
  } else {
69
69
  response.children.push({ type: "text", messageId, content, status: "streaming" });
70
70
  }
71
- if (event) {
72
- this.#appendEventToResponse({
73
- type: "message-start",
74
- timestamp: Date.now(),
75
- data: event,
76
- rawEvent: event.rawEvent
77
- });
78
- }
79
71
  this.#updateResponseInItems();
80
72
  this.#notifyStateChange();
81
73
  }
82
- appendTextDelta(messageId, delta, event) {
74
+ appendTextDelta(messageId, delta) {
83
75
  const response = this._activeResponse ?? this.startResponse();
84
76
  response.isThinking = false;
85
77
  const lastChild = response.children[response.children.length - 1];
@@ -88,18 +80,10 @@ class MessageStateController {
88
80
  } else {
89
81
  response.children.push({ type: "text", messageId, content: delta, status: "streaming" });
90
82
  }
91
- if (event) {
92
- this.#appendEventToResponse({
93
- type: "message-delta",
94
- timestamp: Date.now(),
95
- data: event,
96
- rawEvent: event.rawEvent
97
- });
98
- }
99
83
  this.#updateResponseInItems();
100
84
  this.#notifyStateChange();
101
85
  }
102
- markTextComplete(messageId, event) {
86
+ markTextComplete(messageId) {
103
87
  if (!this._activeResponse) {
104
88
  return;
105
89
  }
@@ -107,37 +91,19 @@ class MessageStateController {
107
91
  if (textChild && textChild.type === "text") {
108
92
  textChild.status = "complete";
109
93
  }
110
- if (event) {
111
- this.#appendEventToResponse({
112
- type: "message-end",
113
- timestamp: Date.now(),
114
- data: event,
115
- rawEvent: event.rawEvent
116
- });
117
- }
118
94
  this.#updateResponseInItems();
119
95
  this.#notifyStateChange();
120
96
  }
121
- addToolCallToResponse(toolCall, event) {
97
+ addToolCallToResponse(toolCall) {
122
98
  const response = this._activeResponse ?? this.startResponse();
123
99
  response.isThinking = false;
124
100
  const toolCallWithTimestamp = { ...toolCall, startTimestamp: Date.now() };
125
101
  this._toolCalls.set(toolCall.id, toolCallWithTimestamp);
126
102
  response.children.push({ type: "toolCall", data: toolCallWithTimestamp });
127
- if (event) {
128
- const streamEvent = {
129
- type: "tool-call-start",
130
- timestamp: Date.now(),
131
- data: event,
132
- rawEvent: event.rawEvent
133
- };
134
- this.#appendEventToResponse(streamEvent);
135
- this.#appendEventToToolCallInResponse(toolCall.id, streamEvent);
136
- }
137
103
  this.#updateResponseInItems();
138
104
  this.#notifyStateChange();
139
105
  }
140
- updateToolCallInResponse(toolCallId, updates, eventData) {
106
+ updateToolCallInResponse(toolCallId, updates) {
141
107
  const toolCall = this._toolCalls.get(toolCallId);
142
108
  if (!toolCall) {
143
109
  return;
@@ -157,29 +123,6 @@ class MessageStateController {
157
123
  }
158
124
  }
159
125
  }
160
- if (eventData) {
161
- if (eventData.eventType === "tool-call-args") {
162
- const argsEvent = eventData.event;
163
- const streamEvent = {
164
- type: "tool-call-args",
165
- timestamp: Date.now(),
166
- data: argsEvent,
167
- rawEvent: argsEvent.rawEvent
168
- };
169
- this.#appendEventToResponse(streamEvent);
170
- this.#appendEventToToolCallInResponse(toolCallId, streamEvent);
171
- } else {
172
- const endEvent = eventData.event;
173
- const streamEvent = {
174
- type: "tool-call-end",
175
- timestamp: Date.now(),
176
- data: endEvent,
177
- rawEvent: endEvent.rawEvent
178
- };
179
- this.#appendEventToResponse(streamEvent);
180
- this.#appendEventToToolCallInResponse(toolCallId, streamEvent);
181
- }
182
- }
183
126
  this.#updateResponseInItems();
184
127
  this.#notifyStateChange();
185
128
  }
@@ -188,16 +131,6 @@ class MessageStateController {
188
131
  result,
189
132
  status: event?.isError === true ? "error" : "complete"
190
133
  });
191
- if (event) {
192
- const streamEvent = {
193
- type: "tool-result",
194
- timestamp: Date.now(),
195
- data: event,
196
- rawEvent: event.rawEvent
197
- };
198
- this.#appendEventToResponse(streamEvent);
199
- this.#appendEventToToolCallInResponse(toolCallId, streamEvent);
200
- }
201
134
  }
202
135
  tryFinalizeResponse() {
203
136
  if (!this._activeResponse) {
@@ -221,29 +154,6 @@ class MessageStateController {
221
154
  return item;
222
155
  });
223
156
  }
224
- #appendEventToResponse(event) {
225
- if (!this._activeResponse) {
226
- return;
227
- }
228
- this._activeResponse.eventStream = [...this._activeResponse.eventStream || [], event];
229
- }
230
- #appendEventToToolCallInResponse(toolCallId, event) {
231
- const toolCall = this._toolCalls.get(toolCallId);
232
- if (!toolCall) {
233
- return;
234
- }
235
- const eventStream = [...toolCall.eventStream || [], event];
236
- const updated = { ...toolCall, eventStream };
237
- this._toolCalls.set(toolCallId, updated);
238
- if (this._activeResponse) {
239
- for (const child of this._activeResponse.children) {
240
- if (child.type === "toolCall" && child.data.id === toolCallId) {
241
- child.data = updated;
242
- break;
243
- }
244
- }
245
- }
246
- }
247
157
  #notifyStateChange() {
248
158
  this._host.requestUpdate();
249
159
  }
@@ -251,21 +161,13 @@ class MessageStateController {
251
161
  this._messageItems = [...this._messageItems, item];
252
162
  this.#notifyStateChange();
253
163
  }
254
- addMessage(message, event) {
164
+ addMessage(message) {
255
165
  this.tryFinalizeResponse();
256
166
  const existing = this.getMessage(message.id);
257
167
  if (existing) {
258
168
  return;
259
169
  }
260
170
  this.addMessageItem({ type: "message", data: message });
261
- if (event) {
262
- this.#appendEventToMessage(message.id, {
263
- type: "message-start",
264
- timestamp: Date.now(),
265
- data: event,
266
- rawEvent: event.rawEvent
267
- });
268
- }
269
171
  if (message.status === "complete" || message.status === "error") {
270
172
  this._config.onThreadSettled?.();
271
173
  }
@@ -308,21 +210,13 @@ class MessageStateController {
308
210
  this._messageItems = this._messageItems.filter((item) => !(item.type === "message" && item.data.id === id));
309
211
  this.#notifyStateChange();
310
212
  }
311
- updateMessageStatus(id, status, event) {
213
+ updateMessageStatus(id, status) {
312
214
  this._messageItems = this._messageItems.map((item) => {
313
215
  if (item.type === "message" && item.data.id === id) {
314
216
  return { ...item, data: { ...item.data, status } };
315
217
  }
316
218
  return item;
317
219
  });
318
- if (event) {
319
- this.#appendEventToMessage(id, {
320
- type: "message-end",
321
- timestamp: Date.now(),
322
- data: event,
323
- rawEvent: event.rawEvent
324
- });
325
- }
326
220
  this.#notifyStateChange();
327
221
  if (status === "complete" || status === "error") {
328
222
  this._config.onThreadSettled?.();
@@ -373,7 +267,6 @@ class MessageStateController {
373
267
  timestamp: response.timestamp,
374
268
  status: response.status === "streaming" ? "streaming" : response.status === "error" ? "error" : "complete",
375
269
  toolCalls: toolCalls.length ? toolCalls : void 0,
376
- eventStream: response.eventStream,
377
270
  feedback: response.feedback,
378
271
  children: response.children
379
272
  };
@@ -418,7 +311,6 @@ class MessageStateController {
418
311
  children,
419
312
  status: msg.status === "streaming" ? "streaming" : "complete",
420
313
  timestamp: msg.timestamp,
421
- eventStream: msg.eventStream,
422
314
  feedback: msg.feedback
423
315
  };
424
316
  messageItems.push({ type: "assistant", data: response });
@@ -436,20 +328,6 @@ class MessageStateController {
436
328
  this.#notifyStateChange();
437
329
  }
438
330
  }
439
- #appendEventToMessage(id, event) {
440
- const messageExists = this._messageItems.some((item) => item.type === "message" && item.data.id === id);
441
- if (!messageExists) {
442
- return;
443
- }
444
- this._messageItems = this._messageItems.map((item) => {
445
- if (item.type === "message" && item.data.id === id) {
446
- const eventStream = [...item.data.eventStream || [], event];
447
- return { ...item, data: { ...item.data, eventStream } };
448
- }
449
- return item;
450
- });
451
- this.#notifyStateChange();
452
- }
453
331
  }
454
332
  export {
455
333
  MessageStateController
@@ -0,0 +1,33 @@
1
+ import { ChatMessage, ToolCall } from './types.js';
2
+ /**
3
+ * Wire shape for a tool call sent back to an agent endpoint: the final `args`
4
+ * and its `result`, and nothing else. Local-only fields (`eventStream`,
5
+ * `argsBuffer`, `children`, timing metadata) are deliberately absent - no
6
+ * backend reads them and they grow without bound across turns.
7
+ */
8
+ export interface RequestToolCall {
9
+ id: string;
10
+ name: string;
11
+ args: Record<string, unknown>;
12
+ status: ToolCall['status'];
13
+ result?: unknown;
14
+ }
15
+ /** Wire shape for a single message sent to an agent endpoint. */
16
+ export interface RequestMessage {
17
+ role: ChatMessage['role'];
18
+ content: string;
19
+ toolCallId?: string;
20
+ toolCalls?: RequestToolCall[];
21
+ }
22
+ /**
23
+ * Projects a tool call onto its wire shape. This is the single boundary at which
24
+ * local state is dropped, so adapters never have to remember to omit it.
25
+ */
26
+ export declare function toRequestToolCall(toolCall: ToolCall): RequestToolCall;
27
+ /**
28
+ * Projects the thread onto the messages an agent endpoint is sent: client-only
29
+ * messages and empty assistant turns are dropped, and every remaining message is
30
+ * rebuilt field by field rather than spread, so no local state can leak into a
31
+ * request body.
32
+ */
33
+ export declare function toRequestMessages(messages: ChatMessage[]): RequestMessage[];
@@ -0,0 +1,31 @@
1
+ function toRequestToolCall(toolCall) {
2
+ const { id, name, args, status, result } = toolCall;
3
+ return {
4
+ id,
5
+ name,
6
+ args,
7
+ status,
8
+ ...result === void 0 ? {} : { result }
9
+ };
10
+ }
11
+ function toRequestMessages(messages) {
12
+ return messages.filter(isSendableMessage).map((message) => ({
13
+ role: message.role,
14
+ content: message.content,
15
+ ...message.toolCallId ? { toolCallId: message.toolCallId } : {},
16
+ ...message.toolCalls?.length ? { toolCalls: message.toolCalls.map(toRequestToolCall) } : {}
17
+ }));
18
+ }
19
+ function isSendableMessage(message) {
20
+ if (message.clientOnly) {
21
+ return false;
22
+ }
23
+ if (message.role === "assistant") {
24
+ return message.content.trim().length > 0 || !!message.toolCalls?.length;
25
+ }
26
+ return true;
27
+ }
28
+ export {
29
+ toRequestMessages,
30
+ toRequestToolCall
31
+ };
@@ -100,76 +100,6 @@ export interface ToolDefinition<THandlerArgs = Record<string, unknown>> {
100
100
  */
101
101
  handler?: (context: HandlerContext<THandlerArgs>) => Promise<string | Record<string, unknown> | void> | string | Record<string, unknown> | void;
102
102
  }
103
- export interface MessageStartEvent {
104
- messageId: string;
105
- }
106
- export interface MessageDeltaEvent {
107
- messageId: string;
108
- delta: string;
109
- }
110
- export interface MessageEndEvent {
111
- messageId: string;
112
- }
113
- export interface ToolCallStartEvent {
114
- id: string;
115
- messageId: string;
116
- name: string;
117
- }
118
- export interface ToolCallArgsEvent {
119
- id: string;
120
- messageId: string;
121
- name: string;
122
- argsBuffer: string;
123
- partialArgs?: Record<string, unknown>;
124
- }
125
- export interface ToolCallEndEvent {
126
- id: string;
127
- messageId: string;
128
- name: string;
129
- args: Record<string, unknown>;
130
- }
131
- export interface ToolResultEvent {
132
- toolCallId: string;
133
- result: unknown;
134
- message: ChatMessage;
135
- isError?: boolean;
136
- }
137
- export type StreamEvent = {
138
- type: 'message-start';
139
- timestamp: number;
140
- data: MessageStartEvent;
141
- rawEvent?: unknown;
142
- } | {
143
- type: 'message-delta';
144
- timestamp: number;
145
- data: MessageDeltaEvent;
146
- rawEvent?: unknown;
147
- } | {
148
- type: 'message-end';
149
- timestamp: number;
150
- data: MessageEndEvent;
151
- rawEvent?: unknown;
152
- } | {
153
- type: 'tool-call-start';
154
- timestamp: number;
155
- data: ToolCallStartEvent;
156
- rawEvent?: unknown;
157
- } | {
158
- type: 'tool-call-args';
159
- timestamp: number;
160
- data: ToolCallArgsEvent;
161
- rawEvent?: unknown;
162
- } | {
163
- type: 'tool-call-end';
164
- timestamp: number;
165
- data: ToolCallEndEvent;
166
- rawEvent?: unknown;
167
- } | {
168
- type: 'tool-result';
169
- timestamp: number;
170
- data: ToolResultEvent;
171
- rawEvent?: unknown;
172
- };
173
103
  export interface ChatMessage {
174
104
  id: string;
175
105
  role: 'user' | 'assistant' | 'system' | 'tool';
@@ -178,7 +108,6 @@ export interface ChatMessage {
178
108
  status: 'pending' | 'streaming' | 'complete' | 'error';
179
109
  toolCalls?: ToolCall[];
180
110
  toolCallId?: string;
181
- eventStream?: StreamEvent[];
182
111
  feedback?: ResponseFeedback;
183
112
  children?: ResponseItem[];
184
113
  clientOnly?: boolean;
@@ -217,7 +146,6 @@ export interface ToolCall<TArgs = Record<string, unknown>> {
217
146
  result?: unknown;
218
147
  status: 'pending' | 'parsing' | 'executing' | 'complete' | 'error';
219
148
  type: ToolType;
220
- eventStream?: StreamEvent[];
221
149
  startTimestamp?: number;
222
150
  endTimestamp?: number;
223
151
  }
@@ -240,7 +168,6 @@ export interface AssistantResponse {
240
168
  children: ResponseItem[];
241
169
  status: 'streaming' | 'complete' | 'error';
242
170
  timestamp: number;
243
- eventStream?: StreamEvent[];
244
171
  feedback?: ResponseFeedback;
245
172
  isThinking?: boolean;
246
173
  }
@@ -46,6 +46,7 @@ declare global {
46
46
  'forge-ai-chatbot-launcher-thread-search': CustomEvent<ForgeAiChatbotLauncherThreadSearchEventData>;
47
47
  'forge-ai-chatbot-launcher-thread-load-more': CustomEvent<ForgeAiChatbotLauncherThreadLoadMoreEventData>;
48
48
  'forge-ai-chatbot-launcher-new-chat': CustomEvent<void>;
49
+ 'forge-ai-chatbot-launcher-thread-retry': CustomEvent<void>;
49
50
  }
50
51
  }
51
52
  export declare const AiChatbotLauncherComponentTagName: keyof HTMLElementTagNameMap;
@@ -72,11 +73,13 @@ export declare const AiChatbotLauncherComponentTagName: keyof HTMLElementTagName
72
73
  * @property {Agent[]} agents - List of available agents for selector
73
74
  * @property {string} selectedAgentId - Currently selected agent ID
74
75
  * @property {string} threadName - The name of the current thread (shown in conversation view breadcrumb)
76
+ * @property {boolean} showHistoryButton - Controls the prompt bar's chat history button and its popover (default: false). Visibility is yours to decide - the component never infers it from whether chats are loaded, so an empty `threads` shows "No chats yet" rather than removing the entry point
75
77
  * @property {boolean} showThreadRename - Whether to show the rename option in thread actions menu
76
78
  * @property {boolean} showThreadDelete - Whether to show the delete option in thread actions menu
77
79
  * @property {Thread[]} threads - The list of chats shown in the history popover and full history view
78
80
  * @property {number} totalThreads - Total number of chats available. When greater than the number of loaded threads, infinite scroll is enabled (0 disables it)
79
- * @property {boolean} threadsLoading - Whether chats are currently loading, used to gate the history button and its disabled state
81
+ * @property {boolean} threadsLoading - Whether chats are currently loading, used to show a spinner on the history button and disable it
82
+ * @property {string | undefined} threadsError - Message describing a failed chat history load. When set, the history popover/view shows the message with a retry button instead of the empty state, and the history button shows an error badge so the failure is visible with the popover closed. If chats are already loaded the list stays visible and the message renders as a compact single line with a retry - at the bottom of the list when a page was in flight, otherwise above it. Clear it once a load succeeds.
80
83
  * @property {string | null} selectedThreadId - The id of the currently selected thread, highlighted in the history popover/view. Updated internally when a thread is selected or a new chat starts.
81
84
  *
82
85
  * @cssproperty --forge-ai-chatbot-launcher-icon-color - The fill color for the AI icon.
@@ -94,10 +97,11 @@ export declare const AiChatbotLauncherComponentTagName: keyof HTMLElementTagName
94
97
  * @event {CustomEvent<ForgeAiChatbotAgentChangeEventData>} forge-ai-chatbot-agent-change - Fired when agent selection changes
95
98
  * @event {CustomEvent<ForgeAiChatbotLauncherThreadRenameEventData>} forge-ai-chatbot-launcher-thread-rename - Fired when thread rename is saved. Parent should update threadName property and call onSuccess() or onError()
96
99
  * @event {CustomEvent<ForgeAiChatbotLauncherThreadDeleteEventData>} forge-ai-chatbot-launcher-thread-delete - Fired when thread deletion is confirmed. Parent should delete thread and call onSuccess() or onError()
97
- * @event {CustomEvent<ForgeAiChatbotLauncherThreadSelectEventData>} forge-ai-chatbot-launcher-thread-select - Fired when a thread is selected from the history popover or full history view
100
+ * @event {CustomEvent<ForgeAiChatbotLauncherThreadSelectEventData>} forge-ai-chatbot-launcher-thread-select - Fired when a thread is selected from the history popover or full history view. Cancelable - prevents selectedThreadId from being set and the transition to the conversation view, leaving the host to commit both once its own load resolves
98
101
  * @event {CustomEvent<ForgeAiChatbotLauncherThreadSearchEventData>} forge-ai-chatbot-launcher-thread-search - Fired when the history search query changes (debounced). Cancelable - call setResults() with the results
99
102
  * @event {CustomEvent<ForgeAiChatbotLauncherThreadLoadMoreEventData>} forge-ai-chatbot-launcher-thread-load-more - Fired when scrolling near the bottom of the history list for pagination. Call appendResults() with the next page (empty array signals no more results)
100
103
  * @event {CustomEvent<void>} forge-ai-chatbot-launcher-new-chat - Fired when "New chat" is clicked from the full history view. Cancelable - prevents startNewChat() from being called
104
+ * @event {CustomEvent<void>} forge-ai-chatbot-launcher-thread-retry - Fired when the retry button in the history error state is clicked. Re-request the chats and clear threadsError once the load succeeds
101
105
  */
102
106
  export declare class AiChatbotLauncherComponent extends AiChatbotBase {
103
107
  #private;
@@ -105,11 +109,13 @@ export declare class AiChatbotLauncherComponent extends AiChatbotBase {
105
109
  placeholder: string;
106
110
  descriptionText?: string;
107
111
  threadName?: string;
112
+ showHistoryButton: boolean;
108
113
  showThreadRename: boolean;
109
114
  showThreadDelete: boolean;
110
115
  threads: Thread[];
111
116
  totalThreads: number;
112
117
  threadsLoading: boolean;
118
+ threadsError?: string;
113
119
  selectedThreadId: string | null;
114
120
  private _viewState;
115
121
  private _skipAnimation;
@@ -120,6 +126,12 @@ export declare class AiChatbotLauncherComponent extends AiChatbotBase {
120
126
  constructor();
121
127
  protected _onConnected(): void;
122
128
  startConversation(): void;
129
+ /**
130
+ * Returns to the welcome view without touching conversation state. Unlike `startNewChat()`, this
131
+ * leaves messages, `selectedThreadId`, and the adapter's thread untouched, so an abandoned thread
132
+ * selection can be undone without discarding the conversation the user was already in.
133
+ */
134
+ showWelcome(): void;
123
135
  /**
124
136
  * Navigates directly to the full history view (not the history popover).
125
137
  */