@assistant-ui/react-ag-ui 0.0.64 → 0.0.65

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.
@@ -180,16 +180,22 @@ export type AgUiEvent =
180
180
  delta: string;
181
181
  subagentRunId?: string;
182
182
  }
183
- | { type: "THINKING_START"; title?: string }
184
- | { type: "THINKING_TEXT_MESSAGE_START" }
183
+ | { type: "THINKING_START"; title?: string; timestamp?: number }
184
+ | { type: "THINKING_TEXT_MESSAGE_START"; timestamp?: number }
185
185
  | { type: "THINKING_TEXT_MESSAGE_CONTENT"; delta: string }
186
- | { type: "THINKING_TEXT_MESSAGE_END" }
187
- | { type: "THINKING_END" }
188
- | { type: "REASONING_START"; messageId?: string; subagentRunId?: string }
186
+ | { type: "THINKING_TEXT_MESSAGE_END"; timestamp?: number }
187
+ | { type: "THINKING_END"; timestamp?: number }
188
+ | {
189
+ type: "REASONING_START";
190
+ messageId?: string;
191
+ subagentRunId?: string;
192
+ timestamp?: number;
193
+ }
189
194
  | {
190
195
  type: "REASONING_MESSAGE_START";
191
196
  messageId?: string;
192
197
  subagentRunId?: string;
198
+ timestamp?: number;
193
199
  }
194
200
  | {
195
201
  type: "REASONING_MESSAGE_CONTENT";
@@ -201,6 +207,7 @@ export type AgUiEvent =
201
207
  type: "REASONING_MESSAGE_END";
202
208
  messageId?: string;
203
209
  subagentRunId?: string;
210
+ timestamp?: number;
204
211
  }
205
212
  | {
206
213
  type: "REASONING_ENCRYPTED_VALUE";
@@ -209,7 +216,12 @@ export type AgUiEvent =
209
216
  encryptedValue: string;
210
217
  subagentRunId?: string;
211
218
  }
212
- | { type: "REASONING_END"; messageId?: string; subagentRunId?: string }
219
+ | {
220
+ type: "REASONING_END";
221
+ messageId?: string;
222
+ subagentRunId?: string;
223
+ timestamp?: number;
224
+ }
213
225
  | {
214
226
  type: "TOOL_CALL_START";
215
227
  toolCallId: string;
@@ -96,11 +96,67 @@ describe("useAgUiRuntime unstable_enableMessageQueue", () => {
96
96
  );
97
97
  });
98
98
 
99
+ it("holds queued sends while sending is disabled", async () => {
100
+ const { agent, runAgent, release } = gatedAgent();
101
+
102
+ const { result, rerender } = renderHook(
103
+ ({ isSendDisabled }) =>
104
+ useAgUiRuntime({
105
+ agent,
106
+ unstable_enableMessageQueue: true,
107
+ isSendDisabled,
108
+ }),
109
+ { initialProps: { isSendDisabled: false } },
110
+ );
111
+ mount(result.current);
112
+
113
+ await act(async () => {
114
+ await result.current.thread.append({
115
+ role: "user",
116
+ content: [{ type: "text", text: "first" }],
117
+ });
118
+ });
119
+ await waitFor(() => expect(runAgent).toHaveBeenCalledTimes(1));
120
+
121
+ await act(async () => {
122
+ await result.current.thread.append({
123
+ role: "user",
124
+ content: [{ type: "text", text: "second" }],
125
+ parentId: result.current.thread.getState().messages.at(-1)?.id ?? null,
126
+ });
127
+ });
128
+ await waitFor(() =>
129
+ expect(screen.getByTestId("queued").textContent).toBe("second"),
130
+ );
131
+ rerender({ isSendDisabled: true });
132
+
133
+ await act(async () => {
134
+ release();
135
+ });
136
+ await waitFor(() =>
137
+ expect(result.current.thread.getState().isRunning).toBe(false),
138
+ );
139
+ expect(runAgent).toHaveBeenCalledTimes(1);
140
+ expect(screen.getByTestId("queued").textContent).toBe("second");
141
+
142
+ rerender({ isSendDisabled: false });
143
+ await waitFor(() => expect(runAgent).toHaveBeenCalledTimes(2));
144
+ await waitFor(() =>
145
+ expect(screen.getByTestId("queued").textContent).toBe(""),
146
+ );
147
+ });
148
+
99
149
  it("preserves queued sends when the active run is cancelled", async () => {
100
150
  const { agent, runAgent, release } = gatedAgent();
101
151
 
102
- const { result } = renderHook(() =>
103
- useAgUiRuntime({ agent, unstable_enableMessageQueue: true }),
152
+ const { result, rerender } = renderHook(
153
+ ({ isSendDisabled }) =>
154
+ useAgUiRuntime({
155
+ agent,
156
+ unstable_enableMessageQueue: true,
157
+ isSendDisabled,
158
+ }),
159
+ { initialProps: { isSendDisabled: false } },
104
160
  );
105
161
  mount(result.current);
106
162
 
@@ -135,6 +191,11 @@ describe("useAgUiRuntime unstable_enableMessageQueue", () => {
135
191
  expect(screen.getByTestId("queued").textContent).toBe("second"),
136
192
  );
137
193
 
194
+ rerender({ isSendDisabled: true });
195
+ rerender({ isSendDisabled: false });
196
+ expect(runAgent).toHaveBeenCalledTimes(1);
197
+ expect(screen.getByTestId("queued").textContent).toBe("second");
198
+
138
199
  await act(async () => {
139
200
  await result.current.thread.append({
140
201
  role: "user",
@@ -175,6 +175,14 @@ export function useAgUiRuntime(
175
175
  // and the queue drops an item before dispatching it, so draining into that
176
176
  // refusal would lose the message instead of keeping it visible.
177
177
  const queueBusy = isRunning || core.getPendingInterrupts() !== null;
178
+ useEffect(() => {
179
+ if (options.isSendDisabled === true) {
180
+ queueController?.hold();
181
+ } else {
182
+ queueController?.release();
183
+ }
184
+ }, [options.isSendDisabled, queueController]);
185
+
178
186
  useEffect(() => {
179
187
  if (!queueController) return;
180
188
  if (