totem-llm 0.3.3 → 0.3.4
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/README.md +3 -3
- package/bin/totem-llm.js +1 -1
- package/lib/launcher.js +48 -22
- package/lib/setup.js +1 -1
- package/package.json +1 -1
- package/server/.env +1 -1
- package/server/index.js +2 -2
- package/server/models/mobileDevice.js +1 -1
- package/server/models/systemSettings.js +1 -1
- package/server/public/assets/{index-9a279a2e.js → index-391c1474.js} +2 -2
- package/server/public/assets/{index-558f988a.js → index-4ce77c64.js} +1 -1
- package/server/public/assets/{index-dcc00e8c.js → index-671239cd.js} +1 -1
- package/server/public/assets/{index-3051865c.js → index-a253e180.js} +1 -1
- package/server/public/assets/{index-d1d3d69a.js → index-df293c50.js} +1 -1
- package/server/public/index.js +5 -5
- package/server/utils/boot/index.js +3 -3
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ This downloads Totem LLM and installs all server and collector dependencies auto
|
|
|
27
27
|
totem-llm start
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
On first run this performs one-time setup (creates `~/totem-llm/`, migrates the database) then launches the server and document collector. Open [http://localhost:
|
|
30
|
+
On first run this performs one-time setup (creates `~/totem-llm/`, migrates the database) then launches the server and document collector. Open [http://localhost:8686](http://localhost:8686) to access the UI.
|
|
31
31
|
|
|
32
32
|
### 3. Install to Desktop (optional)
|
|
33
33
|
|
|
@@ -37,7 +37,7 @@ In the browser, click the install icon in the address bar (or use the browser me
|
|
|
37
37
|
|
|
38
38
|
```
|
|
39
39
|
totem-llm --no-collector Start without the document collector
|
|
40
|
-
totem-llm --port=8080 Override the server port (default:
|
|
40
|
+
totem-llm --port=8080 Override the server port (default: 8686)
|
|
41
41
|
totem-llm setup Run first-time setup without starting
|
|
42
42
|
totem-llm --help Show all options
|
|
43
43
|
```
|
|
@@ -102,7 +102,7 @@ All other settings (LLM provider, embedding model, etc.) can be changed later th
|
|
|
102
102
|
yarn dev:all
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
This starts the server (port `
|
|
105
|
+
This starts the server (port `8686`), collector (port `8888`), and frontend dev server (port `5173`) concurrently. Open [http://localhost:5173](http://localhost:5173) to access the UI.
|
|
106
106
|
|
|
107
107
|
> Alternatively, run each service in its own terminal: `yarn dev:server`, `yarn dev:collector`, `yarn dev:frontend`.
|
|
108
108
|
|
package/bin/totem-llm.js
CHANGED
|
@@ -75,7 +75,7 @@ Commands:
|
|
|
75
75
|
|
|
76
76
|
Options:
|
|
77
77
|
--no-collector Start without the document collector (skips Puppeteer/ffmpeg)
|
|
78
|
-
--port=<port> Override the server port (default:
|
|
78
|
+
--port=<port> Override the server port (default: 8686)
|
|
79
79
|
--version, -v Print Totem LLM version and exit
|
|
80
80
|
--force (setup only) Regenerate configuration even if it already exists
|
|
81
81
|
|
package/lib/launcher.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import { join } from "path";
|
|
3
|
+
import { appendFileSync, mkdirSync, writeFileSync } from "fs";
|
|
3
4
|
import { getEnv } from "./config.js";
|
|
4
5
|
import { getPackageVersion } from "./version.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Spawn a Node.js service and prefix every log line with a fixed-width label.
|
|
9
|
+
* Also writes all logs to a session log file.
|
|
8
10
|
*
|
|
9
11
|
* @param {string} nodeExe Absolute path to the Node binary (process.execPath)
|
|
10
12
|
* @param {string} cwd Working directory for the child process
|
|
11
13
|
* @param {object} env Environment variables to pass to the child
|
|
12
14
|
* @param {string} label Log prefix, e.g. "[server] "
|
|
15
|
+
* @param {string} logFile Path to the session log file
|
|
13
16
|
* @returns {{ process: import('child_process').ChildProcess }}
|
|
14
17
|
*/
|
|
15
|
-
function spawnService(nodeExe, cwd, env, label) {
|
|
18
|
+
function spawnService(nodeExe, cwd, env, label, logFile) {
|
|
16
19
|
const child = spawn(nodeExe, ["index.js"], {
|
|
17
20
|
cwd,
|
|
18
21
|
env,
|
|
@@ -22,17 +25,19 @@ function spawnService(nodeExe, cwd, env, label) {
|
|
|
22
25
|
const pad = label.padEnd(13);
|
|
23
26
|
let buf = "";
|
|
24
27
|
|
|
25
|
-
function flush(
|
|
28
|
+
function flush(chunk) {
|
|
26
29
|
buf += chunk.toString();
|
|
27
30
|
const lines = buf.split("\n");
|
|
28
31
|
buf = lines.pop(); // keep any incomplete trailing line
|
|
29
32
|
for (const line of lines) {
|
|
30
|
-
if (line.trim())
|
|
33
|
+
if (line.trim()) {
|
|
34
|
+
appendFileSync(logFile, `${pad} ${line}\n`);
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
child.stdout.on("data", (c) => flush(
|
|
35
|
-
child.stderr.on("data", (c) => flush(
|
|
39
|
+
child.stdout.on("data", (c) => flush(c));
|
|
40
|
+
child.stderr.on("data", (c) => flush(c));
|
|
36
41
|
|
|
37
42
|
return child;
|
|
38
43
|
}
|
|
@@ -52,27 +57,43 @@ export async function launch({ packageRoot, noCollector = false, port } = {}) {
|
|
|
52
57
|
appVersion = getPackageVersion(packageRoot) ?? "unknown";
|
|
53
58
|
} catch {}
|
|
54
59
|
|
|
55
|
-
const serverPort = env.SERVER_PORT ?? "
|
|
60
|
+
const serverPort = env.SERVER_PORT ?? "8686";
|
|
56
61
|
const collectorPort = env.COLLECTOR_PORT ?? "8888";
|
|
57
62
|
const nodeExe = process.execPath; // cross-platform: always the right Node binary
|
|
58
63
|
|
|
59
64
|
const serverDir = join(packageRoot, "server");
|
|
60
65
|
const collectorDir = join(packageRoot, "collector");
|
|
61
66
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
// Initialize session log file - clear on each startup
|
|
68
|
+
const logsDir = join(serverDir, "storage", "logs");
|
|
69
|
+
mkdirSync(logsDir, { recursive: true });
|
|
70
|
+
const sessionLogFile = join(logsDir, "totem-session.log");
|
|
71
|
+
writeFileSync(sessionLogFile, `${"=".repeat(80)}\nSession started: ${new Date().toISOString()}\n${"=".repeat(80)}\n`);
|
|
72
|
+
|
|
73
|
+
process.stdout.write(`
|
|
74
|
+
████████╗ ██████╗ ████████╗███████╗███╗ ███╗ ██╗ ██╗ ███╗ ███╗
|
|
75
|
+
╚══██╔══╝██╔═══██╗╚══██╔══╝██╔════╝████╗ ████║ ██║ ██║ ████╗ ████║
|
|
76
|
+
██║ ██║ ██║ ██║ █████╗ ██╔████╔██║ ██║ ██║ ██╔████╔██║
|
|
77
|
+
██║ ██║ ██║ ██║ ██╔══╝ ██║╚██╔╝██║ ██║ ██║ ██║╚██╔╝██║
|
|
78
|
+
██║ ╚██████╔╝ ██║ ███████╗██║ ╚═╝ ██║ ███████╗███████╗██║ ╚═╝ ██║
|
|
79
|
+
╚═╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝
|
|
80
|
+
|
|
81
|
+
Your Private AI
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Starting Totem LLM…\n
|
|
85
|
+
============================================================================\n
|
|
86
|
+
Logs → ${sessionLogFile}\n
|
|
87
|
+
LAUNCH UI HERE (ctrl + click)--> http://localhost:${serverPort}/\n
|
|
88
|
+
|
|
89
|
+
Press Ctrl+C to stop.\n
|
|
90
|
+
`);
|
|
91
|
+
|
|
92
|
+
const serverProc = spawnService(nodeExe, serverDir, env, "[server]", sessionLogFile);
|
|
72
93
|
|
|
73
94
|
let collectorProc = null;
|
|
74
95
|
if (!noCollector) {
|
|
75
|
-
collectorProc = spawnService(nodeExe, collectorDir, env, "[collector]");
|
|
96
|
+
collectorProc = spawnService(nodeExe, collectorDir, env, "[collector]", sessionLogFile);
|
|
76
97
|
}
|
|
77
98
|
|
|
78
99
|
// ── Graceful shutdown ────────────────────────────────────────────────────
|
|
@@ -82,7 +103,10 @@ export async function launch({ packageRoot, noCollector = false, port } = {}) {
|
|
|
82
103
|
if (shuttingDown) return;
|
|
83
104
|
shuttingDown = true;
|
|
84
105
|
|
|
85
|
-
|
|
106
|
+
const shutdownMsg = `\nShutting down (${signal})…`;
|
|
107
|
+
process.stdout.write(`${shutdownMsg}\n`);
|
|
108
|
+
appendFileSync(sessionLogFile, `${shutdownMsg}\n`);
|
|
109
|
+
|
|
86
110
|
serverProc.kill("SIGTERM");
|
|
87
111
|
if (collectorProc) collectorProc.kill("SIGTERM");
|
|
88
112
|
|
|
@@ -102,7 +126,9 @@ export async function launch({ packageRoot, noCollector = false, port } = {}) {
|
|
|
102
126
|
// Exit this process when the server exits unexpectedly
|
|
103
127
|
serverProc.on("close", (code) => {
|
|
104
128
|
if (!shuttingDown && code !== null && code !== 0) {
|
|
105
|
-
|
|
129
|
+
const errMsg = `[server] exited unexpectedly with code ${code}`;
|
|
130
|
+
process.stderr.write(`${errMsg}\n`);
|
|
131
|
+
appendFileSync(sessionLogFile, `${errMsg}\n`);
|
|
106
132
|
shutdown("server-exit");
|
|
107
133
|
setTimeout(() => process.exit(1), 500);
|
|
108
134
|
}
|
|
@@ -111,9 +137,9 @@ export async function launch({ packageRoot, noCollector = false, port } = {}) {
|
|
|
111
137
|
if (collectorProc) {
|
|
112
138
|
collectorProc.on("close", (code) => {
|
|
113
139
|
if (!shuttingDown && code !== null && code !== 0) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
);
|
|
140
|
+
const errMsg = `[collector] exited with code ${code} — document ingestion unavailable`;
|
|
141
|
+
process.stderr.write(`${errMsg}\n`);
|
|
142
|
+
appendFileSync(sessionLogFile, `${errMsg}\n`);
|
|
117
143
|
}
|
|
118
144
|
});
|
|
119
145
|
}
|
package/lib/setup.js
CHANGED
|
@@ -28,7 +28,7 @@ function buildEnvFile(storageDir) {
|
|
|
28
28
|
"# Edit this file to configure your instance, then restart.",
|
|
29
29
|
"",
|
|
30
30
|
`STORAGE_DIR="${storageDir}"`,
|
|
31
|
-
"SERVER_PORT=
|
|
31
|
+
"SERVER_PORT=8686",
|
|
32
32
|
"COLLECTOR_PORT=8888",
|
|
33
33
|
"",
|
|
34
34
|
"# Security secrets (auto-generated — do not share these)",
|
package/package.json
CHANGED
package/server/.env
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
SERVER_PORT=
|
|
1
|
+
SERVER_PORT=8686
|
|
2
2
|
DATABASE_URL="file:../storage/anythingllm.db"
|
|
3
3
|
JWT_SECRET="my-random-string-for-seeding" # Please generate random string at least 12 chars long.
|
|
4
4
|
# JWT_EXPIRY="30d" # (optional) https://docs.anythingllm.com/configuration#custom-ttl-for-sessions
|
package/server/index.js
CHANGED
|
@@ -82,7 +82,7 @@ app.use(
|
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
if (!!process.env.ENABLE_HTTPS) {
|
|
85
|
-
bootSSL(app, process.env.SERVER_PORT ||
|
|
85
|
+
bootSSL(app, process.env.SERVER_PORT || 8686);
|
|
86
86
|
} else {
|
|
87
87
|
require("@mintplex-labs/express-ws").default(app); // load WebSockets in non-SSL mode.
|
|
88
88
|
}
|
|
@@ -187,4 +187,4 @@ app.all("*", function (_, response) {
|
|
|
187
187
|
|
|
188
188
|
// In non-https mode we need to boot at the end since the server has not yet
|
|
189
189
|
// started and is `.listen`ing.
|
|
190
|
-
if (!process.env.ENABLE_HTTPS) bootHTTP(app, process.env.SERVER_PORT ||
|
|
190
|
+
if (!process.env.ENABLE_HTTPS) bootHTTP(app, process.env.SERVER_PORT || 8686);
|
|
@@ -100,7 +100,7 @@ const MobileDevice = {
|
|
|
100
100
|
let baseUrl = "/api/mobile";
|
|
101
101
|
if (process.env.NODE_ENV === "production") baseUrl = "/api/mobile";
|
|
102
102
|
else
|
|
103
|
-
baseUrl = `http://${ip.address()}:${process.env.SERVER_PORT ||
|
|
103
|
+
baseUrl = `http://${ip.address()}:${process.env.SERVER_PORT || 8686}/api/mobile`;
|
|
104
104
|
|
|
105
105
|
const tempToken = this.registerTempToken(user);
|
|
106
106
|
baseUrl = `${baseUrl}?t=${tempToken}`;
|
|
@@ -36,7 +36,7 @@ function mergeStringField(target, source, fieldName, validator = null) {
|
|
|
36
36
|
const SystemSettings = {
|
|
37
37
|
/** A default system prompt that is used when no other system prompt is set or available to the function caller. */
|
|
38
38
|
saneDefaultSystemPrompt:
|
|
39
|
-
"You are Totem LLM. You are an AI that prioritizes consistent behavior with your history.",
|
|
39
|
+
"You are Totem LLM. You are an AI that prioritizes consistent behavior with your history. The current date and time is {datetime}.",
|
|
40
40
|
protectedFields: ["multi_user_mode", "hub_api_key", "onboarding_complete"],
|
|
41
41
|
publicFields: [
|
|
42
42
|
"footer_data",
|