@dotsetlabs/dotclaw 1.9.0 → 2.1.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 (171) hide show
  1. package/.env.example +6 -0
  2. package/README.md +13 -8
  3. package/config-examples/groups/global/CLAUDE.md +6 -14
  4. package/config-examples/groups/main/CLAUDE.md +8 -39
  5. package/config-examples/runtime.json +16 -122
  6. package/config-examples/tool-policy.json +2 -15
  7. package/container/agent-runner/package-lock.json +258 -0
  8. package/container/agent-runner/package.json +2 -1
  9. package/container/agent-runner/src/agent-config.ts +62 -47
  10. package/container/agent-runner/src/browser.ts +180 -0
  11. package/container/agent-runner/src/container-protocol.ts +4 -9
  12. package/container/agent-runner/src/id.ts +3 -2
  13. package/container/agent-runner/src/index.ts +331 -846
  14. package/container/agent-runner/src/ipc.ts +3 -33
  15. package/container/agent-runner/src/mcp-client.ts +222 -0
  16. package/container/agent-runner/src/mcp-registry.ts +163 -0
  17. package/container/agent-runner/src/skill-loader.ts +375 -0
  18. package/container/agent-runner/src/tools.ts +154 -184
  19. package/container/agent-runner/src/tts.ts +61 -0
  20. package/dist/admin-commands.d.ts.map +1 -1
  21. package/dist/admin-commands.js +12 -0
  22. package/dist/admin-commands.js.map +1 -1
  23. package/dist/agent-execution.d.ts +5 -9
  24. package/dist/agent-execution.d.ts.map +1 -1
  25. package/dist/agent-execution.js +32 -20
  26. package/dist/agent-execution.js.map +1 -1
  27. package/dist/cli.js +61 -16
  28. package/dist/cli.js.map +1 -1
  29. package/dist/config.d.ts +1 -4
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +2 -5
  32. package/dist/config.js.map +1 -1
  33. package/dist/container-protocol.d.ts +4 -9
  34. package/dist/container-protocol.d.ts.map +1 -1
  35. package/dist/container-runner.d.ts.map +1 -1
  36. package/dist/container-runner.js +3 -8
  37. package/dist/container-runner.js.map +1 -1
  38. package/dist/dashboard.d.ts +5 -6
  39. package/dist/dashboard.d.ts.map +1 -1
  40. package/dist/dashboard.js +12 -60
  41. package/dist/dashboard.js.map +1 -1
  42. package/dist/db.d.ts +1 -59
  43. package/dist/db.d.ts.map +1 -1
  44. package/dist/db.js +41 -262
  45. package/dist/db.js.map +1 -1
  46. package/dist/error-messages.d.ts.map +1 -1
  47. package/dist/error-messages.js +5 -1
  48. package/dist/error-messages.js.map +1 -1
  49. package/dist/hooks.d.ts +7 -0
  50. package/dist/hooks.d.ts.map +1 -0
  51. package/dist/hooks.js +93 -0
  52. package/dist/hooks.js.map +1 -0
  53. package/dist/id.d.ts.map +1 -1
  54. package/dist/id.js +2 -1
  55. package/dist/id.js.map +1 -1
  56. package/dist/index.js +673 -2790
  57. package/dist/index.js.map +1 -1
  58. package/dist/ipc-dispatcher.d.ts +26 -0
  59. package/dist/ipc-dispatcher.d.ts.map +1 -0
  60. package/dist/ipc-dispatcher.js +861 -0
  61. package/dist/ipc-dispatcher.js.map +1 -0
  62. package/dist/local-embeddings.d.ts +7 -0
  63. package/dist/local-embeddings.d.ts.map +1 -0
  64. package/dist/local-embeddings.js +60 -0
  65. package/dist/local-embeddings.js.map +1 -0
  66. package/dist/maintenance.d.ts.map +1 -1
  67. package/dist/maintenance.js +3 -7
  68. package/dist/maintenance.js.map +1 -1
  69. package/dist/memory-embeddings.d.ts +1 -1
  70. package/dist/memory-embeddings.d.ts.map +1 -1
  71. package/dist/memory-embeddings.js +59 -31
  72. package/dist/memory-embeddings.js.map +1 -1
  73. package/dist/memory-store.d.ts +0 -10
  74. package/dist/memory-store.d.ts.map +1 -1
  75. package/dist/memory-store.js +11 -27
  76. package/dist/memory-store.js.map +1 -1
  77. package/dist/message-pipeline.d.ts +47 -0
  78. package/dist/message-pipeline.d.ts.map +1 -0
  79. package/dist/message-pipeline.js +652 -0
  80. package/dist/message-pipeline.js.map +1 -0
  81. package/dist/metrics.d.ts +7 -10
  82. package/dist/metrics.d.ts.map +1 -1
  83. package/dist/metrics.js +2 -33
  84. package/dist/metrics.js.map +1 -1
  85. package/dist/model-registry.d.ts +0 -14
  86. package/dist/model-registry.d.ts.map +1 -1
  87. package/dist/model-registry.js +0 -36
  88. package/dist/model-registry.js.map +1 -1
  89. package/dist/paths.d.ts.map +1 -1
  90. package/dist/paths.js +2 -0
  91. package/dist/paths.js.map +1 -1
  92. package/dist/providers/discord/discord-format.d.ts +16 -0
  93. package/dist/providers/discord/discord-format.d.ts.map +1 -0
  94. package/dist/providers/discord/discord-format.js +153 -0
  95. package/dist/providers/discord/discord-format.js.map +1 -0
  96. package/dist/providers/discord/discord-provider.d.ts +50 -0
  97. package/dist/providers/discord/discord-provider.d.ts.map +1 -0
  98. package/dist/providers/discord/discord-provider.js +607 -0
  99. package/dist/providers/discord/discord-provider.js.map +1 -0
  100. package/dist/providers/discord/index.d.ts +4 -0
  101. package/dist/providers/discord/index.d.ts.map +1 -0
  102. package/dist/providers/discord/index.js +3 -0
  103. package/dist/providers/discord/index.js.map +1 -0
  104. package/dist/providers/registry.d.ts +14 -0
  105. package/dist/providers/registry.d.ts.map +1 -0
  106. package/dist/providers/registry.js +49 -0
  107. package/dist/providers/registry.js.map +1 -0
  108. package/dist/providers/telegram/index.d.ts +4 -0
  109. package/dist/providers/telegram/index.d.ts.map +1 -0
  110. package/dist/providers/telegram/index.js +3 -0
  111. package/dist/providers/telegram/index.js.map +1 -0
  112. package/dist/providers/telegram/telegram-format.d.ts +3 -0
  113. package/dist/providers/telegram/telegram-format.d.ts.map +1 -0
  114. package/dist/providers/telegram/telegram-format.js +215 -0
  115. package/dist/providers/telegram/telegram-format.js.map +1 -0
  116. package/dist/providers/telegram/telegram-provider.d.ts +51 -0
  117. package/dist/providers/telegram/telegram-provider.d.ts.map +1 -0
  118. package/dist/providers/telegram/telegram-provider.js +824 -0
  119. package/dist/providers/telegram/telegram-provider.js.map +1 -0
  120. package/dist/providers/types.d.ts +107 -0
  121. package/dist/providers/types.d.ts.map +1 -0
  122. package/dist/providers/types.js +2 -0
  123. package/dist/providers/types.js.map +1 -0
  124. package/dist/request-router.d.ts +9 -31
  125. package/dist/request-router.d.ts.map +1 -1
  126. package/dist/request-router.js +12 -142
  127. package/dist/request-router.js.map +1 -1
  128. package/dist/runtime-config.d.ts +79 -101
  129. package/dist/runtime-config.d.ts.map +1 -1
  130. package/dist/runtime-config.js +140 -208
  131. package/dist/runtime-config.js.map +1 -1
  132. package/dist/skill-manager.d.ts +39 -0
  133. package/dist/skill-manager.d.ts.map +1 -0
  134. package/dist/skill-manager.js +286 -0
  135. package/dist/skill-manager.js.map +1 -0
  136. package/dist/streaming.d.ts +58 -0
  137. package/dist/streaming.d.ts.map +1 -0
  138. package/dist/streaming.js +196 -0
  139. package/dist/streaming.js.map +1 -0
  140. package/dist/task-scheduler.d.ts.map +1 -1
  141. package/dist/task-scheduler.js +11 -45
  142. package/dist/task-scheduler.js.map +1 -1
  143. package/dist/tool-policy.d.ts.map +1 -1
  144. package/dist/tool-policy.js +13 -5
  145. package/dist/tool-policy.js.map +1 -1
  146. package/dist/transcription.d.ts +8 -0
  147. package/dist/transcription.d.ts.map +1 -0
  148. package/dist/transcription.js +174 -0
  149. package/dist/transcription.js.map +1 -0
  150. package/dist/types.d.ts +2 -50
  151. package/dist/types.d.ts.map +1 -1
  152. package/package.json +15 -4
  153. package/scripts/bootstrap.js +40 -4
  154. package/scripts/configure.js +129 -7
  155. package/scripts/doctor.js +30 -4
  156. package/scripts/init.js +13 -6
  157. package/scripts/install.sh +1 -1
  158. package/config-examples/plugin-http.json +0 -18
  159. package/container/skills/agent-browser.md +0 -159
  160. package/dist/background-job-classifier.d.ts +0 -20
  161. package/dist/background-job-classifier.d.ts.map +0 -1
  162. package/dist/background-job-classifier.js +0 -145
  163. package/dist/background-job-classifier.js.map +0 -1
  164. package/dist/background-jobs.d.ts +0 -56
  165. package/dist/background-jobs.d.ts.map +0 -1
  166. package/dist/background-jobs.js +0 -550
  167. package/dist/background-jobs.js.map +0 -1
  168. package/dist/planner-probe.d.ts +0 -14
  169. package/dist/planner-probe.d.ts.map +0 -1
  170. package/dist/planner-probe.js +0 -97
  171. package/dist/planner-probe.js.map +0 -1
