Repository: coze-dev/coze-js
Pull request #157: feat: bugfix for tt and refreshtoken in chat
Author: login: DingGao-Devin
Created: 2025-03-24T02:40:02Z | Merged: 2025-03-25T09:08:59Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Introduced pre-send detection during message composition to ensure messages are sent only when allowed.
  - Enabled automatic cleanup of temporary audio files for smoother media playback.

- **Bug Fixes**
  - Enhanced error handling for authentication issues and token refresh, resulting in improved session reliability.
  - Addressed sequencing issues in audio playback and messaging across various app scenarios.

- **Style**
  - Updated UI text rendering and standardized cosmetic styling for a cleaner chat display.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-13-02-28.json b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-13-02-28.json
new file mode 100644
index 00000000..8bc830a1
--- /dev/null
+++ b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-13-02-28.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@coze/chat-sdk",
+      "comment": "添加input判断逻辑",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@coze/chat-sdk",
+  "email": "gaoding.devingao@bytedance.com"
+}
diff --git a/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-02-23.json b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-02-23.json
new file mode 100644
index 00000000..c66a5f44
--- /dev/null
+++ b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-02-23.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@coze/chat-sdk",
+      "comment": "发送前检测",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@coze/chat-sdk",
+  "email": "gaoding.devingao@bytedance.com"
+}
diff --git a/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-08-49.json b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-08-49.json
new file mode 100644
index 00000000..99b66c55
--- /dev/null
+++ b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-08-49.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@coze/chat-sdk",
+      "comment": "fix bug in tt mini app",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@coze/chat-sdk",
+  "email": "gaoding.devingao@bytedance.com"
+}
diff --git a/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-17.json b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-17.json
new file mode 100644
index 00000000..3492b31b
--- /dev/null
+++ b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-17.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@coze/chat-sdk",
+      "comment": "fix apiclient refreshtoken on error",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@coze/chat-sdk",
+  "email": "gaoding.devingao@bytedance.com"
+}
diff --git a/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-37.json b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-37.json
new file mode 100644
index 00000000..3a418760
--- /dev/null
+++ b/common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-37.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@coze/chat-sdk",
+      "comment": "change dependcies",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@coze/chat-sdk",
+  "email": "gaoding.devingao@bytedance.com"
+}
diff --git a/packages/chat-sdk/package.json b/packages/chat-sdk/package.json
index 8d96c516..f444e620 100644
--- a/packages/chat-sdk/package.json
+++ b/packages/chat-sdk/package.json
@@ -154,4 +154,4 @@
     "css": "Less",
     "framework": "React"
   }
-}
\ No newline at end of file
+}
diff --git a/packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx b/packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx
index d27885c2..80819e05 100644
--- a/packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx
+++ b/packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx
@@ -60,7 +60,6 @@ export const CommandAudio: FC<{
         if (!refPlayAudio.current) {
           refPlayAudio.current = new PlayAudio();
         }
-        await refPlayAudio.current.playText(text, audioSpeech);
         refPlayAudio.current.on(AudioPlayEvent.STOP, res => {
           logger.debug('CommandAudio Stop Audio Play', res);
           if ((res as { isError?: boolean }).isError) {
@@ -68,6 +67,7 @@ export const CommandAudio: FC<{
           }
           setIsPlaying(false);
         });
+        await refPlayAudio.current.playText(text, audioSpeech);
       } catch (error) {
         //如果失败
         handleError();
diff --git a/packages/chat-sdk/src/libs/services/helper/chat-service.ts b/packages/chat-sdk/src/libs/services/helper/chat-service.ts
index 3b771bcd..307ecf40 100644
--- a/packages/chat-sdk/src/libs/services/helper/chat-service.ts
+++ b/packages/chat-sdk/src/libs/services/helper/chat-service.ts
@@ -9,7 +9,7 @@ import type {
   CozeAPI,
 } from '@coze/api';
 
-import { logger, MiniChatError } from '@/libs/utils';
+import { logger, MiniChatError, MiniCozeApi } from '@/libs/utils';
 import { SuggestPromoteInfo } from '@/libs/types/base/chat';
 import { IChatService, ChatServiceProps } from '@/libs/types';
 import type { ChatInfo, ChatType } from '@/libs/types';
@@ -155,4 +155,11 @@ export class ChatService implements IChatService {
   }) {
     return await this.apiClient.audio.speech.create(params);
   }
+  async handleErrorCode(code: number) {
+    const apiClient = this.apiClient as MiniCozeApi;
+    if (apiClient.isAuthErrorCode(code)) {
+      return await apiClient.refreshToken(apiClient.token as string);
+    }
+    return '';
+  }
 }
