@assistant-ui/react 0.12.1 → 0.12.3

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 (115) hide show
  1. package/dist/client/Suggestions.d.ts +11 -0
  2. package/dist/client/Suggestions.d.ts.map +1 -0
  3. package/dist/client/Suggestions.js +43 -0
  4. package/dist/client/Suggestions.js.map +1 -0
  5. package/dist/client/Tools.d.ts.map +1 -1
  6. package/dist/client/Tools.js +5 -1
  7. package/dist/client/Tools.js.map +1 -1
  8. package/dist/context/providers/SuggestionByIndexProvider.d.ts +6 -0
  9. package/dist/context/providers/SuggestionByIndexProvider.d.ts.map +1 -0
  10. package/dist/context/providers/SuggestionByIndexProvider.js +14 -0
  11. package/dist/context/providers/SuggestionByIndexProvider.js.map +1 -0
  12. package/dist/context/providers/index.d.ts +1 -0
  13. package/dist/context/providers/index.d.ts.map +1 -1
  14. package/dist/context/providers/index.js +1 -0
  15. package/dist/context/providers/index.js.map +1 -1
  16. package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts +5 -0
  17. package/dist/legacy-runtime/AssistantRuntimeProvider.d.ts.map +1 -1
  18. package/dist/legacy-runtime/AssistantRuntimeProvider.js +2 -4
  19. package/dist/legacy-runtime/AssistantRuntimeProvider.js.map +1 -1
  20. package/dist/legacy-runtime/RuntimeAdapter.js +2 -1
  21. package/dist/legacy-runtime/RuntimeAdapter.js.map +1 -1
  22. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  23. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +3 -5
  24. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  25. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.d.ts +10 -12
  26. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.d.ts.map +1 -1
  27. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.js +14 -19
  28. package/dist/legacy-runtime/runtime-cores/assistant-transport/utils.js.map +1 -1
  29. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.d.ts.map +1 -1
  30. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js +32 -4
  31. package/dist/legacy-runtime/runtime-cores/external-store/external-message-converter.js.map +1 -1
  32. package/dist/legacy-runtime/runtime-cores/remote-thread-list/BaseSubscribable.d.ts.map +1 -1
  33. package/dist/legacy-runtime/runtime-cores/remote-thread-list/BaseSubscribable.js +3 -0
  34. package/dist/legacy-runtime/runtime-cores/remote-thread-list/BaseSubscribable.js.map +1 -1
  35. package/dist/model-context/index.d.ts +1 -0
  36. package/dist/model-context/index.d.ts.map +1 -1
  37. package/dist/model-context/index.js +1 -0
  38. package/dist/model-context/index.js.map +1 -1
  39. package/dist/primitives/assistantModal/AssistantModalRoot.js +1 -1
  40. package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
  41. package/dist/primitives/index.d.ts +1 -0
  42. package/dist/primitives/index.d.ts.map +1 -1
  43. package/dist/primitives/index.js +1 -0
  44. package/dist/primitives/index.js.map +1 -1
  45. package/dist/primitives/message/MessageParts.d.ts +11 -0
  46. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  47. package/dist/primitives/message/MessageParts.js +18 -2
  48. package/dist/primitives/message/MessageParts.js.map +1 -1
  49. package/dist/primitives/suggestion/SuggestionDescription.d.ts +18 -0
  50. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -0
  51. package/dist/primitives/suggestion/SuggestionDescription.js +19 -0
  52. package/dist/primitives/suggestion/SuggestionDescription.js.map +1 -0
  53. package/dist/primitives/suggestion/SuggestionTitle.d.ts +18 -0
  54. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -0
  55. package/dist/primitives/suggestion/SuggestionTitle.js +19 -0
  56. package/dist/primitives/suggestion/SuggestionTitle.js.map +1 -0
  57. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +49 -0
  58. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -0
  59. package/dist/primitives/suggestion/SuggestionTrigger.js +45 -0
  60. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -0
  61. package/dist/primitives/suggestion/index.d.ts +4 -0
  62. package/dist/primitives/suggestion/index.d.ts.map +1 -0
  63. package/dist/primitives/suggestion/index.js +4 -0
  64. package/dist/primitives/suggestion/index.js.map +1 -0
  65. package/dist/primitives/thread/ThreadSuggestions.d.ts +53 -0
  66. package/dist/primitives/thread/ThreadSuggestions.d.ts.map +1 -0
  67. package/dist/primitives/thread/ThreadSuggestions.js +58 -0
  68. package/dist/primitives/thread/ThreadSuggestions.js.map +1 -0
  69. package/dist/primitives/thread/index.d.ts +1 -0
  70. package/dist/primitives/thread/index.d.ts.map +1 -1
  71. package/dist/primitives/thread/index.js +1 -0
  72. package/dist/primitives/thread/index.js.map +1 -1
  73. package/dist/types/scopes/index.d.ts +2 -0
  74. package/dist/types/scopes/index.d.ts.map +1 -1
  75. package/dist/types/scopes/suggestion.d.ts +20 -0
  76. package/dist/types/scopes/suggestion.d.ts.map +1 -0
  77. package/dist/types/scopes/suggestion.js +2 -0
  78. package/dist/types/scopes/suggestion.js.map +1 -0
  79. package/dist/types/scopes/suggestions.d.ts +20 -0
  80. package/dist/types/scopes/suggestions.d.ts.map +1 -0
  81. package/dist/types/scopes/suggestions.js +2 -0
  82. package/dist/types/scopes/suggestions.js.map +1 -0
  83. package/dist/types/store-augmentation.d.ts +4 -0
  84. package/dist/types/store-augmentation.d.ts.map +1 -1
  85. package/dist/utils/idUtils.d.ts +2 -0
  86. package/dist/utils/idUtils.d.ts.map +1 -1
  87. package/dist/utils/idUtils.js +3 -0
  88. package/dist/utils/idUtils.js.map +1 -1
  89. package/package.json +10 -10
  90. package/src/client/Suggestions.ts +74 -0
  91. package/src/client/Tools.ts +10 -1
  92. package/src/context/providers/SuggestionByIndexProvider.tsx +23 -0
  93. package/src/context/providers/index.ts +1 -0
  94. package/src/legacy-runtime/AssistantRuntimeProvider.tsx +8 -5
  95. package/src/legacy-runtime/RuntimeAdapter.ts +2 -1
  96. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.tsx +3 -4
  97. package/src/legacy-runtime/runtime-cores/assistant-transport/utils.ts +19 -24
  98. package/src/legacy-runtime/runtime-cores/external-store/external-message-converter.tsx +42 -7
  99. package/src/legacy-runtime/runtime-cores/remote-thread-list/BaseSubscribable.tsx +3 -0
  100. package/src/model-context/index.ts +2 -0
  101. package/src/primitives/assistantModal/AssistantModalRoot.tsx +1 -1
  102. package/src/primitives/index.ts +1 -0
  103. package/src/primitives/message/MessageParts.tsx +45 -1
  104. package/src/primitives/suggestion/SuggestionDescription.tsx +33 -0
  105. package/src/primitives/suggestion/SuggestionTitle.tsx +33 -0
  106. package/src/primitives/suggestion/SuggestionTrigger.tsx +79 -0
  107. package/src/primitives/suggestion/index.ts +3 -0
  108. package/src/primitives/thread/ThreadSuggestions.tsx +109 -0
  109. package/src/primitives/thread/index.ts +4 -0
  110. package/src/tests/external-message-converter.test.ts +105 -16
  111. package/src/types/scopes/index.ts +12 -0
  112. package/src/types/scopes/suggestion.ts +20 -0
  113. package/src/types/scopes/suggestions.ts +21 -0
  114. package/src/types/store-augmentation.ts +4 -0
  115. package/src/utils/idUtils.tsx +4 -0
