tinywebui 0.1.4 → 0.1.5
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 +20 -13
- package/bin/tinywebui.js +69 -53
- package/package.json +25 -8
- package/public/app.js +40 -34
- package/public/chat/composer.js +1 -1
- package/public/chat/sidebar.js +8 -5
- package/public/index.html +88 -53
- package/public/panels/admin.js +40 -1
- package/public/panels/model-editor.js +336 -0
- package/public/panels/panels.js +37 -12
- package/public/panels/settings-home.js +125 -0
- package/public/panels/settings.js +124 -36
- package/public/shared/attachment_note.js +7 -1
- package/public/shared/events.js +1 -0
- package/public/shared/features.js +1 -0
- package/public/shared/origins.js +1 -0
- package/public/shared/usage.js +16 -1
- package/public/styles.css +84 -21
- package/src/access/auth.js +155 -155
- package/src/access/auth_gate.js +39 -38
- package/src/access/email.js +17 -0
- package/src/access/policy.js +123 -136
- package/src/audit.js +1 -1
- package/src/automations/automation.js +135 -123
- package/src/automations/scheduler.js +138 -127
- package/src/chat/compact.js +149 -156
- package/src/chat/llm.js +380 -382
- package/src/chat/runs.js +162 -151
- package/src/chat/tool_executor.js +229 -218
- package/src/cli.js +535 -433
- package/src/config/approval.js +35 -29
- package/src/config/config.js +546 -454
- package/src/config/data_dir.js +24 -0
- package/src/config/models.js +191 -115
- package/src/config/refs.js +32 -0
- package/src/config/secrets.js +153 -0
- package/src/files/documents.js +57 -68
- package/src/files/images.js +30 -31
- package/src/harness/agent.js +60 -60
- package/src/harness/attribution.js +66 -58
- package/src/harness/checkpoint.js +67 -62
- package/src/harness/history.js +28 -23
- package/src/harness/prompt.js +40 -57
- package/src/harness/provider.js +284 -283
- package/src/harness/types.js +1 -0
- package/src/http.js +90 -72
- package/src/log.js +11 -12
- package/src/mcp.js +398 -374
- package/src/retrieval/embedding.js +228 -240
- package/src/retrieval/retrieval.js +182 -173
- package/src/routes/admin.js +178 -138
- package/src/routes/auth.js +184 -111
- package/src/routes/automations.js +99 -82
- package/src/routes/chats.js +240 -218
- package/src/routes/documents.js +130 -120
- package/src/routes/library.js +43 -46
- package/src/routes/mcp.js +49 -49
- package/src/routes/settings.js +127 -122
- package/src/routes/types.js +1 -0
- package/src/server.js +426 -415
- package/src/store/automations.js +106 -106
- package/src/store/chats.js +217 -242
- package/src/store/documents.js +181 -185
- package/src/store/embeddings.js +52 -54
- package/src/store/index.js +95 -49
- package/src/store/messages.js +55 -80
- package/src/store/schema.js +128 -107
- package/src/store/scope.js +18 -17
- package/src/store/search.js +25 -27
- package/src/store/turns.js +53 -53
- package/src/store/usage.js +343 -269
- package/src/store/users.js +162 -87
- package/src/store/wire.js +50 -41
- package/src/tools/ask_tool.js +68 -68
- package/src/tools/chat_search_tool.js +38 -44
- package/src/tools/context_tool.js +131 -138
- package/src/tools/document_tool.js +73 -78
- package/src/tools/mcp_tool.js +274 -232
- package/src/tools/task_tool.js +53 -50
- package/src/tools/types.js +1 -0
- package/public/panels/connectors.js +0 -184
- package/src/set-password.js +0 -43
package/src/store/automations.js
CHANGED
|
@@ -1,119 +1,119 @@
|
|
|
1
1
|
import { scope, ownerOf } from './scope.js';
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
|
-
|
|
4
3
|
// Scheduled automations and their runs.
|
|
5
4
|
// One area of the Store; see index.js.
|
|
6
|
-
|
|
7
|
-
function automationView(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
// Takes the row as node:sqlite returns it, so callers can map query results straight through.
|
|
6
|
+
function automationView(r) {
|
|
7
|
+
const row = r;
|
|
8
|
+
return {
|
|
9
|
+
id: row.id, userId: row.user_id, chatId: row.chat_id, chatTitle: row.chat_title,
|
|
10
|
+
name: row.name, prompt: row.prompt, cron: row.cron, timezone: row.timezone,
|
|
11
|
+
enabled: Boolean(row.enabled), nextRunAt: row.next_run_at, lastRunAt: row.last_run_at,
|
|
12
|
+
lastStatus: row.last_status, lastResult: row.last_result, source: row.source,
|
|
13
|
+
createdAt: row.created_at, updatedAt: row.updated_at
|
|
14
|
+
};
|
|
15
15
|
}
|
|
16
|
-
|
|
17
16
|
export class AutomationStore {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
db;
|
|
18
|
+
constructor(db) {
|
|
19
|
+
this.db = db;
|
|
20
|
+
}
|
|
21
|
+
claimUnowned(userId) {
|
|
22
|
+
this.db.prepare('UPDATE automations SET user_id = ? WHERE user_id IS NULL').run(userId);
|
|
23
|
+
}
|
|
24
|
+
list(userId) {
|
|
25
|
+
const s = scope(userId, 'a.user_id');
|
|
26
|
+
return this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
26
27
|
WHERE ${s.sql} ORDER BY a.updated_at DESC`).all(...s.params).map(automationView);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
28
|
+
}
|
|
29
|
+
listAll() {
|
|
30
|
+
return this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
31
31
|
ORDER BY a.updated_at DESC`).all().map(automationView);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const row = this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
32
|
+
}
|
|
33
|
+
get(id, userId) {
|
|
34
|
+
const s = scope(userId, 'a.user_id');
|
|
35
|
+
const row = this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
37
36
|
WHERE a.id=? AND ${s.sql}`).get(id, ...s.params);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.db.prepare(`INSERT INTO automations
|
|
37
|
+
return row ? automationView(row) : null;
|
|
38
|
+
}
|
|
39
|
+
create(data, userId) {
|
|
40
|
+
scope(userId);
|
|
41
|
+
const id = randomBytes(12).toString('hex');
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
this.db.prepare(`INSERT INTO automations
|
|
46
44
|
(id,user_id,chat_id,name,prompt,cron,timezone,enabled,next_run_at,source,created_at,updated_at)
|
|
47
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`).run(id,ownerOf(userId),data.chatId,data.name,data.prompt,data.cron,data.timezone,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
45
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`).run(id, ownerOf(userId), data.chatId, data.name, data.prompt, data.cron, data.timezone, data.enabled === false ? 0 : 1, data.nextRunAt, data.source || 'user', now, now);
|
|
46
|
+
return this.get(id, userId);
|
|
47
|
+
}
|
|
48
|
+
update(id, patch, userId) {
|
|
49
|
+
const current = this.get(id, userId);
|
|
50
|
+
if (!current)
|
|
51
|
+
return null;
|
|
52
|
+
const fields = { chatId: 'chat_id', name: 'name', prompt: 'prompt', cron: 'cron', timezone: 'timezone', enabled: 'enabled', nextRunAt: 'next_run_at', lastRunAt: 'last_run_at', lastStatus: 'last_status', lastResult: 'last_result' };
|
|
53
|
+
const sets = ['updated_at=?'];
|
|
54
|
+
const values = [Date.now()];
|
|
55
|
+
for (const [key, col] of Object.entries(fields))
|
|
56
|
+
if (patch[key] !== undefined) {
|
|
57
|
+
sets.push(`${col}=?`);
|
|
58
|
+
values.push(key === 'enabled' ? (patch[key] ? 1 : 0) : patch[key]);
|
|
59
|
+
}
|
|
60
|
+
values.push(id);
|
|
61
|
+
this.db.prepare(`UPDATE automations SET ${sets.join(',')} WHERE id=?`).run(...values);
|
|
62
|
+
return this.get(id, userId);
|
|
63
|
+
}
|
|
64
|
+
delete(id, userId) {
|
|
65
|
+
const s = scope(userId);
|
|
66
|
+
return this.db.prepare(`DELETE FROM automations WHERE id=? AND ${s.sql}`).run(id, ...s.params).changes > 0;
|
|
60
67
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/** Drops every automation that posts into a chat (the chat is going). */
|
|
72
|
-
deleteForChat(chatId) {
|
|
73
|
-
this.db.prepare('DELETE FROM automations WHERE chat_id = ?').run(chatId);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** When the next enabled automation is due, or null when none is. */
|
|
77
|
-
nextDue() {
|
|
78
|
-
return this.db.prepare('SELECT MIN(next_run_at) AS due FROM automations WHERE enabled=1').get()?.due ?? null;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
due(now = Date.now()) {
|
|
82
|
-
return this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
68
|
+
/** Drops every automation that posts into a chat (the chat is going). */
|
|
69
|
+
deleteForChat(chatId) {
|
|
70
|
+
this.db.prepare('DELETE FROM automations WHERE chat_id = ?').run(chatId);
|
|
71
|
+
}
|
|
72
|
+
/** When the next enabled automation is due, or null when none is. */
|
|
73
|
+
nextDue() {
|
|
74
|
+
return this.db.prepare('SELECT MIN(next_run_at) AS due FROM automations WHERE enabled=1').get()?.due ?? null;
|
|
75
|
+
}
|
|
76
|
+
due(now = Date.now()) {
|
|
77
|
+
return this.db.prepare(`SELECT a.*, c.title AS chat_title FROM automations a JOIN chats c ON c.id=a.chat_id
|
|
83
78
|
WHERE a.enabled=1 AND a.next_run_at<=? ORDER BY a.next_run_at`).all(now).map(automationView);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
79
|
+
}
|
|
80
|
+
addRun(automationId, scheduledAt, status = 'queued', triggerType = 'schedule') {
|
|
81
|
+
const id = randomBytes(12).toString('hex');
|
|
82
|
+
this.db.prepare(`INSERT INTO automation_runs(id,automation_id,scheduled_at,status,trigger_type) VALUES(?,?,?,?,?)`)
|
|
83
|
+
.run(id, automationId, scheduledAt, status, triggerType);
|
|
84
|
+
return id;
|
|
85
|
+
}
|
|
86
|
+
updateRun(id, patch) {
|
|
87
|
+
const fields = { status: 'status', startedAt: 'started_at', finishedAt: 'finished_at', result: 'result', error: 'error' };
|
|
88
|
+
const sets = [];
|
|
89
|
+
const values = [];
|
|
90
|
+
for (const [key, col] of Object.entries(fields))
|
|
91
|
+
if (patch[key] !== undefined) {
|
|
92
|
+
sets.push(`${col}=?`);
|
|
93
|
+
values.push(patch[key]);
|
|
94
|
+
}
|
|
95
|
+
if (sets.length)
|
|
96
|
+
this.db.prepare(`UPDATE automation_runs SET ${sets.join(',')} WHERE id=?`).run(...values, id);
|
|
97
|
+
const row = this.db.prepare('SELECT * FROM automation_runs WHERE id=?').get(id);
|
|
98
|
+
const owner = this.db.prepare('SELECT user_id FROM automations WHERE id=?').get(row?.automation_id ?? null)?.user_id ?? null;
|
|
99
|
+
if (row)
|
|
100
|
+
this.update(row.automation_id, {
|
|
101
|
+
lastRunAt: row.started_at || row.scheduled_at, lastStatus: row.status,
|
|
102
|
+
...(row.result !== null ? { lastResult: row.result.slice(0, 4000) } : {})
|
|
103
|
+
}, owner);
|
|
104
|
+
}
|
|
105
|
+
listRuns(automationId, userId, limit = 10) {
|
|
106
|
+
const owned = this.get(automationId, userId);
|
|
107
|
+
if (!owned)
|
|
108
|
+
return null;
|
|
109
|
+
return this.db.prepare('SELECT id,scheduled_at,started_at,finished_at,status,trigger_type,result,error FROM automation_runs WHERE automation_id=? ORDER BY scheduled_at DESC LIMIT ?')
|
|
110
|
+
.all(automationId, Math.min(50, Math.max(1, limit)));
|
|
111
|
+
}
|
|
112
|
+
recoverRuns(now = Date.now()) {
|
|
113
|
+
const rows = this.db.prepare("SELECT id FROM automation_runs WHERE status IN ('queued','running')").all();
|
|
114
|
+
for (const row of rows)
|
|
115
|
+
this.updateRun(row.id, {
|
|
116
|
+
status: 'failed', finishedAt: now, error: 'Server restarted during this run.'
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
119
|
}
|