@@ -43,26 +43,6 @@ export type AgentRuntimeConfig = {
43
43
  models: {
44
44
  summary: string;
45
45
  memory: string;
46
- planner: string;
47
- responseValidation: string;
48
- toolSummary: string;
49
- };
50
- planner: {
51
- enabled: boolean;
52
- mode: string;
53
- minTokens: number;
54
- triggerRegex: string;
55
- maxOutputTokens: number;
56
- temperature: number;
57
- };
58
- responseValidation: {
59
- enabled: boolean;
60
- maxOutputTokens: number;
61
- temperature: number;
62
- maxRetries: number;
63
- allowToolCalls: boolean;
64
- minPromptTokens: number;
65
- minResponseTokens: number;
66
46
  };
67
47
  tools: {
68
48
  maxToolSteps: number;
@@ -113,6 +93,37 @@ export type AgentRuntimeConfig = {
113
93
  tokensPerMessage: number;
114
94
  tokensPerRequest: number;
115
95
  };
96
+ tts: {
97
+ enabled: boolean;
98
+ model: string;
99
+ baseUrl: string;
100
+ defaultVoice: string;
101
+ };
102
+ browser: {
103
+ enabled: boolean;
104
+ timeoutMs: number;
105
+ screenshotQuality: number;
106
+ };
107
+ mcp: {
108
+ enabled: boolean;
109
+ servers: Array<{
110
+ name: string;
111
+ transport: 'stdio';
112
+ command?: string;
113
+ args?: string[];
114
+ env?: Record<string, string>;
115
+ url?: string;
116
+ }>;
117
+ connectionTimeoutMs: number;
118
+ };
119
+ reasoning: {
120
+ effort: 'off' | 'low' | 'medium' | 'high';
121
+ };
122
+ skills: {
123
+ enabled: boolean;
124
+ maxSkills: number;
125
+ maxSummaryChars: number;
126
+ };
116
127
  };
117
128
  };
