botinabox 2.16.5 → 2.16.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2101,6 +2101,144 @@ ${list}`);
2101
2101
  return sections.join("\n\n");
2102
2102
  }
2103
2103
 
2104
+ // src/core/orchestrator/execution-engine.ts
2105
+ function formatContextFilesBlock(files) {
2106
+ if (!files || files.length === 0) return "";
2107
+ return files.map((f) => `<file path="${f.path}">
2108
+ ${f.content}
2109
+ </file>`).join("\n\n");
2110
+ }
2111
+ async function registerExecutionEngine(opts) {
2112
+ const { db, hooks, runs, config } = opts;
2113
+ const model = config.model ?? "claude-sonnet-4-20250514";
2114
+ const maxIterations = config.maxIterations ?? 5;
2115
+ const includeContext = config.includeSystemContext ?? true;
2116
+ const systemContext = includeContext ? await buildSystemContext(db) : "";
2117
+ const toolDefs = (config.tools ?? []).map((t) => t.definition);
2118
+ const toolHandlers = new Map(
2119
+ (config.tools ?? []).map((t) => [t.definition.name, t.handler])
2120
+ );
2121
+ async function tryExecuteTask(taskId, hintAgentId) {
2122
+ const task = await db.get("tasks", { id: taskId });
2123
+ if (!task || task.status !== "todo") return;
2124
+ const nextRetryAt = task["next_retry_at"];
2125
+ if (nextRetryAt && new Date(nextRetryAt) > /* @__PURE__ */ new Date()) return;
2126
+ const assigneeId = hintAgentId ?? task.assignee_id;
2127
+ if (!assigneeId) return;
2128
+ if (runs.isLocked(assigneeId)) return;
2129
+ const agent = await db.get("agents", { id: assigneeId });
2130
+ if (!agent) return;
2131
+ let runId;
2132
+ try {
2133
+ runId = await runs.startRun(assigneeId, taskId, "api");
2134
+ } catch {
2135
+ return;
2136
+ }
2137
+ const prompt = task.description ?? task.title ?? "";
2138
+ try {
2139
+ const taskModel = config.resolveModel ? config.resolveModel({ agent, task }) ?? model : model;
2140
+ const contextFiles = config.resolveContextFiles ? await config.resolveContextFiles({ agent, task }) : [];
2141
+ const contextFilesBlock = formatContextFilesBlock(contextFiles);
2142
+ const toolListing = toolDefs.length > 0 ? `
2143
+ ## Available Tools
2144
+ ${toolDefs.map((t) => `- **${t.name}**: ${t.description}`).join("\n")}
2145
+
2146
+ Use your tools to take action. Do NOT describe what you would do \u2014 call the tool.` : "";
2147
+ const systemPrompt = [
2148
+ `You are ${agent.name}, an AI agent with role: ${agent.role}.`,
2149
+ systemContext ? `
2150
+ ${systemContext}` : "",
2151
+ contextFilesBlock ? `
2152
+ ${contextFilesBlock}` : "",
2153
+ toolListing,
2154
+ config.systemPromptSuffix ?? ""
2155
+ ].filter(Boolean).join("\n");
2156
+ const messages = [{ role: "user", content: prompt }];
2157
+ let finalOutput = "";
2158
+ let totalInput = 0;
2159
+ let totalOutput = 0;
2160
+ const systemField = config.cacheSystemPrompt ? [
2161
+ {
2162
+ type: "text",
2163
+ text: systemPrompt,
2164
+ cache_control: { type: "ephemeral" }
2165
+ }
2166
+ ] : systemPrompt;
2167
+ for (let i = 0; i < maxIterations; i++) {
2168
+ const createParams = {
2169
+ model: taskModel,
2170
+ max_tokens: 4096,
2171
+ system: systemField,
2172
+ messages
2173
+ };
2174
+ if (toolDefs.length > 0) {
2175
+ createParams.tools = toolDefs;
2176
+ createParams.tool_choice = i === 0 ? { type: "any" } : { type: "auto" };
2177
+ }
2178
+ const response = await config.client.messages.create(createParams);
2179
+ totalInput += response.usage.input_tokens;
2180
+ totalOutput += response.usage.output_tokens;
2181
+ const textBlocks = response.content.filter((b) => b.type === "text").map((b) => b.text ?? "");
2182
+ if (textBlocks.length > 0) finalOutput += textBlocks.join("");
2183
+ if (response.stop_reason !== "tool_use") break;
2184
+ const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
2185
+ const toolResults = [];
2186
+ for (const toolUse of toolUseBlocks) {
2187
+ const handler = toolHandlers.get(toolUse.name);
2188
+ if (handler) {
2189
+ try {
2190
+ const result = await handler(
2191
+ toolUse.input,
2192
+ { taskId, agentId: assigneeId, hooks, db, resolveFilePath: config.resolveFilePath }
2193
+ );
2194
+ toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
2195
+ } catch (err) {
2196
+ toolResults.push({
2197
+ type: "tool_result",
2198
+ tool_use_id: toolUse.id,
2199
+ content: `Error: ${err instanceof Error ? err.message : String(err)}`
2200
+ });
2201
+ }
2202
+ }
2203
+ }
2204
+ messages.push({ role: "assistant", content: response.content });
2205
+ messages.push({ role: "user", content: toolResults });
2206
+ }
2207
+ const costCents = Math.round((totalInput * 0.3 + totalOutput * 1.5) / 100);
2208
+ await runs.finishRun(runId, {
2209
+ exitCode: 0,
2210
+ output: finalOutput,
2211
+ costCents,
2212
+ usage: { inputTokens: totalInput, outputTokens: totalOutput },
2213
+ model: taskModel,
2214
+ provider: "anthropic"
2215
+ });
2216
+ } catch (err) {
2217
+ const msg = err instanceof Error ? err.message : String(err);
2218
+ await runs.finishRun(runId, { exitCode: 1, output: `Execution error: ${msg}` });
2219
+ }
2220
+ }
2221
+ hooks.register("task.created", async (ctx) => {
2222
+ const taskId = ctx.id ?? ctx.taskId;
2223
+ if (!taskId) return;
2224
+ await tryExecuteTask(taskId);
2225
+ });
2226
+ hooks.register("agent.wakeup", async (ctx) => {
2227
+ const taskId = ctx.taskId;
2228
+ const agentId = ctx.agentId;
2229
+ if (!taskId) return;
2230
+ await tryExecuteTask(taskId, agentId);
2231
+ });
2232
+ hooks.register("run.completed", async (ctx) => {
2233
+ const agentId = ctx.agentId;
2234
+ if (!agentId) return;
2235
+ const pendingTasks = (await db.query("tasks", { where: { status: "todo" } })).filter((t) => t["assignee_id"] === agentId).sort((a, b) => a["priority"] - b["priority"]);
2236
+ if (pendingTasks.length > 0) {
2237
+ await tryExecuteTask(pendingTasks[0]["id"], agentId);
2238
+ }
2239
+ });
2240
+ }
2241
+
2104
2242
  // src/core/chat/chat-pipeline-v2.ts
2105
2243
  var DEFAULT_DEDUP_WINDOW_MS2 = 5 * 60 * 1e3;
2106
2244
  var DEFAULT_MAX_ITERATIONS = 5;
@@ -2193,6 +2331,19 @@ var ChatPipelineV2 = class {
2193
2331
  if (ctx2) systemPrompt += `
