botinabox 2.16.16 → 2.16.18
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/core/chat/chat-pipeline-v2.d.ts +21 -0
- package/dist/core/orchestrator/secret-store.d.ts +11 -0
- package/dist/index.js +61 -17
- package/package.json +100 -100
|
@@ -117,6 +117,27 @@ export interface ChatPipelineV2Config {
|
|
|
117
117
|
messageText: string;
|
|
118
118
|
channel: string;
|
|
119
119
|
}) => Promise<ContextFile[]> | ContextFile[];
|
|
120
|
+
/**
|
|
121
|
+
* Optional per-turn tool-context resolver. Called once per inbound message
|
|
122
|
+
* with the resolved conversation coordinates (the same shape passed to
|
|
123
|
+
* `resolveContextFiles`). The returned fields are merged into the
|
|
124
|
+
* `ToolContext` handed to every tool handler for that turn — letting an app
|
|
125
|
+
* thread per-turn identity (e.g. which user the primary agent is acting on
|
|
126
|
+
* behalf of) into tool execution, which the static config cannot express.
|
|
127
|
+
*
|
|
128
|
+
* The base `ToolContext` fields (`taskId`, `agentId`, `hooks`, `db`,
|
|
129
|
+
* `resolveFilePath`) are applied first and cannot be overridden by the
|
|
130
|
+
* resolver — returned keys that collide with them are ignored. If the
|
|
131
|
+
* resolver throws, the error propagates to the turn's try/catch and fails
|
|
132
|
+
* loudly; there is no silent fallback.
|
|
133
|
+
*/
|
|
134
|
+
resolveToolContext?: (ctx: {
|
|
135
|
+
channelId: string;
|
|
136
|
+
threadId: string;
|
|
137
|
+
userId?: string;
|
|
138
|
+
messageText: string;
|
|
139
|
+
channel: string;
|
|
140
|
+
}) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
120
141
|
}
|
|
121
142
|
export declare class ChatPipelineV2 {
|
|
122
143
|
private db;
|
|
@@ -41,6 +41,17 @@ export declare class SecretStore {
|
|
|
41
41
|
set(input: SecretInput): Promise<SecretMeta>;
|
|
42
42
|
get(name: string, environment?: string): Promise<string | null>;
|
|
43
43
|
getMeta(name: string, environment?: string): Promise<SecretMeta | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Fetch the most recently created live row for (name, environment).
|
|
46
|
+
*
|
|
47
|
+
* `set()` keeps this to a single row in steady state, but we still pick the
|
|
48
|
+
* newest in JS rather than rely on a SQL `LIMIT 1` (nondeterministic without
|
|
49
|
+
* an ORDER BY) or a dialect/version-specific `orderBy` form: legacy data
|
|
50
|
+
* written before the upsert fix can still have duplicate live rows, and JS
|
|
51
|
+
* sorting resolves them deterministically across SQLite and Postgres. (Same
|
|
52
|
+
* cross-dialect-sort rationale as the chat memory resolver.)
|
|
53
|
+
*/
|
|
54
|
+
private _latestRow;
|
|
44
55
|
list(): Promise<SecretMeta[]>;
|
|
45
56
|
rotate(name: string, newValue: string, environment?: string): Promise<void>;
|
|
46
57
|
delete(name: string, environment?: string): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -2345,13 +2345,24 @@ ${ctx2}`;
|
|
|
2345
2345
|
|
|
2346
2346
|
${contextFilesBlock}`;
|
|
2347
2347
|
}
|
|
2348
|
+
let toolContextExtra = {};
|
|
2349
|
+
if (this.config.resolveToolContext) {
|
|
2350
|
+
toolContextExtra = await this.config.resolveToolContext({
|
|
2351
|
+
channelId,
|
|
2352
|
+
threadId: threadTs,
|
|
2353
|
+
userId: msg.from,
|
|
2354
|
+
messageText: msg.body,
|
|
2355
|
+
channel: this.channel
|
|
2356
|
+
}) ?? {};
|
|
2357
|
+
}
|
|
2348
2358
|
const { text, tasksDispatched } = await this.think(
|
|
2349
2359
|
systemPrompt,
|
|
2350
2360
|
history,
|
|
2351
2361
|
msg.body,
|
|
2352
2362
|
threadTs,
|
|
2353
2363
|
channelId,
|
|
2354
|
-
msg.attachmentBlocks
|
|
2364
|
+
msg.attachmentBlocks,
|
|
2365
|
+
toolContextExtra
|
|
2355
2366
|
);
|
|
2356
2367
|
await this.hooks.emit("typing.stop", { channel: this.channel, threadId: threadTs });
|
|
2357
2368
|
if (text) {
|
|
@@ -2399,7 +2410,7 @@ ${contextFilesBlock}`;
|
|
|
2399
2410
|
/**
|
|
2400
2411
|
* Primary agent tool loop — adapted from ExecutionEngine pattern.
|
|
2401
2412
|
*/
|
|
2402
|
-
async think(systemPrompt, history, currentMessage, threadTs, channelId, attachmentBlocks) {
|
|
2413
|
+
async think(systemPrompt, history, currentMessage, threadTs, channelId, attachmentBlocks, toolContextExtra) {
|
|
2403
2414
|
const model = this.config.model ?? "claude-sonnet-4-6";
|
|
2404
2415
|
const maxIterations = this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
2405
2416
|
const maxTokens = this.config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
@@ -2432,6 +2443,9 @@ ${contextFilesBlock}`;
|
|
|
2432
2443
|
if (handler) {
|
|
2433
2444
|
try {
|
|
2434
2445
|
const toolCtx = {
|
|
2446
|
+
// Per-turn extras first; base fields applied last so the
|
|
2447
|
+
// resolver can never override taskId/agentId/hooks/db.
|
|
2448
|
+
...toolContextExtra,
|
|
2435
2449
|
taskId: "",
|
|
2436
2450
|
agentId: "primary",
|
|
2437
2451
|
hooks: this.hooks,
|
|
@@ -7510,35 +7524,65 @@ var SecretStore = class {
|
|
|
7510
7524
|
this.encKey = encryptionKey ? deriveEncKey(encryptionKey) : null;
|
|
7511
7525
|
}
|
|
7512
7526
|
async set(input) {
|
|
7513
|
-
const
|
|
7514
|
-
const
|
|
7515
|
-
|
|
7516
|
-
|
|
7527
|
+
const environment = input.environment ?? "production";
|
|
7528
|
+
const value = this.encKey && input.value ? encryptValue(input.value, this.encKey) : input.value;
|
|
7529
|
+
const existing = await this.db.query("secrets", {
|
|
7530
|
+
where: { name: input.name, environment },
|
|
7531
|
+
filters: [{ col: "deleted_at", op: "isNull" }],
|
|
7532
|
+
limit: 1
|
|
7533
|
+
});
|
|
7534
|
+
if (existing.length > 0) {
|
|
7535
|
+
const id2 = existing[0].id;
|
|
7536
|
+
const changes = {
|
|
7537
|
+
value,
|
|
7538
|
+
environment,
|
|
7539
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7540
|
+
};
|
|
7541
|
+
if (input.type !== void 0) changes.type = input.type;
|
|
7542
|
+
if (input.description !== void 0) changes.description = input.description;
|
|
7543
|
+
await this.db.update("secrets", id2, changes);
|
|
7544
|
+
await this.hooks.emit("secret.updated", { name: input.name });
|
|
7545
|
+
const updated = await this.db.get("secrets", id2);
|
|
7546
|
+
return this._toMeta(updated);
|
|
7517
7547
|
}
|
|
7518
|
-
|
|
7548
|
+
const id = uuidv42();
|
|
7549
|
+
await this.db.insert("secrets", { ...input, id, value, environment });
|
|
7519
7550
|
await this.hooks.emit("secret.created", { name: input.name });
|
|
7520
7551
|
const inserted = await this.db.get("secrets", id);
|
|
7521
7552
|
return this._toMeta(inserted);
|
|
7522
7553
|
}
|
|
7523
7554
|
async get(name, environment = "production") {
|
|
7524
|
-
const
|
|
7525
|
-
|
|
7526
|
-
filters: [{ col: "deleted_at", op: "isNull" }],
|
|
7527
|
-
limit: 1
|
|
7528
|
-
});
|
|
7529
|
-
if (rows.length === 0) return null;
|
|
7555
|
+
const row = await this._latestRow(name, environment);
|
|
7556
|
+
if (!row) return null;
|
|
7530
7557
|
await this.hooks.emit("secret.accessed", { name, environment });
|
|
7531
|
-
const raw =
|
|
7558
|
+
const raw = row.value ?? null;
|
|
7532
7559
|
if (raw && this.encKey) return decryptValue(raw, this.encKey);
|
|
7533
7560
|
return raw;
|
|
7534
7561
|
}
|
|
7535
7562
|
async getMeta(name, environment = "production") {
|
|
7563
|
+
const row = await this._latestRow(name, environment);
|
|
7564
|
+
return row ? this._toMeta(row) : null;
|
|
7565
|
+
}
|
|
7566
|
+
/**
|
|
7567
|
+
* Fetch the most recently created live row for (name, environment).
|
|
7568
|
+
*
|
|
7569
|
+
* `set()` keeps this to a single row in steady state, but we still pick the
|
|
7570
|
+
* newest in JS rather than rely on a SQL `LIMIT 1` (nondeterministic without
|
|
7571
|
+
* an ORDER BY) or a dialect/version-specific `orderBy` form: legacy data
|
|
7572
|
+
* written before the upsert fix can still have duplicate live rows, and JS
|
|
7573
|
+
* sorting resolves them deterministically across SQLite and Postgres. (Same
|
|
7574
|
+
* cross-dialect-sort rationale as the chat memory resolver.)
|
|
7575
|
+
*/
|
|
7576
|
+
async _latestRow(name, environment) {
|
|
7536
7577
|
const rows = await this.db.query("secrets", {
|
|
7537
7578
|
where: { name, environment },
|
|
7538
|
-
filters: [{ col: "deleted_at", op: "isNull" }]
|
|
7539
|
-
limit: 1
|
|
7579
|
+
filters: [{ col: "deleted_at", op: "isNull" }]
|
|
7540
7580
|
});
|
|
7541
|
-
|
|
7581
|
+
if (rows.length === 0) return void 0;
|
|
7582
|
+
rows.sort(
|
|
7583
|
+
(a, b) => String(b.created_at ?? "").localeCompare(String(a.created_at ?? ""))
|
|
7584
|
+
);
|
|
7585
|
+
return rows[0];
|
|
7542
7586
|
}
|
|
7543
7587
|
async list() {
|
|
7544
7588
|
const rows = await this.db.query("secrets", {
|
package/package.json
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "botinabox",
|
|
3
|
-
"version": "2.16.
|
|
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.16.4",
|
|
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.18",
|
|
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.16.4",
|
|
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
|
+
}
|