118
129
 
@@ -126,8 +137,8 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
126
137
  openrouter: {
127
138
  timeoutMs: 180_000,
128
139
  retry: true,
129
- siteUrl: '',
130
- siteName: ''
140
+ siteUrl: 'https://github.com/dotsetlabs/dotclaw',
141
+ siteName: 'DotClaw'
131
142
  },
132
143
  promptPacks: {
133
144
  enabled: true,
@@ -140,7 +151,7 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
140
151
  compactionTriggerTokens: 20_000,
141
152
  recentContextTokens: 8000,
142
153
  summaryUpdateEveryMessages: 20,
143
- maxOutputTokens: 1024,
154
+ maxOutputTokens: 4096,
144
155
  summaryMaxOutputTokens: 2048,
145
156
  temperature: 0.2,
146
157
  maxContextMessageTokens: 3000
@@ -158,31 +169,11 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
158
169
  extractScheduled: false
159
170
  },
160
171
  models: {
161
- summary: 'openai/gpt-5-nano',
162
- memory: 'openai/gpt-5-mini',
163
- planner: 'openai/gpt-5-nano',
164
- responseValidation: 'openai/gpt-5-nano',
165
- toolSummary: 'openai/gpt-5-nano'
166
- },
167
- planner: {
168
- enabled: true,
169
- mode: 'auto',
170
- minTokens: 800,
171
- triggerRegex: '(plan|steps|roadmap|research|design|architecture|spec|strategy)',
172
- maxOutputTokens: 1024,
173
- temperature: 0.2
174
- },
175
- responseValidation: {
176
- enabled: true,
177
- maxOutputTokens: 1024,
178
- temperature: 0,
179
- maxRetries: 1,
180
- allowToolCalls: false,
181
- minPromptTokens: 400,
182
- minResponseTokens: 160
172
+ summary: 'deepseek/deepseek-v3.2',
173
+ memory: 'deepseek/deepseek-v3.2'
183
174
  },
