openbot 0.1.17 → 0.1.20
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/dist/agent.js +12 -4
- package/dist/cli.js +1 -1
- package/dist/config.js +1 -1
- package/dist/handlers/init.js +10 -141
- package/dist/server.js +12 -7
- package/dist/session.js +79 -1
- package/dist/ui/header.js +55 -0
- package/dist/ui/layout.js +25 -0
- package/dist/ui/navigation.js +13 -0
- package/dist/ui/settings.js +44 -0
- package/dist/ui/sidebar.js +57 -0
- package/dist/ui/skills.js +7 -0
- package/dist/ui/thread.js +14 -0
- package/package.json +8 -7
package/dist/agent.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
1
|
import { melony } from "melony";
|
|
3
2
|
import { shellPlugin, shellToolDefinitions } from "@melony/plugin-shell";
|
|
3
|
+
import { shellUIPlugin } from "@melony/plugin-shell/ui";
|
|
4
4
|
import { browserPlugin, browserToolDefinitions } from "@melony/plugin-browser";
|
|
5
|
+
import { browserUIPlugin } from "@melony/plugin-browser/ui";
|
|
5
6
|
import { fileSystemPlugin, fileSystemToolDefinitions } from "@melony/plugin-file-system";
|
|
7
|
+
import { fileSystemUIPlugin } from "@melony/plugin-file-system/ui";
|
|
6
8
|
import { metaAgentPlugin, metaAgentToolDefinitions, buildSystemPrompt } from "@melony/plugin-meta-agent";
|
|
9
|
+
import { metaAgentUIPlugin } from "@melony/plugin-meta-agent/ui";
|
|
7
10
|
import { aiSDKPlugin } from "@melony/plugin-ai-sdk";
|
|
8
11
|
import { openai } from "@ai-sdk/openai";
|
|
9
12
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
@@ -77,26 +80,31 @@ export async function createOpenBot(options) {
|
|
|
77
80
|
}
|
|
78
81
|
const llmPlugin = aiSDKPlugin({
|
|
79
82
|
model: model,
|
|
80
|
-
system: (
|
|
83
|
+
system: (context) => buildSystemPrompt(resolvedBaseDir, context),
|
|
81
84
|
toolDefinitions,
|
|
82
85
|
});
|
|
83
86
|
// Use a dedicated directory for the agent's browser data to avoid conflicts with your main Chrome.
|
|
84
87
|
// Using the root Chrome directory causes conflicts and can log you out of your main browser.
|
|
85
|
-
const userDataDir = path.join(
|
|
88
|
+
const userDataDir = path.join(resolvedBaseDir, "browser-data");
|
|
86
89
|
return melony()
|
|
87
90
|
.use(shellPlugin({ cwd: process.cwd() }))
|
|
91
|
+
.use(shellUIPlugin())
|
|
88
92
|
.use(browserPlugin({
|
|
89
93
|
headless: true, // Set to false once to log in manually if needed
|
|
90
94
|
userDataDir: userDataDir,
|
|
91
|
-
channel: 'chrome'
|
|
95
|
+
channel: 'chrome',
|
|
96
|
+
model: model
|
|
92
97
|
}))
|
|
98
|
+
.use(browserUIPlugin())
|
|
93
99
|
.use(fileSystemPlugin({
|
|
94
100
|
baseDir: "/", // Global access
|
|
95
101
|
}))
|
|
102
|
+
.use(fileSystemUIPlugin())
|
|
96
103
|
.use(metaAgentPlugin({
|
|
97
104
|
baseDir: resolvedBaseDir,
|
|
98
105
|
allowSoulModification: false, // Protect core values
|
|
99
106
|
}))
|
|
107
|
+
.use(metaAgentUIPlugin())
|
|
100
108
|
.use(llmPlugin)
|
|
101
109
|
.on("init", initHandler);
|
|
102
110
|
}
|
package/dist/cli.js
CHANGED
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import os from "node:os";
|
|
4
|
-
export const DEFAULT_BASE_DIR = "
|
|
4
|
+
export const DEFAULT_BASE_DIR = "~/.openbot";
|
|
5
5
|
export function loadConfig() {
|
|
6
6
|
const configPath = path.join(os.homedir(), ".openbot", "config.json");
|
|
7
7
|
if (fs.existsSync(configPath)) {
|
package/dist/handlers/init.js
CHANGED
|
@@ -1,148 +1,17 @@
|
|
|
1
|
+
import { layoutUI } from "../ui/layout.js";
|
|
1
2
|
/**
|
|
2
3
|
* Initial application layout handler
|
|
3
4
|
*/
|
|
4
|
-
export async function* initHandler(event) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"What is in my current directory?",
|
|
13
|
-
"Check system status",
|
|
14
|
-
"Who am I?",
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
const navigationUI = {
|
|
19
|
-
type: "list",
|
|
20
|
-
props: {
|
|
21
|
-
gap: "sm",
|
|
22
|
-
padding: "sm",
|
|
23
|
-
},
|
|
24
|
-
children: [
|
|
25
|
-
{
|
|
26
|
-
type: "listItem",
|
|
27
|
-
props: {
|
|
28
|
-
onClickAction: {
|
|
29
|
-
type: "client:navigate",
|
|
30
|
-
data: {
|
|
31
|
-
path: "/some-url",
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
children: [
|
|
36
|
-
{
|
|
37
|
-
type: "icon",
|
|
38
|
-
props: {
|
|
39
|
-
name: "🏠"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
type: "listItem",
|
|
46
|
-
props: {
|
|
47
|
-
onClickAction: {
|
|
48
|
-
type: "client:navigate",
|
|
49
|
-
data: {
|
|
50
|
-
path: "/some-other-url",
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
children: [
|
|
55
|
-
{
|
|
56
|
-
type: "icon",
|
|
57
|
-
props: {
|
|
58
|
-
name: "⚙️"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
};
|
|
65
|
-
const browserMonitorUI = {
|
|
66
|
-
type: "card",
|
|
67
|
-
props: {
|
|
68
|
-
title: "Browser Manager",
|
|
69
|
-
subtitle: "Manage open tabs & memory",
|
|
70
|
-
padding: "sm",
|
|
71
|
-
width: "300px",
|
|
72
|
-
},
|
|
73
|
-
children: [
|
|
74
|
-
{
|
|
75
|
-
type: "col",
|
|
76
|
-
props: { gap: "sm" },
|
|
77
|
-
children: [
|
|
78
|
-
{
|
|
79
|
-
type: "text",
|
|
80
|
-
props: {
|
|
81
|
-
value: "Status: Persistent session active",
|
|
82
|
-
size: "xs",
|
|
83
|
-
color: "muted"
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
type: "row",
|
|
88
|
-
props: { gap: "xs", justify: "end" },
|
|
89
|
-
children: [
|
|
90
|
-
{
|
|
91
|
-
type: "button",
|
|
92
|
-
props: {
|
|
93
|
-
label: "Refresh",
|
|
94
|
-
size: "xs",
|
|
95
|
-
variant: "outline",
|
|
96
|
-
onClickAction: {
|
|
97
|
-
type: "browser:poll_state", // Sends this event to the server
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
type: "button",
|
|
103
|
-
props: {
|
|
104
|
-
label: "Clean Junk",
|
|
105
|
-
size: "xs",
|
|
106
|
-
variant: "danger",
|
|
107
|
-
onClickAction: {
|
|
108
|
-
type: "browser:cleanup", // Sends this event to the server
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
]
|
|
117
|
-
};
|
|
118
|
-
const layoutUI = {
|
|
119
|
-
type: "box",
|
|
120
|
-
props: {
|
|
121
|
-
padding: "none",
|
|
122
|
-
radius: "md",
|
|
123
|
-
shadow: "sm",
|
|
124
|
-
height: "full",
|
|
125
|
-
},
|
|
126
|
-
children: [
|
|
127
|
-
thredUI,
|
|
128
|
-
{
|
|
129
|
-
type: "float",
|
|
130
|
-
props: {
|
|
131
|
-
position: "top-left"
|
|
132
|
-
},
|
|
133
|
-
children: [
|
|
134
|
-
navigationUI
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
// {
|
|
138
|
-
// type: "float",
|
|
139
|
-
// props: { position: "top-right", margin: "md" }, // Add it to the top right
|
|
140
|
-
// children: [browserMonitorUI]
|
|
141
|
-
// }
|
|
142
|
-
]
|
|
143
|
-
};
|
|
5
|
+
export async function* initHandler(event, { state }) {
|
|
6
|
+
// Initialize path state if not already present
|
|
7
|
+
if (!state.cwd) {
|
|
8
|
+
state.cwd = process.cwd();
|
|
9
|
+
}
|
|
10
|
+
if (!state.workspaceRoot) {
|
|
11
|
+
state.workspaceRoot = process.cwd();
|
|
12
|
+
}
|
|
144
13
|
yield {
|
|
145
14
|
type: "ui",
|
|
146
|
-
data: layoutUI
|
|
15
|
+
data: await layoutUI({ tab: event.data?.tab || "chat", sessionId: state.sessionId })
|
|
147
16
|
};
|
|
148
17
|
}
|
package/dist/server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
import { generateId } from "melony";
|
|
7
7
|
import { createOpenBot } from "./agent.js";
|
|
8
8
|
import { loadConfig } from "./config.js";
|
|
9
|
-
import { loadSession, saveSession } from "./session.js";
|
|
9
|
+
import { loadSession, saveSession, logEvent, loadEvents } from "./session.js";
|
|
10
10
|
const program = new Command();
|
|
11
11
|
program
|
|
12
12
|
.name("openbot-server")
|
|
@@ -36,18 +36,21 @@ program
|
|
|
36
36
|
app.get("/api/init", async (req, res) => {
|
|
37
37
|
const platform = req.query.platform || "web";
|
|
38
38
|
const sessionId = req.query.sessionId || "default";
|
|
39
|
+
const tab = req.query.tab;
|
|
39
40
|
const state = await loadSession(sessionId) ?? {};
|
|
40
41
|
const response = await openBot.jsonResponse({
|
|
41
42
|
type: "init",
|
|
42
|
-
data: { platform }
|
|
43
|
+
data: { platform, tab }
|
|
43
44
|
}, {
|
|
44
|
-
state,
|
|
45
|
+
state: { ...state, sessionId },
|
|
45
46
|
runId: generateId()
|
|
46
47
|
});
|
|
47
48
|
const result = await response.json();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const initialEvents = await loadEvents(sessionId);
|
|
50
|
+
res.json({
|
|
51
|
+
data: result.data,
|
|
52
|
+
initialEvents
|
|
53
|
+
});
|
|
51
54
|
});
|
|
52
55
|
// Chat endpoint
|
|
53
56
|
app.post("/api/chat", async (req, res) => {
|
|
@@ -67,6 +70,8 @@ program
|
|
|
67
70
|
const sessionId = body.sessionId ?? "default";
|
|
68
71
|
const runId = body.runId ?? `run_${generateId()}`;
|
|
69
72
|
const state = await loadSession(sessionId) ?? {};
|
|
73
|
+
// Log the incoming event
|
|
74
|
+
await logEvent(sessionId, runId, body.event);
|
|
70
75
|
const iterator = runtime.run(body.event, {
|
|
71
76
|
runId,
|
|
72
77
|
state,
|
|
@@ -81,7 +86,7 @@ program
|
|
|
81
86
|
break;
|
|
82
87
|
}
|
|
83
88
|
// Log each event to the persistent file
|
|
84
|
-
|
|
89
|
+
await logEvent(sessionId, runId, chunk);
|
|
85
90
|
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
86
91
|
}
|
|
87
92
|
// After the run finishes, save the final state back to disk
|
package/dist/session.js
CHANGED
|
@@ -35,6 +35,12 @@ function getSessionDir(sessionId) {
|
|
|
35
35
|
const today = new Date().toISOString().slice(0, 10);
|
|
36
36
|
return path.join(SESSIONS_DIR, today, sessionId);
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of messages to keep when loading a session.
|
|
40
|
+
* Older messages are dropped to avoid bloated context windows.
|
|
41
|
+
* System messages at the start are always preserved and don't count toward the limit.
|
|
42
|
+
*/
|
|
43
|
+
const MAX_MESSAGES = 1000; // aiSdkPlugin defaults to latest 20 messages
|
|
38
44
|
export async function loadSession(sessionId) {
|
|
39
45
|
const sessionDir = getSessionDir(sessionId);
|
|
40
46
|
const statePath = path.join(sessionDir, "state.json");
|
|
@@ -43,7 +49,19 @@ export async function loadSession(sessionId) {
|
|
|
43
49
|
}
|
|
44
50
|
try {
|
|
45
51
|
const data = fs.readFileSync(statePath, "utf-8");
|
|
46
|
-
|
|
52
|
+
const state = JSON.parse(data);
|
|
53
|
+
if (state.messages && state.messages.length > MAX_MESSAGES) {
|
|
54
|
+
// Preserve system messages at the beginning, then keep the tail
|
|
55
|
+
const systemMessages = [];
|
|
56
|
+
let rest = state.messages;
|
|
57
|
+
while (rest.length > 0 && rest[0].role === "system") {
|
|
58
|
+
systemMessages.push(rest[0]);
|
|
59
|
+
rest = rest.slice(1);
|
|
60
|
+
}
|
|
61
|
+
const kept = rest.slice(-MAX_MESSAGES);
|
|
62
|
+
state.messages = [...systemMessages, ...kept];
|
|
63
|
+
}
|
|
64
|
+
return state;
|
|
47
65
|
}
|
|
48
66
|
catch (error) {
|
|
49
67
|
console.error(`Failed to load session ${sessionId}:`, error);
|
|
@@ -71,3 +89,63 @@ export async function logEvent(sessionId, runId, event) {
|
|
|
71
89
|
});
|
|
72
90
|
fs.appendFileSync(logPath, entry + "\n", "utf-8");
|
|
73
91
|
}
|
|
92
|
+
export async function loadEvents(sessionId) {
|
|
93
|
+
const sessionDir = getSessionDir(sessionId);
|
|
94
|
+
const logPath = path.join(sessionDir, `events.jsonl`);
|
|
95
|
+
if (!fs.existsSync(logPath)) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const data = fs.readFileSync(logPath, "utf-8");
|
|
100
|
+
return data
|
|
101
|
+
.split("\n")
|
|
102
|
+
.filter((line) => line.trim() !== "")
|
|
103
|
+
.map((line) => JSON.parse(line));
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error(`Failed to load events for session ${sessionId}:`, error);
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export async function listSessions() {
|
|
111
|
+
if (!fs.existsSync(SESSIONS_DIR))
|
|
112
|
+
return [];
|
|
113
|
+
const sessions = [];
|
|
114
|
+
try {
|
|
115
|
+
const items = fs.readdirSync(SESSIONS_DIR);
|
|
116
|
+
for (const item of items) {
|
|
117
|
+
const itemPath = path.join(SESSIONS_DIR, item);
|
|
118
|
+
const stat = fs.statSync(itemPath);
|
|
119
|
+
if (stat.isDirectory()) {
|
|
120
|
+
// If it's a date folder (YYYY-MM-DD), look inside
|
|
121
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(item)) {
|
|
122
|
+
const subItems = fs.readdirSync(itemPath);
|
|
123
|
+
for (const subItem of subItems) {
|
|
124
|
+
const sessionPath = path.join(itemPath, subItem);
|
|
125
|
+
const statePath = path.join(sessionPath, "state.json");
|
|
126
|
+
if (fs.existsSync(statePath)) {
|
|
127
|
+
sessions.push({
|
|
128
|
+
id: subItem,
|
|
129
|
+
mtime: fs.statSync(statePath).birthtime, // sort by creation time
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// It's a legacy session folder in root
|
|
136
|
+
const statePath = path.join(itemPath, "state.json");
|
|
137
|
+
if (fs.existsSync(statePath)) {
|
|
138
|
+
sessions.push({
|
|
139
|
+
id: item,
|
|
140
|
+
mtime: fs.statSync(statePath).birthtime, // sort by creation time
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error("Failed to list sessions:", error);
|
|
149
|
+
}
|
|
150
|
+
return sessions.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
151
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
export const headerUI = (tab) => ui.box({
|
|
3
|
+
padding: "sm",
|
|
4
|
+
background: "background",
|
|
5
|
+
width: "full",
|
|
6
|
+
}, [
|
|
7
|
+
ui.row({ justify: "between", align: "center", width: "full" }, [
|
|
8
|
+
ui.row({ gap: "xs", align: "center" }, [
|
|
9
|
+
ui.button({
|
|
10
|
+
label: "OpenBot",
|
|
11
|
+
variant: "ghost",
|
|
12
|
+
size: "sm",
|
|
13
|
+
onClickAction: {
|
|
14
|
+
type: "client:navigate",
|
|
15
|
+
data: { path: "/" },
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
ui.divider({ orientation: "vertical", margin: "xs" }),
|
|
19
|
+
ui.button({
|
|
20
|
+
label: "Chat",
|
|
21
|
+
variant: (tab === "chat" || !tab) ? "secondary" : "ghost",
|
|
22
|
+
size: "sm",
|
|
23
|
+
onClickAction: {
|
|
24
|
+
type: "client:navigate",
|
|
25
|
+
data: { path: "/" },
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
ui.button({
|
|
29
|
+
label: "Skills",
|
|
30
|
+
variant: tab === "skills" ? "secondary" : "ghost",
|
|
31
|
+
size: "sm",
|
|
32
|
+
onClickAction: {
|
|
33
|
+
type: "client:navigate",
|
|
34
|
+
data: { path: "/?tab=skills" },
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
ui.button({
|
|
38
|
+
label: "Settings",
|
|
39
|
+
variant: tab === "settings" ? "secondary" : "ghost",
|
|
40
|
+
size: "sm",
|
|
41
|
+
onClickAction: {
|
|
42
|
+
type: "client:navigate",
|
|
43
|
+
data: { path: "/?tab=settings" },
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
]),
|
|
47
|
+
ui.row({ gap: "sm", align: "center", width: "auto" }, [
|
|
48
|
+
ui.button({
|
|
49
|
+
label: "JD",
|
|
50
|
+
variant: "outline",
|
|
51
|
+
size: "sm",
|
|
52
|
+
}),
|
|
53
|
+
]),
|
|
54
|
+
]),
|
|
55
|
+
]);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
import { threadUI } from "./thread.js";
|
|
3
|
+
import { sidebarUI } from "./sidebar.js";
|
|
4
|
+
import { settingsUI } from "./settings.js";
|
|
5
|
+
import { skillsUI } from "./skills.js";
|
|
6
|
+
import { listSessions } from "../session.js";
|
|
7
|
+
const tabs = {
|
|
8
|
+
chat: threadUI,
|
|
9
|
+
settings: settingsUI,
|
|
10
|
+
skills: skillsUI,
|
|
11
|
+
};
|
|
12
|
+
// export const layoutUI = (tab: string) =>
|
|
13
|
+
// ui.col({ height: "full", width: "full", gap: "none" }, [
|
|
14
|
+
// headerUI(tab),
|
|
15
|
+
// ui.box({ flex: 1, width: "full", overflow: "auto" }, [
|
|
16
|
+
// tabs[tab as keyof typeof tabs],
|
|
17
|
+
// ]),
|
|
18
|
+
// ]);
|
|
19
|
+
export const layoutUI = async ({ tab, sessionId }) => {
|
|
20
|
+
const sessions = await listSessions();
|
|
21
|
+
return ui.row({ height: "full" }, [
|
|
22
|
+
sidebarUI({ sessions, sessionId }),
|
|
23
|
+
tabs[tab]
|
|
24
|
+
]);
|
|
25
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
const listItemProps = (path) => ({
|
|
3
|
+
onClickAction: {
|
|
4
|
+
type: "client:navigate",
|
|
5
|
+
data: { path },
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
export const navigationUI = ui.box({ width: "full" }, [ui.list({
|
|
9
|
+
gap: "none",
|
|
10
|
+
}, [
|
|
11
|
+
ui.listItem(listItemProps("/"), [ui.text("Chat", { size: "sm" })]),
|
|
12
|
+
ui.listItem(listItemProps("/?tab=skills"), [ui.text("Skills", { size: "sm" })]),
|
|
13
|
+
])]);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
export const settingsUI = ui.box({
|
|
3
|
+
width: "full",
|
|
4
|
+
height: "full",
|
|
5
|
+
padding: "xl",
|
|
6
|
+
background: "background",
|
|
7
|
+
}, [
|
|
8
|
+
ui.col({ gap: "xl", width: "full" }, [
|
|
9
|
+
ui.col({ gap: "xs" }, [
|
|
10
|
+
ui.heading("Settings", 2),
|
|
11
|
+
ui.text("Manage your OpenBot configuration", { color: "mutedForeground" }),
|
|
12
|
+
]),
|
|
13
|
+
ui.divider(),
|
|
14
|
+
ui.col({ gap: "md" }, [
|
|
15
|
+
ui.heading("Model Configuration", 4),
|
|
16
|
+
ui.row({ align: "center", gap: "md" }, [
|
|
17
|
+
ui.box({ flex: 1 }, [
|
|
18
|
+
ui.node("label", { value: "Provider" }),
|
|
19
|
+
ui.text("OpenAI (GPT-4o)", { size: "sm", color: "mutedForeground" }),
|
|
20
|
+
]),
|
|
21
|
+
ui.button({ label: "Change", variant: "outline", size: "sm" })
|
|
22
|
+
]),
|
|
23
|
+
]),
|
|
24
|
+
ui.col({ gap: "md" }, [
|
|
25
|
+
ui.heading("API Keys", 4),
|
|
26
|
+
ui.col({ gap: "sm" }, [
|
|
27
|
+
ui.node("label", { value: "OpenAI API Key" }),
|
|
28
|
+
ui.row({ gap: "sm" }, [
|
|
29
|
+
ui.input("openai_api_key", undefined, {
|
|
30
|
+
placeholder: "sk-...",
|
|
31
|
+
inputType: "password",
|
|
32
|
+
defaultValue: "••••••••••••••••",
|
|
33
|
+
width: "full"
|
|
34
|
+
}),
|
|
35
|
+
ui.button({ label: "Save", size: "sm" })
|
|
36
|
+
])
|
|
37
|
+
])
|
|
38
|
+
]),
|
|
39
|
+
ui.col({ gap: "md" }, [
|
|
40
|
+
ui.heading("Theme", 4),
|
|
41
|
+
ui.themeToggle(),
|
|
42
|
+
])
|
|
43
|
+
])
|
|
44
|
+
]);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
import { navigationUI } from "./navigation.js";
|
|
3
|
+
export const sidebarUI = ({ sessions, sessionId }) => ui.box({
|
|
4
|
+
width: 280,
|
|
5
|
+
height: "full",
|
|
6
|
+
overflow: "hidden",
|
|
7
|
+
background: "muted/20",
|
|
8
|
+
}, [
|
|
9
|
+
ui.col({ width: "full", height: "full" }, [
|
|
10
|
+
ui.box({ padding: "xs" }, [
|
|
11
|
+
ui.row({ justify: "between", align: "center", width: "full" }, [
|
|
12
|
+
ui.button({
|
|
13
|
+
label: "OpenBot",
|
|
14
|
+
variant: "ghost",
|
|
15
|
+
size: "sm",
|
|
16
|
+
onClickAction: {
|
|
17
|
+
type: "client:navigate",
|
|
18
|
+
data: { path: "/" },
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
]),
|
|
22
|
+
]),
|
|
23
|
+
ui.col({ width: "full", gap: "sm", padding: "sm" }, [
|
|
24
|
+
navigationUI,
|
|
25
|
+
]),
|
|
26
|
+
ui.col({ width: "full", flex: 1, padding: "sm", overflow: "auto" }, [
|
|
27
|
+
ui.list({
|
|
28
|
+
gap: "none",
|
|
29
|
+
width: "full",
|
|
30
|
+
}, [
|
|
31
|
+
...sessions.map((session) => ui.listItem({
|
|
32
|
+
padding: "sm",
|
|
33
|
+
onClickAction: {
|
|
34
|
+
type: "client:navigate",
|
|
35
|
+
data: { path: `/?sessionId=${session.id}` },
|
|
36
|
+
},
|
|
37
|
+
background: session.id === sessionId ? "muted" : "transparent",
|
|
38
|
+
}, [ui.text(session.id.slice(0, 10), { size: "sm" })]))
|
|
39
|
+
]),
|
|
40
|
+
]),
|
|
41
|
+
ui.spacer({ size: "xs" }),
|
|
42
|
+
ui.box({ padding: "sm", width: "full" }, [
|
|
43
|
+
ui.list({
|
|
44
|
+
gap: "sm",
|
|
45
|
+
width: "full",
|
|
46
|
+
}, [
|
|
47
|
+
ui.listItem({
|
|
48
|
+
padding: "sm",
|
|
49
|
+
onClickAction: {
|
|
50
|
+
type: "client:navigate",
|
|
51
|
+
data: { path: "/?tab=settings" },
|
|
52
|
+
},
|
|
53
|
+
}, [ui.text("Settings", { size: "sm" })]),
|
|
54
|
+
]),
|
|
55
|
+
]),
|
|
56
|
+
]),
|
|
57
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ui } from "@melony/ui-kit";
|
|
2
|
+
export const threadUI = ui.box({
|
|
3
|
+
width: "full",
|
|
4
|
+
height: "full",
|
|
5
|
+
}, [ui.thread({
|
|
6
|
+
placeholder: "Ask me anything about your system or projects...",
|
|
7
|
+
welcomeTitle: "OpenBot",
|
|
8
|
+
welcomeMessage: "Hey there! I'm your trusty system sidekick with superpowers over your files and terminal. Let's make some magic happen!",
|
|
9
|
+
suggestions: [
|
|
10
|
+
"What is in my current directory?",
|
|
11
|
+
"Check system status",
|
|
12
|
+
"Who am I?",
|
|
13
|
+
]
|
|
14
|
+
})]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
"dotenv": "^16.4.5",
|
|
17
17
|
"express": "^4.19.2",
|
|
18
18
|
"zod": "^4.3.5",
|
|
19
|
-
"@melony/plugin-ai-sdk": "0.1.
|
|
20
|
-
"@melony/plugin-file-system": "0.1.
|
|
21
|
-
"@melony/plugin-browser": "0.1.
|
|
22
|
-
"@melony/plugin-shell": "0.1.
|
|
23
|
-
"
|
|
24
|
-
"melony": "0.
|
|
19
|
+
"@melony/plugin-ai-sdk": "0.1.5",
|
|
20
|
+
"@melony/plugin-file-system": "0.1.3",
|
|
21
|
+
"@melony/plugin-browser": "0.1.5",
|
|
22
|
+
"@melony/plugin-shell": "0.1.2",
|
|
23
|
+
"melony": "0.2.7",
|
|
24
|
+
"@melony/ui-kit": "0.1.3",
|
|
25
|
+
"@melony/plugin-meta-agent": "0.1.3"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/express": "^4.17.21",
|