@jcheesepkg/nanobot 0.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 (130) hide show
  1. package/README.md +139 -0
  2. package/dist/_virtual/_rolldown/runtime.mjs +40 -0
  3. package/dist/agent/context.d.mts +44 -0
  4. package/dist/agent/context.d.mts.map +1 -0
  5. package/dist/agent/context.mjs +153 -0
  6. package/dist/agent/context.mjs.map +1 -0
  7. package/dist/agent/loop.d.mts +56 -0
  8. package/dist/agent/loop.d.mts.map +1 -0
  9. package/dist/agent/loop.mjs +232 -0
  10. package/dist/agent/loop.mjs.map +1 -0
  11. package/dist/agent/memory.d.mts +30 -0
  12. package/dist/agent/memory.d.mts.map +1 -0
  13. package/dist/agent/memory.mjs +77 -0
  14. package/dist/agent/memory.mjs.map +1 -0
  15. package/dist/agent/skills.d.mts +43 -0
  16. package/dist/agent/skills.d.mts.map +1 -0
  17. package/dist/agent/skills.mjs +159 -0
  18. package/dist/agent/skills.mjs.map +1 -0
  19. package/dist/agent/subagent.d.mts +39 -0
  20. package/dist/agent/subagent.d.mts.map +1 -0
  21. package/dist/agent/subagent.mjs +167 -0
  22. package/dist/agent/subagent.mjs.map +1 -0
  23. package/dist/agent/tools/base.d.mts +16 -0
  24. package/dist/agent/tools/base.d.mts.map +1 -0
  25. package/dist/agent/tools/base.mjs +19 -0
  26. package/dist/agent/tools/base.mjs.map +1 -0
  27. package/dist/agent/tools/cron.d.mts +49 -0
  28. package/dist/agent/tools/cron.d.mts.map +1 -0
  29. package/dist/agent/tools/cron.mjs +101 -0
  30. package/dist/agent/tools/cron.mjs.map +1 -0
  31. package/dist/agent/tools/filesystem.d.mts +87 -0
  32. package/dist/agent/tools/filesystem.d.mts.map +1 -0
  33. package/dist/agent/tools/filesystem.mjs +145 -0
  34. package/dist/agent/tools/filesystem.mjs.map +1 -0
  35. package/dist/agent/tools/message.d.mts +44 -0
  36. package/dist/agent/tools/message.d.mts.map +1 -0
  37. package/dist/agent/tools/message.mjs +68 -0
  38. package/dist/agent/tools/message.mjs.map +1 -0
  39. package/dist/agent/tools/registry.d.mts +29 -0
  40. package/dist/agent/tools/registry.d.mts.map +1 -0
  41. package/dist/agent/tools/registry.mjs +49 -0
  42. package/dist/agent/tools/registry.mjs.map +1 -0
  43. package/dist/agent/tools/shell.d.mts +36 -0
  44. package/dist/agent/tools/shell.d.mts.map +1 -0
  45. package/dist/agent/tools/shell.mjs +73 -0
  46. package/dist/agent/tools/shell.mjs.map +1 -0
  47. package/dist/agent/tools/spawn.d.mts +35 -0
  48. package/dist/agent/tools/spawn.d.mts.map +1 -0
  49. package/dist/agent/tools/spawn.mjs +50 -0
  50. package/dist/agent/tools/spawn.mjs.map +1 -0
  51. package/dist/agent/tools/web.d.mts +63 -0
  52. package/dist/agent/tools/web.d.mts.map +1 -0
  53. package/dist/agent/tools/web.mjs +195 -0
  54. package/dist/agent/tools/web.mjs.map +1 -0
  55. package/dist/bus/events.d.mts +29 -0
  56. package/dist/bus/events.d.mts.map +1 -0
  57. package/dist/bus/events.mjs +30 -0
  58. package/dist/bus/events.mjs.map +1 -0
  59. package/dist/bus/queue.d.mts +38 -0
  60. package/dist/bus/queue.d.mts.map +1 -0
  61. package/dist/bus/queue.mjs +90 -0
  62. package/dist/bus/queue.mjs.map +1 -0
  63. package/dist/channels/base.d.mts +31 -0
  64. package/dist/channels/base.d.mts.map +1 -0
  65. package/dist/channels/base.mjs +49 -0
  66. package/dist/channels/base.mjs.map +1 -0
  67. package/dist/channels/manager.d.mts +30 -0
  68. package/dist/channels/manager.d.mts.map +1 -0
  69. package/dist/channels/manager.mjs +100 -0
  70. package/dist/channels/manager.mjs.map +1 -0
  71. package/dist/channels/telegram.d.mts +23 -0
  72. package/dist/channels/telegram.d.mts.map +1 -0
  73. package/dist/channels/telegram.mjs +161 -0
  74. package/dist/channels/telegram.mjs.map +1 -0
  75. package/dist/cli/index.d.mts +1 -0
  76. package/dist/cli/index.mjs +337 -0
  77. package/dist/cli/index.mjs.map +1 -0
  78. package/dist/config/loader.d.mts +14 -0
  79. package/dist/config/loader.d.mts.map +1 -0
  80. package/dist/config/loader.mjs +40 -0
  81. package/dist/config/loader.mjs.map +1 -0
  82. package/dist/config/schema.d.mts +724 -0
  83. package/dist/config/schema.d.mts.map +1 -0
  84. package/dist/config/schema.mjs +123 -0
  85. package/dist/config/schema.mjs.map +1 -0
  86. package/dist/cron/service.d.mts +42 -0
  87. package/dist/cron/service.d.mts.map +1 -0
  88. package/dist/cron/service.mjs +256 -0
  89. package/dist/cron/service.mjs.map +1 -0
  90. package/dist/cron/types.d.mts +55 -0
  91. package/dist/cron/types.d.mts.map +1 -0
  92. package/dist/cron/types.mjs +30 -0
  93. package/dist/cron/types.mjs.map +1 -0
  94. package/dist/heartbeat/service.d.mts +29 -0
  95. package/dist/heartbeat/service.d.mts.map +1 -0
  96. package/dist/heartbeat/service.mjs +96 -0
  97. package/dist/heartbeat/service.mjs.map +1 -0
  98. package/dist/index.d.mts +23 -0
  99. package/dist/index.d.mts.map +1 -0
  100. package/dist/index.mjs +23 -0
  101. package/dist/index.mjs.map +1 -0
  102. package/dist/providers/base.d.mts +65 -0
  103. package/dist/providers/base.d.mts.map +1 -0
  104. package/dist/providers/base.mjs +1 -0
  105. package/dist/providers/openai-provider.d.mts +27 -0
  106. package/dist/providers/openai-provider.d.mts.map +1 -0
  107. package/dist/providers/openai-provider.mjs +67 -0
  108. package/dist/providers/openai-provider.mjs.map +1 -0
  109. package/dist/providers/transcription.d.mts +14 -0
  110. package/dist/providers/transcription.d.mts.map +1 -0
  111. package/dist/providers/transcription.mjs +46 -0
  112. package/dist/providers/transcription.mjs.map +1 -0
  113. package/dist/session/manager.d.mts +56 -0
  114. package/dist/session/manager.d.mts.map +1 -0
  115. package/dist/session/manager.mjs +144 -0
  116. package/dist/session/manager.mjs.map +1 -0
  117. package/dist/utils/helpers.d.mts +26 -0
  118. package/dist/utils/helpers.d.mts.map +1 -0
  119. package/dist/utils/helpers.mjs +60 -0
  120. package/dist/utils/helpers.mjs.map +1 -0
  121. package/dist/utils/which.d.mts +6 -0
  122. package/dist/utils/which.d.mts.map +1 -0
  123. package/dist/utils/which.mjs +20 -0
  124. package/dist/utils/which.mjs.map +1 -0
  125. package/package.json +45 -0
  126. package/skills/cron/SKILL.md +40 -0
  127. package/skills/github/SKILL.md +48 -0
  128. package/skills/skill-creator/SKILL.md +73 -0
  129. package/skills/summarize/SKILL.md +47 -0
  130. package/skills/weather/SKILL.md +43 -0
