omnibot3000 1.9.8 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.github/workflows/tag.yml +38 -0
  2. package/.husky/commit-msg +2 -1
  3. package/.husky/pre-commit +1 -1
  4. package/.stylelintrc.json +12 -0
  5. package/README.md +3 -3
  6. package/TODO.md +33 -0
  7. package/api/server.ts +36 -24
  8. package/{tsconfig.api.json → api/tsconfig.json} +6 -6
  9. package/nodemon.json +1 -1
  10. package/omnibot3000.code-workspace +36 -0
  11. package/package.json +24 -22
  12. package/src/App.module.css +16 -14
  13. package/src/Error.tsx +1 -1
  14. package/src/commons/OmnibotSpeak.module.css +13 -2
  15. package/src/commons/api/api.ts +3 -3
  16. package/src/commons/api/utils/getStream.ts +8 -6
  17. package/src/commons/constants.ts +5 -2
  18. package/src/commons/hooks/useCli.tsx +7 -14
  19. package/src/commons/hooks/useStorage.tsx +2 -2
  20. package/src/commons/layout/Background.module.css +4 -2
  21. package/src/commons/layout/Breadcrumb.module.css +1 -0
  22. package/src/commons/layout/Container.module.css +2 -2
  23. package/src/commons/layout/Footer.module.css +3 -2
  24. package/src/commons/layout/Header.module.css +3 -4
  25. package/src/commons/layout/Menu.module.css +1 -0
  26. package/src/commons/layout/Menu.tsx +1 -1
  27. package/src/commons/styles/debug.css +9 -11
  28. package/src/commons/styles/main.css +44 -31
  29. package/src/commons/styles/vt220.css +7 -8
  30. package/src/commons/ui/Box.module.css +2 -1
  31. package/src/commons/ui/Button.tsx +3 -1
  32. package/src/commons/ui/ProgressBar.module.css +3 -1
  33. package/src/commons/utils/debug.ts +7 -0
  34. package/src/commons/utils/strings.ts +1 -1
  35. package/src/features/chat/Chat.tsx +34 -61
  36. package/src/features/chat/commons/getQuery.ts +34 -0
  37. package/src/features/chat/commons/strings.ts +13 -3
  38. package/src/features/chat/components/Toolbar.tsx +62 -4
  39. package/src/features/chat/hooks/useChatCompletionStore.tsx +339 -84
  40. package/src/features/cli/Cli.tsx +7 -5
  41. package/src/features/history/History.module.css +2 -2
  42. package/src/features/history/History.tsx +2 -8
  43. package/src/features/home/Home.tsx +1 -4
  44. package/src/features/version/Version.module.css +1 -0
  45. package/src/features/version/Version.tsx +35 -10
  46. package/tsconfig.json +19 -20
  47. package/upgrade.sh +19 -1
  48. package/vite.config.ts +11 -3
