omnibot3000 1.10.1 → 1.10.3
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.
- package/.github/workflows/keep_alive.yml +13 -0
- package/.github/workflows/publish.yml +2 -0
- package/TODO.md +5 -3
- package/netlify.toml +6 -1
- package/package.json +16 -16
- package/src/App.tsx +5 -2
- package/src/commons/api/api.ts +1 -0
- package/src/commons/constants.ts +1 -1
- package/src/commons/utils/math.ts +10 -0
- package/src/features/chat/Chat.tsx +16 -10
- package/src/features/chat/components/Toolbar.tsx +24 -6
- package/src/features/chat/hooks/useChatCompletionStore.tsx +90 -223
- package/src/features/console/cmd.ts +6 -6
- package/vite.config.ts +6 -0
package/TODO.md
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## In Progress
|
|
4
4
|
|
|
5
|
-
- allow query retry
|
|
6
|
-
- handle conversation tree with multiple branches
|
|
7
|
-
|
|
8
5
|
## Backlog
|
|
9
6
|
|
|
10
7
|
- add [OpenRouter](https://openrouter.ai/docs/quickstart#using-the-openai-sdk)
|
|
@@ -16,7 +13,9 @@
|
|
|
16
13
|
- support for multiple models in the same conversation
|
|
17
14
|
- keep the latest query on the top while streaming the response
|
|
18
15
|
- hide all visual elements in _Game of Life_ mode except the toggle button
|
|
16
|
+
- randomize _Game of Life_ lifeforms angle by 90° steps
|
|
19
17
|
- try to color text with [rasterbars](https://en.wikipedia.org/wiki/Raster_bar)
|
|
18
|
+
- add links to [npmjs.com package](https://www.npmjs.com) on the /version page
|
|
20
19
|
|
|
21
20
|
## Done
|
|
22
21
|
|
|
@@ -31,3 +30,6 @@
|
|
|
31
30
|
[Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life)
|
|
32
31
|
in the background
|
|
33
32
|
- make the Game of Life background interactive with mouse clicks
|
|
33
|
+
- allow query retry
|
|
34
|
+
- handle conversation tree with multiple branches
|
|
35
|
+
- make API available online on [Render](https://render.com)
|
package/netlify.toml
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
[build]
|
|
2
|
+
command = "pnpm run build"
|
|
3
|
+
publish = "dist"
|
|
4
|
+
|
|
1
5
|
[[redirects]]
|
|
2
6
|
from = "/*"
|
|
3
7
|
to = "/index.html"
|
|
@@ -5,5 +9,6 @@
|
|
|
5
9
|
|
|
6
10
|
[[redirects]]
|
|
7
11
|
from = "/api/*"
|
|
8
|
-
to = "/api"
|
|
12
|
+
to = "https://omnibot3000.onrender.com/api/:splat"
|
|
9
13
|
status = 200
|
|
14
|
+
force = true
|
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.10.
|
|
6
|
+
"version": "1.10.3",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "rez",
|
|
@@ -19,39 +19,39 @@
|
|
|
19
19
|
"omnibot": "./bin/omnibot.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@mistralai/mistralai": "^2.2.
|
|
22
|
+
"@mistralai/mistralai": "^2.2.5",
|
|
23
23
|
"dotenv": "^17.4.2",
|
|
24
|
-
"openai": "^6.
|
|
25
|
-
"react": "^19.2.
|
|
26
|
-
"react-dom": "^19.2.
|
|
24
|
+
"openai": "^6.42.0",
|
|
25
|
+
"react": "^19.2.7",
|
|
26
|
+
"react-dom": "^19.2.7",
|
|
27
27
|
"react-markdown": "^10.1.0",
|
|
28
|
-
"react-router-dom": "^7.
|
|
29
|
-
"zustand": "^5.0.
|
|
28
|
+
"react-router-dom": "^7.17.0",
|
|
29
|
+
"zustand": "^5.0.14"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@eslint/js": "^10.0.1",
|
|
33
|
-
"@types/node": "^25.9.
|
|
34
|
-
"@types/react": "^19.2.
|
|
33
|
+
"@types/node": "^25.9.3",
|
|
34
|
+
"@types/react": "^19.2.17",
|
|
35
35
|
"@types/react-dom": "^19.2.3",
|
|
36
36
|
"@vitejs/plugin-react": "^6.0.2",
|
|
37
37
|
"classnames": "^2.5.1",
|
|
38
|
-
"eslint": "^10.
|
|
38
|
+
"eslint": "^10.5.0",
|
|
39
39
|
"eslint-plugin-import": "^2.32.0",
|
|
40
40
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
41
|
-
"eslint-plugin-react-refresh": "^0.5.
|
|
41
|
+
"eslint-plugin-react-refresh": "^0.5.3",
|
|
42
42
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
43
43
|
"globals": "^17.6.0",
|
|
44
44
|
"husky": "^9.1.7",
|
|
45
|
-
"knip": "^6.
|
|
45
|
+
"knip": "^6.16.1",
|
|
46
46
|
"nodemon": "^3.1.14",
|
|
47
47
|
"npm-run-all": "^4.1.5",
|
|
48
|
-
"prettier": "^3.8.
|
|
48
|
+
"prettier": "^3.8.4",
|
|
49
49
|
"react-refresh": "^0.18.0",
|
|
50
|
-
"stylelint": "^17.
|
|
50
|
+
"stylelint": "^17.13.0",
|
|
51
51
|
"stylelint-config-standard": "^40.0.0",
|
|
52
52
|
"typescript": "^6.0.3",
|
|
53
|
-
"typescript-eslint": "^8.
|
|
54
|
-
"vite": "^8.0.
|
|
53
|
+
"typescript-eslint": "^8.61.0",
|
|
54
|
+
"vite": "^8.0.16"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"start": "pnpm run-p start:dev start:api",
|
package/src/App.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import Menu from "@layout/Menu";
|
|
|
15
15
|
import Line from "@ui/Line";
|
|
16
16
|
import {format} from "@utils/math";
|
|
17
17
|
import {getCharWidth, getLineHeight} from "@utils/strings";
|
|
18
|
+
import {getVariableFromCSS} from "@utils/styles";
|
|
18
19
|
import {isSystemDarkModeOn} from "@utils/system";
|
|
19
20
|
|
|
20
21
|
import {CliProvider} from "@hooks/useCli";
|
|
@@ -100,9 +101,11 @@ const Layout = () => {
|
|
|
100
101
|
el.className = "debug-info";
|
|
101
102
|
document.body.appendChild(el);
|
|
102
103
|
el.innerHTML = [
|
|
103
|
-
`
|
|
104
|
+
`v: ${vw}*${vh}`,
|
|
105
|
+
`scr: ${w}*${h}`,
|
|
104
106
|
`char: ${cw}*${lh}`,
|
|
105
|
-
`
|
|
107
|
+
`size: ${Math.floor((w - cw * 2) / cw)}*${Math.floor((h - cw * 2) / lh)}`,
|
|
108
|
+
`col: ${getVariableFromCSS("h")},${getVariableFromCSS("s")},${getVariableFromCSS("l")}`,
|
|
106
109
|
].join(" | ");
|
|
107
110
|
el.style.display = debug ? "block" : "none";
|
|
108
111
|
}, [w, h]);
|
package/src/commons/api/api.ts
CHANGED
package/src/commons/constants.ts
CHANGED
|
@@ -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 = "
|
|
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";
|
|
@@ -15,6 +15,16 @@ export const clamp = (
|
|
|
15
15
|
max: number = 1,
|
|
16
16
|
): number => Math.max(min, Math.min(n, max));
|
|
17
17
|
|
|
18
|
+
export const lerp = (min: number = 0, max: number = 1, n: number = 0): number =>
|
|
19
|
+
min + (max - min) * clamp(n);
|
|
20
|
+
|
|
21
|
+
export const lead = (
|
|
22
|
+
n: number = 0,
|
|
23
|
+
l: number = 1000,
|
|
24
|
+
c: string = "0",
|
|
25
|
+
): string =>
|
|
26
|
+
`${c.repeat(Math.max(0, l.toFixed(0).length - n.toFixed(0).length))}${n}`;
|
|
27
|
+
|
|
18
28
|
export type Unit = "byte" | "time" | "percent";
|
|
19
29
|
|
|
20
30
|
const UNIT_SCALE: Record<Unit, Record<string, number>> = {
|
|
@@ -27,6 +27,7 @@ const Chat = () => {
|
|
|
27
27
|
const [parentId, setParentId] = useState<CompletionId>();
|
|
28
28
|
const [loading, setLoading] = useState<boolean>(false);
|
|
29
29
|
const [query, setQuery] = useState<string>("");
|
|
30
|
+
const [retry, setRetry] = useState<number>(0);
|
|
30
31
|
const [updateTitle, setUpdateTitle] = useState<boolean>(false);
|
|
31
32
|
|
|
32
33
|
const navigate = useNavigate();
|
|
@@ -45,6 +46,7 @@ const Chat = () => {
|
|
|
45
46
|
const completion = chatStore.createCompletion(id, created, model, query);
|
|
46
47
|
setCompletion(completion);
|
|
47
48
|
setQuery("");
|
|
49
|
+
setRetry(0);
|
|
48
50
|
cli.set([""]);
|
|
49
51
|
cli.unblock();
|
|
50
52
|
};
|
|
@@ -62,8 +64,8 @@ const Chat = () => {
|
|
|
62
64
|
setLoading,
|
|
63
65
|
setResponse,
|
|
64
66
|
query,
|
|
65
|
-
chatStore.readMessages(
|
|
66
|
-
completion?.message,
|
|
67
|
+
chatStore.readMessages(id).slice(0, -retry * 2 || undefined),
|
|
68
|
+
undefined, //!retry ? completion?.message : undefined,
|
|
67
69
|
completionCallback,
|
|
68
70
|
);
|
|
69
71
|
}, [query]);
|
|
@@ -76,9 +78,11 @@ const Chat = () => {
|
|
|
76
78
|
} else {
|
|
77
79
|
chatStore.loadChat(id);
|
|
78
80
|
}
|
|
81
|
+
const conversation = chatStore.readConversation(id);
|
|
82
|
+
setParentId(conversation[conversation.length - 1]?.id);
|
|
79
83
|
}, [id]);
|
|
80
84
|
|
|
81
|
-
/* update
|
|
85
|
+
/* update url if the chatId value in store changed */
|
|
82
86
|
useEffect(() => {
|
|
83
87
|
const unsubscribe = useChatCompletionStore.subscribe((state) => {
|
|
84
88
|
navigate(`/chat${state.chatId ? `/${state.chatId}` : ""}`);
|
|
@@ -93,19 +97,18 @@ const Chat = () => {
|
|
|
93
97
|
prev.message = response;
|
|
94
98
|
return prev;
|
|
95
99
|
});
|
|
96
|
-
if (!chatStore.
|
|
97
|
-
else chatStore.updateCompletion(
|
|
100
|
+
if (!chatStore.readChat(id)) chatStore.createChat(completion);
|
|
101
|
+
else chatStore.updateCompletion(parentId, completion);
|
|
98
102
|
/* reset values once the completion is saved in the store */
|
|
99
|
-
|
|
100
|
-
setParentId(undefined);
|
|
103
|
+
setParentId(completion.id);
|
|
101
104
|
setResponse("");
|
|
102
105
|
setUpdateTitle(true);
|
|
103
106
|
}, [completion]);
|
|
104
107
|
|
|
105
108
|
const setTitle = async () => {
|
|
106
|
-
const title = await getChatTitle(chatStore.readMessages());
|
|
107
|
-
chatStore.updateChatTitle(title);
|
|
108
|
-
chatStore.updateCompletionTitle(title);
|
|
109
|
+
const title = await getChatTitle(chatStore.readMessages(id));
|
|
110
|
+
chatStore.updateChatTitle(id, title);
|
|
111
|
+
if (completion) chatStore.updateCompletionTitle(completion.id, title);
|
|
109
112
|
storage.save();
|
|
110
113
|
};
|
|
111
114
|
|
|
@@ -120,6 +123,7 @@ const Chat = () => {
|
|
|
120
123
|
<Container>
|
|
121
124
|
{chatStore
|
|
122
125
|
.readConversation(id)
|
|
126
|
+
.slice(0, retry ? -retry : undefined)
|
|
123
127
|
.map((completion: Completion, i: number, a: Completion[]) => (
|
|
124
128
|
<Fragment key={`chat-completion-${completion.id}`}>
|
|
125
129
|
<Message
|
|
@@ -132,8 +136,10 @@ const Chat = () => {
|
|
|
132
136
|
<Toolbar
|
|
133
137
|
completion={completion}
|
|
134
138
|
query={query}
|
|
139
|
+
number={a.length - i}
|
|
135
140
|
setQuery={setQuery}
|
|
136
141
|
setParentId={setParentId}
|
|
142
|
+
setRetry={setRetry}
|
|
137
143
|
/>
|
|
138
144
|
</div>
|
|
139
145
|
</Fragment>
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import Button from "@ui/Button";
|
|
10
10
|
import Line from "@ui/Line";
|
|
11
11
|
import {log} from "@utils/debug";
|
|
12
|
+
import {lead} from "@utils/math";
|
|
12
13
|
|
|
13
14
|
import useStorage from "@hooks/useStorage";
|
|
14
15
|
|
|
@@ -23,13 +24,15 @@ import cls from "classnames";
|
|
|
23
24
|
const Toolbar = (props: {
|
|
24
25
|
completion: Completion;
|
|
25
26
|
query: string;
|
|
27
|
+
number: number;
|
|
26
28
|
setQuery: React.Dispatch<React.SetStateAction<string>>;
|
|
27
|
-
setParentId: React.Dispatch<React.SetStateAction<CompletionId
|
|
29
|
+
setParentId: React.Dispatch<React.SetStateAction<CompletionId>>;
|
|
30
|
+
setRetry: React.Dispatch<React.SetStateAction<number>>;
|
|
28
31
|
}) => {
|
|
29
32
|
const chatStore = useChatCompletionStore();
|
|
30
33
|
const storage = useStorage();
|
|
31
34
|
|
|
32
|
-
const {setQuery, setParentId} = props;
|
|
35
|
+
const {setQuery, setParentId, setRetry} = props;
|
|
33
36
|
|
|
34
37
|
const deleteCompletion = (id: CompletionId) => {
|
|
35
38
|
log(`delete ${id}`, "chat");
|
|
@@ -44,17 +47,32 @@ const Toolbar = (props: {
|
|
|
44
47
|
log(`prompt: ${completion.prompt}`, "chat");
|
|
45
48
|
setQuery(completion.prompt);
|
|
46
49
|
setParentId(completion.parentId);
|
|
50
|
+
setRetry(number);
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
const loadCompletion = (id: CompletionId, index: number) => {
|
|
54
|
+
log(`load ${id} (index: ${index})`, "chat");
|
|
50
55
|
const c = chatStore.findCompletion(id, index);
|
|
51
56
|
if (!c) return;
|
|
52
|
-
|
|
57
|
+
chatStore.updateIndex(c.parentId, index);
|
|
53
58
|
storage.save();
|
|
59
|
+
const conversation = chatStore.readConversation(chatStore.chatId);
|
|
60
|
+
setParentId(conversation[conversation.length - 1]?.id);
|
|
54
61
|
};
|
|
55
62
|
|
|
56
|
-
const {completion} = props;
|
|
57
|
-
|
|
63
|
+
const {completion, number} = props;
|
|
64
|
+
|
|
65
|
+
let parent;
|
|
66
|
+
if (completion.parentId === chatStore.chatId) {
|
|
67
|
+
const chat = chatStore.readChat(chatStore.chatId);
|
|
68
|
+
parent = {
|
|
69
|
+
id: chat?.id,
|
|
70
|
+
children: chatStore.completions.filter((c) => c.parentId === chat?.id),
|
|
71
|
+
index: chat?.index ?? 0,
|
|
72
|
+
};
|
|
73
|
+
} else {
|
|
74
|
+
parent = chatStore.readCompletion(completion.parentId);
|
|
75
|
+
}
|
|
58
76
|
|
|
59
77
|
return (
|
|
60
78
|
<footer className={styles.root}>
|
|
@@ -78,7 +96,7 @@ const Toolbar = (props: {
|
|
|
78
96
|
}}
|
|
79
97
|
disabled={parent.index === 0}
|
|
80
98
|
/>
|
|
81
|
-
<span>{`${parent.index + 1}/${parent.children.length}`}</span>
|
|
99
|
+
<span>{`${lead(parent.index + 1, parent.children.length)}/${parent.children.length}`}</span>
|
|
82
100
|
<Button
|
|
83
101
|
name={BUTTON_RIGHT}
|
|
84
102
|
handler={() => {
|
|
@@ -2,7 +2,8 @@ import {create} from "zustand";
|
|
|
2
2
|
|
|
3
3
|
import {ChatCompletionMessageParam} from "openai/resources/index.mjs";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import {clamp} from "@utils/math";
|
|
6
|
+
|
|
6
7
|
import {getCompletionId, getRandomToken} from "@chat/commons/strings";
|
|
7
8
|
|
|
8
9
|
export type ChatId = string | undefined;
|
|
@@ -15,6 +16,8 @@ export interface Chat {
|
|
|
15
16
|
|
|
16
17
|
export type CompletionId = string | undefined;
|
|
17
18
|
|
|
19
|
+
export type ParentId = ChatId | CompletionId;
|
|
20
|
+
|
|
18
21
|
export interface Completion {
|
|
19
22
|
id: CompletionId;
|
|
20
23
|
created: EpochTimeStamp;
|
|
@@ -24,13 +27,12 @@ export interface Completion {
|
|
|
24
27
|
title: string;
|
|
25
28
|
index: number;
|
|
26
29
|
children: Completion[];
|
|
27
|
-
parentId:
|
|
30
|
+
parentId: ParentId;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export interface Data {
|
|
31
34
|
chatId: ChatId;
|
|
32
35
|
chats: Chat[];
|
|
33
|
-
completionId: CompletionId;
|
|
34
36
|
completions: Completion[];
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -39,14 +41,13 @@ export interface ChatCompletionStoreState {
|
|
|
39
41
|
chatId: ChatId;
|
|
40
42
|
chats: Chat[];
|
|
41
43
|
createChat: (completion: Completion) => void;
|
|
42
|
-
readChat: (id
|
|
44
|
+
readChat: (id: ChatId) => Chat | undefined;
|
|
43
45
|
updateChat: (chat: Chat) => void;
|
|
44
|
-
updateChatTitle: (
|
|
45
|
-
deleteChat: (id
|
|
46
|
+
updateChatTitle: (id: ChatId, title: string) => void;
|
|
47
|
+
deleteChat: (id: ChatId) => void;
|
|
46
48
|
resetChat: () => void;
|
|
47
|
-
loadChat: (id
|
|
49
|
+
loadChat: (id: ChatId) => void;
|
|
48
50
|
/* completions */
|
|
49
|
-
completionId: CompletionId;
|
|
50
51
|
completions: Completion[];
|
|
51
52
|
createCompletion: (
|
|
52
53
|
id: string,
|
|
@@ -54,15 +55,17 @@ export interface ChatCompletionStoreState {
|
|
|
54
55
|
model: string,
|
|
55
56
|
query: string,
|
|
56
57
|
) => Completion;
|
|
57
|
-
readCompletion: (id
|
|
58
|
-
updateCompletion: (
|
|
59
|
-
updateCompletionTitle: (
|
|
60
|
-
deleteCompletion: (id
|
|
58
|
+
readCompletion: (id: CompletionId) => Completion | undefined;
|
|
59
|
+
updateCompletion: (id: CompletionId, completion: Completion) => void;
|
|
60
|
+
updateCompletionTitle: (id: CompletionId, title: string) => void;
|
|
61
|
+
deleteCompletion: (id: CompletionId) => void;
|
|
61
62
|
findCompletion: (id: CompletionId, index: number) => Completion | undefined;
|
|
62
63
|
/* tools */
|
|
63
|
-
getParent: (id
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
getParent: (id: CompletionId) => Completion | Chat | undefined;
|
|
65
|
+
getCompletions: (id: ParentId) => Completion[];
|
|
66
|
+
updateIndex: (id: CompletionId, index: number) => void;
|
|
67
|
+
readConversation: (id: ParentId) => Completion[];
|
|
68
|
+
readMessages: (id: ParentId) => ChatCompletionMessageParam[];
|
|
66
69
|
/* data */
|
|
67
70
|
export: () => Data;
|
|
68
71
|
import: (data: Data) => void;
|
|
@@ -80,20 +83,18 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
80
83
|
index: 0,
|
|
81
84
|
};
|
|
82
85
|
get().chats.push(chat);
|
|
83
|
-
set({chatId: chat.id
|
|
86
|
+
set({chatId: chat.id});
|
|
84
87
|
completion.parentId = chat.id;
|
|
85
88
|
get().completions.push(completion);
|
|
86
89
|
},
|
|
87
90
|
readChat: (id?: ChatId): Chat | undefined =>
|
|
88
|
-
get().chats.find((chat: Chat) =>
|
|
89
|
-
Boolean((id || get().chatId) === chat.id),
|
|
90
|
-
),
|
|
91
|
+
get().chats.find((chat: Chat) => (id || get().chatId) === chat.id),
|
|
91
92
|
updateChat: (chat: Chat) => {
|
|
92
93
|
set({
|
|
93
94
|
chats: get().chats.map((c: Chat) => (c.id === chat.id ? {...chat} : c)),
|
|
94
95
|
});
|
|
95
96
|
},
|
|
96
|
-
updateChatTitle: (
|
|
97
|
+
updateChatTitle: (id: ChatId, title: string) => {
|
|
97
98
|
const chat = get().readChat(id);
|
|
98
99
|
if (!chat) return;
|
|
99
100
|
chat.title = title;
|
|
@@ -112,24 +113,14 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
112
113
|
});
|
|
113
114
|
},
|
|
114
115
|
resetChat: () => {
|
|
115
|
-
set({
|
|
116
|
-
chatId: undefined,
|
|
117
|
-
completionId: undefined,
|
|
118
|
-
});
|
|
116
|
+
set({chatId: undefined});
|
|
119
117
|
},
|
|
120
118
|
loadChat: (id?: ChatId) => {
|
|
121
119
|
const chat = get().readChat(id);
|
|
122
120
|
if (!chat) return;
|
|
123
|
-
set({
|
|
124
|
-
chatId: chat.id,
|
|
125
|
-
completionId:
|
|
126
|
-
get().completions.find((completion) =>
|
|
127
|
-
Boolean(completion.parentId === chat.id),
|
|
128
|
-
)?.id || undefined,
|
|
129
|
-
});
|
|
121
|
+
set({chatId: chat.id});
|
|
130
122
|
},
|
|
131
123
|
/* completions */
|
|
132
|
-
completionId: undefined,
|
|
133
124
|
completions: [],
|
|
134
125
|
createCompletion: (
|
|
135
126
|
id: string,
|
|
@@ -150,34 +141,30 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
150
141
|
};
|
|
151
142
|
return completion;
|
|
152
143
|
},
|
|
153
|
-
readCompletion: (id
|
|
154
|
-
const completionId = id || get().completionId;
|
|
144
|
+
readCompletion: (id: CompletionId): Completion | undefined => {
|
|
155
145
|
const queue: Completion[] = [...get().completions];
|
|
156
146
|
let i = 0;
|
|
157
147
|
while (i < queue.length) {
|
|
158
148
|
const current = queue[i++];
|
|
159
|
-
if (current.id ===
|
|
149
|
+
if (current.id === id) return current;
|
|
160
150
|
if (current.children.length > 0) queue.push(...current.children);
|
|
161
151
|
}
|
|
162
152
|
return undefined;
|
|
163
153
|
},
|
|
164
|
-
updateCompletion: (
|
|
165
|
-
const parent = get().
|
|
166
|
-
if (parent)
|
|
167
|
-
|
|
154
|
+
updateCompletion: (id: ParentId, completion: Completion) => {
|
|
155
|
+
const parent = get().getParent(id);
|
|
156
|
+
if (!parent) return;
|
|
157
|
+
completion.parentId = parent.id;
|
|
158
|
+
if ("children" in parent) {
|
|
168
159
|
parent.children.push(completion);
|
|
169
160
|
parent.index = parent.children.length - 1;
|
|
170
|
-
} else
|
|
171
|
-
const chat = get().readChat();
|
|
172
|
-
if (!chat) return;
|
|
173
|
-
completion.parentId = chat.id;
|
|
161
|
+
} else {
|
|
174
162
|
get().completions.push(completion);
|
|
175
|
-
|
|
176
|
-
get().completions.filter((c) => c.parentId ===
|
|
177
|
-
}
|
|
178
|
-
set({completionId: completion.id});
|
|
163
|
+
parent.index =
|
|
164
|
+
get().completions.filter((c) => c.parentId === parent.id).length - 1;
|
|
165
|
+
}
|
|
179
166
|
},
|
|
180
|
-
updateCompletionTitle: (
|
|
167
|
+
updateCompletionTitle: (id: CompletionId, title: string) => {
|
|
181
168
|
const completion = get().readCompletion(id);
|
|
182
169
|
if (!completion) return;
|
|
183
170
|
completion.title = title;
|
|
@@ -186,55 +173,79 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
186
173
|
deleteCompletion: (id?: CompletionId) => {
|
|
187
174
|
const completion = get().readCompletion(id);
|
|
188
175
|
if (!completion) return;
|
|
189
|
-
const parent = get().
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
completionId: undefined,
|
|
200
|
-
completions: get().completions.filter((c) => c.id !== completion.id),
|
|
201
|
-
});
|
|
176
|
+
const parent = get().getParent(completion.parentId);
|
|
177
|
+
const completions = get().completions.filter(
|
|
178
|
+
(c) => c.id !== completion.id,
|
|
179
|
+
);
|
|
180
|
+
set({completions: [...completions]});
|
|
181
|
+
/* delete the chat if the deleted completion is the last one */
|
|
182
|
+
if (completions.length === 0) get().deleteChat(completion.parentId);
|
|
183
|
+
if (!parent) return;
|
|
184
|
+
if ("children" in parent) {
|
|
185
|
+
parent.children = parent.children.filter((c) => c.id !== id);
|
|
202
186
|
}
|
|
203
|
-
|
|
204
|
-
getParent: (id?: CompletionId): Completion | Chat | undefined => {
|
|
205
|
-
const completion = get().readCompletion(id);
|
|
206
|
-
if (!completion) return;
|
|
207
|
-
const parent =
|
|
208
|
-
get().readCompletion(completion.parentId) ||
|
|
209
|
-
get().readChat(completion.parentId);
|
|
210
|
-
return parent;
|
|
187
|
+
get().updateIndex(parent.id, parent.index - 1);
|
|
211
188
|
},
|
|
212
189
|
findCompletion: (
|
|
213
190
|
id: CompletionId,
|
|
214
191
|
index: number,
|
|
215
192
|
): Completion | undefined => {
|
|
216
|
-
const
|
|
217
|
-
if (!
|
|
218
|
-
|
|
193
|
+
const completion = get().readCompletion(id);
|
|
194
|
+
if (!completion) return;
|
|
195
|
+
const parent = get().getParent(completion.parentId);
|
|
196
|
+
if (!parent) return;
|
|
197
|
+
return get()
|
|
198
|
+
.getCompletions(parent.id)
|
|
199
|
+
.filter((c) => c.parentId === parent.id)[index];
|
|
219
200
|
},
|
|
220
201
|
/* tools */
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
202
|
+
getParent: (id?: ParentId): Completion | Chat | undefined =>
|
|
203
|
+
get().readCompletion(id) || get().readChat(id),
|
|
204
|
+
getCompletions: (id?: ParentId): Completion[] => {
|
|
205
|
+
let completions: Completion[] = [];
|
|
206
|
+
const parent = get().getParent(id);
|
|
207
|
+
if (!parent) return completions;
|
|
208
|
+
if ("children" in parent) completions = parent.children;
|
|
209
|
+
else
|
|
210
|
+
completions = completions.concat(
|
|
211
|
+
get().completions.filter((c) => c.parentId === parent.id),
|
|
212
|
+
);
|
|
213
|
+
return completions.sort((a, b) => a.created - b.created);
|
|
214
|
+
},
|
|
215
|
+
updateIndex: (id: ParentId, index: number) => {
|
|
216
|
+
const parent = get().getParent(id);
|
|
217
|
+
if (!parent) return;
|
|
218
|
+
const completions = get().getCompletions(parent.id);
|
|
219
|
+
parent.index = clamp(index, 0, completions.length - 1);
|
|
220
|
+
const conversation = get().readConversation(get().chatId);
|
|
221
|
+
get().updateChatTitle(
|
|
222
|
+
get().chatId,
|
|
223
|
+
conversation[conversation.length - 1]?.title || "",
|
|
225
224
|
);
|
|
225
|
+
},
|
|
226
|
+
readConversation: (id: ParentId): Completion[] => {
|
|
227
|
+
const conversation: Completion[] = [];
|
|
228
|
+
const chat = get().readChat(id);
|
|
229
|
+
if (!chat) return [];
|
|
230
|
+
const completions = get()
|
|
231
|
+
.completions.filter((c) => c.parentId === chat.id)
|
|
232
|
+
.sort((a, b) => a.created - b.created);
|
|
233
|
+
let current = completions[clamp(chat.index, 0, completions.length - 1)];
|
|
226
234
|
if (!current) return [];
|
|
227
235
|
conversation.push(current);
|
|
228
236
|
if (!current?.children) return conversation;
|
|
229
237
|
while (current.children.length > 0) {
|
|
230
|
-
current =
|
|
238
|
+
current =
|
|
239
|
+
current.children[
|
|
240
|
+
clamp(current.index, 0, current.children.length - 1)
|
|
241
|
+
];
|
|
231
242
|
conversation.push(current);
|
|
232
243
|
}
|
|
233
244
|
return conversation;
|
|
234
245
|
},
|
|
235
|
-
readMessages: (): ChatCompletionMessageParam[] =>
|
|
246
|
+
readMessages: (id: ParentId): ChatCompletionMessageParam[] =>
|
|
236
247
|
get()
|
|
237
|
-
.readConversation()
|
|
248
|
+
.readConversation(id)
|
|
238
249
|
.map((completion: Completion) => {
|
|
239
250
|
return [
|
|
240
251
|
{role: "user", content: completion.prompt},
|
|
@@ -249,10 +260,6 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
249
260
|
get().chats.find((chat: Chat) => Boolean(chat.id === get().chatId))
|
|
250
261
|
?.id || undefined,
|
|
251
262
|
chats: get().chats,
|
|
252
|
-
completionId:
|
|
253
|
-
get().completions.find((completion: Completion) =>
|
|
254
|
-
Boolean(completion.id === get().completionId),
|
|
255
|
-
)?.id || undefined,
|
|
256
263
|
completions: get().completions.filter((completion: Completion) =>
|
|
257
264
|
Boolean(
|
|
258
265
|
get().chats.find((chat: Chat) =>
|
|
@@ -266,7 +273,6 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
266
273
|
set({
|
|
267
274
|
chatId: data.chatId,
|
|
268
275
|
chats: [...data.chats],
|
|
269
|
-
completionId: data.completionId,
|
|
270
276
|
completions: [...data.completions],
|
|
271
277
|
});
|
|
272
278
|
},
|
|
@@ -274,142 +280,3 @@ const useChatCompletionStore = create<ChatCompletionStoreState>()(
|
|
|
274
280
|
);
|
|
275
281
|
|
|
276
282
|
export default useChatCompletionStore;
|
|
277
|
-
|
|
278
|
-
/*
|
|
279
|
-
updateChat: (newChat: Chat) => {
|
|
280
|
-
const updatedChats: Chat[] = get().chats.map(
|
|
281
|
-
(chat: Chat): Chat => (chat.id === newChat.id ? {...newChat} : chat),
|
|
282
|
-
);
|
|
283
|
-
set({chats: updatedChats});
|
|
284
|
-
get().setConversation();
|
|
285
|
-
get().setMessages();
|
|
286
|
-
},
|
|
287
|
-
updateChatTitle: (title: string, id?: ChatId) => {
|
|
288
|
-
const chat = get().getChat(id);
|
|
289
|
-
if (!chat) return;
|
|
290
|
-
chat.title = title;
|
|
291
|
-
get().updateChat(chat);
|
|
292
|
-
},
|
|
293
|
-
loadChat: (id?: ChatId) => {
|
|
294
|
-
const chat = get().getChat(id);
|
|
295
|
-
if (!chat) return;
|
|
296
|
-
set({
|
|
297
|
-
chatId: chat.id,
|
|
298
|
-
chat,
|
|
299
|
-
completions: chat.completions,
|
|
300
|
-
});
|
|
301
|
-
const completion = get().getCompletion(get().getCompletionId());
|
|
302
|
-
if (completion) set({completionId: completion.id, completion});
|
|
303
|
-
get().setConversation();
|
|
304
|
-
get().setMessages();
|
|
305
|
-
console.info(get().chatId);
|
|
306
|
-
console.info(get().chat);
|
|
307
|
-
console.info(get().completions);
|
|
308
|
-
console.info(get().completionId);
|
|
309
|
-
console.info(get().completion);
|
|
310
|
-
console.info(get().conversation);
|
|
311
|
-
console.info(get().messages);
|
|
312
|
-
},
|
|
313
|
-
deleteChat: (id?: ChatId) => {
|
|
314
|
-
const index = get().chats.findIndex((chat: Chat) => id === chat.id);
|
|
315
|
-
if (index === -1) return;
|
|
316
|
-
const updatedChats = [...get().chats];
|
|
317
|
-
updatedChats.splice(index, 1);
|
|
318
|
-
get().setChats(updatedChats);
|
|
319
|
-
get().resetChat();
|
|
320
|
-
},
|
|
321
|
-
resetChat: () => {
|
|
322
|
-
set({
|
|
323
|
-
completionId: undefined,
|
|
324
|
-
completion: undefined,
|
|
325
|
-
completions: [],
|
|
326
|
-
chatId: undefined,
|
|
327
|
-
chat: undefined,
|
|
328
|
-
conversation: [],
|
|
329
|
-
messages: [],
|
|
330
|
-
});
|
|
331
|
-
},
|
|
332
|
-
chats: [],
|
|
333
|
-
getChats: () => get().chats,
|
|
334
|
-
setChats: (chats?: Chat[]) => set({chats}),
|
|
335
|
-
completionId: undefined,
|
|
336
|
-
setCompletionId: (id?: CompletionId) => set({completionId: id}),
|
|
337
|
-
getCompletionId: () => {
|
|
338
|
-
const completions = get().completions;
|
|
339
|
-
if (!completions.length) return;
|
|
340
|
-
let current = completions[get().chat?.index ?? completions.length - 1];
|
|
341
|
-
if (!current?.children) return;
|
|
342
|
-
while (current.children.length > 0)
|
|
343
|
-
current =
|
|
344
|
-
current.children[current.index ?? current.children.length - 1];
|
|
345
|
-
return current.id;
|
|
346
|
-
},
|
|
347
|
-
completion: undefined,
|
|
348
|
-
setCompletion: (completion?: Completion) => set({completion}),
|
|
349
|
-
appendCompletion: () => {
|
|
350
|
-
const completion = get().completion;
|
|
351
|
-
if (!completion) return;
|
|
352
|
-
if (completion.parentId) {
|
|
353
|
-
const parent = get().getCompletion(completion.parentId);
|
|
354
|
-
if (!parent) return;
|
|
355
|
-
console.info("append completion to", parent.id);
|
|
356
|
-
completion.parentId = parent.id;
|
|
357
|
-
parent.children.push(completion);
|
|
358
|
-
parent.index = parent.children.length - 1;
|
|
359
|
-
} else {
|
|
360
|
-
const chat = get().getChat();
|
|
361
|
-
if (!chat) return;
|
|
362
|
-
console.info("append completion to", chat.id);
|
|
363
|
-
completion.parentId = undefined;
|
|
364
|
-
chat.completions.push(completion);
|
|
365
|
-
chat.index = chat.completions.length - 1;
|
|
366
|
-
}
|
|
367
|
-
set({completionId: completion.id, completion});
|
|
368
|
-
},
|
|
369
|
-
loadCompletion: (id?: CompletionId) => {
|
|
370
|
-
const completion = get().getCompletion(id);
|
|
371
|
-
if (!completion) return;
|
|
372
|
-
set({completionId: completion.id, completion});
|
|
373
|
-
get().setConversation();
|
|
374
|
-
get().setMessages();
|
|
375
|
-
},
|
|
376
|
-
deleteCompletion: (id?: CompletionId) => {
|
|
377
|
-
const completion = get().getCompletion(id);
|
|
378
|
-
if (!completion) return;
|
|
379
|
-
const parent = get().getCompletion(completion.parentId);
|
|
380
|
-
if (parent) {
|
|
381
|
-
parent.children = parent.children.filter((c) => c.id !== completion.id);
|
|
382
|
-
parent.index = parent.children.length - 1;
|
|
383
|
-
set({
|
|
384
|
-
completionId: parent.id,
|
|
385
|
-
completion: parent,
|
|
386
|
-
completions: [...get().completions],
|
|
387
|
-
});
|
|
388
|
-
} else if (get().completions.length > 0) {
|
|
389
|
-
set({
|
|
390
|
-
completions: get().completions.filter((c) => c.id !== completion.id),
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
},
|
|
394
|
-
setCompletionIndex: (id?: CompletionId, index?: number) => {
|
|
395
|
-
const completion = get().getCompletion(id);
|
|
396
|
-
if (!completion) return;
|
|
397
|
-
completion.index = clamp(index, 0, completion.children.length - 1);
|
|
398
|
-
get().loadCompletion(completion.id);
|
|
399
|
-
},
|
|
400
|
-
completions: [],
|
|
401
|
-
setCompletions: (id?: ChatId) =>
|
|
402
|
-
set({completions: get().getCompletions(id)}),
|
|
403
|
-
getCompletions: (id?: ChatId) => get().getChat(id)?.completions || [],
|
|
404
|
-
updateCompletions: (id?: ChatId) => {
|
|
405
|
-
const chat = get().getChat(id);
|
|
406
|
-
if (!chat) return;
|
|
407
|
-
get().updateChat({...chat, completions: get().completions});
|
|
408
|
-
},
|
|
409
|
-
conversation: [],
|
|
410
|
-
setConversation: (id?: ChatId) =>
|
|
411
|
-
set({conversation: get().getConversation(id)}),
|
|
412
|
-
messages: [],
|
|
413
|
-
setMessages: (id?: ChatId) => set({messages: get().getMessages(id)}),
|
|
414
|
-
getMessages: (id?: ChatId) =>
|
|
415
|
-
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {clamp} from "@utils/math";
|
|
1
|
+
import {clamp, format} from "@utils/math";
|
|
2
2
|
import {getVariableFromCSS, setVariableToCSS} from "@utils/styles";
|
|
3
3
|
|
|
4
4
|
import Config, {ConfigValue} from "@console/config";
|
|
@@ -53,17 +53,17 @@ const cmd = (
|
|
|
53
53
|
}
|
|
54
54
|
switch (arg1) {
|
|
55
55
|
case "h":
|
|
56
|
-
value = clamp(parseFloat(arg2), 0, 360)
|
|
56
|
+
value = format(clamp(parseFloat(arg2), 0, 360), 0);
|
|
57
57
|
break;
|
|
58
58
|
case "s":
|
|
59
|
-
value = clamp(
|
|
59
|
+
value = format(clamp(parseFloat(arg2), 0, 100), 0);
|
|
60
60
|
break;
|
|
61
61
|
case "l":
|
|
62
|
-
value = clamp(
|
|
62
|
+
value = format(clamp(parseFloat(arg2), 0, 100), 0);
|
|
63
63
|
break;
|
|
64
64
|
}
|
|
65
|
-
setVariableToCSS(arg1, value);
|
|
66
|
-
config.update(cmd, arg1, value);
|
|
65
|
+
setVariableToCSS(arg1, value.toString());
|
|
66
|
+
config.update(cmd, arg1, value.toString());
|
|
67
67
|
break;
|
|
68
68
|
case "size":
|
|
69
69
|
value = clamp(
|
package/vite.config.ts
CHANGED
|
@@ -41,6 +41,12 @@ export default defineConfig(({mode}) => {
|
|
|
41
41
|
host: true,
|
|
42
42
|
port: 3000,
|
|
43
43
|
allowedHosts: [env.DOMAIN],
|
|
44
|
+
proxy: {
|
|
45
|
+
"/api": {
|
|
46
|
+
target: "https://omnibot3000.onrender.com",
|
|
47
|
+
changeOrigin: true,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
44
50
|
watch: {
|
|
45
51
|
usePolling: false /* speed up updates */,
|
|
46
52
|
ignored: ["**/node_modules/**", "**/dist/**"],
|