Skip to content

Bug: @coze/uniapp-api 0.3.1版本流式请求返回内容过长时,流式请求没结束,流式接口直接返回 空 error了 #333

Description

@guanxin2015

在uni-app项目中使用 @coze/uniapp-api 0.3.1 版本,编译成微信小程序
遇到的问题:
流式接口返回内容时间过长时,接口直接 走了下面方法中的 catch, error 内容为空。但是我这边测试发现,内容还是在返回中的,并且再次进入页面,这条内容能完整的呈现出来。

期望行为:
1、增加流式接口响应的时长;
2、能否返回真正的流式接口底层错误码。

流式接口相关代码:
import { RoleType, ChatStatus, ChatEventType } from '@coze/api';
import { CozeAPI } from '@coze/uniapp-api';
import { parseJwt, getTokenFromStore } from "@/utils/jwt";

interface StreamChatOptions {
onMessage?: (content: string, data?: any) => void
onError?: (error: any) => void
onComplete?: (data: any) => void
onStatusChange?: (status: ChatStatus) => void
additionalMessages?: any[]
onEmptyError?: () => void
onChatInProgress?: (data: { conversationId: string; chatId: string }) => void
}

// Token 管理(简化版,仅保留 streamChat 依赖的部分)
async function getCozeToken(): Promise {
// 此处保留 token 获取逻辑,streamChat 依赖此函数
// 实际实现参考原文件的 tokenInfo.isTokenExpired()
return '';
}

// 按需创建带最新 token 的 CozeAPI 客户端
export async function getCozeClient(): Promise {
const token = await getCozeToken();
return new CozeAPI({
token,
baseURL: COZE_CN_BASE_URL,
allowPersonalAccessTokenInBrowser: import.meta.env.NODE_ENV !== 'production'
});
}

// ==================== 流式聊天核心接口 ====================

// 流式请求聊天
async function streamChat(
message: string,
conversation_id: string | null = null,
parameters: Record<string, any> | null = null,
options: StreamChatOptions = {}
) {
const botId = import.meta.env.VITE_COZE_BOT_ID;
if (!botId) {
const error = { msg: '缺少配置: cozeBotId', code: -1 };
console.error('[Chat Config Error]', error);
throw error;
}

const {
    onMessage = (content: string, _data?: any) => console.log(content),
    onError = (error: { msg: string; code?: number }) => console.error('聊天错误:', error),
    onComplete = (data: any) => console.log('聊天完成', data),
    onStatusChange = (status: ChatStatus) => console.log('聊天状态变化:', status),
    additionalMessages = [],
    onEmptyError,
    onChatInProgress
} = options;

try {
    const client = await getCozeClient();

    const messages = [
        { role: RoleType.User, content: message, content_type: 'text' },
        ...additionalMessages
    ];

    const obj: any = {
        bot_id: botId,
        additional_messages: messages,
        auto_save_history: true
    };

    if (conversation_id) obj.conversation_id = conversation_id;
    if (parameters) obj.parameters = parameters;

    const payload = parseJwt(getTokenFromStore());

    if (payload && payload.sub) {
        obj.user_id = payload.sub;
    }

    console.log('[Chat Request]', {
        bot_id: botId,
        conversation_id: conversation_id || 'new',
        user_id: obj.user_id || 'none',
        message_length: message.length,
        has_parameters: !!parameters
    });

    const stream = await client.chat.stream(obj);

    let isCompleted = false;
    let receivedTerminalEvent = false;

    for await (const part of stream) {
        console.log('[Chat Stream]', part);
        if (!part?.event) {
            console.error('[Chat Stream Protocol Error]', part);
            throw part || new Error('流式响应格式异常');
        }

        if (part.event === ChatEventType.CONVERSATION_MESSAGE_DELTA) {
            const deltaContent = typeof part?.data?.content === 'string' ? part.data.content : '';
            if (deltaContent !== '') {
                onMessage(deltaContent);
            }
        } else if (part.event === ChatEventType.CONVERSATION_CHAT_IN_PROGRESS) {
            console.log('[Chat In Progress]', part.data);
            onChatInProgress?.({
                conversationId: part.data?.conversation_id,
                chatId: part.data?.id
            });
        } else if (part.event === ChatEventType.CONVERSATION_CHAT_COMPLETED) {
            receivedTerminalEvent = true;
            console.log('[Chat Completed]', {
                conversation_id: part.data?.conversation_id
            });
            onStatusChange?.(ChatStatus.COMPLETED);
            onComplete?.(part.data);
            isCompleted = true;
        } else if (part.event === ChatEventType.CONVERSATION_CHAT_FAILED) {
            receivedTerminalEvent = true;
            console.error('[Chat Failed]', part.data);
            throw part.data;
        } else if (part.event === ChatEventType.ERROR) {
            receivedTerminalEvent = true;
            console.error('[Chat Stream Error]', part.data);
            throw part.data;
        } else if (part.event === ChatEventType.DONE) {
            receivedTerminalEvent = true;
            console.log('[Chat Stream Done]');
            if (!isCompleted) {
                throw new Error('流式响应异常结束');
            }
        }
    }

    // 检查是否收到终止事件
    if (!receivedTerminalEvent) {
        throw new Error('流式响应异常结束:未收到终止事件');
    }
} catch (error: any) {
    console.log('[Chat Error]', error);

    // 检测空 Error:可能是流式请求网络中断,但服务端可能已保存数据
    const isEmptyError = error instanceof Error &&
        (!error.message || error.message.trim() === '');

    if (isEmptyError) {
        console.warn('[Chat Stream] 检测到空错误,触发空错误处理流程');
        onEmptyError?.();
        return;
    }

    console.error('[Chat Error]', error);
    onStatusChange?.(ChatStatus.FAILED);
    onError?.(error);
    throw error;
}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions