ChatCraft Adventures #12, Slash Commands

ChatCraft Adventures #12, Slash Commands

ChatCraft Release 1.8 is available here.

ChatCraft Week 12 Recap

This week I started addressing some of the technical debt my classmates and I accrued during the past semester. I have quite a few code enhancements/bug fixes I plan to fix in April, but I’ve made a slow start.

Sheriff Duty 2: Electric Boogaloo

This week I also wear my Sheriff’s hat for a second and final time. I described my first Sheriff duty experience earlier in this series, and it was nice to try it again this week. The largest portion of Sheriff duty is leading the weekly triage meeting, and I feel I did a better job than I did the first time around. Many of the Issues we planned to close in this milestone were completed, though I think I should have helped review more Pull Requests.

Pull Requests

Update Slash Command Handling

ChatCraft has a cool feature we call “slash commands”, which start with a forward slash (/). Here’s a list of current slash commands:

Typically, when you try to use a slash command that doesn’t exist, like /invalidcommand, you receive a message telling you that command is invalid and showing you the list of valid commands:

What if you want to send something that isn’t a slash command, but it starts with a forward slash?

ChatCraft creator Taras reported how his ChatCraft Chat crashed when he pasted the following block:

/workspaces/DeepStructure/misc/getsetup/add-to-notion.ts:181
throw new Error(`Notion API call failed: ${await response.text()}`);
^

Error: Notion API call failed: {“object”:”error”,”status”:400,”code”:”validation_error”,”message”:”body failed validation: body.children[0].heading_1.rich_text should be defined, instead was `undefined`.”,”request_id”:”f73a1254-1204-4610-9820-76f6890821dc”}
at notionApiCall (/workspaces/DeepStructure/misc/getsetup/add-to-notion.ts:181:15)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at createHeadingWithText (/workspaces/DeepStructure/misc/getsetup/add-to-notion.ts:137:5)
at updateOrAppendAiSummary (/workspaces/DeepStructure/misc/getsetup/add-to-notion.ts:113:5)
at main (/workspaces/DeepStructure/misc/getsetup/add-to-notion.ts:192:5)

Node.js v20.8.1

My investigation

My first instinct was to replicate this error myself and to read the error. After replicating, I found this error using my browser’s developer tools:

From this error, it was clear that a function called parseCommand was throwing an error. To determine where parseCommand was called, I used git grep
git grep:

After adding some console.log() calls and replicating the error a few more times, I was able to locate the bug to parseCommand() returning null because although the above block starts with a forward slash, it fails the slash command check (it contains a non-word character – special characters like ;, /, @ – after the [/command] block) in parseCommand:

My solution

Though the error is thrown by parseCommand(), the main issue is that ChatCraft interpreted every prompt that starts with a forward slash as a potential slash command:

Since the above error block starts off with a forward slash, if it is pasted by itself in a ChatCraft chat, it would be treated as a potential slash command, and throwing the error Taras observed.

I’ll admit I took a while to figure out a good solution to this issue. Before this PR, routine for handling potential slash commands is as follows:

If prompt is a potential slash command (starts with forward slash)

If the slash command exists attempt to run it
Else, parse the invalid command using parseCommand then send a relevant message

Else, Pass prompt to LLM

Although the above error block starts with a forward slash, we don’t want to treat it as a potential slash command, and instead, pass it directly the LLM. But how do we do that?

Initial Implementation

My solution was to update the isCommand() method to use stricter criteria for determining a potential slash command. I figured a good start was to reuse the RegEx used in parseCommand:

// Checks if a string is a command.
static isCommand(input: string): boolean {
// Check if there’s something resembling a command (no non-word characters in the portion after forward slash)
const match = input.match(/^/(w+)(?:s+(.*))?$/);
return !!match;
}

Final Implementation

Though this implementation worked, I felt I could do the same in one line, but I wasn’t sure how. Fortunately, my class instructor Dave suggested a concise way to do this using RegExp.prototype.test(), which became my final implementation:

// Checks if a string is a command.
static isCommand(input: string): boolean {
// Check if there’s something resembling a command (no non-word characters in the portion after forward slash)
return /^/(w+)(?:s+(.*))?$/.test(input);
}

Aftermath

These changes to isCommand() preserve the functionality of current (as they still satisfy the RegEx check in isCommand()), while allowing things like error blocks (that start with a forward slash) to be directly pasted into a ChatCraft message and sent to the LLM.

However, my update isn’t perfect. If a user were to enter something like /badcommand@, instead of the website returning a message saying “badcommand@ is not a valid command”, this is sent to the LLM as a message:

I hope I, or someone else can determine a more robust RegEx to use in isCommand().

Remaining Plans

With two weeks left, I hope to complete more code enhancement/bug-fix related issues.
Here are some issues I have planned:

Adding an eye icon to supplement API key hide/show state
Don’t show “free mode” banner when multiple providers set
Add share_target support

Leave a Reply

Your email address will not be published. Required fields are marked *