verybot 0.1.3

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.

Potentially problematic release.


This version of verybot might be problematic. Click here for more details.

Files changed (244) hide show
  1. package/dist/brain/agent-registry.d.ts +75 -0
  2. package/dist/brain/agent-registry.js +124 -0
  3. package/dist/brain/agent.d.ts +146 -0
  4. package/dist/brain/agent.js +680 -0
  5. package/dist/brain/channel-store.d.ts +27 -0
  6. package/dist/brain/channel-store.js +78 -0
  7. package/dist/brain/compaction.d.ts +37 -0
  8. package/dist/brain/compaction.js +214 -0
  9. package/dist/brain/context.d.ts +33 -0
  10. package/dist/brain/context.js +77 -0
  11. package/dist/brain/delegation-store.d.ts +33 -0
  12. package/dist/brain/delegation-store.js +106 -0
  13. package/dist/brain/loop.d.ts +21 -0
  14. package/dist/brain/loop.js +161 -0
  15. package/dist/brain/mcp-adapter.d.ts +39 -0
  16. package/dist/brain/mcp-adapter.js +227 -0
  17. package/dist/brain/memory-extractor.d.ts +26 -0
  18. package/dist/brain/memory-extractor.js +82 -0
  19. package/dist/brain/providers.d.ts +10 -0
  20. package/dist/brain/providers.js +69 -0
  21. package/dist/brain/queue.d.ts +18 -0
  22. package/dist/brain/queue.js +84 -0
  23. package/dist/brain/run-tools.d.ts +47 -0
  24. package/dist/brain/run-tools.js +84 -0
  25. package/dist/brain/session-key.d.ts +23 -0
  26. package/dist/brain/session-key.js +41 -0
  27. package/dist/brain/session-state.d.ts +36 -0
  28. package/dist/brain/session-state.js +51 -0
  29. package/dist/brain/session-store.d.ts +50 -0
  30. package/dist/brain/session-store.js +207 -0
  31. package/dist/brain/session.d.ts +32 -0
  32. package/dist/brain/session.js +75 -0
  33. package/dist/brain/utils.d.ts +4 -0
  34. package/dist/brain/utils.js +26 -0
  35. package/dist/brain/worker-coordinator.d.ts +25 -0
  36. package/dist/brain/worker-coordinator.js +83 -0
  37. package/dist/channels/commands.d.ts +35 -0
  38. package/dist/channels/commands.js +65 -0
  39. package/dist/channels/discord/channel.d.ts +18 -0
  40. package/dist/channels/discord/channel.js +154 -0
  41. package/dist/channels/discord/markdown.d.ts +19 -0
  42. package/dist/channels/discord/markdown.js +62 -0
  43. package/dist/channels/manager.d.ts +29 -0
  44. package/dist/channels/manager.js +100 -0
  45. package/dist/channels/slack/channel.d.ts +26 -0
  46. package/dist/channels/slack/channel.js +207 -0
  47. package/dist/channels/slack/markdown.d.ts +19 -0
  48. package/dist/channels/slack/markdown.js +62 -0
  49. package/dist/channels/specs.d.ts +21 -0
  50. package/dist/channels/specs.js +96 -0
  51. package/dist/channels/telegram/channel.d.ts +18 -0
  52. package/dist/channels/telegram/channel.js +156 -0
  53. package/dist/channels/telegram/markdown.d.ts +17 -0
  54. package/dist/channels/telegram/markdown.js +66 -0
  55. package/dist/channels/types.d.ts +26 -0
  56. package/dist/channels/types.js +1 -0
  57. package/dist/channels/whatsapp/channel.d.ts +23 -0
  58. package/dist/channels/whatsapp/channel.js +242 -0
  59. package/dist/channels/whatsapp/markdown.d.ts +20 -0
  60. package/dist/channels/whatsapp/markdown.js +51 -0
  61. package/dist/cli/config.d.ts +5 -0
  62. package/dist/cli/config.js +78 -0
  63. package/dist/cli/index.d.ts +5 -0
  64. package/dist/cli/index.js +13 -0
  65. package/dist/computer/browser/actions.d.ts +31 -0
  66. package/dist/computer/browser/actions.js +148 -0
  67. package/dist/computer/browser/manager.d.ts +55 -0
  68. package/dist/computer/browser/manager.js +496 -0
  69. package/dist/computer/browser/profile-badge.d.ts +13 -0
  70. package/dist/computer/browser/profile-badge.js +67 -0
  71. package/dist/computer/browser/screenshot.d.ts +5 -0
  72. package/dist/computer/browser/screenshot.js +21 -0
  73. package/dist/computer/browser/snapshot.d.ts +30 -0
  74. package/dist/computer/browser/snapshot.js +242 -0
  75. package/dist/computer/browser/tools.d.ts +5 -0
  76. package/dist/computer/browser/tools.js +167 -0
  77. package/dist/computer/desktop/adapter.d.ts +25 -0
  78. package/dist/computer/desktop/adapter.js +11 -0
  79. package/dist/computer/desktop/macos.d.ts +24 -0
  80. package/dist/computer/desktop/macos.js +223 -0
  81. package/dist/computer/desktop/tools.d.ts +25 -0
  82. package/dist/computer/desktop/tools.js +114 -0
  83. package/dist/config/agent-config.d.ts +41 -0
  84. package/dist/config/agent-config.js +14 -0
  85. package/dist/config/model-catalog.d.ts +22 -0
  86. package/dist/config/model-catalog.js +99 -0
  87. package/dist/config/store.d.ts +25 -0
  88. package/dist/config/store.js +143 -0
  89. package/dist/config.d.ts +103 -0
  90. package/dist/config.js +224 -0
  91. package/dist/control-ui/assets/index-BANXNUyt.js +143 -0
  92. package/dist/control-ui/assets/index-BSUFrP9R.css +1 -0
  93. package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
  94. package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
  95. package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
  96. package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
  97. package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
  98. package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
  99. package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
  100. package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
  101. package/dist/control-ui/index.html +14 -0
  102. package/dist/control-ui/vite.svg +1 -0
  103. package/dist/events.d.ts +2 -0
  104. package/dist/events.js +11 -0
  105. package/dist/gateway/broadcast.d.ts +5 -0
  106. package/dist/gateway/broadcast.js +33 -0
  107. package/dist/gateway/methods/chat.d.ts +24 -0
  108. package/dist/gateway/methods/chat.js +19 -0
  109. package/dist/gateway/methods/config.d.ts +13 -0
  110. package/dist/gateway/methods/config.js +14 -0
  111. package/dist/gateway/methods/models.d.ts +10 -0
  112. package/dist/gateway/methods/models.js +14 -0
  113. package/dist/gateway/methods/prompt-templates.d.ts +23 -0
  114. package/dist/gateway/methods/prompt-templates.js +82 -0
  115. package/dist/gateway/methods/scheduler.d.ts +62 -0
  116. package/dist/gateway/methods/scheduler.js +129 -0
  117. package/dist/gateway/methods/sessions.d.ts +26 -0
  118. package/dist/gateway/methods/sessions.js +54 -0
  119. package/dist/gateway/methods/skills.d.ts +35 -0
  120. package/dist/gateway/methods/skills.js +202 -0
  121. package/dist/gateway/methods/system.d.ts +12 -0
  122. package/dist/gateway/methods/system.js +39 -0
  123. package/dist/gateway/methods/tasks.d.ts +21 -0
  124. package/dist/gateway/methods/tasks.js +46 -0
  125. package/dist/gateway/methods/teams.d.ts +70 -0
  126. package/dist/gateway/methods/teams.js +374 -0
  127. package/dist/gateway/methods/tools.d.ts +6 -0
  128. package/dist/gateway/methods/tools.js +7 -0
  129. package/dist/gateway/methods/whatsapp.d.ts +19 -0
  130. package/dist/gateway/methods/whatsapp.js +35 -0
  131. package/dist/gateway/rpc.d.ts +38 -0
  132. package/dist/gateway/rpc.js +75 -0
  133. package/dist/gateway/server.d.ts +4 -0
  134. package/dist/gateway/server.js +133 -0
  135. package/dist/index.d.ts +1 -0
  136. package/dist/index.js +212 -0
  137. package/dist/integrations/github.d.ts +7 -0
  138. package/dist/integrations/github.js +133 -0
  139. package/dist/integrations/mcp.d.ts +7 -0
  140. package/dist/integrations/mcp.js +106 -0
  141. package/dist/integrations/registry.d.ts +43 -0
  142. package/dist/integrations/registry.js +258 -0
  143. package/dist/integrations/scanner.d.ts +10 -0
  144. package/dist/integrations/scanner.js +122 -0
  145. package/dist/integrations/twitter.d.ts +10 -0
  146. package/dist/integrations/twitter.js +120 -0
  147. package/dist/integrations/types.d.ts +72 -0
  148. package/dist/integrations/types.js +1 -0
  149. package/dist/logger.d.ts +16 -0
  150. package/dist/logger.js +104 -0
  151. package/dist/markdown/chunk.d.ts +9 -0
  152. package/dist/markdown/chunk.js +52 -0
  153. package/dist/markdown/ir.d.ts +37 -0
  154. package/dist/markdown/ir.js +529 -0
  155. package/dist/markdown/render.d.ts +22 -0
  156. package/dist/markdown/render.js +148 -0
  157. package/dist/markdown/table-render.d.ts +43 -0
  158. package/dist/markdown/table-render.js +219 -0
  159. package/dist/markdown/tables.d.ts +17 -0
  160. package/dist/markdown/tables.js +27 -0
  161. package/dist/memory/embedding.d.ts +16 -0
  162. package/dist/memory/embedding.js +66 -0
  163. package/dist/memory/extractor.d.ts +6 -0
  164. package/dist/memory/extractor.js +72 -0
  165. package/dist/memory/search.d.ts +15 -0
  166. package/dist/memory/search.js +57 -0
  167. package/dist/memory/store.d.ts +34 -0
  168. package/dist/memory/store.js +328 -0
  169. package/dist/memory/types.d.ts +9 -0
  170. package/dist/memory/types.js +2 -0
  171. package/dist/paths.d.ts +20 -0
  172. package/dist/paths.js +29 -0
  173. package/dist/prompt-templates/builtins.d.ts +2 -0
  174. package/dist/prompt-templates/builtins.js +72 -0
  175. package/dist/prompt-templates/store.d.ts +39 -0
  176. package/dist/prompt-templates/store.js +174 -0
  177. package/dist/prompt-templates/types.d.ts +10 -0
  178. package/dist/prompt-templates/types.js +1 -0
  179. package/dist/scheduler/connected-channels.d.ts +24 -0
  180. package/dist/scheduler/connected-channels.js +57 -0
  181. package/dist/scheduler/scheduler.d.ts +22 -0
  182. package/dist/scheduler/scheduler.js +132 -0
  183. package/dist/scheduler/store.d.ts +27 -0
  184. package/dist/scheduler/store.js +205 -0
  185. package/dist/scheduler/types.d.ts +29 -0
  186. package/dist/scheduler/types.js +1 -0
  187. package/dist/security/command-validator.d.ts +22 -0
  188. package/dist/security/command-validator.js +160 -0
  189. package/dist/security/docker-sandbox.d.ts +48 -0
  190. package/dist/security/docker-sandbox.js +218 -0
  191. package/dist/security/env-filter.d.ts +8 -0
  192. package/dist/security/env-filter.js +41 -0
  193. package/dist/skills/loader.d.ts +33 -0
  194. package/dist/skills/loader.js +132 -0
  195. package/dist/skills/prompt.d.ts +6 -0
  196. package/dist/skills/prompt.js +17 -0
  197. package/dist/skills/read-tool.d.ts +7 -0
  198. package/dist/skills/read-tool.js +24 -0
  199. package/dist/skills/scanner.d.ts +6 -0
  200. package/dist/skills/scanner.js +73 -0
  201. package/dist/skills/types.d.ts +15 -0
  202. package/dist/skills/types.js +1 -0
  203. package/dist/tasks/store.d.ts +47 -0
  204. package/dist/tasks/store.js +193 -0
  205. package/dist/tasks/types.d.ts +75 -0
  206. package/dist/tasks/types.js +32 -0
  207. package/dist/teams/store.d.ts +78 -0
  208. package/dist/teams/store.js +420 -0
  209. package/dist/teams/types.d.ts +23 -0
  210. package/dist/teams/types.js +1 -0
  211. package/dist/tools/bash.d.ts +16 -0
  212. package/dist/tools/bash.js +62 -0
  213. package/dist/tools/channel-history.d.ts +10 -0
  214. package/dist/tools/channel-history.js +43 -0
  215. package/dist/tools/delegate.d.ts +16 -0
  216. package/dist/tools/delegate.js +216 -0
  217. package/dist/tools/fs.d.ts +4 -0
  218. package/dist/tools/fs.js +335 -0
  219. package/dist/tools/integration-toggle.d.ts +14 -0
  220. package/dist/tools/integration-toggle.js +47 -0
  221. package/dist/tools/memory.d.ts +13 -0
  222. package/dist/tools/memory.js +65 -0
  223. package/dist/tools/registry.d.ts +6 -0
  224. package/dist/tools/registry.js +9 -0
  225. package/dist/tools/schedule.d.ts +8 -0
  226. package/dist/tools/schedule.js +219 -0
  227. package/dist/tools/speak.d.ts +10 -0
  228. package/dist/tools/speak.js +56 -0
  229. package/dist/tools/tasks.d.ts +29 -0
  230. package/dist/tools/tasks.js +92 -0
  231. package/dist/tools/teams.d.ts +7 -0
  232. package/dist/tools/teams.js +180 -0
  233. package/dist/tools/web-fetch.d.ts +3 -0
  234. package/dist/tools/web-fetch.js +22 -0
  235. package/dist/tts/edge.d.ts +10 -0
  236. package/dist/tts/edge.js +60 -0
  237. package/dist/tts/speak.d.ts +12 -0
  238. package/dist/tts/speak.js +81 -0
  239. package/dist/tts/transcribe.d.ts +5 -0
  240. package/dist/tts/transcribe.js +40 -0
  241. package/dist/utils.d.ts +5 -0
  242. package/dist/utils.js +22 -0
  243. package/package.json +90 -0
  244. package/verybot.js +2 -0
