verybot 0.1.3
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.
Potentially problematic release.
This version of verybot might be problematic. Click here for more details.
- package/dist/brain/agent-registry.d.ts +75 -0
- package/dist/brain/agent-registry.js +124 -0
- package/dist/brain/agent.d.ts +146 -0
- package/dist/brain/agent.js +680 -0
- package/dist/brain/channel-store.d.ts +27 -0
- package/dist/brain/channel-store.js +78 -0
- package/dist/brain/compaction.d.ts +37 -0
- package/dist/brain/compaction.js +214 -0
- package/dist/brain/context.d.ts +33 -0
- package/dist/brain/context.js +77 -0
- package/dist/brain/delegation-store.d.ts +33 -0
- package/dist/brain/delegation-store.js +106 -0
- package/dist/brain/loop.d.ts +21 -0
- package/dist/brain/loop.js +161 -0
- package/dist/brain/mcp-adapter.d.ts +39 -0
- package/dist/brain/mcp-adapter.js +227 -0
- package/dist/brain/memory-extractor.d.ts +26 -0
- package/dist/brain/memory-extractor.js +82 -0
- package/dist/brain/providers.d.ts +10 -0
- package/dist/brain/providers.js +69 -0
- package/dist/brain/queue.d.ts +18 -0
- package/dist/brain/queue.js +84 -0
- package/dist/brain/run-tools.d.ts +47 -0
- package/dist/brain/run-tools.js +84 -0
- package/dist/brain/session-key.d.ts +23 -0
- package/dist/brain/session-key.js +41 -0
- package/dist/brain/session-state.d.ts +36 -0
- package/dist/brain/session-state.js +51 -0
- package/dist/brain/session-store.d.ts +50 -0
- package/dist/brain/session-store.js +207 -0
- package/dist/brain/session.d.ts +32 -0
- package/dist/brain/session.js +75 -0
- package/dist/brain/utils.d.ts +4 -0
- package/dist/brain/utils.js +26 -0
- package/dist/brain/worker-coordinator.d.ts +25 -0
- package/dist/brain/worker-coordinator.js +83 -0
- package/dist/channels/commands.d.ts +35 -0
- package/dist/channels/commands.js +65 -0
- package/dist/channels/discord/channel.d.ts +18 -0
- package/dist/channels/discord/channel.js +154 -0
- package/dist/channels/discord/markdown.d.ts +19 -0
- package/dist/channels/discord/markdown.js +62 -0
- package/dist/channels/manager.d.ts +29 -0
- package/dist/channels/manager.js +100 -0
- package/dist/channels/slack/channel.d.ts +26 -0
- package/dist/channels/slack/channel.js +207 -0
- package/dist/channels/slack/markdown.d.ts +19 -0
- package/dist/channels/slack/markdown.js +62 -0
- package/dist/channels/specs.d.ts +21 -0
- package/dist/channels/specs.js +96 -0
- package/dist/channels/telegram/channel.d.ts +18 -0
- package/dist/channels/telegram/channel.js +156 -0
- package/dist/channels/telegram/markdown.d.ts +17 -0
- package/dist/channels/telegram/markdown.js +66 -0
- package/dist/channels/types.d.ts +26 -0
- package/dist/channels/types.js +1 -0
- package/dist/channels/whatsapp/channel.d.ts +23 -0
- package/dist/channels/whatsapp/channel.js +242 -0
- package/dist/channels/whatsapp/markdown.d.ts +20 -0
- package/dist/channels/whatsapp/markdown.js +51 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.js +78 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +13 -0
- package/dist/computer/browser/actions.d.ts +31 -0
- package/dist/computer/browser/actions.js +148 -0
- package/dist/computer/browser/manager.d.ts +55 -0
- package/dist/computer/browser/manager.js +496 -0
- package/dist/computer/browser/profile-badge.d.ts +13 -0
- package/dist/computer/browser/profile-badge.js +67 -0
- package/dist/computer/browser/screenshot.d.ts +5 -0
- package/dist/computer/browser/screenshot.js +21 -0
- package/dist/computer/browser/snapshot.d.ts +30 -0
- package/dist/computer/browser/snapshot.js +242 -0
- package/dist/computer/browser/tools.d.ts +5 -0
- package/dist/computer/browser/tools.js +167 -0
- package/dist/computer/desktop/adapter.d.ts +25 -0
- package/dist/computer/desktop/adapter.js +11 -0
- package/dist/computer/desktop/macos.d.ts +24 -0
- package/dist/computer/desktop/macos.js +223 -0
- package/dist/computer/desktop/tools.d.ts +25 -0
- package/dist/computer/desktop/tools.js +114 -0
- package/dist/config/agent-config.d.ts +41 -0
- package/dist/config/agent-config.js +14 -0
- package/dist/config/model-catalog.d.ts +22 -0
- package/dist/config/model-catalog.js +99 -0
- package/dist/config/store.d.ts +25 -0
- package/dist/config/store.js +143 -0
- package/dist/config.d.ts +103 -0
- package/dist/config.js +224 -0
- package/dist/control-ui/assets/index-BANXNUyt.js +143 -0
- package/dist/control-ui/assets/index-BSUFrP9R.css +1 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
- package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
- package/dist/control-ui/index.html +14 -0
- package/dist/control-ui/vite.svg +1 -0
- package/dist/events.d.ts +2 -0
- package/dist/events.js +11 -0
- package/dist/gateway/broadcast.d.ts +5 -0
- package/dist/gateway/broadcast.js +33 -0
- package/dist/gateway/methods/chat.d.ts +24 -0
- package/dist/gateway/methods/chat.js +19 -0
- package/dist/gateway/methods/config.d.ts +13 -0
- package/dist/gateway/methods/config.js +14 -0
- package/dist/gateway/methods/models.d.ts +10 -0
- package/dist/gateway/methods/models.js +14 -0
- package/dist/gateway/methods/prompt-templates.d.ts +23 -0
- package/dist/gateway/methods/prompt-templates.js +82 -0
- package/dist/gateway/methods/scheduler.d.ts +62 -0
- package/dist/gateway/methods/scheduler.js +129 -0
- package/dist/gateway/methods/sessions.d.ts +26 -0
- package/dist/gateway/methods/sessions.js +54 -0
- package/dist/gateway/methods/skills.d.ts +35 -0
- package/dist/gateway/methods/skills.js +202 -0
- package/dist/gateway/methods/system.d.ts +12 -0
- package/dist/gateway/methods/system.js +39 -0
- package/dist/gateway/methods/tasks.d.ts +21 -0
- package/dist/gateway/methods/tasks.js +46 -0
- package/dist/gateway/methods/teams.d.ts +70 -0
- package/dist/gateway/methods/teams.js +374 -0
- package/dist/gateway/methods/tools.d.ts +6 -0
- package/dist/gateway/methods/tools.js +7 -0
- package/dist/gateway/methods/whatsapp.d.ts +19 -0
- package/dist/gateway/methods/whatsapp.js +35 -0
- package/dist/gateway/rpc.d.ts +38 -0
- package/dist/gateway/rpc.js +75 -0
- package/dist/gateway/server.d.ts +4 -0
- package/dist/gateway/server.js +133 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +212 -0
- package/dist/integrations/github.d.ts +7 -0
- package/dist/integrations/github.js +133 -0
- package/dist/integrations/mcp.d.ts +7 -0
- package/dist/integrations/mcp.js +106 -0
- package/dist/integrations/registry.d.ts +43 -0
- package/dist/integrations/registry.js +258 -0
- package/dist/integrations/scanner.d.ts +10 -0
- package/dist/integrations/scanner.js +122 -0
- package/dist/integrations/twitter.d.ts +10 -0
- package/dist/integrations/twitter.js +120 -0
- package/dist/integrations/types.d.ts +72 -0
- package/dist/integrations/types.js +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +104 -0
- package/dist/markdown/chunk.d.ts +9 -0
- package/dist/markdown/chunk.js +52 -0
- package/dist/markdown/ir.d.ts +37 -0
- package/dist/markdown/ir.js +529 -0
- package/dist/markdown/render.d.ts +22 -0
- package/dist/markdown/render.js +148 -0
- package/dist/markdown/table-render.d.ts +43 -0
- package/dist/markdown/table-render.js +219 -0
- package/dist/markdown/tables.d.ts +17 -0
- package/dist/markdown/tables.js +27 -0
- package/dist/memory/embedding.d.ts +16 -0
- package/dist/memory/embedding.js +66 -0
- package/dist/memory/extractor.d.ts +6 -0
- package/dist/memory/extractor.js +72 -0
- package/dist/memory/search.d.ts +15 -0
- package/dist/memory/search.js +57 -0
- package/dist/memory/store.d.ts +34 -0
- package/dist/memory/store.js +328 -0
- package/dist/memory/types.d.ts +9 -0
- package/dist/memory/types.js +2 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +29 -0
- package/dist/prompt-templates/builtins.d.ts +2 -0
- package/dist/prompt-templates/builtins.js +72 -0
- package/dist/prompt-templates/store.d.ts +39 -0
- package/dist/prompt-templates/store.js +174 -0
- package/dist/prompt-templates/types.d.ts +10 -0
- package/dist/prompt-templates/types.js +1 -0
- package/dist/scheduler/connected-channels.d.ts +24 -0
- package/dist/scheduler/connected-channels.js +57 -0
- package/dist/scheduler/scheduler.d.ts +22 -0
- package/dist/scheduler/scheduler.js +132 -0
- package/dist/scheduler/store.d.ts +27 -0
- package/dist/scheduler/store.js +205 -0
- package/dist/scheduler/types.d.ts +29 -0
- package/dist/scheduler/types.js +1 -0
- package/dist/security/command-validator.d.ts +22 -0
- package/dist/security/command-validator.js +160 -0
- package/dist/security/docker-sandbox.d.ts +48 -0
- package/dist/security/docker-sandbox.js +218 -0
- package/dist/security/env-filter.d.ts +8 -0
- package/dist/security/env-filter.js +41 -0
- package/dist/skills/loader.d.ts +33 -0
- package/dist/skills/loader.js +132 -0
- package/dist/skills/prompt.d.ts +6 -0
- package/dist/skills/prompt.js +17 -0
- package/dist/skills/read-tool.d.ts +7 -0
- package/dist/skills/read-tool.js +24 -0
- package/dist/skills/scanner.d.ts +6 -0
- package/dist/skills/scanner.js +73 -0
- package/dist/skills/types.d.ts +15 -0
- package/dist/skills/types.js +1 -0
- package/dist/tasks/store.d.ts +47 -0
- package/dist/tasks/store.js +193 -0
- package/dist/tasks/types.d.ts +75 -0
- package/dist/tasks/types.js +32 -0
- package/dist/teams/store.d.ts +78 -0
- package/dist/teams/store.js +420 -0
- package/dist/teams/types.d.ts +23 -0
- package/dist/teams/types.js +1 -0
- package/dist/tools/bash.d.ts +16 -0
- package/dist/tools/bash.js +62 -0
- package/dist/tools/channel-history.d.ts +10 -0
- package/dist/tools/channel-history.js +43 -0
- package/dist/tools/delegate.d.ts +16 -0
- package/dist/tools/delegate.js +216 -0
- package/dist/tools/fs.d.ts +4 -0
- package/dist/tools/fs.js +335 -0
- package/dist/tools/integration-toggle.d.ts +14 -0
- package/dist/tools/integration-toggle.js +47 -0
- package/dist/tools/memory.d.ts +13 -0
- package/dist/tools/memory.js +65 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +9 -0
- package/dist/tools/schedule.d.ts +8 -0
- package/dist/tools/schedule.js +219 -0
- package/dist/tools/speak.d.ts +10 -0
- package/dist/tools/speak.js +56 -0
- package/dist/tools/tasks.d.ts +29 -0
- package/dist/tools/tasks.js +92 -0
- package/dist/tools/teams.d.ts +7 -0
- package/dist/tools/teams.js +180 -0
- package/dist/tools/web-fetch.d.ts +3 -0
- package/dist/tools/web-fetch.js +22 -0
- package/dist/tts/edge.d.ts +10 -0
- package/dist/tts/edge.js +60 -0
- package/dist/tts/speak.d.ts +12 -0
- package/dist/tts/speak.js +81 -0
- package/dist/tts/transcribe.d.ts +5 -0
- package/dist/tts/transcribe.js +40 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +22 -0
- package/package.json +90 -0
- package/verybot.js +2 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { mkdirSync } from "fs";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
import { DEFAULT_TEAM_ID, DEFAULT_WORKER_TIMEOUT_S, FALLBACK_ORCHESTRATOR } from "../config/agent-config.js";
|
|
7
|
+
/** Max allowed length for team/agent names. */
|
|
8
|
+
export const MAX_NAME_LENGTH = 128;
|
|
9
|
+
/** Max allowed length for agent identity strings. */
|
|
10
|
+
export const MAX_IDENTITY_LENGTH = 10_000;
|
|
11
|
+
/** Max allowed length for model strings. */
|
|
12
|
+
export const MAX_MODEL_LENGTH = 256;
|
|
13
|
+
/** Max allowed length for caller-provided ids. */
|
|
14
|
+
const MAX_ID_LENGTH = 128;
|
|
15
|
+
/** Hex color pattern: #RRGGBB */
|
|
16
|
+
export const HEX_COLOR_RE = /^#[0-9a-fA-F]{6}$/;
|
|
17
|
+
/** Validate a caller-provided id string. */
|
|
18
|
+
function validateId(id) {
|
|
19
|
+
if (typeof id !== "string" || id.trim().length === 0) {
|
|
20
|
+
throw new Error("id must be a non-empty string");
|
|
21
|
+
}
|
|
22
|
+
if (id.length > MAX_ID_LENGTH) {
|
|
23
|
+
throw new Error(`id exceeds maximum length of ${MAX_ID_LENGTH}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Max allowed length for workspace paths. */
|
|
27
|
+
const MAX_WORKSPACE_LENGTH = 1024;
|
|
28
|
+
/** Max number of user-defined variables per team. */
|
|
29
|
+
const MAX_VARIABLES_COUNT = 50;
|
|
30
|
+
/** Max allowed length for a single variable value. */
|
|
31
|
+
const MAX_VARIABLE_VALUE_LENGTH = 10_000;
|
|
32
|
+
/** Variable key pattern: alphanumeric + underscore. */
|
|
33
|
+
const VARIABLE_KEY_RE = /^\w+$/;
|
|
34
|
+
/**
|
|
35
|
+
* SQLite-backed persistence for teams and agents.
|
|
36
|
+
* Shares the same DB file as MemoryStore, TaskStore, etc.
|
|
37
|
+
*/
|
|
38
|
+
export class TeamStore {
|
|
39
|
+
db;
|
|
40
|
+
constructor(db) {
|
|
41
|
+
this.db = db;
|
|
42
|
+
}
|
|
43
|
+
static async create(dbPath) {
|
|
44
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
45
|
+
const db = new Database(dbPath);
|
|
46
|
+
db.pragma("journal_mode = WAL");
|
|
47
|
+
const store = new TeamStore(db);
|
|
48
|
+
store.createSchema();
|
|
49
|
+
return store;
|
|
50
|
+
}
|
|
51
|
+
createSchema() {
|
|
52
|
+
// Enable foreign key enforcement before creating tables
|
|
53
|
+
this.db.pragma("foreign_keys = ON");
|
|
54
|
+
// Ensure prompt_templates table exists (may already be created by PromptTemplateStore)
|
|
55
|
+
// Needed for agents.template_id FK and toTeamConfigs() JOIN.
|
|
56
|
+
this.db.exec(`
|
|
57
|
+
CREATE TABLE IF NOT EXISTS prompt_templates (
|
|
58
|
+
id TEXT PRIMARY KEY,
|
|
59
|
+
name TEXT NOT NULL UNIQUE,
|
|
60
|
+
description TEXT NOT NULL DEFAULT '',
|
|
61
|
+
role TEXT NOT NULL,
|
|
62
|
+
content TEXT NOT NULL DEFAULT '',
|
|
63
|
+
builtin INTEGER NOT NULL DEFAULT 0,
|
|
64
|
+
created_at INTEGER NOT NULL,
|
|
65
|
+
updated_at INTEGER NOT NULL
|
|
66
|
+
);
|
|
67
|
+
`);
|
|
68
|
+
this.db.exec(`
|
|
69
|
+
CREATE TABLE IF NOT EXISTS teams (
|
|
70
|
+
id TEXT PRIMARY KEY,
|
|
71
|
+
name TEXT NOT NULL UNIQUE,
|
|
72
|
+
created_at INTEGER NOT NULL,
|
|
73
|
+
updated_at INTEGER NOT NULL
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
77
|
+
id TEXT PRIMARY KEY,
|
|
78
|
+
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
|
|
79
|
+
name TEXT NOT NULL,
|
|
80
|
+
role TEXT NOT NULL,
|
|
81
|
+
model TEXT NOT NULL,
|
|
82
|
+
context_window INTEGER DEFAULT 0,
|
|
83
|
+
max_steps INTEGER DEFAULT 0,
|
|
84
|
+
identity TEXT NOT NULL DEFAULT '',
|
|
85
|
+
tools TEXT DEFAULT '[]',
|
|
86
|
+
timeout INTEGER DEFAULT ${DEFAULT_WORKER_TIMEOUT_S},
|
|
87
|
+
created_at INTEGER NOT NULL,
|
|
88
|
+
updated_at INTEGER NOT NULL,
|
|
89
|
+
UNIQUE(team_id, name)
|
|
90
|
+
);
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_agents_team ON agents(team_id);
|
|
92
|
+
`);
|
|
93
|
+
// Add color column to existing tables (idempotent — SQLite errors if column exists)
|
|
94
|
+
try {
|
|
95
|
+
this.db.exec("ALTER TABLE teams ADD COLUMN color TEXT NOT NULL DEFAULT ''");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Column already exists
|
|
99
|
+
}
|
|
100
|
+
// Add template_id FK column to agents (idempotent)
|
|
101
|
+
try {
|
|
102
|
+
this.db.exec("ALTER TABLE agents ADD COLUMN template_id TEXT REFERENCES prompt_templates(id) ON DELETE SET NULL");
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Column already exists
|
|
106
|
+
}
|
|
107
|
+
// Add workspace column to teams (idempotent)
|
|
108
|
+
try {
|
|
109
|
+
this.db.exec("ALTER TABLE teams ADD COLUMN workspace TEXT NOT NULL DEFAULT ''");
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Column already exists
|
|
113
|
+
}
|
|
114
|
+
// Add variables column to teams (JSON-encoded Record<string, string>)
|
|
115
|
+
try {
|
|
116
|
+
this.db.exec("ALTER TABLE teams ADD COLUMN variables TEXT NOT NULL DEFAULT '{}'");
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Column already exists
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// --- Team CRUD ---
|
|
123
|
+
/** Run a function inside a SQLite transaction (all-or-nothing). */
|
|
124
|
+
transaction(fn) {
|
|
125
|
+
return this.db.transaction(fn)();
|
|
126
|
+
}
|
|
127
|
+
createTeam(input) {
|
|
128
|
+
const { name, color = "", workspace = "", variables = {} } = input;
|
|
129
|
+
if (input.id !== undefined)
|
|
130
|
+
validateId(input.id);
|
|
131
|
+
if (name.length > MAX_NAME_LENGTH)
|
|
132
|
+
throw new Error(`Team name exceeds maximum length of ${MAX_NAME_LENGTH}`);
|
|
133
|
+
if (color !== "" && !HEX_COLOR_RE.test(color))
|
|
134
|
+
throw new Error("color must be a valid hex color (e.g. #ef4444)");
|
|
135
|
+
if (workspace.length > MAX_WORKSPACE_LENGTH)
|
|
136
|
+
throw new Error(`workspace exceeds maximum length of ${MAX_WORKSPACE_LENGTH}`);
|
|
137
|
+
validateVariables(variables);
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
const id = input.id ?? randomUUID();
|
|
140
|
+
try {
|
|
141
|
+
this.db.prepare("INSERT INTO teams (id, name, color, workspace, variables, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run(id, name, color, workspace, JSON.stringify(variables), now, now);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
145
|
+
throw new Error(`A team named "${name}" already exists`);
|
|
146
|
+
}
|
|
147
|
+
throw err;
|
|
148
|
+
}
|
|
149
|
+
return { id, name, color, workspace, createdAt: now, updatedAt: now };
|
|
150
|
+
}
|
|
151
|
+
updateTeam(id, input) {
|
|
152
|
+
const existing = this.getTeamById(id);
|
|
153
|
+
if (!existing)
|
|
154
|
+
return null;
|
|
155
|
+
const name = input.name ?? existing.name;
|
|
156
|
+
const color = input.color ?? existing.color;
|
|
157
|
+
const workspace = input.workspace ?? existing.workspace;
|
|
158
|
+
if (color !== "" && !HEX_COLOR_RE.test(color))
|
|
159
|
+
throw new Error("color must be a valid hex color (e.g. #ef4444)");
|
|
160
|
+
if (workspace.length > MAX_WORKSPACE_LENGTH)
|
|
161
|
+
throw new Error(`workspace exceeds maximum length of ${MAX_WORKSPACE_LENGTH}`);
|
|
162
|
+
// Variables: replace entirely if provided, otherwise keep existing
|
|
163
|
+
let variables;
|
|
164
|
+
if (input.variables !== undefined) {
|
|
165
|
+
validateVariables(input.variables);
|
|
166
|
+
variables = input.variables;
|
|
167
|
+
}
|
|
168
|
+
const varsJson = variables !== undefined ? JSON.stringify(variables) : undefined;
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
if (varsJson !== undefined) {
|
|
171
|
+
this.db.prepare("UPDATE teams SET name = ?, color = ?, workspace = ?, variables = ?, updated_at = ? WHERE id = ?").run(name, color, workspace, varsJson, now, id);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.db.prepare("UPDATE teams SET name = ?, color = ?, workspace = ?, updated_at = ? WHERE id = ?").run(name, color, workspace, now, id);
|
|
175
|
+
}
|
|
176
|
+
return { ...existing, name, color, workspace, updatedAt: now };
|
|
177
|
+
}
|
|
178
|
+
deleteTeam(id) {
|
|
179
|
+
if (id === DEFAULT_TEAM_ID)
|
|
180
|
+
throw new Error("Cannot delete the default team");
|
|
181
|
+
const info = this.db.prepare("DELETE FROM teams WHERE id = ?").run(id);
|
|
182
|
+
return info.changes > 0;
|
|
183
|
+
}
|
|
184
|
+
getTeamById(id) {
|
|
185
|
+
const row = this.db.prepare("SELECT * FROM teams WHERE id = ?").get(id);
|
|
186
|
+
return row ? toTeam(row) : null;
|
|
187
|
+
}
|
|
188
|
+
getTeamByName(name) {
|
|
189
|
+
const row = this.db.prepare("SELECT * FROM teams WHERE name = ?").get(name);
|
|
190
|
+
return row ? toTeam(row) : null;
|
|
191
|
+
}
|
|
192
|
+
listTeams() {
|
|
193
|
+
const rows = this.db.prepare("SELECT * FROM teams ORDER BY created_at ASC").all();
|
|
194
|
+
return rows.map(toTeam);
|
|
195
|
+
}
|
|
196
|
+
// --- Agent CRUD ---
|
|
197
|
+
createAgent(teamId, input) {
|
|
198
|
+
if (input.id !== undefined)
|
|
199
|
+
validateId(input.id);
|
|
200
|
+
if (input.name.length > MAX_NAME_LENGTH)
|
|
201
|
+
throw new Error(`Agent name exceeds maximum length of ${MAX_NAME_LENGTH}`);
|
|
202
|
+
if (input.model.length > MAX_MODEL_LENGTH)
|
|
203
|
+
throw new Error(`Model string exceeds maximum length of ${MAX_MODEL_LENGTH}`);
|
|
204
|
+
if (input.identity && input.identity.length > MAX_IDENTITY_LENGTH)
|
|
205
|
+
throw new Error(`Identity exceeds maximum length of ${MAX_IDENTITY_LENGTH}`);
|
|
206
|
+
// Verify team exists (friendly error instead of FK violation)
|
|
207
|
+
if (!this.getTeamById(teamId))
|
|
208
|
+
throw new Error(`Team not found: ${teamId}`);
|
|
209
|
+
// Prevent multiple orchestrators per team
|
|
210
|
+
if (input.role === "orchestrator") {
|
|
211
|
+
const existing = this.db.prepare("SELECT id FROM agents WHERE team_id = ? AND role = 'orchestrator'").get(teamId);
|
|
212
|
+
if (existing)
|
|
213
|
+
throw new Error("Team already has an orchestrator — update the existing one instead");
|
|
214
|
+
}
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
const id = input.id ?? randomUUID();
|
|
217
|
+
try {
|
|
218
|
+
this.db.prepare(`INSERT INTO agents (id, team_id, name, role, model, context_window, max_steps, identity, tools, timeout, template_id, created_at, updated_at)
|
|
219
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, teamId, input.name, input.role, input.model, input.contextWindow ?? 0, input.maxSteps ?? 0, input.identity ?? "", JSON.stringify(input.tools ?? []), input.timeout ?? DEFAULT_WORKER_TIMEOUT_S, input.templateId ?? null, now, now);
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
223
|
+
throw new Error(`Agent "${input.name}" already exists in this team`);
|
|
224
|
+
}
|
|
225
|
+
throw err;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
id, teamId, name: input.name, role: input.role, model: input.model,
|
|
229
|
+
contextWindow: input.contextWindow ?? 0, maxSteps: input.maxSteps ?? 0,
|
|
230
|
+
identity: input.identity ?? "", tools: input.tools ?? [],
|
|
231
|
+
timeout: input.timeout ?? DEFAULT_WORKER_TIMEOUT_S,
|
|
232
|
+
templateId: input.templateId ?? null,
|
|
233
|
+
createdAt: now, updatedAt: now,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
updateAgent(id, input) {
|
|
237
|
+
if (input.name !== undefined && input.name.length > MAX_NAME_LENGTH)
|
|
238
|
+
throw new Error(`Agent name exceeds maximum length of ${MAX_NAME_LENGTH}`);
|
|
239
|
+
if (input.model !== undefined && input.model.length > MAX_MODEL_LENGTH)
|
|
240
|
+
throw new Error(`Model string exceeds maximum length of ${MAX_MODEL_LENGTH}`);
|
|
241
|
+
if (input.identity !== undefined && input.identity.length > MAX_IDENTITY_LENGTH)
|
|
242
|
+
throw new Error(`Identity exceeds maximum length of ${MAX_IDENTITY_LENGTH}`);
|
|
243
|
+
const existing = this.getAgentById(id);
|
|
244
|
+
if (!existing)
|
|
245
|
+
return null;
|
|
246
|
+
const now = Date.now();
|
|
247
|
+
const updated = {
|
|
248
|
+
...existing,
|
|
249
|
+
...(input.name !== undefined && { name: input.name }),
|
|
250
|
+
...(input.role !== undefined && { role: input.role }),
|
|
251
|
+
...(input.model !== undefined && { model: input.model }),
|
|
252
|
+
...(input.contextWindow !== undefined && { contextWindow: input.contextWindow }),
|
|
253
|
+
...(input.maxSteps !== undefined && { maxSteps: input.maxSteps }),
|
|
254
|
+
...(input.identity !== undefined && { identity: input.identity }),
|
|
255
|
+
...(input.tools !== undefined && { tools: input.tools }),
|
|
256
|
+
...(input.timeout !== undefined && { timeout: input.timeout }),
|
|
257
|
+
...(input.templateId !== undefined && { templateId: input.templateId }),
|
|
258
|
+
updatedAt: now,
|
|
259
|
+
};
|
|
260
|
+
this.db.prepare(`UPDATE agents SET name = ?, role = ?, model = ?, context_window = ?, max_steps = ?,
|
|
261
|
+
identity = ?, tools = ?, timeout = ?, template_id = ?, updated_at = ? WHERE id = ?`).run(updated.name, updated.role, updated.model, updated.contextWindow, updated.maxSteps, updated.identity, JSON.stringify(updated.tools), updated.timeout, updated.templateId ?? null, now, id);
|
|
262
|
+
return updated;
|
|
263
|
+
}
|
|
264
|
+
deleteAgent(id) {
|
|
265
|
+
// Prevent deleting a team's only orchestrator
|
|
266
|
+
const agent = this.getAgentById(id);
|
|
267
|
+
if (agent?.role === "orchestrator") {
|
|
268
|
+
throw new Error("Cannot delete a team's orchestrator agent");
|
|
269
|
+
}
|
|
270
|
+
const info = this.db.prepare("DELETE FROM agents WHERE id = ?").run(id);
|
|
271
|
+
return info.changes > 0;
|
|
272
|
+
}
|
|
273
|
+
getAgentById(id) {
|
|
274
|
+
const row = this.db.prepare("SELECT * FROM agents WHERE id = ?").get(id);
|
|
275
|
+
return row ? toAgentRow(row) : null;
|
|
276
|
+
}
|
|
277
|
+
listAgentsByTeam(teamId) {
|
|
278
|
+
const rows = this.db.prepare("SELECT * FROM agents WHERE team_id = ? ORDER BY role ASC, created_at ASC").all(teamId);
|
|
279
|
+
return rows.map(toAgentRow);
|
|
280
|
+
}
|
|
281
|
+
getAgentByName(teamId, name) {
|
|
282
|
+
const row = this.db.prepare("SELECT * FROM agents WHERE team_id = ? AND name = ?").get(teamId, name);
|
|
283
|
+
return row ? toAgentRow(row) : null;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Convert DB rows to the existing TeamConfig[] format so TeamRegistry
|
|
287
|
+
* constructor is unchanged. Uses a single JOIN query instead of N+1.
|
|
288
|
+
*/
|
|
289
|
+
toTeamConfigs() {
|
|
290
|
+
const rows = this.db.prepare(`SELECT t.id AS tid, t.name AS tname, t.color AS tcolor,
|
|
291
|
+
t.workspace AS tworkspace, t.variables AS tvariables,
|
|
292
|
+
a.id, a.name, a.role, a.model, a.context_window, a.max_steps,
|
|
293
|
+
a.identity, a.tools, a.timeout, a.template_id,
|
|
294
|
+
pt.content AS template_content
|
|
295
|
+
FROM teams t LEFT JOIN agents a ON a.team_id = t.id
|
|
296
|
+
LEFT JOIN prompt_templates pt ON a.template_id = pt.id
|
|
297
|
+
ORDER BY t.created_at ASC, a.role ASC, a.created_at ASC`).all();
|
|
298
|
+
const teamMap = new Map();
|
|
299
|
+
for (const row of rows) {
|
|
300
|
+
const tid = row.tid;
|
|
301
|
+
if (!teamMap.has(tid)) {
|
|
302
|
+
let variables = {};
|
|
303
|
+
try {
|
|
304
|
+
variables = JSON.parse(row.tvariables || "{}");
|
|
305
|
+
}
|
|
306
|
+
catch { /* ignore */ }
|
|
307
|
+
teamMap.set(tid, {
|
|
308
|
+
id: tid,
|
|
309
|
+
name: row.tname,
|
|
310
|
+
color: row.tcolor ?? "",
|
|
311
|
+
workspace: row.tworkspace ?? "",
|
|
312
|
+
variables,
|
|
313
|
+
orchestrator: { ...FALLBACK_ORCHESTRATOR },
|
|
314
|
+
workers: [],
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
// LEFT JOIN may produce a row with no agent columns
|
|
318
|
+
if (!row.id)
|
|
319
|
+
continue;
|
|
320
|
+
const team = teamMap.get(tid);
|
|
321
|
+
const agent = toAgentConfig(row, team.variables);
|
|
322
|
+
if (row.role === "orchestrator") {
|
|
323
|
+
team.orchestrator = agent;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
team.workers.push(agent);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return [...teamMap.values()];
|
|
330
|
+
}
|
|
331
|
+
close() {
|
|
332
|
+
this.db.close();
|
|
333
|
+
logger.info("Team store closed");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function toTeam(row) {
|
|
337
|
+
return {
|
|
338
|
+
id: row.id,
|
|
339
|
+
name: row.name,
|
|
340
|
+
color: row.color ?? "",
|
|
341
|
+
workspace: row.workspace ?? "",
|
|
342
|
+
createdAt: row.created_at,
|
|
343
|
+
updatedAt: row.updated_at,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function toAgentConfig(row, teamVariables) {
|
|
347
|
+
let tools = [];
|
|
348
|
+
try {
|
|
349
|
+
tools = JSON.parse(row.tools || "[]");
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
tools = [];
|
|
353
|
+
}
|
|
354
|
+
const templateId = row.template_id ?? null;
|
|
355
|
+
const templateContent = row.template_content ?? null;
|
|
356
|
+
// If a template is linked, resolve identity from the template content
|
|
357
|
+
const rawIdentity = row.identity ?? "";
|
|
358
|
+
let identity = templateId && templateContent != null ? templateContent : rawIdentity;
|
|
359
|
+
// Interpolate team variables into identity ({{varName}} placeholders)
|
|
360
|
+
if (identity && row.tname !== undefined) {
|
|
361
|
+
const vars = {
|
|
362
|
+
teamName: row.tname ?? "",
|
|
363
|
+
workspace: row.tworkspace ?? "",
|
|
364
|
+
...(teamVariables ?? {}),
|
|
365
|
+
};
|
|
366
|
+
identity = identity.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? `{{${key}}}`);
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
id: row.id,
|
|
370
|
+
name: row.name,
|
|
371
|
+
model: row.model,
|
|
372
|
+
contextWindow: row.context_window ?? 0,
|
|
373
|
+
maxSteps: row.max_steps ?? 0,
|
|
374
|
+
identity,
|
|
375
|
+
tools,
|
|
376
|
+
timeout: row.timeout ?? DEFAULT_WORKER_TIMEOUT_S,
|
|
377
|
+
templateId,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function validateVariables(variables) {
|
|
381
|
+
const keys = Object.keys(variables);
|
|
382
|
+
if (keys.length > MAX_VARIABLES_COUNT) {
|
|
383
|
+
throw new Error(`Too many variables (max ${MAX_VARIABLES_COUNT})`);
|
|
384
|
+
}
|
|
385
|
+
for (const key of keys) {
|
|
386
|
+
if (!VARIABLE_KEY_RE.test(key)) {
|
|
387
|
+
throw new Error(`Invalid variable key "${key}": only letters, numbers, and underscores allowed`);
|
|
388
|
+
}
|
|
389
|
+
if (typeof variables[key] !== "string") {
|
|
390
|
+
throw new Error(`Variable "${key}" must have a string value`);
|
|
391
|
+
}
|
|
392
|
+
if (variables[key].length > MAX_VARIABLE_VALUE_LENGTH) {
|
|
393
|
+
throw new Error(`Variable "${key}" value exceeds maximum length of ${MAX_VARIABLE_VALUE_LENGTH}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function toAgentRow(row) {
|
|
398
|
+
let tools = [];
|
|
399
|
+
try {
|
|
400
|
+
tools = JSON.parse(row.tools || "[]");
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
tools = [];
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
id: row.id,
|
|
407
|
+
teamId: row.team_id,
|
|
408
|
+
name: row.name,
|
|
409
|
+
role: row.role,
|
|
410
|
+
model: row.model,
|
|
411
|
+
contextWindow: row.context_window ?? 0,
|
|
412
|
+
maxSteps: row.max_steps ?? 0,
|
|
413
|
+
identity: row.identity ?? "",
|
|
414
|
+
tools,
|
|
415
|
+
timeout: row.timeout ?? DEFAULT_WORKER_TIMEOUT_S,
|
|
416
|
+
templateId: row.template_id ?? null,
|
|
417
|
+
createdAt: row.created_at,
|
|
418
|
+
updatedAt: row.updated_at,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Team {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
color: string;
|
|
5
|
+
workspace: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
updatedAt: number;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentRow {
|
|
10
|
+
id: string;
|
|
11
|
+
teamId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
role: "orchestrator" | "worker";
|
|
14
|
+
model: string;
|
|
15
|
+
contextWindow: number;
|
|
16
|
+
maxSteps: number;
|
|
17
|
+
identity: string;
|
|
18
|
+
tools: string[];
|
|
19
|
+
timeout: number;
|
|
20
|
+
templateId: string | null;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
updatedAt: number;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Tool } from "ai";
|
|
2
|
+
import type { BashConfig } from "../config.js";
|
|
3
|
+
import type { DockerSandbox } from "../security/docker-sandbox.js";
|
|
4
|
+
/** Per-run context injected when creating the bash tool inside Agent.run(). */
|
|
5
|
+
export interface BashToolContext {
|
|
6
|
+
sessionKey: string;
|
|
7
|
+
sandbox: DockerSandbox | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create a bash tool with the given security config and optional per-run context.
|
|
11
|
+
* Returns null in "deny" mode (tool not registered at all).
|
|
12
|
+
*
|
|
13
|
+
* When `ctx.sandbox` is provided, commands execute inside a Docker container.
|
|
14
|
+
* Otherwise, commands execute on the host with sanitized environment.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createBashTool(config: BashConfig, ctx?: BashToolContext): Tool | null;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { validateCommand, isAllowed, DEFAULT_SAFE_BINS } from "../security/command-validator.js";
|
|
5
|
+
import { sanitizeEnv } from "../security/env-filter.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
7
|
+
const EXEC_TIMEOUT = 30_000;
|
|
8
|
+
const MAX_OUTPUT = 10_000;
|
|
9
|
+
const MAX_ERROR = 5_000;
|
|
10
|
+
/**
|
|
11
|
+
* Create a bash tool with the given security config and optional per-run context.
|
|
12
|
+
* Returns null in "deny" mode (tool not registered at all).
|
|
13
|
+
*
|
|
14
|
+
* When `ctx.sandbox` is provided, commands execute inside a Docker container.
|
|
15
|
+
* Otherwise, commands execute on the host with sanitized environment.
|
|
16
|
+
*/
|
|
17
|
+
export function createBashTool(config, ctx) {
|
|
18
|
+
if (config.security === "deny")
|
|
19
|
+
return null;
|
|
20
|
+
// Merge user-provided safe bins with defaults
|
|
21
|
+
const safeBins = new Set([...DEFAULT_SAFE_BINS, ...config.safeBins]);
|
|
22
|
+
return tool({
|
|
23
|
+
description: "Execute a shell command. Confirm with user before destructive commands (rm, mv, chmod). " +
|
|
24
|
+
"Backticks, $(), redirects, and subshells are blocked.",
|
|
25
|
+
inputSchema: z.object({
|
|
26
|
+
command: z.string().describe("The shell command to execute"),
|
|
27
|
+
}),
|
|
28
|
+
execute: async ({ command }) => {
|
|
29
|
+
// 1. Always validate syntax (blocks dangerous tokens in all modes)
|
|
30
|
+
const validation = validateCommand(command);
|
|
31
|
+
if (!validation.ok) {
|
|
32
|
+
logger.warn(`Bash blocked (syntax): ${validation.reason} — ${command}`);
|
|
33
|
+
return `Blocked: ${validation.reason}`;
|
|
34
|
+
}
|
|
35
|
+
// 2. In allowlist mode, check executables against safe bins + allowlist
|
|
36
|
+
if (config.security === "allowlist") {
|
|
37
|
+
if (!isAllowed(command, safeBins, config.allowlist)) {
|
|
38
|
+
logger.warn(`Bash blocked (allowlist): ${command}`);
|
|
39
|
+
return `Blocked: command not in allowlist. Safe bins: ${[...safeBins].join(", ")}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 3. Execute — sandbox if available, otherwise host
|
|
43
|
+
if (ctx?.sandbox) {
|
|
44
|
+
return ctx.sandbox.exec(ctx.sessionKey, command);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const output = execSync(command, {
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
timeout: EXEC_TIMEOUT,
|
|
50
|
+
maxBuffer: 1024 * 1024,
|
|
51
|
+
env: sanitizeEnv(),
|
|
52
|
+
});
|
|
53
|
+
return output.slice(0, MAX_OUTPUT);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
57
|
+
const stderr = err.stderr ?? "";
|
|
58
|
+
return `Error: ${msg}\n${stderr}`.slice(0, MAX_ERROR);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Tool } from "ai";
|
|
2
|
+
import type { ChannelManager } from "../channels/manager.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a read_channel_history tool that lets the LLM fetch recent messages
|
|
5
|
+
* from the current messaging channel (Slack, etc.) on demand.
|
|
6
|
+
*
|
|
7
|
+
* The channelId is resolved fresh at execution time from a callback
|
|
8
|
+
* to avoid stale closures.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createChannelHistoryTool(channelManager: ChannelManager, channelType: string, resolveChannelId: () => string): Tool | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
/** Default number of messages to fetch. */
|
|
5
|
+
const DEFAULT_LIMIT = 20;
|
|
6
|
+
/**
|
|
7
|
+
* Create a read_channel_history tool that lets the LLM fetch recent messages
|
|
8
|
+
* from the current messaging channel (Slack, etc.) on demand.
|
|
9
|
+
*
|
|
10
|
+
* The channelId is resolved fresh at execution time from a callback
|
|
11
|
+
* to avoid stale closures.
|
|
12
|
+
*/
|
|
13
|
+
export function createChannelHistoryTool(channelManager, channelType, resolveChannelId) {
|
|
14
|
+
const ch = channelManager.get(channelType);
|
|
15
|
+
if (!ch?.readHistory)
|
|
16
|
+
return null;
|
|
17
|
+
return tool({
|
|
18
|
+
description: "Read recent messages from the current chat channel or thread. " +
|
|
19
|
+
"Use this when the user references prior conversation, asks what was discussed, " +
|
|
20
|
+
"or needs context about the channel's recent messages. " +
|
|
21
|
+
"Returns messages in chronological order.",
|
|
22
|
+
inputSchema: z.object({
|
|
23
|
+
limit: z
|
|
24
|
+
.number()
|
|
25
|
+
.int()
|
|
26
|
+
.min(1)
|
|
27
|
+
.max(50)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Number of recent messages to fetch (default 20, max 50)"),
|
|
30
|
+
}),
|
|
31
|
+
execute: async ({ limit }) => {
|
|
32
|
+
const channelId = resolveChannelId();
|
|
33
|
+
logger.info(`[channel-history] Reading ${channelType}/${channelId} limit=${limit ?? DEFAULT_LIMIT}`);
|
|
34
|
+
const messages = await ch.readHistory(channelId, limit ?? DEFAULT_LIMIT);
|
|
35
|
+
if (messages.length === 0)
|
|
36
|
+
return `No messages found in channel ${channelId}.`;
|
|
37
|
+
const formatted = messages
|
|
38
|
+
.map((m) => `<@${m.user}>: ${m.text}`)
|
|
39
|
+
.join("\n");
|
|
40
|
+
return `[${channelType} channel ${channelId} — ${messages.length} messages]\n${formatted}`;
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { AgentRegistry } from "../brain/agent-registry.js";
|
|
3
|
+
import type { ChannelStore } from "../brain/channel-store.js";
|
|
4
|
+
import type { DelegationStore } from "../brain/delegation-store.js";
|
|
5
|
+
import type { SessionStore } from "../brain/session-store.js";
|
|
6
|
+
import type { MemoryStore } from "../memory/store.js";
|
|
7
|
+
import type { EmbeddingProvider } from "../memory/embedding.js";
|
|
8
|
+
import { type BrowserConfig } from "../computer/browser/manager.js";
|
|
9
|
+
/**
|
|
10
|
+
* Creates delegation tools:
|
|
11
|
+
* - `delegate` — fires a worker in background, returns channel ID immediately
|
|
12
|
+
* - `read_channel` — reads all messages from a channel (available to orchestrator AND workers)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createDelegationTools(registry: AgentRegistry, channelStore: ChannelStore, delegationStore: DelegationStore, sessionStore: SessionStore, orchestratorId: string, sessionKey: string, memoryStore: MemoryStore | null, embeddingProvider: EmbeddingProvider | null, memoryMaxResults: number, onWorkerComplete: (sessionKey: string, channelId: string) => void, browserConfig: BrowserConfig | null,
|
|
15
|
+
/** Human-readable session label for logs (team name instead of UUID). */
|
|
16
|
+
sessionLabel?: string): ToolSet;
|