@@ -0,0 +1,38 @@
1
+ name: tag new version
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+
8
+ jobs:
9
+ tag:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write
13
+ steps:
14
+ - name: checkout code
15
+ uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 2
18
+
19
+ - name: check if version changed
20
+ id: version_check
21
+ run: |
22
+ CURRENT=$(node -p "require('./package.json').version")
23
+ PREVIOUS=$(git show HEAD~1:package.json 2>/dev/null | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version" || echo "none")
24
+ echo "current=$CURRENT" >> $GITHUB_OUTPUT
25
+ if [ "$CURRENT" != "$PREVIOUS" ]; then
26
+ echo "changed=true" >> $GITHUB_OUTPUT
27
+ else
28
+ echo "changed=false" >> $GITHUB_OUTPUT
29
+ fi
30
+
31
+ - name: create git tag
32
+ if: steps.version_check.outputs.changed == 'true'
33
+ run: |
34
+ VERSION=${{ steps.version_check.outputs.current }}
35
+ git config user.name github-actions
36
+ git config user.email github-actions@github.com
37
+ git tag "v$VERSION"
38
+ git push origin "v$VERSION"
package/.husky/commit-msg CHANGED
@@ -1,6 +1,6 @@
1
1
  # basic commit message validation
2
2
 
3
- if ! head -1 "$1" | grep -qE '^\[(feat|fix|doc|style|perf|test|chore|misc)(\(.+\))?!?\]'; then
3
+ if ! head -1 "$1" | grep -qE '^\[(feat|fix|update|doc|style|perf|test|conf|chore|misc)(\(.+\))?!?\]'; then
4
4
  echo "❌ Commit message must follow format: [type] message"
5
5
  echo ""
6
6
  echo "Examples:"
@@ -8,5 +8,6 @@ if ! head -1 "$1" | grep -qE '^\[(feat|fix|doc|style|perf|test|chore|misc)(\(.+\
8
8
  echo " [fix] resolve bug in component"
9
9
  echo " [doc] update README"
10
10
  echo " [chore] update dependencies"
11
+ echo " [conf] modify configuration"
11
12
  exit 1
12
13
  fi
package/.husky/pre-commit CHANGED
@@ -1 +1 @@
1
- pnpm lint && pnpm prettify && .codacy/cli.sh analyze ./src
1
+ pnpm lint && pnpm prettify
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "stylelint-config-standard",
3
+ "rules": {
4
+ "selector-class-pattern": [
5
+ "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
6
+ {
7
+ "message": "expect class selector to be kebab-case"
8
+ }
9
+ ]
10
+ },
11
+ "ignoreFiles": ["node_modules/**", "dist/**"]
12
+ }
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- ## OMNIBOT 3000
1
+ # OMNIBOT 3000
2
2
 
3
- YOUR OMNISCIENT SOURCE OF TRUTH
3
+ ## YOUR OMNISCIENT SOURCE OF TRUTH
4
4
 
