@agenticmail/enterprise 0.2.1
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/ARCHITECTURE.md +183 -0
- package/agenticmail-enterprise.db +0 -0
- package/dashboards/README.md +120 -0
- package/dashboards/dotnet/Program.cs +261 -0
- package/dashboards/express/app.js +146 -0
- package/dashboards/go/main.go +513 -0
- package/dashboards/html/index.html +535 -0
- package/dashboards/java/AgenticMailDashboard.java +376 -0
- package/dashboards/php/index.php +414 -0
- package/dashboards/python/app.py +273 -0
- package/dashboards/ruby/app.rb +195 -0
- package/dist/chunk-77IDQJL3.js +7 -0
- package/dist/chunk-7RGCCHIT.js +115 -0
- package/dist/chunk-DXNKR3TG.js +1355 -0
- package/dist/chunk-IQWA44WT.js +970 -0
- package/dist/chunk-LCUZGIDH.js +965 -0
- package/dist/chunk-N2JVTNNJ.js +2553 -0
- package/dist/chunk-O462UJBH.js +363 -0
- package/dist/chunk-PNKVD2UK.js +26 -0
- package/dist/cli.js +218 -0
- package/dist/dashboard/index.html +558 -0
- package/dist/db-adapter-DEWEFNIV.js +7 -0
- package/dist/dynamodb-CCGL2E77.js +426 -0
- package/dist/engine/index.js +1261 -0
- package/dist/index.js +522 -0
- package/dist/mongodb-ODTXIVPV.js +319 -0
- package/dist/mysql-RM3S2FV5.js +521 -0
- package/dist/postgres-LN7A6MGQ.js +518 -0
- package/dist/routes-2JEPIIKC.js +441 -0
- package/dist/routes-74ZLKJKP.js +399 -0
- package/dist/server.js +7 -0
- package/dist/sqlite-3K5YOZ4K.js +439 -0
- package/dist/turso-LDWODSDI.js +442 -0
- package/package.json +49 -0
- package/src/admin/routes.ts +331 -0
- package/src/auth/routes.ts +130 -0
- package/src/cli.ts +260 -0
- package/src/dashboard/index.html +558 -0
- package/src/db/adapter.ts +230 -0
- package/src/db/dynamodb.ts +456 -0
- package/src/db/factory.ts +51 -0
- package/src/db/mongodb.ts +360 -0
- package/src/db/mysql.ts +472 -0
- package/src/db/postgres.ts +479 -0
- package/src/db/sql-schema.ts +123 -0
- package/src/db/sqlite.ts +391 -0
- package/src/db/turso.ts +411 -0
- package/src/deploy/fly.ts +368 -0
- package/src/deploy/managed.ts +213 -0
- package/src/engine/activity.ts +474 -0
- package/src/engine/agent-config.ts +429 -0
- package/src/engine/agenticmail-bridge.ts +296 -0
- package/src/engine/approvals.ts +278 -0
- package/src/engine/db-adapter.ts +682 -0
- package/src/engine/db-schema.ts +335 -0
- package/src/engine/deployer.ts +595 -0
- package/src/engine/index.ts +134 -0
- package/src/engine/knowledge.ts +486 -0
- package/src/engine/lifecycle.ts +635 -0
- package/src/engine/openclaw-hook.ts +371 -0
- package/src/engine/routes.ts +528 -0
- package/src/engine/skills.ts +473 -0
- package/src/engine/tenant.ts +345 -0
- package/src/engine/tool-catalog.ts +189 -0
- package/src/index.ts +64 -0
- package/src/lib/resilience.ts +326 -0
- package/src/middleware/index.ts +286 -0
- package/src/server.ts +310 -0
- package/tsconfig.json +14 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENTICMAIL_TOOLS,
|
|
3
|
+
ALL_TOOLS,
|
|
4
|
+
ActivityTracker,
|
|
5
|
+
AgentConfigGenerator,
|
|
6
|
+
AgentLifecycleManager,
|
|
7
|
+
ApprovalEngine,
|
|
8
|
+
BUILTIN_SKILLS,
|
|
9
|
+
DeploymentEngine,
|
|
10
|
+
KnowledgeBaseEngine,
|
|
11
|
+
OPENCLAW_CORE_TOOLS,
|
|
12
|
+
PLAN_LIMITS,
|
|
13
|
+
PRESET_PROFILES,
|
|
14
|
+
PermissionEngine,
|
|
15
|
+
TOOL_INDEX,
|
|
16
|
+
TenantManager,
|
|
17
|
+
generateOpenClawToolPolicy,
|
|
18
|
+
getToolsBySkill,
|
|
19
|
+
init_tool_catalog
|
|
20
|
+
} from "./chunk-N2JVTNNJ.js";
|
|
21
|
+
import {
|
|
22
|
+
ENGINE_TABLES,
|
|
23
|
+
ENGINE_TABLES_POSTGRES,
|
|
24
|
+
EngineDatabase,
|
|
25
|
+
MIGRATIONS,
|
|
26
|
+
MIGRATIONS_TABLE,
|
|
27
|
+
MIGRATIONS_TABLE_POSTGRES,
|
|
28
|
+
sqliteToMySQL,
|
|
29
|
+
sqliteToPostgres
|
|
30
|
+
} from "./chunk-IQWA44WT.js";
|
|
31
|
+
import {
|
|
32
|
+
CircuitBreaker,
|
|
33
|
+
CircuitOpenError,
|
|
34
|
+
HealthMonitor,
|
|
35
|
+
KeyedRateLimiter,
|
|
36
|
+
RateLimiter,
|
|
37
|
+
ValidationError,
|
|
38
|
+
auditLogger,
|
|
39
|
+
createAdapter,
|
|
40
|
+
createAdminRoutes,
|
|
41
|
+
createAuthRoutes,
|
|
42
|
+
createServer,
|
|
43
|
+
deployToCloud,
|
|
44
|
+
errorHandler,
|
|
45
|
+
generateDockerCompose,
|
|
46
|
+
generateFlyToml,
|
|
47
|
+
getSupportedDatabases,
|
|
48
|
+
rateLimiter,
|
|
49
|
+
requestIdMiddleware,
|
|
50
|
+
requestLogger,
|
|
51
|
+
requireRole,
|
|
52
|
+
securityHeaders,
|
|
53
|
+
validate,
|
|
54
|
+
withRetry
|
|
55
|
+
} from "./chunk-DXNKR3TG.js";
|
|
56
|
+
import {
|
|
57
|
+
DatabaseAdapter
|
|
58
|
+
} from "./chunk-77IDQJL3.js";
|
|
59
|
+
import "./chunk-PNKVD2UK.js";
|
|
60
|
+
|
|
61
|
+
// src/engine/index.ts
|
|
62
|
+
init_tool_catalog();
|
|
63
|
+
|
|
64
|
+
// src/engine/openclaw-hook.ts
|
|
65
|
+
var EnterpriseHook = class {
|
|
66
|
+
config;
|
|
67
|
+
permissionCache = /* @__PURE__ */ new Map();
|
|
68
|
+
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
69
|
+
// callId → toolCallRecordId
|
|
70
|
+
connected = false;
|
|
71
|
+
constructor(config) {
|
|
72
|
+
this.config = {
|
|
73
|
+
engineUrl: config.engineUrl,
|
|
74
|
+
agentId: config.agentId,
|
|
75
|
+
orgId: config.orgId,
|
|
76
|
+
apiToken: config.apiToken || "",
|
|
77
|
+
knowledgeBaseEnabled: config.knowledgeBaseEnabled ?? true,
|
|
78
|
+
kbMaxTokens: config.kbMaxTokens ?? 2e3,
|
|
79
|
+
activityStreamEnabled: config.activityStreamEnabled ?? true,
|
|
80
|
+
failMode: config.failMode ?? "open",
|
|
81
|
+
permissionCacheTtlSec: config.permissionCacheTtlSec ?? 30
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* BEFORE a tool call — check permissions, record start
|
|
86
|
+
*/
|
|
87
|
+
async beforeToolCall(ctx) {
|
|
88
|
+
try {
|
|
89
|
+
const cached = this.permissionCache.get(ctx.toolId);
|
|
90
|
+
if (cached && cached.expires > Date.now()) {
|
|
91
|
+
await this.recordToolCallStart(ctx);
|
|
92
|
+
return cached.result;
|
|
93
|
+
}
|
|
94
|
+
const permResult = await this.apiCall("/api/engine/permissions/check", "POST", {
|
|
95
|
+
agentId: this.config.agentId,
|
|
96
|
+
toolId: ctx.toolId
|
|
97
|
+
});
|
|
98
|
+
const result = {
|
|
99
|
+
allowed: permResult.allowed ?? this.config.failMode === "open",
|
|
100
|
+
reason: permResult.reason || "Unknown",
|
|
101
|
+
requiresApproval: permResult.requiresApproval || false,
|
|
102
|
+
sandbox: permResult.sandbox || false
|
|
103
|
+
};
|
|
104
|
+
this.permissionCache.set(ctx.toolId, {
|
|
105
|
+
result,
|
|
106
|
+
expires: Date.now() + this.config.permissionCacheTtlSec * 1e3
|
|
107
|
+
});
|
|
108
|
+
if (result.requiresApproval && result.allowed) {
|
|
109
|
+
const approval = await this.requestApproval(ctx);
|
|
110
|
+
if (approval) {
|
|
111
|
+
result.approvalId = approval.id;
|
|
112
|
+
if (approval.status === "denied") {
|
|
113
|
+
result.allowed = false;
|
|
114
|
+
result.reason = `Denied by ${approval.decision?.by}: ${approval.decision?.reason || "No reason given"}`;
|
|
115
|
+
} else if (approval.status === "expired") {
|
|
116
|
+
result.allowed = false;
|
|
117
|
+
result.reason = "Approval request expired";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (result.allowed) {
|
|
122
|
+
await this.recordToolCallStart(ctx);
|
|
123
|
+
} else {
|
|
124
|
+
await this.recordActivity("tool_blocked", {
|
|
125
|
+
toolId: ctx.toolId,
|
|
126
|
+
toolName: ctx.toolName,
|
|
127
|
+
reason: result.reason
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const allowed = this.config.failMode === "open";
|
|
133
|
+
return {
|
|
134
|
+
allowed,
|
|
135
|
+
reason: allowed ? `Engine unreachable (fail-open): ${error.message}` : `Engine unreachable (fail-closed): ${error.message}`,
|
|
136
|
+
requiresApproval: false
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* AFTER a tool call — record result, update usage
|
|
142
|
+
*/
|
|
143
|
+
async afterToolCall(ctx, result) {
|
|
144
|
+
try {
|
|
145
|
+
await this.apiCall("/api/engine/agents/" + this.config.agentId + "/record-tool-call", "POST", {
|
|
146
|
+
toolId: ctx.toolId,
|
|
147
|
+
tokensUsed: (result.inputTokens || 0) + (result.outputTokens || 0),
|
|
148
|
+
costUsd: result.costUsd || 0,
|
|
149
|
+
isExternalAction: this.isExternalAction(ctx.toolId),
|
|
150
|
+
error: !result.success
|
|
151
|
+
});
|
|
152
|
+
await this.recordActivity(result.success ? "tool_call_end" : "tool_call_error", {
|
|
153
|
+
toolId: ctx.toolId,
|
|
154
|
+
toolName: ctx.toolName,
|
|
155
|
+
success: result.success,
|
|
156
|
+
error: result.error,
|
|
157
|
+
durationMs: ctx.timestamp ? Date.now() - ctx.timestamp.getTime() : void 0,
|
|
158
|
+
inputTokens: result.inputTokens,
|
|
159
|
+
outputTokens: result.outputTokens,
|
|
160
|
+
costUsd: result.costUsd
|
|
161
|
+
});
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* BEFORE an LLM call — inject knowledge base context
|
|
167
|
+
*/
|
|
168
|
+
async getKnowledgeContext(userMessage) {
|
|
169
|
+
if (!this.config.knowledgeBaseEnabled) return null;
|
|
170
|
+
try {
|
|
171
|
+
const result = await this.apiCall("/api/engine/knowledge-bases/context", "POST", {
|
|
172
|
+
agentId: this.config.agentId,
|
|
173
|
+
query: userMessage,
|
|
174
|
+
maxTokens: this.config.kbMaxTokens
|
|
175
|
+
});
|
|
176
|
+
return result.context || null;
|
|
177
|
+
} catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* ON session start
|
|
183
|
+
*/
|
|
184
|
+
async onSessionStart(sessionId) {
|
|
185
|
+
try {
|
|
186
|
+
await this.recordActivity("session_start", { sessionId });
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* ON session end
|
|
192
|
+
*/
|
|
193
|
+
async onSessionEnd(sessionId) {
|
|
194
|
+
try {
|
|
195
|
+
await this.recordActivity("session_end", { sessionId });
|
|
196
|
+
} catch {
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Record a conversation message
|
|
201
|
+
*/
|
|
202
|
+
async recordMessage(opts) {
|
|
203
|
+
try {
|
|
204
|
+
await this.apiCall("/api/engine/activity/record-message", "POST", {
|
|
205
|
+
agentId: this.config.agentId,
|
|
206
|
+
...opts
|
|
207
|
+
});
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get the tool policy for this agent (used on startup to configure OpenClaw)
|
|
213
|
+
*/
|
|
214
|
+
async getToolPolicy() {
|
|
215
|
+
try {
|
|
216
|
+
return await this.apiCall(`/api/engine/permissions/${this.config.agentId}/policy`, "GET");
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Check if engine is reachable
|
|
223
|
+
*/
|
|
224
|
+
async healthCheck() {
|
|
225
|
+
try {
|
|
226
|
+
const result = await this.apiCall("/health", "GET");
|
|
227
|
+
this.connected = result.status === "ok";
|
|
228
|
+
return this.connected;
|
|
229
|
+
} catch {
|
|
230
|
+
this.connected = false;
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ─── Private ──────────────────────────────────────────
|
|
235
|
+
async requestApproval(ctx) {
|
|
236
|
+
try {
|
|
237
|
+
const result = await this.apiCall("/api/engine/approvals/request", "POST", {
|
|
238
|
+
agentId: this.config.agentId,
|
|
239
|
+
agentName: this.config.agentId,
|
|
240
|
+
toolId: ctx.toolId,
|
|
241
|
+
toolName: ctx.toolName,
|
|
242
|
+
parameters: ctx.parameters,
|
|
243
|
+
context: `Session ${ctx.sessionId}`
|
|
244
|
+
});
|
|
245
|
+
if (result.request?.id) {
|
|
246
|
+
const start = Date.now();
|
|
247
|
+
while (Date.now() - start < 3e5) {
|
|
248
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
249
|
+
const check = await this.apiCall(`/api/engine/approvals/${result.request.id}`, "GET");
|
|
250
|
+
if (check.request?.status !== "pending") return check.request;
|
|
251
|
+
}
|
|
252
|
+
return { status: "expired" };
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
} catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async recordToolCallStart(ctx) {
|
|
260
|
+
if (!this.config.activityStreamEnabled) return;
|
|
261
|
+
try {
|
|
262
|
+
await this.recordActivity("tool_call_start", {
|
|
263
|
+
toolId: ctx.toolId,
|
|
264
|
+
toolName: ctx.toolName,
|
|
265
|
+
sessionId: ctx.sessionId
|
|
266
|
+
});
|
|
267
|
+
} catch {
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async recordActivity(type, data) {
|
|
271
|
+
try {
|
|
272
|
+
await this.apiCall("/api/engine/activity/record", "POST", {
|
|
273
|
+
agentId: this.config.agentId,
|
|
274
|
+
orgId: this.config.orgId,
|
|
275
|
+
type,
|
|
276
|
+
data
|
|
277
|
+
});
|
|
278
|
+
} catch {
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
isExternalAction(toolId) {
|
|
282
|
+
const externalTools = [
|
|
283
|
+
"agenticmail_send",
|
|
284
|
+
"agenticmail_reply",
|
|
285
|
+
"agenticmail_forward",
|
|
286
|
+
"agenticmail_sms_send",
|
|
287
|
+
"message",
|
|
288
|
+
"tts"
|
|
289
|
+
];
|
|
290
|
+
return externalTools.includes(toolId);
|
|
291
|
+
}
|
|
292
|
+
async apiCall(path, method, body) {
|
|
293
|
+
const opts = {
|
|
294
|
+
method,
|
|
295
|
+
headers: {
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
...this.config.apiToken ? { "Authorization": `Bearer ${this.config.apiToken}` } : {}
|
|
298
|
+
},
|
|
299
|
+
signal: AbortSignal.timeout(5e3)
|
|
300
|
+
};
|
|
301
|
+
if (body && method !== "GET") opts.body = JSON.stringify(body);
|
|
302
|
+
const resp = await fetch(`${this.config.engineUrl}${path}`, opts);
|
|
303
|
+
return resp.json();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
function createEnterpriseHook(config) {
|
|
307
|
+
return new EnterpriseHook(config);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/engine/agenticmail-bridge.ts
|
|
311
|
+
init_tool_catalog();
|
|
312
|
+
var AgenticMailBridge = class {
|
|
313
|
+
hook;
|
|
314
|
+
config;
|
|
315
|
+
toolPolicy = null;
|
|
316
|
+
sessionId = "";
|
|
317
|
+
rateLimiter = { count: 0, resetAt: 0 };
|
|
318
|
+
constructor(config) {
|
|
319
|
+
this.config = config;
|
|
320
|
+
this.hook = new EnterpriseHook(config);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Initialize the bridge — load config, verify connection
|
|
324
|
+
*/
|
|
325
|
+
async initialize() {
|
|
326
|
+
const connected = await this.hook.healthCheck();
|
|
327
|
+
if (connected && this.config.autoConfigureTools !== false) {
|
|
328
|
+
this.toolPolicy = await this.hook.getToolPolicy();
|
|
329
|
+
}
|
|
330
|
+
if (this.config.verbose) {
|
|
331
|
+
console.log(`[Enterprise] Bridge initialized. Connected: ${connected}`);
|
|
332
|
+
if (this.toolPolicy) {
|
|
333
|
+
console.log(`[Enterprise] Tool policy: ${this.toolPolicy.allowedTools.length} allowed, ${this.toolPolicy.blockedTools.length} blocked`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return { connected, toolPolicy: this.toolPolicy };
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get a tool interceptor that can be registered with OpenClaw
|
|
340
|
+
*/
|
|
341
|
+
getInterceptor() {
|
|
342
|
+
return {
|
|
343
|
+
beforeTool: async (toolId, params, sessionId) => {
|
|
344
|
+
this.sessionId = sessionId;
|
|
345
|
+
if (this.toolPolicy?.blockedTools.includes(toolId)) {
|
|
346
|
+
if (this.config.verbose) console.log(`[Enterprise] BLOCKED: ${toolId} (policy)`);
|
|
347
|
+
return { allowed: false, reason: `Tool "${toolId}" is blocked by enterprise policy` };
|
|
348
|
+
}
|
|
349
|
+
const now = Date.now();
|
|
350
|
+
if (now > this.rateLimiter.resetAt) {
|
|
351
|
+
this.rateLimiter = { count: 0, resetAt: now + 6e4 };
|
|
352
|
+
}
|
|
353
|
+
this.rateLimiter.count++;
|
|
354
|
+
const limit = this.toolPolicy?.rateLimits?.toolCallsPerMinute || 120;
|
|
355
|
+
if (this.rateLimiter.count > limit) {
|
|
356
|
+
return { allowed: false, reason: `Rate limit exceeded: ${this.rateLimiter.count}/${limit} calls/min` };
|
|
357
|
+
}
|
|
358
|
+
const result = await this.hook.beforeToolCall({
|
|
359
|
+
toolId,
|
|
360
|
+
toolName: toolId,
|
|
361
|
+
parameters: params,
|
|
362
|
+
sessionId,
|
|
363
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
364
|
+
});
|
|
365
|
+
if (this.config.verbose && !result.allowed) {
|
|
366
|
+
console.log(`[Enterprise] BLOCKED: ${toolId} \u2014 ${result.reason}`);
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
allowed: result.allowed,
|
|
370
|
+
reason: result.reason,
|
|
371
|
+
modifiedParams: result.modifiedParameters
|
|
372
|
+
};
|
|
373
|
+
},
|
|
374
|
+
afterTool: async (toolId, params, result, sessionId) => {
|
|
375
|
+
await this.hook.afterToolCall(
|
|
376
|
+
{ toolId, toolName: toolId, parameters: params, sessionId, timestamp: /* @__PURE__ */ new Date() },
|
|
377
|
+
{
|
|
378
|
+
success: !result?.error,
|
|
379
|
+
output: typeof result === "string" ? result : JSON.stringify(result)?.slice(0, 500),
|
|
380
|
+
error: result?.error
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get knowledge base context to inject before LLM call
|
|
388
|
+
*/
|
|
389
|
+
async getKBContext(userMessage) {
|
|
390
|
+
return this.hook.getKnowledgeContext(userMessage);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Generate coordination context for the agent's system prompt
|
|
394
|
+
*/
|
|
395
|
+
getCoordinationContext() {
|
|
396
|
+
if (!this.config.injectCoordinationContext) return "";
|
|
397
|
+
const blocked = this.toolPolicy?.blockedTools || [];
|
|
398
|
+
const needsApproval = this.toolPolicy?.approvalRequired || [];
|
|
399
|
+
let ctx = "\n<enterprise-context>\n";
|
|
400
|
+
ctx += "\u{1F3E2} This agent is managed by AgenticMail Enterprise.\n";
|
|
401
|
+
if (blocked.length > 0) {
|
|
402
|
+
ctx += `\u26D4 Blocked tools (do not attempt): ${blocked.join(", ")}
|
|
403
|
+
`;
|
|
404
|
+
}
|
|
405
|
+
if (needsApproval.length > 0) {
|
|
406
|
+
ctx += `\u26A0\uFE0F Tools requiring human approval: ${needsApproval.join(", ")}
|
|
407
|
+
`;
|
|
408
|
+
ctx += "When using these tools, the call will pause until a human approves or denies.\n";
|
|
409
|
+
}
|
|
410
|
+
ctx += "</enterprise-context>\n";
|
|
411
|
+
return ctx;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Notify engine of session lifecycle
|
|
415
|
+
*/
|
|
416
|
+
async onSessionStart(sessionId) {
|
|
417
|
+
this.sessionId = sessionId;
|
|
418
|
+
await this.hook.onSessionStart(sessionId);
|
|
419
|
+
}
|
|
420
|
+
async onSessionEnd(sessionId) {
|
|
421
|
+
await this.hook.onSessionEnd(sessionId);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Record a message in the conversation log
|
|
425
|
+
*/
|
|
426
|
+
async recordMessage(role, content, opts) {
|
|
427
|
+
await this.hook.recordMessage({
|
|
428
|
+
sessionId: this.sessionId,
|
|
429
|
+
role,
|
|
430
|
+
content,
|
|
431
|
+
channel: opts?.channel,
|
|
432
|
+
tokenCount: opts?.tokenCount || Math.ceil(content.length / 4)
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get the loaded tool policy
|
|
437
|
+
*/
|
|
438
|
+
getToolPolicy() {
|
|
439
|
+
return this.toolPolicy;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Generate OpenClaw-compatible config for tools.allow / tools.deny
|
|
443
|
+
* This is what gets written to the gateway config
|
|
444
|
+
*/
|
|
445
|
+
getOpenClawToolConfig() {
|
|
446
|
+
if (!this.toolPolicy) return {};
|
|
447
|
+
return generateOpenClawToolPolicy(
|
|
448
|
+
this.toolPolicy.allowedTools,
|
|
449
|
+
this.toolPolicy.blockedTools
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
async function createAgenticMailBridge(config) {
|
|
454
|
+
const bridge = new AgenticMailBridge({
|
|
455
|
+
autoConfigureTools: true,
|
|
456
|
+
injectCoordinationContext: true,
|
|
457
|
+
verbose: false,
|
|
458
|
+
failMode: "open",
|
|
459
|
+
permissionCacheTtlSec: 30,
|
|
460
|
+
kbMaxTokens: 2e3,
|
|
461
|
+
knowledgeBaseEnabled: true,
|
|
462
|
+
activityStreamEnabled: true,
|
|
463
|
+
...config
|
|
464
|
+
});
|
|
465
|
+
await bridge.initialize();
|
|
466
|
+
return bridge;
|
|
467
|
+
}
|
|
468
|
+
export {
|
|
469
|
+
AGENTICMAIL_TOOLS,
|
|
470
|
+
ALL_TOOLS,
|
|
471
|
+
ActivityTracker,
|
|
472
|
+
AgentConfigGenerator,
|
|
473
|
+
AgentLifecycleManager,
|
|
474
|
+
AgenticMailBridge,
|
|
475
|
+
ApprovalEngine,
|
|
476
|
+
BUILTIN_SKILLS,
|
|
477
|
+
CircuitBreaker,
|
|
478
|
+
CircuitOpenError,
|
|
479
|
+
DatabaseAdapter,
|
|
480
|
+
DeploymentEngine,
|
|
481
|
+
ENGINE_TABLES,
|
|
482
|
+
ENGINE_TABLES_POSTGRES,
|
|
483
|
+
EngineDatabase,
|
|
484
|
+
EnterpriseHook,
|
|
485
|
+
HealthMonitor,
|
|
486
|
+
KeyedRateLimiter,
|
|
487
|
+
KnowledgeBaseEngine,
|
|
488
|
+
MIGRATIONS,
|
|
489
|
+
MIGRATIONS_TABLE,
|
|
490
|
+
MIGRATIONS_TABLE_POSTGRES,
|
|
491
|
+
OPENCLAW_CORE_TOOLS,
|
|
492
|
+
PLAN_LIMITS,
|
|
493
|
+
PRESET_PROFILES,
|
|
494
|
+
PermissionEngine,
|
|
495
|
+
RateLimiter,
|
|
496
|
+
TOOL_INDEX,
|
|
497
|
+
TenantManager,
|
|
498
|
+
ValidationError,
|
|
499
|
+
auditLogger,
|
|
500
|
+
createAdapter,
|
|
501
|
+
createAdminRoutes,
|
|
502
|
+
createAgenticMailBridge,
|
|
503
|
+
createAuthRoutes,
|
|
504
|
+
createEnterpriseHook,
|
|
505
|
+
createServer,
|
|
506
|
+
deployToCloud,
|
|
507
|
+
errorHandler,
|
|
508
|
+
generateDockerCompose,
|
|
509
|
+
generateFlyToml,
|
|
510
|
+
generateOpenClawToolPolicy,
|
|
511
|
+
getSupportedDatabases,
|
|
512
|
+
getToolsBySkill,
|
|
513
|
+
rateLimiter,
|
|
514
|
+
requestIdMiddleware,
|
|
515
|
+
requestLogger,
|
|
516
|
+
requireRole,
|
|
517
|
+
securityHeaders,
|
|
518
|
+
sqliteToMySQL,
|
|
519
|
+
sqliteToPostgres,
|
|
520
|
+
validate,
|
|
521
|
+
withRetry
|
|
522
|
+
};
|