@stevederico/dotbot 0.16.0 → 0.17.0
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/CHANGELOG.md +14 -0
- package/README.md +10 -10
- package/bin/dotbot.js +39 -18
- package/dotbot.db +0 -0
- package/package.json +1 -1
- package/storage/SQLiteCronAdapter.js +15 -14
- package/storage/SQLiteEventStore.js +2 -3
- package/storage/SQLiteMemoryAdapter.js +2 -3
- package/storage/SQLiteTaskAdapter.js +2 -3
- package/storage/SQLiteTriggerAdapter.js +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
0.17
|
|
2
|
+
|
|
3
|
+
Default model grok-4-1-fast-reasoning
|
|
4
|
+
Show thinking stream
|
|
5
|
+
Remove chat keyword requirement
|
|
6
|
+
Suppress SQLite warning
|
|
7
|
+
Fix store init signatures
|
|
8
|
+
|
|
9
|
+
0.16.1
|
|
10
|
+
|
|
11
|
+
Fix store init signatures
|
|
12
|
+
Fix cron table creation order
|
|
13
|
+
Standardize init(dbPath) API
|
|
14
|
+
|
|
1
15
|
0.16.0
|
|
2
16
|
|
|
3
17
|
Rename to @stevederico/dotbot
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<img src="https://img.shields.io/github/stars/stevederico/dotbot?style=social" alt="GitHub stars">
|
|
13
13
|
</a>
|
|
14
14
|
<a href="https://github.com/stevederico/dotbot">
|
|
15
|
-
<img src="https://img.shields.io/badge/version-0.
|
|
15
|
+
<img src="https://img.shields.io/badge/version-0.17-green" alt="version">
|
|
16
16
|
</a>
|
|
17
17
|
<img src="https://img.shields.io/badge/LOC-11k-orange" alt="Lines of Code">
|
|
18
18
|
</p>
|
|
@@ -40,7 +40,7 @@ A **streaming AI agent** with tool execution, autonomous tasks, and scheduled jo
|
|
|
40
40
|
|
|
41
41
|
**As a CLI:**
|
|
42
42
|
```bash
|
|
43
|
-
dotbot
|
|
43
|
+
dotbot "What's the weather in San Francisco?"
|
|
44
44
|
dotbot repl
|
|
45
45
|
dotbot serve --port 3000
|
|
46
46
|
```
|
|
@@ -64,7 +64,7 @@ npm install -g @stevederico/dotbot
|
|
|
64
64
|
export XAI_API_KEY=xai-...
|
|
65
65
|
|
|
66
66
|
# Chat
|
|
67
|
-
dotbot
|
|
67
|
+
dotbot "Summarize the top 3 AI news stories today"
|
|
68
68
|
|
|
69
69
|
# Interactive REPL
|
|
70
70
|
dotbot repl
|
|
@@ -99,7 +99,7 @@ for await (const event of agent.chat({
|
|
|
99
99
|
sessionId: session.id,
|
|
100
100
|
message: 'Search for the latest AI news',
|
|
101
101
|
provider: 'xai',
|
|
102
|
-
model: 'grok-
|
|
102
|
+
model: 'grok-4-1-fast-reasoning',
|
|
103
103
|
})) {
|
|
104
104
|
if (event.type === 'text_delta') process.stdout.write(event.text);
|
|
105
105
|
}
|
|
@@ -126,7 +126,7 @@ for await (const event of agent.chat({
|
|
|
126
126
|
- **Weather** — Open-Meteo API (no key required)
|
|
127
127
|
|
|
128
128
|
### 🔌 **Multi-Provider Support**
|
|
129
|
-
- **xAI Grok** — grok-
|
|
129
|
+
- **xAI Grok** — grok-4-1-fast-reasoning, with real-time web search and image generation
|
|
130
130
|
- **Anthropic Claude** — claude-sonnet-4-5, claude-opus-4, etc.
|
|
131
131
|
- **OpenAI** — gpt-4o, gpt-4-turbo, etc.
|
|
132
132
|
- **Cerebras** — ultra-fast inference
|
|
@@ -147,16 +147,16 @@ for await (const event of agent.chat({
|
|
|
147
147
|
## CLI Reference
|
|
148
148
|
|
|
149
149
|
```
|
|
150
|
-
dotbot v0.
|
|
150
|
+
dotbot v0.17 — AI agent CLI
|
|
151
151
|
|
|
152
152
|
Usage:
|
|
153
|
-
dotbot
|
|
153
|
+
dotbot "message" Send a message (default)
|
|
154
154
|
dotbot repl Interactive chat session
|
|
155
155
|
dotbot serve [--port N] Start HTTP server (default: 3000)
|
|
156
156
|
|
|
157
157
|
Options:
|
|
158
158
|
--provider, -p AI provider: xai, anthropic, openai, ollama (default: xai)
|
|
159
|
-
--model, -m Model name (default: grok-
|
|
159
|
+
--model, -m Model name (default: grok-4-1-fast-reasoning)
|
|
160
160
|
--db SQLite database path (default: ./dotbot.db)
|
|
161
161
|
--port Server port for 'serve' command
|
|
162
162
|
--help, -h Show help
|
|
@@ -202,7 +202,7 @@ for await (const event of agent.chat({
|
|
|
202
202
|
sessionId: 'sess_123',
|
|
203
203
|
message: 'Hello',
|
|
204
204
|
provider: 'xai',
|
|
205
|
-
model: 'grok-
|
|
205
|
+
model: 'grok-4-1-fast-reasoning',
|
|
206
206
|
signal: abortController.signal, // optional
|
|
207
207
|
context: { userID: 'user123' }, // passed to tools
|
|
208
208
|
})) {
|
|
@@ -260,7 +260,7 @@ await agent.chat({
|
|
|
260
260
|
message: `Create a task to audit our API endpoints.
|
|
261
261
|
Break it into 5 steps, use auto mode.`,
|
|
262
262
|
provider: 'xai',
|
|
263
|
-
model: 'grok-
|
|
263
|
+
model: 'grok-4-1-fast-reasoning',
|
|
264
264
|
context: { userID: 'user-123' },
|
|
265
265
|
});
|
|
266
266
|
// Step 1 runs → schedules Step 2 → ... → task complete
|
package/bin/dotbot.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// Suppress SQLite experimental warning (stable but still flagged in Node 24)
|
|
4
|
+
const originalEmit = process.emit;
|
|
5
|
+
process.emit = function (event, error) {
|
|
6
|
+
if (event === 'warning' && error?.name === 'ExperimentalWarning' && error?.message?.includes('SQLite')) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
return originalEmit.apply(process, arguments);
|
|
10
|
+
};
|
|
11
|
+
|
|
3
12
|
/**
|
|
4
13
|
* dotbot CLI
|
|
5
14
|
*
|
|
@@ -41,7 +50,7 @@ async function loadModules() {
|
|
|
41
50
|
agentLoop = mod.agentLoop;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
|
-
const VERSION = '0.
|
|
53
|
+
const VERSION = '0.17';
|
|
45
54
|
const DEFAULT_PORT = 3000;
|
|
46
55
|
const DEFAULT_DB = './dotbot.db';
|
|
47
56
|
|
|
@@ -53,13 +62,13 @@ function printHelp() {
|
|
|
53
62
|
dotbot v${VERSION} — AI agent CLI
|
|
54
63
|
|
|
55
64
|
Usage:
|
|
56
|
-
dotbot
|
|
65
|
+
dotbot "message" Send a message (default command)
|
|
57
66
|
dotbot repl Interactive chat session
|
|
58
67
|
dotbot serve [--port N] Start HTTP server (default: ${DEFAULT_PORT})
|
|
59
68
|
|
|
60
69
|
Options:
|
|
61
70
|
--provider, -p AI provider: xai, anthropic, openai, ollama (default: xai)
|
|
62
|
-
--model, -m Model name (default: grok-
|
|
71
|
+
--model, -m Model name (default: grok-4-1-fast-reasoning)
|
|
63
72
|
--db SQLite database path (default: ${DEFAULT_DB})
|
|
64
73
|
--port Server port for 'serve' command (default: ${DEFAULT_PORT})
|
|
65
74
|
--help, -h Show this help
|
|
@@ -72,8 +81,9 @@ Environment Variables:
|
|
|
72
81
|
OLLAMA_BASE_URL Base URL for Ollama (default: http://localhost:11434)
|
|
73
82
|
|
|
74
83
|
Examples:
|
|
75
|
-
dotbot
|
|
76
|
-
dotbot
|
|
84
|
+
dotbot "What's the weather in SF?"
|
|
85
|
+
dotbot "Summarize the news" -p anthropic -m claude-sonnet-4-5
|
|
86
|
+
dotbot repl
|
|
77
87
|
dotbot serve --port 8080
|
|
78
88
|
`);
|
|
79
89
|
}
|
|
@@ -89,7 +99,7 @@ function parseCliArgs() {
|
|
|
89
99
|
help: { type: 'boolean', short: 'h', default: false },
|
|
90
100
|
version: { type: 'boolean', short: 'v', default: false },
|
|
91
101
|
provider: { type: 'string', short: 'p', default: 'xai' },
|
|
92
|
-
model: { type: 'string', short: 'm', default: 'grok-
|
|
102
|
+
model: { type: 'string', short: 'm', default: 'grok-4-1-fast-reasoning' },
|
|
93
103
|
db: { type: 'string', default: DEFAULT_DB },
|
|
94
104
|
port: { type: 'string', default: String(DEFAULT_PORT) },
|
|
95
105
|
},
|
|
@@ -150,19 +160,19 @@ async function initStores(dbPath) {
|
|
|
150
160
|
});
|
|
151
161
|
|
|
152
162
|
const cronStore = new stores.SQLiteCronStore();
|
|
153
|
-
await cronStore.init(
|
|
163
|
+
await cronStore.init(dbPath);
|
|
154
164
|
|
|
155
165
|
const taskStore = new stores.SQLiteTaskStore();
|
|
156
|
-
await taskStore.init(
|
|
166
|
+
await taskStore.init(dbPath);
|
|
157
167
|
|
|
158
168
|
const triggerStore = new stores.SQLiteTriggerStore();
|
|
159
|
-
await triggerStore.init(
|
|
169
|
+
await triggerStore.init(dbPath);
|
|
160
170
|
|
|
161
171
|
const memoryStore = new stores.SQLiteMemoryStore();
|
|
162
|
-
await memoryStore.init(
|
|
172
|
+
await memoryStore.init(dbPath);
|
|
163
173
|
|
|
164
174
|
const eventStore = new stores.SQLiteEventStore();
|
|
165
|
-
await eventStore.init(
|
|
175
|
+
await eventStore.init(dbPath);
|
|
166
176
|
|
|
167
177
|
return { sessionStore, cronStore, taskStore, triggerStore, memoryStore, eventStore };
|
|
168
178
|
}
|
|
@@ -198,6 +208,11 @@ async function runChat(message, options) {
|
|
|
198
208
|
context,
|
|
199
209
|
})) {
|
|
200
210
|
switch (event.type) {
|
|
211
|
+
case 'thinking':
|
|
212
|
+
if (event.text) {
|
|
213
|
+
process.stdout.write(`\x1b[2m${event.text}\x1b[0m`);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
201
216
|
case 'text_delta':
|
|
202
217
|
process.stdout.write(event.text);
|
|
203
218
|
break;
|
|
@@ -280,6 +295,11 @@ async function runRepl(options) {
|
|
|
280
295
|
context,
|
|
281
296
|
})) {
|
|
282
297
|
switch (event.type) {
|
|
298
|
+
case 'thinking':
|
|
299
|
+
if (event.text) {
|
|
300
|
+
process.stdout.write(`\x1b[2m${event.text}\x1b[0m`);
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
283
303
|
case 'text_delta':
|
|
284
304
|
process.stdout.write(event.text);
|
|
285
305
|
assistantContent += event.text;
|
|
@@ -432,12 +452,12 @@ async function main() {
|
|
|
432
452
|
|
|
433
453
|
switch (command) {
|
|
434
454
|
case 'chat':
|
|
435
|
-
const
|
|
436
|
-
if (!
|
|
437
|
-
console.error('Usage: dotbot
|
|
455
|
+
const chatMessage = args.positionals.slice(1).join(' ');
|
|
456
|
+
if (!chatMessage) {
|
|
457
|
+
console.error('Usage: dotbot "your message"');
|
|
438
458
|
process.exit(1);
|
|
439
459
|
}
|
|
440
|
-
await runChat(
|
|
460
|
+
await runChat(chatMessage, args);
|
|
441
461
|
break;
|
|
442
462
|
|
|
443
463
|
case 'repl':
|
|
@@ -449,9 +469,10 @@ async function main() {
|
|
|
449
469
|
break;
|
|
450
470
|
|
|
451
471
|
default:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
472
|
+
// Default to chat if not a recognized command
|
|
473
|
+
const message = args.positionals.join(' ');
|
|
474
|
+
await runChat(message, args);
|
|
475
|
+
break;
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
478
|
|
package/dotbot.db
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -34,20 +34,7 @@ export class SQLiteCronStore extends CronStore {
|
|
|
34
34
|
this.db = new DatabaseSync(dbPath);
|
|
35
35
|
this.onTaskFire = options.onTaskFire || null;
|
|
36
36
|
|
|
37
|
-
//
|
|
38
|
-
const cols = this.db.prepare("PRAGMA table_info(cron_tasks)").all();
|
|
39
|
-
if (cols.some(c => c.name === 'goal_id') && !cols.some(c => c.name === 'task_id')) {
|
|
40
|
-
console.log('[cron] migrating goal_id column to task_id...');
|
|
41
|
-
this.db.exec('ALTER TABLE cron_tasks RENAME COLUMN goal_id TO task_id');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Migration: goal_step → task_step task type
|
|
45
|
-
const goalStepCount = this.db.prepare("SELECT COUNT(*) as cnt FROM cron_tasks WHERE name = 'goal_step'").get();
|
|
46
|
-
if (goalStepCount && goalStepCount.cnt > 0) {
|
|
47
|
-
console.log('[cron] migrating goal_step tasks to task_step...');
|
|
48
|
-
this.db.prepare("UPDATE cron_tasks SET name = 'task_step' WHERE name = 'goal_step'").run();
|
|
49
|
-
}
|
|
50
|
-
|
|
37
|
+
// Create table first
|
|
51
38
|
this.db.exec(`
|
|
52
39
|
CREATE TABLE IF NOT EXISTS cron_tasks (
|
|
53
40
|
id TEXT PRIMARY KEY,
|
|
@@ -71,6 +58,20 @@ export class SQLiteCronStore extends CronStore {
|
|
|
71
58
|
CREATE INDEX IF NOT EXISTS idx_cron_session ON cron_tasks(session_id);
|
|
72
59
|
`);
|
|
73
60
|
|
|
61
|
+
// Migration: goal_id → task_id column
|
|
62
|
+
const cols = this.db.prepare("PRAGMA table_info(cron_tasks)").all();
|
|
63
|
+
if (cols.some(c => c.name === 'goal_id') && !cols.some(c => c.name === 'task_id')) {
|
|
64
|
+
console.log('[cron] migrating goal_id column to task_id...');
|
|
65
|
+
this.db.exec('ALTER TABLE cron_tasks RENAME COLUMN goal_id TO task_id');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Migration: goal_step → task_step task type
|
|
69
|
+
const goalStepCount = this.db.prepare("SELECT COUNT(*) as cnt FROM cron_tasks WHERE name = 'goal_step'").get();
|
|
70
|
+
if (goalStepCount && goalStepCount.cnt > 0) {
|
|
71
|
+
console.log('[cron] migrating goal_step tasks to task_step...');
|
|
72
|
+
this.db.prepare("UPDATE cron_tasks SET name = 'task_step' WHERE name = 'goal_step'").run();
|
|
73
|
+
}
|
|
74
|
+
|
|
74
75
|
// Deduplicate existing heartbeats before relying on the unique index
|
|
75
76
|
const dupes = this.db.prepare(`
|
|
76
77
|
SELECT user_id, GROUP_CONCAT(id) as ids, COUNT(*) as cnt
|
|
@@ -17,10 +17,9 @@ export class SQLiteEventStore extends EventStore {
|
|
|
17
17
|
/**
|
|
18
18
|
* Initialize SQLite event store
|
|
19
19
|
*
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {string} config.dbPath - Path to SQLite database file
|
|
20
|
+
* @param {string} dbPath - Path to SQLite database file
|
|
22
21
|
*/
|
|
23
|
-
async init(
|
|
22
|
+
async init(dbPath) {
|
|
24
23
|
this.db = new DatabaseSync(dbPath);
|
|
25
24
|
|
|
26
25
|
this.db.exec(`
|
|
@@ -14,10 +14,9 @@ export class SQLiteMemoryStore {
|
|
|
14
14
|
/**
|
|
15
15
|
* Initialize SQLite memory store
|
|
16
16
|
*
|
|
17
|
-
* @param {
|
|
18
|
-
* @param {string} config.dbPath - Path to SQLite database file
|
|
17
|
+
* @param {string} dbPath - Path to SQLite database file
|
|
19
18
|
*/
|
|
20
|
-
async init(
|
|
19
|
+
async init(dbPath) {
|
|
21
20
|
this.db = new DatabaseSync(dbPath);
|
|
22
21
|
|
|
23
22
|
this.db.exec(`
|
|
@@ -17,10 +17,9 @@ export class SQLiteTaskStore extends TaskStore {
|
|
|
17
17
|
/**
|
|
18
18
|
* Initialize SQLite task store
|
|
19
19
|
*
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {string} config.dbPath - Path to SQLite database file
|
|
20
|
+
* @param {string} dbPath - Path to SQLite database file
|
|
22
21
|
*/
|
|
23
|
-
async init(
|
|
22
|
+
async init(dbPath) {
|
|
24
23
|
this.db = new DatabaseSync(dbPath);
|
|
25
24
|
|
|
26
25
|
// Migration: goals → tasks table
|
|
@@ -17,11 +17,10 @@ export class SQLiteTriggerStore extends TriggerStore {
|
|
|
17
17
|
/**
|
|
18
18
|
* Initialize SQLite trigger store
|
|
19
19
|
*
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {string} config.dbPath - Path to SQLite database file
|
|
20
|
+
* @param {string} dbPath - Path to SQLite database file
|
|
22
21
|
* @param {Object} [options={}] - Reserved for future use
|
|
23
22
|
*/
|
|
24
|
-
async init(
|
|
23
|
+
async init(dbPath, options = {}) {
|
|
25
24
|
this.db = new DatabaseSync(dbPath);
|
|
26
25
|
|
|
27
26
|
this.db.exec(`
|