botinabox 1.9.3 → 2.0.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.
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  parseDiscordEvent
3
3
  } from "../../chunk-DLJKZD3Q.js";
4
+ import "../../chunk-3RG5ZIWI.js";
4
5
 
5
6
  // src/channels/discord/outbound.ts
6
7
  var DISCORD_MAX_LENGTH = 2e3;
@@ -80,7 +81,7 @@ var DiscordAdapter = class {
80
81
  /** Simulate receiving an inbound message (for testing/webhooks). */
81
82
  async receive(event) {
82
83
  if (this.onMessage) {
83
- const { parseDiscordEvent: parseDiscordEvent2 } = await import("../../inbound-SNEMBLGA.js");
84
+ const { parseDiscordEvent: parseDiscordEvent2 } = await import("../../inbound-WU7X2HGA.js");
84
85
  const msg = parseDiscordEvent2(event);
85
86
  await this.onMessage(msg);
86
87
  }
@@ -8,6 +8,7 @@ import {
8
8
  import {
9
9
  chunkText
10
10
  } from "../../chunk-ZTZFPTOQ.js";
11
+ import "../../chunk-3RG5ZIWI.js";
11
12
 
12
13
  // src/channels/slack/outbound.ts
13
14
  function formatForSlack(text) {
@@ -70,8 +71,8 @@ var SlackAdapter = class {
70
71
  /** Simulate receiving an inbound message (for testing/webhooks). */
71
72
  async receive(event) {
72
73
  if (this.onMessage) {
73
- const { parseSlackEvent: parseSlackEvent2 } = await import("../../inbound-ZJHAYVMF.js");
74
- const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-ZJHAYVMF.js");
74
+ const { parseSlackEvent: parseSlackEvent2 } = await import("../../inbound-IBKXBFZF.js");
75
+ const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-IBKXBFZF.js");
75
76
  let msg = parseSlackEvent2(event);
76
77
  if (msg.body.includes("[Voice message") && this.config?.botToken) {
77
78
  msg = await enrichVoiceMessage2(msg, this.config.botToken);
@@ -94,7 +95,7 @@ var SlackBoltAdapter = class {
94
95
  async start() {
95
96
  const boltModule = "@slack/bolt";
96
97
  const bolt = await import(boltModule);
97
- const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-ZJHAYVMF.js");
98
+ const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-IBKXBFZF.js");
98
99
  const boltApp = new bolt.App({
99
100
  token: this.config.botToken,
100
101
  appToken: this.config.appToken,
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/channels/webhook/server.ts
2
4
  import { createServer } from "http";
3
5
 
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./chunk-3RG5ZIWI.js";
2
3
 
3
4
  // src/cli.ts
4
5
  import * as readline from "readline";
@@ -178,7 +179,7 @@ async function authGoogle(args) {
178
179
  });
179
180
  }
180
181
  };
181
- const { GoogleGmailConnector } = await import("./gmail-connector-ULSMN6X2.js");
182
+ const { GoogleGmailConnector } = await import("./gmail-connector-Z7SO6VOS.js");
182
183
  const connector = new GoogleGmailConnector({ tokenLoader, tokenSaver });
183
184
  connector.config = {
184
185
  account,
@@ -8,6 +8,7 @@ import {
8
8
  refreshIfNeeded,
9
9
  saveTokens
10
10
  } from "../../chunk-XYF5PSB2.js";
11
+ import "../../chunk-3RG5ZIWI.js";
11
12
 
12
13
  // src/connectors/google/calendar-connector.ts
13
14
  var GoogleCalendarConnector = class {
@@ -0,0 +1,7 @@
1
+ import {
2
+ GoogleGmailConnector
3
+ } from "./chunk-XYF5PSB2.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ GoogleGmailConnector
7
+ };
@@ -0,0 +1,11 @@
1
+ import {
2
+ enrichVoiceMessage,
3
+ extractVoiceTranscript,
4
+ parseSlackEvent
5
+ } from "./chunk-NNPCKR6G.js";
6
+ import "./chunk-3RG5ZIWI.js";
7
+ export {
8
+ enrichVoiceMessage,
9
+ extractVoiceTranscript,
10
+ parseSlackEvent
11
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ parseDiscordEvent
3
+ } from "./chunk-DLJKZD3Q.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ parseDiscordEvent
7
+ };
package/dist/index.d.ts CHANGED
@@ -1831,11 +1831,15 @@ interface ToolDefinition {
1831
1831
  description: string;
1832
1832
  input_schema: Record<string, unknown>;
1833
1833
  }
1834
- type ToolHandler = (input: Record<string, unknown>, context: {
1834
+ type ToolHandler = (input: Record<string, unknown>, context: ToolContext) => Promise<string>;
1835
+ interface ToolContext {
1835
1836
  taskId: string;
1836
1837
  agentId: string;
1837
1838
  hooks: HookBus;
1838
- }) => Promise<string>;
1839
+ db: DataStore;
1840
+ /** Resolve a relative file path to an absolute path (environment-aware). */
1841
+ resolveFilePath?: (path: string) => string;
1842
+ }
1839
1843
  interface ExecutionEngineConfig {
1840
1844
  /** Anthropic client instance */
1841
1845
  client: {
@@ -1869,6 +1873,8 @@ interface ExecutionEngineConfig {
1869
1873
  systemPromptSuffix?: string;
1870
1874
  /** Include system context (users, files, etc). Default: true */
1871
1875
  includeSystemContext?: boolean;
1876
+ /** Resolve file paths from DB-relative to absolute (for cross-environment support). */
1877
+ resolveFilePath?: (path: string) => string;
1872
1878
  }
1873
1879
  declare function registerExecutionEngine(opts: {
1874
1880
  db: DataStore;
@@ -1877,6 +1883,115 @@ declare function registerExecutionEngine(opts: {
1877
1883
  config: ExecutionEngineConfig;
1878
1884
  }): Promise<void>;
1879
1885
 
1886
+ declare const sendFileTool: {
1887
+ definition: ToolDefinition;
1888
+ handler: ToolHandler;
1889
+ };
1890
+
1891
+ declare const readFileTool: {
1892
+ definition: ToolDefinition;
1893
+ handler: ToolHandler;
1894
+ };
1895
+
1896
+ /**
1897
+ * Built-in tools: File operations — list, register, send, read.
1898
+ */
1899
+
1900
+ declare const listFilesTool: {
1901
+ definition: ToolDefinition;
1902
+ handler: ToolHandler;
1903
+ };
1904
+ declare const registerFileTool: {
1905
+ definition: ToolDefinition;
1906
+ handler: ToolHandler;
1907
+ };
1908
+
1909
+ declare const dispatchTaskTool: {
1910
+ definition: ToolDefinition;
1911
+ handler: ToolHandler;
1912
+ };
1913
+ declare const cancelTaskTool: {
1914
+ definition: ToolDefinition;
1915
+ handler: ToolHandler;
1916
+ };
1917
+ declare const reassignTaskTool: {
1918
+ definition: ToolDefinition;
1919
+ handler: ToolHandler;
1920
+ };
1921
+
1922
+ /**
1923
+ * Built-in tools: System awareness — task status, agent status, system health.
1924
+ */
1925
+
1926
+ declare const getTaskStatusTool: {
1927
+ definition: ToolDefinition;
1928
+ handler: ToolHandler;
1929
+ };
1930
+ declare const getAgentStatusTool: {
1931
+ definition: ToolDefinition;
1932
+ handler: ToolHandler;
1933
+ };
1934
+ declare const getSystemStatusTool: {
1935
+ definition: ToolDefinition;
1936
+ handler: ToolHandler;
1937
+ };
1938
+ declare const getActiveTasksTool: {
1939
+ definition: ToolDefinition;
1940
+ handler: ToolHandler;
1941
+ };
1942
+
1943
+ /**
1944
+ * Built-in tools: Entity lookup — agents, projects, details.
1945
+ */
1946
+
1947
+ declare const listAgentsTool: {
1948
+ definition: ToolDefinition;
1949
+ handler: ToolHandler;
1950
+ };
1951
+ declare const listProjectsTool: {
1952
+ definition: ToolDefinition;
1953
+ handler: ToolHandler;
1954
+ };
1955
+ declare const getAgentDetailTool: {
1956
+ definition: ToolDefinition;
1957
+ handler: ToolHandler;
1958
+ };
1959
+
1960
+ /**
1961
+ * Built-in tools: Communication — send messages, read conversations, search history.
1962
+ * All messaging is channel-agnostic: slack, email, discord, sms — same tools.
1963
+ */
1964
+
1965
+ declare const sendMessageTool: {
1966
+ definition: ToolDefinition;
1967
+ handler: ToolHandler;
1968
+ };
1969
+ declare const addTaskCommentTool: {
1970
+ definition: ToolDefinition;
1971
+ handler: ToolHandler;
1972
+ };
1973
+ declare const readConversationTool: {
1974
+ definition: ToolDefinition;
1975
+ handler: ToolHandler;
1976
+ };
1977
+ declare const searchConversationTool: {
1978
+ definition: ToolDefinition;
1979
+ handler: ToolHandler;
1980
+ };
1981
+
1982
+ /**
1983
+ * Built-in tools: Entity creation — agents, projects.
1984
+ */
1985
+
1986
+ declare const createAgentTool: {
1987
+ definition: ToolDefinition;
1988
+ handler: ToolHandler;
1989
+ };
1990
+ declare const createProjectTool: {
1991
+ definition: ToolDefinition;
1992
+ handler: ToolHandler;
1993
+ };
1994
+
1880
1995
  interface SecretInput {
1881
1996
  name: string;
1882
1997
  type?: string;
@@ -1965,4 +2080,4 @@ declare function isLoginRequired(stdout: string): boolean;
1965
2080
  /** Rewrite local image paths to prevent CLI auto-embedding as vision content. */
1966
2081
  declare function deactivateLocalImagePaths(prompt: string): string;
1967
2082
 
1968
- export { AGENT_STATUSES, type AgentConfig, type AgentDefinition, type AgentFilter, type AgentRecord, AgentRegistry, type AgentStatus, ApiExecutionAdapter, type ApprovalResponse, type ApprovalStatus, AuditEmitter, type AuditEvent, BackupManager, type BotConfig, BreakerState, type BudgetCheck, type BudgetConfig, BudgetController, CORE_MIGRATIONS, ChannelAdapter, ChannelRegistry, ChannelRegistryError, ChatMessage, ChatResponderConfig, ChatSessionManager, CircuitBreaker, type CircuitBreakerConfig, CliExecutionAdapter, type ColumnValidator, ColumnValidatorImpl, type ConfigLoadError, type ConfigLoadResult, ConnectorConfig, DEFAULTS, DEFAULT_CONFIG, type DataConfig, DataStore, type DefaultLLMCallConfig, DeterministicAdapter, type DeterministicConfig, type DomainEntityContextOptions, type DomainSchemaOptions, DriftGate, EVENTS, type EntityColumnDef, type EntityConfig, type ExecutionAdapter, type ExecutionEngineConfig, type FeedbackEntry, type GateFinding, type GateInput, type GateResult, GateRunner, type GateVerdict, GovernanceGate, HealthStatus, HookBus, InboundMessage, LLMProvider, LearningPipeline, type LearningPipelineConfig, type LoopDetection, LoopDetector, type LoopDetectorConfig, LoopType, MAX_CHAIN_DEPTH, MessagePipeline, type ModelConfig, ModelInfo, ModelRouter, NdjsonLogger, NotificationQueue, type PackageMigration, type PackageUpdate, type ParsedStream, type PermissionPrompt, type PermissionProvider, PermissionRelay, type PermissionRelayConfig, type PlaybookEntry, ProviderRegistry, QAGate, QualityGate, RUN_STATUSES, type RenderConfig, ResolvedModel, type RetryPolicy, type RunContext, RunManager, type RunResult, type RunStatus, type SanitizerOptions, type Schedule, type ScheduleDef, Scheduler, type SchemaError, type SecretInput, type SecretMeta, SecretStore, type SecurityConfig, SessionKey, SessionManager, type SkillEntry, type StepRef, type SystemContextOptions, TASK_STATUSES, type TaskDefinition, TaskQueue, type TaskRecord, type TaskStatus, TokenUsage, type ToolDefinition, type ToolHandler, UpdateChecker, type UpdateConfig, UpdateManager, type UpdateManifest, type UsageSummary, type User, type UserInput, UserRegistry, WakeupQueue, type WorkflowConfigEntry, type WorkflowDefinition$1 as WorkflowDefinition, WorkflowEngine, type WorkflowRunRecord, type WorkflowRunStatus, type WorkflowStep$1 as WorkflowStep, type WorkflowStepConfig, type WorkflowTrigger, _resetConfig, areDependenciesMet, autoUpdate, buildAgentBindings, buildChainOrigin, buildProcessEnv, buildSystemContext, checkAllowlist, checkChainDepth, checkMentionGate, chunkText, classifyUpdate, compareVersions, createConfigRevision, createDefaultLLMCall, deactivateLocalImagePaths, defineCoreEntityContexts, defineCoreTables, defineDomainEntityContexts, defineDomainTables, detectCycle, discoverChannels, discoverProviders, formatText, getConfig, initConfig, interpolate, interpolateEnv, isLoginRequired, isMaxTurns, loadConfig, parseClaudeStream, parseVersion, registerExecutionEngine, runPackageMigrations, sanitize, topologicalSort, truncateAtWord, validateConfig };
2083
+ export { AGENT_STATUSES, type AgentConfig, type AgentDefinition, type AgentFilter, type AgentRecord, AgentRegistry, type AgentStatus, ApiExecutionAdapter, type ApprovalResponse, type ApprovalStatus, AuditEmitter, type AuditEvent, BackupManager, type BotConfig, BreakerState, type BudgetCheck, type BudgetConfig, BudgetController, CORE_MIGRATIONS, ChannelAdapter, ChannelRegistry, ChannelRegistryError, ChatMessage, ChatResponderConfig, ChatSessionManager, CircuitBreaker, type CircuitBreakerConfig, CliExecutionAdapter, type ColumnValidator, ColumnValidatorImpl, type ConfigLoadError, type ConfigLoadResult, ConnectorConfig, DEFAULTS, DEFAULT_CONFIG, type DataConfig, DataStore, type DefaultLLMCallConfig, DeterministicAdapter, type DeterministicConfig, type DomainEntityContextOptions, type DomainSchemaOptions, DriftGate, EVENTS, type EntityColumnDef, type EntityConfig, type ExecutionAdapter, type ExecutionEngineConfig, type FeedbackEntry, type GateFinding, type GateInput, type GateResult, GateRunner, type GateVerdict, GovernanceGate, HealthStatus, HookBus, InboundMessage, LLMProvider, LearningPipeline, type LearningPipelineConfig, type LoopDetection, LoopDetector, type LoopDetectorConfig, LoopType, MAX_CHAIN_DEPTH, MessagePipeline, type ModelConfig, ModelInfo, ModelRouter, NdjsonLogger, NotificationQueue, type PackageMigration, type PackageUpdate, type ParsedStream, type PermissionPrompt, type PermissionProvider, PermissionRelay, type PermissionRelayConfig, type PlaybookEntry, ProviderRegistry, QAGate, QualityGate, RUN_STATUSES, type RenderConfig, ResolvedModel, type RetryPolicy, type RunContext, RunManager, type RunResult, type RunStatus, type SanitizerOptions, type Schedule, type ScheduleDef, Scheduler, type SchemaError, type SecretInput, type SecretMeta, SecretStore, type SecurityConfig, SessionKey, SessionManager, type SkillEntry, type StepRef, type SystemContextOptions, TASK_STATUSES, type TaskDefinition, TaskQueue, type TaskRecord, type TaskStatus, TokenUsage, type ToolContext, type ToolDefinition, type ToolHandler, UpdateChecker, type UpdateConfig, UpdateManager, type UpdateManifest, type UsageSummary, type User, type UserInput, UserRegistry, WakeupQueue, type WorkflowConfigEntry, type WorkflowDefinition$1 as WorkflowDefinition, WorkflowEngine, type WorkflowRunRecord, type WorkflowRunStatus, type WorkflowStep$1 as WorkflowStep, type WorkflowStepConfig, type WorkflowTrigger, _resetConfig, addTaskCommentTool, areDependenciesMet, autoUpdate, buildAgentBindings, buildChainOrigin, buildProcessEnv, buildSystemContext, cancelTaskTool, checkAllowlist, checkChainDepth, checkMentionGate, chunkText, classifyUpdate, compareVersions, createAgentTool, createConfigRevision, createDefaultLLMCall, createProjectTool, deactivateLocalImagePaths, defineCoreEntityContexts, defineCoreTables, defineDomainEntityContexts, defineDomainTables, detectCycle, discoverChannels, discoverProviders, dispatchTaskTool, formatText, getActiveTasksTool, getAgentDetailTool, getAgentStatusTool, getConfig, getSystemStatusTool, getTaskStatusTool, initConfig, interpolate, interpolateEnv, isLoginRequired, isMaxTurns, listAgentsTool, listFilesTool, listProjectsTool, loadConfig, parseClaudeStream, parseVersion, readConversationTool, readFileTool, reassignTaskTool, registerExecutionEngine, registerFileTool, runPackageMigrations, sanitize, searchConversationTool, sendFileTool, sendMessageTool, topologicalSort, truncateAtWord, validateConfig };
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  chunkText
3
3
  } from "./chunk-ZTZFPTOQ.js";
4
+ import {
5
+ __require
6
+ } from "./chunk-3RG5ZIWI.js";
4
7
 
5
8
  // src/shared/constants.ts
6
9
  var EVENTS = {
@@ -6123,7 +6126,7 @@ ${systemContext}` : "",
6123
6126
  try {
6124
6127
  const result = await handler(
6125
6128
  toolUse.input,
6126
- { taskId, agentId: assigneeId, hooks }
6129
+ { taskId, agentId: assigneeId, hooks, db, resolveFilePath: config.resolveFilePath }
6127
6130
  );
6128
6131
  toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
6129
6132
  } catch (err) {
@@ -6152,6 +6155,557 @@ ${systemContext}` : "",
6152
6155
  });
6153
6156
  }
6154
6157
 
6158
+ // src/core/orchestrator/tools/send-file.ts
6159
+ import { existsSync as existsSync3 } from "fs";
6160
+ import { basename } from "path";
6161
+ var sendFileTool = {
6162
+ definition: {
6163
+ name: "send_file",
6164
+ description: "Send/deliver/attach a file to the user on Slack. Use this when the user asks for a document, contract, report, or any file. The file_path is in the Files section of your system context.",
6165
+ input_schema: {
6166
+ type: "object",
6167
+ properties: {
6168
+ file_path: { type: "string", description: "Path to the file (from system context)" }
6169
+ },
6170
+ required: ["file_path"]
6171
+ }
6172
+ },
6173
+ handler: async (input, context) => {
6174
+ const rawPath = input.file_path;
6175
+ const filePath = context.resolveFilePath?.(rawPath) ?? rawPath;
6176
+ if (!existsSync3(filePath)) return `Error: file not found at ${filePath}`;
6177
+ await context.hooks.emit("file.deliver", {
6178
+ filePath,
6179
+ fileName: basename(filePath),
6180
+ taskId: context.taskId
6181
+ });
6182
+ return `File "${basename(filePath)}" sent to user.`;
6183
+ }
6184
+ };
6185
+
6186
+ // src/core/orchestrator/tools/read-file.ts
6187
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
6188
+ var readFileTool = {
6189
+ definition: {
6190
+ name: "read_file",
6191
+ description: "Read/review the contents of a file. Use this when the user asks about what a document contains, wants you to review a contract, check terms, summarize a report, etc. Supports .docx (Word), .txt, .md, .json, .csv. The file_path is in the Files section of your system context.",
6192
+ input_schema: {
6193
+ type: "object",
6194
+ properties: {
6195
+ file_path: { type: "string", description: "Path to the file (from system context)" }
6196
+ },
6197
+ required: ["file_path"]
6198
+ }
6199
+ },
6200
+ handler: async (input, context) => {
6201
+ const rawPath = input.file_path;
6202
+ const filePath = context.resolveFilePath?.(rawPath) ?? rawPath;
6203
+ if (!existsSync4(filePath)) return `Error: file not found at ${filePath}`;
6204
+ try {
6205
+ if (filePath.endsWith(".docx")) {
6206
+ return extractDocxText(filePath);
6207
+ }
6208
+ return readFileSync6(filePath, "utf8").slice(0, 8e3);
6209
+ } catch (err) {
6210
+ return `Error reading file: ${err instanceof Error ? err.message : String(err)}`;
6211
+ }
6212
+ }
6213
+ };
6214
+ function extractDocxText(filePath) {
6215
+ const data = readFileSync6(filePath);
6216
+ try {
6217
+ const zip = parseZipEntries(data);
6218
+ const docEntry = zip.find((e) => e.name === "word/document.xml");
6219
+ if (!docEntry) return "Error: could not find document.xml in docx";
6220
+ const xml = docEntry.data.toString("utf8");
6221
+ return xml.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 8e3);
6222
+ } catch {
6223
+ return "Error: could not parse docx file";
6224
+ }
6225
+ }
6226
+ function parseZipEntries(buf) {
6227
+ const entries = [];
6228
+ let offset = 0;
6229
+ while (offset < buf.length - 4) {
6230
+ if (buf[offset] !== 80 || buf[offset + 1] !== 75 || buf[offset + 2] !== 3 || buf[offset + 3] !== 4) {
6231
+ break;
6232
+ }
6233
+ const compressionMethod = buf.readUInt16LE(offset + 8);
6234
+ const compressedSize = buf.readUInt32LE(offset + 18);
6235
+ const nameLen = buf.readUInt16LE(offset + 26);
6236
+ const extraLen = buf.readUInt16LE(offset + 28);
6237
+ const name = buf.slice(offset + 30, offset + 30 + nameLen).toString("utf8");
6238
+ const dataStart = offset + 30 + nameLen + extraLen;
6239
+ if (compressionMethod === 0) {
6240
+ entries.push({ name, data: buf.slice(dataStart, dataStart + compressedSize) });
6241
+ } else if (compressionMethod === 8) {
6242
+ try {
6243
+ const { inflateRawSync } = __require("zlib");
6244
+ const inflated = inflateRawSync(buf.slice(dataStart, dataStart + compressedSize));
6245
+ entries.push({ name, data: inflated });
6246
+ } catch {
6247
+ }
6248
+ }
6249
+ offset = dataStart + compressedSize;
6250
+ }
6251
+ return entries;
6252
+ }
6253
+
6254
+ // src/core/orchestrator/tools/file-ops.ts
6255
+ var listFilesTool = {
6256
+ definition: {
6257
+ name: "list_files",
6258
+ description: 'List all files in the system. Shows file names, types, access levels, and paths. Use when the user asks "what files do we have?" or needs to find a document.',
6259
+ input_schema: {
6260
+ type: "object",
6261
+ properties: {
6262
+ search: { type: "string", description: "Optional search term to filter files by name" }
6263
+ }
6264
+ }
6265
+ },
6266
+ handler: async (input, ctx) => {
6267
+ const files = await ctx.db.query("file");
6268
+ let results = files.filter((f) => !f.deleted_at);
6269
+ const search = input.search;
6270
+ if (search) {
6271
+ const lower = search.toLowerCase();
6272
+ results = results.filter((f) => (f.name ?? "").toLowerCase().includes(lower));
6273
+ }
6274
+ if (results.length === 0) return "No files found.";
6275
+ return results.map((f) => `- ${f.name} (${f.access_level ?? "internal"}) | ${f.file_path ?? "no path"}`).join("\n");
6276
+ }
6277
+ };
6278
+ var registerFileTool = {
6279
+ definition: {
6280
+ name: "register_file",
6281
+ description: "Register a new file in the vault for tracking. Use when a new document needs to be tracked by the system.",
6282
+ input_schema: {
6283
+ type: "object",
6284
+ properties: {
6285
+ name: { type: "string", description: "File name/title" },
6286
+ file_path: { type: "string", description: "Path to the file on disk" },
6287
+ mime_type: { type: "string", description: "MIME type (e.g. application/pdf)" },
6288
+ access_level: { type: "string", description: "Access level: internal, confidential, public" }
6289
+ },
6290
+ required: ["name", "file_path"]
6291
+ }
6292
+ },
6293
+ handler: async (input, ctx) => {
6294
+ const orgs = await ctx.db.query("org");
6295
+ const orgId = orgs[0]?.id ?? "";
6296
+ const row = await ctx.db.insert("file", {
6297
+ org_id: orgId,
6298
+ name: input.name,
6299
+ file_path: input.file_path,
6300
+ mime_type: input.mime_type ?? "application/octet-stream",
6301
+ access_level: input.access_level ?? "internal"
6302
+ });
6303
+ return `File "${input.name}" registered with ID ${row.id}.`;
6304
+ }
6305
+ };
6306
+
6307
+ // src/core/orchestrator/tools/task-ops.ts
6308
+ import { randomUUID as randomUUID2 } from "crypto";
6309
+ var dispatchTaskTool = {
6310
+ definition: {
6311
+ name: "dispatch_task",
6312
+ description: "Create a new task and assign it to an agent. The agent will automatically pick it up and execute. Use when work needs to be delegated to a specialist.",
6313
+ input_schema: {
6314
+ type: "object",
6315
+ properties: {
6316
+ title: { type: "string", description: "Short task title" },
6317
+ description: { type: "string", description: "Detailed task description" },
6318
+ agent_slug: { type: "string", description: 'Agent slug to assign to (e.g. "engineer", "qa")' },
6319
+ priority: { type: "number", description: "Priority 1-10 (lower = higher priority). Default: 5" }
6320
+ },
6321
+ required: ["title", "agent_slug"]
6322
+ }
6323
+ },
6324
+ handler: async (input, ctx) => {
6325
+ const agents = await ctx.db.query("agents", { where: { slug: input.agent_slug } });
6326
+ const agent = agents[0];
6327
+ if (!agent) return `Error: agent "${input.agent_slug}" not found.`;
6328
+ const row = await ctx.db.insert("tasks", {
6329
+ id: randomUUID2(),
6330
+ title: input.title,
6331
+ description: input.description ?? input.title,
6332
+ assignee_id: agent.id,
6333
+ priority: input.priority ?? 5,
6334
+ status: "todo"
6335
+ });
6336
+ return `Task "${input.title}" dispatched to ${agent.name} (ID: ${row.id}).`;
6337
+ }
6338
+ };
6339
+ var cancelTaskTool = {
6340
+ definition: {
6341
+ name: "cancel_task",
6342
+ description: "Cancel a task by ID. Use when a task is no longer needed.",
6343
+ input_schema: {
6344
+ type: "object",
6345
+ properties: {
6346
+ task_id: { type: "string", description: "Task ID to cancel" }
6347
+ },
6348
+ required: ["task_id"]
6349
+ }
6350
+ },
6351
+ handler: async (input, ctx) => {
6352
+ const task = await ctx.db.get("tasks", { id: input.task_id });
6353
+ if (!task) return `Error: task ${input.task_id} not found.`;
6354
+ await ctx.db.update("tasks", { id: input.task_id }, { status: "cancelled" });
6355
+ return `Task "${task.title}" cancelled.`;
6356
+ }
6357
+ };
6358
+ var reassignTaskTool = {
6359
+ definition: {
6360
+ name: "reassign_task",
6361
+ description: "Reassign a task to a different agent. Cancels the original and creates a copy for the new agent.",
6362
+ input_schema: {
6363
+ type: "object",
6364
+ properties: {
6365
+ task_id: { type: "string", description: "Task ID to reassign" },
6366
+ new_agent_slug: { type: "string", description: "Agent slug to reassign to" }
6367
+ },
6368
+ required: ["task_id", "new_agent_slug"]
6369
+ }
6370
+ },
6371
+ handler: async (input, ctx) => {
6372
+ const task = await ctx.db.get("tasks", { id: input.task_id });
6373
+ if (!task) return `Error: task ${input.task_id} not found.`;
6374
+ const agents = await ctx.db.query("agents", { where: { slug: input.new_agent_slug } });
6375
+ const newAgent = agents[0];
6376
+ if (!newAgent) return `Error: agent "${input.new_agent_slug}" not found.`;
6377
+ await ctx.db.update("tasks", { id: input.task_id }, { status: "cancelled" });
6378
+ const row = await ctx.db.insert("tasks", {
6379
+ id: randomUUID2(),
6380
+ title: task.title,
6381
+ description: task.description,
6382
+ assignee_id: newAgent.id,
6383
+ priority: task.priority,
6384
+ status: "todo"
6385
+ });
6386
+ return `Task "${task.title}" reassigned from original to ${newAgent.name} (new ID: ${row.id}).`;
6387
+ }
6388
+ };
6389
+
6390
+ // src/core/orchestrator/tools/status.ts
6391
+ var getTaskStatusTool = {
6392
+ definition: {
6393
+ name: "get_task_status",
6394
+ description: "Get the current status, result, and details of a specific task. Use when checking on work progress.",
6395
+ input_schema: {
6396
+ type: "object",
6397
+ properties: {
6398
+ task_id: { type: "string", description: "Task ID to check" }
6399
+ },
6400
+ required: ["task_id"]
6401
+ }
6402
+ },
6403
+ handler: async (input, ctx) => {
6404
+ const task = await ctx.db.get("tasks", { id: input.task_id });
6405
+ if (!task) return `Task ${input.task_id} not found.`;
6406
+ const agent = task.assignee_id ? await ctx.db.get("agents", { id: task.assignee_id }) : null;
6407
+ return [
6408
+ `**${task.title}**`,
6409
+ `Status: ${task.status}`,
6410
+ `Assigned to: ${agent?.name ?? "unassigned"}`,
6411
+ `Priority: ${task.priority}`,
6412
+ task.result ? `Result: ${task.result.slice(0, 500)}` : null
6413
+ ].filter(Boolean).join("\n");
6414
+ }
6415
+ };
6416
+ var getAgentStatusTool = {
6417
+ definition: {
6418
+ name: "get_agent_status",
6419
+ description: "Get an agent's current status, active tasks, and recent run history. Use when checking what an agent is doing.",
6420
+ input_schema: {
6421
+ type: "object",
6422
+ properties: {
6423
+ agent_slug: { type: "string", description: 'Agent slug (e.g. "engineer")' }
6424
+ },
6425
+ required: ["agent_slug"]
6426
+ }
6427
+ },
6428
+ handler: async (input, ctx) => {
6429
+ const agents = await ctx.db.query("agents", { where: { slug: input.agent_slug } });
6430
+ const agent = agents[0];
6431
+ if (!agent) return `Agent "${input.agent_slug}" not found.`;
6432
+ const tasks = await ctx.db.query("tasks", { where: { assignee_id: agent.id, status: "todo" } });
6433
+ const runs = await ctx.db.query("runs", { where: { agent_id: agent.id }, limit: 5 });
6434
+ return [
6435
+ `**${agent.name}** (${agent.role})`,
6436
+ `Status: ${agent.status}`,
6437
+ `Pending tasks: ${tasks.length}`,
6438
+ runs.length > 0 ? `Recent runs: ${runs.map((r) => `${r.status} (${r.exit_code})`).join(", ")}` : "No recent runs"
6439
+ ].join("\n");
6440
+ }
6441
+ };
6442
+ var getSystemStatusTool = {
6443
+ definition: {
6444
+ name: "get_system_status",
6445
+ description: "Get overall system health: active agents, pending tasks, recent activity. Use for a quick system overview.",
6446
+ input_schema: { type: "object", properties: {} }
6447
+ },
6448
+ handler: async (_input, ctx) => {
6449
+ const agents = await ctx.db.query("agents");
6450
+ const todoTasks = await ctx.db.query("tasks", { where: { status: "todo" } });
6451
+ const runningTasks = await ctx.db.query("tasks", { where: { status: "in_progress" } });
6452
+ const recentRuns = await ctx.db.query("runs", { limit: 5 });
6453
+ return [
6454
+ `Agents: ${agents.length} (${agents.filter((a) => a.status === "running").length} running)`,
6455
+ `Pending tasks: ${todoTasks.length}`,
6456
+ `In-progress tasks: ${runningTasks.length}`,
6457
+ `Recent runs: ${recentRuns.length}`
6458
+ ].join("\n");
6459
+ }
6460
+ };
6461
+ var getActiveTasksTool = {
6462
+ definition: {
6463
+ name: "get_active_tasks",
6464
+ description: "List all active (todo/in_progress) tasks across all agents. Use to see what work is pending.",
6465
+ input_schema: { type: "object", properties: {} }
6466
+ },
6467
+ handler: async (_input, ctx) => {
6468
+ const todo = await ctx.db.query("tasks", { where: { status: "todo" } });
6469
+ const inProgress = await ctx.db.query("tasks", { where: { status: "in_progress" } });
6470
+ const all = [...todo, ...inProgress];
6471
+ if (all.length === 0) return "No active tasks.";
6472
+ return all.map((t) => `- [${t.status}] ${t.title} (priority: ${t.priority})`).join("\n");
6473
+ }
6474
+ };
6475
+
6476
+ // src/core/orchestrator/tools/roster.ts
6477
+ var listAgentsTool = {
6478
+ definition: {
6479
+ name: "list_agents",
6480
+ description: 'List all agents with their roles, status, and capabilities. Use when asking "who can do this?" or "what agents do we have?"',
6481
+ input_schema: { type: "object", properties: {} }
6482
+ },
6483
+ handler: async (_input, ctx) => {
6484
+ const agents = await ctx.db.query("agents");
6485
+ if (agents.length === 0) return "No agents registered.";
6486
+ return agents.filter((a) => !a.deleted_at).map((a) => `- **${a.name}** (${a.role}) \u2014 ${a.status}`).join("\n");
6487
+ }
6488
+ };
6489
+ var listProjectsTool = {
6490
+ definition: {
6491
+ name: "list_projects",
6492
+ description: "List all projects with status and description. Use when asking about company projects or work.",
6493
+ input_schema: { type: "object", properties: {} }
6494
+ },
6495
+ handler: async (_input, ctx) => {
6496
+ const projects = await ctx.db.query("project").catch(() => []);
6497
+ if (projects.length === 0) return "No projects found.";
6498
+ return projects.filter((p) => !p.deleted_at).map((p) => `- **${p.name}** (${p.status ?? "unknown"})${p.description ? ` \u2014 ${p.description.slice(0, 80)}` : ""}`).join("\n");
6499
+ }
6500
+ };
6501
+ var getAgentDetailTool = {
6502
+ definition: {
6503
+ name: "get_agent_detail",
6504
+ description: "Get full details about an agent: role, projects, skills, recent messages. Use when you need to know an agent's capabilities or history.",
6505
+ input_schema: {
6506
+ type: "object",
6507
+ properties: {
6508
+ agent_slug: { type: "string", description: "Agent slug" }
6509
+ },
6510
+ required: ["agent_slug"]
6511
+ }
6512
+ },
6513
+ handler: async (input, ctx) => {
6514
+ const agents = await ctx.db.query("agents", { where: { slug: input.agent_slug } });
6515
+ const agent = agents[0];
6516
+ if (!agent) return `Agent "${input.agent_slug}" not found.`;
6517
+ const skills = await ctx.db.query("agent_skills", { where: { agent_id: agent.id } }).catch(() => []);
6518
+ const skillNames = [];
6519
+ for (const link of skills) {
6520
+ const skill = await ctx.db.get("skills", { id: link.skill_id });
6521
+ if (skill) skillNames.push(skill.name);
6522
+ }
6523
+ return [
6524
+ `# ${agent.name}`,
6525
+ `Role: ${agent.role}`,
6526
+ `Status: ${agent.status}`,
6527
+ `Adapter: ${agent.adapter}`,
6528
+ skillNames.length > 0 ? `Skills: ${skillNames.join(", ")}` : "No skills assigned"
6529
+ ].join("\n");
6530
+ }
6531
+ };
6532
+
6533
+ // src/core/orchestrator/tools/messaging.ts
6534
+ var sendMessageTool = {
6535
+ definition: {
6536
+ name: "send_message",
6537
+ description: 'Send a message to a user or channel. Works across any channel: slack, email, discord, sms. For email, set channel="email" and include subject in the message. Use when the user asks to send/email/message someone.',
6538
+ input_schema: {
6539
+ type: "object",
6540
+ properties: {
6541
+ channel: { type: "string", description: 'Channel: "slack", "email", "discord", etc.' },
6542
+ recipient: { type: "string", description: "Recipient: Slack user ID, email address, channel name, etc." },
6543
+ text: { type: "string", description: "Message body" },
6544
+ subject: { type: "string", description: "Subject line (for email channel)" }
6545
+ },
6546
+ required: ["channel", "recipient", "text"]
6547
+ }
6548
+ },
6549
+ handler: async (input, ctx) => {
6550
+ await ctx.hooks.emit("message.send", {
6551
+ channel: input.channel,
6552
+ recipient: input.recipient,
6553
+ text: input.text,
6554
+ subject: input.subject,
6555
+ taskId: ctx.taskId
6556
+ });
6557
+ return `Message sent to ${input.recipient} via ${input.channel}.`;
6558
+ }
6559
+ };
6560
+ var addTaskCommentTool = {
6561
+ definition: {
6562
+ name: "add_task_comment",
6563
+ description: "Add a progress update or comment to a task. This syncs back to the Slack thread where the task was created. Use for mid-task status updates.",
6564
+ input_schema: {
6565
+ type: "object",
6566
+ properties: {
6567
+ task_id: { type: "string", description: "Task ID to comment on" },
6568
+ comment: { type: "string", description: "Progress update text" }
6569
+ },
6570
+ required: ["task_id", "comment"]
6571
+ }
6572
+ },
6573
+ handler: async (input, ctx) => {
6574
+ const task = await ctx.db.get("tasks", { id: input.task_id });
6575
+ if (!task) return `Task ${input.task_id} not found.`;
6576
+ const result = (task.result ?? "") + `
6577
+
6578
+ ---
6579
+ ${input.comment}`;
6580
+ await ctx.db.update("tasks", { id: input.task_id }, { result });
6581
+ const mappings = await ctx.db.query("thread_task_map", { where: { task_id: input.task_id } });
6582
+ if (mappings.length > 0) {
6583
+ await ctx.hooks.emit("response.ready", {
6584
+ text: input.comment,
6585
+ channel: "slack",
6586
+ threadId: mappings[0].thread_ts,
6587
+ taskId: input.task_id
6588
+ });
6589
+ }
6590
+ return `Comment added to task "${task.title}".`;
6591
+ }
6592
+ };
6593
+ var readConversationTool = {
6594
+ definition: {
6595
+ name: "read_conversation",
6596
+ description: "Read recent messages from a channel or conversation. Use when you need context about what was discussed recently.",
6597
+ input_schema: {
6598
+ type: "object",
6599
+ properties: {
6600
+ channel: { type: "string", description: 'Channel name (e.g. "slack")' },
6601
+ limit: { type: "number", description: "Number of recent messages to read. Default: 20" }
6602
+ },
6603
+ required: ["channel"]
6604
+ }
6605
+ },
6606
+ handler: async (input, ctx) => {
6607
+ const limit = input.limit ?? 20;
6608
+ const messages = await ctx.db.query("messages", {
6609
+ where: { channel: input.channel },
6610
+ orderBy: "created_at",
6611
+ limit
6612
+ });
6613
+ if (messages.length === 0) return `No messages found in ${input.channel}.`;
6614
+ return messages.map((m) => {
6615
+ const dir = m.direction === "inbound" ? "\u2192" : "\u2190";
6616
+ const who = m.from_user ?? m.from_agent ?? "unknown";
6617
+ return `${dir} ${who}: ${(m.body ?? "").slice(0, 200)}`;
6618
+ }).join("\n");
6619
+ }
6620
+ };
6621
+ var searchConversationTool = {
6622
+ definition: {
6623
+ name: "search_conversation",
6624
+ description: "Search message history across all channels by keyword. Use when looking for a specific discussion, decision, or topic that was mentioned previously.",
6625
+ input_schema: {
6626
+ type: "object",
6627
+ properties: {
6628
+ query: { type: "string", description: "Search keyword or phrase" },
6629
+ limit: { type: "number", description: "Max results. Default: 10" }
6630
+ },
6631
+ required: ["query"]
6632
+ }
6633
+ },
6634
+ handler: async (input, ctx) => {
6635
+ const query = input.query;
6636
+ const limit = input.limit ?? 10;
6637
+ const messages = await ctx.db.query("messages", {
6638
+ filters: [{ col: "body", op: "like", val: `%${query}%` }],
6639
+ orderBy: "created_at",
6640
+ limit
6641
+ });
6642
+ if (messages.length === 0) return `No messages found matching "${query}".`;
6643
+ return messages.map((m) => {
6644
+ const who = m.from_user ?? m.from_agent ?? "unknown";
6645
+ const ts = m.created_at?.slice(0, 16) ?? "";
6646
+ return `[${ts}] ${who}: ${(m.body ?? "").slice(0, 150)}`;
6647
+ }).join("\n");
6648
+ }
6649
+ };
6650
+
6651
+ // src/core/orchestrator/tools/management.ts
6652
+ var createAgentTool = {
6653
+ definition: {
6654
+ name: "create_agent",
6655
+ description: "Register a new agent in the system with a role and adapter. Use when the team needs a new specialist.",
6656
+ input_schema: {
6657
+ type: "object",
6658
+ properties: {
6659
+ slug: { type: "string", description: "Unique identifier (lowercase, no spaces)" },
6660
+ name: { type: "string", description: "Display name" },
6661
+ role: { type: "string", description: 'Role (e.g. "engineer", "qa", "marketing")' },
6662
+ adapter: { type: "string", description: 'Execution adapter: "api" or "cli". Default: "api"' }
6663
+ },
6664
+ required: ["slug", "name", "role"]
6665
+ }
6666
+ },
6667
+ handler: async (input, ctx) => {
6668
+ const existing = await ctx.db.query("agents", { where: { slug: input.slug } });
6669
+ if (existing.length > 0) return `Agent "${input.slug}" already exists.`;
6670
+ const row = await ctx.db.insert("agents", {
6671
+ slug: input.slug,
6672
+ name: input.name,
6673
+ role: input.role,
6674
+ adapter: input.adapter ?? "api",
6675
+ status: "idle",
6676
+ adapter_config: "{}",
6677
+ heartbeat_config: "{}"
6678
+ });
6679
+ return `Agent "${input.name}" (${input.role}) created with ID ${row.id}.`;
6680
+ }
6681
+ };
6682
+ var createProjectTool = {
6683
+ definition: {
6684
+ name: "create_project",
6685
+ description: "Register a new project with status and description. Use when a new initiative or product needs tracking.",
6686
+ input_schema: {
6687
+ type: "object",
6688
+ properties: {
6689
+ name: { type: "string", description: "Project name" },
6690
+ status: { type: "string", description: "Status: active_build, production, planning, etc." },
6691
+ description: { type: "string", description: "Brief description" }
6692
+ },
6693
+ required: ["name"]
6694
+ }
6695
+ },
6696
+ handler: async (input, ctx) => {
6697
+ const orgs = await ctx.db.query("org");
6698
+ const orgId = orgs[0]?.id ?? "";
6699
+ const row = await ctx.db.insert("project", {
6700
+ org_id: orgId,
6701
+ name: input.name,
6702
+ status: input.status ?? "planning",
6703
+ description: input.description ?? ""
6704
+ });
6705
+ return `Project "${input.name}" created with ID ${row.id}.`;
6706
+ }
6707
+ };
6708
+
6155
6709
  // src/core/orchestrator/user-registry.ts
6156
6710
  import { v4 as uuidv4 } from "uuid";
6157
6711
  var UserRegistry = class {
@@ -6533,20 +7087,24 @@ export {
6533
7087
  WakeupQueue,
6534
7088
  WorkflowEngine,
6535
7089
  _resetConfig,
7090
+ addTaskCommentTool,
6536
7091
  areDependenciesMet,
6537
7092
  autoUpdate,
6538
7093
  buildAgentBindings,
6539
7094
  buildChainOrigin,
6540
7095
  buildProcessEnv,
6541
7096
  buildSystemContext,
7097
+ cancelTaskTool,
6542
7098
  checkAllowlist,
6543
7099
  checkChainDepth,
6544
7100
  checkMentionGate,
6545
7101
  chunkText,
6546
7102
  classifyUpdate,
6547
7103
  compareVersions,
7104
+ createAgentTool,
6548
7105
  createConfigRevision,
6549
7106
  createDefaultLLMCall,
7107
+ createProjectTool,
6550
7108
  deactivateLocalImagePaths,
6551
7109
  defineCoreEntityContexts,
6552
7110
  defineCoreTables,
@@ -6555,19 +7113,35 @@ export {
6555
7113
  detectCycle,
6556
7114
  discoverChannels,
6557
7115
  discoverProviders,
7116
+ dispatchTaskTool,
6558
7117
  formatText,
7118
+ getActiveTasksTool,
7119
+ getAgentDetailTool,
7120
+ getAgentStatusTool,
6559
7121
  getConfig,
7122
+ getSystemStatusTool,
7123
+ getTaskStatusTool,
6560
7124
  initConfig,
6561
7125
  interpolate,
6562
7126
  interpolateEnv,
6563
7127
  isLoginRequired,
6564
7128
  isMaxTurns,
7129
+ listAgentsTool,
7130
+ listFilesTool,
7131
+ listProjectsTool,
6565
7132
  loadConfig,
6566
7133
  parseClaudeStream,
6567
7134
  parseVersion,
7135
+ readConversationTool,
7136
+ readFileTool,
7137
+ reassignTaskTool,
6568
7138
  registerExecutionEngine,
7139
+ registerFileTool,
6569
7140
  runPackageMigrations,
6570
7141
  sanitize,
7142
+ searchConversationTool,
7143
+ sendFileTool,
7144
+ sendMessageTool,
6571
7145
  topologicalSort,
6572
7146
  truncateAtWord,
6573
7147
  validateConfig
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/anthropic/provider.ts
2
4
  import Anthropic from "@anthropic-ai/sdk";
3
5
 
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/ollama/provider.ts
2
4
  var OllamaProvider = class {
3
5
  id = "ollama";
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/openai/provider.ts
2
4
  import OpenAI from "openai";
3
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botinabox",
3
- "version": "1.9.3",
3
+ "version": "2.0.0",
4
4
  "description": "Bot in a Box — framework for building multi-agent bots",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",