in src/common/chat/gitlab_chat_controller.ts [139:200]
async processNewUserRecord(record: GitLabChatRecord) {
if (!record.content) {
log.warn('Duo Chat: no content to send to API');
return;
}
await this.#view.show();
let useFallback: boolean = false;
// establish a websocket connection before sending the message to the API
// this is ensure that we avoid race conditions
const subscribeToUpdatesResult = await this.#subscribeToUpdates(record);
const aiActionResult = await this.#aiAction(record);
const { cable, error: subscriptionError } = subscribeToUpdatesResult;
const { actionResponse, error: actionError } = aiActionResult;
if (!actionResponse) {
if (cable) {
cable.disconnect();
}
const apiResponseMessage = actionError
? (actionError.response?.errors?.[0]?.message ?? actionError.message)
: 'No action response';
const userMessage = `Failed to send the chat message to the API: ${apiResponseMessage}`;
record.update({ errors: [userMessage] });
log.error(actionError);
handleError(new Error(userMessage));
return;
}
if (subscriptionError) {
log.error('Duo Chat: error subscribing to updates, using fallback', subscriptionError);
useFallback = true;
}
record.update(actionResponse.aiAction);
await this.#addToChat(record);
if (record.type === 'newConversation') return;
if (record.type === 'clearChat') {
await this.#clearChatWindow();
return;
}
const responseRecord = new GitLabChatRecord({
role: 'assistant',
state: 'pending',
requestId: record.requestId,
});
await this.#addToChat(responseRecord);
// Fallback if websocket fails or disabled.
// Used in the Web IDE.
if (useFallback) {
log.error('Duo Chat: error connecting to cable socket, refreshing feed via https.');
await Promise.all([this.#refreshRecord(record), this.#refreshRecord(responseRecord)]);
}
}