@stevederico/dotbot 0.27.0 → 0.29.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/observer/index.js DELETED
@@ -1,164 +0,0 @@
1
- /**
2
- * Browser Observer — in-memory snapshot store and agent tool.
3
- *
4
- * The frontend pushes structured browser-state snapshots via POST /api/agent/observer.
5
- * The agent reads the latest snapshot via the `browser_observe` tool to understand
6
- * what the user is currently doing in the browser.
7
- */
8
-
9
- const SNAPSHOT_TTL_MS = 5 * 60 * 1000; // 5 minutes
10
-
11
- /** @type {Map<string, Object>} userID → { ...snapshot, receivedAt } */
12
- const snapshots = new Map();
13
-
14
- /**
15
- * Store the latest browser snapshot for a user.
16
- *
17
- * @param {string} userID - Authenticated user ID
18
- * @param {Object} snapshot - Structured browser state from the frontend
19
- */
20
- export function storeSnapshot(userID, snapshot) {
21
- snapshots.set(userID, { ...snapshot, receivedAt: Date.now() });
22
- }
23
-
24
- /**
25
- * Retrieve the latest snapshot for a user, or null if stale/missing.
26
- *
27
- * @param {string} userID - Authenticated user ID
28
- * @returns {Object|null} Snapshot with receivedAt, or null
29
- */
30
- export function getSnapshot(userID) {
31
- const entry = snapshots.get(userID);
32
- if (!entry) return null;
33
- if (Date.now() - entry.receivedAt > SNAPSHOT_TTL_MS) {
34
- snapshots.delete(userID);
35
- return null;
36
- }
37
- return entry;
38
- }
39
-
40
- /**
41
- * Remove a user's snapshot (cleanup on logout, etc.).
42
- *
43
- * @param {string} userID - Authenticated user ID
44
- */
45
- export function clearSnapshot(userID) {
46
- snapshots.delete(userID);
47
- }
48
-
49
- /**
50
- * Format a snapshot into plain-text for LLM consumption.
51
- *
52
- * @param {Object} snap - Snapshot object from the store
53
- * @param {boolean} includeActions - Whether to include recent actions
54
- * @returns {string} Human-readable state description
55
- */
56
- function formatSnapshot(snap, includeActions = true) {
57
- const ageSec = Math.round((Date.now() - snap.timestamp) / 1000);
58
- const lines = [];
59
-
60
- lines.push(`Browser state (${ageSec}s ago):`);
61
- lines.push('');
62
-
63
- // Windows
64
- if (snap.windows && snap.windows.length > 0) {
65
- lines.push(`Open apps (${snap.windowCount || snap.windows.length}):`);
66
- for (const w of snap.windows) {
67
- const focus = w.isFocused ? ' [focused]' : '';
68
- lines.push(` - ${w.app}${w.title ? ': ' + w.title : ''}${focus}`);
69
- }
70
- } else {
71
- lines.push('No apps open.');
72
- }
73
-
74
- if (snap.focusedApp) {
75
- lines.push(`Focused: ${snap.focusedApp}`);
76
- }
77
-
78
- // Docked panel
79
- if (snap.isDottieDocked) {
80
- lines.push('DotBot panel: docked (sidebar)');
81
- }
82
-
83
- // Input bar
84
- if (snap.isInputElevated) {
85
- lines.push(`Input bar: elevated${snap.inputValue ? ' — "' + snap.inputValue + '"' : ''}`);
86
- }
87
-
88
- // Voice
89
- if (snap.voiceState && snap.voiceState !== 'idle') {
90
- lines.push(`Voice: ${snap.voiceState}`);
91
- }
92
-
93
- // Streaming
94
- if (snap.isStreaming) {
95
- lines.push('Agent: streaming response');
96
- }
97
-
98
- // Last tool call
99
- if (snap.lastToolCall) {
100
- const tc = snap.lastToolCall;
101
- const tcAge = Math.round((Date.now() - tc.timestamp) / 1000);
102
- lines.push(`Last tool: ${tc.name} (${tc.status}, ${tcAge}s ago)`);
103
- }
104
-
105
- // Messages
106
- if (snap.messageCount > 0) {
107
- lines.push(`Messages in session: ${snap.messageCount}`);
108
- }
109
-
110
- // Provider/model
111
- if (snap.currentProvider || snap.currentModel) {
112
- lines.push(`Model: ${snap.currentProvider || '?'}/${snap.currentModel || '?'}`);
113
- }
114
-
115
- // Layout + dock
116
- lines.push(`Layout: ${snap.layoutMode || 'desktop'}`);
117
- if (snap.dockApps && snap.dockApps.length > 0) {
118
- lines.push(`Dock: ${snap.dockApps.join(', ')}`);
119
- }
120
-
121
- // Viewport
122
- if (snap.viewport) {
123
- lines.push(`Viewport: ${snap.viewport.width}x${snap.viewport.height}`);
124
- }
125
-
126
- // Recent actions
127
- if (includeActions && snap.recentActions && snap.recentActions.length > 0) {
128
- lines.push('');
129
- lines.push('Recent actions:');
130
- for (const a of snap.recentActions) {
131
- const aAge = Math.round((Date.now() - a.timestamp) / 1000);
132
- const detail = a.app ? ` (${a.app})` : a.tool ? ` (${a.tool})` : '';
133
- lines.push(` - ${a.action}${detail} — ${aAge}s ago`);
134
- }
135
- }
136
-
137
- return lines.join('\n');
138
- }
139
-
140
- /** Agent tool definitions for the browser observer. */
141
- export const observerTools = [
142
- {
143
- name: 'browser_observe',
144
- description:
145
- "See what the user is currently doing in Dottie OS — open apps, focused window, voice state, recent actions. " +
146
- "Call this when you need context about the user's current activity, or when they reference 'this', 'what I'm looking at', or 'current'.",
147
- parameters: {
148
- type: 'object',
149
- properties: {
150
- include_actions: {
151
- type: 'boolean',
152
- description: 'Include recent user actions (default true)',
153
- },
154
- },
155
- },
156
- execute: async (input, signal, context) => {
157
- if (!context?.userID) return 'Error: user context not available';
158
- const snap = getSnapshot(context.userID);
159
- if (!snap) return 'No browser state available. The user may have the tab in the background or just opened the page.';
160
- const includeActions = input.include_actions !== false;
161
- return formatSnapshot(snap, includeActions);
162
- },
163
- },
164
- ];