Skip to content

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

@guanxin2015

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions