@stevederico/dotbot 0.16.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +380 -0
  3. package/bin/dotbot.js +461 -0
  4. package/core/agent.js +779 -0
  5. package/core/compaction.js +261 -0
  6. package/core/cron_handler.js +262 -0
  7. package/core/events.js +229 -0
  8. package/core/failover.js +193 -0
  9. package/core/gptoss_tool_parser.js +173 -0
  10. package/core/init.js +154 -0
  11. package/core/normalize.js +324 -0
  12. package/core/trigger_handler.js +148 -0
  13. package/docs/core.md +103 -0
  14. package/docs/protected-files.md +59 -0
  15. package/examples/sqlite-session-example.js +69 -0
  16. package/index.js +341 -0
  17. package/observer/index.js +164 -0
  18. package/package.json +42 -0
  19. package/storage/CronStore.js +145 -0
  20. package/storage/EventStore.js +71 -0
  21. package/storage/MemoryStore.js +175 -0
  22. package/storage/MongoAdapter.js +291 -0
  23. package/storage/MongoCronAdapter.js +347 -0
  24. package/storage/MongoTaskAdapter.js +242 -0
  25. package/storage/MongoTriggerAdapter.js +158 -0
  26. package/storage/SQLiteAdapter.js +382 -0
  27. package/storage/SQLiteCronAdapter.js +562 -0
  28. package/storage/SQLiteEventStore.js +300 -0
  29. package/storage/SQLiteMemoryAdapter.js +240 -0
  30. package/storage/SQLiteTaskAdapter.js +419 -0
  31. package/storage/SQLiteTriggerAdapter.js +262 -0
  32. package/storage/SessionStore.js +149 -0
  33. package/storage/TaskStore.js +100 -0
  34. package/storage/TriggerStore.js +90 -0
  35. package/storage/cron_constants.js +48 -0
  36. package/storage/index.js +21 -0
  37. package/tools/appgen.js +311 -0
  38. package/tools/browser.js +634 -0
  39. package/tools/code.js +101 -0
  40. package/tools/events.js +145 -0
  41. package/tools/files.js +201 -0
  42. package/tools/images.js +253 -0
  43. package/tools/index.js +97 -0
  44. package/tools/jobs.js +159 -0
  45. package/tools/memory.js +332 -0
  46. package/tools/messages.js +135 -0
  47. package/tools/notify.js +42 -0
  48. package/tools/tasks.js +404 -0
  49. package/tools/triggers.js +159 -0
  50. package/tools/weather.js +82 -0
  51. package/tools/web.js +283 -0
  52. package/utils/providers.js +136 -0
@@ -0,0 +1,149 @@
1
+ /**
2
+ * SessionStore Interface
3
+ *
4
+ * Abstract interface for session storage backends. Implementations must provide
5
+ * all methods defined here.
6
+ */
7
+ export class SessionStore {
8
+ /**
9
+ * Initialize the session store
10
+ *
11
+ * @param {Object} options - Store-specific initialization options
12
+ * @param {Function} [options.prefsFetcher] - Async function (userId) => { agentName, agentPersonality }
13
+ * @param {Function} [options.systemPromptBuilder] - Function ({ agentName, agentPersonality }) => string
14
+ * @param {Function} [options.heartbeatEnsurer] - Async function (userId) => Promise<Object|null>
15
+ */
16
+ async init(options = {}) {
17
+ throw new Error('SessionStore.init() must be implemented');
18
+ }
19
+
20
+ /**
21
+ * Create a new session for a user
22
+ *
23
+ * @param {string} owner - User ID who owns this session
24
+ * @param {string} [model] - Initial model name
25
+ * @param {string} [provider] - AI provider ID
26
+ * @returns {Promise<Object>} Newly created session document
27
+ */
28
+ async createSession(owner, model, provider) {
29
+ throw new Error('SessionStore.createSession() must be implemented');
30
+ }
31
+
32
+ /**
33
+ * Get a session by its UUID, verifying ownership
34
+ *
35
+ * @param {string} sessionId - Session UUID
36
+ * @param {string} owner - User ID (for ownership verification)
37
+ * @returns {Promise<Object|null>} Session document or null
38
+ */
39
+ async getSession(sessionId, owner) {
40
+ throw new Error('SessionStore.getSession() must be implemented');
41
+ }
42
+
43
+ /**
44
+ * Get a session by ID without ownership check (for internal/cron use)
45
+ *
46
+ * @param {string} sessionId - Session UUID
47
+ * @returns {Promise<Object|null>} Session document or null
48
+ */
49
+ async getSessionInternal(sessionId) {
50
+ throw new Error('SessionStore.getSessionInternal() must be implemented');
51
+ }
52
+
53
+ /**
54
+ * Get the most recent session for a user, or create one if none exist
55
+ *
56
+ * @param {string} owner - User ID
57
+ * @returns {Promise<Object>} Session document
58
+ */
59
+ async getOrCreateDefaultSession(owner) {
60
+ throw new Error('SessionStore.getOrCreateDefaultSession() must be implemented');
61
+ }
62
+
63
+ /**
64
+ * Save messages back to storage after agent loop
65
+ *
66
+ * @param {string} sessionId - Session UUID
67
+ * @param {Array} messages - Full conversation history
68
+ * @param {string} model - Current model name
69
+ * @param {string} [provider] - AI provider ID
70
+ */
71
+ async saveSession(sessionId, messages, model, provider) {
72
+ throw new Error('SessionStore.saveSession() must be implemented');
73
+ }
74
+
75
+ /**
76
+ * Add a single message to a session and persist
77
+ *
78
+ * @param {string} sessionId - Session UUID
79
+ * @param {Object} message - Message object with role and content
80
+ * @returns {Promise<Object>} Updated session
81
+ */
82
+ async addMessage(sessionId, message) {
83
+ throw new Error('SessionStore.addMessage() must be implemented');
84
+ }
85
+
86
+ /**
87
+ * Set the model for a session
88
+ *
89
+ * @param {string} sessionId - Session UUID
90
+ * @param {string} model - Model name
91
+ */
92
+ async setModel(sessionId, model) {
93
+ throw new Error('SessionStore.setModel() must be implemented');
94
+ }
95
+
96
+ /**
97
+ * Set the AI provider for a session
98
+ *
99
+ * @param {string} sessionId - Session UUID
100
+ * @param {string} provider - Provider ID
101
+ */
102
+ async setProvider(sessionId, provider) {
103
+ throw new Error('SessionStore.setProvider() must be implemented');
104
+ }
105
+
106
+ /**
107
+ * Clear a session's conversation history (keeps system prompt)
108
+ *
109
+ * @param {string} sessionId - Session UUID
110
+ */
111
+ async clearSession(sessionId) {
112
+ throw new Error('SessionStore.clearSession() must be implemented');
113
+ }
114
+
115
+ /**
116
+ * List all sessions for a user with summary info
117
+ *
118
+ * @param {string} owner - User ID
119
+ * @returns {Promise<Array>} Session summaries sorted by last update
120
+ */
121
+ async listSessions(owner) {
122
+ throw new Error('SessionStore.listSessions() must be implemented');
123
+ }
124
+
125
+ /**
126
+ * Delete a session by ID, verifying ownership
127
+ *
128
+ * @param {string} sessionId - Session UUID
129
+ * @param {string} owner - User ID (for ownership verification)
130
+ * @returns {Promise<any>} Delete result
131
+ */
132
+ async deleteSession(sessionId, owner) {
133
+ throw new Error('SessionStore.deleteSession() must be implemented');
134
+ }
135
+
136
+ /**
137
+ * Trim messages if conversation is too long
138
+ *
139
+ * @param {Array} messages - Full message array
140
+ * @param {number} [maxMessages] - Maximum messages to keep
141
+ * @returns {Array} Trimmed message array
142
+ */
143
+ trimMessages(messages, maxMessages = 40) {
144
+ if (messages.length <= maxMessages) return messages;
145
+ const system = messages[0];
146
+ const recent = messages.slice(-(maxMessages - 1));
147
+ return [system, ...recent];
148
+ }
149
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * TaskStore Interface
3
+ *
4
+ * Abstract interface for task storage. Implementations must provide
5
+ * all methods defined here.
6
+ */
7
+ export class TaskStore {
8
+ /**
9
+ * Initialize the task store
10
+ *
11
+ * @param {Object} db - Database instance (implementation-specific)
12
+ * @param {Object} options - Store-specific initialization options
13
+ */
14
+ async init(db, options = {}) {
15
+ throw new Error('TaskStore.init() must be implemented');
16
+ }
17
+
18
+ /**
19
+ * Create a new task
20
+ *
21
+ * @param {Object} params
22
+ * @param {string} params.userId - Owner user ID
23
+ * @param {string} params.description - Task description
24
+ * @param {Array<string|Object>} params.steps - Array of step descriptions or step objects
25
+ * @param {string} [params.category] - Category (e.g., fitness, learning, productivity)
26
+ * @param {string} [params.priority] - Priority: low, medium, high
27
+ * @param {string} [params.deadline] - ISO 8601 deadline
28
+ * @param {string} [params.mode] - Execution mode: manual or auto
29
+ * @returns {Promise<Object>} Created task document
30
+ */
31
+ async createTask({ userId, description, steps, category, priority, deadline, mode }) {
32
+ throw new Error('TaskStore.createTask() must be implemented');
33
+ }
34
+
35
+ /**
36
+ * Get tasks for a user
37
+ *
38
+ * @param {string} userId - User ID
39
+ * @param {Object} filters - Optional filters (status, category, etc.)
40
+ * @returns {Promise<Array>} Task list
41
+ */
42
+ async getTasks(userId, filters = {}) {
43
+ throw new Error('TaskStore.getTasks() must be implemented');
44
+ }
45
+
46
+ /**
47
+ * Get a single task by ID
48
+ *
49
+ * @param {string} userId - User ID
50
+ * @param {string} taskId - Task document ID
51
+ * @returns {Promise<Object|null>} Task document or null
52
+ */
53
+ async getTask(userId, taskId) {
54
+ throw new Error('TaskStore.getTask() must be implemented');
55
+ }
56
+
57
+ /**
58
+ * Update a task
59
+ *
60
+ * @param {string} userId - User ID
61
+ * @param {string} taskId - Task document ID
62
+ * @param {Object} updates - Fields to update
63
+ * @returns {Promise<Object>} Update result
64
+ */
65
+ async updateTask(userId, taskId, updates) {
66
+ throw new Error('TaskStore.updateTask() must be implemented');
67
+ }
68
+
69
+ /**
70
+ * Delete a task
71
+ *
72
+ * @param {string} userId - User ID
73
+ * @param {string} taskId - Task document ID
74
+ * @returns {Promise<Object>} Delete result
75
+ */
76
+ async deleteTask(userId, taskId) {
77
+ throw new Error('TaskStore.deleteTask() must be implemented');
78
+ }
79
+
80
+ /**
81
+ * Search tasks by text
82
+ *
83
+ * @param {string} userId - User ID
84
+ * @param {string} query - Search query
85
+ * @returns {Promise<Array>} Matching tasks
86
+ */
87
+ async searchTasks(userId, query) {
88
+ throw new Error('TaskStore.searchTasks() must be implemented');
89
+ }
90
+
91
+ /**
92
+ * Get task statistics
93
+ *
94
+ * @param {string} userId - User ID
95
+ * @returns {Promise<Object>} Stats (total, completed, in_progress, etc.)
96
+ */
97
+ async getTaskStats(userId) {
98
+ throw new Error('TaskStore.getTaskStats() must be implemented');
99
+ }
100
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * TriggerStore Interface
3
+ *
4
+ * Abstract interface for event trigger storage. Implementations must provide
5
+ * all methods defined here.
6
+ */
7
+ export class TriggerStore {
8
+ /**
9
+ * Initialize the trigger store
10
+ *
11
+ * @param {Object} db - Database instance (implementation-specific)
12
+ * @param {Object} options - Store-specific initialization options
13
+ */
14
+ async init(db, options = {}) {
15
+ throw new Error('TriggerStore.init() must be implemented');
16
+ }
17
+
18
+ /**
19
+ * Create an event trigger
20
+ *
21
+ * @param {Object} params
22
+ * @param {string} params.userId - Owner user ID
23
+ * @param {string} params.eventType - Event type to trigger on
24
+ * @param {string} params.prompt - Prompt to inject when event fires
25
+ * @param {number} [params.cooldownMs] - Cooldown period in milliseconds
26
+ * @param {Object} [params.metadata] - Additional metadata (e.g., appName for app_opened events)
27
+ * @param {boolean} [params.enabled] - Whether trigger is enabled (default: true)
28
+ * @returns {Promise<Object>} Created trigger document
29
+ */
30
+ async createTrigger({ userId, eventType, prompt, cooldownMs, metadata, enabled }) {
31
+ throw new Error('TriggerStore.createTrigger() must be implemented');
32
+ }
33
+
34
+ /**
35
+ * List triggers for a user
36
+ *
37
+ * @param {string} userId - User ID
38
+ * @param {Object} filters - Optional filters (enabled, eventType, etc.)
39
+ * @returns {Promise<Array>} Trigger list
40
+ */
41
+ async listTriggers(userId, filters = {}) {
42
+ throw new Error('TriggerStore.listTriggers() must be implemented');
43
+ }
44
+
45
+ /**
46
+ * Find enabled triggers matching userId and eventType, filtering out
47
+ * those still within cooldown period
48
+ *
49
+ * @param {string} userId - User ID
50
+ * @param {string} eventType - Event type to match
51
+ * @param {Object} metadata - Event metadata for matching (e.g., { appName: 'Mail' })
52
+ * @returns {Promise<Array>} Matching trigger documents
53
+ */
54
+ async findMatchingTriggers(userId, eventType, metadata = {}) {
55
+ throw new Error('TriggerStore.findMatchingTriggers() must be implemented');
56
+ }
57
+
58
+ /**
59
+ * Toggle a trigger on/off
60
+ *
61
+ * @param {string} userId - User ID
62
+ * @param {string} triggerId - Trigger document ID
63
+ * @param {boolean} enabled - Whether to enable or disable
64
+ * @returns {Promise<Object>} Update result
65
+ */
66
+ async toggleTrigger(userId, triggerId, enabled) {
67
+ throw new Error('TriggerStore.toggleTrigger() must be implemented');
68
+ }
69
+
70
+ /**
71
+ * Delete a trigger
72
+ *
73
+ * @param {string} userId - User ID
74
+ * @param {string} triggerId - Trigger document ID
75
+ * @returns {Promise<Object>} Delete result
76
+ */
77
+ async deleteTrigger(userId, triggerId) {
78
+ throw new Error('TriggerStore.deleteTrigger() must be implemented');
79
+ }
80
+
81
+ /**
82
+ * Record that a trigger has fired by updating its lastFiredAt timestamp
83
+ *
84
+ * @param {string} triggerId - Trigger document ID
85
+ * @returns {Promise<void>}
86
+ */
87
+ async markTriggerFired(triggerId) {
88
+ throw new Error('TriggerStore.markTriggerFired() must be implemented');
89
+ }
90
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared constants and utilities for cron stores
3
+ *
4
+ * Used by both MongoCronStore and SQLiteCronStore to ensure consistent
5
+ * behavior across storage backends.
6
+ */
7
+
8
+ /** Heartbeat interval in milliseconds (15 minutes) */
9
+ export const HEARTBEAT_INTERVAL_MS = 15 * 60 * 1000;
10
+
11
+ /** Max heartbeats processed in parallel per poll cycle */
12
+ export const HEARTBEAT_CONCURRENCY = 5;
13
+
14
+ /** The current heartbeat prompt — defines proactive agent behavior */
15
+ export const HEARTBEAT_PROMPT = "Review your active tasks and take action on the highest priority one. Use tools to make real progress — search for information, execute steps, send notifications. If no tasks exist, check memories for pending work.";
16
+
17
+ /**
18
+ * Run an array of async functions with a concurrency limit
19
+ *
20
+ * @param {Array<Function>} fns - Async functions to execute
21
+ * @param {number} limit - Max concurrent executions
22
+ */
23
+ export async function runWithConcurrency(fns, limit) {
24
+ const executing = new Set();
25
+ for (const fn of fns) {
26
+ const p = fn().finally(() => executing.delete(p));
27
+ executing.add(p);
28
+ if (executing.size >= limit) {
29
+ await Promise.race(executing);
30
+ }
31
+ }
32
+ await Promise.all(executing);
33
+ }
34
+
35
+ /**
36
+ * Parse a human-friendly interval string to milliseconds
37
+ *
38
+ * @param {string} str - Interval string e.g. "5m", "2h", "1d", "1w"
39
+ * @returns {number|null} Milliseconds or null if invalid
40
+ */
41
+ export function parseInterval(str) {
42
+ const match = str.match(/^(\d+)\s*(s|m|h|d|w)$/i);
43
+ if (!match) return null;
44
+ const num = parseInt(match[1]);
45
+ const unit = match[2].toLowerCase();
46
+ const multipliers = { s: 1000, m: 60000, h: 3600000, d: 86400000, w: 604800000 };
47
+ return num * multipliers[unit];
48
+ }
@@ -0,0 +1,21 @@
1
+ export { SessionStore } from './SessionStore.js';
2
+ export { MongoSessionStore, defaultSystemPrompt } from './MongoAdapter.js';
3
+ export { SQLiteSessionStore } from './SQLiteAdapter.js';
4
+ export { MemorySessionStore } from './MemoryStore.js';
5
+ export { CronStore } from './CronStore.js';
6
+ export { MongoCronStore, parseInterval, HEARTBEAT_INTERVAL_MS, HEARTBEAT_PROMPT } from './MongoCronAdapter.js';
7
+ export { SQLiteCronStore } from './SQLiteCronAdapter.js';
8
+ export { TaskStore } from './TaskStore.js';
9
+ export { MongoTaskStore } from './MongoTaskAdapter.js';
10
+ export { SQLiteTaskStore } from './SQLiteTaskAdapter.js';
11
+ // Backwards compatibility aliases
12
+ export { TaskStore as GoalStore } from './TaskStore.js';
13
+ export { MongoTaskStore as MongoGoalStore } from './MongoTaskAdapter.js';
14
+ export { SQLiteTaskStore as SQLiteGoalStore } from './SQLiteTaskAdapter.js';
15
+ export { TriggerStore } from './TriggerStore.js';
16
+ export { MongoTriggerStore } from './MongoTriggerAdapter.js';
17
+ export { SQLiteTriggerStore } from './SQLiteTriggerAdapter.js';
18
+ export { SQLiteMemoryStore } from './SQLiteMemoryAdapter.js';
19
+ export { EventStore } from './EventStore.js';
20
+ export { SQLiteEventStore } from './SQLiteEventStore.js';
21
+ export * from './cron_constants.js';