openbot 0.1.16 → 0.1.17
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 +1 -1
- package/dist/cli.js +1 -1
- package/dist/handlers/init.js +0 -1
- package/dist/server.js +20 -7
- package/dist/session.js +73 -0
- package/package.json +3 -3
package/dist/agent.js
CHANGED
|
@@ -53,7 +53,7 @@ export async function createOpenBot(options) {
|
|
|
53
53
|
const baseDir = config.baseDir || DEFAULT_BASE_DIR;
|
|
54
54
|
const resolvedBaseDir = resolvePath(baseDir);
|
|
55
55
|
// Parse model configuration
|
|
56
|
-
const { provider, modelId } = parseModelString(config.model || "gpt-
|
|
56
|
+
const { provider, modelId } = parseModelString(config.model || "gpt-4o-mini");
|
|
57
57
|
// Tool definitions shared by both providers
|
|
58
58
|
const toolDefinitions = {
|
|
59
59
|
...shellToolDefinitions,
|
package/dist/cli.js
CHANGED
package/dist/handlers/init.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -3,8 +3,10 @@ import "dotenv/config";
|
|
|
3
3
|
import express from "express";
|
|
4
4
|
import cors from "cors";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
+
import { generateId } from "melony";
|
|
6
7
|
import { createOpenBot } from "./agent.js";
|
|
7
8
|
import { loadConfig } from "./config.js";
|
|
9
|
+
import { loadSession, saveSession } from "./session.js";
|
|
8
10
|
const program = new Command();
|
|
9
11
|
program
|
|
10
12
|
.name("openbot-server")
|
|
@@ -21,8 +23,6 @@ program
|
|
|
21
23
|
openaiApiKey: options.openaiApiKey,
|
|
22
24
|
anthropicApiKey: options.anthropicApiKey,
|
|
23
25
|
});
|
|
24
|
-
// In-memory state store (use a real database for production)
|
|
25
|
-
const stateStore = new Map();
|
|
26
26
|
app.use(cors());
|
|
27
27
|
app.use(express.json());
|
|
28
28
|
app.get("/", async (req, res) => {
|
|
@@ -32,14 +32,24 @@ program
|
|
|
32
32
|
stream: "Server-Sent Events (SSE)",
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
|
+
// Init endpoint
|
|
35
36
|
app.get("/api/init", async (req, res) => {
|
|
36
37
|
const platform = req.query.platform || "web";
|
|
38
|
+
const sessionId = req.query.sessionId || "default";
|
|
39
|
+
const state = await loadSession(sessionId) ?? {};
|
|
37
40
|
const response = await openBot.jsonResponse({
|
|
38
41
|
type: "init",
|
|
39
42
|
data: { platform }
|
|
43
|
+
}, {
|
|
44
|
+
state,
|
|
45
|
+
runId: generateId()
|
|
40
46
|
});
|
|
41
|
-
|
|
47
|
+
const result = await response.json();
|
|
48
|
+
// Save state in case init handler modified it
|
|
49
|
+
await saveSession(sessionId, state);
|
|
50
|
+
res.json(result);
|
|
42
51
|
});
|
|
52
|
+
// Chat endpoint
|
|
43
53
|
app.post("/api/chat", async (req, res) => {
|
|
44
54
|
const body = req.body;
|
|
45
55
|
if (!body.event || typeof body.event.type !== "string") {
|
|
@@ -54,8 +64,9 @@ program
|
|
|
54
64
|
});
|
|
55
65
|
res.flushHeaders?.();
|
|
56
66
|
const runtime = openBot.build();
|
|
57
|
-
const
|
|
58
|
-
const
|
|
67
|
+
const sessionId = body.sessionId ?? "default";
|
|
68
|
+
const runId = body.runId ?? `run_${generateId()}`;
|
|
69
|
+
const state = await loadSession(sessionId) ?? {};
|
|
59
70
|
const iterator = runtime.run(body.event, {
|
|
60
71
|
runId,
|
|
61
72
|
state,
|
|
@@ -69,10 +80,12 @@ program
|
|
|
69
80
|
if (res.writableEnded) {
|
|
70
81
|
break;
|
|
71
82
|
}
|
|
83
|
+
// Log each event to the persistent file
|
|
84
|
+
// await logEvent(sessionId, runId, chunk);
|
|
72
85
|
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
73
86
|
}
|
|
74
|
-
// After the run finishes, the state
|
|
75
|
-
|
|
87
|
+
// After the run finishes, save the final state back to disk
|
|
88
|
+
await saveSession(sessionId, state);
|
|
76
89
|
}
|
|
77
90
|
catch (error) {
|
|
78
91
|
console.error("Melony stream error:", error);
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
const SESSIONS_DIR = path.join(os.homedir(), ".openbot", "sessions");
|
|
5
|
+
function getSessionDir(sessionId) {
|
|
6
|
+
if (!fs.existsSync(SESSIONS_DIR)) {
|
|
7
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
8
|
+
return path.join(SESSIONS_DIR, today, sessionId);
|
|
9
|
+
}
|
|
10
|
+
// 1. Check if it already exists in a date-based folder (YYYY-MM-DD or YYYY-MM)
|
|
11
|
+
const dateFolders = fs.readdirSync(SESSIONS_DIR).filter(d => /^\d{4}-\d{2}(-\d{2})?$/.test(d));
|
|
12
|
+
for (const folder of dateFolders) {
|
|
13
|
+
const dir = path.join(SESSIONS_DIR, folder, sessionId);
|
|
14
|
+
if (fs.existsSync(dir)) {
|
|
15
|
+
return dir;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// 2. Check if it exists in the root (legacy)
|
|
19
|
+
const legacyDir = path.join(SESSIONS_DIR, sessionId);
|
|
20
|
+
if (fs.existsSync(legacyDir) && fs.statSync(legacyDir).isDirectory()) {
|
|
21
|
+
const stats = fs.statSync(legacyDir);
|
|
22
|
+
const day = stats.mtime.toISOString().slice(0, 10);
|
|
23
|
+
const newDir = path.join(SESSIONS_DIR, day, sessionId);
|
|
24
|
+
fs.mkdirSync(path.dirname(newDir), { recursive: true });
|
|
25
|
+
try {
|
|
26
|
+
fs.renameSync(legacyDir, newDir);
|
|
27
|
+
return newDir;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.warn(`Failed to migrate session ${sessionId} to ${day}:`, error);
|
|
31
|
+
return legacyDir;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 3. New session - use current day
|
|
35
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
36
|
+
return path.join(SESSIONS_DIR, today, sessionId);
|
|
37
|
+
}
|
|
38
|
+
export async function loadSession(sessionId) {
|
|
39
|
+
const sessionDir = getSessionDir(sessionId);
|
|
40
|
+
const statePath = path.join(sessionDir, "state.json");
|
|
41
|
+
if (!fs.existsSync(statePath)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const data = fs.readFileSync(statePath, "utf-8");
|
|
46
|
+
return JSON.parse(data);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error(`Failed to load session ${sessionId}:`, error);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export async function saveSession(sessionId, state) {
|
|
54
|
+
const sessionDir = getSessionDir(sessionId);
|
|
55
|
+
if (!fs.existsSync(sessionDir)) {
|
|
56
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
const statePath = path.join(sessionDir, "state.json");
|
|
59
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
60
|
+
}
|
|
61
|
+
export async function logEvent(sessionId, runId, event) {
|
|
62
|
+
const sessionDir = getSessionDir(sessionId);
|
|
63
|
+
if (!fs.existsSync(sessionDir)) {
|
|
64
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
const logPath = path.join(sessionDir, `events.jsonl`);
|
|
67
|
+
const entry = JSON.stringify({
|
|
68
|
+
timestamp: new Date().toISOString(),
|
|
69
|
+
runId,
|
|
70
|
+
...event,
|
|
71
|
+
});
|
|
72
|
+
fs.appendFileSync(logPath, entry + "\n", "utf-8");
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"express": "^4.19.2",
|
|
18
18
|
"zod": "^4.3.5",
|
|
19
19
|
"@melony/plugin-ai-sdk": "0.1.4",
|
|
20
|
+
"@melony/plugin-file-system": "0.1.1",
|
|
20
21
|
"@melony/plugin-browser": "0.1.3",
|
|
21
|
-
"@melony/plugin-meta-agent": "0.1.2",
|
|
22
22
|
"@melony/plugin-shell": "0.1.1",
|
|
23
|
-
"@melony/plugin-
|
|
23
|
+
"@melony/plugin-meta-agent": "0.1.2",
|
|
24
24
|
"melony": "0.2.6"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|