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,65 @@
1
+ import { randomUUID } from "crypto";
2
+ import { tool } from "ai";
3
+ import { z } from "zod";
4
+ import { searchMemory } from "../memory/search.js";
5
+ /**
6
+ * Create a session-scoped memory_search tool.
7
+ * Called per-run so results are restricted to the current session's memories.
8
+ */
9
+ export function createMemorySearchTool(store, embeddingProvider, maxResults, teamId) {
10
+ return tool({
11
+ description: "Search long-term memory for facts about this user. " +
12
+ "ALWAYS call BEFORE responding to personal questions (name, location, preferences, history). " +
13
+ "Call multiple times with different queries to gather all relevant facts. " +
14
+ "When in doubt, search — it is fast.",
15
+ inputSchema: z.object({
16
+ query: z
17
+ .string()
18
+ .describe("What to search for, e.g. 'favorite food' or 'project details'"),
19
+ }),
20
+ execute: async ({ query }) => {
21
+ const facts = await searchMemory(store, query, {
22
+ limit: maxResults,
23
+ embeddingProvider,
24
+ teamId,
25
+ });
26
+ if (facts.length === 0)
27
+ return "No relevant memories found.";
28
+ return facts.map((f, i) => `${i + 1}. ${f}`).join("\n");
29
+ },
30
+ });
31
+ }
32
+ /**
33
+ * Create a session-scoped memory_save tool.
34
+ * Allows the agent to explicitly persist facts when the user asks to remember something.
35
+ */
36
+ export function createMemorySaveTool(store, embeddingProvider, sessionKey, teamId) {
37
+ return tool({
38
+ description: "Save a fact about the user to long-term memory. Use this when the user " +
39
+ "explicitly asks you to remember something, or shares personal information " +
40
+ "they expect you to retain (name, location, preferences, etc.). " +
41
+ "Each call saves ONE atomic fact — call multiple times for multiple facts.",
42
+ inputSchema: z.object({
43
+ fact: z
44
+ .string()
45
+ .describe("A single factual statement to remember, e.g. 'User lives in Singapore' " +
46
+ "or 'User's favorite food is noodles'"),
47
+ }),
48
+ execute: async ({ fact }) => {
49
+ const embedding = embeddingProvider
50
+ ? await embeddingProvider.embed(fact)
51
+ : undefined;
52
+ const saved = store.save({
53
+ id: randomUUID(),
54
+ fact,
55
+ source: sessionKey,
56
+ timestamp: Date.now(),
57
+ embedding,
58
+ teamId,
59
+ });
60
+ return saved
61
+ ? `Saved: "${fact}"`
62
+ : `Already known: "${fact}"`;
63
+ },
64
+ });
65
+ }
@@ -0,0 +1,6 @@
1
+ import type { Tool, ToolSet } from "ai";
2
+ export declare class ToolRegistry {
3
+ private tools;
4
+ register(name: string, tool: Tool): void;
5
+ getAll(): ToolSet;
6
+ }
@@ -0,0 +1,9 @@
1
+ export class ToolRegistry {
2
+ tools = new Map();
3
+ register(name, tool) {
4
+ this.tools.set(name, tool);
5
+ }
6
+ getAll() {
7
+ return Object.fromEntries(this.tools);
8
+ }
9
+ }
@@ -0,0 +1,8 @@
1
+ import { type ToolSet } from "ai";
2
+ import type { ScheduleStore } from "../scheduler/store.js";
3
+ /**
4
+ * Create schedule management tools scoped to a team.
5
+ * These let the LLM create, list, delete, pause, resume schedules
6
+ * and set the team's timezone.
7
+ */
8
+ export declare function createScheduleTools(store: ScheduleStore, teamId: string, availableIntegrations: string[]): ToolSet;
@@ -0,0 +1,219 @@
1
+ import { randomUUID } from "crypto";
2
+ import { tool } from "ai";
3
+ import { z } from "zod";
4
+ import { Cron } from "croner";
5
+ /**
6
+ * Create schedule management tools scoped to a team.
7
+ * These let the LLM create, list, delete, pause, resume schedules
8
+ * and set the team's timezone.
9
+ */
10
+ export function createScheduleTools(store, teamId, availableIntegrations) {
11
+ const integrationsList = availableIntegrations.length > 0
12
+ ? `Available integrations: ${availableIntegrations.join(", ")}.`
13
+ : "No integrations available.";
14
+ const createSchedule = tool({
15
+ description: `Create a scheduled task. Create IMMEDIATELY when user asks — do NOT ask for confirmation. ` +
16
+ `One-shot: provide runAt (ISO 8601). Recurring: provide cron (e.g. "0 9 * * *"). ` +
17
+ `Convert relative times to absolute timestamps using current time. ` +
18
+ `${integrationsList}`,
19
+ inputSchema: z.object({
20
+ prompt: z.string().describe("The exact message or instruction to execute when this task fires. " +
21
+ "For reminders: write the actual reminder text the user should see (e.g. 'Time to call Sarah!' not 'Reminder from Assistant'). " +
22
+ "For data tasks: write a clear instruction (e.g. 'Check BTC price and report current value')."),
23
+ type: z.enum(["one_shot", "recurring"]).describe("one_shot for reminders, recurring for repeating tasks"),
24
+ cron: z.string().optional().describe("Cron expression for recurring tasks (e.g. '0 9 * * *')"),
25
+ runAt: z.string().optional().describe("ISO 8601 timestamp for one-shot tasks (e.g. '2026-02-08T15:30:00')"),
26
+ timezone: z.string().optional().describe("IANA timezone (e.g. 'America/New_York'). Uses saved team timezone if omitted."),
27
+ integrations: z.string().optional().describe("Comma-separated integration names to enable for this task"),
28
+ conditional: z.boolean().optional().describe("If true, the agent can skip delivery if nothing noteworthy happened"),
29
+ }),
30
+ execute: async (params) => {
31
+ // Resolve timezone: user param > saved setting > UTC default
32
+ const tz = params.timezone || store.getTimezone(teamId) || "UTC";
33
+ // Validate timezone
34
+ try {
35
+ Intl.DateTimeFormat(undefined, { timeZone: tz });
36
+ }
37
+ catch {
38
+ return `Invalid timezone "${tz}". Use IANA format like "America/New_York" or "Asia/Shanghai".`;
39
+ }
40
+ const type = params.type;
41
+ // Validate cron for recurring
42
+ if (type === "recurring") {
43
+ if (!params.cron) {
44
+ return "Recurring schedules require a cron expression.";
45
+ }
46
+ try {
47
+ new Cron(params.cron);
48
+ }
49
+ catch (err) {
50
+ return `Invalid cron expression "${params.cron}": ${err instanceof Error ? err.message : err}`;
51
+ }
52
+ }
53
+ // Validate runAt for one-shot
54
+ if (type === "one_shot") {
55
+ if (!params.runAt) {
56
+ return "One-shot schedules require a runAt timestamp.";
57
+ }
58
+ const runDate = new Date(params.runAt);
59
+ if (isNaN(runDate.getTime())) {
60
+ return `Invalid timestamp "${params.runAt}". Use ISO 8601 format.`;
61
+ }
62
+ if (runDate.getTime() <= Date.now()) {
63
+ return `The time "${params.runAt}" is in the past. Provide a future time.`;
64
+ }
65
+ }
66
+ // Compute nextRun
67
+ let nextRun = null;
68
+ if (type === "one_shot" && params.runAt) {
69
+ nextRun = new Date(params.runAt).toISOString();
70
+ }
71
+ else if (type === "recurring" && params.cron) {
72
+ try {
73
+ const job = new Cron(params.cron, { timezone: tz });
74
+ const next = job.nextRun();
75
+ nextRun = next ? next.toISOString() : null;
76
+ }
77
+ catch {
78
+ return "Failed to compute next run time from cron expression.";
79
+ }
80
+ }
81
+ const now = new Date().toISOString();
82
+ const id = randomUUID();
83
+ store.create({
84
+ id,
85
+ teamId,
86
+ prompt: params.prompt,
87
+ type,
88
+ cron: params.cron ?? null,
89
+ runAt: params.runAt ?? null,
90
+ timezone: tz,
91
+ integrations: params.integrations ?? "",
92
+ conditional: params.conditional ?? false,
93
+ status: "active",
94
+ nextRun,
95
+ lastRun: null,
96
+ failCount: 0,
97
+ createdAt: now,
98
+ updatedAt: now,
99
+ });
100
+ const nextRunFormatted = nextRun
101
+ ? new Date(nextRun).toLocaleString("en-US", { timeZone: tz })
102
+ : "unknown";
103
+ return `Schedule created (${type}). ID: ${id}\nNext run: ${nextRunFormatted} (${tz})`;
104
+ },
105
+ });
106
+ const listSchedules = tool({
107
+ description: "List all scheduled tasks for the current team.",
108
+ inputSchema: z.object({
109
+ status: z.enum(["active", "paused", "completed", "failed"]).optional()
110
+ .describe("Filter by status. Omit to show all."),
111
+ }),
112
+ execute: async ({ status }) => {
113
+ const schedules = store.listByTeam(teamId, status);
114
+ if (schedules.length === 0) {
115
+ return status ? `No ${status} schedules found.` : "No schedules found.";
116
+ }
117
+ const tz = store.getTimezone(teamId) ?? "UTC";
118
+ const lines = schedules.map((s) => {
119
+ const nextStr = s.nextRun
120
+ ? new Date(s.nextRun).toLocaleString("en-US", { timeZone: tz })
121
+ : "—";
122
+ const typeStr = s.type === "recurring" ? `recurring (${s.cron})` : "one-shot";
123
+ const condStr = s.conditional ? " [conditional]" : "";
124
+ return `- **${s.id.slice(0, 8)}** [${s.status}] ${typeStr}${condStr}\n "${s.prompt.slice(0, 80)}"\n Next: ${nextStr}`;
125
+ });
126
+ return lines.join("\n\n");
127
+ },
128
+ });
129
+ const deleteSchedule = tool({
130
+ description: "Delete a scheduled task by its ID.",
131
+ inputSchema: z.object({
132
+ id: z.string().describe("Schedule ID (full or first 8 chars)"),
133
+ }),
134
+ execute: async ({ id }) => {
135
+ const schedule = resolveScheduleId(store, teamId, id);
136
+ if (!schedule)
137
+ return `Schedule "${id}" not found or does not belong to this team.`;
138
+ store.delete(schedule.id);
139
+ return `Schedule "${schedule.id.slice(0, 8)}" deleted.`;
140
+ },
141
+ });
142
+ const pauseSchedule = tool({
143
+ description: "Pause an active scheduled task. It will not fire until resumed.",
144
+ inputSchema: z.object({
145
+ id: z.string().describe("Schedule ID (full or first 8 chars)"),
146
+ }),
147
+ execute: async ({ id }) => {
148
+ const schedule = resolveScheduleId(store, teamId, id);
149
+ if (!schedule)
150
+ return `Schedule "${id}" not found or does not belong to this team.`;
151
+ if (schedule.status !== "active")
152
+ return `Schedule is not active (status: ${schedule.status}).`;
153
+ store.update(schedule.id, { status: "paused" });
154
+ return `Schedule "${schedule.id.slice(0, 8)}" paused.`;
155
+ },
156
+ });
157
+ const resumeSchedule = tool({
158
+ description: "Resume a paused scheduled task.",
159
+ inputSchema: z.object({
160
+ id: z.string().describe("Schedule ID (full or first 8 chars)"),
161
+ }),
162
+ execute: async ({ id }) => {
163
+ const schedule = resolveScheduleId(store, teamId, id);
164
+ if (!schedule)
165
+ return `Schedule "${id}" not found or does not belong to this team.`;
166
+ if (schedule.status !== "paused")
167
+ return `Schedule is not paused (status: ${schedule.status}).`;
168
+ // Recompute next run
169
+ let nextRun = null;
170
+ if (schedule.type === "recurring" && schedule.cron) {
171
+ nextRun = store.computeNextRun(schedule);
172
+ }
173
+ else if (schedule.type === "one_shot" && schedule.runAt) {
174
+ // For one-shots, use original runAt if still in the future
175
+ const runDate = new Date(schedule.runAt);
176
+ nextRun = runDate.getTime() > Date.now() ? runDate.toISOString() : new Date().toISOString();
177
+ }
178
+ store.update(schedule.id, { status: "active", nextRun });
179
+ return `Schedule "${schedule.id.slice(0, 8)}" resumed. Next run: ${nextRun ?? "now"}`;
180
+ },
181
+ });
182
+ const setTimezone = tool({
183
+ description: `Set your timezone for scheduled tasks. Use IANA timezone names like "America/New_York", "Asia/Shanghai", "Europe/London".`,
184
+ inputSchema: z.object({
185
+ timezone: z.string().describe('IANA timezone name (e.g. "America/New_York")'),
186
+ }),
187
+ execute: async ({ timezone }) => {
188
+ try {
189
+ Intl.DateTimeFormat(undefined, { timeZone: timezone });
190
+ }
191
+ catch {
192
+ return `Invalid timezone "${timezone}". Use IANA format like "America/New_York" or "Asia/Shanghai".`;
193
+ }
194
+ store.setTimezone(teamId, timezone);
195
+ return `Timezone set to "${timezone}".`;
196
+ },
197
+ });
198
+ return {
199
+ create_schedule: createSchedule,
200
+ list_schedules: listSchedules,
201
+ delete_schedule: deleteSchedule,
202
+ pause_schedule: pauseSchedule,
203
+ resume_schedule: resumeSchedule,
204
+ set_timezone: setTimezone,
205
+ };
206
+ }
207
+ /** Resolve a schedule ID (full or short) that belongs to the given team. */
208
+ function resolveScheduleId(store, teamId, id) {
209
+ // Try exact match first
210
+ const exact = store.getById(id);
211
+ if (exact && exact.teamId === teamId)
212
+ return exact;
213
+ // Try short ID prefix match
214
+ const all = store.listByTeam(teamId);
215
+ const matches = all.filter((s) => s.id.startsWith(id));
216
+ if (matches.length === 1)
217
+ return matches[0];
218
+ return null;
219
+ }
@@ -0,0 +1,10 @@
1
+ import { type ToolSet } from "ai";
2
+ export interface TTSConfig {
3
+ enabled: boolean;
4
+ voice: string;
5
+ }
6
+ /**
7
+ * Create TTS tools: speak (synthesize + play) and speech_control (pause/resume/stop).
8
+ * Returns null when TTS is disabled.
9
+ */
10
+ export declare function createSpeakTools(config: TTSConfig): ToolSet | null;
@@ -0,0 +1,56 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ import { synthesize } from "../tts/edge.js";
4
+ import { playAudio, pauseAudio, resumeAudio, stopAudio } from "../tts/speak.js";
5
+ import { logger } from "../logger.js";
6
+ const PREVIEW_LENGTH = 80;
7
+ /**
8
+ * Create TTS tools: speak (synthesize + play) and speech_control (pause/resume/stop).
9
+ * Returns null when TTS is disabled.
10
+ */
11
+ export function createSpeakTools(config) {
12
+ if (!config.enabled)
13
+ return null;
14
+ const speak = tool({
15
+ description: "Speak text aloud through the computer's speakers. " +
16
+ "Keep spoken text concise and conversational. " +
17
+ "Do NOT speak code blocks, URLs, or long technical output — use text for those.",
18
+ inputSchema: z.object({
19
+ text: z.string().describe("The text to speak aloud"),
20
+ voice: z
21
+ .string()
22
+ .optional()
23
+ .describe("Edge TTS voice name (e.g. en-US-GuyNeural). Defaults to config voice."),
24
+ }),
25
+ execute: async ({ text, voice }) => {
26
+ try {
27
+ // voice param overrides; otherwise auto-detect from text content
28
+ const audioPath = await synthesize(text, voice);
29
+ playAudio(audioPath);
30
+ const preview = text.length > PREVIEW_LENGTH
31
+ ? `${text.slice(0, PREVIEW_LENGTH)}...`
32
+ : text;
33
+ return `Spoke: "${preview}"`;
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ logger.error(`TTS failed: ${msg}`);
38
+ return `TTS error: ${msg}`;
39
+ }
40
+ },
41
+ });
42
+ const speechControl = tool({
43
+ description: "Control ongoing speech playback. Use this to pause, resume, or stop the current TTS audio.",
44
+ inputSchema: z.object({
45
+ action: z.enum(["pause", "resume", "stop"]).describe("The playback control action"),
46
+ }),
47
+ execute: async ({ action }) => {
48
+ switch (action) {
49
+ case "pause": return pauseAudio();
50
+ case "resume": return resumeAudio();
51
+ case "stop": return stopAudio();
52
+ }
53
+ },
54
+ });
55
+ return { speak, speech_control: speechControl };
56
+ }
@@ -0,0 +1,29 @@
1
+ import type { TaskStore } from "../tasks/store.js";
2
+ /**
3
+ * Creates AI-facing tools for task management.
4
+ * Non-default teams are scoped to their own tasks only.
5
+ * The default team has access to all tasks across all teams.
6
+ */
7
+ export declare function createTaskTools(taskStore: TaskStore, teamId?: string): {
8
+ task_create: import("ai").Tool<{
9
+ title: string;
10
+ description?: string | undefined;
11
+ assignee?: string | undefined;
12
+ priority?: "low" | "medium" | "high" | undefined;
13
+ }, string>;
14
+ task_update: import("ai").Tool<{
15
+ id: string;
16
+ status?: "done" | "backlog" | "todo" | "in_progress" | "archived" | undefined;
17
+ title?: string | undefined;
18
+ description?: string | null | undefined;
19
+ assignee?: string | null | undefined;
20
+ priority?: "low" | "medium" | "high" | undefined;
21
+ }, string>;
22
+ task_list: import("ai").Tool<{
23
+ status?: "done" | "backlog" | "todo" | "in_progress" | "archived" | undefined;
24
+ team?: string | undefined;
25
+ }, string>;
26
+ task_delete: import("ai").Tool<{
27
+ id: string;
28
+ }, string>;
29
+ };
@@ -0,0 +1,92 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ import { TASK_STATUSES, TASK_PRIORITIES } from "../tasks/types.js";
4
+ import { DEFAULT_TEAM_ID } from "../config/agent-config.js";
5
+ import { emit } from "../events.js";
6
+ /**
7
+ * Creates AI-facing tools for task management.
8
+ * Non-default teams are scoped to their own tasks only.
9
+ * The default team has access to all tasks across all teams.
10
+ */
11
+ export function createTaskTools(taskStore, teamId) {
12
+ /** Non-default teams can only access their own tasks. */
13
+ const scoped = !!teamId && teamId !== DEFAULT_TEAM_ID;
14
+ const createTask = tool({
15
+ description: "Create a new task for the team. Returns the created task with its ID.",
16
+ inputSchema: z.object({
17
+ title: z.string().describe("Short task title"),
18
+ description: z.string().optional().describe("Optional detailed description"),
19
+ assignee: z.string().optional().describe("Agent ID or 'user' to assign to"),
20
+ priority: z.enum(TASK_PRIORITIES).optional().describe("Task priority: low, medium, or high"),
21
+ }),
22
+ execute: async ({ title, description, assignee, priority }) => {
23
+ const task = taskStore.create({ title, description, teamId, assignee, priority });
24
+ emit("taskChange", { action: "created", task });
25
+ return `Task created: [${task.id}] ${task.title} (${task.priority}, ${task.status})`;
26
+ },
27
+ });
28
+ const updateTask = tool({
29
+ description: "Update an existing task. Set status to in_progress when starting work, done when completing.",
30
+ inputSchema: z.object({
31
+ id: z.string().describe("Task ID to update"),
32
+ status: z.enum(TASK_STATUSES).optional().describe("New status: backlog, todo, in_progress, done, archived"),
33
+ title: z.string().optional().describe("New title"),
34
+ description: z.string().nullable().optional().describe("New description (null to clear)"),
35
+ assignee: z.string().nullable().optional().describe("New assignee (agent ID, 'user', or null to unassign)"),
36
+ priority: z.enum(TASK_PRIORITIES).optional().describe("New priority"),
37
+ }),
38
+ execute: async ({ id, status, title, description, assignee, priority }) => {
39
+ if (scoped) {
40
+ const existing = taskStore.getById(id);
41
+ if (!existing || existing.teamId !== teamId)
42
+ return `Task not found: ${id}`;
43
+ }
44
+ const task = taskStore.update(id, { status, title, description, assignee, priority });
45
+ if (!task)
46
+ return `Task not found: ${id}`;
47
+ emit("taskChange", { action: "updated", task });
48
+ return `Task updated: [${task.id}] ${task.title} — ${task.status} (${task.priority})`;
49
+ },
50
+ });
51
+ const listTasks = tool({
52
+ description: "List tasks. ALWAYS call fresh — never rely on cached results. " +
53
+ "Only include filters the user explicitly requests. Returns all tasks when called with no parameters.",
54
+ inputSchema: z.object({
55
+ status: z.enum(TASK_STATUSES).optional().describe("Filter by status"),
56
+ team: z.string().optional().describe("Filter by team ID"),
57
+ }),
58
+ execute: async ({ status, team }) => {
59
+ const effectiveTeamId = scoped ? teamId : team;
60
+ const tasks = taskStore.list({ teamId: effectiveTeamId, status });
61
+ if (tasks.length === 0)
62
+ return "No tasks found.";
63
+ return tasks
64
+ .map((t) => `[${t.id}] ${t.title} — ${t.status} (${t.priority}, team: ${t.teamId}${t.assignee ? `, assigned: ${t.assignee}` : ""})`)
65
+ .join("\n");
66
+ },
67
+ });
68
+ const deleteTask = tool({
69
+ description: "Permanently delete a task by ID.",
70
+ inputSchema: z.object({
71
+ id: z.string().describe("Task ID to delete"),
72
+ }),
73
+ execute: async ({ id }) => {
74
+ if (scoped) {
75
+ const existing = taskStore.getById(id);
76
+ if (!existing || existing.teamId !== teamId)
77
+ return `Task not found: ${id}`;
78
+ }
79
+ const deleted = taskStore.delete(id);
80
+ if (!deleted)
81
+ return `Task not found: ${id}`;
82
+ emit("taskChange", { action: "deleted", id });
83
+ return `Task deleted: ${id}`;
84
+ },
85
+ });
86
+ return {
87
+ task_create: createTask,
88
+ task_update: updateTask,
89
+ task_list: listTasks,
90
+ task_delete: deleteTask,
91
+ };
92
+ }
@@ -0,0 +1,7 @@
1
+ import { type ToolSet } from "ai";
2
+ import type { TeamStore } from "../teams/store.js";
3
+ /**
4
+ * Creates AI-facing tools for team and worker management.
5
+ * Only available to the default team orchestrator.
6
+ */
7
+ export declare function createTeamManagementTools(teamStore: TeamStore): ToolSet;