@@ -0,0 +1,232 @@
1
+ import { createInboundMessage, createOutboundMessage, init_events } from "../bus/events.mjs";
2
+ import { ContextBuilder } from "./context.mjs";
3
+ import { ToolRegistry } from "./tools/registry.mjs";
4
+ import { EditFileTool, ListDirTool, ReadFileTool, WriteFileTool } from "./tools/filesystem.mjs";
5
+ import { ExecTool } from "./tools/shell.mjs";
6
+ import { WebFetchTool, WebSearchTool } from "./tools/web.mjs";
7
+ import { MessageTool } from "./tools/message.mjs";
8
+ import { SpawnTool } from "./tools/spawn.mjs";
9
+ import { CronTool } from "./tools/cron.mjs";
10
+ import { SubagentManager } from "./subagent.mjs";
11
+ import { SessionManager } from "../session/manager.mjs";
12
+
13
+ //#region src/agent/loop.ts
14
+ init_events();
15
+ /**
16
+ * The agent loop: core processing engine.
17
+ *
18
+ * 1. Receives messages from the bus
19
+ * 2. Builds context with history, memory, skills
20
+ * 3. Calls the LLM
21
+ * 4. Executes tool calls
22
+ * 5. Sends responses back
23
+ */
24
+ var AgentLoop = class {
25
+ bus;
26
+ provider;
27
+ workspace;
28
+ model;
29
+ maxIterations;
30
+ context;
31
+ sessions;
32
+ tools;
33
+ subagents;
34
+ _running = false;
35
+ constructor(params) {
36
+ this.bus = params.bus;
37
+ this.provider = params.provider;
38
+ this.workspace = params.workspace;
39
+ this.model = params.model ?? params.provider.getDefaultModel();
40
+ this.maxIterations = params.maxIterations ?? 20;
41
+ const execConfig = params.execConfig ?? {
42
+ timeout: 60,
43
+ restrictToWorkspace: false
44
+ };
45
+ this.context = new ContextBuilder(params.workspace);
46
+ this.sessions = new SessionManager(params.workspace);
47
+ this.tools = new ToolRegistry();
48
+ this.subagents = new SubagentManager({
49
+ provider: params.provider,
50
+ workspace: params.workspace,
51
+ bus: params.bus,
52
+ model: this.model,
53
+ braveApiKey: params.braveApiKey,
54
+ execConfig
55
+ });
56
+ this.registerDefaultTools(execConfig, params.braveApiKey, params.cronService);
57
+ }
58
+ registerDefaultTools(execConfig, braveApiKey, cronService) {
59
+ this.tools.register(new ReadFileTool());
60
+ this.tools.register(new WriteFileTool());
61
+ this.tools.register(new EditFileTool());
62
+ this.tools.register(new ListDirTool());
63
+ this.tools.register(new ExecTool({
64
+ workingDir: this.workspace,
65
+ timeout: execConfig.timeout,
66
+ restrictToWorkspace: execConfig.restrictToWorkspace
67
+ }));
68
+ this.tools.register(new WebSearchTool({ apiKey: braveApiKey }));
69
+ this.tools.register(new WebFetchTool());
70
+ const messageTool = new MessageTool({ sendCallback: (msg) => this.bus.publishOutbound(msg) });
71
+ this.tools.register(messageTool);
72
+ const spawnTool = new SpawnTool(this.subagents);
73
+ this.tools.register(spawnTool);
74
+ if (cronService) this.tools.register(new CronTool(cronService));
75
+ }
76
+ /** Run the agent loop, processing messages from the bus. */
77
+ async run() {
78
+ this._running = true;
79
+ console.log("Agent loop started");
80
+ while (this._running) try {
81
+ const msg = await withTimeout(this.bus.consumeInbound(), 1e3);
82
+ try {
83
+ const response = await this.processMessage(msg);
84
+ if (response) await this.bus.publishOutbound(response);
85
+ } catch (err) {
86
+ console.error("Error processing message:", err);
87
+ await this.bus.publishOutbound(createOutboundMessage({
88
+ channel: msg.channel,
89
+ chatId: msg.chatId,
90
+ content: `Sorry, I encountered an error: ${err instanceof Error ? err.message : err}`
91
+ }));
92
+ }
93
+ } catch {}
94
+ }
95
+ /** Stop the agent loop. */
96
+ stop() {
97
+ this._running = false;
98
+ console.log("Agent loop stopping");
99
+ }
100
+ /** Process a single inbound message. */
101
+ async processMessage(msg) {
102
+ if (msg.channel === "system") return this.processSystemMessage(msg);
103
+ console.log(`Processing message from ${msg.channel}:${msg.senderId}`);
104
+ const sessionKey = `${msg.channel}:${msg.chatId}`;
105
+ const session = this.sessions.getOrCreate(sessionKey);
106
+ this.updateToolContexts(msg.channel, msg.chatId);
107
+ const messages = this.context.buildMessages({
108
+ history: session.getHistory(),
109
+ currentMessage: msg.content,
110
+ media: msg.media.length > 0 ? msg.media : void 0,
111
+ channel: msg.channel,
112
+ chatId: msg.chatId
113
+ });
114
+ const finalContent = await this.runAgentLoop(messages);
115
+ session.addMessage("user", msg.content);
116
+ session.addMessage("assistant", finalContent);
117
+ this.sessions.save(session);
118
+ return createOutboundMessage({
119
+ channel: msg.channel,
120
+ chatId: msg.chatId,
121
+ content: finalContent
122
+ });
123
+ }
124
+ async processSystemMessage(msg) {
125
+ console.log(`Processing system message from ${msg.senderId}`);
126
+ let originChannel;
127
+ let originChatId;
128
+ if (msg.chatId.includes(":")) {
129
+ const [ch, id] = msg.chatId.split(":", 2);
130
+ originChannel = ch;
131
+ originChatId = id;
132
+ } else {
133
+ originChannel = "cli";
134
+ originChatId = msg.chatId;
135
+ }
136
+ const sessionKey = `${originChannel}:${originChatId}`;
137
+ const session = this.sessions.getOrCreate(sessionKey);
138
+ this.updateToolContexts(originChannel, originChatId);
139
+ const messages = this.context.buildMessages({
140
+ history: session.getHistory(),
141
+ currentMessage: msg.content,
142
+ channel: originChannel,
143
+ chatId: originChatId
144
+ });
145
+ const finalContent = await this.runAgentLoop(messages);
146
+ session.addMessage("user", `[System: ${msg.senderId}] ${msg.content}`);
147
+ session.addMessage("assistant", finalContent);
148
+ this.sessions.save(session);
149
+ return createOutboundMessage({
150
+ channel: originChannel,
151
+ chatId: originChatId,
152
+ content: finalContent
153
+ });
154
+ }
155
+ async runAgentLoop(messages) {
156
+ let finalContent = null;
157
+ for (let i = 0; i < this.maxIterations; i++) {
158
+ const response = await this.provider.chat({
159
+ messages,
160
+ tools: this.tools.getDefinitions(),
161
+ model: this.model
162
+ });
163
+ if (response.hasToolCalls) {
164
+ const toolCallDicts = response.toolCalls.map((tc) => ({
165
+ id: tc.id,
166
+ type: "function",
167
+ function: {
168
+ name: tc.name,
169
+ arguments: JSON.stringify(tc.arguments)
170
+ }
171
+ }));
172
+ this.context.addAssistantMessage(messages, response.content, toolCallDicts);
173
+ for (const tc of response.toolCalls) {
174
+ console.log(`Executing tool: ${tc.name} with arguments: ${JSON.stringify(tc.arguments)}`);
175
+ const result = await this.tools.execute(tc.name, tc.arguments);
176
+ this.context.addToolResult(messages, tc.id, tc.name, result);
177
+ }
178
+ } else {
179
+ finalContent = response.content;
180
+ break;
181
+ }
182
+ }
183
+ return finalContent ?? "I've completed processing but have no response to give.";
184
+ }
185
+ updateToolContexts(channel, chatId) {
186
+ const messageTool = this.tools.get("message");
187
+ if (messageTool instanceof MessageTool) messageTool.setContext(channel, chatId);
188
+ const spawnTool = this.tools.get("spawn");
189
+ if (spawnTool instanceof SpawnTool) spawnTool.setContext(channel, chatId);
190
+ const cronTool = this.tools.get("cron");
191
+ if (cronTool instanceof CronTool) cronTool.setContext(channel, chatId);
192
+ }
193
+ /** Process a message directly (for CLI or cron usage). */
194
+ async processDirect(content, sessionKey = "cli:direct", channel = "cli", chatId = "direct") {
195
+ createInboundMessage({
196
+ channel,
197
+ senderId: "user",
198
+ chatId,
199
+ content
200
+ });
201
+ const session = this.sessions.getOrCreate(sessionKey);
202
+ this.updateToolContexts(channel, chatId);
203
+ const messages = this.context.buildMessages({
204
+ history: session.getHistory(),
205
+ currentMessage: content,
206
+ channel,
207
+ chatId
208
+ });
209
+ const finalContent = await this.runAgentLoop(messages);
210
+ session.addMessage("user", content);
211
+ session.addMessage("assistant", finalContent);
212
+ this.sessions.save(session);
213
+ return finalContent;
214
+ }
215
+ };
216
+ /** Promise.race with a timeout. */
217
+ function withTimeout(promise, ms) {
218
+ return new Promise((resolve, reject) => {
219
+ const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("timeout")), ms);
220
+ promise.then((val) => {
221
+ clearTimeout(timer);
222
+ resolve(val);
223
+ }, (err) => {
224
+ clearTimeout(timer);
225
+ reject(err);
226
+ });
227
+ });
228
+ }
229
+
230
+ //#endregion
231
+ export { AgentLoop };
232
+ //# sourceMappingURL=loop.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.mjs","names":[],"sources":["../../src/agent/loop.ts"],"sourcesContent":["import type { LLMProvider, ChatMessage } from \"../providers/base.js\";\nimport type { MessageBus } from \"../bus/queue.js\";\nimport type {\n InboundMessage,\n OutboundMessage,\n} from \"../bus/events.js\";\nimport { createInboundMessage, createOutboundMessage } from \"../bus/events.js\";\nimport { ContextBuilder } from \"./context.js\";\nimport { ToolRegistry } from \"./tools/registry.js\";\nimport {\n ReadFileTool,\n WriteFileTool,\n EditFileTool,\n ListDirTool,\n} from \"./tools/filesystem.js\";\nimport { ExecTool } from \"./tools/shell.js\";\nimport { WebSearchTool, WebFetchTool } from \"./tools/web.js\";\nimport { MessageTool } from \"./tools/message.js\";\nimport { SpawnTool } from \"./tools/spawn.js\";\nimport { CronTool } from \"./tools/cron.js\";\nimport { SubagentManager } from \"./subagent.js\";\nimport { SessionManager } from \"../session/manager.js\";\nimport type { ExecToolConfig } from \"../config/schema.js\";\nimport type { CronService } from \"../cron/service.js\";\n\n/**\n * The agent loop: core processing engine.\n *\n * 1. Receives messages from the bus\n * 2. Builds context with history, memory, skills\n * 3. Calls the LLM\n * 4. Executes tool calls\n * 5. Sends responses back\n */\nexport class AgentLoop {\n private bus: MessageBus;\n private provider: LLMProvider;\n private workspace: string;\n private model: string;\n private maxIterations: number;\n\n readonly context: ContextBuilder;\n readonly sessions: SessionManager;\n readonly tools: ToolRegistry;\n readonly subagents: SubagentManager;\n\n private _running = false;\n\n constructor(params: {\n bus: MessageBus;\n provider: LLMProvider;\n workspace: string;\n model?: string;\n maxIterations?: number;\n braveApiKey?: string;\n execConfig?: ExecToolConfig;\n cronService?: CronService;\n }) {\n this.bus = params.bus;\n this.provider = params.provider;\n this.workspace = params.workspace;\n this.model = params.model ?? params.provider.getDefaultModel();\n this.maxIterations = params.maxIterations ?? 20;\n\n const execConfig = params.execConfig ?? {\n timeout: 60,\n restrictToWorkspace: false,\n };\n\n this.context = new ContextBuilder(params.workspace);\n this.sessions = new SessionManager(params.workspace);\n this.tools = new ToolRegistry();\n this.subagents = new SubagentManager({\n provider: params.provider,\n workspace: params.workspace,\n bus: params.bus,\n model: this.model,\n braveApiKey: params.braveApiKey,\n execConfig,\n });\n\n this.registerDefaultTools(execConfig, params.braveApiKey, params.cronService);\n }\n\n private registerDefaultTools(\n execConfig: ExecToolConfig,\n braveApiKey?: string,\n cronService?: CronService,\n ): void {\n // File tools\n this.tools.register(new ReadFileTool());\n this.tools.register(new WriteFileTool());\n this.tools.register(new EditFileTool());\n this.tools.register(new ListDirTool());\n\n // Shell tool\n this.tools.register(\n new ExecTool({\n workingDir: this.workspace,\n timeout: execConfig.timeout,\n restrictToWorkspace: execConfig.restrictToWorkspace,\n }),\n );\n\n // Web tools\n this.tools.register(new WebSearchTool({ apiKey: braveApiKey }));\n this.tools.register(new WebFetchTool());\n\n // Message tool\n const messageTool = new MessageTool({\n sendCallback: (msg) => this.bus.publishOutbound(msg),\n });\n this.tools.register(messageTool);\n\n // Spawn tool\n const spawnTool = new SpawnTool(this.subagents);\n this.tools.register(spawnTool);\n\n // Cron tool\n if (cronService) {\n this.tools.register(new CronTool(cronService));\n }\n }\n\n /** Run the agent loop, processing messages from the bus. */\n async run(): Promise<void> {\n this._running = true;\n console.log(\"Agent loop started\");\n\n while (this._running) {\n try {\n const msg = await withTimeout(this.bus.consumeInbound(), 1000);\n\n try {\n const response = await this.processMessage(msg);\n if (response) {\n await this.bus.publishOutbound(response);\n }\n } catch (err) {\n console.error(\"Error processing message:\", err);\n await this.bus.publishOutbound(\n createOutboundMessage({\n channel: msg.channel,\n chatId: msg.chatId,\n content: `Sorry, I encountered an error: ${err instanceof Error ? err.message : err}`,\n }),\n );\n }\n } catch {\n // timeout, continue\n }\n }\n }\n\n /** Stop the agent loop. */\n stop(): void {\n this._running = false;\n console.log(\"Agent loop stopping\");\n }\n\n /** Process a single inbound message. */\n private async processMessage(\n msg: InboundMessage,\n ): Promise<OutboundMessage | null> {\n // Handle system messages (subagent announces)\n if (msg.channel === \"system\") {\n return this.processSystemMessage(msg);\n }\n\n console.log(`Processing message from ${msg.channel}:${msg.senderId}`);\n\n const sessionKey = `${msg.channel}:${msg.chatId}`;\n const session = this.sessions.getOrCreate(sessionKey);\n\n // Update tool contexts\n this.updateToolContexts(msg.channel, msg.chatId);\n\n // Build initial messages\n const messages = this.context.buildMessages({\n history: session.getHistory(),\n currentMessage: msg.content,\n media: msg.media.length > 0 ? msg.media : undefined,\n channel: msg.channel,\n chatId: msg.chatId,\n });\n\n // Agent loop\n const finalContent = await this.runAgentLoop(messages);\n\n // Save to session\n session.addMessage(\"user\", msg.content);\n session.addMessage(\"assistant\", finalContent);\n this.sessions.save(session);\n\n return createOutboundMessage({\n channel: msg.channel,\n chatId: msg.chatId,\n content: finalContent,\n });\n }\n\n private async processSystemMessage(\n msg: InboundMessage,\n ): Promise<OutboundMessage | null> {\n console.log(`Processing system message from ${msg.senderId}`);\n\n let originChannel: string;\n let originChatId: string;\n\n if (msg.chatId.includes(\":\")) {\n const [ch, id] = msg.chatId.split(\":\", 2);\n originChannel = ch;\n originChatId = id;\n } else {\n originChannel = \"cli\";\n originChatId = msg.chatId;\n }\n\n const sessionKey = `${originChannel}:${originChatId}`;\n const session = this.sessions.getOrCreate(sessionKey);\n\n this.updateToolContexts(originChannel, originChatId);\n\n const messages = this.context.buildMessages({\n history: session.getHistory(),\n currentMessage: msg.content,\n channel: originChannel,\n chatId: originChatId,\n });\n\n const finalContent = await this.runAgentLoop(messages);\n\n session.addMessage(\"user\", `[System: ${msg.senderId}] ${msg.content}`);\n session.addMessage(\"assistant\", finalContent);\n this.sessions.save(session);\n\n return createOutboundMessage({\n channel: originChannel,\n chatId: originChatId,\n content: finalContent,\n });\n }\n\n private async runAgentLoop(messages: ChatMessage[]): Promise<string> {\n let finalContent: string | null = null;\n\n for (let i = 0; i < this.maxIterations; i++) {\n const response = await this.provider.chat({\n messages,\n tools: this.tools.getDefinitions(),\n model: this.model,\n });\n\n if (response.hasToolCalls) {\n const toolCallDicts = response.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: JSON.stringify(tc.arguments),\n },\n }));\n\n this.context.addAssistantMessage(\n messages,\n response.content,\n toolCallDicts,\n );\n\n for (const tc of response.toolCalls) {\n console.log(\n `Executing tool: ${tc.name} with arguments: ${JSON.stringify(tc.arguments)}`,\n );\n const result = await this.tools.execute(tc.name, tc.arguments);\n this.context.addToolResult(messages, tc.id, tc.name, result);\n }\n } else {\n finalContent = response.content;\n break;\n }\n }\n\n return finalContent ?? \"I've completed processing but have no response to give.\";\n }\n\n private updateToolContexts(channel: string, chatId: string): void {\n const messageTool = this.tools.get(\"message\");\n if (messageTool instanceof MessageTool) {\n messageTool.setContext(channel, chatId);\n }\n\n const spawnTool = this.tools.get(\"spawn\");\n if (spawnTool instanceof SpawnTool) {\n spawnTool.setContext(channel, chatId);\n }\n\n const cronTool = this.tools.get(\"cron\");\n if (cronTool instanceof CronTool) {\n cronTool.setContext(channel, chatId);\n }\n }\n\n /** Process a message directly (for CLI or cron usage). */\n async processDirect(\n content: string,\n sessionKey = \"cli:direct\",\n channel = \"cli\",\n chatId = \"direct\",\n ): Promise<string> {\n const msg = createInboundMessage({\n channel,\n senderId: \"user\",\n chatId,\n content,\n });\n\n // Use inline version of processMessage for direct calls\n const session = this.sessions.getOrCreate(sessionKey);\n this.updateToolContexts(channel, chatId);\n\n const messages = this.context.buildMessages({\n history: session.getHistory(),\n currentMessage: content,\n channel,\n chatId,\n });\n\n const finalContent = await this.runAgentLoop(messages);\n\n session.addMessage(\"user\", content);\n session.addMessage(\"assistant\", finalContent);\n this.sessions.save(session);\n\n return finalContent;\n }\n}\n\n/** Promise.race with a timeout. */\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(\"timeout\")), ms);\n promise.then(\n (val) => {\n clearTimeout(timer);\n resolve(val);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ //#region src/agent/memory.d.ts
2
+ /**
3
+ * Memory system for the agent.
4
+ * Supports daily notes (memory/YYYY-MM-DD.md) and long-term memory (MEMORY.md).
5
+ */
6
+ declare class MemoryStore {
7
+ private workspace;
8
+ private memoryDir;
9
+ private memoryFile;
10
+ constructor(workspace: string);
11
+ /** Get path to today's memory file. */
12
+ getTodayFile(): string;
13
+ /** Read today's memory notes. */
14
+ readToday(): string;
15
+ /** Append content to today's memory notes. */
16
+ appendToday(content: string): void;
17
+ /** Read long-term memory (MEMORY.md). */
18
+ readLongTerm(): string;
19
+ /** Write to long-term memory (MEMORY.md). */
20
+ writeLongTerm(content: string): void;
21
+ /** Get memories from the last N days. */
22
+ getRecentMemories(days?: number): string;
23
+ /** List all memory files sorted by date (newest first). */
24
+ listMemoryFiles(): string[];
25
+ /** Get memory context for the agent prompt. */
26
+ getMemoryContext(): string;
27
+ }
28
+ //#endregion
29
+ export { MemoryStore };
30
+ //# sourceMappingURL=memory.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.mts","names":[],"sources":["../../src/agent/memory.ts"],"mappings":";;AAQA;;;cAAa,WAAA;EAAA,QACH,SAAA;EAAA,QACA,SAAA;EAAA,QACA,UAAA;cAEI,SAAA;EAAA;EAOZ,YAAA,CAAA;EAKA;EAAA,SAAA,CAAA;EASY;EAAZ,WAAA,CAAY,OAAA;EAuBZ;EARA,YAAA,CAAA;EAaA;EALA,aAAA,CAAc,OAAA;EAwBd;EAnBA,iBAAA,CAAkB,IAAA;EA8BF;EAXhB,eAAA,CAAA;;EAWA,gBAAA,CAAA;AAAA"}
@@ -0,0 +1,77 @@
1
+ import { ensureDir, todayDate } from "../utils/helpers.mjs";
2
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ //#region src/agent/memory.ts
6
+ /**
7
+ * Memory system for the agent.
8
+ * Supports daily notes (memory/YYYY-MM-DD.md) and long-term memory (MEMORY.md).
9
+ */
10
+ var MemoryStore = class {
11
+ workspace;
12
+ memoryDir;
13
+ memoryFile;
14
+ constructor(workspace) {
15
+ this.workspace = workspace;
16
+ this.memoryDir = ensureDir(join(workspace, "memory"));
17
+ this.memoryFile = join(this.memoryDir, "MEMORY.md");
18
+ }
19
+ /** Get path to today's memory file. */
20
+ getTodayFile() {
21
+ return join(this.memoryDir, `${todayDate()}.md`);
22
+ }
23
+ /** Read today's memory notes. */
24
+ readToday() {
25
+ const todayFile = this.getTodayFile();
26
+ if (existsSync(todayFile)) return readFileSync(todayFile, "utf-8");
27
+ return "";
28
+ }
29
+ /** Append content to today's memory notes. */
30
+ appendToday(content) {
31
+ const todayFile = this.getTodayFile();
32
+ let finalContent;
33
+ if (existsSync(todayFile)) finalContent = readFileSync(todayFile, "utf-8") + "\n" + content;
34
+ else finalContent = `# ${todayDate()}\n\n${content}`;
35
+ writeFileSync(todayFile, finalContent, "utf-8");
36
+ }
37
+ /** Read long-term memory (MEMORY.md). */
38
+ readLongTerm() {
39
+ if (existsSync(this.memoryFile)) return readFileSync(this.memoryFile, "utf-8");
40
+ return "";
41
+ }
42
+ /** Write to long-term memory (MEMORY.md). */
43
+ writeLongTerm(content) {
44
+ writeFileSync(this.memoryFile, content, "utf-8");
45
+ }
46
+ /** Get memories from the last N days. */
47
+ getRecentMemories(days = 7) {
48
+ const memories = [];
49
+ const today = /* @__PURE__ */ new Date();
50
+ for (let i = 0; i < days; i++) {
51
+ const date = new Date(today);
52
+ date.setDate(date.getDate() - i);
53
+ const dateStr = date.toISOString().slice(0, 10);
54
+ const filePath = join(this.memoryDir, `${dateStr}.md`);
55
+ if (existsSync(filePath)) memories.push(readFileSync(filePath, "utf-8"));
56
+ }
57
+ return memories.join("\n\n---\n\n");
58
+ }
59
+ /** List all memory files sorted by date (newest first). */
60
+ listMemoryFiles() {
61
+ if (!existsSync(this.memoryDir)) return [];
62
+ return readdirSync(this.memoryDir).filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort().reverse().map((f) => join(this.memoryDir, f));
63
+ }
64
+ /** Get memory context for the agent prompt. */
65
+ getMemoryContext() {
66
+ const parts = [];
67
+ const longTerm = this.readLongTerm();
68
+ if (longTerm) parts.push("## Long-term Memory\n" + longTerm);
69
+ const today = this.readToday();
70
+ if (today) parts.push("## Today's Notes\n" + today);
71
+ return parts.join("\n\n");
72
+ }
73
+ };
74
+
75
+ //#endregion
76
+ export { MemoryStore };
77
+ //# sourceMappingURL=memory.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/agent/memory.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { ensureDir, todayDate } from \"../utils/helpers.js\";\n\n/**\n * Memory system for the agent.\n * Supports daily notes (memory/YYYY-MM-DD.md) and long-term memory (MEMORY.md).\n */\nexport class MemoryStore {\n private workspace: string;\n private memoryDir: string;\n private memoryFile: string;\n\n constructor(workspace: string) {\n this.workspace = workspace;\n this.memoryDir = ensureDir(join(workspace, \"memory\"));\n this.memoryFile = join(this.memoryDir, \"MEMORY.md\");\n }\n\n /** Get path to today's memory file. */\n getTodayFile(): string {\n return join(this.memoryDir, `${todayDate()}.md`);\n }\n\n /** Read today's memory notes. */\n readToday(): string {\n const todayFile = this.getTodayFile();\n if (existsSync(todayFile)) {\n return readFileSync(todayFile, \"utf-8\");\n }\n return \"\";\n }\n\n /** Append content to today's memory notes. */\n appendToday(content: string): void {\n const todayFile = this.getTodayFile();\n let finalContent: string;\n\n if (existsSync(todayFile)) {\n const existing = readFileSync(todayFile, \"utf-8\");\n finalContent = existing + \"\\n\" + content;\n } else {\n finalContent = `# ${todayDate()}\\n\\n${content}`;\n }\n\n writeFileSync(todayFile, finalContent, \"utf-8\");\n }\n\n /** Read long-term memory (MEMORY.md). */\n readLongTerm(): string {\n if (existsSync(this.memoryFile)) {\n return readFileSync(this.memoryFile, \"utf-8\");\n }\n return \"\";\n }\n\n /** Write to long-term memory (MEMORY.md). */\n writeLongTerm(content: string): void {\n writeFileSync(this.memoryFile, content, \"utf-8\");\n }\n\n /** Get memories from the last N days. */\n getRecentMemories(days = 7): string {\n const memories: string[] = [];\n const today = new Date();\n\n for (let i = 0; i < days; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n const dateStr = date.toISOString().slice(0, 10);\n const filePath = join(this.memoryDir, `${dateStr}.md`);\n\n if (existsSync(filePath)) {\n memories.push(readFileSync(filePath, \"utf-8\"));\n }\n }\n\n return memories.join(\"\\n\\n---\\n\\n\");\n }\n\n /** List all memory files sorted by date (newest first). */\n listMemoryFiles(): string[] {\n if (!existsSync(this.memoryDir)) return [];\n\n return readdirSync(this.memoryDir)\n .filter((f) => /^\\d{4}-\\d{2}-\\d{2}\\.md$/.test(f))\n .sort()\n .reverse()\n .map((f) => join(this.memoryDir, f));\n }\n\n /** Get memory context for the agent prompt. */\n getMemoryContext(): string {\n const parts: string[] = [];\n\n const longTerm = this.readLongTerm();\n if (longTerm) {\n parts.push(\"## Long-term Memory\\n\" + longTerm);\n }\n\n const today = this.readToday();\n if (today) {\n parts.push(\"## Today's Notes\\n\" + today);\n }\n\n return parts.join(\"\\n\\n\");\n }\n}\n"],"mappings":";;;;;;;;;AAQA,IAAa,cAAb,MAAyB;CACvB,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,WAAmB;AAC7B,OAAK,YAAY;AACjB,OAAK,YAAY,UAAU,KAAK,WAAW,SAAS,CAAC;AACrD,OAAK,aAAa,KAAK,KAAK,WAAW,YAAY;;;CAIrD,eAAuB;AACrB,SAAO,KAAK,KAAK,WAAW,GAAG,WAAW,CAAC,KAAK;;;CAIlD,YAAoB;EAClB,MAAM,YAAY,KAAK,cAAc;AACrC,MAAI,WAAW,UAAU,CACvB,QAAO,aAAa,WAAW,QAAQ;AAEzC,SAAO;;;CAIT,YAAY,SAAuB;EACjC,MAAM,YAAY,KAAK,cAAc;EACrC,IAAI;AAEJ,MAAI,WAAW,UAAU,CAEvB,gBADiB,aAAa,WAAW,QAAQ,GACvB,OAAO;MAEjC,gBAAe,KAAK,WAAW,CAAC,MAAM;AAGxC,gBAAc,WAAW,cAAc,QAAQ;;;CAIjD,eAAuB;AACrB,MAAI,WAAW,KAAK,WAAW,CAC7B,QAAO,aAAa,KAAK,YAAY,QAAQ;AAE/C,SAAO;;;CAIT,cAAc,SAAuB;AACnC,gBAAc,KAAK,YAAY,SAAS,QAAQ;;;CAIlD,kBAAkB,OAAO,GAAW;EAClC,MAAM,WAAqB,EAAE;EAC7B,MAAM,wBAAQ,IAAI,MAAM;AAExB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK;GAC7B,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,QAAK,QAAQ,KAAK,SAAS,GAAG,EAAE;GAChC,MAAM,UAAU,KAAK,aAAa,CAAC,MAAM,GAAG,GAAG;GAC/C,MAAM,WAAW,KAAK,KAAK,WAAW,GAAG,QAAQ,KAAK;AAEtD,OAAI,WAAW,SAAS,CACtB,UAAS,KAAK,aAAa,UAAU,QAAQ,CAAC;;AAIlD,SAAO,SAAS,KAAK,cAAc;;;CAIrC,kBAA4B;AAC1B,MAAI,CAAC,WAAW,KAAK,UAAU,CAAE,QAAO,EAAE;AAE1C,SAAO,YAAY,KAAK,UAAU,CAC/B,QAAQ,MAAM,0BAA0B,KAAK,EAAE,CAAC,CAChD,MAAM,CACN,SAAS,CACT,KAAK,MAAM,KAAK,KAAK,WAAW,EAAE,CAAC;;;CAIxC,mBAA2B;EACzB,MAAM,QAAkB,EAAE;EAE1B,MAAM,WAAW,KAAK,cAAc;AACpC,MAAI,SACF,OAAM,KAAK,0BAA0B,SAAS;EAGhD,MAAM,QAAQ,KAAK,WAAW;AAC9B,MAAI,MACF,OAAM,KAAK,uBAAuB,MAAM;AAG1C,SAAO,MAAM,KAAK,OAAO"}
@@ -0,0 +1,43 @@
1
+ //#region src/agent/skills.d.ts
2
+ interface SkillInfo {
3
+ name: string;
4
+ path: string;
5
+ source: "workspace" | "builtin";
6
+ }
7
+ interface SkillMeta {
8
+ description?: string;
9
+ always?: string;
10
+ metadata?: string;
11
+ [key: string]: string | undefined;
12
+ }
13
+ /**
14
+ * Loader for agent skills.
15
+ * Skills are markdown files (SKILL.md) that teach the agent specific capabilities.
16
+ */
17
+ declare class SkillsLoader {
18
+ private workspace;
19
+ private workspaceSkills;
20
+ private builtinSkills;
21
+ constructor(workspace: string, builtinSkillsDir?: string);
22
+ /** List all available skills. */
23
+ listSkills(filterUnavailable?: boolean): SkillInfo[];
24
+ /** Load a skill by name. */
25
+ loadSkill(name: string): string | null;
26
+ /** Load specific skills for inclusion in agent context. */
27
+ loadSkillsForContext(skillNames: string[]): string;
28
+ /** Build a summary of all skills. */
29
+ buildSkillsSummary(): string;
30
+ /** Get skills marked as always=true. */
31
+ getAlwaysSkills(): string[];
32
+ /** Get metadata from a skill's frontmatter. */
33
+ getSkillMetadata(name: string): SkillMeta | null;
34
+ private stripFrontmatter;
35
+ private parseNanobotMetadata;
36
+ private checkRequirements;
37
+ private getSkillMeta;
38
+ private getSkillDescription;
39
+ private getMissingRequirements;
40
+ }
41
+ //#endregion
42
+ export { SkillsLoader };
43
+ //# sourceMappingURL=skills.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.mts","names":[],"sources":["../../src/agent/skills.ts"],"mappings":";UAWU,SAAA;EACR,IAAA;EACA,IAAA;EACA,MAAA;AAAA;AAAA,UAGQ,SAAA;EACR,WAAA;EACA,MAAA;EACA,QAAA;EAAA,CACC,GAAA;AAAA;;;;;cAOU,YAAA;EAAA,QACH,SAAA;EAAA,QACA,eAAA;EAAA,QACA,aAAA;cAEI,SAAA,UAAmB,gBAAA;EALpB;EAYX,UAAA,CAAW,iBAAA,aAA2B,SAAA;;EAsCtC,SAAA,CAAU,IAAA;EAjDF;EAgER,oBAAA,CAAqB,UAAA;EA9Db;EA2ER,kBAAA,CAAA;EAzEY;EA0GZ,eAAA,CAAA;EAnGA;EAgHA,gBAAA,CAAiB,IAAA,WAAe,SAAA;EAAA,QAsBxB,gBAAA;EAAA,QAQA,oBAAA;EAAA,QAWA,iBAAA;EAAA,QAWA,YAAA;EAAA,QAKA,mBAAA;EAAA,QAKA,sBAAA;AAAA"}
@@ -0,0 +1,159 @@
1
+ import { which } from "../utils/which.mjs";
2
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+
5
+ //#region src/agent/skills.ts
6
+ /** Default builtin skills directory (relative to this file in dist). */
7
+ function getBuiltinSkillsDir() {
8
+ return join(dirname(dirname(__dirname)), "skills");
9
+ }
10
+ /**
11
+ * Loader for agent skills.
12
+ * Skills are markdown files (SKILL.md) that teach the agent specific capabilities.
13
+ */
14
+ var SkillsLoader = class {
15
+ workspace;
16
+ workspaceSkills;
17
+ builtinSkills;
18
+ constructor(workspace, builtinSkillsDir) {
19
+ this.workspace = workspace;
20
+ this.workspaceSkills = join(workspace, "skills");
21
+ this.builtinSkills = builtinSkillsDir ?? getBuiltinSkillsDir();
22
+ }
23
+ /** List all available skills. */
24
+ listSkills(filterUnavailable = true) {
25
+ const skills = [];
26
+ if (existsSync(this.workspaceSkills)) for (const entry of readdirSync(this.workspaceSkills)) {
27
+ const skillDir = join(this.workspaceSkills, entry);
28
+ const skillFile = join(skillDir, "SKILL.md");
29
+ if (statSync(skillDir).isDirectory() && existsSync(skillFile)) skills.push({
30
+ name: entry,
31
+ path: skillFile,
32
+ source: "workspace"
33
+ });
34
+ }
35
+ if (existsSync(this.builtinSkills)) for (const entry of readdirSync(this.builtinSkills)) {
36
+ const skillDir = join(this.builtinSkills, entry);
37
+ const skillFile = join(skillDir, "SKILL.md");
38
+ if (statSync(skillDir).isDirectory() && existsSync(skillFile) && !skills.some((s) => s.name === entry)) skills.push({
39
+ name: entry,
40
+ path: skillFile,
41
+ source: "builtin"
42
+ });
43
+ }
44
+ if (filterUnavailable) return skills.filter((s) => this.checkRequirements(this.getSkillMeta(s.name)));
45
+ return skills;
46
+ }
47
+ /** Load a skill by name. */
48
+ loadSkill(name) {
49
+ const wsSkill = join(this.workspaceSkills, name, "SKILL.md");
50
+ if (existsSync(wsSkill)) return readFileSync(wsSkill, "utf-8");
51
+ const builtinSkill = join(this.builtinSkills, name, "SKILL.md");
52
+ if (existsSync(builtinSkill)) return readFileSync(builtinSkill, "utf-8");
53
+ return null;
54
+ }
55
+ /** Load specific skills for inclusion in agent context. */
56
+ loadSkillsForContext(skillNames) {
57
+ const parts = [];
58
+ for (const name of skillNames) {
59
+ const content = this.loadSkill(name);
60
+ if (content) {
61
+ const stripped = this.stripFrontmatter(content);
62
+ parts.push(`### Skill: ${name}\n\n${stripped}`);
63
+ }
64
+ }
65
+ return parts.join("\n\n---\n\n");
66
+ }
67
+ /** Build a summary of all skills. */
68
+ buildSkillsSummary() {
69
+ const allSkills = this.listSkills(false);
70
+ if (allSkills.length === 0) return "";
71
+ const escapeXml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
72
+ const lines = ["<skills>"];
73
+ for (const s of allSkills) {
74
+ const name = escapeXml(s.name);
75
+ const desc = escapeXml(this.getSkillDescription(s.name));
76
+ const meta = this.getSkillMeta(s.name);
77
+ const available = this.checkRequirements(meta);
78
+ lines.push(` <skill available="${available}">`);
79
+ lines.push(` <name>${name}</name>`);
80
+ lines.push(` <description>${desc}</description>`);
81
+ lines.push(` <location>${s.path}</location>`);
82
+ if (!available) {
83
+ const missing = this.getMissingRequirements(meta);
84
+ if (missing) lines.push(` <requires>${escapeXml(missing)}</requires>`);
85
+ }
86
+ lines.push(" </skill>");
87
+ }
88
+ lines.push("</skills>");
89
+ return lines.join("\n");
90
+ }
91
+ /** Get skills marked as always=true. */
92
+ getAlwaysSkills() {
93
+ const result = [];
94
+ for (const s of this.listSkills(true)) {
95
+ const meta = this.getSkillMetadata(s.name);
96
+ if (this.parseNanobotMetadata(meta?.metadata ?? "").always || meta?.always) result.push(s.name);
97
+ }
98
+ return result;
99
+ }
100
+ /** Get metadata from a skill's frontmatter. */
101
+ getSkillMetadata(name) {
102
+ const content = this.loadSkill(name);
103
+ if (!content) return null;
104
+ if (content.startsWith("---")) {
105
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
106
+ if (match) {
107
+ const metadata = {};
108
+ for (const line of match[1].split("\n")) {
109
+ const colonIdx = line.indexOf(":");
110
+ if (colonIdx !== -1) {
111
+ const key = line.slice(0, colonIdx).trim();
112
+ metadata[key] = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, "");
113
+ }
114
+ }
115
+ return metadata;
116
+ }
117
+ }
118
+ return null;
119
+ }
120
+ stripFrontmatter(content) {
121
+ if (content.startsWith("---")) {
122
+ const match = content.match(/^---\n[\s\S]*?\n---\n/);
123
+ if (match) return content.slice(match[0].length).trim();
124
+ }
125
+ return content;
126
+ }
127
+ parseNanobotMetadata(raw) {
128
+ try {
129
+ const data = JSON.parse(raw);
130
+ return typeof data === "object" && data !== null ? data.nanobot ?? {} : {};
131
+ } catch {
132
+ return {};
133
+ }
134
+ }
135
+ checkRequirements(meta) {
136
+ const requires = meta.requires ?? {};
137
+ for (const bin of requires.bins ?? []) if (!which(bin)) return false;
138
+ for (const env of requires.env ?? []) if (!process.env[env]) return false;
139
+ return true;
140
+ }
141
+ getSkillMeta(name) {
142
+ const meta = this.getSkillMetadata(name) ?? {};
143
+ return this.parseNanobotMetadata(String(meta.metadata ?? ""));
144
+ }
145
+ getSkillDescription(name) {
146
+ return this.getSkillMetadata(name)?.description ?? name;
147
+ }
148
+ getMissingRequirements(meta) {
149
+ const missing = [];
150
+ const requires = meta.requires ?? {};
151
+ for (const bin of requires.bins ?? []) if (!which(bin)) missing.push(`CLI: ${bin}`);
152
+ for (const env of requires.env ?? []) if (!process.env[env]) missing.push(`ENV: ${env}`);
153
+ return missing.join(", ");
154
+ }
155
+ };
156
+
157
+ //#endregion
158
+ export { SkillsLoader };
159
+ //# sourceMappingURL=skills.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.mjs","names":[],"sources":["../../src/agent/skills.ts"],"sourcesContent":["import { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { which } from \"../utils/which.js\";\n\n/** Default builtin skills directory (relative to this file in dist). */\nfunction getBuiltinSkillsDir(): string {\n // In dist: dist/agent/skills.js -> ../../skills\n // In src: src/agent/skills.ts -> ../../skills\n return join(dirname(dirname(__dirname)), \"skills\");\n}\n\ninterface SkillInfo {\n name: string;\n path: string;\n source: \"workspace\" | \"builtin\";\n}\n\ninterface SkillMeta {\n description?: string;\n always?: string;\n metadata?: string;\n [key: string]: string | undefined;\n}\n\n/**\n * Loader for agent skills.\n * Skills are markdown files (SKILL.md) that teach the agent specific capabilities.\n */\nexport class SkillsLoader {\n private workspace: string;\n private workspaceSkills: string;\n private builtinSkills: string;\n\n constructor(workspace: string, builtinSkillsDir?: string) {\n this.workspace = workspace;\n this.workspaceSkills = join(workspace, \"skills\");\n this.builtinSkills = builtinSkillsDir ?? getBuiltinSkillsDir();\n }\n\n /** List all available skills. */\n listSkills(filterUnavailable = true): SkillInfo[] {\n const skills: SkillInfo[] = [];\n\n // Workspace skills (highest priority)\n if (existsSync(this.workspaceSkills)) {\n for (const entry of readdirSync(this.workspaceSkills)) {\n const skillDir = join(this.workspaceSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (statSync(skillDir).isDirectory() && existsSync(skillFile)) {\n skills.push({ name: entry, path: skillFile, source: \"workspace\" });\n }\n }\n }\n\n // Built-in skills\n if (existsSync(this.builtinSkills)) {\n for (const entry of readdirSync(this.builtinSkills)) {\n const skillDir = join(this.builtinSkills, entry);\n const skillFile = join(skillDir, \"SKILL.md\");\n if (\n statSync(skillDir).isDirectory() &&\n existsSync(skillFile) &&\n !skills.some((s) => s.name === entry)\n ) {\n skills.push({ name: entry, path: skillFile, source: \"builtin\" });\n }\n }\n }\n\n if (filterUnavailable) {\n return skills.filter((s) =>\n this.checkRequirements(this.getSkillMeta(s.name)),\n );\n }\n return skills;\n }\n\n /** Load a skill by name. */\n loadSkill(name: string): string | null {\n const wsSkill = join(this.workspaceSkills, name, \"SKILL.md\");\n if (existsSync(wsSkill)) {\n return readFileSync(wsSkill, \"utf-8\");\n }\n\n const builtinSkill = join(this.builtinSkills, name, \"SKILL.md\");\n if (existsSync(builtinSkill)) {\n return readFileSync(builtinSkill, \"utf-8\");\n }\n\n return null;\n }\n\n /** Load specific skills for inclusion in agent context. */\n loadSkillsForContext(skillNames: string[]): string {\n const parts: string[] = [];\n for (const name of skillNames) {\n const content = this.loadSkill(name);\n if (content) {\n const stripped = this.stripFrontmatter(content);\n parts.push(`### Skill: ${name}\\n\\n${stripped}`);\n }\n }\n return parts.join(\"\\n\\n---\\n\\n\");\n }\n\n /** Build a summary of all skills. */\n buildSkillsSummary(): string {\n const allSkills = this.listSkills(false);\n if (allSkills.length === 0) return \"\";\n\n const escapeXml = (s: string) =>\n s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\n const lines = [\"<skills>\"];\n for (const s of allSkills) {\n const name = escapeXml(s.name);\n const desc = escapeXml(this.getSkillDescription(s.name));\n const meta = this.getSkillMeta(s.name);\n const available = this.checkRequirements(meta);\n\n lines.push(` <skill available=\"${available}\">`);\n lines.push(` <name>${name}</name>`);\n lines.push(` <description>${desc}</description>`);\n lines.push(` <location>${s.path}</location>`);\n\n if (!available) {\n const missing = this.getMissingRequirements(meta);\n if (missing) {\n lines.push(` <requires>${escapeXml(missing)}</requires>`);\n }\n }\n\n lines.push(\" </skill>\");\n }\n lines.push(\"</skills>\");\n return lines.join(\"\\n\");\n }\n\n /** Get skills marked as always=true. */\n getAlwaysSkills(): string[] {\n const result: string[] = [];\n for (const s of this.listSkills(true)) {\n const meta = this.getSkillMetadata(s.name);\n const skillMeta = this.parseNanobotMetadata(meta?.metadata ?? \"\");\n if (skillMeta.always || meta?.always) {\n result.push(s.name);\n }\n }\n return result;\n }\n\n /** Get metadata from a skill's frontmatter. */\n getSkillMetadata(name: string): SkillMeta | null {\n const content = this.loadSkill(name);\n if (!content) return null;\n\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (match) {\n const metadata: SkillMeta = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx !== -1) {\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim().replace(/^[\"']|[\"']$/g, \"\");\n metadata[key] = value;\n }\n }\n return metadata;\n }\n }\n return null;\n }\n\n private stripFrontmatter(content: string): string {\n if (content.startsWith(\"---\")) {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n/);\n if (match) return content.slice(match[0].length).trim();\n }\n return content;\n }\n\n private parseNanobotMetadata(raw: string): Record<string, unknown> {\n try {\n const data = JSON.parse(raw);\n return typeof data === \"object\" && data !== null\n ? (data.nanobot ?? {})\n : {};\n } catch {\n return {};\n }\n }\n\n private checkRequirements(meta: Record<string, unknown>): boolean {\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) return false;\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) return false;\n }\n return true;\n }\n\n private getSkillMeta(name: string): Record<string, unknown> {\n const meta = this.getSkillMetadata(name) ?? {};\n return this.parseNanobotMetadata(String(meta.metadata ?? \"\"));\n }\n\n private getSkillDescription(name: string): string {\n const meta = this.getSkillMetadata(name);\n return meta?.description ?? name;\n }\n\n private getMissingRequirements(meta: Record<string, unknown>): string {\n const missing: string[] = [];\n const requires = (meta.requires ?? {}) as Record<string, string[]>;\n for (const bin of requires.bins ?? []) {\n if (!which(bin)) missing.push(`CLI: ${bin}`);\n }\n for (const env of requires.env ?? []) {\n if (!process.env[env]) missing.push(`ENV: ${env}`);\n }\n return missing.join(\", \");\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { LLMProvider } from "../providers/base.mjs";
2
+ import { MessageBus } from "../bus/queue.mjs";
3
+ import { ExecToolConfig } from "../config/schema.mjs";
4
+
5
+ //#region src/agent/subagent.d.ts
6
+ /**
7
+ * Manages background subagent execution.
8
+ */
9
+ declare class SubagentManager {
10
+ private provider;
11
+ private workspace;
12
+ private bus;
13
+ private model;
14
+ private braveApiKey?;
15
+ private execConfig;
16
+ private runningTasks;
17
+ constructor(params: {
18
+ provider: LLMProvider;
19
+ workspace: string;
20
+ bus: MessageBus;
21
+ model?: string;
22
+ braveApiKey?: string;
23
+ execConfig?: ExecToolConfig;
24
+ });
25
+ /** Spawn a subagent to execute a task in the background. */
26
+ spawn(params: {
27
+ task: string;
28
+ label?: string;
29
+ originChannel?: string;
30
+ originChatId?: string;
31
+ }): Promise<string>;
32
+ private runSubagent;
33
+ private announceResult;
34
+ private buildSubagentPrompt;
35
+ get runningCount(): number;
36
+ }
37
+ //#endregion
38
+ export { SubagentManager };
39
+ //# sourceMappingURL=subagent.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent.d.mts","names":[],"sources":["../../src/agent/subagent.ts"],"mappings":";;;;;;;AAaA;cAAa,eAAA;EAAA,QACH,QAAA;EAAA,QACA,SAAA;EAAA,QACA,GAAA;EAAA,QACA,KAAA;EAAA,QACA,WAAA;EAAA,QACA,UAAA;EAAA,QACA,YAAA;cAEI,MAAA;IACV,QAAA,EAAU,WAAA;IACV,SAAA;IACA,GAAA,EAAK,UAAA;IACL,KAAA;IACA,WAAA;IACA,UAAA,GAAa,cAAA;EAAA;EALb;EAgBI,KAAA,CAAM,MAAA;IACV,IAAA;IACA,KAAA;IACA,aAAA;IACA,YAAA;EAAA,IACE,OAAA;EAAA,QAwBU,WAAA;EAAA,QA2FA,cAAA;EAAA,QA8BN,mBAAA;EAAA,IA+BJ,YAAA,CAAA;AAAA"}