@@ -0,0 +1,180 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ import { emit } from "../events.js";
4
+ /**
5
+ * Creates AI-facing tools for team and worker management.
6
+ * Only available to the default team orchestrator.
7
+ */
8
+ export function createTeamManagementTools(teamStore) {
9
+ const teamList = tool({
10
+ description: "List all teams and their agents (orchestrators + workers).",
11
+ inputSchema: z.object({}),
12
+ execute: async () => {
13
+ try {
14
+ const teams = teamStore.listTeams();
15
+ if (teams.length === 0)
16
+ return "No teams found.";
17
+ const lines = teams.map((team) => {
18
+ const agents = teamStore.listAgentsByTeam(team.id);
19
+ const agentLines = agents
20
+ .map((a) => ` - ${a.name} (${a.role}, model: ${a.model}, id: ${a.id})`)
21
+ .join("\n");
22
+ const colorStr = team.color ? `, color: ${team.color}` : "";
23
+ return `**${team.name}** (id: ${team.id}${colorStr})\n${agentLines || " (no agents)"}`;
24
+ });
25
+ return lines.join("\n\n");
26
+ }
27
+ catch (err) {
28
+ return `Failed to list teams: ${err instanceof Error ? err.message : err}`;
29
+ }
30
+ },
31
+ });
32
+ const teamCreate = tool({
33
+ description: "Create a new team. Configure its orchestrator via the UI, then add workers via worker_create.",
34
+ inputSchema: z.object({
35
+ name: z.string().describe("Team name (must be unique)"),
36
+ color: z.string().optional().describe("Optional hex color (e.g. #ef4444)"),
37
+ }),
38
+ execute: async ({ name, color }) => {
39
+ try {
40
+ const team = teamStore.createTeam({ name, color });
41
+ emit("teamChange", { action: "created", team });
42
+ return `Team created: "${team.name}" (id: ${team.id})`;
43
+ }
44
+ catch (err) {
45
+ return `Failed to create team: ${err instanceof Error ? err.message : err}`;
46
+ }
47
+ },
48
+ });
49
+ const teamUpdate = tool({
50
+ description: "Update an existing team's name or color.",
51
+ inputSchema: z.object({
52
+ id: z.string().describe("Team ID to update"),
53
+ name: z.string().optional().describe("New team name"),
54
+ color: z.string().optional().describe("New hex color (e.g. #ef4444)"),
55
+ }),
56
+ execute: async ({ id, name, color }) => {
57
+ try {
58
+ const team = teamStore.updateTeam(id, { name, color });
59
+ if (!team)
60
+ return `Team not found: ${id}`;
61
+ emit("teamChange", { action: "updated", team });
62
+ return `Team updated: "${team.name}" (id: ${team.id})`;
63
+ }
64
+ catch (err) {
65
+ return `Failed to update team: ${err instanceof Error ? err.message : err}`;
66
+ }
67
+ },
68
+ });
69
+ const teamDelete = tool({
70
+ description: "Delete a team and all its agents. This cannot be undone.",
71
+ inputSchema: z.object({
72
+ id: z.string().describe("Team ID to delete"),
73
+ }),
74
+ execute: async ({ id }) => {
75
+ try {
76
+ const deleted = teamStore.deleteTeam(id);
77
+ if (!deleted)
78
+ return `Team not found: ${id}`;
79
+ emit("teamChange", { action: "deleted", id });
80
+ return `Team deleted: ${id}`;
81
+ }
82
+ catch (err) {
83
+ return `Failed to delete team: ${err instanceof Error ? err.message : err}`;
84
+ }
85
+ },
86
+ });
87
+ const workerCreate = tool({
88
+ description: "Add a worker agent to a team. Workers can be delegated tasks by the orchestrator.",
89
+ inputSchema: z.object({
90
+ teamId: z.string().describe("Team ID to add the worker to"),
91
+ name: z.string().describe("Worker name (unique within the team)"),
92
+ model: z.string().describe("Model string (e.g. 'anthropic:claude-sonnet-4-20250514')"),
93
+ identity: z.string().optional().describe("System prompt / identity for the worker"),
94
+ tools: z.array(z.string()).optional().describe("List of tool names to enable"),
95
+ maxSteps: z.number().optional().describe("Max inference steps per run"),
96
+ timeout: z.number().optional().describe("Timeout in seconds for delegated tasks"),
97
+ }),
98
+ execute: async ({ teamId, name, model, identity, tools, maxSteps, timeout }) => {
99
+ try {
100
+ const agent = teamStore.createAgent(teamId, {
101
+ name,
102
+ role: "worker",
103
+ model,
104
+ identity,
105
+ tools,
106
+ maxSteps,
107
+ timeout,
108
+ });
109
+ emit("teamChange", { action: "agentCreated", agent });
110
+ return `Worker created: "${agent.name}" (id: ${agent.id}) in team ${teamId}`;
111
+ }
112
+ catch (err) {
113
+ return `Failed to create worker: ${err instanceof Error ? err.message : err}`;
114
+ }
115
+ },
116
+ });
117
+ const workerUpdate = tool({
118
+ description: "Update a worker's configuration (name, model, identity, tools, etc.).",
119
+ inputSchema: z.object({
120
+ id: z.string().describe("Agent ID to update"),
121
+ name: z.string().optional().describe("New worker name"),
122
+ model: z.string().optional().describe("New model string"),
123
+ identity: z.string().optional().describe("New system prompt / identity"),
124
+ tools: z.array(z.string()).optional().describe("New list of tool names"),
125
+ maxSteps: z.number().optional().describe("New max inference steps"),
126
+ timeout: z.number().optional().describe("New timeout in seconds"),
127
+ }),
128
+ execute: async ({ id, name, model, identity, tools, maxSteps, timeout }) => {
129
+ try {
130
+ const existing = teamStore.getAgentById(id);
131
+ if (!existing)
132
+ return `Agent not found: ${id}`;
133
+ if (existing.role === "orchestrator") {
134
+ return "Cannot modify an orchestrator via worker_update. Use the UI to update orchestrators.";
135
+ }
136
+ const agent = teamStore.updateAgent(id, { name, model, identity, tools, maxSteps, timeout });
137
+ if (!agent)
138
+ return `Agent not found: ${id}`;
139
+ emit("teamChange", { action: "agentUpdated", agent });
140
+ return `Worker updated: "${agent.name}" (id: ${agent.id})`;
141
+ }
142
+ catch (err) {
143
+ return `Failed to update worker: ${err instanceof Error ? err.message : err}`;
144
+ }
145
+ },
146
+ });
147
+ const workerDelete = tool({
148
+ description: "Remove a worker from a team. This cannot be undone.",
149
+ inputSchema: z.object({
150
+ id: z.string().describe("Agent ID to delete"),
151
+ }),
152
+ execute: async ({ id }) => {
153
+ try {
154
+ const existing = teamStore.getAgentById(id);
155
+ if (!existing)
156
+ return `Agent not found: ${id}`;
157
+ if (existing.role === "orchestrator") {
158
+ return "Cannot delete an orchestrator via worker_delete. Use the UI to manage orchestrators.";
159
+ }
160
+ const deleted = teamStore.deleteAgent(id);
161
+ if (!deleted)
162
+ return `Agent not found: ${id}`;
163
+ emit("teamChange", { action: "agentDeleted", id });
164
+ return `Worker deleted: ${id}`;
165
+ }
166
+ catch (err) {
167
+ return `Failed to delete worker: ${err instanceof Error ? err.message : err}`;
168
+ }
169
+ },
170
+ });
171
+ return {
172
+ team_list: teamList,
173
+ team_create: teamCreate,
174
+ team_update: teamUpdate,
175
+ team_delete: teamDelete,
176
+ worker_create: workerCreate,
177
+ worker_update: workerUpdate,
178
+ worker_delete: workerDelete,
179
+ };
180
+ }
@@ -0,0 +1,3 @@
1
+ export declare const webFetchTool: import("ai").Tool<{
2
+ url: string;
3
+ }, string>;
@@ -0,0 +1,22 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ // TODO: phase 5 — improve with HTML→markdown conversion
4
+ export const webFetchTool = tool({
5
+ description: "Fetch a URL and return its text content",
6
+ inputSchema: z.object({
7
+ url: z.string().url().describe("The URL to fetch"),
8
+ }),
9
+ execute: async ({ url }) => {
10
+ try {
11
+ const res = await fetch(url, {
12
+ headers: { "User-Agent": "mini-agent/0.1" },
13
+ signal: AbortSignal.timeout(15_000),
14
+ });
15
+ const text = await res.text();
16
+ return text.slice(0, 20_000); // cap size
17
+ }
18
+ catch (err) {
19
+ return `Error fetching ${url}: ${err.message}`;
20
+ }
21
+ },
22
+ });
@@ -0,0 +1,10 @@
1
+ /** Detect dominant language from text content. */
2
+ export declare function detectLanguage(text: string): string;
3
+ /** Pick the right voice for the text language. */
4
+ export declare function resolveVoice(text: string, explicitVoice?: string): string;
5
+ /**
6
+ * Synthesize text to an mp3 file using Microsoft Edge TTS.
7
+ * Free, no API key required — uses the same neural voices as Edge browser.
8
+ * Returns the path to the generated mp3 file (caller must clean up).
9
+ */
10
+ export declare function synthesize(text: string, voice?: string): Promise<string>;
@@ -0,0 +1,60 @@
1
+ import { EdgeTTS } from "node-edge-tts";
2
+ import { join } from "path";
3
+ import { tmpdir } from "os";
4
+ import { randomBytes } from "crypto";
5
+ import { logger } from "../logger.js";
6
+ const OUTPUT_FORMAT = "audio-24khz-96kbitrate-mono-mp3";
7
+ const MAX_TEXT_LENGTH = 2_000;
8
+ const SYNTHESIS_TIMEOUT = 300_000;
9
+ /** Default voices per detected language. */
10
+ const VOICE_MAP = {
11
+ zh: "zh-CN-XiaoxiaoNeural",
12
+ ja: "ja-JP-NanamiNeural",
13
+ ko: "ko-KR-SunHiNeural",
14
+ en: "en-US-AriaNeural",
15
+ };
16
+ const FALLBACK_VOICE = "en-US-AriaNeural";
17
+ // CJK Unicode ranges for language detection
18
+ const CJK_RE = /[\u4e00-\u9fff\u3400-\u4dbf]/;
19
+ const JAPANESE_RE = /[\u3040-\u309f\u30a0-\u30ff]/;
20
+ const KOREAN_RE = /[\uac00-\ud7af\u1100-\u11ff]/;
21
+ /** Detect dominant language from text content. */
22
+ export function detectLanguage(text) {
23
+ // Sample first 200 chars for speed
24
+ const sample = text.slice(0, 200);
25
+ if (JAPANESE_RE.test(sample))
26
+ return "ja";
27
+ if (KOREAN_RE.test(sample))
28
+ return "ko";
29
+ if (CJK_RE.test(sample))
30
+ return "zh";
31
+ return "en";
32
+ }
33
+ /** Pick the right voice for the text language. */
34
+ export function resolveVoice(text, explicitVoice) {
35
+ if (explicitVoice)
36
+ return explicitVoice;
37
+ const lang = detectLanguage(text);
38
+ return VOICE_MAP[lang] ?? FALLBACK_VOICE;
39
+ }
40
+ /**
41
+ * Synthesize text to an mp3 file using Microsoft Edge TTS.
42
+ * Free, no API key required — uses the same neural voices as Edge browser.
43
+ * Returns the path to the generated mp3 file (caller must clean up).
44
+ */
45
+ export async function synthesize(text, voice) {
46
+ const trimmed = text.length > MAX_TEXT_LENGTH
47
+ ? text.slice(0, MAX_TEXT_LENGTH)
48
+ : text;
49
+ const resolvedVoice = resolveVoice(trimmed, voice);
50
+ const outPath = join(tmpdir(), `edge-tts-${randomBytes(6).toString("hex")}.mp3`);
51
+ const tts = new EdgeTTS({
52
+ voice: resolvedVoice,
53
+ lang: resolvedVoice.split("-").slice(0, 2).join("-"),
54
+ outputFormat: OUTPUT_FORMAT,
55
+ timeout: SYNTHESIS_TIMEOUT,
56
+ });
57
+ await tts.ttsPromise(trimmed, outPath);
58
+ logger.info(`TTS synthesized ${trimmed.length} chars with voice=${resolvedVoice}`);
59
+ return outPath;
60
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Start playing an mp3 file in the background (non-blocking).
3
+ * Returns immediately — use stopAudio/pauseAudio to control playback.
4
+ * Cleans up the temp file when playback ends.
5
+ */
6
+ export declare function playAudio(filePath: string): void;
7
+ /** Pause current playback (SIGSTOP). */
8
+ export declare function pauseAudio(): string;
9
+ /** Resume paused playback (SIGCONT). */
10
+ export declare function resumeAudio(): string;
11
+ /** Stop current playback immediately. */
12
+ export declare function stopAudio(): string;
@@ -0,0 +1,81 @@
1
+ import { spawn } from "child_process";
2
+ import { unlink } from "fs/promises";
3
+ import { logger } from "../logger.js";
4
+ const PLAYBACK_TIMEOUT = 300_000;
5
+ let activeChild = null;
6
+ let activeFile = null;
7
+ let paused = false;
8
+ /**
9
+ * Start playing an mp3 file in the background (non-blocking).
10
+ * Returns immediately — use stopAudio/pauseAudio to control playback.
11
+ * Cleans up the temp file when playback ends.
12
+ */
13
+ export function playAudio(filePath) {
14
+ // Stop any existing playback first
15
+ stopAudio();
16
+ activeFile = filePath;
17
+ paused = false;
18
+ const cmd = process.platform === "darwin" ? "afplay" : "ffplay";
19
+ const args = process.platform === "darwin"
20
+ ? [filePath]
21
+ : ["-nodisp", "-autoexit", filePath];
22
+ const child = spawn(cmd, args, { stdio: "ignore" });
23
+ activeChild = child;
24
+ const timer = setTimeout(() => {
25
+ child.kill();
26
+ logger.warn("TTS playback timed out");
27
+ }, PLAYBACK_TIMEOUT);
28
+ const cleanup = () => {
29
+ clearTimeout(timer);
30
+ activeChild = null;
31
+ activeFile = null;
32
+ paused = false;
33
+ unlink(filePath).catch(() => { });
34
+ };
35
+ child.on("close", (code) => {
36
+ cleanup();
37
+ if (code === 0 || code === null) {
38
+ logger.info("TTS playback finished");
39
+ }
40
+ else {
41
+ logger.warn(`TTS player exited with code ${code}`);
42
+ }
43
+ });
44
+ child.on("error", (err) => {
45
+ cleanup();
46
+ logger.error(`TTS player error: ${err.message}`);
47
+ });
48
+ }
49
+ /** Pause current playback (SIGSTOP). */
50
+ export function pauseAudio() {
51
+ if (!activeChild)
52
+ return "Nothing is playing.";
53
+ if (paused)
54
+ return "Already paused.";
55
+ activeChild.kill("SIGSTOP");
56
+ paused = true;
57
+ logger.info("TTS playback paused");
58
+ return "Playback paused.";
59
+ }
60
+ /** Resume paused playback (SIGCONT). */
61
+ export function resumeAudio() {
62
+ if (!activeChild)
63
+ return "Nothing is playing.";
64
+ if (!paused)
65
+ return "Already playing.";
66
+ activeChild.kill("SIGCONT");
67
+ paused = false;
68
+ logger.info("TTS playback resumed");
69
+ return "Playback resumed.";
70
+ }
71
+ /** Stop current playback immediately. */
72
+ export function stopAudio() {
73
+ if (!activeChild)
74
+ return "Nothing is playing.";
75
+ // Resume first if paused, then kill — avoids zombie stopped process
76
+ if (paused)
77
+ activeChild.kill("SIGCONT");
78
+ activeChild.kill();
79
+ logger.info("TTS playback stopped");
80
+ return "Playback stopped.";
81
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Transcribe an audio buffer to text using OpenAI's gpt-4o-mini-transcribe.
3
+ * Accepts ogg/opus (Telegram voice), mp3, wav, m4a, webm, etc.
4
+ */
5
+ export declare function transcribe(audioBuffer: Buffer, filename?: string): Promise<string>;
@@ -0,0 +1,40 @@
1
+ import OpenAI from "openai";
2
+ import { logger } from "../logger.js";
3
+ const TRANSCRIBE_MODEL = "gpt-4o-mini-transcribe";
4
+ let client = null;
5
+ function getClient() {
6
+ if (!client) {
7
+ client = new OpenAI();
8
+ }
9
+ return client;
10
+ }
11
+ /**
12
+ * Transcribe an audio buffer to text using OpenAI's gpt-4o-mini-transcribe.
13
+ * Accepts ogg/opus (Telegram voice), mp3, wav, m4a, webm, etc.
14
+ */
15
+ export async function transcribe(audioBuffer, filename = "voice.ogg") {
16
+ // Telegram sends .oga (Opus in Ogg) — normalize to .ogg which OpenAI accepts
17
+ const normalizedName = filename.replace(/\.oga$/, ".ogg");
18
+ const file = new File([new Uint8Array(audioBuffer)], normalizedName, {
19
+ type: mimeFromFilename(normalizedName),
20
+ });
21
+ const result = await getClient().audio.transcriptions.create({
22
+ model: TRANSCRIBE_MODEL,
23
+ file,
24
+ });
25
+ logger.info(`Transcribed ${audioBuffer.length} bytes → ${result.text.length} chars`);
26
+ return result.text;
27
+ }
28
+ function mimeFromFilename(name) {
29
+ if (name.endsWith(".ogg") || name.endsWith(".oga"))
30
+ return "audio/ogg";
31
+ if (name.endsWith(".mp3"))
32
+ return "audio/mpeg";
33
+ if (name.endsWith(".wav"))
34
+ return "audio/wav";
35
+ if (name.endsWith(".m4a"))
36
+ return "audio/mp4";
37
+ if (name.endsWith(".webm"))
38
+ return "audio/webm";
39
+ return "audio/ogg";
40
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Split a long message into chunks that fit within a character limit.
3
+ * Splits on newline boundaries when possible, hard-splits otherwise.
4
+ */
5
+ export declare function splitMessage(text: string, maxLength: number): string[];
package/dist/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Split a long message into chunks that fit within a character limit.
3
+ * Splits on newline boundaries when possible, hard-splits otherwise.
4
+ */
5
+ export function splitMessage(text, maxLength) {
6
+ if (text.length <= maxLength)
7
+ return [text];
8
+ const chunks = [];
9
+ let remaining = text;
10
+ while (remaining.length > 0) {
11
+ if (remaining.length <= maxLength) {
12
+ chunks.push(remaining);
13
+ break;
14
+ }
15
+ let splitAt = remaining.lastIndexOf("\n", maxLength);
16
+ if (splitAt <= 0)
17
+ splitAt = maxLength;
18
+ chunks.push(remaining.slice(0, splitAt));
19
+ remaining = remaining.slice(splitAt).replace(/^\n/, "");
20
+ }
21
+ return chunks;
22
+ }
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "verybot",
3
+ "version": "0.1.3",
4
+ "description": "Multi-channel AI agent framework with Telegram, Discord, Slack, and WhatsApp support",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "charlie",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/charlie0077/verybot"
11
+ },
12
+ "keywords": [
13
+ "ai",
14
+ "agent",
15
+ "telegram",
16
+ "discord",
17
+ "slack",
18
+ "whatsapp",
19
+ "llm",
20
+ "chatbot",
21
+ "mcp"
22
+ ],
23
+ "engines": {
24
+ "node": ">=22"
25
+ },
26
+ "bin": {
27
+ "verybot": "./verybot.js"
28
+ },
29
+ "files": [
30
+ "dist/",
31
+ "verybot.js"
32
+ ],
33
+ "scripts": {
34
+ "dev": "tsx watch src/index.ts",
35
+ "build": "rm -rf dist && tsc && find dist -name '*.test.js' -o -name '*.test.d.ts' | xargs rm -f && cd ui && vite build --outDir ../dist/control-ui",
36
+ "start": "node dist/index.js",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "prepublishOnly": "bun run build && bun run test",
40
+ "publish:patch": "npm version patch && npm publish --access public",
41
+ "publish:minor": "npm version minor && npm publish --access public",
42
+ "publish:major": "npm version major && npm publish --access public"
43
+ },
44
+ "dependencies": {
45
+ "@ai-sdk/anthropic": "^3.0.38",
46
+ "@ai-sdk/deepseek": "^2.0.18",
47
+ "@ai-sdk/elevenlabs": "^2.0.18",
48
+ "@ai-sdk/google": "^3.0.22",
49
+ "@ai-sdk/groq": "^3.0.22",
50
+ "@ai-sdk/mistral": "^3.0.19",
51
+ "@ai-sdk/openai": "^3.0.26",
52
+ "@ai-sdk/openai-compatible": "^2.0.28",
53
+ "@ai-sdk/togetherai": "^2.0.31",
54
+ "@ai-sdk/xai": "^3.0.50",
55
+ "@modelcontextprotocol/sdk": "^1.26.0",
56
+ "@slack/bolt": "^4.6.0",
57
+ "@whiskeysockets/baileys": "^7.0.0-rc.9",
58
+ "ai": "^6.0.75",
59
+ "ai-sdk-provider-claude-code": "^3.4.0",
60
+ "ai-sdk-provider-codex-cli": "^1.0.5",
61
+ "better-sqlite3": "^12.6.2",
62
+ "chokidar": "^5.0.0",
63
+ "croner": "^10.0.1",
64
+ "discord.js": "^14.25.1",
65
+ "grammy": "^1.39.3",
66
+ "markdown-it": "^14.1.1",
67
+ "node-edge-tts": "^1.2.10",
68
+ "node-llama-cpp": "^3.15.1",
69
+ "octokit": "^5.0.5",
70
+ "openai": "^6.18.0",
71
+ "playwright": "^1.58.2",
72
+ "qrcode": "^1.5.4",
73
+ "sharp": "^0.34.5",
74
+ "sqlite-vec": "^0.1.7-alpha.2",
75
+ "twitter-api-v2": "^1.29.0",
76
+ "winston": "^3.19.0",
77
+ "ws": "^8.19.0",
78
+ "zod": "^4.3.6"
79
+ },
80
+ "devDependencies": {
81
+ "@types/better-sqlite3": "^7.6.13",
82
+ "@types/markdown-it": "^14.1.2",
83
+ "@types/node": "^25.2.1",
84
+ "@types/qrcode": "^1.5.6",
85
+ "@types/ws": "^8.18.1",
86
+ "tsx": "^4.21.0",
87
+ "typescript": "^5.9.3",
88
+ "vitest": "^4.0.18"
89
+ }
90
+ }
package/verybot.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "./dist/index.js";