realcoloride / node_characterai

Unofficial Character AI wrapper for node.
https://beta.character.ai/
348 stars 74 forks source link

Chat.sendAndAwaitResponse throws TypeError: Cannot read properties of undefined (reading 'status') #157

Closed SeoulSKY closed 7 months ago

SeoulSKY commented 8 months ago

Version: 1.2.7

I found the closed issue #26 which describes the exact same issue, but it seems like it's not resolved yet.

Error log

[2024-03-14T17:42:25.905] [ERROR] default - TypeError: Cannot read properties of undefined (reading 'status')
    at Chat.sendAndAwaitResponse (/app/node_modules/node_characterai/chat.js:62:21)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/assert.js:28
        throw new Error(message);
              ^

Error: Request Interception is not enabled!
    at assert (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/util/assert.js:28:15)
    at HTTPRequest.continue (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/HTTPRequest.js:155:32)
    at /app/node_modules/node_characterai/requester.js:204:41
    at onceHandler (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/EventEmitter.js:98:13)
    at /app/node_modules/puppeteer-core/lib/cjs/puppeteer/api/Page.js:114:32
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async HTTPRequest.finalizeInterceptions (/app/node_modules/puppeteer-core/lib/cjs/puppeteer/common/HTTPRequest.js:99:9)

Looks like the problem is that it throws this error when you send another request before getting a response from the previous request.

I think it would be awesome if the library implements queuing requests if sendAndAwaitResponse() is called again before the previous sendAndAwaitResponse returns the response, or at least throws an error saying you can't call sendAndAwaitResponse() before the previous sendAndAwaitResponse() returns.

realcoloride commented 8 months ago

Hello, I don't quite know how that would work. The reason being that request interception (see requester.js) requires data to be checked in as blocks you keep checking until they're ended (data).

(I think that) the reason you get this error is that it was loading data for a response and got another response so it mixed and did something wrong.

A solution would be to swap to neo endpoints (the ones with the websocket) or find another solution for puppeteer (that i'm not aware of).

SeoulSKY commented 8 months ago

I found a workaround. I used async-mutex to implement the Monitor design pattern, which prevents race conditions and ensures data consistency.

A minimum working example:

import CharacterAI from "node_characterai";
import {Mutex} from "async-mutex";

let chat;
const mutex = new Mutex();

(async () => {
  const characterAI = new CharacterAI();

  await characterAI.authenticateWithToken("TOKEN");
  chat = await characterAI.createOrContinueChat("8_1NyR8w1dOXmI1uWaieQcd147hecbdIK7CeEAIrdJw");
})();

/**
 * Send a message to the AI and get the response
 * @param id {string} chat ID
 * @param message {string} message to send
 * @returns {Promise<Reply>} response from the AI
 */
export async function sendMessage(id, message) {
  return await mutex.runExclusive(async () => {
    await chat.changeToConversationId(id);
    return await chat.sendAndAwaitResponse(message, true);
  });
}

Although I used another library for mutex, implementing it from scratch shouldn't be super difficult

realcoloride commented 8 months ago

This is interesting! Thank you for the sample @SeoulSKY

realcoloride commented 7 months ago

Hello there, I've included a link to your sample in the README.md. Commit: https://github.com/realcoloride/node_characterai/commit/5089995d2d448c748a2ac017f2eb5c3438116494

Thank you for the contribution!