zubo 0.1.21 → 0.1.23
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/.playwright-mcp/console-2026-02-16T19-06-21-167Z.log +31 -0
- package/README.md +2 -1
- package/dashboard-chat.png +0 -0
- package/dashboard-followups.png +0 -0
- package/dashboard-history.png +0 -0
- package/dashboard-integrations.png +0 -0
- package/dashboard-knowledge-ok.png +0 -0
- package/dashboard-knowledge.png +0 -0
- package/dashboard-notes-add.png +0 -0
- package/dashboard-notes-improved.png +0 -0
- package/dashboard-notes.png +0 -0
- package/dashboard-overview.png +0 -0
- package/dashboard-preferences.png +0 -0
- package/dashboard-settings-fixed.png +0 -0
- package/dashboard-settings.png +0 -0
- package/dashboard-skills-ok.png +0 -0
- package/dashboard-skills.png +0 -0
- package/dashboard-todos-add.png +0 -0
- package/dashboard-todos-improved.png +0 -0
- package/dashboard-todos-item.png +0 -0
- package/dashboard-todos-priority-badge.png +0 -0
- package/dashboard-todos.png +0 -0
- package/dashboard-topics.png +0 -0
- package/docs/ROADMAP.md +12 -49
- package/migrations/024_personal_features.sql +96 -0
- package/package.json +1 -1
- package/site/docs/index.html +11 -0
- package/site/docs/skills.html +107 -0
- package/site/index.html +9 -1
- package/src/agent/context.ts +3 -3
- package/src/agent/delegate.ts +7 -2
- package/src/agent/loop.ts +6 -6
- package/src/agent/prompts.ts +49 -1
- package/src/agent/workflow-executor.ts +5 -1
- package/src/channels/dashboard.html.ts +558 -6
- package/src/channels/webchat.ts +305 -27
- package/src/llm/claude-code.ts +58 -17
- package/src/llm/codex.ts +59 -18
- package/src/start.ts +12 -0
- package/src/tools/builtin/diagnose.ts +19 -5
- package/src/tools/builtin/follow-ups.ts +189 -0
- package/src/tools/builtin/notes.ts +207 -0
- package/src/tools/builtin/preferences.ts +173 -0
- package/src/tools/builtin/todos.ts +270 -0
- package/src/tools/builtin/topics.ts +166 -0
- package/src/tools/mcp-client.ts +8 -0
- package/src/tools/permissions.ts +7 -0
- package/tests/agent/session.test.ts +43 -45
- package/tests/mcp-registry.test.ts +32 -35
- package/tests/personal-features.test.ts +1251 -0
- package/tests/skill-registry.test.ts +1 -7
- package/tests/db/export.test.ts +0 -219
- package/tests/session.test.ts +0 -58
- package/tests/tools/executor.test.ts +0 -150
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[ 127722ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://localhost:57108/api/dashboard/memory:0
|
|
2
|
+
[ 127722ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://localhost:57108/api/dashboard/memory/recent:0
|
|
3
|
+
[ 127722ms] [WARNING] Dashboard API request failed TypeError: Failed to fetch
|
|
4
|
+
at api (http://localhost:57108/:2291:10)
|
|
5
|
+
at loadRecentMemories (http://localhost:57108/:2795:3)
|
|
6
|
+
at loadMemory (http://localhost:57108/:2756:5)
|
|
7
|
+
at showPanel (http://localhost:57108/:2089:26)
|
|
8
|
+
at HTMLAnchorElement.onclick (http://localhost:57108/#status:929:53) @ http://localhost:57108/:2796
|
|
9
|
+
[ 127754ms] TypeError: Failed to fetch
|
|
10
|
+
at api (http://localhost:57108/:2291:10)
|
|
11
|
+
at loadMemory (http://localhost:57108/:2750:3)
|
|
12
|
+
at showPanel (http://localhost:57108/:2089:26)
|
|
13
|
+
at HTMLAnchorElement.onclick (http://localhost:57108/#status:929:53)
|
|
14
|
+
[ 127724ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://localhost:57108/api/dashboard/memory:0
|
|
15
|
+
[ 127754ms] TypeError: Failed to fetch
|
|
16
|
+
at api (http://localhost:57108/:2291:10)
|
|
17
|
+
at loadMemory (http://localhost:57108/:2750:3)
|
|
18
|
+
at showPanel (http://localhost:57108/:2089:26)
|
|
19
|
+
at routeFromHash (http://localhost:57108/:2277:3)
|
|
20
|
+
[ 143412ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://localhost:57108/api/dashboard/skills:0
|
|
21
|
+
[ 143463ms] TypeError: Failed to fetch
|
|
22
|
+
at api (http://localhost:57108/:2291:10)
|
|
23
|
+
at loadSkills (http://localhost:57108/:2818:3)
|
|
24
|
+
at showPanel (http://localhost:57108/:2090:26)
|
|
25
|
+
at HTMLAnchorElement.onclick (http://localhost:57108/#status:932:53)
|
|
26
|
+
[ 143412ms] [ERROR] Failed to load resource: net::ERR_CONNECTION_REFUSED @ http://localhost:57108/api/dashboard/skills:0
|
|
27
|
+
[ 143463ms] TypeError: Failed to fetch
|
|
28
|
+
at api (http://localhost:57108/:2291:10)
|
|
29
|
+
at loadSkills (http://localhost:57108/:2818:3)
|
|
30
|
+
at showPanel (http://localhost:57108/:2090:26)
|
|
31
|
+
at routeFromHash (http://localhost:57108/:2277:3)
|
package/README.md
CHANGED
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
- **Workflows** — Multi-agent pipelines with delegation
|
|
36
36
|
- **Natural language scheduling** — "Every weekday at 9am" just works. Cron jobs, heartbeat, proactive tasks.
|
|
37
37
|
- **Voice** — Speech-to-text (Whisper) and text-to-speech (OpenAI, ElevenLabs)
|
|
38
|
-
- **
|
|
38
|
+
- **Personal tools** — Todos, notes, preferences, topics, and follow-ups — all manageable from the dashboard or via chat
|
|
39
|
+
- **Dashboard** — Built-in web UI with analytics, memory management, personal tools, and settings
|
|
39
40
|
- **Document ingestion** — Upload PDF, DOCX, TXT, CSV, JSON, and more
|
|
40
41
|
- **Budget controls** — Daily/monthly spending limits with per-model cost tracking
|
|
41
42
|
- **100% local** — SQLite database, local vector store. Your data never leaves your machine.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/ROADMAP.md
CHANGED
|
@@ -439,52 +439,15 @@ Shows:
|
|
|
439
439
|
|
|
440
440
|
---
|
|
441
441
|
|
|
442
|
-
##
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
HIGH IMPACT, MEDIUM EFFORT (do second)
|
|
456
|
-
├── Phase 1.3 Failover wrapper ★★★★
|
|
457
|
-
├── Phase 3.1 Skill format + loader ★★★★
|
|
458
|
-
├── Phase 3.3 web-search + url-fetch skills ★★★★
|
|
459
|
-
├── Phase 2.4 WebChat (local HTTP UI) ★★★★
|
|
460
|
-
├── Phase 4.1 Streaming responses ★★★
|
|
461
|
-
└── Phase 4.4 Context window awareness ★★★
|
|
462
|
-
|
|
463
|
-
MEDIUM IMPACT, MEDIUM EFFORT (do third)
|
|
464
|
-
├── Phase 2.2 Discord channel ★★★
|
|
465
|
-
├── Phase 2.3 WhatsApp channel ★★★
|
|
466
|
-
├── Phase 5.1 Webhook inbound ★★★
|
|
467
|
-
├── Phase 6.1 Tool approval / permissions ★★★
|
|
468
|
-
└── Phase 5.3 Daily digest ★★★
|
|
469
|
-
|
|
470
|
-
NICE TO HAVE (do when stable)
|
|
471
|
-
├── Phase 1.4 Ollama auto-discovery ★★
|
|
472
|
-
├── Phase 4.2 Extended thinking ★★
|
|
473
|
-
├── Phase 6.2 Message pairing / auth ★★
|
|
474
|
-
└── Phase 7.2 Web dashboard ★★
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
---
|
|
478
|
-
|
|
479
|
-
## Next Concrete Step
|
|
480
|
-
|
|
481
|
-
**Phase 1.1 + 1.2**: Multi-LLM support. One session of work:
|
|
482
|
-
|
|
483
|
-
1. Create `src/llm/openai-compat.ts` — OpenAI-compatible provider
|
|
484
|
-
2. Create `src/llm/factory.ts` — Provider factory
|
|
485
|
-
3. Update `src/config/schema.ts` — New provider config fields
|
|
486
|
-
4. Update `src/start.ts` — Use factory
|
|
487
|
-
5. Update `src/setup.ts` — Provider selection in wizard
|
|
488
|
-
6. Test with Ollama locally
|
|
489
|
-
|
|
490
|
-
This single change makes Zubo usable with any model, which unlocks everything else.
|
|
442
|
+
## Completed
|
|
443
|
+
|
|
444
|
+
Most phases above are now implemented:
|
|
445
|
+
|
|
446
|
+
- Phase 1 (Multi-LLM) — 11+ providers, failover, smart routing, CLI providers (Codex, Claude Code)
|
|
447
|
+
- Phase 2 (Channels) — Telegram, Discord, Slack, WhatsApp, Signal, Email, WebChat
|
|
448
|
+
- Phase 3 (Skills) — Skill loader, sandboxed execution, community registry, MCP support
|
|
449
|
+
- Phase 4 (Agent) — Streaming, cost tracking, context window awareness, knowledge graph
|
|
450
|
+
- Phase 5 (Automation) — Webhooks, agent-managed cron, daily digests, follow-ups
|
|
451
|
+
- Phase 6 (Security) — Tool permissions (auto/confirm/deny), confirmation tokens, API key auth
|
|
452
|
+
- Phase 7 (Interfaces) — Web dashboard with analytics, memory, skills, settings, and personal tools (todos, notes, preferences, topics, follow-ups)
|
|
453
|
+
- Personal features — Todos, notes, preferences, topics, follow-ups with full CRUD in the dashboard
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
-- Personal agent features: todos, notes, preferences, topics, follow-ups
|
|
2
|
+
|
|
3
|
+
CREATE TABLE IF NOT EXISTS todos (
|
|
4
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5
|
+
title TEXT NOT NULL,
|
|
6
|
+
description TEXT,
|
|
7
|
+
priority TEXT NOT NULL DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high', 'urgent')),
|
|
8
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'done')),
|
|
9
|
+
due_date TEXT,
|
|
10
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
11
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
12
|
+
completed_at TEXT
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_todos_status ON todos(status);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_todos_priority ON todos(priority);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_todos_due ON todos(due_date);
|
|
18
|
+
|
|
19
|
+
CREATE TABLE IF NOT EXISTS notes (
|
|
20
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
+
title TEXT NOT NULL,
|
|
22
|
+
content TEXT NOT NULL,
|
|
23
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
24
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
25
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
26
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
|
|
30
|
+
title,
|
|
31
|
+
content,
|
|
32
|
+
tags,
|
|
33
|
+
content='notes',
|
|
34
|
+
content_rowid='id'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
CREATE TRIGGER IF NOT EXISTS notes_ai AFTER INSERT ON notes BEGIN
|
|
38
|
+
INSERT INTO notes_fts(rowid, title, content, tags)
|
|
39
|
+
VALUES (new.id, new.title, new.content, new.tags);
|
|
40
|
+
END;
|
|
41
|
+
|
|
42
|
+
CREATE TRIGGER IF NOT EXISTS notes_ad AFTER DELETE ON notes BEGIN
|
|
43
|
+
INSERT INTO notes_fts(notes_fts, rowid, title, content, tags)
|
|
44
|
+
VALUES ('delete', old.id, old.title, old.content, old.tags);
|
|
45
|
+
END;
|
|
46
|
+
|
|
47
|
+
CREATE TRIGGER IF NOT EXISTS notes_au AFTER UPDATE ON notes BEGIN
|
|
48
|
+
INSERT INTO notes_fts(notes_fts, rowid, title, content, tags)
|
|
49
|
+
VALUES ('delete', old.id, old.title, old.content, old.tags);
|
|
50
|
+
INSERT INTO notes_fts(rowid, title, content, tags)
|
|
51
|
+
VALUES (new.id, new.title, new.content, new.tags);
|
|
52
|
+
END;
|
|
53
|
+
|
|
54
|
+
-- Upgrade user_preferences from migration 008 (simple key/value)
|
|
55
|
+
-- to the expanded schema with category, confidence, source
|
|
56
|
+
CREATE TABLE IF NOT EXISTS _user_preferences_new (
|
|
57
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
58
|
+
category TEXT NOT NULL DEFAULT 'general',
|
|
59
|
+
key TEXT NOT NULL,
|
|
60
|
+
value TEXT NOT NULL,
|
|
61
|
+
confidence REAL NOT NULL DEFAULT 0.8,
|
|
62
|
+
source TEXT NOT NULL DEFAULT 'inferred',
|
|
63
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
64
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
65
|
+
UNIQUE(category, key)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
INSERT OR IGNORE INTO _user_preferences_new (key, value, updated_at)
|
|
69
|
+
SELECT key, value, updated_at FROM user_preferences;
|
|
70
|
+
|
|
71
|
+
DROP TABLE IF EXISTS user_preferences;
|
|
72
|
+
|
|
73
|
+
ALTER TABLE _user_preferences_new RENAME TO user_preferences;
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_prefs_category ON user_preferences(category);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE IF NOT EXISTS conversation_topics (
|
|
78
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
79
|
+
name TEXT NOT NULL UNIQUE,
|
|
80
|
+
description TEXT,
|
|
81
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived')),
|
|
82
|
+
last_message_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
83
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
CREATE TABLE IF NOT EXISTS follow_ups (
|
|
87
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
88
|
+
context TEXT NOT NULL,
|
|
89
|
+
message TEXT NOT NULL,
|
|
90
|
+
follow_up_at TEXT NOT NULL,
|
|
91
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'sent', 'cancelled')),
|
|
92
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
CREATE INDEX IF NOT EXISTS idx_followups_status ON follow_ups(status);
|
|
96
|
+
CREATE INDEX IF NOT EXISTS idx_followups_time ON follow_ups(follow_up_at);
|
package/package.json
CHANGED
package/site/docs/index.html
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
<a href="/docs/agents">Agents & Workflows</a>
|
|
62
62
|
<a href="/docs/memory">Memory System</a>
|
|
63
63
|
<a href="/docs/skills">Skills</a>
|
|
64
|
+
<a href="/docs/skills#personal-features">Personal Features</a>
|
|
64
65
|
</div>
|
|
65
66
|
</div>
|
|
66
67
|
<div class="docs-sidebar-section">
|
|
@@ -154,6 +155,15 @@
|
|
|
154
155
|
<li><strong>Skill sandboxing</strong> — user-installed skills run in isolated subprocesses with configurable timeouts, preventing runaway code from affecting the main process.</li>
|
|
155
156
|
</ul>
|
|
156
157
|
|
|
158
|
+
<h3>Personal Features</h3>
|
|
159
|
+
<ul>
|
|
160
|
+
<li><strong>Todos</strong> — add, list, complete, update, and remove tasks with priorities (<code>low</code> / <code>medium</code> / <code>high</code>), due dates, and tags. A full task manager inside your agent.</li>
|
|
161
|
+
<li><strong>Notes</strong> — save, search (FTS5), list, update, delete, and pin notes with tags. Fast full-text search across all your notes.</li>
|
|
162
|
+
<li><strong>Preferences</strong> — store user preferences as category/key/value pairs. Preferences are automatically injected into the system prompt so the agent always respects your settings.</li>
|
|
163
|
+
<li><strong>Topics</strong> — create, switch, list, and archive conversation topics. Each topic scopes a separate session, keeping context focused when you juggle multiple projects.</li>
|
|
164
|
+
<li><strong>Follow-ups</strong> — schedule proactive follow-up messages at a specific time or delay. Uses one-shot cron jobs that fire once and auto-delete.</li>
|
|
165
|
+
</ul>
|
|
166
|
+
|
|
157
167
|
<h3>Agents</h3>
|
|
158
168
|
<ul>
|
|
159
169
|
<li><strong>Custom sub-agents</strong> with focused system prompts, restricted tool access, and specialized behavior. Define a “code-reviewer” agent that only has access to file and git tools, or a “researcher” agent that only has web search.</li>
|
|
@@ -640,6 +650,7 @@ zubo start --daemon</code></pre>
|
|
|
640
650
|
<li><a href="/docs/agents"><strong>Agents & Workflows</strong></a> — learn how to create custom sub-agents with focused system prompts and restricted tools, and build multi-agent pipelines with dependency resolution and parallel execution.</li>
|
|
641
651
|
<li><a href="/docs/memory"><strong>Memory System</strong></a> — understand how semantic memory works, how to ingest documents, search your knowledge base, and tune the hybrid search weights.</li>
|
|
642
652
|
<li><a href="/docs/skills"><strong>Skills</strong></a> — write, install, and share single-file TypeScript skills. Learn the skill manifest format, the sandbox environment, and the community registry.</li>
|
|
653
|
+
<li><a href="/docs/skills#personal-features"><strong>Personal Features</strong></a> — built-in tools for todos, notes, preferences, conversation topics, and scheduled follow-ups. Your personal productivity layer, stored locally.</li>
|
|
643
654
|
<li><a href="/docs/channels"><strong>Channel Setup</strong></a> — step-by-step guides for configuring each channel: creating bots, obtaining tokens, setting up webhooks, and configuring allow-lists.</li>
|
|
644
655
|
<li><a href="/docs/conversations"><strong>Conversation History</strong></a> — unified cross-channel history with FTS5 search, dashboard browsing, and API access for searching and analyzing past conversations across all channels.</li>
|
|
645
656
|
<li><a href="/docs/webhooks"><strong>Webhooks</strong></a> — create webhook endpoints for GitHub, Stripe, CI/CD, and any external service. HMAC signature verification, prompt templates with <code>{{payload}}</code> substitution, and dashboard management.</li>
|
package/site/docs/skills.html
CHANGED
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
<a href="/docs/agents">Agents & Workflows</a>
|
|
66
66
|
<a href="/docs/memory">Memory System</a>
|
|
67
67
|
<a href="/docs/skills" class="active">Skills</a>
|
|
68
|
+
<a href="/docs/skills#personal-features">Personal Features</a>
|
|
68
69
|
</div>
|
|
69
70
|
</div>
|
|
70
71
|
<div class="docs-sidebar-section">
|
|
@@ -295,10 +296,116 @@ zubo publish my_skill # Publish your skill to the registry</code></pre>
|
|
|
295
296
|
<tr><td><code>image_generate</code></td><td>Generate images using AI (DALL-E, etc.)</td><td>auto</td></tr>
|
|
296
297
|
<tr><td><code>webhook_manage</code></td><td>Create, list, or remove incoming webhooks</td><td>auto</td></tr>
|
|
297
298
|
<tr><td><code>oauth_manage</code></td><td>Manage OAuth provider connections</td><td>auto</td></tr>
|
|
299
|
+
<tr><td><code>todos</code></td><td>Add, list, complete, update, and remove tasks with priorities, due dates, and tags</td><td>auto</td></tr>
|
|
300
|
+
<tr><td><code>notes</code></td><td>Save, search (FTS5), list, update, delete, and pin notes with tags</td><td>auto</td></tr>
|
|
301
|
+
<tr><td><code>preferences</code></td><td>Set, get, list, and remove user preferences (injected into system prompt)</td><td>auto</td></tr>
|
|
302
|
+
<tr><td><code>topics</code></td><td>Create, switch, list, and archive conversation topics</td><td>auto</td></tr>
|
|
303
|
+
<tr><td><code>follow_ups</code></td><td>Schedule, list, and cancel proactive follow-up messages</td><td>auto</td></tr>
|
|
298
304
|
</tbody>
|
|
299
305
|
</table>
|
|
300
306
|
<p>Tools marked <strong>confirm</strong> require user confirmation before execution. Tools marked <strong>auto</strong> run immediately without prompting.</p>
|
|
301
307
|
|
|
308
|
+
<h2 id="personal-features">Personal Features</h2>
|
|
309
|
+
<p>Built-in tools for personal productivity — todos, notes, preferences, conversation topics, and scheduled follow-ups. These run in the main process (not sandboxed) and store data in your local SQLite database.</p>
|
|
310
|
+
|
|
311
|
+
<h3><code>todos</code></h3>
|
|
312
|
+
<p>A full task manager built into your agent. Add tasks, set priorities and due dates, tag them for organization, and check them off when done.</p>
|
|
313
|
+
<table>
|
|
314
|
+
<thead>
|
|
315
|
+
<tr><th>Action</th><th>Description</th></tr>
|
|
316
|
+
</thead>
|
|
317
|
+
<tbody>
|
|
318
|
+
<tr><td><code>add</code></td><td>Create a new task with an optional priority (<code>low</code>, <code>medium</code>, <code>high</code>), due date, and tags.</td></tr>
|
|
319
|
+
<tr><td><code>list</code></td><td>List tasks, optionally filtered by status, priority, tag, or due date.</td></tr>
|
|
320
|
+
<tr><td><code>complete</code></td><td>Mark a task as done by ID.</td></tr>
|
|
321
|
+
<tr><td><code>update</code></td><td>Update a task's text, priority, due date, or tags.</td></tr>
|
|
322
|
+
<tr><td><code>remove</code></td><td>Delete a task by ID.</td></tr>
|
|
323
|
+
</tbody>
|
|
324
|
+
</table>
|
|
325
|
+
<p><strong>Key parameters:</strong> <code>text</code> (string), <code>priority</code> (<code>"low"</code> | <code>"medium"</code> | <code>"high"</code>), <code>due</code> (date string), <code>tags</code> (comma-separated), <code>id</code> (task ID for update/complete/remove).</p>
|
|
326
|
+
<p><strong>Example:</strong></p>
|
|
327
|
+
<pre><code>"Add a todo: finish the API docs, high priority, due Friday, tag: work"
|
|
328
|
+
"Show my todos tagged work"
|
|
329
|
+
"Complete todo #3"</code></pre>
|
|
330
|
+
|
|
331
|
+
<h3><code>notes</code></h3>
|
|
332
|
+
<p>Save, search, and organize notes with full-text search (FTS5). Pin important notes so they surface first.</p>
|
|
333
|
+
<table>
|
|
334
|
+
<thead>
|
|
335
|
+
<tr><th>Action</th><th>Description</th></tr>
|
|
336
|
+
</thead>
|
|
337
|
+
<tbody>
|
|
338
|
+
<tr><td><code>save</code></td><td>Create a new note with optional title, tags, and pinned status.</td></tr>
|
|
339
|
+
<tr><td><code>search</code></td><td>Full-text search across all notes using FTS5.</td></tr>
|
|
340
|
+
<tr><td><code>list</code></td><td>List all notes, optionally filtered by tag or pinned status.</td></tr>
|
|
341
|
+
<tr><td><code>update</code></td><td>Update a note's content, title, tags, or pinned status.</td></tr>
|
|
342
|
+
<tr><td><code>delete</code></td><td>Delete a note by ID.</td></tr>
|
|
343
|
+
<tr><td><code>pin</code></td><td>Toggle the pinned status of a note.</td></tr>
|
|
344
|
+
</tbody>
|
|
345
|
+
</table>
|
|
346
|
+
<p><strong>Key parameters:</strong> <code>title</code> (string), <code>content</code> (string), <code>tags</code> (comma-separated), <code>pinned</code> (boolean), <code>query</code> (search string), <code>id</code> (note ID).</p>
|
|
347
|
+
<p><strong>Example:</strong></p>
|
|
348
|
+
<pre><code>"Save a note: meeting with design team moved to Thursday 2pm, tag: meetings"
|
|
349
|
+
"Search my notes for API design"
|
|
350
|
+
"Pin note #5"</code></pre>
|
|
351
|
+
|
|
352
|
+
<h3><code>preferences</code></h3>
|
|
353
|
+
<p>Store user preferences as category/key/value pairs. Preferences are automatically injected into the system prompt so the agent always knows your settings.</p>
|
|
354
|
+
<table>
|
|
355
|
+
<thead>
|
|
356
|
+
<tr><th>Action</th><th>Description</th></tr>
|
|
357
|
+
</thead>
|
|
358
|
+
<tbody>
|
|
359
|
+
<tr><td><code>set</code></td><td>Set a preference value for a given category and key.</td></tr>
|
|
360
|
+
<tr><td><code>get</code></td><td>Retrieve a specific preference by category and key.</td></tr>
|
|
361
|
+
<tr><td><code>list</code></td><td>List all preferences, optionally filtered by category.</td></tr>
|
|
362
|
+
<tr><td><code>remove</code></td><td>Delete a preference by category and key.</td></tr>
|
|
363
|
+
</tbody>
|
|
364
|
+
</table>
|
|
365
|
+
<p><strong>Key parameters:</strong> <code>category</code> (string, e.g. <code>"display"</code>, <code>"communication"</code>, <code>"coding"</code>), <code>key</code> (string), <code>value</code> (string).</p>
|
|
366
|
+
<p><strong>Example:</strong></p>
|
|
367
|
+
<pre><code>"Set my preference: coding/language = TypeScript"
|
|
368
|
+
"What are my communication preferences?"
|
|
369
|
+
"Remove preference coding/editor"</code></pre>
|
|
370
|
+
|
|
371
|
+
<h3><code>topics</code></h3>
|
|
372
|
+
<p>Organize conversations into named topics. Each topic scopes a separate session, so context stays focused and you can switch between projects easily.</p>
|
|
373
|
+
<table>
|
|
374
|
+
<thead>
|
|
375
|
+
<tr><th>Action</th><th>Description</th></tr>
|
|
376
|
+
</thead>
|
|
377
|
+
<tbody>
|
|
378
|
+
<tr><td><code>create</code></td><td>Create a new topic with a name and optional description.</td></tr>
|
|
379
|
+
<tr><td><code>switch</code></td><td>Switch the active conversation to a different topic.</td></tr>
|
|
380
|
+
<tr><td><code>list</code></td><td>List all topics, including archived ones.</td></tr>
|
|
381
|
+
<tr><td><code>archive</code></td><td>Archive a topic to keep things tidy without deleting history.</td></tr>
|
|
382
|
+
</tbody>
|
|
383
|
+
</table>
|
|
384
|
+
<p><strong>Key parameters:</strong> <code>name</code> (string), <code>description</code> (string), <code>id</code> (topic ID for switch/archive).</p>
|
|
385
|
+
<p><strong>Example:</strong></p>
|
|
386
|
+
<pre><code>"Create a topic called 'Website Redesign'"
|
|
387
|
+
"Switch to the API project topic"
|
|
388
|
+
"List my topics"
|
|
389
|
+
"Archive the old marketing topic"</code></pre>
|
|
390
|
+
|
|
391
|
+
<h3><code>follow_ups</code></h3>
|
|
392
|
+
<p>Schedule proactive follow-up messages that Zubo sends to you at a specified time. Uses one-shot cron jobs under the hood — the job fires once and auto-deletes.</p>
|
|
393
|
+
<table>
|
|
394
|
+
<thead>
|
|
395
|
+
<tr><th>Action</th><th>Description</th></tr>
|
|
396
|
+
</thead>
|
|
397
|
+
<tbody>
|
|
398
|
+
<tr><td><code>schedule</code></td><td>Schedule a follow-up message for a specific time or delay.</td></tr>
|
|
399
|
+
<tr><td><code>list</code></td><td>List all pending follow-ups.</td></tr>
|
|
400
|
+
<tr><td><code>cancel</code></td><td>Cancel a scheduled follow-up by ID.</td></tr>
|
|
401
|
+
</tbody>
|
|
402
|
+
</table>
|
|
403
|
+
<p><strong>Key parameters:</strong> <code>message</code> (string — what Zubo should say), <code>time</code> (date/time string or natural language like <code>"in 2 hours"</code>, <code>"tomorrow at 9am"</code>), <code>id</code> (follow-up ID for cancel).</p>
|
|
404
|
+
<p><strong>Example:</strong></p>
|
|
405
|
+
<pre><code>"Follow up with me tomorrow at 10am about the deployment"
|
|
406
|
+
"List my pending follow-ups"
|
|
407
|
+
"Cancel follow-up #2"</code></pre>
|
|
408
|
+
|
|
302
409
|
<h2>Legacy Format (SKILL.md)</h2>
|
|
303
410
|
<p>Earlier versions of Zubo used a Markdown-based skill definition file called <code>SKILL.md</code>. This format is still fully supported for backward compatibility:</p>
|
|
304
411
|
<pre><code># weather
|
package/site/index.html
CHANGED
|
@@ -300,7 +300,15 @@
|
|
|
300
300
|
<p>Build your own tools in TypeScript and share them with the community. A sandboxed skill system with scoped secrets, hot-reload, and a public registry.</p>
|
|
301
301
|
</div>
|
|
302
302
|
|
|
303
|
-
<div class="bento-card
|
|
303
|
+
<div class="bento-card tilt-card" data-feature="personal">
|
|
304
|
+
<div class="bento-icon">
|
|
305
|
+
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
|
306
|
+
</div>
|
|
307
|
+
<h3>Personal Features</h3>
|
|
308
|
+
<p>Built-in todos, notes, preferences, conversation topics, and scheduled follow-ups. Your personal productivity layer, stored locally and always in context.</p>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<div class="bento-card tilt-card" data-feature="llm">
|
|
304
312
|
<div class="bento-icon">
|
|
305
313
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="7.5 4.21 12 6.81 16.5 4.21"/><polyline points="7.5 19.79 7.5 14.6 3 12"/><polyline points="21 12 16.5 14.6 16.5 19.79"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
|
|
306
314
|
</div>
|
package/src/agent/context.ts
CHANGED
|
@@ -7,12 +7,12 @@ export interface AgentContext {
|
|
|
7
7
|
messages: LlmMessage[];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function assembleContext(
|
|
10
|
+
export async function assembleContext(
|
|
11
11
|
sessionId: string,
|
|
12
12
|
maxTurns: number = 50,
|
|
13
13
|
memories: string = ""
|
|
14
|
-
): AgentContext {
|
|
14
|
+
): Promise<AgentContext> {
|
|
15
15
|
const messages = loadSession(sessionId, maxTurns);
|
|
16
|
-
const system = buildSystemPrompt(memories);
|
|
16
|
+
const system = await buildSystemPrompt(memories);
|
|
17
17
|
return { system, messages };
|
|
18
18
|
}
|
package/src/agent/delegate.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { LlmProvider } from "../llm/provider";
|
|
2
2
|
import { getAgentDefinition } from "./agents";
|
|
3
3
|
import { agentLoop } from "./loop";
|
|
4
|
+
import { getAllToolDefs } from "../tools/registry";
|
|
4
5
|
import { searchMemory } from "../memory/engine";
|
|
5
6
|
import { getDb } from "../db/connection";
|
|
6
7
|
import { logger } from "../util/logger";
|
|
@@ -107,7 +108,11 @@ export async function delegateToAgent(
|
|
|
107
108
|
"delegate", "delegate_task", "manage_agents",
|
|
108
109
|
"config_update", "secret_set", "secret_delete", "manage_skills",
|
|
109
110
|
]);
|
|
110
|
-
|
|
111
|
+
// Support wildcard "*" — gives the agent all non-forbidden tools dynamically
|
|
112
|
+
const baseTools = agent.tools.includes("*")
|
|
113
|
+
? getAllToolDefs().map(t => t.name)
|
|
114
|
+
: agent.tools;
|
|
115
|
+
const filteredTools = baseTools.filter(
|
|
111
116
|
(t) => !FORBIDDEN_DELEGATION_TOOLS.has(t)
|
|
112
117
|
);
|
|
113
118
|
|
|
@@ -115,7 +120,7 @@ export async function delegateToAgent(
|
|
|
115
120
|
try {
|
|
116
121
|
const result = await agentLoop(llm, sessionId, task, {
|
|
117
122
|
systemPromptOverride: systemPrompt,
|
|
118
|
-
allowedTools: filteredTools
|
|
123
|
+
allowedTools: filteredTools,
|
|
119
124
|
maxRounds: 8,
|
|
120
125
|
memories,
|
|
121
126
|
});
|
package/src/agent/loop.ts
CHANGED
|
@@ -39,12 +39,12 @@ function resolveOptions(memoriesOrOptions: string | AgentLoopOptions): AgentLoop
|
|
|
39
39
|
: memoriesOrOptions;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/** Detect
|
|
42
|
+
/** Detect standalone greetings that don't need tool definitions in context. */
|
|
43
43
|
function looksConversational(text: string): boolean {
|
|
44
|
-
const t = text.trim().toLowerCase();
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
return
|
|
44
|
+
const t = text.trim().toLowerCase().replace(/[!?.,:;]+$/g, "");
|
|
45
|
+
// Only match messages that are PURELY a greeting — no follow-up request
|
|
46
|
+
const standaloneGreetings = /^(h(ello|i|ey|owdy|ola)|yo|sup|good\s*(morning|afternoon|evening|night)|what'?s\s*up|gm|thanks|thank\s*you|ok(ay)?|bye|see\s*ya|cool|nice|wow|lol|haha)$/;
|
|
47
|
+
return standaloneGreetings.test(t);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async function prepareLoop(
|
|
@@ -79,7 +79,7 @@ async function prepareLoop(
|
|
|
79
79
|
// Assemble context (uses static import — no dynamic import overhead)
|
|
80
80
|
const ctx = options.systemPromptOverride
|
|
81
81
|
? { system: options.systemPromptOverride, messages: loadSession(sessionId, 50) }
|
|
82
|
-
: assembleContext(sessionId, 50, fullMemories);
|
|
82
|
+
: await assembleContext(sessionId, 50, fullMemories);
|
|
83
83
|
|
|
84
84
|
const messages = compactMessages(ctx.messages, llm.contextWindow);
|
|
85
85
|
|
package/src/agent/prompts.ts
CHANGED
|
@@ -42,13 +42,39 @@ const DEFAULT_PERSONALITY = `You are Zubo, a personal AI agent. You are friendly
|
|
|
42
42
|
- Use cron_create for recurring tasks. Natural language works: "every weekday at 9am", "every monday at noon".
|
|
43
43
|
- Use reminder_set for one-time reminders: "in 30 minutes", "in 2 hours".
|
|
44
44
|
- When the user says "remind me", "ping me", "follow up" — create a reminder.
|
|
45
|
+
- Use follow_ups to schedule check-ins: "follow up about the dentist tomorrow", "check in about the project in 3 days".
|
|
46
|
+
|
|
47
|
+
## Todos & notes
|
|
48
|
+
|
|
49
|
+
- Use the todos tool when the user asks to track tasks, create to-do lists, or manage action items. "Add buy groceries to my list" → todos with action "add".
|
|
50
|
+
- Use the notes tool to save, search, and organize information. "Save this recipe" → notes with action "save". "Find my notes about React" → notes with action "search".
|
|
51
|
+
- When the user mentions something they need to do, proactively offer to add it as a todo.
|
|
52
|
+
|
|
53
|
+
## Preferences
|
|
54
|
+
|
|
55
|
+
- Use the preferences tool to store and recall user preferences. When the user says "I prefer morning meetings" or "I always use TypeScript" — save it immediately with the preferences tool (action "set").
|
|
56
|
+
- Before making choices on behalf of the user, check their preferences first (action "get" or "list").
|
|
57
|
+
- Preferences persist across sessions and channels. They're different from memory — preferences are structured key-value pairs about how the user likes things done.
|
|
58
|
+
|
|
59
|
+
## Conversation topics
|
|
60
|
+
|
|
61
|
+
- Use the topics tool when the user wants to organize conversations. "Let's start a new thread about the trip" → topics with action "create" then "switch".
|
|
62
|
+
- When switching topics, the conversation context changes. Each topic maintains its own conversation history.
|
|
63
|
+
- List topics to show the user what threads they have going.
|
|
45
64
|
|
|
46
65
|
## Delegation
|
|
47
66
|
|
|
48
67
|
- Create specialized sub-agents with manage_agents for recurring task types (research, code review, data analysis).
|
|
49
68
|
- Delegate tasks using the delegate tool. Sub-agents share your memory but have scoped tools.
|
|
69
|
+
- When creating agents, use "*" in the tools list to give them access to all available tools dynamically (including skills and MCP tools installed later).
|
|
50
70
|
- Keep the main conversation lightweight. Offload complex, self-contained tasks.
|
|
51
71
|
|
|
72
|
+
## MCP (external tool servers)
|
|
73
|
+
|
|
74
|
+
- You may have tools from MCP (Model Context Protocol) servers. These are prefixed with the server name, e.g. "servername__toolname".
|
|
75
|
+
- MCP tools work like any other tool — just call them. Check your available tools list for MCP-provided capabilities.
|
|
76
|
+
- If an MCP tool fails, it may mean the server is disconnected. Let the user know.
|
|
77
|
+
|
|
52
78
|
## Connecting services (integrations)
|
|
53
79
|
|
|
54
80
|
Service integrations and LLM providers are COMPLETELY SEPARATE concepts. Never confuse them:
|
|
@@ -115,7 +141,7 @@ function loadPersonality(): string {
|
|
|
115
141
|
return DEFAULT_PERSONALITY;
|
|
116
142
|
}
|
|
117
143
|
|
|
118
|
-
export function buildSystemPrompt(memories: string = ""): string {
|
|
144
|
+
export async function buildSystemPrompt(memories: string = ""): Promise<string> {
|
|
119
145
|
const now = new Date().toISOString();
|
|
120
146
|
const personality = loadPersonality();
|
|
121
147
|
|
|
@@ -123,6 +149,28 @@ export function buildSystemPrompt(memories: string = ""): string {
|
|
|
123
149
|
|
|
124
150
|
Current time: ${now}`;
|
|
125
151
|
|
|
152
|
+
// Inject user preferences
|
|
153
|
+
try {
|
|
154
|
+
const { loadPreferencesContext } = await import("../tools/builtin/preferences");
|
|
155
|
+
const prefsContext = await loadPreferencesContext();
|
|
156
|
+
if (prefsContext) {
|
|
157
|
+
prompt += `\n\n${prefsContext}`;
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
// preferences module may not be available yet
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Inject active topic
|
|
164
|
+
try {
|
|
165
|
+
const { getActiveTopic } = await import("../tools/builtin/topics");
|
|
166
|
+
const topic = getActiveTopic();
|
|
167
|
+
if (topic) {
|
|
168
|
+
prompt += `\n\nActive conversation topic: "${topic}"`;
|
|
169
|
+
}
|
|
170
|
+
} catch {
|
|
171
|
+
// topics module may not be available yet
|
|
172
|
+
}
|
|
173
|
+
|
|
126
174
|
if (memories) {
|
|
127
175
|
prompt += `\n\n## Relevant memories
|
|
128
176
|
<memory-data>
|
|
@@ -3,6 +3,7 @@ import type { WorkflowDefinition, WorkflowStep } from "./workflow";
|
|
|
3
3
|
import { getWorkflowDefinition } from "./workflow";
|
|
4
4
|
import { delegateToAgent } from "./delegate";
|
|
5
5
|
import { agentLoop } from "./loop";
|
|
6
|
+
import { getAllToolDefs } from "../tools/registry";
|
|
6
7
|
import { getDb } from "../db/connection";
|
|
7
8
|
import { logger } from "../util/logger";
|
|
8
9
|
|
|
@@ -158,7 +159,10 @@ async function executeStep(
|
|
|
158
159
|
try {
|
|
159
160
|
if (step.agent === "main") {
|
|
160
161
|
const sessionId = `workflow:${executionId}:${step.name}`;
|
|
161
|
-
const result = await agentLoop(llm, sessionId, task, {
|
|
162
|
+
const result = await agentLoop(llm, sessionId, task, {
|
|
163
|
+
maxRounds: 8,
|
|
164
|
+
allowedTools: getAllToolDefs().map(t => t.name),
|
|
165
|
+
});
|
|
162
166
|
output = result.reply;
|
|
163
167
|
} else {
|
|
164
168
|
output = await delegateToAgent(llm, step.agent, task);
|