ChatCraft Adventures #12, Slash Commands
Tags: opensource, beginners, webdev
Published: 2024-04-06 04:56:55

[ChatCraft](https://chatcraft.org/) Release 1.8 is available [here](https://github.com/tarasglek/chatcraft.org).

# 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](https://dev.to/rjwignar/chatcraft-adventures-4-50o7), 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](https://github.com/tarasglek/chatcraft.org/pull/567)

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zp1gz531wxn6vgcak2l.png)

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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkau7hkkb7lr78lcmex2.png)

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

ChatCraft creator Taras [reported](https://github.com/tarasglek/chatcraft.org/issues/500) how his ChatCraft Chat crashed when he pasted the following block:

```error
/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](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Tools_and_setup/What_are_browser_developer_tools):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/emjiycue8a5rz6z3zr92.png)

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](https://git-scm.com/docs/git-grep):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psv2ig9sq1pr6qmpv5cf.png)

After adding some [console.log()](https://www.w3schools.com/jsref/met_console_log.asp) 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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7du19v7btqkaip33mbo.png)

#### 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](https://github.com/tarasglek/chatcraft.org/blob/f7b28038b3820d617a14b346536377977f4379d0/src/lib/ChatCraftCommand.ts#L19-L21):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jba5sr1soebjcowpnuk.png)

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:

```tsx
  // 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()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test), which became my final implementation:

```tsx
  // 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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4cjefmrvfps1tf994jcq.png)

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](https://github.com/tarasglek/chatcraft.org/issues/552)
- [Don't show "free mode" banner when multiple providers set](https://github.com/tarasglek/chatcraft.org/issues/544)
- [Add share_target support](https://github.com/tarasglek/chatcraft.org/issues/451)