diff --git a/packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts b/packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts
index 13a0b2c2..7669ddcd 100644
--- a/packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts
+++ b/packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts
@@ -49,6 +49,7 @@ export class AsyncSendMessage extends MultiSendMessage {
     this._checkTimeout();
     try {
       for await (const eventData of this.chatStream) {
+        logger.debug('asyncChat pollAnswer awaiting start2', eventData);
         this._checkTimeout();
         if (!this.isAbort) {
           const { event, data } = eventData;
@@ -142,6 +143,7 @@ export class AsyncSendMessage extends MultiSendMessage {
                 code: number;
                 msg: string;
               };
+              this.chatService.handleErrorCode(messageError.code || -1);
               this.sendErrorEvent(
                 new MiniChatError(
                   messageError.code || -1,
diff --git a/packages/chat-sdk/src/libs/services/use-send-message.ts b/packages/chat-sdk/src/libs/services/use-send-message.ts
index e9c4a170..c46f4088 100644
--- a/packages/chat-sdk/src/libs/services/use-send-message.ts
+++ b/packages/chat-sdk/src/libs/services/use-send-message.ts
@@ -51,8 +51,11 @@ export const useSendMessage = () => {
   const onRequiresAction = useChatPropsStore(
     store => store.eventCallbacks?.message?.onRequiresAction,
   );
+  const checkCanSendMessage = useChatPropsStore(
+    store => store.ui?.chatSlot?.input?.checkCanSendMessage,
+  );
   const sendMessage = usePersistCallback(
-    (rawMessage: RawMessage, historyMessages?: EnterMessage[]) => {
+    async (rawMessage: RawMessage, historyMessages?: EnterMessage[]) => {
       const { clearMessage: disableState } = getOpDisabledState();
       if (disableState) {
         return;
@@ -60,6 +63,12 @@ export const useSendMessage = () => {
       if (!botId || !conversationId) {
         return;
       }
+      if (checkCanSendMessage) {
+        if ((await checkCanSendMessage(rawMessage)) === false) {
+          return false;
+        }
+      }
+
       // Clear task message after message sended
       setTaskList({ taskList: [] });
       setIsDeleting(true);
@@ -104,38 +113,35 @@ export const useSendMessage = () => {
   );
 
   const sendTextMessage = useCallback(
-    (content: string) => {
-      sendMessage({
+    async (content: string) =>
+      await sendMessage({
         type: RawMessageType.TEXT,
         data: content,
-      });
-    },
+      }),
     [sendMessage],
   );
   const sendFileMessage = useCallback(
-    (files: ChooseFileInfo[]) => {
-      sendMessage({
+    async (files: ChooseFileInfo[]) =>
+      await sendMessage({
         type: RawMessageType.FILE,
         data: files,
-      });
-    },
+      }),
     [sendMessage],
   );
 
   const sendAudioMessage = useCallback(
-    (audio: AudioRaw) => {
-      sendMessage({
+    async (audio: AudioRaw) =>
+      await sendMessage({
         type: RawMessageType.AUDIO,
         data: audio,
-      });
-    },
+      }),
     [sendMessage],
   );
 
-  const reSendLastErrorMessage = useCallback(() => {
+  const reSendLastErrorMessage = useCallback(async () => {
     const chatMessageGroup = popLastErrorChatGroup();
     if (chatMessageGroup?.query?.rawMessage) {
-      sendMessage(chatMessageGroup?.query?.rawMessage);
+      return await sendMessage(chatMessageGroup?.query?.rawMessage);
     }
   }, [sendMessage]);
 
diff --git a/packages/chat-sdk/src/libs/types/base/ui.ts b/packages/chat-sdk/src/libs/types/base/ui.ts
index d526969e..c4a05bc7 100644
--- a/packages/chat-sdk/src/libs/types/base/ui.ts
+++ b/packages/chat-sdk/src/libs/types/base/ui.ts
@@ -2,6 +2,7 @@ import React from 'react';
 
 import { II18n } from '../utils/i18n';
 import { IMiniChatError } from '../utils/error';
+import { type RawMessage } from '../services/send-message';
 import { ChatMessage, ChatMessageGroup } from './message';
 import { IOnImageClickEvent, IOnTaskListChange } from './event-callback';
 
@@ -55,6 +56,10 @@ export interface InputConfig {
   isNeedTaskMessage?: boolean; // Whether or not using task message， default is false
   placeholder?: string;
   defaultText?: string;
+  // 判断是否可以发送消息，返回false则不能发送，其他可发送（包括undefined）
+  checkCanSendMessage?: (
+    message: RawMessage,
+  ) => Promise<boolean | undefined> | boolean | undefined;
   renderChatInputTopSlot?: (isChatError?: boolean) => React.ReactNode;
 }
 export interface ClearContextConfig {
diff --git a/packages/chat-sdk/src/libs/types/services/chat-service.ts b/packages/chat-sdk/src/libs/types/services/chat-service.ts
index ac6c5477..b916d457 100644
--- a/packages/chat-sdk/src/libs/types/services/chat-service.ts
+++ b/packages/chat-sdk/src/libs/types/services/chat-service.ts
@@ -65,6 +65,7 @@ export interface IChatService {
     params: CreateFileReq,
     options?: RequestOptions,
   ) => Promise<FileObject>;
+  handleErrorCode: (code: number) => Promise<string>;
   audioSpeech: (params: {
     input: string;
     voice_id: string;
diff --git a/packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts b/packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts
index f4d69b5c..78351107 100644
--- a/packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts
+++ b/packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts
@@ -58,7 +58,7 @@ export const useTextInputHandle = (
     }
   }, [defaultValue]);
 
-  const onSendTextMessage = usePersistCallback(() => {
+  const onSendTextMessage = usePersistCallback(async () => {
     logger.debug('useTextInputHandle onSendTextMessage:', {
       inputValue,
       toSendInputValue,
@@ -66,7 +66,9 @@ export const useTextInputHandle = (
     });
 
     if (toSendInputValue && !disabled) {
-      onSendTextMessageOnly?.(toSendInputValue);
+      if ((await onSendTextMessageOnly?.(toSendInputValue)) === false) {
+        return;
+      }
 
       clearInput(!isWeb);
     }
diff --git a/packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts b/packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts
index 926cbf4d..954e0d71 100644
--- a/packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts
+++ b/packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts
@@ -24,10 +24,10 @@ export interface IChatInputProps {
   frameEventTarget?: InstanceType<TaroStatic['Events']>;
   isPcMode?: boolean;
   onKeyBoardHeightChange?: (height: number) => void;
-  onSendTextMessage?: (text: string) => void;
-  onSendFileMessage?: (files: ChooseFileInfo[]) => void;
-  onSendAudioMessage?: (audio: AudioRaw) => void;
-  onAudioRecording?: (isRecording: boolean) => void;
+  onSendTextMessage?: (text: string) => Promise<boolean | undefined>;
+  onSendFileMessage?: (files: ChooseFileInfo[]) => Promise<boolean | undefined>;
+  onSendAudioMessage?: (audio: AudioRaw) => Promise<boolean | undefined>;
+  onAudioRecording?: (isRecording: boolean) => Promise<boolean | undefined>;
 }
 
 export interface ITaskMessage {
diff --git a/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less b/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less
index 955ef80a..70cd3987 100644
--- a/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less
+++ b/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less
@@ -39,11 +39,10 @@
     line-height: 20px;
     font-weight: 400;
     margin-bottom: 12px;
-
   }
 
   .switch-node-switch-item {
-    background-color: #FFF;
+    background-color: #fff;
     font-size: 14px;
     padding: 6px 15px;
     line-height: 20px;
diff --git a/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx b/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx
index e501f4a0..f54d9d2b 100644
--- a/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx
+++ b/packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx
@@ -113,11 +113,7 @@ const SwitchNode: FC<{
               sendTextMessage?.(item.name);
             }}
           >
-            <Text
-              className={styles['switch-node-switch-item-text']}
-              numberOfLines={1}
-              overflow="ellipsis"
-            >
+            <Text className={styles['switch-node-switch-item-text']}>
               {item.name}
             </Text>
           </View>
diff --git a/packages/chat-sdk/src/libs/utils/event-source/request.ts b/packages/chat-sdk/src/libs/utils/event-source/request.ts
index 4bcbae83..e1fc8070 100644
--- a/packages/chat-sdk/src/libs/utils/event-source/request.ts
+++ b/packages/chat-sdk/src/libs/utils/event-source/request.ts
@@ -42,16 +42,31 @@ export async function* requestSSE(
   });
   eventSource.sendMessage();
   genNextPromise();
+  let hsSendData = false;
   do {
     await yieldPromise;
+    let hasDataToResolve = false;
     const messageListNow = messageList.splice(0);
     genNextPromise();
     for (const eventData of messageListNow) {
       if (eventData) {
+        hsSendData = true;
+        hasDataToResolve = true;
         yield eventData;
       }
     }
-    // eslint-disable-next-line  no-unmodified-loop-condition
+
+    if (isDone && !hasDataToResolve) {
+      if (hsSendData) {
+        yield {
+          data: '[DONE]',
+          event: 'done',
+        };
+      } else {
+        throw new Error('EventSourceRequest has been closed');
+      }
+    }
+    // eslint-disable-next-line
   } while (!isDone);
 
   function genNextPromise() {
diff --git a/packages/chat-sdk/src/libs/utils/mini-coze-api.ts b/packages/chat-sdk/src/libs/utils/mini-coze-api.ts
index 01d72260..6a6bde68 100644
--- a/packages/chat-sdk/src/libs/utils/mini-coze-api.ts
+++ b/packages/chat-sdk/src/libs/utils/mini-coze-api.ts
@@ -96,7 +96,7 @@ export class MiniCozeApi extends CozeAPI {
       },
     );
   }
-  private isAuthErrorCode(code: number) {
+  isAuthErrorCode(code: number) {
     return [
       ApiAuthError.ERROR_FORBIDDEN,
       ApiAuthError.ERROR_INVALID_TOKEN,
@@ -107,13 +107,13 @@ export class MiniCozeApi extends CozeAPI {
   getTokenFromHeaderAuth(authorization: string) {
     return authorization.replace(/^\s*Bearer\s*/, '').replace(/\s+$/, '');
   }
-  async refreshToken(oldToken: string) {
+  async refreshToken(oldToken: string): Promise<string> {
     if (this.refreshTokenPromise) {
       return this.refreshTokenPromise;
     }
     if (oldToken !== this.token) {
       // 同时并发的接口已经获取过token，直接返回
-      return this.token;
+      return this.token as string;
     }
     this.refreshTokenPromise = this.onRefreshToken?.(this.token);
     const token = await this.refreshTokenPromise;
@@ -153,7 +153,11 @@ export class MiniCozeApi extends CozeAPI {
     options?: RequestOptions,
   ): Promise<Rsp> {
     if (isWeb || !isStream) {
-      return super.makeRequest(apiUrl, method, body, isStream, options);
+      try {
+        return super.makeRequest(apiUrl, method, body, isStream, options);
+      } catch (err) {
+        console.log('makeRequestError:', err);
+      }
     }
     return this.requestMiniSse({
       apiUrl,
diff --git a/packages/chat-sdk/src/libs/utils/play-audio.ts b/packages/chat-sdk/src/libs/utils/play-audio.ts
index a8eaef13..8590e4ab 100644
--- a/packages/chat-sdk/src/libs/utils/play-audio.ts
+++ b/packages/chat-sdk/src/libs/utils/play-audio.ts
@@ -16,7 +16,7 @@ export class PlayAudio {
   private audioContext?: InnerAudioContext;
   private event: InstanceType<TaroStatic['Events']> = new Events();
   private audioPrm: Promise<ArrayBuffer> | null = null;
-
+  private filePath = '';
   static stopNow() {
     PlayAudio.instance?.stop();
   }
@@ -31,6 +31,7 @@ export class PlayAudio {
       this.audioPrm = audioSpeechFunc(text);
     }
     this.isStop = false;
+    PlayAudio.instance = this;
     try {
       const audioData = await this.audioPrm;
       if (this.isStop) {
@@ -52,18 +53,13 @@ export class PlayAudio {
       tempFile = URL.createObjectURL(blobData);
     } else {
       tempFile = `${Taro.env.USER_DATA_PATH}/tempFile${playNo++}.wav`;
+      this.filePath = tempFile;
       Taro.getFileSystemManager().writeFileSync(tempFile, data, 'binary');
     }
     logger.debug('playData:', tempFile);
     this.play(tempFile);
   }
   async play(audioSrc: string) {
-    if (!PlayAudio.instance?.isStop) {
-      PlayAudio.instance?.stop();
-    }
-
-    this.isStop = false;
-
     PlayAudio.instance = this;
     this.audioContext = Taro.createInnerAudioContext();
     this.audioContext.src = audioSrc;
@@ -114,6 +110,16 @@ export class PlayAudio {
     } catch (_err) {
       this.emitStopEvent(true);
     }
+    this.removeAudio();
+  }
+  removeAudio() {
+    try {
+      if (!isWeb) {
+        Taro.getFileSystemManager().unlinkSync(this.filePath || '');
+      }
+    } catch (err) {
+      logger.error('removeAudio error', err);
+    }
   }
   on(event: AudioPlayEvent, callback: (params: unknown) => void) {
     this.event.on(event, callback);
diff --git a/packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts b/packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts
index ea2768dd..17911b25 100644
--- a/packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts
+++ b/packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts
@@ -79,22 +79,30 @@ export class TaroRecorderManager extends BaseRecorderManager {
         success: res => {
           logger.debug('TaroRecorderManager getSetting', res);
           if (res.authSetting['scope.record'] !== true) {
-            Taro.authorize({
-              scope: 'scope.record',
-              success: () => {
-                logger.debug('TaroRecorderManager authorize scope.record true');
-                resolve(true);
-              },
-              fail: resFail => {
-                logger.error(
-                  'TaroRecorderManager authorize scope.record false',
-                  resFail,
-                );
-                reject(
-                  new Error('TaroRecorderManager authorize scope.record false'),
-                );
-              },
-            });
+            if (isTT) {
+              resolve(true);
+            } else {
+              Taro.authorize({
+                scope: 'scope.record',
+                success: () => {
+                  logger.debug(
+                    'TaroRecorderManager authorize scope.record true',
+                  );
+                  resolve(true);
+                },
+                fail: resFail => {
+                  logger.error(
+                    'TaroRecorderManager authorize scope.record false',
+                    resFail,
+                  );
+                  reject(
+                    new Error(
+                      'TaroRecorderManager authorize scope.record false',
+                    ),
+                  );
+                },
+              });
+            }
           } else {
             logger.debug('TaroRecorderManager getSetting scope.record true');
             resolve(true);
diff --git a/packages/chat-sdk/src/pages/chat/index.tsx b/packages/chat-sdk/src/pages/chat/index.tsx
index a33cd3f3..ead76f0f 100644
--- a/packages/chat-sdk/src/pages/chat/index.tsx
+++ b/packages/chat-sdk/src/pages/chat/index.tsx
@@ -52,6 +52,8 @@ export default function Index() {
               input: {
                 isNeedAudio: true,
                 renderChatInputTopSlot: props => <View>Input Slot</View>,
+                checkCanSendMessage: _message => true,
+                //return false;
               },
               messageWrapper: {
                 senderName: {


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-37.json (1)</summary><blockquote>

`1-11`: **Typo in JSON Change Comment**

The change entry's "comment" field `"change dependcies"` contains a typo. Please update it to `"change dependencies"` to maintain clarity and consistency.

```diff
-      "comment": "change dependcies",
+      "comment": "change dependencies",
```

</blockquote></details>
<details>
<summary>packages/chat-sdk/src/pages/chat/index.tsx (1)</summary><blockquote>

`55-56`: **Pre-send message validation mechanism looks good, but contains commented code.**

The new `checkCanSendMessage` function provides a foundation for message validation before sending. It currently always returns `true`, which doesn't affect existing behavior.

The commented line `//return false;` should either be removed or properly structured within the function body if it's intended for future use.


```diff
-                checkCanSendMessage: _message => true,
-                //return false;
+                checkCanSendMessage: _message => {
+                  // TODO: Add validation logic here if needed
+                  return true;
+                },
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 51b5d1e04d5e41f34ee008ab26e740edb6acdacf and 2c8ef88ff110d292cdbf1d41ca7c3b526f753282.

</details>

<details>
<summary>📒 Files selected for processing (21)</summary>

* `common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-13-02-28.json` (1 hunks)
* `common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-02-23.json` (1 hunks)
* `common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-08-49.json` (1 hunks)
* `common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-17.json` (1 hunks)
* `common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-37.json` (1 hunks)
* `packages/chat-sdk/package.json` (1 hunks)
* `packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx` (1 hunks)
* `packages/chat-sdk/src/libs/services/helper/chat-service.ts` (2 hunks)
* `packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts` (2 hunks)
* `packages/chat-sdk/src/libs/services/use-send-message.ts` (2 hunks)
* `packages/chat-sdk/src/libs/types/base/ui.ts` (2 hunks)
* `packages/chat-sdk/src/libs/types/services/chat-service.ts` (1 hunks)
* `packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts` (1 hunks)
* `packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts` (1 hunks)
* `packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less` (1 hunks)
* `packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx` (1 hunks)
* `packages/chat-sdk/src/libs/utils/event-source/request.ts` (1 hunks)
* `packages/chat-sdk/src/libs/utils/mini-coze-api.ts` (3 hunks)
* `packages/chat-sdk/src/libs/utils/play-audio.ts` (4 hunks)
* `packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts` (1 hunks)
* `packages/chat-sdk/src/pages/chat/index.tsx` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (4)</summary>

<details>
<summary>packages/chat-sdk/src/libs/services/helper/chat-service.ts (1)</summary><blockquote>

<details>
<summary>packages/chat-sdk/src/libs/utils/mini-coze-api.ts (1)</summary>

* `MiniCozeApi` (35-316)

</details>

</blockquote></details>
<details>
<summary>packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts (1)</summary><blockquote>

<details>
<summary>packages/chat-sdk/src/libs/utils/index.ts (1)</summary>

* `logger` (20-20)

</details>

</blockquote></details>
<details>
<summary>packages/chat-sdk/src/libs/types/base/ui.ts (1)</summary><blockquote>

<details>
<summary>packages/chat-sdk/src/libs/types/services/send-message.ts (1)</summary>

* `RawMessage` (21-33)

</details>

</blockquote></details>
<details>
<summary>packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts (1)</summary><blockquote>

<details>
<summary>packages/chat-sdk/src/libs/utils/index.ts (1)</summary>

* `logger` (20-20)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Node.js v20 (ubuntu-latest)

</details>

<details>
<summary>🔇 Additional comments (34)</summary><blockquote>

<details>
<summary>common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-13-02-28.json (1)</summary>

`1-11`: **JSON Structure and Entry for Input Validation Change**

The file is well-formed and clearly documents the minor change ("添加input判断逻辑") for the @coze/chat-sdk package. All required keys (such as "changes", "packageName", and "email") are provided and consistent with similar change log files.

</details>
<details>
<summary>common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-08-49.json (1)</summary>

`1-11`: **JSON Entry for TT Mini App Bugfix**

The change log correctly records a minor bug fix ("fix bug in tt mini app") for the @coze/chat-sdk package. The structure is consistent with other change log files. Verify that this change is fully integrated with the corresponding TT mini app code if needed.

</details>
<details>
<summary>common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-21-02-23.json (1)</summary>

`1-11`: **JSON Entry for Pre-send Detection Feature**

The file correctly documents the addition of the pre-send detection feature ("发送前检测") with a clear and consistent structure across the change log files.

</details>
<details>
<summary>packages/chat-sdk/package.json (1)</summary>

`1-158`: **Minor Formatting Update in package.json**

The only change is the addition of a newline character at the end of the file, which is a best practice for file formatting. There are no functional changes or alterations to dependency configuration or scripts.

</details>
<details>
<summary>common/changes/@coze/chat-sdk/feat-feat-nl2app3_2025-03-24-02-17.json (1)</summary>

`1-11`: **Change log file looks good.**

The change log entry correctly documents the fix for the API client's refresh token handling on error. The metadata and structure follow the expected format.

</details>
<details>
<summary>packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less (1)</summary>

`45-45`: **Consistent CSS formatting.**

The change from `#FFF` to `#fff` standardizes the hex color code format to lowercase, which is good for consistency.

</details>
<details>
<summary>packages/chat-sdk/src/libs/types/services/chat-service.ts (1)</summary>

`68-68`: **New error handling method looks good.**

The addition of `handleErrorCode` method to the `IChatService` interface aligns with the PR objective of fixing the refresh token mechanism. This method will allow for proper error code processing related to authentication issues.

</details>
<details>
<summary>packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts (1)</summary>

`82-105`: <details>
<summary>✅ Verification successful</summary>

**Improved microphone permission handling for TT platform.**

The change adds a special case for the TT platform (TikTok's mini-app platform) to bypass the normal microphone authorization flow. This fixes permission handling issues specific to the TT platform while maintaining the original logic for other platforms.


---

🏁 Script executed:

```shell
#!/bin/bash
# Verify that isTT is properly defined and used consistently across the codebase

# Check how isTT is defined
rg -A 5 "export const isTT" --type=typescript

# Check other usages of isTT with Taro.authorize to understand the pattern
rg "isTT.*Taro\.authorize" --type=typescript
```

Length of output: 164

---

Below is an updated verification script that avoids the “unrecognized file type: typescript” issue by searching only in *.ts and *.tsx files. Please run the script and manually verify that:

• The constant `isTT` is consistently defined where expected.  
• Its usage alongside `Taro.authorize` follows the correct pattern throughout the codebase, ensuring that the special-case handling for the TT platform is applied correctly.



Please share the output or verify it yourself to ensure the modifications (specifically, the TT platform’s bypass of the regular authorization flow) are correctly integrated into the codebase.



---

🏁 Script executed:

```shell

#!/bin/bash
echo "Searching for 'export const isTT' definitions in .ts and .tsx files..."
rg -A 5 "export const isTT" -g "*.ts" -g "*.tsx"

echo "Searching for usages of 'isTT' with Taro.authorize in .ts and .tsx files..."
rg "isTT.*Taro\.authorize" -g "*.ts" -g "*.tsx"
```

Length of output: 989

---



</details>

**TT Platform Microphone Permission Handling Verified**

The modification to bypass the standard microphone authorization flow for TT platforms has been verified:

- The `isTT` constant is defined as `export const isTT = env === ENV_TYPE.TT;` in `packages/chat-sdk/src/libs/utils/device.ts`.
- The `taro-recorder-manager.ts` file correctly uses an `if (isTT)` check to immediately resolve, bypassing the Taro authorization flow on TT platforms (lines 82–105).

Based on the gathered evidence, the special-case handling for the TT platform is implemented as intended and aligns with the original design.

</details>
<details>
<summary>packages/chat-sdk/src/libs/framework/component/chat-group-list/command/command-audio/index.tsx (1)</summary>

`70-70`: **Fixed audio playback event handling sequence.**

Moving the audio playback call after the event listener registration ensures that the stop event listener is properly set up before audio starts playing. This prevents potential race conditions where audio could finish playing before the listener is registered, leading to state inconsistencies.

</details>
<details>
<summary>packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx (1)</summary>

`116-116`: **Simplified text display in switch node options.**

Removed the `numberOfLines` and `overflow` properties from the Text component, which allows the text to wrap naturally instead of being truncated with ellipsis. This improves readability for longer option texts.

</details>
<details>
<summary>packages/chat-sdk/src/libs/services/helper/chat-service.ts (2)</summary>

`12-12`: **Added MiniCozeApi import to support token refresh functionality.**

Added import for MiniCozeApi which is required for the new token refresh handling.

---

`158-164`: <details>
<summary>❓ Verification inconclusive</summary>

**Added token refresh mechanism for authentication errors.**

This new method handles authentication errors by automatically refreshing the token when necessary. This is a critical fix for scenarios where users might experience session timeouts or token expiration during chat sessions.


---

🏁 Script executed:

```shell
#!/bin/bash
# Check where this method is called to understand its integration points

# Search for references to handleErrorCode method
rg "handleErrorCode\(" --type=typescript

# Check if there's an interface definition that this implementation satisfies
rg "interface.*ChatService" -A 20 --type=typescript
```

Length of output: 166

---



</details>

Below is a revised set of commands that target the correct file extension. Please run this new script to verify integration points (usage of the new token refresh mechanism and any ChatService interface implementations):

```shell
#!/bin/bash
# Search for references to handleErrorCode in all .ts files
rg "handleErrorCode\(" -g "*.ts"

# Search for the ChatService interface definition in all .ts files
rg "interface ChatService" -g "*.ts"
```

Once you run these commands, please verify that the method is indeed being integrated correctly and that there are no missing references. If everything checks out, we can finalize the review comment accordingly.

</details>
<details>
<summary>packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts (2)</summary>

`52-52`: **Added helpful debug log.**

This log statement improves debugging by capturing each event as it's processed in the polling loop, making it easier to troubleshoot stream processing issues.

---

`146-146`: **Enhanced error handling with centralized error code processing.**

Good addition of the `handleErrorCode` method call before sending the error event, which centralizes error code handling logic in the ChatService class and improves token refresh handling for authentication errors.

</details>
<details>
<summary>packages/chat-sdk/src/libs/types/base/ui.ts (1)</summary>

`5-5`: **Added message validation capability.**

The new `checkCanSendMessage` property adds a valuable pre-send validation mechanism that can prevent invalid messages from being sent. The function signature supports both synchronous and asynchronous validation, providing flexibility for different validation scenarios.



Also applies to: 59-62

</details>
<details>
<summary>packages/chat-sdk/src/libs/utils/mini-coze-api.ts (2)</summary>

`99-99`: **Improved cross-class error handling access.**

Making `isAuthErrorCode` public allows the method to be used by other classes, specifically enabling the new `handleErrorCode` method in the ChatService class to check for authentication errors when handling error codes.

---

`110-110`: **Enhanced type safety for token handling.**

The explicit return type declaration for `refreshToken` and the string type casting for `this.token` improve type safety and make the API more self-documenting.



Also applies to: 116-116

</details>
<details>
<summary>packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts (1)</summary>

`61-71`: **Improved message sending flow with validation.**

Making `onSendTextMessage` async and adding the conditional check for the result of `onSendTextMessageOnly` enhances the control flow by:

1. Supporting asynchronous validation through the new `checkCanSendMessage` function
2. Preventing further execution when validation fails (returns `false`)
3. Maintaining backward compatibility with synchronous implementations

This change aligns with the new validation capabilities added to the `InputConfig` interface.

</details>
<details>
<summary>packages/chat-sdk/src/libs/utils/event-source/request.ts (4)</summary>

`45-45`: **Improved error handling for SSE requests**

Added variable to track if any data has been sent during the request lifecycle. This will be used to determine the appropriate action when the connection is closed.

---

`48-48`: **Enhanced completion state tracking**

Added flag to track if there are messages to yield in the current iteration, improving the control flow.

---

`52-55`: **Proper data transmission tracking**

Setting both flags when event data exists ensures accurate state management for both the overall request lifecycle and the current iteration.

---

`59-68`: **Improved SSE completion handling**

This logic enhancement properly handles the request completion state:
1. If the connection is done but no data is available to resolve in this iteration
2. If data was sent during the request, a proper completion message is yielded
3. Otherwise, an error is thrown to indicate an unexpected closure

This fixes potential issues in the TT mini app where connections might close without proper data transmission.

</details>
<details>
<summary>packages/chat-sdk/src/libs/utils/play-audio.ts (5)</summary>

`19-19`: **Added file path tracking for resource cleanup**

New private property to store the temporary audio file path, enabling proper cleanup later.

---

`56-56`: **Storing file path for later cleanup**

Capturing the file path when creating temporary audio files enables proper resource management.

---

`33-34`: **Simplified audio instance management**

Removed conditional logic and directly set the instance and stop flag, streamlining the control flow.

---

`113-113`: **Added audio file cleanup on stop**

Now calling the new `removeAudio` method when stopping playback to clean up temporary files.

---

`115-123`: **Implemented temporary file cleanup**

New method to handle the deletion of temporary audio files from the file system when playback is stopped. The implementation includes:
1. Safely skipping cleanup in web environments
2. Using the stored file path to remove the file
3. Proper error handling to prevent crashes during cleanup

This prevents file system clutter from temporary audio files that are no longer needed.

</details>
<details>
<summary>packages/chat-sdk/src/libs/services/use-send-message.ts (6)</summary>

`54-56`: **Added pre-send message validation**

Retrieving the `checkCanSendMessage` function from the chat properties store to validate messages before sending.

---

`58-70`: **Enhanced message sending with pre-validation**

The `sendMessage` function has been updated to:
1. Be asynchronous to support awaiting validation results
2. Check if the message can be sent using the `checkCanSendMessage` function
3. Early return with `false` if validation fails

This provides better control over message sending, allowing for validation before messages are processed.

---

`115-122`: **Updated text message sending to support async validation**

Modified to be async and properly await the sendMessage result, aligning with the new validation approach.

---

`123-130`: **Updated file message sending to support async validation**

Modified to be async and properly await the sendMessage result, aligning with the new validation approach.

---

`132-139`: **Updated audio message sending to support async validation**

Modified to be async and properly await the sendMessage result, aligning with the new validation approach.

---

`141-145`: **Updated error message resending to support async validation**

Modified to be async and properly await the sendMessage result, aligning with the new validation approach.

</details>
<details>
<summary>packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts (1)</summary>

`27-30`: **Updated callback signatures to support async operations**

All message-related callback interfaces have been updated to return `Promise<boolean | undefined>` instead of `void`, enabling:
1. Asynchronous processing in the callbacks
2. Providing feedback on whether the operation succeeded
3. Consistency with the new pre-validation mechanism

This change ensures that the interface properly reflects the asynchronous nature of the message sending operations and allows for proper error handling.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T02:44:32Z
user: login: jackshen310
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-25T06:42:17Z
user: login: DingGao-Devin
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-25T09:08:27Z

Review comments:
diff_hunk: @@ -153,7 +153,11 @@ export class MiniCozeApi extends CozeAPI {
     options?: RequestOptions,
   ): Promise<Rsp> {
     if (isWeb || !isStream) {
-      return super.makeRequest(apiUrl, method, body, isStream, options);
+      try {
+        return super.makeRequest(apiUrl, method, body, isStream, options);
+      } catch (err) {
+        console.log('makeRequestError:', err);
+      }
path: packages/chat-sdk/src/libs/utils/mini-coze-api.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Error handling needs improvement.**

While adding error handling is good, the current implementation has issues:

1. Errors are logged but not rethrown, which could silently swallow exceptions
2. Using `console.log` instead of the established logger utility is inconsistent


```diff
try {
  return super.makeRequest(apiUrl, method, body, isStream, options);
} catch (err) {
-  console.log('makeRequestError:', err);
+  logger.error('makeRequestError:', err);
+  throw err;
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
      try {
        return super.makeRequest(apiUrl, method, body, isStream, options);
      } catch (err) {
        logger.error('makeRequestError:', err);
        throw err;
      }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-24T02:44:32Z
author_association: NONE
diff_hunk: @@ -49,6 +49,7 @@ export class AsyncSendMessage extends MultiSendMessage {
     this._checkTimeout();
     try {
       for await (const eventData of this.chatStream) {
+        logger.debug('asyncChat pollAnswer awaiting start2', eventData);
path: packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts
user: login: jackshen310
body: 要不要删掉
created_at: 2025-03-25T06:41:35Z
author_association: COLLABORATOR
diff_hunk: @@ -49,6 +49,7 @@ export class AsyncSendMessage extends MultiSendMessage {
     this._checkTimeout();
     try {
       for await (const eventData of this.chatStream) {
+        logger.debug('asyncChat pollAnswer awaiting start2', eventData);
path: packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts
user: login: DingGao-Devin
body: 没事，debug日志，用户设置日志等级之后，不会打印
created_at: 2025-03-25T09:08:27Z
author_association: COLLABORATOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-24T02:40:10Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The pull request introduces multiple change log JSON files for the `@coze/chat-sdk` package to document minor feature enhancements and bug fixes. Changes include improved input validation, pre-send detection, bug fixes in TT mini app, refresh token handling, dependency records, and formatting tweaks. In addition, the pull request updates asynchronous handling in message sending, enhances error handling via a new method in ChatService, reorders audio playback operations, and refines CSS styling. Minor adjustments in type declarations and recorder permission logic are also included.

## Changes

| File(s) | Summary |
|---------|---------|
| `common/changes/@coze/chat-sdk/feat-feat-nl2app3_*.json` | New JSON files recording minor updates: input validation, pre-send detection, TT mini app bug fix, refresh token fix, and dependency modification. |
| `packages/chat-sdk/package.json` | Added a newline at the end of the file (formatting change). |
| `packages/chat-sdk/src/libs/framework/.../command-audio/index.tsx` | Reordered the audio playback call so that event listener registration precedes the playText invocation. |
| `packages/chat-sdk/src/libs/services/helper/chat-service.ts` | Added new async method `handleErrorCode` to check authentication via `isAuthErrorCode` and trigger token refresh. |
| `packages/chat-sdk/src/libs/services/helper/message/send-message/async-send-message.ts` | Introduced debug logging and enhanced error handling in the `pollAnswer` method by processing error codes. |
| `packages/chat-sdk/src/libs/services/use-send-message.ts` | Made `sendMessage` and related functions asynchronous; added a pre-check function `checkCanSendMessage` to determine message send eligibility. |
| `packages/chat-sdk/src/libs/types/base/ui.ts` | Added optional property `checkCanSendMessage` to the `InputConfig` interface and imported the `RawMessage` type. |
| `packages/chat-sdk/src/libs/types/services/chat-service.ts` | Updated `IChatService` interface by adding the `handleErrorCode` method signature. |
| `packages/chat-sdk/src/libs/ui-kit/chat-input/hooks/use-text-input-handle.ts` | Updated the `onSendTextMessage` callback to be asynchronous with a conditional check on the send result. |
| `packages/chat-sdk/src/libs/ui-kit/chat-input/type.ts` | Modified callback signatures to return a `Promise<boolean | undefined>` instead of void. |
| `packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.module.less` | Standardized background color hex value to lowercase. |
| `packages/chat-sdk/src/libs/ui-kit/message/components/chatflow-node/index.tsx` | Removed `numberOfLines` and `overflow` props from the Text component in the `SwitchNode` component. |
| `packages/chat-sdk/src/libs/utils/event-source/request.ts` | Enhanced the event source request control flow with flags to yield a `[DONE]` message or throw an error if no data is sent. |
| `packages/chat-sdk/src/libs/utils/mini-coze-api.ts` | Made `isAuthErrorCode` public, updated `refreshToken` to return an explicit `Promise<string>`, and added error logging in `makeRequest`. |
| `packages/chat-sdk/src/libs/utils/play-audio.ts` | Introduced a new `filePath` property and `removeAudio` method for audio file cleanup; simplified the play method’s logic. |
| `packages/chat-sdk/src/libs/utils/recorder-manager/taro-recorder-manager.ts` | Modified `checkPermission` to bypass authorization when the `isTT` condition is true. |
| `packages/chat-sdk/src/pages/chat/index.tsx` | Added the `checkCanSendMessage` property to the chatSlot input configuration in the `ChatFramework` component. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant U as User
    participant CI as Chat Input
    participant SM as SendMessage
    participant CS as ChatService
    participant API as MiniCozeAPI

    U->>CI: Enter message
    CI->>SM: call async sendMessage(message)
    SM->>SM: Invoke checkCanSendMessage(message)
    alt Message not allowed
        SM->>U: Return false (abort sending)
    else Message allowed
        SM->>CS: Process message send request
        CS-->>SM: Process message
        note right of CS: On auth error, call handleErrorCode
        CS->>API: refreshToken(oldToken)
        API-->>CS: Return new token
        CS->>SM: Continue error handling
        SM->>U: Message sent (or error event)
    end
```

```mermaid
sequenceDiagram
    participant C as CommandAudio
    participant R as AudioRef
    participant EH as ErrorHandler

    C->>R: Register STOP event listener
    R->>C: Await playText(text, audioSpeech)
    alt Playback error occurs
        R->>EH: Invoke handleError for error processing
    else Playback completes
        R-->>C: Playback complete
    end
```

## Poem

> I'm a rabbit, coding through the night,  
> Hopping over bugs with asynchronous might.  
> Logs and checks dance in my keen, swift paws,  
> Token refresh and validation earn my applause.  
> With each change, I celebrate in carrot delight!  
> 🥕🐇

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=coze-dev/coze-js&utm_content=157):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-25T09:09:57Z
body: ## [Codecov](https://app.codecov.io/gh/coze-dev/coze-js/pull/157?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev) Report
All modified and coverable lines are covered by tests :white_check_mark:

:x: Your project status has failed because the head coverage (0.00%) is below the target coverage (90.00%). You can increase the head coverage or adjust the [target](https://docs.codecov.com/docs/commit-status#target) coverage.

```diff
@@            Coverage Diff            @@
##             main   #157       +/-   ##
=========================================
- Coverage   91.82%      0   -91.83%     
=========================================
  Files         117      0      -117     
  Lines        5469      0     -5469     
  Branches     1106      0     -1106     
=========================================
- Hits         5022      0     -5022     
+ Misses        447      0      -447     
```

| [Components](https://app.codecov.io/gh/coze-dev/coze-js/pull/157/components?src=pr&el=components&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev) | Coverage Δ | |
|---|---|---|
| [coze-js](https://app.codecov.io/gh/coze-dev/coze-js/pull/157/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev) | `∅ <ø> (∅)` | |
| [realtime-api](https://app.codecov.io/gh/coze-dev/coze-js/pull/157/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev) | `∅ <ø> (∅)` | |
| [chat-sdk](https://app.codecov.io/gh/coze-dev/coze-js/pull/157/components?src=pr&el=component&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev) | `∅ <ø> (∅)` | |

[see 117 files with indirect coverage changes](https://app.codecov.io/gh/coze-dev/coze-js/pull/157/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=coze-dev)

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE