@assistant-ui/react 0.12.7 → 0.12.8

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 (66) hide show
  1. package/dist/client/ChainOfThoughtClient.d.ts +15 -0
  2. package/dist/client/ChainOfThoughtClient.d.ts.map +1 -0
  3. package/dist/client/ChainOfThoughtClient.js +21 -0
  4. package/dist/client/ChainOfThoughtClient.js.map +1 -0
  5. package/dist/client/index.d.ts +1 -0
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +1 -0
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/context/providers/ChainOfThoughtByIndicesProvider.d.ts +6 -0
  10. package/dist/context/providers/ChainOfThoughtByIndicesProvider.d.ts.map +1 -0
  11. package/dist/context/providers/ChainOfThoughtByIndicesProvider.js +21 -0
  12. package/dist/context/providers/ChainOfThoughtByIndicesProvider.js.map +1 -0
  13. package/dist/context/providers/ChainOfThoughtPartByIndexProvider.d.ts +5 -0
  14. package/dist/context/providers/ChainOfThoughtPartByIndexProvider.d.ts.map +1 -0
  15. package/dist/context/providers/ChainOfThoughtPartByIndexProvider.js +14 -0
  16. package/dist/context/providers/ChainOfThoughtPartByIndexProvider.js.map +1 -0
  17. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +28 -0
  18. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -0
  19. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +27 -0
  20. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -0
  21. package/dist/primitives/chainOfThought/ChainOfThoughtParts.d.ts +37 -0
  22. package/dist/primitives/chainOfThought/ChainOfThoughtParts.d.ts.map +1 -0
  23. package/dist/primitives/chainOfThought/ChainOfThoughtParts.js +42 -0
  24. package/dist/primitives/chainOfThought/ChainOfThoughtParts.js.map +1 -0
  25. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +28 -0
  26. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -0
  27. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js +25 -0
  28. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js.map +1 -0
  29. package/dist/primitives/chainOfThought/index.d.ts +4 -0
  30. package/dist/primitives/chainOfThought/index.d.ts.map +1 -0
  31. package/dist/primitives/chainOfThought/index.js +4 -0
  32. package/dist/primitives/chainOfThought/index.js.map +1 -0
  33. package/dist/primitives/index.d.ts +1 -0
  34. package/dist/primitives/index.d.ts.map +1 -1
  35. package/dist/primitives/index.js +1 -0
  36. package/dist/primitives/index.js.map +1 -1
  37. package/dist/primitives/message/MessageParts.d.ts +29 -0
  38. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  39. package/dist/primitives/message/MessageParts.js +48 -23
  40. package/dist/primitives/message/MessageParts.js.map +1 -1
  41. package/dist/types/scopes/chainOfThought.d.ts +40 -0
  42. package/dist/types/scopes/chainOfThought.d.ts.map +1 -0
  43. package/dist/types/scopes/chainOfThought.js +2 -0
  44. package/dist/types/scopes/chainOfThought.js.map +1 -0
  45. package/dist/types/scopes/index.d.ts +1 -0
  46. package/dist/types/scopes/index.d.ts.map +1 -1
  47. package/dist/types/scopes/part.d.ts +6 -0
  48. package/dist/types/scopes/part.d.ts.map +1 -1
  49. package/dist/types/store-augmentation.d.ts +2 -0
  50. package/dist/types/store-augmentation.d.ts.map +1 -1
  51. package/package.json +1 -1
  52. package/src/client/ChainOfThoughtClient.ts +43 -0
  53. package/src/client/index.ts +1 -0
  54. package/src/context/providers/ChainOfThoughtByIndicesProvider.tsx +35 -0
  55. package/src/context/providers/ChainOfThoughtPartByIndexProvider.tsx +20 -0
  56. package/src/primitives/chainOfThought/CHAIN_OF_THOUGHT.spec.md +68 -0
  57. package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.tsx +51 -0
  58. package/src/primitives/chainOfThought/ChainOfThoughtParts.tsx +79 -0
  59. package/src/primitives/chainOfThought/ChainOfThoughtRoot.tsx +36 -0
  60. package/src/primitives/chainOfThought/index.ts +14 -0
  61. package/src/primitives/index.ts +1 -0
  62. package/src/primitives/message/MessageParts.tsx +90 -26
  63. package/src/types/scopes/chainOfThought.ts +42 -0
  64. package/src/types/scopes/index.ts +7 -0
  65. package/src/types/scopes/part.ts +11 -6
  66. package/src/types/store-augmentation.ts +2 -0
@@ -12,6 +12,7 @@ import {
12
12
  PartByIndexProvider,
13
13
  TextMessagePartProvider,
14
14
  } from "../../context/providers";
15
+ import { ChainOfThoughtByIndicesProvider } from "../../context/providers/ChainOfThoughtByIndicesProvider";
15
16
  import { MessagePartPrimitiveText } from "../messagePart/MessagePartText";
16
17
  import { MessagePartPrimitiveImage } from "../messagePart/MessagePartImage";
17
18
  import type {
@@ -33,13 +34,16 @@ import { useShallow } from "zustand/shallow";
33
34
  type MessagePartRange =
34
35
  | { type: "single"; index: number }
35
36
  | { type: "toolGroup"; startIndex: number; endIndex: number }
36
- | { type: "reasoningGroup"; startIndex: number; endIndex: number };
37
+ | { type: "reasoningGroup"; startIndex: number; endIndex: number }
38
+ | { type: "chainOfThoughtGroup"; startIndex: number; endIndex: number };
37
39
 
38
40
  /**
39
41
  * Creates a group state manager for a specific part type.
40
42
  * Returns functions to start, end, and finalize groups.
41
43
  */
42
- const createGroupState = <T extends "toolGroup" | "reasoningGroup">(
44
+ const createGroupState = <
45
+ T extends "toolGroup" | "reasoningGroup" | "chainOfThoughtGroup",
46
+ >(
43
47
  groupType: T,
44
48
  ) => {
45
49
  let start = -1;
@@ -75,37 +79,59 @@ const createGroupState = <T extends "toolGroup" | "reasoningGroup">(
75
79
  /**
76
80
  * Groups consecutive tool-call and reasoning message parts into ranges.
77
81
  * Always groups tool calls and reasoning parts, even if there's only one.
82
+ * When useChainOfThought is true, groups tool-call and reasoning parts together.
78
83
  */
79
84
  const groupMessageParts = (
80
85
  messageTypes: readonly string[],
86
+ useChainOfThought: boolean,
81
87
  ): MessagePartRange[] => {
82
88
  const ranges: MessagePartRange[] = [];
83
- const toolGroup = createGroupState("toolGroup");
84
- const reasoningGroup = createGroupState("reasoningGroup");
85
-
86
- for (let i = 0; i < messageTypes.length; i++) {
87
- const type = messageTypes[i];
88
-
89
- if (type === "tool-call") {
90
- reasoningGroup.endGroup(i - 1, ranges);
91
- toolGroup.startGroup(i);
92
- } else if (type === "reasoning") {
93
- toolGroup.endGroup(i - 1, ranges);
94
- reasoningGroup.startGroup(i);
95
- } else {
96
- toolGroup.endGroup(i - 1, ranges);
97
- reasoningGroup.endGroup(i - 1, ranges);
98
- ranges.push({ type: "single", index: i });
89
+
90
+ if (useChainOfThought) {
91
+ const chainOfThoughtGroup = createGroupState("chainOfThoughtGroup");
92
+
93
+ for (let i = 0; i < messageTypes.length; i++) {
94
+ const type = messageTypes[i];
95
+
96
+ if (type === "tool-call" || type === "reasoning") {
97
+ chainOfThoughtGroup.startGroup(i);
98
+ } else {
99
+ chainOfThoughtGroup.endGroup(i - 1, ranges);
100
+ ranges.push({ type: "single", index: i });
101
+ }
99
102
  }
100
- }
101
103
 
102
- toolGroup.finalize(messageTypes.length - 1, ranges);
103
- reasoningGroup.finalize(messageTypes.length - 1, ranges);
104
+ chainOfThoughtGroup.finalize(messageTypes.length - 1, ranges);
105
+ } else {
106
+ const toolGroup = createGroupState("toolGroup");
107
+ const reasoningGroup = createGroupState("reasoningGroup");
108
+
109
+ for (let i = 0; i < messageTypes.length; i++) {
110
+ const type = messageTypes[i];
111
+
112
+ if (type === "tool-call") {
113
+ reasoningGroup.endGroup(i - 1, ranges);
114
+ toolGroup.startGroup(i);
115
+ } else if (type === "reasoning") {
116
+ toolGroup.endGroup(i - 1, ranges);
117
+ reasoningGroup.startGroup(i);
118
+ } else {
119
+ toolGroup.endGroup(i - 1, ranges);
120
+ reasoningGroup.endGroup(i - 1, ranges);
121
+ ranges.push({ type: "single", index: i });
122
+ }
123
+ }
124
+
125
+ toolGroup.finalize(messageTypes.length - 1, ranges);
126
+ reasoningGroup.finalize(messageTypes.length - 1, ranges);
127
+ }
104
128
 
105
129
  return ranges;
106
130
  };
107
131
 
108
- const useMessagePartsGroups = (): MessagePartRange[] => {
132
+ const useMessagePartsGroups = (
133
+ useChainOfThought: boolean,
134
+ ): MessagePartRange[] => {
109
135
  const messageTypes = useAuiState(
110
136
  useShallow((s) => s.message.parts.map((c: any) => c.type)),
111
137
  );
@@ -114,8 +140,8 @@ const useMessagePartsGroups = (): MessagePartRange[] => {
114
140
  if (messageTypes.length === 0) {
115
141
  return [];
116
142
  }
117
- return groupMessageParts(messageTypes);
118
- }, [messageTypes]);
143
+ return groupMessageParts(messageTypes, useChainOfThought);
144
+ }, [messageTypes, useChainOfThought]);
119
145
  };
120
146
 
121
147
  export namespace MessagePrimitiveParts {
@@ -240,6 +266,31 @@ export namespace MessagePrimitiveParts {
240
266
  * @param children - Rendered reasoning part components
241
267
  */
242
268
  ReasoningGroup?: ReasoningGroupComponent;
269
+
270
+ /**
271
+ * Component for rendering chain of thought (reasoning + tool-call) parts.
272
+ *
273
+ * When provided, this component takes control of rendering ALL reasoning and
274
+ * tool-call parts in the message. The Reasoning, tools, ReasoningGroup, and
275
+ * ToolGroup components are completely ignored when ChainOfThought is set.
276
+ *
277
+ * The component is automatically wrapped in a ChainOfThoughtByIndicesProvider
278
+ * that sets up the chainOfThought client scope with the correct parts.
279
+ *
280
+ * @example
281
+ * ```tsx
282
+ * // Chain of thought with accordion
283
+ * ChainOfThought: () => (
284
+ * <ChainOfThoughtPrimitive.Root>
285
+ * <ChainOfThoughtPrimitive.AccordionTrigger>
286
+ * Toggle reasoning
287
+ * </ChainOfThoughtPrimitive.AccordionTrigger>
288
+ * <ChainOfThoughtPrimitive.Parts />
289
+ * </ChainOfThoughtPrimitive.Root>
290
+ * )
291
+ * ```
292
+ */
293
+ ChainOfThought?: ComponentType;
243
294
  }
244
295
  | undefined;
245
296
  /**
@@ -293,7 +344,7 @@ type MessagePartComponentProps = {
293
344
  components: MessagePrimitiveParts.Props["components"];
294
345
  };
295
346
 
296
- const MessagePartComponent: FC<MessagePartComponentProps> = ({
347
+ export const MessagePartComponent: FC<MessagePartComponentProps> = ({
297
348
  components: {
298
349
  Text = defaultComponents.Text,
299
350
  Reasoning = defaultComponents.Reasoning,
@@ -493,7 +544,8 @@ export const MessagePrimitiveParts: FC<MessagePrimitiveParts.Props> = ({
493
544
  unstable_showEmptyOnNonTextEnd = true,
494
545
  }) => {
495
546
  const contentLength = useAuiState(({ message }) => message.parts.length);
496
- const messageRanges = useMessagePartsGroups();
547
+ const useChainOfThought = !!components?.ChainOfThought;
548
+ const messageRanges = useMessagePartsGroups(useChainOfThought);
497
549
 
498
550
  const partsElements = useMemo(() => {
499
551
  if (contentLength === 0) {
@@ -509,6 +561,18 @@ export const MessagePrimitiveParts: FC<MessagePrimitiveParts.Props> = ({
509
561
  components={components}
510
562
  />
511
563
  );
564
+ } else if (range.type === "chainOfThoughtGroup") {
565
+ const ChainOfThoughtComponent = components?.ChainOfThought;
566
+ if (!ChainOfThoughtComponent) return null;
567
+ return (
568
+ <ChainOfThoughtByIndicesProvider
569
+ key={`chainOfThought-${range.startIndex}`}
570
+ startIndex={range.startIndex}
571
+ endIndex={range.endIndex}
572
+ >
573
+ <ChainOfThoughtComponent />
574
+ </ChainOfThoughtByIndicesProvider>
575
+ );
512
576
  } else if (range.type === "toolGroup") {
513
577
  const ToolGroupComponent =
514
578
  components?.ToolGroup ?? defaultComponents.ToolGroup;
@@ -0,0 +1,42 @@
1
+ import type {
2
+ MessagePartStatus,
3
+ ToolCallMessagePartStatus,
4
+ } from "../AssistantTypes";
5
+ import type { PartMethods, PartState } from "./part";
6
+
7
+ export type ChainOfThoughtPart = Extract<
8
+ PartState,
9
+ { type: "tool-call" } | { type: "reasoning" }
10
+ >;
11
+
12
+ export type ChainOfThoughtState = {
13
+ readonly parts: readonly ChainOfThoughtPart[];
14
+ readonly collapsed: boolean;
15
+ readonly status: MessagePartStatus | ToolCallMessagePartStatus;
16
+ };
17
+
18
+ export type ChainOfThoughtMethods = {
19
+ /**
20
+ * Get the current state of the chain of thought.
21
+ */
22
+ getState(): ChainOfThoughtState;
23
+ /**
24
+ * Set the collapsed state of the chain of thought accordion.
25
+ */
26
+ setCollapsed(collapsed: boolean): void;
27
+ /**
28
+ * Get the part methods for a specific part within this chain of thought.
29
+ */
30
+ part(selector: { index: number }): PartMethods;
31
+ };
32
+
33
+ export type ChainOfThoughtMeta = {
34
+ source: "message";
35
+ query: { type: "chainOfThought" };
36
+ };
37
+
38
+ export type ChainOfThoughtClientSchema = {
39
+ state: ChainOfThoughtState;
40
+ methods: ChainOfThoughtMethods;
41
+ meta: ChainOfThoughtMeta;
42
+ };
@@ -60,3 +60,10 @@ export type {
60
60
  ModelContextMethods,
61
61
  ModelContextClientSchema,
62
62
  } from "./modelContext";
63
+ export type {
64
+ ChainOfThoughtState,
65
+ ChainOfThoughtMethods,
66
+ ChainOfThoughtMeta,
67
+ ChainOfThoughtClientSchema,
68
+ ChainOfThoughtPart,
69
+ } from "./chainOfThought";
@@ -30,12 +30,17 @@ export type PartMethods = {
30
30
  __internal_getRuntime?(): MessagePartRuntime;
31
31
  };
32
32
 
33
- export type PartMeta = {
34
- source: "message";
35
- query:
36
- | { type: "index"; index: number }
37
- | { type: "toolCallId"; toolCallId: string };
38
- };
33
+ export type PartMeta =
34
+ | {
35
+ source: "message";
36
+ query:
37
+ | { type: "index"; index: number }
38
+ | { type: "toolCallId"; toolCallId: string };
39
+ }
40
+ | {
41
+ source: "chainOfThought";
42
+ query: { type: "index"; index: number };
43
+ };
39
44
 
40
45
  export type PartClientSchema = {
41
46
  state: PartState;
@@ -11,6 +11,7 @@ import type { ToolsClientSchema } from "./scopes/tools";
11
11
  import type { ModelContextClientSchema } from "./scopes/modelContext";
12
12
  import type { SuggestionsClientSchema } from "./scopes/suggestions";
13
13
  import type { SuggestionClientSchema } from "./scopes/suggestion";
14
+ import type { ChainOfThoughtClientSchema } from "./scopes/chainOfThought";
14
15
 
15
16
  declare module "@assistant-ui/store" {
16
17
  interface ClientRegistry {
@@ -25,5 +26,6 @@ declare module "@assistant-ui/store" {
25
26
  modelContext: ModelContextClientSchema;
26
27
  suggestions: SuggestionsClientSchema;
27
28
  suggestion: SuggestionClientSchema;
29
+ chainOfThought: ChainOfThoughtClientSchema;
28
30
  }
29
31
  }