@@ -0,0 +1,79 @@
1
+ "use client";
2
+
3
+ import {
4
+ ActionButtonElement,
5
+ ActionButtonProps,
6
+ createActionButton,
7
+ } from "../../utils/createActionButton";
8
+ import { useCallback } from "react";
9
+ import { useAuiState, useAui } from "@assistant-ui/store";
10
+
11
+ const useSuggestionTrigger = ({
12
+ send,
13
+ clearComposer = true,
14
+ }: {
15
+ /**
16
+ * When true, automatically sends the message.
17
+ * When false, replaces or appends the composer text with the suggestion - depending on the value of `clearComposer`.
18
+ */
19
+ send?: boolean | undefined;
20
+
21
+ /**
22
+ * Whether to clear the composer after sending.
23
+ * When send is set to false, determines if composer text is replaced with suggestion (true, default),
24
+ * or if it's appended to the composer text (false).
25
+ *
26
+ * @default true
27
+ */
28
+ clearComposer?: boolean | undefined;
29
+ }) => {
30
+ const aui = useAui();
31
+ const disabled = useAuiState(({ thread }) => thread.isDisabled);
32
+ const prompt = useAuiState(({ suggestion }) => suggestion.prompt);
33
+
34
+ const resolvedSend = send ?? false;
35
+
36
+ const callback = useCallback(() => {
37
+ const isRunning = aui.thread().getState().isRunning;
38
+
39
+ if (resolvedSend && !isRunning) {
40
+ aui.thread().append(prompt);
41
+ if (clearComposer) {
42
+ aui.composer().setText("");
43
+ }
44
+ } else {
45
+ if (clearComposer) {
46
+ aui.composer().setText(prompt);
47
+ } else {
48
+ const currentText = aui.composer().getState().text;
49
+ aui
50
+ .composer()
51
+ .setText(currentText.trim() ? `${currentText} ${prompt}` : prompt);
52
+ }
53
+ }
54
+ }, [aui, resolvedSend, clearComposer, prompt]);
55
+
56
+ if (disabled) return null;
57
+ return callback;
58
+ };
59
+
60
+ export namespace SuggestionPrimitiveTrigger {
61
+ export type Element = ActionButtonElement;
62
+ export type Props = ActionButtonProps<typeof useSuggestionTrigger>;
63
+ }
64
+
65
+ /**
66
+ * A button that triggers the suggestion action (send or insert into composer).
67
+ *
68
+ * @example
69
+ * ```tsx
70
+ * <SuggestionPrimitive.Trigger send>
71
+ * Click me
72
+ * </SuggestionPrimitive.Trigger>
73
+ * ```
74
+ */
75
+ export const SuggestionPrimitiveTrigger = createActionButton(
76
+ "SuggestionPrimitive.Trigger",
77
+ useSuggestionTrigger,
78
+ ["send", "clearComposer"],
79
+ );
@@ -0,0 +1,3 @@
1
+ export { SuggestionPrimitiveTitle as Title } from "./SuggestionTitle";
2
+ export { SuggestionPrimitiveDescription as Description } from "./SuggestionDescription";
3
+ export { SuggestionPrimitiveTrigger as Trigger } from "./SuggestionTrigger";
@@ -0,0 +1,109 @@
1
+ "use client";
2
+
3
+ import { type ComponentType, type FC, memo, useMemo } from "react";
4
+ import { useAuiState } from "@assistant-ui/store";
5
+ import { SuggestionByIndexProvider } from "../../context/providers";
6
+
7
+ export namespace ThreadPrimitiveSuggestions {
8
+ export type Props = {
9
+ /**
10
+ * Component to render for each suggestion.
11
+ */
12
+ components: {
13
+ /** Component used to render each suggestion */
14
+ Suggestion: ComponentType;
15
+ };
16
+ };
17
+ }
18
+
19
+ type SuggestionComponentProps = {
20
+ components: ThreadPrimitiveSuggestions.Props["components"];
21
+ };
22
+
23
+ const SuggestionComponent: FC<SuggestionComponentProps> = ({ components }) => {
24
+ const Component = components.Suggestion;
25
+ return <Component />;
26
+ };
27
+
28
+ export namespace ThreadPrimitiveSuggestionByIndex {
29
+ export type Props = {
30
+ index: number;
31
+ components: ThreadPrimitiveSuggestions.Props["components"];
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Renders a single suggestion at the specified index.
37
+ *
38
+ * This component provides suggestion context for a specific suggestion
39
+ * and renders it using the provided component configuration.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * <ThreadPrimitive.SuggestionByIndex
44
+ * index={0}
45
+ * components={{
46
+ * Suggestion: MySuggestion
47
+ * }}
48
+ * />
49
+ * ```
50
+ */
51
+ export const ThreadPrimitiveSuggestionByIndex: FC<ThreadPrimitiveSuggestionByIndex.Props> =
52
+ memo(
53
+ ({ index, components }) => {
54
+ return (
55
+ <SuggestionByIndexProvider index={index}>
56
+ <SuggestionComponent components={components} />
57
+ </SuggestionByIndexProvider>
58
+ );
59
+ },
60
+ (prev, next) =>
61
+ prev.index === next.index &&
62
+ prev.components.Suggestion === next.components.Suggestion,
63
+ );
64
+
65
+ ThreadPrimitiveSuggestionByIndex.displayName =
66
+ "ThreadPrimitive.SuggestionByIndex";
67
+
68
+ /**
69
+ * Renders all suggestions using the provided component configuration.
70
+ *
71
+ * This component automatically renders all suggestions from the suggestions scope,
72
+ * providing the appropriate suggestion context for each one.
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * <ThreadPrimitive.Suggestions
77
+ * components={{
78
+ * Suggestion: MySuggestion
79
+ * }}
80
+ * />
81
+ * ```
82
+ */
83
+ export const ThreadPrimitiveSuggestionsImpl: FC<
84
+ ThreadPrimitiveSuggestions.Props
85
+ > = ({ components }) => {
86
+ const suggestionsLength = useAuiState(
87
+ ({ suggestions }) => suggestions.suggestions.length,
88
+ );
89
+
90
+ const suggestionElements = useMemo(() => {
91
+ if (suggestionsLength === 0) return null;
92
+ return Array.from({ length: suggestionsLength }, (_, index) => (
93
+ <ThreadPrimitiveSuggestionByIndex
94
+ key={index}
95
+ index={index}
96
+ components={components}
97
+ />
98
+ ));
99
+ }, [suggestionsLength, components]);
100
+
101
+ return suggestionElements;
102
+ };
103
+
104
+ ThreadPrimitiveSuggestionsImpl.displayName = "ThreadPrimitive.Suggestions";
105
+
106
+ export const ThreadPrimitiveSuggestions = memo(
107
+ ThreadPrimitiveSuggestionsImpl,
108
+ (prev, next) => prev.components.Suggestion === next.components.Suggestion,
109
+ );
@@ -9,3 +9,7 @@ export { ThreadPrimitiveMessages as Messages } from "./ThreadMessages";
9
9
  export { ThreadPrimitiveMessageByIndex as MessageByIndex } from "./ThreadMessages";
10
10
  export { ThreadPrimitiveScrollToBottom as ScrollToBottom } from "./ThreadScrollToBottom";
11
11
  export { ThreadPrimitiveSuggestion as Suggestion } from "./ThreadSuggestion";
12
+ export {
13
+ ThreadPrimitiveSuggestions as Suggestions,
14
+ ThreadPrimitiveSuggestionByIndex as SuggestionByIndex,
15
+ } from "./ThreadSuggestions";
@@ -1,16 +1,10 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { convertExternalMessages } from "../legacy-runtime/runtime-cores/external-store/external-message-converter";
3
3
  import type { useExternalMessageConverter } from "../legacy-runtime/runtime-cores/external-store/external-message-converter";
4
+ import { isErrorMessageId } from "../utils/idUtils";
4
5
 
5
- /**
6
- * Tests for the external message converter, specifically the joinExternalMessages logic.
7
- */
8
6
  describe("convertExternalMessages", () => {
9
7
  describe("reasoning part merging", () => {
10
- /**
11
- * Tests that reasoning parts with the same parentId are merged together.
12
- * The text should be concatenated with a double newline separator.
13
- */
14
8
  it("should merge reasoning parts with the same parentId", () => {
15
9
  const messages = [
16
10
  {
@@ -56,9 +50,6 @@ describe("convertExternalMessages", () => {
56
50
  expect((reasoningParts[0] as any).parentId).toBe("parent1");
57
51
  });
58
52
 
59
- /**
60
- * Tests that reasoning parts without parentId remain separate.
61
- */
62
53
  it("should keep reasoning parts without parentId separate", () => {
63
54
  const messages = [
64
55
  {
@@ -89,9 +80,6 @@ describe("convertExternalMessages", () => {
89
80
  expect((reasoningParts[1] as any).text).toBe("Second reasoning");
90
81
  });
91
82
 
92
- /**
93
- * Tests that reasoning parts with different parentIds remain separate.
94
- */
95
83
  it("should keep reasoning parts with different parentIds separate", () => {
96
84
  const messages = [
97
85
  {
@@ -134,9 +122,6 @@ describe("convertExternalMessages", () => {
134
122
  expect((reasoningParts[1] as any).parentId).toBe("parent2");
135
123
  });
136
124
 
137
- /**
138
- * Tests that tool result merging still works correctly alongside reasoning merging.
139
- */
140
125
  it("should still merge tool results with matching tool calls", () => {
141
126
  const messages = [
142
127
  {
@@ -174,4 +159,108 @@ describe("convertExternalMessages", () => {
174
159
  expect((toolCallParts[0] as any).result).toEqual({ data: "result" });
175
160
  });
176
161
  });
162
+
163
+ describe("synthetic error message", () => {
164
+ it("should create synthetic error message when error exists and no messages", () => {
165
+ const messages: never[] = [];
166
+ const callback: useExternalMessageConverter.Callback<never> = (msg) =>
167
+ msg;
168
+
169
+ const result = convertExternalMessages(messages, callback, false, {
170
+ error: "API key is missing",
171
+ });
172
+
173
+ expect(result).toHaveLength(1);
174
+ expect(result[0]!.role).toBe("assistant");
175
+ expect(result[0]!.content).toHaveLength(0);
176
+ expect(result[0]!.status).toEqual({
177
+ type: "incomplete",
178
+ reason: "error",
179
+ error: "API key is missing",
180
+ });
181
+ expect(isErrorMessageId(result[0]!.id)).toBe(true);
182
+ });
183
+
184
+ it("should create synthetic error message when error exists and last message is user", () => {
185
+ const messages = [
186
+ {
187
+ id: "user1",
188
+ role: "user" as const,
189
+ content: "Hello",
190
+ },
191
+ ];
192
+
193
+ const callback: useExternalMessageConverter.Callback<
194
+ (typeof messages)[number]
195
+ > = (msg) => msg;
196
+
197
+ const result = convertExternalMessages(messages, callback, false, {
198
+ error: { message: "Invalid API key" },
199
+ });
200
+
201
+ expect(result).toHaveLength(2);
202
+ expect(result[0]!.role).toBe("user");
203
+ expect(result[1]!.role).toBe("assistant");
204
+ expect(result[1]!.content).toHaveLength(0);
205
+ expect(result[1]!.status).toEqual({
206
+ type: "incomplete",
207
+ reason: "error",
208
+ error: { message: "Invalid API key" },
209
+ });
210
+ expect(isErrorMessageId(result[1]!.id)).toBe(true);
211
+ });
212
+
213
+ it("should not create synthetic error message when last message is assistant", () => {
214
+ const messages = [
215
+ {
216
+ id: "user1",
217
+ role: "user" as const,
218
+ content: "Hello",
219
+ },
220
+ {
221
+ id: "assistant1",
222
+ role: "assistant" as const,
223
+ content: "Hi there",
224
+ },
225
+ ];
226
+
227
+ const callback: useExternalMessageConverter.Callback<
228
+ (typeof messages)[number]
229
+ > = (msg) => msg;
230
+
231
+ const result = convertExternalMessages(messages, callback, false, {
232
+ error: "Connection error",
233
+ });
234
+
235
+ expect(result).toHaveLength(2);
236
+ expect(result[0]!.role).toBe("user");
237
+ expect(result[1]!.role).toBe("assistant");
238
+ expect(result[1]!.id).toBe("assistant1");
239
+ expect(result[1]!.status).toMatchObject({
240
+ type: "incomplete",
241
+ reason: "error",
242
+ error: "Connection error",
243
+ });
244
+ expect(isErrorMessageId(result[1]!.id)).toBe(false);
245
+ });
246
+
247
+ it("should not create synthetic message when no error", () => {
248
+ const messages = [
249
+ {
250
+ id: "user1",
251
+ role: "user" as const,
252
+ content: "Hello",
253
+ },
254
+ ];
255
+
256
+ const callback: useExternalMessageConverter.Callback<
257
+ (typeof messages)[number]
258
+ > = (msg) => msg;
259
+
260
+ const result = convertExternalMessages(messages, callback, false, {});
261
+
262
+ expect(result).toHaveLength(1);
263
+ expect(result[0]!.role).toBe("user");
264
+ });
265
+ });
177
266
  });
@@ -43,6 +43,18 @@ export type {
43
43
  AttachmentClientSchema,
44
44
  } from "./attachment";
45
45
  export type { ToolsState, ToolsMethods, ToolsClientSchema } from "./tools";
46
+ export type {
47
+ SuggestionsState,
48
+ SuggestionsMethods,
49
+ SuggestionsClientSchema,
50
+ Suggestion,
51
+ } from "./suggestions";
52
+ export type {
53
+ SuggestionState,
54
+ SuggestionMethods,
55
+ SuggestionMeta,
56
+ SuggestionClientSchema,
57
+ } from "./suggestion";
46
58
  export type {
47
59
  ModelContextState,
48
60
  ModelContextMethods,
@@ -0,0 +1,20 @@
1
+ export type SuggestionState = {
2
+ title: string;
3
+ label: string;
4
+ prompt: string;
5
+ };
6
+
7
+ export type SuggestionMethods = {
8
+ getState(): SuggestionState;
9
+ };
10
+
11
+ export type SuggestionMeta = {
12
+ source: "suggestions";
13
+ query: { index: number };
14
+ };
15
+
16
+ export type SuggestionClientSchema = {
17
+ state: SuggestionState;
18
+ methods: SuggestionMethods;
19
+ meta: SuggestionMeta;
20
+ };
@@ -0,0 +1,21 @@
1
+ import type { SuggestionMethods } from "./suggestion";
2
+
3
+ export type Suggestion = {
4
+ title: string;
5
+ label: string;
6
+ prompt: string;
7
+ };
8
+
9
+ export type SuggestionsState = {
10
+ suggestions: Suggestion[];
11
+ };
12
+
13
+ export type SuggestionsMethods = {
14
+ getState(): SuggestionsState;
15
+ suggestion(query: { index: number }): SuggestionMethods;
16
+ };
17
+
18
+ export type SuggestionsClientSchema = {
19
+ state: SuggestionsState;
20
+ methods: SuggestionsMethods;
21
+ };
@@ -9,6 +9,8 @@ import type { ComposerClientSchema } from "./scopes/composer";
9
9
  import type { AttachmentClientSchema } from "./scopes/attachment";
10
10
  import type { ToolsClientSchema } from "./scopes/tools";
11
11
  import type { ModelContextClientSchema } from "./scopes/modelContext";
12
+ import type { SuggestionsClientSchema } from "./scopes/suggestions";
13
+ import type { SuggestionClientSchema } from "./scopes/suggestion";
12
14
 
13
15
  declare module "@assistant-ui/store" {
14
16
  interface ClientRegistry {
@@ -21,5 +23,7 @@ declare module "@assistant-ui/store" {
21
23
  attachment: AttachmentClientSchema;
22
24
  tools: ToolsClientSchema;
23
25
  modelContext: ModelContextClientSchema;
26
+ suggestions: SuggestionsClientSchema;
27
+ suggestion: SuggestionClientSchema;
24
28
  }
25
29
  }
@@ -8,3 +8,7 @@ export const generateId = customAlphabet(
8
8
  const optimisticPrefix = "__optimistic__";
9
9
  export const generateOptimisticId = () => `${optimisticPrefix}${generateId()}`;
10
10
  export const isOptimisticId = (id: string) => id.startsWith(optimisticPrefix);
11
+
12
+ const errorPrefix = "__error__";
13
+ export const generateErrorMessageId = () => `${errorPrefix}${generateId()}`;
14
+ export const isErrorMessageId = (id: string) => id.startsWith(errorPrefix);