botinabox 2.4.2 → 2.5.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/LICENSE +21 -21
- package/README.md +190 -190
- package/bin/botinabox.mjs +2 -2
- package/dist/channels/slack/index.d.ts +1 -1
- package/dist/{chat-pipeline-BWrtVqEP.d.ts → chat-pipeline-DuNX5WoL.d.ts} +3 -0
- package/dist/cli.js +0 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +64 -27
- package/package.json +100 -99
- package/dist/channels/discord/adapter.d.ts +0 -32
- package/dist/channels/discord/adapter.js +0 -70
- package/dist/channels/discord/inbound.d.ts +0 -25
- package/dist/channels/discord/inbound.js +0 -24
- package/dist/channels/discord/models.d.ts +0 -8
- package/dist/channels/discord/models.js +0 -5
- package/dist/channels/discord/outbound.d.ts +0 -14
- package/dist/channels/discord/outbound.js +0 -38
- package/dist/channels/slack/adapter.d.ts +0 -33
- package/dist/channels/slack/adapter.js +0 -74
- package/dist/channels/slack/inbound.d.ts +0 -59
- package/dist/channels/slack/inbound.js +0 -96
- package/dist/channels/slack/models.d.ts +0 -9
- package/dist/channels/slack/models.js +0 -5
- package/dist/channels/slack/outbound.d.ts +0 -12
- package/dist/channels/slack/outbound.js +0 -18
- package/dist/channels/slack/transcribe.d.ts +0 -41
- package/dist/channels/slack/transcribe.js +0 -106
- package/dist/channels/webhook/adapter.d.ts +0 -23
- package/dist/channels/webhook/adapter.js +0 -86
- package/dist/channels/webhook/hmac.d.ts +0 -13
- package/dist/channels/webhook/hmac.js +0 -26
- package/dist/channels/webhook/models.d.ts +0 -9
- package/dist/channels/webhook/models.js +0 -5
- package/dist/channels/webhook/server.d.ts +0 -20
- package/dist/channels/webhook/server.js +0 -91
- package/dist/chat-pipeline-C-XlLGNl.d.ts +0 -648
- package/dist/chat-pipeline-CR1KF6eX.d.ts +0 -652
- package/dist/chat-pipeline-DisuC8SB.d.ts +0 -643
- package/dist/chunk-2LGXQPEA.js +0 -41
- package/dist/chunk-3X3YKI4T.js +0 -357
- package/dist/chunk-D47AIFOD.js +0 -351
- package/dist/chunk-DSNJKNEW.js +0 -328
- package/dist/chunk-GS2JFL6I.js +0 -144
- package/dist/chunk-J6S6QMUY.js +0 -144
- package/dist/chunk-QLA6YOFN.js +0 -22
- package/dist/chunk-UACT2WXX.js +0 -381
- package/dist/cli/templates/config.yml.d.ts +0 -7
- package/dist/cli/templates/config.yml.js +0 -61
- package/dist/cli/templates/env.d.ts +0 -1
- package/dist/cli/templates/env.js +0 -30
- package/dist/cli/templates/index.ts.d.ts +0 -2
- package/dist/cli/templates/index.ts.js +0 -30
- package/dist/cli/templates/package.json.d.ts +0 -5
- package/dist/cli/templates/package.json.js +0 -28
- package/dist/connector-DDahQw-2.d.ts +0 -63
- package/dist/connectors/google/calendar-connector.d.ts +0 -40
- package/dist/connectors/google/calendar-connector.js +0 -243
- package/dist/connectors/google/gmail-connector.d.ts +0 -42
- package/dist/connectors/google/gmail-connector.js +0 -345
- package/dist/connectors/google/oauth.d.ts +0 -48
- package/dist/connectors/google/oauth.js +0 -112
- package/dist/connectors/google/types.d.ts +0 -78
- package/dist/connectors/google/types.js +0 -2
- package/dist/core/chat/auto-discovery.d.ts +0 -16
- package/dist/core/chat/auto-discovery.js +0 -54
- package/dist/core/chat/channel-registry.d.ts +0 -45
- package/dist/core/chat/channel-registry.js +0 -96
- package/dist/core/chat/chat-pipeline.d.ts +0 -113
- package/dist/core/chat/chat-pipeline.js +0 -395
- package/dist/core/chat/chat-responder.d.ts +0 -90
- package/dist/core/chat/chat-responder.js +0 -185
- package/dist/core/chat/formatter.d.ts +0 -11
- package/dist/core/chat/formatter.js +0 -60
- package/dist/core/chat/index.d.ts +0 -24
- package/dist/core/chat/index.js +0 -18
- package/dist/core/chat/message-interpreter.d.ts +0 -91
- package/dist/core/chat/message-interpreter.js +0 -166
- package/dist/core/chat/message-store.d.ts +0 -66
- package/dist/core/chat/message-store.js +0 -131
- package/dist/core/chat/notification-queue.d.ts +0 -34
- package/dist/core/chat/notification-queue.js +0 -111
- package/dist/core/chat/pipeline.d.ts +0 -38
- package/dist/core/chat/pipeline.js +0 -89
- package/dist/core/chat/policies.d.ts +0 -16
- package/dist/core/chat/policies.js +0 -25
- package/dist/core/chat/routing.d.ts +0 -17
- package/dist/core/chat/routing.js +0 -36
- package/dist/core/chat/session-key.d.ts +0 -30
- package/dist/core/chat/session-key.js +0 -65
- package/dist/core/chat/session-manager.d.ts +0 -17
- package/dist/core/chat/session-manager.js +0 -23
- package/dist/core/chat/text-chunker.d.ts +0 -9
- package/dist/core/chat/text-chunker.js +0 -48
- package/dist/core/chat/triage-router.d.ts +0 -75
- package/dist/core/chat/triage-router.js +0 -142
- package/dist/core/chat/types.d.ts +0 -5
- package/dist/core/chat/types.js +0 -5
- package/dist/core/config/defaults.d.ts +0 -2
- package/dist/core/config/defaults.js +0 -38
- package/dist/core/config/index.d.ts +0 -6
- package/dist/core/config/index.js +0 -4
- package/dist/core/config/interpolate.d.ts +0 -5
- package/dist/core/config/interpolate.js +0 -27
- package/dist/core/config/loader.d.ts +0 -24
- package/dist/core/config/loader.js +0 -59
- package/dist/core/config/schema.d.ts +0 -5
- package/dist/core/config/schema.js +0 -119
- package/dist/core/data/core-entity-contexts.d.ts +0 -14
- package/dist/core/data/core-entity-contexts.js +0 -197
- package/dist/core/data/core-migrations.d.ts +0 -5
- package/dist/core/data/core-migrations.js +0 -45
- package/dist/core/data/core-schema.d.ts +0 -6
- package/dist/core/data/core-schema.js +0 -454
- package/dist/core/data/data-store.d.ts +0 -67
- package/dist/core/data/data-store.js +0 -218
- package/dist/core/data/domain-entity-contexts.d.ts +0 -29
- package/dist/core/data/domain-entity-contexts.js +0 -321
- package/dist/core/data/domain-schema.d.ts +0 -36
- package/dist/core/data/domain-schema.js +0 -323
- package/dist/core/data/index.d.ts +0 -7
- package/dist/core/data/index.js +0 -7
- package/dist/core/data/types.d.ts +0 -111
- package/dist/core/data/types.js +0 -1
- package/dist/core/hooks/hook-bus.d.ts +0 -18
- package/dist/core/hooks/hook-bus.js +0 -120
- package/dist/core/hooks/index.d.ts +0 -2
- package/dist/core/hooks/index.js +0 -1
- package/dist/core/hooks/types.d.ts +0 -19
- package/dist/core/hooks/types.js +0 -1
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.js +0 -4
- package/dist/core/llm/auto-discovery.d.ts +0 -11
- package/dist/core/llm/auto-discovery.js +0 -49
- package/dist/core/llm/cost-tracker.d.ts +0 -6
- package/dist/core/llm/cost-tracker.js +0 -38
- package/dist/core/llm/index.d.ts +0 -4
- package/dist/core/llm/index.js +0 -3
- package/dist/core/llm/model-router.d.ts +0 -25
- package/dist/core/llm/model-router.js +0 -49
- package/dist/core/llm/provider-registry.d.ts +0 -9
- package/dist/core/llm/provider-registry.js +0 -25
- package/dist/core/llm/types.d.ts +0 -2
- package/dist/core/llm/types.js +0 -2
- package/dist/core/orchestrator/adapters/api-adapter.d.ts +0 -34
- package/dist/core/orchestrator/adapters/api-adapter.js +0 -88
- package/dist/core/orchestrator/adapters/cli-adapter.d.ts +0 -22
- package/dist/core/orchestrator/adapters/cli-adapter.js +0 -69
- package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +0 -35
- package/dist/core/orchestrator/adapters/deterministic-adapter.js +0 -75
- package/dist/core/orchestrator/adapters/env-whitelist.d.ts +0 -4
- package/dist/core/orchestrator/adapters/env-whitelist.js +0 -27
- package/dist/core/orchestrator/adapters/output-extractor.d.ts +0 -11
- package/dist/core/orchestrator/adapters/output-extractor.js +0 -59
- package/dist/core/orchestrator/adapters/process-manager.d.ts +0 -15
- package/dist/core/orchestrator/adapters/process-manager.js +0 -26
- package/dist/core/orchestrator/adapters/tool-loop.d.ts +0 -22
- package/dist/core/orchestrator/adapters/tool-loop.js +0 -66
- package/dist/core/orchestrator/agent-registry.d.ts +0 -31
- package/dist/core/orchestrator/agent-registry.js +0 -135
- package/dist/core/orchestrator/budget-controller.d.ts +0 -19
- package/dist/core/orchestrator/budget-controller.js +0 -73
- package/dist/core/orchestrator/chain-guard.d.ts +0 -14
- package/dist/core/orchestrator/chain-guard.js +0 -23
- package/dist/core/orchestrator/circuit-breaker.d.ts +0 -65
- package/dist/core/orchestrator/circuit-breaker.js +0 -159
- package/dist/core/orchestrator/claude-stream-parser.d.ts +0 -31
- package/dist/core/orchestrator/claude-stream-parser.js +0 -99
- package/dist/core/orchestrator/config-revisions.d.ts +0 -6
- package/dist/core/orchestrator/config-revisions.js +0 -17
- package/dist/core/orchestrator/dependency-resolver.d.ts +0 -20
- package/dist/core/orchestrator/dependency-resolver.js +0 -78
- package/dist/core/orchestrator/governance-gate.d.ts +0 -110
- package/dist/core/orchestrator/governance-gate.js +0 -170
- package/dist/core/orchestrator/learning-pipeline.d.ts +0 -109
- package/dist/core/orchestrator/learning-pipeline.js +0 -249
- package/dist/core/orchestrator/loop-detector.d.ts +0 -51
- package/dist/core/orchestrator/loop-detector.js +0 -133
- package/dist/core/orchestrator/ndjson-logger.d.ts +0 -6
- package/dist/core/orchestrator/ndjson-logger.js +0 -18
- package/dist/core/orchestrator/permission-relay.d.ts +0 -72
- package/dist/core/orchestrator/permission-relay.js +0 -164
- package/dist/core/orchestrator/run-manager.d.ts +0 -31
- package/dist/core/orchestrator/run-manager.js +0 -178
- package/dist/core/orchestrator/scheduler.d.ts +0 -70
- package/dist/core/orchestrator/scheduler.js +0 -198
- package/dist/core/orchestrator/secret-store.d.ts +0 -57
- package/dist/core/orchestrator/secret-store.js +0 -171
- package/dist/core/orchestrator/session-manager.d.ts +0 -13
- package/dist/core/orchestrator/session-manager.js +0 -66
- package/dist/core/orchestrator/task-queue.d.ts +0 -34
- package/dist/core/orchestrator/task-queue.js +0 -83
- package/dist/core/orchestrator/template-interpolate.d.ts +0 -5
- package/dist/core/orchestrator/template-interpolate.js +0 -18
- package/dist/core/orchestrator/user-registry.d.ts +0 -47
- package/dist/core/orchestrator/user-registry.js +0 -76
- package/dist/core/orchestrator/wakeup-queue.d.ts +0 -9
- package/dist/core/orchestrator/wakeup-queue.js +0 -45
- package/dist/core/orchestrator/workflow-engine.d.ts +0 -47
- package/dist/core/orchestrator/workflow-engine.js +0 -204
- package/dist/core/security/audit.d.ts +0 -20
- package/dist/core/security/audit.js +0 -33
- package/dist/core/security/column-validator.d.ts +0 -20
- package/dist/core/security/column-validator.js +0 -37
- package/dist/core/security/index.d.ts +0 -5
- package/dist/core/security/index.js +0 -5
- package/dist/core/security/process-env.d.ts +0 -13
- package/dist/core/security/process-env.js +0 -49
- package/dist/core/security/sanitizer.d.ts +0 -11
- package/dist/core/security/sanitizer.js +0 -39
- package/dist/core/security/types.d.ts +0 -11
- package/dist/core/security/types.js +0 -1
- package/dist/core/update/auto-update.d.ts +0 -21
- package/dist/core/update/auto-update.js +0 -102
- package/dist/core/update/backup-manager.d.ts +0 -7
- package/dist/core/update/backup-manager.js +0 -24
- package/dist/core/update/index.d.ts +0 -8
- package/dist/core/update/index.js +0 -6
- package/dist/core/update/migration-hooks.d.ts +0 -11
- package/dist/core/update/migration-hooks.js +0 -10
- package/dist/core/update/types.d.ts +0 -11
- package/dist/core/update/types.js +0 -1
- package/dist/core/update/update-checker.d.ts +0 -11
- package/dist/core/update/update-checker.js +0 -63
- package/dist/core/update/update-manager.d.ts +0 -25
- package/dist/core/update/update-manager.js +0 -101
- package/dist/core/update/version-utils.d.ts +0 -6
- package/dist/core/update/version-utils.js +0 -34
- package/dist/gmail-connector-2FVYTQJH.js +0 -6
- package/dist/gmail-connector-MNUBRNFM.js +0 -6
- package/dist/gmail-connector-PS2VLGNE.js +0 -6
- package/dist/gmail-connector-ULSMN6X2.js +0 -6
- package/dist/gmail-connector-URRFX6A3.js +0 -6
- package/dist/inbound-AFBUPSPG.js +0 -10
- package/dist/inbound-AFOHYNUY.js +0 -6
- package/dist/inbound-CGIXRXGC.js +0 -8
- package/dist/inbound-MCOLRH6U.js +0 -10
- package/dist/inbound-SNEMBLGA.js +0 -6
- package/dist/inbound-ZJHAYVMF.js +0 -10
- package/dist/provider-qqJYv9nv.d.ts +0 -75
- package/dist/providers/anthropic/models.d.ts +0 -2
- package/dist/providers/anthropic/models.js +0 -29
- package/dist/providers/anthropic/provider.d.ts +0 -13
- package/dist/providers/anthropic/provider.js +0 -119
- package/dist/providers/anthropic/tool-converter.d.ts +0 -10
- package/dist/providers/anthropic/tool-converter.js +0 -7
- package/dist/providers/ollama/provider.d.ts +0 -17
- package/dist/providers/ollama/provider.js +0 -185
- package/dist/providers/openai/models.d.ts +0 -2
- package/dist/providers/openai/models.js +0 -29
- package/dist/providers/openai/provider.d.ts +0 -13
- package/dist/providers/openai/provider.js +0 -163
- package/dist/providers/openai/tool-converter.d.ts +0 -10
- package/dist/providers/openai/tool-converter.js +0 -10
- package/dist/shared/constants.d.ts +0 -50
- package/dist/shared/constants.js +0 -64
- package/dist/shared/index.d.ts +0 -14
- package/dist/shared/index.js +0 -14
- package/dist/shared/types/agent.d.ts +0 -36
- package/dist/shared/types/agent.js +0 -2
- package/dist/shared/types/channel.d.ts +0 -70
- package/dist/shared/types/channel.js +0 -2
- package/dist/shared/types/config.d.ts +0 -111
- package/dist/shared/types/config.js +0 -2
- package/dist/shared/types/connector.d.ts +0 -77
- package/dist/shared/types/connector.js +0 -2
- package/dist/shared/types/execution.d.ts +0 -29
- package/dist/shared/types/execution.js +0 -2
- package/dist/shared/types/provider.d.ts +0 -73
- package/dist/shared/types/provider.js +0 -2
- package/dist/shared/types/task.d.ts +0 -47
- package/dist/shared/types/task.js +0 -2
- package/dist/shared/types/workflow.d.ts +0 -39
- package/dist/shared/types/workflow.js +0 -2
- package/dist/shared/utils.d.ts +0 -6
- package/dist/shared/utils.js +0 -13
- package/dist/update-check.d.ts +0 -5
- package/dist/update-check.js +0 -56
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TriageRouter — content-based routing with deterministic-first resolution.
|
|
3
|
-
* Story 6.3
|
|
4
|
-
*
|
|
5
|
-
* Replaces the simple channel→agent binding with intelligent routing:
|
|
6
|
-
* 1. Keyword/regex rules evaluated first (deterministic, ~4ms)
|
|
7
|
-
* 2. LLM classification only for ambiguous messages (async, ~2-4s)
|
|
8
|
-
* 3. Ownership chain logged for every routing decision
|
|
9
|
-
*
|
|
10
|
-
* Key constraint: specialists return to triage, never to another specialist.
|
|
11
|
-
*/
|
|
12
|
-
export class TriageRouter {
|
|
13
|
-
db;
|
|
14
|
-
hooks;
|
|
15
|
-
rules;
|
|
16
|
-
fallbackAgent;
|
|
17
|
-
llmFallback;
|
|
18
|
-
persist;
|
|
19
|
-
compiledRules;
|
|
20
|
-
constructor(db, hooks, config) {
|
|
21
|
-
this.db = db;
|
|
22
|
-
this.hooks = hooks;
|
|
23
|
-
this.rules = config.rules;
|
|
24
|
-
this.fallbackAgent = config.fallbackAgent;
|
|
25
|
-
this.llmFallback = config.llmFallback ?? true;
|
|
26
|
-
this.persist = config.persist ?? true;
|
|
27
|
-
// Pre-compile patterns for fast matching
|
|
28
|
-
this.compiledRules = this.rules
|
|
29
|
-
.sort((a, b) => (a.priority ?? 50) - (b.priority ?? 50))
|
|
30
|
-
.map((rule) => ({
|
|
31
|
-
rule,
|
|
32
|
-
regexes: (rule.patterns ?? []).map((p) => new RegExp(p, 'i')),
|
|
33
|
-
keywordSet: new Set((rule.keywords ?? []).map((k) => k.toLowerCase())),
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Route an inbound message to the best agent.
|
|
38
|
-
* Returns the agent slug and the routing decision.
|
|
39
|
-
*/
|
|
40
|
-
async route(msg) {
|
|
41
|
-
const body = msg.body.toLowerCase();
|
|
42
|
-
const words = new Set(body.split(/\s+/));
|
|
43
|
-
// Phase 1: Deterministic — keyword + regex matching
|
|
44
|
-
for (const { rule, regexes, keywordSet } of this.compiledRules) {
|
|
45
|
-
// Keyword match
|
|
46
|
-
for (const keyword of keywordSet) {
|
|
47
|
-
if (words.has(keyword) || body.includes(keyword)) {
|
|
48
|
-
const decision = this.buildDecision(rule.agentSlug, `keyword: '${keyword}'`, 'deterministic', msg);
|
|
49
|
-
await this.logDecision(decision);
|
|
50
|
-
return { agentSlug: rule.agentSlug, decision };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
// Regex match
|
|
54
|
-
for (const regex of regexes) {
|
|
55
|
-
if (regex.test(msg.body)) {
|
|
56
|
-
const decision = this.buildDecision(rule.agentSlug, `pattern: ${regex.source}`, 'deterministic', msg);
|
|
57
|
-
await this.logDecision(decision);
|
|
58
|
-
return { agentSlug: rule.agentSlug, decision };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
// Phase 2: LLM classification (if enabled)
|
|
63
|
-
if (this.llmFallback) {
|
|
64
|
-
const agentSlugs = this.rules.map((r) => r.agentSlug);
|
|
65
|
-
const classified = await this.classifyWithLLM(msg, agentSlugs);
|
|
66
|
-
if (classified) {
|
|
67
|
-
const decision = this.buildDecision(classified.agentSlug, `llm: ${classified.reason}`, 'llm', msg);
|
|
68
|
-
await this.logDecision(decision);
|
|
69
|
-
return { agentSlug: classified.agentSlug, decision };
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Phase 3: Fallback
|
|
73
|
-
const decision = this.buildDecision(this.fallbackAgent, 'fallback: no rule matched', 'deterministic', msg);
|
|
74
|
-
await this.logDecision(decision);
|
|
75
|
-
return { agentSlug: this.fallbackAgent, decision };
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Query the ownership chain for a given message or channel.
|
|
79
|
-
*/
|
|
80
|
-
async getDecisionHistory(filter) {
|
|
81
|
-
const rows = await this.db.query('activity_log', {
|
|
82
|
-
where: { event_type: 'triage_decision' },
|
|
83
|
-
});
|
|
84
|
-
let decisions = rows.map((r) => {
|
|
85
|
-
try {
|
|
86
|
-
return JSON.parse(r['payload']);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
}).filter((d) => d !== null);
|
|
92
|
-
if (filter?.channel) {
|
|
93
|
-
decisions = decisions.filter((d) => d.channel === filter.channel);
|
|
94
|
-
}
|
|
95
|
-
// Sort by timestamp descending
|
|
96
|
-
decisions.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
97
|
-
if (filter?.limit) {
|
|
98
|
-
decisions = decisions.slice(0, filter.limit);
|
|
99
|
-
}
|
|
100
|
-
return decisions;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* LLM classification — emits a hook for external LLM integration.
|
|
104
|
-
* Returns agent slug + reason, or undefined if LLM is unavailable.
|
|
105
|
-
*/
|
|
106
|
-
async classifyWithLLM(msg, agentSlugs) {
|
|
107
|
-
// Emit classification request — listeners provide the result
|
|
108
|
-
const result = {};
|
|
109
|
-
await this.hooks.emit('triage.classify', {
|
|
110
|
-
message: msg,
|
|
111
|
-
candidates: agentSlugs,
|
|
112
|
-
respond: (slug, reason) => {
|
|
113
|
-
result.agentSlug = slug;
|
|
114
|
-
result.reason = reason;
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
if (result.agentSlug && result.reason) {
|
|
118
|
-
return { agentSlug: result.agentSlug, reason: result.reason };
|
|
119
|
-
}
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
buildDecision(target, reason, method, msg) {
|
|
123
|
-
return {
|
|
124
|
-
timestamp: new Date().toISOString(),
|
|
125
|
-
source: 'triage',
|
|
126
|
-
target: target ?? 'none',
|
|
127
|
-
reason,
|
|
128
|
-
method,
|
|
129
|
-
messageId: msg.id,
|
|
130
|
-
channel: msg.channel,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
async logDecision(decision) {
|
|
134
|
-
if (!this.persist)
|
|
135
|
-
return;
|
|
136
|
-
await this.db.insert('activity_log', {
|
|
137
|
-
event_type: 'triage_decision',
|
|
138
|
-
payload: JSON.stringify(decision),
|
|
139
|
-
});
|
|
140
|
-
await this.hooks.emit('triage.routed', { decision });
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat types — re-exports from @botinabox/shared channel types.
|
|
3
|
-
* Story 4.1
|
|
4
|
-
*/
|
|
5
|
-
export type { ChatType, FormattingMode, ChannelCapabilities, ChannelMeta, InboundMessage, Attachment, OutboundPayload, SendResult, HealthStatus, ChannelConfig, ChannelAdapter, } from "../../shared/index.js";
|
package/dist/core/chat/types.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_CONFIG = {
|
|
2
|
-
data: {
|
|
3
|
-
path: "./data/bot.db",
|
|
4
|
-
walMode: true,
|
|
5
|
-
},
|
|
6
|
-
channels: {},
|
|
7
|
-
agents: [],
|
|
8
|
-
providers: {},
|
|
9
|
-
models: {
|
|
10
|
-
aliases: {
|
|
11
|
-
fast: "claude-haiku-4-5",
|
|
12
|
-
smart: "claude-opus-4-6",
|
|
13
|
-
balanced: "claude-sonnet-4-6",
|
|
14
|
-
},
|
|
15
|
-
default: "smart",
|
|
16
|
-
routing: {
|
|
17
|
-
conversation: "fast",
|
|
18
|
-
task_execution: "smart",
|
|
19
|
-
classification: "fast",
|
|
20
|
-
},
|
|
21
|
-
fallbackChain: [],
|
|
22
|
-
},
|
|
23
|
-
entities: {},
|
|
24
|
-
security: {
|
|
25
|
-
fieldLengthLimits: { default: 65535 },
|
|
26
|
-
},
|
|
27
|
-
render: {
|
|
28
|
-
outputDir: "./context",
|
|
29
|
-
watchIntervalMs: 30_000,
|
|
30
|
-
},
|
|
31
|
-
updates: {
|
|
32
|
-
policy: "auto-compatible",
|
|
33
|
-
checkIntervalMs: 86_400_000,
|
|
34
|
-
},
|
|
35
|
-
budget: {
|
|
36
|
-
warnPercent: 80,
|
|
37
|
-
},
|
|
38
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { loadConfig, getConfig, initConfig, _resetConfig } from "./loader.js";
|
|
2
|
-
export type { ConfigLoadError, ConfigLoadResult } from "./loader.js";
|
|
3
|
-
export { interpolateEnv } from "./interpolate.js";
|
|
4
|
-
export { validateConfig } from "./schema.js";
|
|
5
|
-
export type { SchemaError } from "./schema.js";
|
|
6
|
-
export { DEFAULT_CONFIG } from "./defaults.js";
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interpolate ${ENV_VAR} references in YAML string values.
|
|
3
|
-
* Recursively walks objects and arrays.
|
|
4
|
-
*/
|
|
5
|
-
export function interpolateEnv(value, env = process.env) {
|
|
6
|
-
if (typeof value === "string") {
|
|
7
|
-
return value.replace(/\$\{([^}]+)\}/g, (_, name) => {
|
|
8
|
-
const envVal = env[name];
|
|
9
|
-
if (envVal === undefined) {
|
|
10
|
-
// Leave the placeholder if env var is not set (don't silently swallow)
|
|
11
|
-
return `\${${name}}`;
|
|
12
|
-
}
|
|
13
|
-
return envVal;
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
if (Array.isArray(value)) {
|
|
17
|
-
return value.map(item => interpolateEnv(item, env));
|
|
18
|
-
}
|
|
19
|
-
if (value !== null && typeof value === "object") {
|
|
20
|
-
const result = {};
|
|
21
|
-
for (const [k, v] of Object.entries(value)) {
|
|
22
|
-
result[k] = interpolateEnv(v, env);
|
|
23
|
-
}
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { BotConfig } from "../../shared/index.js";
|
|
2
|
-
export interface ConfigLoadError {
|
|
3
|
-
field: string;
|
|
4
|
-
message: string;
|
|
5
|
-
}
|
|
6
|
-
export interface ConfigLoadResult {
|
|
7
|
-
config: BotConfig;
|
|
8
|
-
errors: ConfigLoadError[];
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Load and merge config from file, with env var interpolation and runtime overrides.
|
|
12
|
-
* Merge order: defaults < config file < runtime overrides
|
|
13
|
-
*/
|
|
14
|
-
export declare function loadConfig(opts?: {
|
|
15
|
-
configPath?: string;
|
|
16
|
-
overrides?: Partial<BotConfig>;
|
|
17
|
-
env?: Record<string, string | undefined>;
|
|
18
|
-
}): ConfigLoadResult;
|
|
19
|
-
/** Get the loaded config singleton. Call loadConfig() first. */
|
|
20
|
-
export declare function getConfig(): BotConfig;
|
|
21
|
-
/** Initialize the config singleton. Returns errors if any. */
|
|
22
|
-
export declare function initConfig(opts?: Parameters<typeof loadConfig>[0]): ConfigLoadError[];
|
|
23
|
-
/** Reset the singleton (for testing) */
|
|
24
|
-
export declare function _resetConfig(): void;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
-
import { parse as parseYaml } from "yaml";
|
|
3
|
-
import { DEFAULT_CONFIG } from "./defaults.js";
|
|
4
|
-
import { interpolateEnv } from "./interpolate.js";
|
|
5
|
-
function deepMerge(base, override) {
|
|
6
|
-
if (override === undefined || override === null)
|
|
7
|
-
return base;
|
|
8
|
-
if (base === undefined || base === null)
|
|
9
|
-
return override;
|
|
10
|
-
if (typeof base !== "object" || typeof override !== "object")
|
|
11
|
-
return override;
|
|
12
|
-
if (Array.isArray(override))
|
|
13
|
-
return override;
|
|
14
|
-
const result = { ...base };
|
|
15
|
-
for (const [k, v] of Object.entries(override)) {
|
|
16
|
-
if (v !== undefined) {
|
|
17
|
-
result[k] = deepMerge(result[k], v);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Load and merge config from file, with env var interpolation and runtime overrides.
|
|
24
|
-
* Merge order: defaults < config file < runtime overrides
|
|
25
|
-
*/
|
|
26
|
-
export function loadConfig(opts) {
|
|
27
|
-
const configPath = opts?.configPath ?? "botinabox.config.yml";
|
|
28
|
-
const errors = [];
|
|
29
|
-
let fileConfig = {};
|
|
30
|
-
if (existsSync(configPath)) {
|
|
31
|
-
try {
|
|
32
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
33
|
-
const parsed = parseYaml(raw);
|
|
34
|
-
fileConfig = interpolateEnv(parsed, opts?.env ?? process.env);
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
errors.push({ field: "configPath", message: `Failed to parse ${configPath}: ${String(err)}` });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const merged = deepMerge(deepMerge(DEFAULT_CONFIG, fileConfig), opts?.overrides ?? {});
|
|
41
|
-
return { config: Object.freeze(merged), errors };
|
|
42
|
-
}
|
|
43
|
-
let _config = null;
|
|
44
|
-
/** Get the loaded config singleton. Call loadConfig() first. */
|
|
45
|
-
export function getConfig() {
|
|
46
|
-
if (!_config)
|
|
47
|
-
throw new Error("Config not loaded — call loadConfig() first");
|
|
48
|
-
return _config;
|
|
49
|
-
}
|
|
50
|
-
/** Initialize the config singleton. Returns errors if any. */
|
|
51
|
-
export function initConfig(opts) {
|
|
52
|
-
const { config, errors } = loadConfig(opts);
|
|
53
|
-
_config = config;
|
|
54
|
-
return errors;
|
|
55
|
-
}
|
|
56
|
-
/** Reset the singleton (for testing) */
|
|
57
|
-
export function _resetConfig() {
|
|
58
|
-
_config = null;
|
|
59
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import Ajv from "ajv";
|
|
2
|
-
const ajv = new Ajv({ allErrors: true, coerceTypes: false });
|
|
3
|
-
const BOT_CONFIG_SCHEMA = {
|
|
4
|
-
type: "object",
|
|
5
|
-
additionalProperties: true,
|
|
6
|
-
properties: {
|
|
7
|
-
data: {
|
|
8
|
-
type: "object",
|
|
9
|
-
required: ["path", "walMode"],
|
|
10
|
-
properties: {
|
|
11
|
-
path: { type: "string", minLength: 1 },
|
|
12
|
-
walMode: { type: "boolean" },
|
|
13
|
-
backupDir: { type: "string" },
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
models: {
|
|
17
|
-
type: "object",
|
|
18
|
-
required: ["aliases", "default", "routing", "fallbackChain"],
|
|
19
|
-
properties: {
|
|
20
|
-
aliases: { type: "object", additionalProperties: { type: "string" } },
|
|
21
|
-
default: { type: "string", minLength: 1 },
|
|
22
|
-
routing: { type: "object", additionalProperties: { type: "string" } },
|
|
23
|
-
fallbackChain: { type: "array", items: { type: "string" } },
|
|
24
|
-
costLimit: {
|
|
25
|
-
type: "object",
|
|
26
|
-
properties: {
|
|
27
|
-
perRunCents: { type: "number", minimum: 0 },
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
security: {
|
|
33
|
-
type: "object",
|
|
34
|
-
properties: {
|
|
35
|
-
fieldLengthLimits: { type: "object", additionalProperties: { type: "number" } },
|
|
36
|
-
allowedFilePrefixes: { type: "array", items: { type: "string" } },
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
render: {
|
|
40
|
-
type: "object",
|
|
41
|
-
required: ["outputDir", "watchIntervalMs"],
|
|
42
|
-
properties: {
|
|
43
|
-
outputDir: { type: "string", minLength: 1 },
|
|
44
|
-
watchIntervalMs: { type: "number", minimum: 1000 },
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
updates: {
|
|
48
|
-
type: "object",
|
|
49
|
-
required: ["policy", "checkIntervalMs"],
|
|
50
|
-
properties: {
|
|
51
|
-
policy: { type: "string", enum: ["auto-all", "auto-compatible", "auto-patch", "notify", "manual"] },
|
|
52
|
-
checkIntervalMs: { type: "number", minimum: 60_000 },
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
budget: {
|
|
56
|
-
type: "object",
|
|
57
|
-
required: ["warnPercent"],
|
|
58
|
-
properties: {
|
|
59
|
-
warnPercent: { type: "number", minimum: 1, maximum: 100 },
|
|
60
|
-
globalMonthlyCents: { type: "number", minimum: 0 },
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
agents: {
|
|
64
|
-
type: "array",
|
|
65
|
-
items: {
|
|
66
|
-
type: "object",
|
|
67
|
-
required: ["slug", "name", "adapter"],
|
|
68
|
-
properties: {
|
|
69
|
-
slug: { type: "string", minLength: 1, pattern: "^[a-z0-9-]+$" },
|
|
70
|
-
name: { type: "string", minLength: 1 },
|
|
71
|
-
adapter: { type: "string", minLength: 1 },
|
|
72
|
-
model: { type: "string" },
|
|
73
|
-
workdir: { type: "string" },
|
|
74
|
-
maxConcurrentRuns: { type: "number", minimum: 1 },
|
|
75
|
-
budgetMonthlyCents: { type: "number", minimum: 0 },
|
|
76
|
-
canCreateAgents: { type: "boolean" },
|
|
77
|
-
skipPermissions: { type: "boolean" },
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
channels: {
|
|
82
|
-
type: "object",
|
|
83
|
-
additionalProperties: {
|
|
84
|
-
type: "object",
|
|
85
|
-
required: ["enabled"],
|
|
86
|
-
properties: {
|
|
87
|
-
enabled: { type: "boolean" },
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
providers: {
|
|
92
|
-
type: "object",
|
|
93
|
-
additionalProperties: {
|
|
94
|
-
type: "object",
|
|
95
|
-
required: ["enabled"],
|
|
96
|
-
properties: {
|
|
97
|
-
enabled: { type: "boolean" },
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
let _validate = null;
|
|
104
|
-
function getValidator() {
|
|
105
|
-
if (!_validate) {
|
|
106
|
-
_validate = ajv.compile(BOT_CONFIG_SCHEMA);
|
|
107
|
-
}
|
|
108
|
-
return _validate;
|
|
109
|
-
}
|
|
110
|
-
export function validateConfig(config) {
|
|
111
|
-
const validate = getValidator();
|
|
112
|
-
const valid = validate(config);
|
|
113
|
-
if (valid)
|
|
114
|
-
return [];
|
|
115
|
-
return (validate.errors ?? []).map(err => ({
|
|
116
|
-
path: err.instancePath || "/",
|
|
117
|
-
message: err.message ?? "invalid",
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { DataStore } from "./data-store.js";
|
|
2
|
-
/**
|
|
3
|
-
* Define default entity context rendering for botinabox core tables.
|
|
4
|
-
* Call after defineCoreTables() and before or after init().
|
|
5
|
-
*
|
|
6
|
-
* Renders:
|
|
7
|
-
* - agents/ — per-agent context (AGENT.md, PROJECTS.md if agent_project exists)
|
|
8
|
-
* - users/ — per-user context (USER.md) — protected
|
|
9
|
-
* - skills/ — per-skill context (SKILL.md)
|
|
10
|
-
*
|
|
11
|
-
* Apps can override by calling db.defineEntityContext() with the same table name
|
|
12
|
-
* BEFORE calling defineCoreEntityContexts().
|
|
13
|
-
*/
|
|
14
|
-
export declare function defineCoreEntityContexts(db: DataStore): void;
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { truncateAtWord } from "../../shared/utils.js";
|
|
2
|
-
/**
|
|
3
|
-
* Define default entity context rendering for botinabox core tables.
|
|
4
|
-
* Call after defineCoreTables() and before or after init().
|
|
5
|
-
*
|
|
6
|
-
* Renders:
|
|
7
|
-
* - agents/ — per-agent context (AGENT.md, PROJECTS.md if agent_project exists)
|
|
8
|
-
* - users/ — per-user context (USER.md) — protected
|
|
9
|
-
* - skills/ — per-skill context (SKILL.md)
|
|
10
|
-
*
|
|
11
|
-
* Apps can override by calling db.defineEntityContext() with the same table name
|
|
12
|
-
* BEFORE calling defineCoreEntityContexts().
|
|
13
|
-
*/
|
|
14
|
-
export function defineCoreEntityContexts(db) {
|
|
15
|
-
// --- Agents ---
|
|
16
|
-
db.defineEntityContext("agents", {
|
|
17
|
-
table: "agents",
|
|
18
|
-
directory: "agents",
|
|
19
|
-
slugColumn: "slug",
|
|
20
|
-
indexFile: "agents/AGENTS.md",
|
|
21
|
-
files: {
|
|
22
|
-
"AGENT.md": {
|
|
23
|
-
source: { type: "self" },
|
|
24
|
-
render: (rows) => {
|
|
25
|
-
const a = rows[0];
|
|
26
|
-
if (!a)
|
|
27
|
-
return "";
|
|
28
|
-
return [
|
|
29
|
-
`# ${a.name}`,
|
|
30
|
-
"",
|
|
31
|
-
a.role ? `**Role:** ${a.role}` : null,
|
|
32
|
-
a.adapter ? `**Adapter:** ${a.adapter}` : null,
|
|
33
|
-
a.status ? `**Status:** ${a.status}` : null,
|
|
34
|
-
a.cwd ? `**Working Directory:** ${a.cwd}` : null,
|
|
35
|
-
a.reports_to ? `**Reports To:** ${a.reports_to}` : null,
|
|
36
|
-
"",
|
|
37
|
-
]
|
|
38
|
-
.filter(Boolean)
|
|
39
|
-
.join("\n");
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
"SKILLS.md": {
|
|
43
|
-
source: {
|
|
44
|
-
type: "manyToMany",
|
|
45
|
-
junctionTable: "agent_skills",
|
|
46
|
-
localKey: "agent_id",
|
|
47
|
-
remoteKey: "skill_id",
|
|
48
|
-
remoteTable: "skills",
|
|
49
|
-
},
|
|
50
|
-
omitIfEmpty: true,
|
|
51
|
-
render: (rows) => {
|
|
52
|
-
if (!rows.length)
|
|
53
|
-
return "";
|
|
54
|
-
const lines = [`# Skills (${rows.length})`, ""];
|
|
55
|
-
for (const s of rows) {
|
|
56
|
-
lines.push(`## ${s.name}`);
|
|
57
|
-
if (s.category)
|
|
58
|
-
lines.push(`**Category:** ${s.category}`);
|
|
59
|
-
if (s.description)
|
|
60
|
-
lines.push("", s.description);
|
|
61
|
-
if (s.definition)
|
|
62
|
-
lines.push("", "```", s.definition, "```");
|
|
63
|
-
lines.push("");
|
|
64
|
-
}
|
|
65
|
-
return lines.join("\n");
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
"PLAYBOOKS.md": {
|
|
69
|
-
source: {
|
|
70
|
-
type: "manyToMany",
|
|
71
|
-
junctionTable: "agent_playbooks",
|
|
72
|
-
localKey: "agent_id",
|
|
73
|
-
remoteKey: "playbook_id",
|
|
74
|
-
remoteTable: "playbooks",
|
|
75
|
-
},
|
|
76
|
-
omitIfEmpty: true,
|
|
77
|
-
render: (rows) => {
|
|
78
|
-
if (!rows.length)
|
|
79
|
-
return "";
|
|
80
|
-
const lines = [`# Playbooks (${rows.length})`, ""];
|
|
81
|
-
for (const pb of rows) {
|
|
82
|
-
lines.push(`## ${pb.pattern ?? pb.name ?? "Unnamed"}`);
|
|
83
|
-
if (pb.rule)
|
|
84
|
-
lines.push("", pb.rule);
|
|
85
|
-
lines.push("");
|
|
86
|
-
}
|
|
87
|
-
return lines.join("\n");
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
// --- Users (protected) ---
|
|
93
|
-
db.defineEntityContext("users", {
|
|
94
|
-
table: "users",
|
|
95
|
-
directory: "users",
|
|
96
|
-
slugColumn: "id",
|
|
97
|
-
protected: true,
|
|
98
|
-
indexFile: "users/USERS.md",
|
|
99
|
-
files: {
|
|
100
|
-
"USER.md": {
|
|
101
|
-
source: { type: "self" },
|
|
102
|
-
render: (rows) => {
|
|
103
|
-
const u = rows[0];
|
|
104
|
-
if (!u)
|
|
105
|
-
return "";
|
|
106
|
-
return [
|
|
107
|
-
`# ${u.name}`,
|
|
108
|
-
"",
|
|
109
|
-
u.role ? `**Role:** ${u.role}` : null,
|
|
110
|
-
u.title ? `**Title:** ${u.title}` : null,
|
|
111
|
-
u.email ? `**Email:** ${u.email}` : null,
|
|
112
|
-
u.timezone ? `**Timezone:** ${u.timezone}` : null,
|
|
113
|
-
"",
|
|
114
|
-
]
|
|
115
|
-
.filter(Boolean)
|
|
116
|
-
.join("\n");
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
// --- Skills ---
|
|
122
|
-
db.defineEntityContext("skills", {
|
|
123
|
-
table: "skills",
|
|
124
|
-
directory: "skills",
|
|
125
|
-
slugColumn: "slug",
|
|
126
|
-
indexFile: "skills/SKILLS.md",
|
|
127
|
-
files: {
|
|
128
|
-
"SKILL.md": {
|
|
129
|
-
source: { type: "self" },
|
|
130
|
-
render: (rows) => {
|
|
131
|
-
const s = rows[0];
|
|
132
|
-
if (!s)
|
|
133
|
-
return "";
|
|
134
|
-
return [
|
|
135
|
-
`# ${s.name}`,
|
|
136
|
-
"",
|
|
137
|
-
s.category ? `**Category:** ${s.category}` : null,
|
|
138
|
-
s.description ? `\n${s.description}` : null,
|
|
139
|
-
s.definition ? `\n## Definition\n\n${s.definition}` : null,
|
|
140
|
-
"",
|
|
141
|
-
]
|
|
142
|
-
.filter(Boolean)
|
|
143
|
-
.join("\n");
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
// --- Messages ---
|
|
149
|
-
db.defineEntityContext("messages", {
|
|
150
|
-
table: "messages",
|
|
151
|
-
directory: "messages",
|
|
152
|
-
slugColumn: "id",
|
|
153
|
-
indexFile: "messages/MESSAGES.md",
|
|
154
|
-
indexRender: (rows) => {
|
|
155
|
-
const active = rows.filter((r) => r.deleted_at == null);
|
|
156
|
-
if (!active.length)
|
|
157
|
-
return "# Messages\n\nNo messages.\n";
|
|
158
|
-
const recent = active.slice(-100);
|
|
159
|
-
const lines = recent.map((r) => {
|
|
160
|
-
const dir = r.direction === "outbound" ? "→" : "←";
|
|
161
|
-
const who = r.from_agent ?? r.from_user ?? "unknown";
|
|
162
|
-
const time = (r.created_at ?? "").slice(0, 16);
|
|
163
|
-
const preview = truncateAtWord(r.body ?? "", 80);
|
|
164
|
-
return `- ${dir} **${who}** (${time}): ${preview}`;
|
|
165
|
-
});
|
|
166
|
-
return `# Messages\n\nLast ${lines.length} messages:\n\n${lines.join("\n")}\n`;
|
|
167
|
-
},
|
|
168
|
-
files: {
|
|
169
|
-
"MESSAGE.md": {
|
|
170
|
-
source: { type: "self" },
|
|
171
|
-
render: (rows) => {
|
|
172
|
-
const m = rows[0];
|
|
173
|
-
if (!m)
|
|
174
|
-
return "";
|
|
175
|
-
return [
|
|
176
|
-
"# Message",
|
|
177
|
-
"",
|
|
178
|
-
`**Direction:** ${m.direction}`,
|
|
179
|
-
m.from_user ? `**From User:** ${m.from_user}` : null,
|
|
180
|
-
m.from_agent ? `**From Agent:** ${m.from_agent}` : null,
|
|
181
|
-
`**Channel:** ${m.channel}`,
|
|
182
|
-
m.thread_id ? `**Thread:** ${m.thread_id}` : null,
|
|
183
|
-
m.task_id ? `**Task:** ${m.task_id}` : null,
|
|
184
|
-
`**Time:** ${m.created_at}`,
|
|
185
|
-
"",
|
|
186
|
-
"---",
|
|
187
|
-
"",
|
|
188
|
-
m.body,
|
|
189
|
-
"",
|
|
190
|
-
]
|
|
191
|
-
.filter(Boolean)
|
|
192
|
-
.join("\n");
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
}
|