botinabox 2.3.1 → 2.4.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.
- package/dist/channels/slack/index.d.ts +1 -1
- package/dist/chat-pipeline-BWrtVqEP.d.ts +652 -0
- package/dist/chat-pipeline-CR1KF6eX.d.ts +652 -0
- package/dist/index.d.ts +332 -192
- package/dist/index.js +401 -68
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -1400,7 +1400,7 @@ You are talking to: ${opts.userName}`;
|
|
|
1400
1400
|
messages: [
|
|
1401
1401
|
{
|
|
1402
1402
|
role: "user",
|
|
1403
|
-
content: `Rewrite this agent/system message to be human-friendly and conversational. Keep the substance, remove jargon, make it feel like a helpful assistant talking to a person. If it's already readable,
|
|
1403
|
+
content: `Rewrite this agent/system message to be human-friendly and conversational. Keep the substance, remove jargon, make it feel like a helpful assistant talking to a person. If it's already readable, output the original text verbatim. CRITICAL: Never add meta-commentary about the text (e.g. "That's already conversational", "No rewrite needed", "Here's the rewritten version"). Output ONLY the final message text, nothing else.
|
|
1404
1404
|
|
|
1405
1405
|
---
|
|
1406
1406
|
${text}`
|
|
@@ -1476,6 +1476,10 @@ ${text}`
|
|
|
1476
1476
|
}
|
|
1477
1477
|
/**
|
|
1478
1478
|
* Build a context window from thread history, trimmed to token limit.
|
|
1479
|
+
*
|
|
1480
|
+
* Only includes inbound (user) messages. Outbound (bot) messages are
|
|
1481
|
+
* excluded to prevent the ack layer from mimicking prior verbose responses,
|
|
1482
|
+
* which caused hallucinated system state and walls of text.
|
|
1479
1483
|
*/
|
|
1480
1484
|
buildContextWindow(history, currentMessage) {
|
|
1481
1485
|
const maxChars = this.contextWindowTokens * APPROX_CHARS_PER_TOKEN;
|
|
@@ -1485,9 +1489,10 @@ ${text}`
|
|
|
1485
1489
|
const msg = history[i];
|
|
1486
1490
|
const body = msg["body"] ?? "";
|
|
1487
1491
|
const direction = msg["direction"];
|
|
1492
|
+
if (direction !== "inbound") continue;
|
|
1488
1493
|
if (charCount + body.length > maxChars) break;
|
|
1489
1494
|
messages.unshift({
|
|
1490
|
-
role:
|
|
1495
|
+
role: "user",
|
|
1491
1496
|
content: body
|
|
1492
1497
|
});
|
|
1493
1498
|
charCount += body.length;
|
|
@@ -1767,7 +1772,8 @@ ${historyContext}` : void 0
|
|
|
1767
1772
|
agentId: ctx.agentId,
|
|
1768
1773
|
taskId,
|
|
1769
1774
|
source: "agent",
|
|
1770
|
-
skipRedundancyCheck: true
|
|
1775
|
+
skipRedundancyCheck: true,
|
|
1776
|
+
skipFilter: true
|
|
1771
1777
|
});
|
|
1772
1778
|
const taskDesc = task?.description ?? "";
|
|
1773
1779
|
try {
|
|
@@ -1985,6 +1991,372 @@ ${extractedTask.description ?? msg.body}`;
|
|
|
1985
1991
|
}
|
|
1986
1992
|
};
|
|
1987
1993
|
|
|
1994
|
+
// src/core/chat/chat-pipeline-v2.ts
|
|
1995
|
+
import { createHash as createHash2 } from "crypto";
|
|
1996
|
+
|
|
1997
|
+
// src/core/data/context-builder.ts
|
|
1998
|
+
async function buildSystemContext(db, options) {
|
|
1999
|
+
const opts = {
|
|
2000
|
+
users: true,
|
|
2001
|
+
agents: true,
|
|
2002
|
+
projects: true,
|
|
2003
|
+
clients: true,
|
|
2004
|
+
files: true,
|
|
2005
|
+
org: true,
|
|
2006
|
+
...options
|
|
2007
|
+
};
|
|
2008
|
+
const sections = [];
|
|
2009
|
+
if (opts.org) {
|
|
2010
|
+
const orgs = await db.query("org").catch(() => []);
|
|
2011
|
+
const org = orgs[0];
|
|
2012
|
+
if (org) {
|
|
2013
|
+
sections.push(`## Organization
|
|
2014
|
+
${org.name} \u2014 ${org.description ?? ""}`);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
if (opts.users) {
|
|
2018
|
+
const users = await db.query("users").catch(() => []);
|
|
2019
|
+
if (users.length > 0) {
|
|
2020
|
+
const list = users.map((u) => `- ${u.name} (${u.role}${u.email ? `, ${u.email}` : ""})`).join("\n");
|
|
2021
|
+
sections.push(`## Users (${users.length})
|
|
2022
|
+
${list}`);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
if (opts.clients) {
|
|
2026
|
+
const clients = await db.query("client").catch(() => []);
|
|
2027
|
+
if (clients.length > 0) {
|
|
2028
|
+
const list = clients.map((c) => `- ${c.name} (${c.status ?? "active"})`).join("\n");
|
|
2029
|
+
sections.push(`## Clients (${clients.length})
|
|
2030
|
+
${list}`);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
if (opts.projects) {
|
|
2034
|
+
const projects = await db.query("project").catch(() => []);
|
|
2035
|
+
if (projects.length > 0) {
|
|
2036
|
+
const list = projects.map((p) => `- ${p.name} (${p.status ?? "unknown"})`).join("\n");
|
|
2037
|
+
sections.push(`## Projects (${projects.length})
|
|
2038
|
+
${list}`);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
if (opts.files) {
|
|
2042
|
+
const files = await db.query("file").catch(() => []);
|
|
2043
|
+
if (files.length > 0) {
|
|
2044
|
+
const list = files.map(
|
|
2045
|
+
(f) => `- ${f.name}${f.file_path ? ` | path: ${f.file_path}` : ""}${f.access_level ? ` (${f.access_level})` : ""}`
|
|
2046
|
+
).join("\n");
|
|
2047
|
+
sections.push(`## Files (${files.length})
|
|
2048
|
+
${list}`);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
if (opts.agents) {
|
|
2052
|
+
const agents = await db.query("agents").catch(() => []);
|
|
2053
|
+
if (agents.length > 0) {
|
|
2054
|
+
const list = agents.map((a) => `- ${a.name} (${a.role}, ${a.status})`).join("\n");
|
|
2055
|
+
sections.push(`## Agents (${agents.length})
|
|
2056
|
+
${list}`);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
return sections.join("\n\n");
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
// src/core/chat/chat-pipeline-v2.ts
|
|
2063
|
+
var DEFAULT_DEDUP_WINDOW_MS2 = 5 * 60 * 1e3;
|
|
2064
|
+
var DEFAULT_MAX_ITERATIONS = 5;
|
|
2065
|
+
var DEFAULT_MAX_TOKENS = 4096;
|
|
2066
|
+
var DEFAULT_MAX_MESSAGES = 50;
|
|
2067
|
+
var DEFAULT_MAX_AGE_DAYS = 7;
|
|
2068
|
+
var ChatPipelineV2 = class {
|
|
2069
|
+
constructor(db, hooks, config) {
|
|
2070
|
+
this.db = db;
|
|
2071
|
+
this.hooks = hooks;
|
|
2072
|
+
this.config = config;
|
|
2073
|
+
this.channel = config.channel ?? "slack";
|
|
2074
|
+
this.messageFilter = config.messageFilter;
|
|
2075
|
+
this.dedupWindowMs = config.dedupWindowMs ?? DEFAULT_DEDUP_WINDOW_MS2;
|
|
2076
|
+
this.toolDefs = (config.tools ?? []).map((t) => t.definition);
|
|
2077
|
+
this.toolHandlers = new Map(
|
|
2078
|
+
(config.tools ?? []).map((t) => [t.definition.name, t.handler])
|
|
2079
|
+
);
|
|
2080
|
+
this.messageStore = new MessageStore(db, hooks);
|
|
2081
|
+
const simpleLlmCall = async (params) => {
|
|
2082
|
+
const result = await config.llmCall({
|
|
2083
|
+
model: params.model ?? config.model ?? "fast",
|
|
2084
|
+
messages: params.messages.map((m) => ({
|
|
2085
|
+
role: m.role,
|
|
2086
|
+
content: typeof m.content === "string" ? m.content : m.content.map((b) => "text" in b ? b.text : "").join("")
|
|
2087
|
+
})),
|
|
2088
|
+
system: params.system,
|
|
2089
|
+
maxTokens: params.maxTokens ?? 500
|
|
2090
|
+
});
|
|
2091
|
+
const text = result.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
|
|
2092
|
+
return { content: text };
|
|
2093
|
+
};
|
|
2094
|
+
this.responder = new ChatResponder(db, hooks, this.messageStore, {
|
|
2095
|
+
llmCall: simpleLlmCall,
|
|
2096
|
+
model: config.model ?? "fast",
|
|
2097
|
+
systemPrompt: config.systemPrompt
|
|
2098
|
+
});
|
|
2099
|
+
this.interpreter = new MessageInterpreter(db, hooks, {
|
|
2100
|
+
llmCall: simpleLlmCall,
|
|
2101
|
+
model: "fast",
|
|
2102
|
+
extractors: config.extractors
|
|
2103
|
+
});
|
|
2104
|
+
this.registerHandlers();
|
|
2105
|
+
}
|
|
2106
|
+
db;
|
|
2107
|
+
hooks;
|
|
2108
|
+
config;
|
|
2109
|
+
messageStore;
|
|
2110
|
+
responder;
|
|
2111
|
+
interpreter;
|
|
2112
|
+
channel;
|
|
2113
|
+
messageFilter;
|
|
2114
|
+
dedupWindowMs;
|
|
2115
|
+
threadChannelMap = /* @__PURE__ */ new Map();
|
|
2116
|
+
toolDefs;
|
|
2117
|
+
toolHandlers;
|
|
2118
|
+
/**
|
|
2119
|
+
* Resolve the channel ID for a thread (for response delivery).
|
|
2120
|
+
*/
|
|
2121
|
+
async resolveChannel(threadId, taskId) {
|
|
2122
|
+
if (taskId) {
|
|
2123
|
+
const mappings = await this.db.query("thread_task_map", { where: { task_id: taskId } });
|
|
2124
|
+
if (mappings.length > 0) return mappings[0].channel_id;
|
|
2125
|
+
}
|
|
2126
|
+
if (threadId) {
|
|
2127
|
+
const mappings = await this.db.query("thread_task_map", { where: { thread_ts: threadId } });
|
|
2128
|
+
if (mappings.length > 0) return mappings[0].channel_id;
|
|
2129
|
+
}
|
|
2130
|
+
return this.threadChannelMap.get(threadId);
|
|
2131
|
+
}
|
|
2132
|
+
registerHandlers() {
|
|
2133
|
+
this.hooks.register("message.inbound", async (ctx) => {
|
|
2134
|
+
const msg = ctx;
|
|
2135
|
+
if (msg.channel !== this.channel) return;
|
|
2136
|
+
if (this.messageFilter && !this.messageFilter(msg)) return;
|
|
2137
|
+
if (await this.isDuplicate(msg)) return;
|
|
2138
|
+
const channelId = msg.account ?? "";
|
|
2139
|
+
const threadTs = channelId || msg.threadId || msg.id;
|
|
2140
|
+
if (threadTs && channelId) {
|
|
2141
|
+
this.threadChannelMap.set(threadTs, channelId);
|
|
2142
|
+
}
|
|
2143
|
+
const msgWithThread = { ...msg, threadId: threadTs };
|
|
2144
|
+
const { messageId } = await this.messageStore.storeInbound(msgWithThread);
|
|
2145
|
+
await this.hooks.emit("typing.start", { channel: this.channel, threadId: threadTs });
|
|
2146
|
+
try {
|
|
2147
|
+
const history = await this.buildHistory(channelId);
|
|
2148
|
+
let systemPrompt = this.config.systemPrompt;
|
|
2149
|
+
if (this.config.includeSystemContext !== false) {
|
|
2150
|
+
const ctx2 = await buildSystemContext(this.db, this.config.systemContextOptions);
|
|
2151
|
+
if (ctx2) systemPrompt += `
|
|
2152
|
+
|
|
2153
|
+
${ctx2}`;
|
|
2154
|
+
}
|
|
2155
|
+
const { text, tasksDispatched } = await this.think(
|
|
2156
|
+
systemPrompt,
|
|
2157
|
+
history,
|
|
2158
|
+
msg.body,
|
|
2159
|
+
threadTs,
|
|
2160
|
+
channelId
|
|
2161
|
+
);
|
|
2162
|
+
await this.hooks.emit("typing.stop", { channel: this.channel, threadId: threadTs });
|
|
2163
|
+
if (text) {
|
|
2164
|
+
await this.responder.sendResponse({
|
|
2165
|
+
text,
|
|
2166
|
+
channel: this.channel,
|
|
2167
|
+
threadId: threadTs,
|
|
2168
|
+
source: "primary",
|
|
2169
|
+
skipFilter: true,
|
|
2170
|
+
skipRedundancyCheck: true
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
void this.extractAsync(messageId);
|
|
2174
|
+
} catch (err) {
|
|
2175
|
+
await this.hooks.emit("typing.stop", { channel: this.channel, threadId: threadTs });
|
|
2176
|
+
await this.hooks.emit("pipeline.error", {
|
|
2177
|
+
messageId,
|
|
2178
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
this.hooks.register("run.completed", async (ctx) => {
|
|
2183
|
+
const taskId = ctx.taskId;
|
|
2184
|
+
if (!taskId) return;
|
|
2185
|
+
const task = await this.db.get("tasks", { id: taskId });
|
|
2186
|
+
const output = task?.result;
|
|
2187
|
+
if (!output) return;
|
|
2188
|
+
const mappings = await this.db.query("thread_task_map", { where: { task_id: taskId } });
|
|
2189
|
+
if (mappings.length === 0) return;
|
|
2190
|
+
const threadId = mappings[0].thread_ts;
|
|
2191
|
+
await this.responder.sendResponse({
|
|
2192
|
+
text: output,
|
|
2193
|
+
channel: this.channel,
|
|
2194
|
+
threadId,
|
|
2195
|
+
agentId: ctx.agentId,
|
|
2196
|
+
taskId,
|
|
2197
|
+
source: "agent",
|
|
2198
|
+
skipFilter: true,
|
|
2199
|
+
skipRedundancyCheck: true
|
|
2200
|
+
});
|
|
2201
|
+
}, { priority: 90 });
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* Primary agent tool loop — adapted from ExecutionEngine pattern.
|
|
2205
|
+
*/
|
|
2206
|
+
async think(systemPrompt, history, currentMessage, threadTs, channelId) {
|
|
2207
|
+
const model = this.config.model ?? "claude-sonnet-4-6";
|
|
2208
|
+
const maxIterations = this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
2209
|
+
const maxTokens = this.config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
2210
|
+
const tasksDispatched = [];
|
|
2211
|
+
const messages = [
|
|
2212
|
+
...history,
|
|
2213
|
+
{ role: "user", content: currentMessage }
|
|
2214
|
+
];
|
|
2215
|
+
let finalText = "";
|
|
2216
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
2217
|
+
const params = {
|
|
2218
|
+
model,
|
|
2219
|
+
messages,
|
|
2220
|
+
system: systemPrompt,
|
|
2221
|
+
maxTokens
|
|
2222
|
+
};
|
|
2223
|
+
if (this.toolDefs.length > 0) {
|
|
2224
|
+
params.tools = this.toolDefs;
|
|
2225
|
+
params.tool_choice = { type: "auto" };
|
|
2226
|
+
}
|
|
2227
|
+
const response = await this.config.llmCall(params);
|
|
2228
|
+
const textBlocks = response.content.filter((b) => b.type === "text").map((b) => b.text ?? "");
|
|
2229
|
+
if (textBlocks.length > 0) finalText += textBlocks.join("");
|
|
2230
|
+
if (response.stop_reason !== "tool_use") break;
|
|
2231
|
+
const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
|
|
2232
|
+
const toolResults = [];
|
|
2233
|
+
for (const toolUse of toolUseBlocks) {
|
|
2234
|
+
const handler = this.toolHandlers.get(toolUse.name);
|
|
2235
|
+
if (handler) {
|
|
2236
|
+
try {
|
|
2237
|
+
const toolCtx = {
|
|
2238
|
+
taskId: "",
|
|
2239
|
+
agentId: "primary",
|
|
2240
|
+
hooks: this.hooks,
|
|
2241
|
+
db: this.db,
|
|
2242
|
+
resolveFilePath: this.config.resolveFilePath
|
|
2243
|
+
};
|
|
2244
|
+
const result = await handler(
|
|
2245
|
+
toolUse.input,
|
|
2246
|
+
toolCtx
|
|
2247
|
+
);
|
|
2248
|
+
if (toolUse.name === "dispatch_task" && result.includes("ID:")) {
|
|
2249
|
+
const idMatch = result.match(/ID:\s*([a-f0-9-]+)/);
|
|
2250
|
+
if (idMatch) {
|
|
2251
|
+
const taskId = idMatch[1];
|
|
2252
|
+
tasksDispatched.push(taskId);
|
|
2253
|
+
try {
|
|
2254
|
+
const existing = await this.db.query("thread_task_map", {
|
|
2255
|
+
where: { thread_ts: threadTs, channel_id: channelId }
|
|
2256
|
+
});
|
|
2257
|
+
if (existing.length > 0) {
|
|
2258
|
+
await this.db.update("thread_task_map", { id: existing[0].id }, { task_id: taskId });
|
|
2259
|
+
} else {
|
|
2260
|
+
await this.db.insert("thread_task_map", {
|
|
2261
|
+
thread_ts: threadTs,
|
|
2262
|
+
channel_id: channelId,
|
|
2263
|
+
task_id: taskId
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
} catch {
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
toolResults.push({
|
|
2271
|
+
type: "tool_result",
|
|
2272
|
+
id: toolUse.id,
|
|
2273
|
+
text: result
|
|
2274
|
+
});
|
|
2275
|
+
} catch (err) {
|
|
2276
|
+
toolResults.push({
|
|
2277
|
+
type: "tool_result",
|
|
2278
|
+
id: toolUse.id,
|
|
2279
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
messages.push({ role: "assistant", content: response.content });
|
|
2285
|
+
messages.push({ role: "user", content: toolResults });
|
|
2286
|
+
}
|
|
2287
|
+
return { text: finalText, tasksDispatched };
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Build conversation history from channel messages.
|
|
2291
|
+
* Includes BOTH user and assistant messages (unlike v1 which excluded bot messages).
|
|
2292
|
+
*/
|
|
2293
|
+
async buildHistory(channelId) {
|
|
2294
|
+
const maxMessages = this.config.history?.maxMessages ?? DEFAULT_MAX_MESSAGES;
|
|
2295
|
+
const maxAgeDays = this.config.history?.maxAgeDays ?? DEFAULT_MAX_AGE_DAYS;
|
|
2296
|
+
const includeAssistant = this.config.history?.includeAssistant !== false;
|
|
2297
|
+
const cutoff = new Date(Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3).toISOString();
|
|
2298
|
+
let rows;
|
|
2299
|
+
try {
|
|
2300
|
+
rows = await this.db.query("messages", {
|
|
2301
|
+
where: { channel: this.channel },
|
|
2302
|
+
orderBy: "created_at",
|
|
2303
|
+
orderDir: "desc",
|
|
2304
|
+
limit: maxMessages
|
|
2305
|
+
});
|
|
2306
|
+
rows.reverse();
|
|
2307
|
+
rows = rows.filter((r) => {
|
|
2308
|
+
const ts = r.created_at;
|
|
2309
|
+
return !ts || ts >= cutoff;
|
|
2310
|
+
});
|
|
2311
|
+
} catch {
|
|
2312
|
+
return [];
|
|
2313
|
+
}
|
|
2314
|
+
const messages = [];
|
|
2315
|
+
const maxChars = 16e3;
|
|
2316
|
+
let charCount = 0;
|
|
2317
|
+
for (const row of rows) {
|
|
2318
|
+
const body = row.body ?? "";
|
|
2319
|
+
const direction = row.direction;
|
|
2320
|
+
if (!includeAssistant && direction !== "inbound") continue;
|
|
2321
|
+
if (charCount + body.length > maxChars) break;
|
|
2322
|
+
messages.push({
|
|
2323
|
+
role: direction === "inbound" ? "user" : "assistant",
|
|
2324
|
+
content: body
|
|
2325
|
+
});
|
|
2326
|
+
charCount += body.length;
|
|
2327
|
+
}
|
|
2328
|
+
return messages;
|
|
2329
|
+
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Dedup check (same as v1).
|
|
2332
|
+
*/
|
|
2333
|
+
async isDuplicate(msg) {
|
|
2334
|
+
const hash = createHash2("sha256").update(`${msg.from}:${msg.body}`).digest("hex");
|
|
2335
|
+
const cutoff = new Date(Date.now() - this.dedupWindowMs).toISOString();
|
|
2336
|
+
const recent = await this.db.query("message_dedup", { where: { content_hash: hash } });
|
|
2337
|
+
if (recent.some((r) => r.created_at > cutoff)) return true;
|
|
2338
|
+
await this.db.insert("message_dedup", {
|
|
2339
|
+
content_hash: hash,
|
|
2340
|
+
channel_id: msg.account ?? "",
|
|
2341
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2342
|
+
});
|
|
2343
|
+
return false;
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Async memory extraction (non-blocking, non-fatal).
|
|
2347
|
+
*/
|
|
2348
|
+
async extractAsync(messageId) {
|
|
2349
|
+
try {
|
|
2350
|
+
await this.interpreter.interpret(messageId);
|
|
2351
|
+
} catch (err) {
|
|
2352
|
+
await this.hooks.emit("interpretation.error", {
|
|
2353
|
+
messageId,
|
|
2354
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
};
|
|
2359
|
+
|
|
1988
2360
|
// src/core/chat/formatter.ts
|
|
1989
2361
|
function formatText(text, mode) {
|
|
1990
2362
|
switch (mode) {
|
|
@@ -3498,71 +3870,6 @@ ${c.instructions}` : null,
|
|
|
3498
3870
|
}
|
|
3499
3871
|
}
|
|
3500
3872
|
|
|
3501
|
-
// src/core/data/context-builder.ts
|
|
3502
|
-
async function buildSystemContext(db, options) {
|
|
3503
|
-
const opts = {
|
|
3504
|
-
users: true,
|
|
3505
|
-
agents: true,
|
|
3506
|
-
projects: true,
|
|
3507
|
-
clients: true,
|
|
3508
|
-
files: true,
|
|
3509
|
-
org: true,
|
|
3510
|
-
...options
|
|
3511
|
-
};
|
|
3512
|
-
const sections = [];
|
|
3513
|
-
if (opts.org) {
|
|
3514
|
-
const orgs = await db.query("org").catch(() => []);
|
|
3515
|
-
const org = orgs[0];
|
|
3516
|
-
if (org) {
|
|
3517
|
-
sections.push(`## Organization
|
|
3518
|
-
${org.name} \u2014 ${org.description ?? ""}`);
|
|
3519
|
-
}
|
|
3520
|
-
}
|
|
3521
|
-
if (opts.users) {
|
|
3522
|
-
const users = await db.query("users").catch(() => []);
|
|
3523
|
-
if (users.length > 0) {
|
|
3524
|
-
const list = users.map((u) => `- ${u.name} (${u.role}${u.email ? `, ${u.email}` : ""})`).join("\n");
|
|
3525
|
-
sections.push(`## Users (${users.length})
|
|
3526
|
-
${list}`);
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
if (opts.clients) {
|
|
3530
|
-
const clients = await db.query("client").catch(() => []);
|
|
3531
|
-
if (clients.length > 0) {
|
|
3532
|
-
const list = clients.map((c) => `- ${c.name} (${c.status ?? "active"})`).join("\n");
|
|
3533
|
-
sections.push(`## Clients (${clients.length})
|
|
3534
|
-
${list}`);
|
|
3535
|
-
}
|
|
3536
|
-
}
|
|
3537
|
-
if (opts.projects) {
|
|
3538
|
-
const projects = await db.query("project").catch(() => []);
|
|
3539
|
-
if (projects.length > 0) {
|
|
3540
|
-
const list = projects.map((p) => `- ${p.name} (${p.status ?? "unknown"})`).join("\n");
|
|
3541
|
-
sections.push(`## Projects (${projects.length})
|
|
3542
|
-
${list}`);
|
|
3543
|
-
}
|
|
3544
|
-
}
|
|
3545
|
-
if (opts.files) {
|
|
3546
|
-
const files = await db.query("file").catch(() => []);
|
|
3547
|
-
if (files.length > 0) {
|
|
3548
|
-
const list = files.map(
|
|
3549
|
-
(f) => `- ${f.name}${f.file_path ? ` | path: ${f.file_path}` : ""}${f.access_level ? ` (${f.access_level})` : ""}`
|
|
3550
|
-
).join("\n");
|
|
3551
|
-
sections.push(`## Files (${files.length})
|
|
3552
|
-
${list}`);
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
if (opts.agents) {
|
|
3556
|
-
const agents = await db.query("agents").catch(() => []);
|
|
3557
|
-
if (agents.length > 0) {
|
|
3558
|
-
const list = agents.map((a) => `- ${a.name} (${a.role}, ${a.status})`).join("\n");
|
|
3559
|
-
sections.push(`## Agents (${agents.length})
|
|
3560
|
-
${list}`);
|
|
3561
|
-
}
|
|
3562
|
-
}
|
|
3563
|
-
return sections.join("\n\n");
|
|
3564
|
-
}
|
|
3565
|
-
|
|
3566
3873
|
// src/core/security/sanitizer.ts
|
|
3567
3874
|
import { Buffer as Buffer2 } from "buffer";
|
|
3568
3875
|
var DEFAULT_FIELD_LIMIT = 65535;
|
|
@@ -6745,6 +7052,30 @@ var nativeTools = [
|
|
|
6745
7052
|
createAgentTool,
|
|
6746
7053
|
createProjectTool
|
|
6747
7054
|
];
|
|
7055
|
+
var coordinatorTools = [
|
|
7056
|
+
// Task management
|
|
7057
|
+
dispatchTaskTool,
|
|
7058
|
+
cancelTaskTool,
|
|
7059
|
+
reassignTaskTool,
|
|
7060
|
+
// Progress monitoring
|
|
7061
|
+
getTaskStatusTool,
|
|
7062
|
+
getActiveTasksTool,
|
|
7063
|
+
// Agent management + awareness
|
|
7064
|
+
listAgentsTool,
|
|
7065
|
+
getAgentStatusTool,
|
|
7066
|
+
getAgentDetailTool,
|
|
7067
|
+
createAgentTool,
|
|
7068
|
+
// Communication (coordinator is the user-facing gateway)
|
|
7069
|
+
sendMessageTool,
|
|
7070
|
+
addTaskCommentTool,
|
|
7071
|
+
// Conversational context
|
|
7072
|
+
readConversationTool,
|
|
7073
|
+
searchConversationTool,
|
|
7074
|
+
// Awareness (for routing decisions, not for doing work)
|
|
7075
|
+
listFilesTool,
|
|
7076
|
+
listProjectsTool,
|
|
7077
|
+
sendFileTool
|
|
7078
|
+
];
|
|
6748
7079
|
|
|
6749
7080
|
// src/core/orchestrator/user-registry.ts
|
|
6750
7081
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -7083,6 +7414,7 @@ export {
|
|
|
7083
7414
|
ChannelRegistry,
|
|
7084
7415
|
ChannelRegistryError,
|
|
7085
7416
|
ChatPipeline,
|
|
7417
|
+
ChatPipelineV2,
|
|
7086
7418
|
ChatResponder,
|
|
7087
7419
|
ChatSessionManager,
|
|
7088
7420
|
CircuitBreaker,
|
|
@@ -7141,6 +7473,7 @@ export {
|
|
|
7141
7473
|
chunkText,
|
|
7142
7474
|
classifyUpdate,
|
|
7143
7475
|
compareVersions,
|
|
7476
|
+
coordinatorTools,
|
|
7144
7477
|
createAgentTool,
|
|
7145
7478
|
createConfigRevision,
|
|
7146
7479
|
createDefaultLLMCall,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botinabox",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Bot in a Box — framework for building multi-agent bots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,8 +53,7 @@
|
|
|
53
53
|
"build": "tsup",
|
|
54
54
|
"test": "vitest run",
|
|
55
55
|
"typecheck": "tsc --noEmit",
|
|
56
|
-
"
|
|
57
|
-
"prepublishOnly": "npm run build && npm run typecheck && npm test && npm run check-docs"
|
|
56
|
+
"prepublishOnly": "npm run build && npm run typecheck && npm test"
|
|
58
57
|
},
|
|
59
58
|
"dependencies": {
|
|
60
59
|
"@types/uuid": "^10.0.0",
|