Skip to content

Commit 7aaa8af

Browse files
committed
Refine useAIChat sendMessage contract
1 parent 1baad84 commit 7aaa8af

2 files changed

Lines changed: 20 additions & 14 deletions

File tree

packages/core/src/ai/use-ai-chat.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe("useAIChat", () => {
5050

5151
const { result } = renderHook(() => useAIChat({ client, model: "gpt-5-mini" }));
5252

53-
let sendPromise: Promise<void> | undefined;
53+
let sendPromise: Promise<boolean> | undefined;
5454
await act(async () => {
5555
sendPromise = result.current.sendMessage("Hi");
5656
});
@@ -71,7 +71,7 @@ describe("useAIChat", () => {
7171

7272
releaseSecondChunk();
7373
await act(async () => {
74-
await sendPromise;
74+
await expect(sendPromise).resolves.toBe(true);
7575
});
7676

7777
await waitFor(() => {
@@ -102,7 +102,7 @@ describe("useAIChat", () => {
102102

103103
const { result } = renderHook(() => useAIChat({ client, model: "gpt-5-mini" }));
104104

105-
let sendPromise: Promise<void> | undefined;
105+
let sendPromise: Promise<boolean> | undefined;
106106
await act(async () => {
107107
sendPromise = result.current.sendMessage("Hi");
108108
});
@@ -118,7 +118,7 @@ describe("useAIChat", () => {
118118
releaseSecondChunk();
119119

120120
await act(async () => {
121-
await sendPromise;
121+
await expect(sendPromise).resolves.toBe(false);
122122
});
123123

124124
await waitFor(() => {
@@ -145,7 +145,7 @@ describe("useAIChat", () => {
145145
const { result } = renderHook(() => useAIChat({ client, model: "gpt-5-mini" }));
146146

147147
await act(async () => {
148-
await result.current.sendMessage("Hi");
148+
await expect(result.current.sendMessage("Hi")).resolves.toBe(false);
149149
});
150150

151151
await waitFor(() => {
@@ -157,7 +157,7 @@ describe("useAIChat", () => {
157157
shouldFail = false;
158158

159159
await act(async () => {
160-
await result.current.sendMessage("Retry");
160+
await expect(result.current.sendMessage("Retry")).resolves.toBe(true);
161161
});
162162

163163
await waitFor(() => {
@@ -187,7 +187,7 @@ describe("useAIChat", () => {
187187
const { result } = renderHook(() => useAIChat({ client, model: "gpt-5-mini" }));
188188

189189
await act(async () => {
190-
await result.current.sendMessage(" ");
190+
await expect(result.current.sendMessage(" ")).resolves.toBe(false);
191191
});
192192

193193
expect(client.chatCompletionStream).not.toHaveBeenCalled();
@@ -197,7 +197,7 @@ describe("useAIChat", () => {
197197
});
198198

199199
await act(async () => {
200-
await result.current.sendMessage("Second");
200+
await expect(result.current.sendMessage("Second")).resolves.toBe(false);
201201
});
202202

203203
expect(client.chatCompletionStream).toHaveBeenCalledTimes(1);

packages/core/src/ai/use-ai-chat.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export function useAIChat(config: { client: AIGatewayClient; model: string }): {
1313
messages: AIChatMessage[];
1414
status: AIChatStatus;
1515
error?: Error;
16-
sendMessage: (message: { text: string } | string) => Promise<void>;
16+
/**
17+
* Returns true when the message is sent and the stream finishes successfully.
18+
* Returns false when the call is ignored, aborted, or the request fails.
19+
*/
20+
sendMessage: (message: string) => Promise<boolean>;
1721
stop: () => void;
1822
} {
1923
const [messages, setMessages] = useState<AIChatMessage[]>([]);
@@ -41,14 +45,14 @@ export function useAIChat(config: { client: AIGatewayClient; model: string }): {
4145
}, []);
4246

4347
const sendMessage = useCallback(
44-
async (message: { text: string } | string) => {
48+
async (message: string) => {
4549
if (abortControllerRef.current) {
46-
return;
50+
return false;
4751
}
4852

49-
const text = (typeof message === "string" ? message : message.text).trim();
53+
const text = message.trim();
5054
if (!text) {
51-
return;
55+
return false;
5256
}
5357

5458
const userMessage: AIChatMessage = {
@@ -102,14 +106,16 @@ export function useAIChat(config: { client: AIGatewayClient; model: string }): {
102106
}
103107

104108
setStatus("ready");
109+
return true;
105110
} catch (caughtError) {
106111
if (isAbortError(caughtError)) {
107112
setStatus("ready");
108-
return;
113+
return false;
109114
}
110115

111116
setError(toError(caughtError));
112117
setStatus("error");
118+
return false;
113119
} finally {
114120
abortControllerRef.current = null;
115121
}

0 commit comments

Comments
 (0)