5
5
  ![image](https://github.com/user-attachments/assets/f3c88ab8-4c8c-4056-8d82-9cfb3fbe023e)
6
6
 
@@ -35,7 +35,7 @@ OPENAI_API_KEY=<your_openai_api_key>
35
35
 
36
36
  ### Package
37
37
 
38
- https://www.npmjs.com/package/omnibot3000
38
+ <https://www.npmjs.com/package/omnibot3000>
39
39
 
40
40
  ### Contributing
41
41
 
package/TODO.md ADDED
@@ -0,0 +1,33 @@
1
+ # TODO
2
+
3
+ ## In Progress
4
+
5
+ - allow query retry
6
+ - handle conversation tree with multiple branches
7
+
8
+ ## Backlog
9
+
10
+ - add [OpenRouter](https://openrouter.ai/docs/quickstart#using-the-openai-sdk)
11
+ as API client
12
+ - use [`commander.js`](https://www.npmjs.com/package/commander) for CLI
13
+ - use `inquirer.js` for CLI prompts
14
+ - arrow key up/down to cycle between CLI history
15
+ - model selection in CLI
16
+ - support for multiple models in the same conversation
17
+ - keep the latest query on the top while streaming the response
18
+ - hide all visual elements in _Game of Life_ mode except the toggle button
19
+ - try to color text with [rasterbars](https://en.wikipedia.org/wiki/Raster_bar)
20
+
21
+ ## Done
22
+
23
+ - resize properly content margin
24
+ - allow clipboard text pasting to CLI
25
+ - support arrow key to move cursor
26
+ - ctrl+u to remove text before cursor
27
+ - ctrl+k to remove text after cursor
28
+ - catch API errors and display a dummy message
29
+ - lock vertical scrolling to line height
30
+ - add a
31
+ [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
32
+ in the background
33
+ - make the Game of Life background interactive with mouse clicks
package/api/server.ts CHANGED
@@ -1,9 +1,10 @@
1
- import {exec} from "child_process";
1
+ import {execSync} from "child_process";
2
2
  import {
3
3
  accessSync,
4
4
  constants as FS,
5
5
  Dirent,
6
6
  readdirSync,
7
+ realpathSync,
7
8
  statSync,
8
9
  writeFileSync,
9
10
  } from "fs";
@@ -12,13 +13,9 @@ import path from "path";
12
13
 
13
14
  import "dotenv/config";
14
15
  import {Mistral} from "@mistralai/mistralai";
15
- import type {
16
- ChatCompletionRequest,
17
- CompletionEvent,
18
- } from "@mistralai/mistralai/models/components";
19
16
  import OpenAI from "openai";
20
17
  import type {ChatCompletionCreateParamsNonStreaming} from "openai/resources/chat/completions";
21
- import type {ChatCompletionChunk} from "openai/resources/index.mjs";
18
+ import type {ChatCompletionChunk} from "openai/resources/chat/completions/completions";
22
19
  import type {Stream} from "openai/streaming";
23
20
 
24
21
  type Package = {
@@ -35,11 +32,14 @@ const JSON_PATH = path.join(BASE_PATH, "dist", "packages.json");
35
32
 
36
33
  type Provider = "openai" | "mistral";
37
34
 
38
- export const MODEL: Provider = "openai";
35
+ export const MODEL: Provider = "openai" as Provider;
39
36
  const MAX_TOKENS = 1000;
40
37
 
41
38
  type OpenAIConfig = Omit<ChatCompletionCreateParamsNonStreaming, "messages">;
42
- type MistralConfig = Omit<ChatCompletionRequest, "messages">;
39
+ type MistralConfig = Omit<
40
+ Parameters<Mistral["chat"]["complete"]>[0],
41
+ "messages"
42
+ >;
43
43
 
44
44
  export const API_CONFIG = {
45
45
  openai: {
@@ -58,21 +58,23 @@ export const API_CONFIG = {
58
58
  topP: 0.1 /* nucleus sampling */,
59
59
  frequencyPenalty: 1.0 /* avoid repetition */,
60
60
  presencePenalty: 1.0 /* encourage new topics */,
61
- maxTokens: MAX_TOKENS,
62
- randomSeed: Math.round(Math.random() * 1e9),
61
+ maxTokens: MAX_TOKENS + 500,
63
62
  } satisfies MistralConfig,
64
63
  };
65
64
 
66
65
  const getFolderSize = (folder: string): number => {
66
+ const resolved = path.resolve(folder);
67
+ if (!resolved.startsWith(BASE_PATH)) return 0;
67
68
  let total = 0;
68
69
  try {
69
- accessSync(folder, FS.R_OK);
70
+ accessSync(resolved, FS.R_OK);
70
71
  } catch {
71
72
  return total;
72
73
  }
73
- const files: Dirent[] = readdirSync(folder, {withFileTypes: true});
74
+ const files: Dirent[] = readdirSync(resolved, {withFileTypes: true});
74
75
  for (const file of files) {
75
- const fullPath = path.join(folder, file.name);
76
+ const fullPath = path.resolve(resolved, file.name);
77
+ if (!fullPath.startsWith(BASE_PATH)) continue;
76
78
  if (file.isDirectory()) total += getFolderSize(fullPath);
77
79
  else total += statSync(fullPath).size;
78
80
  }
@@ -150,10 +152,11 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
150
152
  });
151
153
  const response = await mistral.chat.stream({
152
154
  ...API_CONFIG[MODEL],
155
+ randomSeed: Math.round(Math.random() * 1e9),
153
156
  messages,
154
157
  });
155
158
  /* forward chunks to browser as SSE */
156
- for await (const chunk of response as AsyncIterable<CompletionEvent>) {
159
+ for await (const chunk of response) {
157
160
  res.write(`data: ${JSON.stringify(chunk)}\n\n`);
158
161
  }
159
162
  /* end the SSE stream */
@@ -162,6 +165,7 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
162
165
  } else {
163
166
  const response = await mistral.chat.complete({
164
167
  ...API_CONFIG[MODEL],
168
+ randomSeed: Math.round(Math.random() * 1e9),
165
169
  messages,
166
170
  });
167
171
  res.writeHead(200, {"Content-Type": "application/json"});
@@ -199,29 +203,37 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
199
203
  res.writeHead(200, {"Content-Type": "application/json"});
200
204
  res.end(JSON.stringify(config));
201
205
  } else if (url.startsWith(`${API_PATH}/packages`)) {
202
- exec("npm list --json --depth=0 --prod --silent", (err, stdout) => {
203
- if (err) {
204
- const error = err instanceof Error ? err.message : "unknown error";
205
- res.writeHead(500, {"Content-Type": "application/json"});
206
- res.end(JSON.stringify({error}));
207
- return;
208
- }
206
+ try {
207
+ const stdout = execSync("npm list --json --depth=0 --prod --silent", {
208
+ encoding: "utf8",
209
+ });
209
210
  const json = JSON.parse(stdout);
210
211
  const data = json?.dependencies || {};
211
212
  const list = Object.keys(data)
212
213
  .map((key) => {
213
- const dir = data[key].resolved.replace("file:", "");
214
+ const modulePath = path.join(BASE_PATH, "node_modules", key);
215
+ let resolvedPath;
216
+ try {
217
+ resolvedPath = realpathSync(modulePath);
218
+ } catch {
219
+ resolvedPath = modulePath;
220
+ }
221
+
214
222
  return {
215
223
  name: key,
216
224
  version: data[key].version.split(".") as Package["version"],
217
- size: getFolderSize(path.join(BASE_PATH, "node_modules", dir)),
225
+ size: getFolderSize(resolvedPath),
218
226
  };
219
227
  })
220
228
  .sort((a, b) => (a.name < b.name ? -1 : 1));
221
229
  res.writeHead(200, {"Content-Type": "application/json"});
222
230
  res.end(JSON.stringify(list));
223
231
  writeFileSync(JSON_PATH, JSON.stringify(list, null, 2));
224
- });
232
+ } catch (error) {
233
+ const message = error instanceof Error ? error.message : "unknown error";
234
+ res.writeHead(500, {"Content-Type": "application/json"});
235
+ res.end(JSON.stringify({error: message}));
236
+ }
225
237
  } else {
226
238
  res.writeHead(404);
227
239
  res.end("nothing to see here");
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2022",
4
- "module": "ESNext",
5
- "moduleResolution": "node",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
6
  "esModuleInterop": true,
7
7
  "skipLibCheck": true,
8
+ "types": ["node"],
8
9
  /* linting */
9
10
  "strict": true,
10
11
  /* paths */
11
- "rootDir": "./api/",
12
- "outDir": "./dist/api/"
12
+ "rootDir": "./",
13
+ "outDir": "../dist/api/"
13
14
  },
14
- "include": ["./api/**/*.ts"],
15
- "exclude": []
15
+ "include": ["./**/*.ts"]
16
16
  }
package/nodemon.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "watch": ["api/server.ts"],
3
- "exec": "rm -rf ./dist/api/server.js && pnpm tsc --project tsconfig.api.json && node ./dist/api/server.js"
3
+ "exec": "rm -rf ./dist/api/server.js && pnpm tsc --project api/tsconfig.json && node ./dist/api/server.js"
4
4
  }
@@ -12,6 +12,42 @@
12
12
  "path": "api",
13
13
  },
14
14
  ],
15
+ "settings": {
16
+ "workbench.colorCustomizations": {
17
+ "statusBar.background": "#042",
18
+ "statusBar.foreground": "#6c8",
19
+ "statusBar.border": "#163",
20
+ "statusBar.focusBorder": "#6c8",
21
+ "statusBarItem.hoverBackground": "#163",
22
+ "statusBarItem.hoverForeground": "#8fc",
23
+ "statusBarItem.activeBackground": "#284",
24
+ "statusBarItem.activeForeground": "#afe",
25
+ "statusBar.debuggingBackground": "#042",
26
+ "statusBar.noFolderBackground": "#042",
27
+ "statusBar.prominentBackground": "#163",
28
+ },
29
+ },
30
+ "extensions": {
31
+ "recommendations": [
32
+ /* code quality */
33
+ "esbenp.prettier-vscode",
34
+ "dbaeumer.vscode-eslint",
35
+ "stylelint.vscode-stylelint",
36
+ "davidanson.vscode-markdownlint",
37
+ "timonwong.shellcheck",
38
+ /* code assistance */
39
+ "github.copilot-chat",
40
+ "github.vscode-github-actions",
41
+ "donjayamanne.githistory",
42
+ /* editor enhancements */
43
+ "vscodevim.vim",
44
+ "medo64.render-crlf",
45
+ "medo64.code-point",
46
+ "tal7aouy.indent-colorizer",
47
+ "atommaterial.a-file-icon-vscode",
48
+ "s3anmorrow.color-stamp",
49
+ ],
50
+ },
15
51
  "launch": {
16
52
  "configurations": [
17
53
  {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "x-display-name": "OMNIBOT 3000",
4
4
  "description": "your omniscient source of truth",
5
5
  "private": false,
6
- "version": "1.9.8",
6
+ "version": "1.10.1",
7
7
  "type": "module",
8
8
  "author": {
9
9
  "name": "rez",
@@ -19,38 +19,39 @@
19
19
  "omnibot": "./bin/omnibot.js"
20
20
  },
21
21
  "dependencies": {
22
- "dotenv": "^17.3.1",
23
- "openai": "^6.29.0",
24
- "react": "^19.2.4",
25
- "react-dom": "^19.2.4",
22
+ "@mistralai/mistralai": "^2.2.1",
23
+ "dotenv": "^17.4.2",
24
+ "openai": "^6.39.0",
25
+ "react": "^19.2.6",
26
+ "react-dom": "^19.2.6",
26
27
  "react-markdown": "^10.1.0",
27
- "react-router-dom": "^7.13.1",
28
- "zustand": "^5.0.11"
28
+ "react-router-dom": "^7.15.1",
29
+ "zustand": "^5.0.13"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@eslint/js": "^10.0.1",
32
- "@mistralai/mistralai": "^1.15.1",
33
- "@types/node": "^25.5.0",
34
- "@types/react": "^19.2.14",
33
+ "@types/node": "^25.9.1",
34
+ "@types/react": "^19.2.15",
35
35
  "@types/react-dom": "^19.2.3",
36
- "@vitejs/plugin-react": "^6.0.1",
36
+ "@vitejs/plugin-react": "^6.0.2",
37
37
  "classnames": "^2.5.1",
38
- "eslint": "^10.0.3",
38
+ "eslint": "^10.4.0",
39
39
  "eslint-plugin-import": "^2.32.0",
40
- "eslint-plugin-react-hooks": "^7.0.1",
40
+ "eslint-plugin-react-hooks": "^7.1.1",
41
41
  "eslint-plugin-react-refresh": "^0.5.2",
42
- "eslint-plugin-simple-import-sort": "^12.1.1",
43
- "globals": "^17.4.0",
42
+ "eslint-plugin-simple-import-sort": "^13.0.0",
43
+ "globals": "^17.6.0",
44
44
  "husky": "^9.1.7",
45
- "knip": "^5.86.0",
45
+ "knip": "^6.14.2",
46
46
  "nodemon": "^3.1.14",
47
47
  "npm-run-all": "^4.1.5",
48
- "prettier": "^3.8.1",
48
+ "prettier": "^3.8.3",
49
49
  "react-refresh": "^0.18.0",
50
- "typescript": "^5.9.3",
51
- "typescript-eslint": "^8.57.0",
52
- "vite": "^8.0.0",
53
- "vite-tsconfig-paths": "^6.1.1"
50
+ "stylelint": "^17.12.0",
51
+ "stylelint-config-standard": "^40.0.0",
52
+ "typescript": "^6.0.3",
53
+ "typescript-eslint": "^8.59.4",
54
+ "vite": "^8.0.14"
54
55
  },
55
56
  "scripts": {
56
57
  "start": "pnpm run-p start:dev start:api",
@@ -62,8 +63,9 @@
62
63
  "api": "node dist/api/server.js",
63
64
  "build": "pnpm run build:client && pnpm run build:api",
64
65
  "build:client": "tsc -b && vite build",
65
- "build:api": "tsc --project tsconfig.api.json",
66
+ "build:api": "tsc --project api/tsconfig.json",
66
67
  "lint": "eslint --fix .",
68
+ "lint:css": "stylelint --fix 'src/**/*.css'",
67
69
  "lint:deps": "knip --dependencies",
68
70
  "prettify": "prettier --write ."
69
71
  }
@@ -26,22 +26,22 @@
26
26
  ),
27
27
  linear-gradient(
28
28
  30deg,
29
- hsla(calc(var(--h) - 90) 30% 30% / var(--opacity-background)) 0%,
30
- hsla(calc(var(--h) - 45) 50% 20% / var(--opacity-background)) 25%,
31
- hsla(calc(var(--h) + 0) 70% 10% / var(--opacity-background)) 50%,
32
- hsla(calc(var(--h) + 45) 50% 20% / var(--opacity-background)) 75%,
33
- hsla(calc(var(--h) + 90) 30% 30% / var(--opacity-background)) 100%
29
+ hsl(calc(var(--h) - 90) 30% 30% / var(--opacity-background)) 0%,
30
+ hsl(calc(var(--h) - 45) 50% 20% / var(--opacity-background)) 25%,
31
+ hsl(calc(var(--h) + 0) 70% 10% / var(--opacity-background)) 50%,
32
+ hsl(calc(var(--h) + 45) 50% 20% / var(--opacity-background)) 75%,
33
+ hsl(calc(var(--h) + 90) 30% 30% / var(--opacity-background)) 100%
34
34
  ),
35
35
  radial-gradient(
36
36
  circle,
37
- hsla(calc(var(--h) - 270) 30% 30% / var(--opacity-background)) 0%,
38
- hsla(calc(var(--h) - 180) 30% 30% / var(--opacity-background)) 100%
37
+ hsl(calc(var(--h) - 270) 30% 30% / var(--opacity-background)) 0%,
38
+ hsl(calc(var(--h) - 180) 30% 30% / var(--opacity-background)) 100%
39
39
  ),
40
40
  radial-gradient(
41
41
  circle,
42
- hsla(0 100% 100% / 0.0125) 0%,
43
- hsla(0 0% 0% / 0.25) 80%,
44
- hsla(0 0% 0% / 0.5) 100%
42
+ hsl(0deg 100% 100% / 1.25%) 0%,
43
+ hsl(0deg 0% 0% / 25%) 80%,
44
+ hsl(0deg 0% 0% / 50%) 100%
45
45
  );
46
46
  animation: fade-tty var(--duration-fade) linear;
47
47
  }
@@ -59,15 +59,15 @@
59
59
  animation: fade-tty var(--duration-fade) linear;
60
60
  background-image: repeating-linear-gradient(
61
61
  0deg,
62
- #0000 0rem,
63
- hsla(0 0% 0% / 0.3) 0.02rem,
64
- hsla(0 0% 0% / 0.3) 0.12rem,
62
+ #0000 0,
63
+ hsl(0deg 0% 0% / 30%) 0.02rem,
64
+ hsl(0deg 0% 0% / 30%) 0.12rem,
65
65
  #0000 0.14rem,
66
66
  #0000 0.2rem
67
67
  );
68
68
  background-size: 100%, 100%;
69
69
  background-repeat: no-repeat, repeat;
70
- background-position: 0rem -0.0333rem;
70
+ background-position: 0 -0.0333rem;
71
71
  background-blend-mode: overlay;
72
72
  }
73
73
 
@@ -119,9 +119,11 @@
119
119
  0% {
120
120
  opacity: 0;
121
121
  }
122
+
122
123
  20% {
123
124
  opacity: 0;
124
125
  }
126
+
125
127
  100% {
126
128
  opacity: 1;
127
129
  }
package/src/Error.tsx CHANGED
@@ -27,7 +27,7 @@ export class ErrorBoundary extends React.Component<Props, State> {
27
27
  }
28
28
 
29
29
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
30
- console.error(`YOU DECEIVED ${NAME}`, error, errorInfo);
30
+ console.error("YOU DECEIVED %s", NAME, error, errorInfo);
31
31
  }
32
32
 
33
33
  render() {
@@ -1,41 +1,51 @@
1
1
  .root {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- word-break: break-word;
4
+ overflow-wrap: break-word;
5
5
  opacity: var(--opacity-secondary);
6
+
6
7
  p {
7
8
  display: inline-block;
8
9
  padding-bottom: var(--line-height);
10
+
9
11
  em {
10
12
  opacity: var(--opacity-primary);
11
13
  color: var(--color-highlight);
12
14
  }
15
+
13
16
  a {
14
17
  opacity: var(--opacity-primary);
15
18
  color: var(--color-highlight);
16
19
  }
17
20
  }
21
+
18
22
  ul {
19
23
  list-style-position: outside;
20
24
  margin-left: calc(var(--tab-size) * var(--font-width));
21
25
  }
26
+
22
27
  ul > :last-child {
23
28
  padding-bottom: 0 !important;
24
29
  }
30
+
25
31
  ol {
26
32
  list-style-position: outside;
27
33
  padding-left: calc(var(--tab-size) * var(--font-width));
28
34
  margin-left: calc(var(--tab-size) * var(--font-width));
29
35
  }
36
+
30
37
  ol > :last-child {
31
38
  padding-bottom: 0 !important;
32
39
  }
40
+
33
41
  li {
34
42
  padding-bottom: var(--line-height);
43
+
35
44
  p {
36
45
  padding-bottom: 0 !important;
37
46
  }
38
47
  }
48
+
39
49
  li > :last-child {
40
50
  margin-bottom: 0;
41
51
  }
@@ -44,7 +54,8 @@
44
54
  .hr {
45
55
  margin: 0;
46
56
  padding: 0;
47
- /*padding-bottom: var(--line-height);*/
57
+
58
+ /* padding-bottom: var(--line-height); */
48
59
  opacity: var(--opacity-tertiary);
49
60
  }
50
61
 
@@ -73,12 +73,12 @@ export const getChatTitle = async (
73
73
  "do not mention your name in the result",
74
74
  "keep it as simple, short and descriptive as possible",
75
75
  "do not mention, repeat or paraphrase this prompt",
76
- "use only use and assistant messages as context",
76
+ "use only user and assistant messages as context",
77
77
  ...smallQueryFormatting(28),
78
78
  ],
79
79
  [
80
- "make a title for this chat",
81
- "do not answer to the query, just provide a title",
80
+ "sum up the conversation in few words",
81
+ "do not answer to the query, just provide a summary",
82
82
  ],
83
83
  messages,
84
84
  );
@@ -25,18 +25,20 @@ const fetchResponse = async (
25
25
  return response;
26
26
  };
27
27
 
28
+ export type CompletionCallback = (
29
+ id: string,
30
+ created: number,
31
+ model: string,
32
+ query: string,
33
+ ) => void;
34
+
28
35
  const getStream = async (
29
36
  setLoading: React.Dispatch<React.SetStateAction<boolean>>,
30
37
  setResponse: React.Dispatch<React.SetStateAction<string>>,
31
38
  system?: string[],
32
39
  query?: string[],
33
40
  context?: ChatCompletionMessageParam[],
34
- completionCallback?: (
35
- id: string,
36
- created: number,
37
- model: string,
38
- query: string,
39
- ) => void,
41
+ completionCallback?: CompletionCallback,
40
42
  ) => {
41
43
  try {
42
44
  const messages: ChatCompletionMessageParam[] = [
@@ -8,7 +8,7 @@ export const AUTHOR = pkg.author;
8
8
  export const SOURCE = pkg.repository.url;
9
9
  export const SESSION_KEY = String(NAME).toLowerCase().replace(/\s/g, "_");
10
10
 
11
- export const COMPLETION_ID_WILDCARD = "chatcmpl-";
11
+ export const COMPLETION_WILDCARD: RegExp = /chatcmpl-/gi;
12
12
 
13
13
  export const ASCII_SPACE = "\u0020";
14
14
  export const ASCII_LOSANGE = "\u00ac";
@@ -16,7 +16,7 @@ export const ASCII_BLOCK1 = "\u00fe";
16
16
  export const ASCII_BLOCK2 = "\u00ae";
17
17
  export const ASCII_BLOCK3 = "\u00b8";
18
18
  export const ASCII_RECTANGLE = "\u00ff";
19
- export const ASCII_VLINE = "\u00af";
19
+ export const ASCII_VLINE = "|"; //"\u00af";
20
20
  export const ASCII_HLINE = "-";
21
21
  export const ASCII_CORNER = "+";
22
22
  export const ASCII_POINT = "\u00a0";
@@ -30,6 +30,9 @@ export const ASCII_PARAGRAPH = "¶";
30
30
 
31
31
  export const BUTTON_CREATE = "[+]";
32
32
  export const BUTTON_DELETE = "[-]";
33
+ export const BUTTON_RETRY = "[+]";
34
+ export const BUTTON_LEFT = "<";
35
+ export const BUTTON_RIGHT = ">";
33
36
  export const BUTTON_SUBMIT = "[ASK]";
34
37
  export const BUTTON_PREVIOUS = "<";
35
38
  export const BUTTON_NEXT = ">";