184
175
  tools: {
185
- maxToolSteps: 96,
176
+ maxToolSteps: 50,
186
177
  outputLimitBytes: 400_000,
187
178
  enableBash: true,
188
179
  enableWebSearch: true,
@@ -222,13 +213,37 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
222
213
  }
223
214
  },
224
215
  ipc: {
225
- requestTimeoutMs: 6000,
216
+ requestTimeoutMs: 30_000,
226
217
  requestPollMs: 150
227
218
  },
228
219
  tokenEstimate: {
229
220
  tokensPerChar: 0.25,
230
221
  tokensPerMessage: 3,
231
222
  tokensPerRequest: 0
223
+ },
224
+ tts: {
225
+ enabled: true,
226
+ model: 'edge-tts',
227
+ baseUrl: '',
228
+ defaultVoice: 'en-US-AriaNeural'
229
+ },
230
+ browser: {
231
+ enabled: true,
232
+ timeoutMs: 30_000,
233
+ screenshotQuality: 80
234
+ },
235
+ mcp: {
236
+ enabled: false,
237
+ servers: [],
238
+ connectionTimeoutMs: 10_000
239
+ },
240
+ reasoning: {
241
+ effort: 'low',
242
+ },
243
+ skills: {
244
+ enabled: true,
245
+ maxSkills: 32,
246
+ maxSummaryChars: 4000,
232
247
  }
233
248
  };
234
249
 