2194
2332
 
2195
2333
  ${ctx2}`;
2334
+ }
2335
+ if (this.config.resolveContextFiles) {
2336
+ const contextFiles = await this.config.resolveContextFiles({
2337
+ channelId,
2338
+ threadId: threadTs,
2339
+ userId: msg.from,
2340
+ messageText: msg.body,
2341
+ channel: this.channel
2342
+ });
2343
+ const contextFilesBlock = formatContextFilesBlock(contextFiles);
2344
+ if (contextFilesBlock) systemPrompt += `
2345
+
2346
+ ${contextFilesBlock}`;
2196
2347
  }
2197
2348
  const { text, tasksDispatched } = await this.think(
2198
2349
  systemPrompt,
@@ -6592,144 +6743,6 @@ var GateRunner = class {
6592
6743
  }
6593
6744
  };
6594
6745
 
6595
- // src/core/orchestrator/execution-engine.ts
6596
- function formatContextFilesBlock(files) {
6597
- if (!files || files.length === 0) return "";
6598
- return files.map((f) => `<file path="${f.path}">
6599
- ${f.content}
6600
- </file>`).join("\n\n");
6601
- }
6602
- async function registerExecutionEngine(opts) {
6603
- const { db, hooks, runs, config } = opts;
6604
- const model = config.model ?? "claude-sonnet-4-20250514";
6605
- const maxIterations = config.maxIterations ?? 5;
6606
- const includeContext = config.includeSystemContext ?? true;
6607
- const systemContext = includeContext ? await buildSystemContext(db) : "";
6608
- const toolDefs = (config.tools ?? []).map((t) => t.definition);
6609
- const toolHandlers = new Map(
6610
- (config.tools ?? []).map((t) => [t.definition.name, t.handler])
6611
- );
6612
- async function tryExecuteTask(taskId, hintAgentId) {
6613
- const task = await db.get("tasks", { id: taskId });
6614
- if (!task || task.status !== "todo") return;
6615
- const nextRetryAt = task["next_retry_at"];
6616
- if (nextRetryAt && new Date(nextRetryAt) > /* @__PURE__ */ new Date()) return;
6617
- const assigneeId = hintAgentId ?? task.assignee_id;
6618
- if (!assigneeId) return;
6619
- if (runs.isLocked(assigneeId)) return;
6620
- const agent = await db.get("agents", { id: assigneeId });
6621
- if (!agent) return;
6622
- let runId;
6623
- try {
6624
- runId = await runs.startRun(assigneeId, taskId, "api");
6625
- } catch {
6626
- return;
6627
- }
6628
- const prompt = task.description ?? task.title ?? "";
6629
- try {
6630
- const taskModel = config.resolveModel ? config.resolveModel({ agent, task }) ?? model : model;
6631
- const contextFiles = config.resolveContextFiles ? await config.resolveContextFiles({ agent, task }) : [];
6632
- const contextFilesBlock = formatContextFilesBlock(contextFiles);
6633
- const toolListing = toolDefs.length > 0 ? `
6634
- ## Available Tools
6635
- ${toolDefs.map((t) => `- **${t.name}**: ${t.description}`).join("\n")}
6636
-
6637
- Use your tools to take action. Do NOT describe what you would do \u2014 call the tool.` : "";
6638
- const systemPrompt = [
6639
- `You are ${agent.name}, an AI agent with role: ${agent.role}.`,
6640
- systemContext ? `
6641
- ${systemContext}` : "",
6642
- contextFilesBlock ? `
6643
- ${contextFilesBlock}` : "",
6644
- toolListing,
6645
- config.systemPromptSuffix ?? ""
6646
- ].filter(Boolean).join("\n");
6647
- const messages = [{ role: "user", content: prompt }];
6648
- let finalOutput = "";
6649
- let totalInput = 0;
6650
- let totalOutput = 0;
6651
- const systemField = config.cacheSystemPrompt ? [
6652
- {
6653
- type: "text",
6654
- text: systemPrompt,
6655
- cache_control: { type: "ephemeral" }
6656
- }
6657
- ] : systemPrompt;
6658
- for (let i = 0; i < maxIterations; i++) {
6659
- const createParams = {
6660
- model: taskModel,
6661
- max_tokens: 4096,
6662
- system: systemField,
6663
- messages
6664
- };
6665
- if (toolDefs.length > 0) {
6666
- createParams.tools = toolDefs;
6667
- createParams.tool_choice = i === 0 ? { type: "any" } : { type: "auto" };
6668
- }
6669
- const response = await config.client.messages.create(createParams);
6670
- totalInput += response.usage.input_tokens;
6671
- totalOutput += response.usage.output_tokens;
6672
- const textBlocks = response.content.filter((b) => b.type === "text").map((b) => b.text ?? "");
6673
- if (textBlocks.length > 0) finalOutput += textBlocks.join("");
6674
- if (response.stop_reason !== "tool_use") break;
6675
- const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
6676
- const toolResults = [];
6677
- for (const toolUse of toolUseBlocks) {
6678
- const handler = toolHandlers.get(toolUse.name);
6679
- if (handler) {
6680
- try {
6681
- const result = await handler(
6682
- toolUse.input,
6683
- { taskId, agentId: assigneeId, hooks, db, resolveFilePath: config.resolveFilePath }
6684
- );
6685
- toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
6686
- } catch (err) {
6687
- toolResults.push({
6688
- type: "tool_result",
6689
- tool_use_id: toolUse.id,
6690
- content: `Error: ${err instanceof Error ? err.message : String(err)}`
6691
- });
6692
- }
6693
- }
6694
- }
6695
- messages.push({ role: "assistant", content: response.content });
6696
- messages.push({ role: "user", content: toolResults });
6697
- }
6698
- const costCents = Math.round((totalInput * 0.3 + totalOutput * 1.5) / 100);
6699
- await runs.finishRun(runId, {
6700
- exitCode: 0,
6701
- output: finalOutput,
6702
- costCents,
6703
- usage: { inputTokens: totalInput, outputTokens: totalOutput },
6704
- model: taskModel,
6705
- provider: "anthropic"
6706
- });
6707
- } catch (err) {
6708
- const msg = err instanceof Error ? err.message : String(err);
6709
- await runs.finishRun(runId, { exitCode: 1, output: `Execution error: ${msg}` });
6710
- }
6711
- }
6712
- hooks.register("task.created", async (ctx) => {
6713
- const taskId = ctx.id ?? ctx.taskId;
6714
- if (!taskId) return;
6715
- await tryExecuteTask(taskId);
6716
- });
6717
- hooks.register("agent.wakeup", async (ctx) => {
6718
- const taskId = ctx.taskId;
6719
- const agentId = ctx.agentId;
6720
- if (!taskId) return;
6721
- await tryExecuteTask(taskId, agentId);
6722
- });
6723
- hooks.register("run.completed", async (ctx) => {
6724
- const agentId = ctx.agentId;
6725
- if (!agentId) return;
6726
- const pendingTasks = (await db.query("tasks", { where: { status: "todo" } })).filter((t) => t["assignee_id"] === agentId).sort((a, b) => a["priority"] - b["priority"]);
6727
- if (pendingTasks.length > 0) {
6728
- await tryExecuteTask(pendingTasks[0]["id"], agentId);
6729
- }
6730
- });
6731
- }
6732
-
6733
6746
  // src/core/orchestrator/tools/send-file.ts
6734
6747
  import { existsSync as existsSync3 } from "fs";
6735
6748
  import { basename } from "path";
package/package.json CHANGED
@@ -1,100 +1,100 @@
1
- {
2
- "name": "botinabox",
3
- "version": "2.16.5",
4
- "description": "Bot in a Box — framework for building multi-agent bots",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- },
13
- "./anthropic": {
14
- "import": "./dist/providers/anthropic/index.js",
15
- "types": "./dist/providers/anthropic/index.d.ts"
16
- },
17
- "./openai": {
18
- "import": "./dist/providers/openai/index.js",
19
- "types": "./dist/providers/openai/index.d.ts"
20
- },
21
- "./ollama": {
22
- "import": "./dist/providers/ollama/index.js",
23
- "types": "./dist/providers/ollama/index.d.ts"
24
- },
25
- "./slack": {
26
- "import": "./dist/channels/slack/index.js",
27
- "types": "./dist/channels/slack/index.d.ts"
28
- },
29
- "./discord": {
30
- "import": "./dist/channels/discord/index.js",
31
- "types": "./dist/channels/discord/index.d.ts"
32
- },
33
- "./webhook": {
34
- "import": "./dist/channels/webhook/index.js",
35
- "types": "./dist/channels/webhook/index.d.ts"
36
- },
37
- "./google": {
38
- "import": "./dist/connectors/google/index.js",
39
- "types": "./dist/connectors/google/index.d.ts"
40
- }
41
- },
42
- "bin": {
43
- "botinabox": "./bin/botinabox.mjs"
44
- },
45
- "files": [
46
- "dist",
47
- "bin"
48
- ],
49
- "engines": {
50
- "node": ">=18"
51
- },
52
- "scripts": {
53
- "build": "tsup && tsc --emitDeclarationOnly",
54
- "test": "vitest run",
55
- "typecheck": "tsc --noEmit",
56
- "check-docs": "echo 'Documentation check passed'",
57
- "prepublishOnly": "npm run build && npm run typecheck && npm test"
58
- },
59
- "dependencies": {
60
- "@types/uuid": "^10.0.0",
61
- "ajv": "^8.17.1",
62
- "cron-parser": "^4.9.0",
63
- "latticesql": "^1.13.9",
64
- "uuid": "^13.0.0",
65
- "yaml": "^2.7.0"
66
- },
67
- "optionalDependencies": {
68
- "whisper-node": "^1.1.1"
69
- },
70
- "peerDependencies": {
71
- "@anthropic-ai/sdk": "^0.52.0",
72
- "googleapis": ">=140.0.0 <200.0.0",
73
- "openai": "^4.104.0"
74
- },
75
- "peerDependenciesMeta": {
76
- "@anthropic-ai/sdk": {
77
- "optional": true
78
- },
79
- "openai": {
80
- "optional": true
81
- },
82
- "googleapis": {
83
- "optional": true
84
- }
85
- },
86
- "repository": {
87
- "type": "git",
88
- "url": "https://github.com/automated-industries/botinabox.git"
89
- },
90
- "devDependencies": {
91
- "@anthropic-ai/sdk": "^0.52.0",
92
- "@types/better-sqlite3": "^7.6.12",
93
- "@types/node": "^22.10.0",
94
- "googleapis": "^171.4.0",
95
- "openai": "^4.104.0",
96
- "tsup": "^8.3.5",
97
- "typescript": "^5.7.2",
98
- "vitest": "^3.0.0"
99
- }
100
- }
1
+ {
2
+ "name": "botinabox",
3
+ "version": "2.16.6",
4
+ "description": "Bot in a Box — framework for building multi-agent bots",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./anthropic": {
14
+ "import": "./dist/providers/anthropic/index.js",
15
+ "types": "./dist/providers/anthropic/index.d.ts"
16
+ },
17
+ "./openai": {
18
+ "import": "./dist/providers/openai/index.js",
19
+ "types": "./dist/providers/openai/index.d.ts"
20
+ },
21
+ "./ollama": {
22
+ "import": "./dist/providers/ollama/index.js",
23
+ "types": "./dist/providers/ollama/index.d.ts"
24
+ },
25
+ "./slack": {
26
+ "import": "./dist/channels/slack/index.js",
27
+ "types": "./dist/channels/slack/index.d.ts"
28
+ },
29
+ "./discord": {
30
+ "import": "./dist/channels/discord/index.js",
31
+ "types": "./dist/channels/discord/index.d.ts"
32
+ },
33
+ "./webhook": {
34
+ "import": "./dist/channels/webhook/index.js",
35
+ "types": "./dist/channels/webhook/index.d.ts"
36
+ },
37
+ "./google": {
38
+ "import": "./dist/connectors/google/index.js",
39
+ "types": "./dist/connectors/google/index.d.ts"
40
+ }
41
+ },
42
+ "bin": {
43
+ "botinabox": "./bin/botinabox.mjs"
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "bin"
48
+ ],
49
+ "engines": {
50
+ "node": ">=18"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup && tsc --emitDeclarationOnly",
54
+ "test": "vitest run",
55
+ "typecheck": "tsc --noEmit",
56
+ "check-docs": "echo 'Documentation check passed'",
57
+ "prepublishOnly": "npm run build && npm run typecheck && npm test"
58
+ },
59
+ "dependencies": {
60
+ "@types/uuid": "^10.0.0",
61
+ "ajv": "^8.17.1",
62
+ "cron-parser": "^4.9.0",
63
+ "latticesql": "^1.13.9",
64
+ "uuid": "^13.0.0",
65
+ "yaml": "^2.7.0"
66
+ },
67
+ "optionalDependencies": {
68
+ "whisper-node": "^1.1.1"
69
+ },
70
+ "peerDependencies": {
71
+ "@anthropic-ai/sdk": "^0.52.0",
72
+ "googleapis": ">=140.0.0 <200.0.0",
73
+ "openai": "^4.104.0"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "@anthropic-ai/sdk": {
77
+ "optional": true
78
+ },
79
+ "openai": {
80
+ "optional": true
81
+ },
82
+ "googleapis": {
83
+ "optional": true
84
+ }
85
+ },
86
+ "repository": {
87
+ "type": "git",
88
+ "url": "https://github.com/automated-industries/botinabox.git"
89
+ },
90
+ "devDependencies": {
91
+ "@anthropic-ai/sdk": "^0.52.0",
92
+ "@types/better-sqlite3": "^7.6.12",
93
+ "@types/node": "^22.10.0",
94
+ "googleapis": "^171.4.0",
95
+ "openai": "^4.104.0",
96
+ "tsup": "^8.3.5",
97
+ "typescript": "^5.7.2",
98
+ "vitest": "^3.0.0"
99
+ }
100
+ }