@@ -0,0 +1,180 @@
1
+ import { spawn } from 'child_process';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ const SCREENSHOTS_DIR = '/workspace/group/screenshots';
6
+ const BROWSER_CMD = 'agent-browser';
7
+
8
+ export interface BrowserResult {
9
+ success: boolean;
10
+ title?: string;
11
+ url?: string;
12
+ elements?: unknown[];
13
+ text?: string;
14
+ html?: string;
15
+ result?: unknown;
16
+ path?: string;
17
+ width?: number;
18
+ height?: number;
19
+ error?: string;
20
+ }
21
+
22
+ export class BrowserSession {
23
+ private timeoutMs: number;
24
+ private screenshotQuality: number;
25
+
26
+ constructor(options?: { timeoutMs?: number; screenshotQuality?: number }) {
27
+ this.timeoutMs = options?.timeoutMs ?? 30_000;
28
+ this.screenshotQuality = options?.screenshotQuality ?? 80;
29
+ }
30
+
31
+ private async exec(args: string[]): Promise<string> {
32
+ return new Promise((resolve, reject) => {
33
+ const proc = spawn(BROWSER_CMD, args, {
34
+ timeout: this.timeoutMs,
35
+ stdio: ['pipe', 'pipe', 'pipe'],
36
+ env: { ...process.env, BROWSER_JSON_OUTPUT: '1' }
37
+ });
38
+
39
+ let stdout = '';
40
+ let stderr = '';
41
+
42
+ proc.stdout?.on('data', (data: Buffer) => {
43
+ stdout += data.toString();
44
+ });
45
+ proc.stderr?.on('data', (data: Buffer) => {
46
+ stderr += data.toString();
47
+ });
48
+
49
+ proc.on('close', (code) => {
50
+ if (code !== 0) {
51
+ reject(new Error(stderr.trim() || `Browser command exited with code ${code}`));
52
+ } else {
53
+ resolve(stdout);
54
+ }
55
+ });
56
+
57
+ proc.on('error', (err) => {
58
+ reject(new Error(`Browser command failed: ${err.message}`));
59
+ });
60
+ });
61
+ }
62
+
63
+ private parseOutput(raw: string): unknown {
64
+ try {
65
+ return JSON.parse(raw);
66
+ } catch {
67
+ return { text: raw.trim() };
68
+ }
69
+ }
70
+
71
+ async navigate(url: string): Promise<BrowserResult> {
72
+ try {
73
+ const output = await this.exec(['navigate', url]);
74
+ const parsed = this.parseOutput(output) as Record<string, unknown>;
75
+ return {
76
+ success: true,
77
+ title: parsed.title as string | undefined,
78
+ url: parsed.url as string | undefined
79
+ };
80
+ } catch (err) {
81
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
82
+ }
83
+ }
84
+
85
+ async snapshot(interactive?: boolean): Promise<BrowserResult> {
86
+ try {
87
+ const args = ['snapshot'];
88
+ if (interactive) args.push('--interactive');
89
+ const output = await this.exec(args);
90
+ const parsed = this.parseOutput(output) as Record<string, unknown>;
91
+ return {
92
+ success: true,
93
+ elements: parsed.elements as unknown[] | undefined,
94
+ text: parsed.text as string | undefined
95
+ };
96
+ } catch (err) {
97
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
98
+ }
99
+ }
100
+
101
+ async click(ref: string): Promise<BrowserResult> {
102
+ try {
103
+ const output = await this.exec(['click', ref]);
104
+ const parsed = this.parseOutput(output) as Record<string, unknown>;
105
+ return {
106
+ success: true,
107
+ url: parsed.url as string | undefined
108
+ };
109
+ } catch (err) {
110
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
111
+ }
112
+ }
113
+
114
+ async fill(ref: string, text: string): Promise<BrowserResult> {
115
+ try {
116
+ await this.exec(['fill', ref, text]);
117
+ return { success: true };
118
+ } catch (err) {
119
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
120
+ }
121
+ }
122
+
123
+ async screenshot(fullPage?: boolean): Promise<BrowserResult> {
124
+ try {
125
+ fs.mkdirSync(SCREENSHOTS_DIR, { recursive: true });
126
+ const filename = `screenshot_${Date.now()}.png`;
127
+ const filepath = path.join(SCREENSHOTS_DIR, filename);
128
+ const args = ['screenshot', '--output', filepath, '--quality', String(this.screenshotQuality)];
129
+ if (fullPage) args.push('--full-page');
130
+ await this.exec(args);
131
+ if (!fs.existsSync(filepath)) {
132
+ return { success: false, error: 'Screenshot file not created' };
133
+ }
134
+ return {
135
+ success: true,
136
+ path: filepath
137
+ };
138
+ } catch (err) {
139
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
140
+ }
141
+ }
142
+
143
+ async extract(selector?: string): Promise<BrowserResult> {
144
+ try {
145
+ const args = ['extract'];
146
+ if (selector) args.push('--selector', selector);
147
+ const output = await this.exec(args);
148
+ const parsed = this.parseOutput(output) as Record<string, unknown>;
149
+ return {
150
+ success: true,
151
+ text: parsed.text as string | undefined,
152
+ html: parsed.html as string | undefined
153
+ };
154
+ } catch (err) {
155
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
156
+ }
157
+ }
158
+
159
+ async evaluate(js: string): Promise<BrowserResult> {
160
+ try {
161
+ const output = await this.exec(['evaluate', js]);
162
+ const parsed = this.parseOutput(output);
163
+ return {
164
+ success: true,
165
+ result: parsed
166
+ };
167
+ } catch (err) {
168
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
169
+ }
170
+ }
171
+
172
+ async close(): Promise<BrowserResult> {
173
+ try {
174
+ await this.exec(['close']);
175
+ return { success: true };
176
+ } catch (err) {
177
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
178
+ }
179
+ }
180
+ }
@@ -8,10 +8,7 @@ export interface ContainerInput {
8
8
  chatJid: string;
9
9
  isMain: boolean;
10
10
  isScheduledTask?: boolean;
11
- isBackgroundTask?: boolean;
12
- isBackgroundJob?: boolean;
13
11
  taskId?: string;
14
- jobId?: string;
15
12
  userId?: string;
16
13
  userName?: string;
17
14
  maxToolSteps?: number;
@@ -37,15 +34,14 @@ export interface ContainerInput {
37
34
  behaviorConfig?: Record<string, unknown>;
38
35
  toolPolicy?: Record<string, unknown>;
39
36
  modelOverride?: string;
37
+ modelFallbacks?: string[];
38
+ reasoningEffort?: 'off' | 'low' | 'medium' | 'high';
40
39
  modelContextTokens?: number;
41
40
  modelMaxOutputTokens?: number;
42
41
  modelTemperature?: number;
43
42
  timezone?: string;
44
43
  hostPlatform?: string;
45
- disablePlanner?: boolean;
46
- disableResponseValidation?: boolean;
47
- responseValidationMaxRetries?: number;
48
- disableMemoryExtraction?: boolean;
44
+ streamDir?: string;
49
45
  attachments?: Array<{
50
46
  type: 'photo' | 'document' | 'voice' | 'video' | 'audio';
51
47
  path: string;
@@ -55,6 +51,7 @@ export interface ContainerInput {
55
51
  duration?: number;
56
52
  width?: number;
57
53
  height?: number;
54
+ transcript?: string;
58
55
  }>;
59
56
  }
60
57
 
@@ -74,8 +71,6 @@ export interface ContainerOutput {
74
71
  memory_items_upserted?: number;
75
72
  memory_items_extracted?: number;
76
73
  timings?: {
77
- planner_ms?: number;
78
- response_validation_ms?: number;
79
74
  memory_extraction_ms?: number;
80
75
  tool_ms?: number;
81
76
  };
@@ -1,4 +1,5 @@
1
+ import { randomUUID } from 'crypto';
2
+
1
3
  export function generateId(prefix: string): string {
2
- if (!prefix) return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
3
- return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
4
+ return prefix ? `${prefix}-${randomUUID()}` : randomUUID();
4
5
  }