@chozzz/vargos 2.0.14 → 2.2.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/README.md +1 -1
- package/dist/.templates/agents/subagent.md +36 -0
- package/dist/.templates/{vargos/workspace → workspace}/AGENTS.md +2 -18
- package/dist/boot.d.ts +2 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +111 -0
- package/dist/boot.js.map +1 -0
- package/dist/cli/channels.d.ts +27 -0
- package/dist/cli/channels.d.ts.map +1 -0
- package/dist/cli/channels.js +116 -0
- package/dist/cli/channels.js.map +1 -0
- package/dist/cli/onboard.d.ts.map +1 -1
- package/dist/cli/onboard.js +181 -109
- package/dist/cli/onboard.js.map +1 -1
- package/dist/cli.js +92 -3
- package/dist/cli.js.map +1 -1
- package/dist/edge/webhooks/index.js +1 -1
- package/dist/edge/webhooks/index.js.map +1 -1
- package/dist/gateway/bus.d.ts +2 -0
- package/dist/gateway/bus.d.ts.map +1 -1
- package/dist/gateway/emitter.d.ts +10 -0
- package/dist/gateway/emitter.d.ts.map +1 -1
- package/dist/gateway/emitter.js +48 -3
- package/dist/gateway/emitter.js.map +1 -1
- package/dist/gateway/events.d.ts +26 -55
- package/dist/gateway/events.d.ts.map +1 -1
- package/dist/gateway/tcp-server.js +3 -0
- package/dist/gateway/tcp-server.js.map +1 -1
- package/dist/index.js +44 -69
- package/dist/index.js.map +1 -1
- package/dist/lib/{glob.d.ts → glob-match.d.ts} +1 -1
- package/dist/lib/glob-match.d.ts.map +1 -0
- package/dist/lib/{glob.js → glob-match.js} +1 -1
- package/dist/lib/glob-match.js.map +1 -0
- package/dist/lib/media.js +1 -1
- package/dist/lib/media.js.map +1 -1
- package/dist/lib/mime.d.ts +10 -3
- package/dist/lib/mime.d.ts.map +1 -1
- package/dist/lib/mime.js +48 -67
- package/dist/lib/mime.js.map +1 -1
- package/dist/lib/session-key.d.ts +21 -0
- package/dist/lib/session-key.d.ts.map +1 -0
- package/dist/lib/session-key.js +44 -0
- package/dist/lib/session-key.js.map +1 -0
- package/dist/lib/templates.d.ts +2 -2
- package/dist/lib/templates.d.ts.map +1 -1
- package/dist/lib/templates.js +7 -14
- package/dist/lib/templates.js.map +1 -1
- package/dist/scripts/migrate-templates.d.ts +14 -0
- package/dist/scripts/migrate-templates.d.ts.map +1 -0
- package/dist/scripts/migrate-templates.js +98 -0
- package/dist/scripts/migrate-templates.js.map +1 -0
- package/dist/{lib → services/agent}/error-store.d.ts +1 -1
- package/dist/services/agent/error-store.d.ts.map +1 -0
- package/dist/{lib → services/agent}/error-store.js +2 -2
- package/dist/services/agent/error-store.js.map +1 -0
- package/dist/services/agent/index.d.ts +19 -20
- package/dist/services/agent/index.d.ts.map +1 -1
- package/dist/services/agent/index.js +70 -93
- package/dist/services/agent/index.js.map +1 -1
- package/dist/services/agent/persona.d.ts +6 -0
- package/dist/services/agent/persona.d.ts.map +1 -1
- package/dist/services/agent/persona.js +19 -0
- package/dist/services/agent/persona.js.map +1 -1
- package/dist/services/agent/prompt-interpolate.d.ts +3 -3
- package/dist/services/agent/prompt-interpolate.js +10 -15
- package/dist/services/agent/prompt-interpolate.js.map +1 -1
- package/dist/services/agent/skills.d.ts.map +1 -0
- package/dist/services/agent/skills.js.map +1 -0
- package/dist/services/agent/tools.d.ts +11 -4
- package/dist/services/agent/tools.d.ts.map +1 -1
- package/dist/services/agent/tools.js +30 -8
- package/dist/services/agent/tools.js.map +1 -1
- package/dist/services/agent/{schema.d.ts → types.d.ts} +1 -1
- package/dist/services/agent/types.d.ts.map +1 -0
- package/dist/services/agent/{schema.js → types.js} +1 -1
- package/dist/services/agent/types.js.map +1 -0
- package/dist/services/channels/base-adapter.d.ts +22 -7
- package/dist/services/channels/base-adapter.d.ts.map +1 -1
- package/dist/services/channels/base-adapter.js +56 -73
- package/dist/services/channels/base-adapter.js.map +1 -1
- package/dist/services/channels/debounce.d.ts +1 -1
- package/dist/services/channels/debounce.d.ts.map +1 -1
- package/dist/services/channels/index.d.ts +1 -1
- package/dist/services/channels/index.d.ts.map +1 -1
- package/dist/services/channels/index.js +64 -25
- package/dist/services/channels/index.js.map +1 -1
- package/dist/services/channels/{media-extract.d.ts → media-paths.d.ts} +1 -1
- package/dist/services/channels/media-paths.d.ts.map +1 -0
- package/dist/services/channels/{media-extract.js → media-paths.js} +2 -2
- package/dist/services/channels/media-paths.js.map +1 -0
- package/dist/services/channels/pipeline.d.ts +2 -7
- package/dist/services/channels/pipeline.d.ts.map +1 -1
- package/dist/services/channels/pipeline.js +29 -48
- package/dist/services/channels/pipeline.js.map +1 -1
- package/dist/services/channels/provider-loader.d.ts +1 -1
- package/dist/services/channels/provider-loader.d.ts.map +1 -1
- package/dist/services/channels/providers/telegram/adapter.d.ts +5 -5
- package/dist/services/channels/providers/telegram/adapter.d.ts.map +1 -1
- package/dist/services/channels/providers/telegram/adapter.js +4 -6
- package/dist/services/channels/providers/telegram/adapter.js.map +1 -1
- package/dist/services/channels/providers/telegram/index.d.ts +1 -1
- package/dist/services/channels/providers/telegram/index.d.ts.map +1 -1
- package/dist/services/channels/providers/telegram/index.js +1 -1
- package/dist/services/channels/providers/telegram/index.js.map +1 -1
- package/dist/services/channels/providers/telegram/normalizer.d.ts +1 -1
- package/dist/services/channels/providers/telegram/normalizer.d.ts.map +1 -1
- package/dist/services/channels/providers/telegram/normalizer.js +9 -5
- package/dist/services/channels/providers/telegram/normalizer.js.map +1 -1
- package/dist/services/channels/providers/whatsapp/adapter.d.ts +6 -9
- package/dist/services/channels/providers/whatsapp/adapter.d.ts.map +1 -1
- package/dist/services/channels/providers/whatsapp/adapter.js +43 -59
- package/dist/services/channels/providers/whatsapp/adapter.js.map +1 -1
- package/dist/services/channels/providers/whatsapp/index.d.ts +1 -1
- package/dist/services/channels/providers/whatsapp/index.d.ts.map +1 -1
- package/dist/services/channels/providers/whatsapp/index.js +1 -1
- package/dist/services/channels/providers/whatsapp/index.js.map +1 -1
- package/dist/services/channels/providers/whatsapp/normalizer.d.ts +2 -1
- package/dist/services/channels/providers/whatsapp/normalizer.d.ts.map +1 -1
- package/dist/services/channels/providers/whatsapp/normalizer.js +17 -12
- package/dist/services/channels/providers/whatsapp/normalizer.js.map +1 -1
- package/dist/services/channels/providers/whatsapp/session.d.ts.map +1 -1
- package/dist/services/channels/providers/whatsapp/session.js +15 -7
- package/dist/services/channels/providers/whatsapp/session.js.map +1 -1
- package/dist/services/channels/providers/whatsapp/types.d.ts +1 -0
- package/dist/services/channels/providers/whatsapp/types.d.ts.map +1 -1
- package/dist/services/channels/types.d.ts +68 -3
- package/dist/services/channels/types.d.ts.map +1 -1
- package/dist/services/channels/types.js +4 -0
- package/dist/services/channels/types.js.map +1 -1
- package/dist/services/config/index.d.ts +3 -3
- package/dist/services/config/schemas/auth.d.ts +2 -2
- package/dist/services/config/schemas/channels.d.ts +2 -0
- package/dist/services/config/schemas/channels.d.ts.map +1 -1
- package/dist/services/config/schemas/channels.js +2 -0
- package/dist/services/config/schemas/channels.js.map +1 -1
- package/dist/services/config/schemas/index.d.ts +3 -3
- package/dist/services/config/schemas/index.d.ts.map +1 -1
- package/dist/services/config/schemas/index.js +2 -2
- package/dist/services/config/schemas/index.js.map +1 -1
- package/dist/services/config/schemas/primitives.d.ts +0 -2
- package/dist/services/config/schemas/primitives.d.ts.map +1 -1
- package/dist/services/config/schemas/primitives.js +0 -1
- package/dist/services/config/schemas/primitives.js.map +1 -1
- package/dist/services/cron/heartbeat.d.ts.map +1 -0
- package/dist/services/cron/heartbeat.js.map +1 -0
- package/dist/services/cron/index.d.ts.map +1 -1
- package/dist/services/cron/index.js +10 -5
- package/dist/services/cron/index.js.map +1 -1
- package/dist/services/media/index.d.ts +1 -0
- package/dist/services/media/index.d.ts.map +1 -1
- package/dist/services/media/index.js +61 -5
- package/dist/services/media/index.js.map +1 -1
- package/dist/services/media/providers/anthropic.js +1 -1
- package/dist/services/media/providers/anthropic.js.map +1 -1
- package/dist/services/media/{extract-document.d.ts → providers/document.d.ts} +1 -1
- package/dist/services/media/providers/document.d.ts.map +1 -0
- package/dist/services/media/{extract-document.js → providers/document.js} +4 -4
- package/dist/services/media/providers/document.js.map +1 -0
- package/dist/services/media/providers/openai.d.ts.map +1 -1
- package/dist/services/media/providers/openai.js +5 -1
- package/dist/services/media/providers/openai.js.map +1 -1
- package/package.json +16 -16
- package/dist/lib/async-handlers.d.ts +0 -13
- package/dist/lib/async-handlers.d.ts.map +0 -1
- package/dist/lib/async-handlers.js +0 -6
- package/dist/lib/async-handlers.js.map +0 -1
- package/dist/lib/error-store.d.ts.map +0 -1
- package/dist/lib/error-store.js.map +0 -1
- package/dist/lib/glob.d.ts.map +0 -1
- package/dist/lib/glob.js.map +0 -1
- package/dist/lib/heartbeat.d.ts.map +0 -1
- package/dist/lib/heartbeat.js.map +0 -1
- package/dist/lib/media-transcribe.d.ts +0 -57
- package/dist/lib/media-transcribe.d.ts.map +0 -1
- package/dist/lib/media-transcribe.js +0 -98
- package/dist/lib/media-transcribe.js.map +0 -1
- package/dist/lib/safe-async.d.ts +0 -27
- package/dist/lib/safe-async.d.ts.map +0 -1
- package/dist/lib/safe-async.js +0 -38
- package/dist/lib/safe-async.js.map +0 -1
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/subagent.d.ts +0 -14
- package/dist/lib/subagent.d.ts.map +0 -1
- package/dist/lib/subagent.js +0 -25
- package/dist/lib/subagent.js.map +0 -1
- package/dist/services/agent/schema.d.ts.map +0 -1
- package/dist/services/agent/schema.js.map +0 -1
- package/dist/services/channels/contracts.d.ts +0 -75
- package/dist/services/channels/contracts.d.ts.map +0 -1
- package/dist/services/channels/contracts.js +0 -6
- package/dist/services/channels/contracts.js.map +0 -1
- package/dist/services/channels/media-extract.d.ts.map +0 -1
- package/dist/services/channels/media-extract.js.map +0 -1
- package/dist/services/media/extract-document.d.ts.map +0 -1
- package/dist/services/media/extract-document.js.map +0 -1
- /package/dist/.templates/{vargos/agent → agent}/extensions/.gitkeep +0 -0
- /package/dist/.templates/{vargos/agent → agent}/mcp.json +0 -0
- /package/dist/.templates/{vargos/agent → agent}/skills/skill-creator/SKILL.md +0 -0
- /package/dist/.templates/{vargos/agent → agent}/skills/token-capture/SKILL.md +0 -0
- /package/dist/.templates/{vargos/agent → agent}/skills/token-capture/scripts/capture-bearer-token.sh +0 -0
- /package/dist/.templates/{vargos/agents → agents}/README +0 -0
- /package/dist/.templates/{vargos/agents → agents}/default.md +0 -0
- /package/dist/.templates/{vargos/config.json → config.json} +0 -0
- /package/dist/.templates/{vargos/cron → cron}/heartbeat.md +0 -0
- /package/dist/.templates/{vargos/workspace → workspace}/HEARTBEAT.md +0 -0
- /package/dist/.templates/{vargos/workspace → workspace}/MEMORY.md +0 -0
- /package/dist/.templates/{vargos/workspace → workspace}/SOUL.md +0 -0
- /package/dist/.templates/{vargos/workspace → workspace}/TOOLS.md +0 -0
- /package/dist/{lib → services/agent}/skills.d.ts +0 -0
- /package/dist/{lib → services/agent}/skills.js +0 -0
- /package/dist/{lib → services/cron}/heartbeat.d.ts +0 -0
- /package/dist/{lib → services/cron}/heartbeat.js +0 -0
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Session key injection:
|
|
7
7
|
* - Every tool closes over the parent sessionKey from getCustomTools().
|
|
8
|
-
* - For agent.execute specifically,
|
|
9
|
-
* so
|
|
10
|
-
* - Other tools inherit the parent sessionKey for context-aware operations
|
|
11
|
-
*
|
|
8
|
+
* - For agent.execute specifically, a unique `:subagent:<id>` suffix is generated
|
|
9
|
+
* so each delegation gets its own isolated session (supports parallel subagents).
|
|
10
|
+
* - Other tools inherit the parent sessionKey for context-aware operations.
|
|
11
|
+
*
|
|
12
|
+
* Subagent tool filtering:
|
|
13
|
+
* - Controlled by the `allowedTools` glob whitelist in `agents/subagent.md` frontmatter.
|
|
14
|
+
* - Applied by `AgentService.getCustomTools()` via `matchesGlob` — not enforced here.
|
|
12
15
|
*
|
|
13
16
|
* Schema vs EventMap gap:
|
|
14
17
|
* - The agent.execute schema omits sessionKey (it's injected here before bus.call).
|
|
@@ -20,7 +23,8 @@
|
|
|
20
23
|
import { createLogger } from '../../lib/logger.js';
|
|
21
24
|
import { isToolEvent } from '../../gateway/emitter.js';
|
|
22
25
|
import { toMessage } from '../../lib/error.js';
|
|
23
|
-
import { appendError } from '
|
|
26
|
+
import { appendError } from './error-store.js';
|
|
27
|
+
import { subagentSessionKey } from '../../lib/session-key.js';
|
|
24
28
|
const log = createLogger('agent-tools');
|
|
25
29
|
const LARGE_RESULT_TOKEN_THRESHOLD = 5_000;
|
|
26
30
|
/**
|
|
@@ -41,9 +45,14 @@ function wrapEventAsToolDefinition(eventName, description, parameters, sessionKe
|
|
|
41
45
|
log.debug(`${eventName}: ${Object.entries(paramsObj).map(([k, v]) => `${k}=${JSON.stringify(v).slice(0, 100)}`).join(', ')}`);
|
|
42
46
|
try {
|
|
43
47
|
// Auto-inject sessionKey for agent.execute subagent calls.
|
|
44
|
-
//
|
|
48
|
+
// Each delegation gets a unique session key to support parallel subagents.
|
|
45
49
|
if (eventName === 'agent.execute') {
|
|
46
|
-
paramsObj.sessionKey =
|
|
50
|
+
paramsObj.sessionKey = subagentSessionKey(sessionKey);
|
|
51
|
+
}
|
|
52
|
+
// Auto-inject sessionKey for channel.send if not provided.
|
|
53
|
+
// Allows the agent to call channel-send without knowing its own sessionKey.
|
|
54
|
+
if (eventName === 'channel.send' && !paramsObj.sessionKey) {
|
|
55
|
+
paramsObj.sessionKey = sessionKey;
|
|
47
56
|
}
|
|
48
57
|
const result = await bus.call(eventName, paramsObj);
|
|
49
58
|
let resultText = '';
|
|
@@ -53,6 +62,13 @@ function wrapEventAsToolDefinition(eventName, description, parameters, sessionKe
|
|
|
53
62
|
else if (result !== undefined && result !== null) {
|
|
54
63
|
resultText = String(result).slice(0, 10_000);
|
|
55
64
|
}
|
|
65
|
+
// Head+tail truncation for large results (preserves start and end, drops middle).
|
|
66
|
+
const MAX_RESULT_CHARS = 20_000;
|
|
67
|
+
if (resultText.length > MAX_RESULT_CHARS) {
|
|
68
|
+
const head = Math.floor(MAX_RESULT_CHARS * 0.7);
|
|
69
|
+
const tail = Math.floor(MAX_RESULT_CHARS * 0.2);
|
|
70
|
+
resultText = `${resultText.slice(0, head)}\n\n[…truncated ${resultText.length - head - tail} chars…]\n\n${resultText.slice(-tail)}`;
|
|
71
|
+
}
|
|
56
72
|
const resultTokens = Math.ceil(resultText.length / 4);
|
|
57
73
|
log.debug(`${eventName} ok (${resultTokens} tokens): ${resultText.slice(0, 200).replace(/\n/g, ' ')}${resultText.length > 200 ? '...' : ''}`);
|
|
58
74
|
const content = [{ type: 'text', text: resultText }];
|
|
@@ -77,9 +93,15 @@ function wrapEventAsToolDefinition(eventName, description, parameters, sessionKe
|
|
|
77
93
|
}
|
|
78
94
|
/**
|
|
79
95
|
* Create PiAgent custom tools from bus callable events.
|
|
96
|
+
*
|
|
97
|
+
* Subagent tool filtering (agent.execute, channel.send, etc.) is handled by the
|
|
98
|
+
* `allowedTools` glob whitelist in `agents/subagent.md` frontmatter, applied
|
|
99
|
+
* by `AgentService.getCustomTools()` via `matchesGlob`.
|
|
80
100
|
*/
|
|
81
101
|
export async function createCustomTools(sessionKey, bus) {
|
|
82
102
|
const metadata = await bus.call('bus.search', {});
|
|
83
|
-
return metadata
|
|
103
|
+
return metadata
|
|
104
|
+
.filter(isToolEvent)
|
|
105
|
+
.map(m => wrapEventAsToolDefinition(m.event, m.description, m.schema?.params || {}, sessionKey, bus));
|
|
84
106
|
}
|
|
85
107
|
//# sourceMappingURL=tools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../services/agent/tools.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../services/agent/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../services/agent/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,SAAS,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../services/agent/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Base channel adapter — shared logic for typing indicators, debounce, dedupe, and media handling.
|
|
3
3
|
*/
|
|
4
|
-
import type { ChannelType, OnInboundMessageFn, InboundMediaSource } from './types.js';
|
|
5
|
-
import type { ChannelAdapter, NormalizedInboundMessage, AdapterDeps } from './contracts.js';
|
|
4
|
+
import type { ChannelType, OnInboundMessageFn, InboundMediaSource, ChannelAdapter, NormalizedInboundMessage, AdapterDeps } from './types.js';
|
|
6
5
|
import type { ChannelStatus } from '../../gateway/events.js';
|
|
7
6
|
import { createMessageDebouncer } from './debounce.js';
|
|
8
7
|
import { TypingStateManager } from './typing-state.js';
|
|
9
|
-
export declare
|
|
8
|
+
export declare const MEDIA_TYPE_LABELS: Record<string, string>;
|
|
9
|
+
export declare abstract class BaseChannelAdapter<TRaw = never> implements ChannelAdapter {
|
|
10
10
|
abstract readonly type: ChannelType;
|
|
11
11
|
readonly instanceId: string;
|
|
12
12
|
status: ChannelStatus;
|
|
@@ -27,7 +27,8 @@ export declare abstract class BaseChannelAdapter implements ChannelAdapter {
|
|
|
27
27
|
protected extractFn?: (filePath: string, mimeType: string) => Promise<{
|
|
28
28
|
text: string;
|
|
29
29
|
}>;
|
|
30
|
-
|
|
30
|
+
protected allowFrom?: string[];
|
|
31
|
+
constructor(instanceId: string, _channelType: ChannelType, deps: AdapterDeps, allowFrom?: string[], debounceMs?: number);
|
|
31
32
|
protected createDebouncer(): ReturnType<typeof createMessageDebouncer>;
|
|
32
33
|
abstract start(): Promise<void>;
|
|
33
34
|
abstract stop(): Promise<void>;
|
|
@@ -43,8 +44,8 @@ export declare abstract class BaseChannelAdapter implements ChannelAdapter {
|
|
|
43
44
|
protected handleBatch(id: string, messages: string[], normalizedMsg?: NormalizedInboundMessage): Promise<void>;
|
|
44
45
|
protected buildSessionKey(id: string): string;
|
|
45
46
|
protected cleanupTimers(): void;
|
|
46
|
-
/** Override to handle media resolution for your channel. */
|
|
47
|
-
protected resolveMedia(_msg:
|
|
47
|
+
/** Override to handle media resolution for your channel. Typed via the adapter's TRaw param. */
|
|
48
|
+
protected resolveMedia(_msg: TRaw): Promise<InboundMediaSource | null>;
|
|
48
49
|
/**
|
|
49
50
|
* Process inbound media message.
|
|
50
51
|
* @param msg - Raw message from channel
|
|
@@ -52,7 +53,21 @@ export declare abstract class BaseChannelAdapter implements ChannelAdapter {
|
|
|
52
53
|
* @param normalizedMsg - Normalized message with flags (skipAgent, etc)
|
|
53
54
|
* @param route - Function to route processed text to onInboundMessage
|
|
54
55
|
*/
|
|
55
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Check if the agent should execute for this message.
|
|
58
|
+
* Used by both media processing and agent execution decisions.
|
|
59
|
+
*
|
|
60
|
+
* Rules:
|
|
61
|
+
* - Private chat: whitelisted user → execute
|
|
62
|
+
* - Group chat: mentioned + whitelisted → execute
|
|
63
|
+
* - No allowFrom configured: always execute (permissive)
|
|
64
|
+
*/
|
|
65
|
+
shouldExecute(userId: string, chatType: string, isMentioned: boolean): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Process inbound media: save file, optionally transcribe/describe.
|
|
68
|
+
* Returns caption text + saved path for routing to onInboundMessage.
|
|
69
|
+
*/
|
|
70
|
+
protected processInboundMedia(msg: TRaw, route: (text: string) => Promise<void>, sessionKey: string, shouldProcessMedia?: boolean): Promise<{
|
|
56
71
|
caption: string;
|
|
57
72
|
savedPath: string;
|
|
58
73
|
mimeType: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../services/channels/base-adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../services/channels/base-adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC7I,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAIvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAIvD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKpD,CAAC;AAEF,8BAAsB,kBAAkB,CAAC,IAAI,GAAG,KAAK,CAAE,YAAW,cAAc;IAC9E,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,aAAa,CAAkB;IAEvC,SAAS,CAAC,MAAM,oCAAyC;IACzD,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;IAC/D,SAAS,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IAChD,SAAS,CAAC,WAAW,qBAA+D;IACpF,SAAS,CAAC,QAAQ,CAAC,GAAG;;;;;MAAC;IACvB,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,eAAe,sBAA6B;IACtD,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxF,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;gBAG7B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,WAAW,EACzB,IAAI,EAAE,WAAW,EACjB,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,UAAU,CAAC,EAAE,MAAM;IAarB,SAAS,CAAC,eAAe,IAAI,UAAU,CAAC,OAAO,sBAAsB,CAAC;IAWtE,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9D,SAAS,CAAC,QAAQ,CAAC,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEzE,+DAA+D;IAC/D,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAKzC,6DAA6D;IAC7D,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS;IAIjE,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,UAAQ,GAAG,IAAI;IAQ9D,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAItC,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,UAAO,GAAG,IAAI;cAIlC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAa,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpH,SAAS,CAAC,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI7C,SAAS,CAAC,aAAa,IAAI,IAAI;IAK/B,gGAAgG;cAChF,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAI5E;;;;;;OAMG;IACH;;;;;;;;OAQG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO;IAoB9E;;;OAGG;cACa,mBAAmB,CACjC,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EACtC,UAAU,EAAE,MAAM,EAClB,kBAAkB,UAAO,GACxB,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAkCrE"}
|
|
@@ -6,11 +6,11 @@ import { createDedupeCache } from './dedupe.js';
|
|
|
6
6
|
import { createMessageDebouncer } from './debounce.js';
|
|
7
7
|
import { createLogger } from '../../lib/logger.js';
|
|
8
8
|
import { toMessage } from '../../lib/error.js';
|
|
9
|
-
import { parseSessionKey } from '../../lib/
|
|
9
|
+
import { parseSessionKey } from '../../lib/session-key.js';
|
|
10
10
|
import { TypingStateManager } from './typing-state.js';
|
|
11
11
|
import { saveMedia } from '../../lib/media.js';
|
|
12
12
|
import { getDataPaths } from '../../lib/paths.js';
|
|
13
|
-
const MEDIA_TYPE_LABELS = {
|
|
13
|
+
export const MEDIA_TYPE_LABELS = {
|
|
14
14
|
audio: 'Voice message',
|
|
15
15
|
video: 'Video message',
|
|
16
16
|
document: 'Document',
|
|
@@ -29,9 +29,11 @@ export class BaseChannelAdapter {
|
|
|
29
29
|
transcribeFn;
|
|
30
30
|
describeFn;
|
|
31
31
|
extractFn;
|
|
32
|
-
|
|
32
|
+
allowFrom;
|
|
33
|
+
constructor(instanceId, _channelType, deps, allowFrom, debounceMs) {
|
|
33
34
|
this.instanceId = instanceId;
|
|
34
35
|
this.onInboundMessage = deps.onInbound;
|
|
36
|
+
this.allowFrom = allowFrom;
|
|
35
37
|
this.transcribeFn = deps.transcribe;
|
|
36
38
|
this.describeFn = deps.describe;
|
|
37
39
|
this.extractFn = deps.extract;
|
|
@@ -84,7 +86,7 @@ export class BaseChannelAdapter {
|
|
|
84
86
|
this.debouncer.flushAll();
|
|
85
87
|
this.typingState.cleanup();
|
|
86
88
|
}
|
|
87
|
-
/** Override to handle media resolution for your channel. */
|
|
89
|
+
/** Override to handle media resolution for your channel. Typed via the adapter's TRaw param. */
|
|
88
90
|
async resolveMedia(_msg) {
|
|
89
91
|
return null;
|
|
90
92
|
}
|
|
@@ -95,87 +97,68 @@ export class BaseChannelAdapter {
|
|
|
95
97
|
* @param normalizedMsg - Normalized message with flags (skipAgent, etc)
|
|
96
98
|
* @param route - Function to route processed text to onInboundMessage
|
|
97
99
|
*/
|
|
98
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Check if the agent should execute for this message.
|
|
102
|
+
* Used by both media processing and agent execution decisions.
|
|
103
|
+
*
|
|
104
|
+
* Rules:
|
|
105
|
+
* - Private chat: whitelisted user → execute
|
|
106
|
+
* - Group chat: mentioned + whitelisted → execute
|
|
107
|
+
* - No allowFrom configured: always execute (permissive)
|
|
108
|
+
*/
|
|
109
|
+
shouldExecute(userId, chatType, isMentioned) {
|
|
110
|
+
// undefined = not configured (allow all), [] = configured but empty (block all)
|
|
111
|
+
if (this.allowFrom === undefined)
|
|
112
|
+
return true;
|
|
113
|
+
const normalizedUser = userId.replace(/^\+/, '').replace(/@[^@]+$/, '');
|
|
114
|
+
const fullJidNoPlus = userId.replace(/^\+/, '');
|
|
115
|
+
const isWhitelisted = this.allowFrom.some(entry => {
|
|
116
|
+
const normalizedEntry = entry.replace(/^\+/, '');
|
|
117
|
+
// Match: full JID (no +) OR normalized numeric (no +, no @...)
|
|
118
|
+
return fullJidNoPlus === normalizedEntry || normalizedUser === normalizedEntry;
|
|
119
|
+
});
|
|
120
|
+
if (!isWhitelisted)
|
|
121
|
+
return false;
|
|
122
|
+
if (chatType === 'private')
|
|
123
|
+
return true;
|
|
124
|
+
// Group chat: require mention. For practical purposes, any @number pattern
|
|
125
|
+
// in the message counts (covers both proper mentions and manual @typing).
|
|
126
|
+
return isMentioned;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Process inbound media: save file, optionally transcribe/describe.
|
|
130
|
+
* Returns caption text + saved path for routing to onInboundMessage.
|
|
131
|
+
*/
|
|
132
|
+
async processInboundMedia(msg, route, sessionKey, shouldProcessMedia = true) {
|
|
99
133
|
const source = await this.resolveMedia(msg);
|
|
100
|
-
const defaultReturn = { caption: '', savedPath: '', mimeType: '' };
|
|
101
134
|
if (!source)
|
|
102
|
-
return
|
|
135
|
+
return { caption: '', savedPath: '', mimeType: '' };
|
|
103
136
|
const { buffer, mimeType, mediaType, caption, duration } = source;
|
|
104
137
|
const mediaDir = path.join(getDataPaths().dataDir, 'media');
|
|
105
138
|
const savedPath = await saveMedia({ buffer, sessionKey, mimeType, mediaDir });
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
savedPath,
|
|
115
|
-
mimeType
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (mediaType === 'image') {
|
|
119
|
-
if (this.describeFn) {
|
|
120
|
-
try {
|
|
121
|
-
const description = await this.describeFn(savedPath);
|
|
122
|
-
await route(`${description}\n\n[Image described from: ${savedPath}]`);
|
|
123
|
-
return {
|
|
124
|
-
caption: description,
|
|
125
|
-
savedPath,
|
|
126
|
-
mimeType
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
this.log.warn(`Image description failed: ${err}. Falling back to caption.`);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const text = caption || 'User sent an image.';
|
|
134
|
-
await route(`${text}\n\n[Image saved: ${savedPath}]`);
|
|
135
|
-
return {
|
|
136
|
-
caption: text,
|
|
137
|
-
savedPath,
|
|
138
|
-
mimeType
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
if (mediaType === 'audio' && this.transcribeFn) {
|
|
142
|
-
try {
|
|
143
|
-
const transcription = await this.transcribeFn(savedPath);
|
|
144
|
-
await route(`${transcription}\n\n[Audio transcribed from: ${savedPath}]`);
|
|
145
|
-
return {
|
|
146
|
-
caption: transcription,
|
|
147
|
-
savedPath,
|
|
148
|
-
mimeType
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
catch (err) {
|
|
152
|
-
this.log.warn(`Audio transcription failed: ${err}. Falling back to file path.`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (mediaType === 'document' && this.extractFn) {
|
|
139
|
+
// Process map: media type → [process function, fallback text, label]
|
|
140
|
+
const processMap = {
|
|
141
|
+
image: [this.describeFn?.bind(this), caption || 'User sent an image.', 'Image'],
|
|
142
|
+
audio: [this.transcribeFn?.bind(this), caption || 'User sent an audio file.', 'Audio'],
|
|
143
|
+
document: [this.extractFn?.bind(this), caption || 'User sent a document.', 'Document'],
|
|
144
|
+
};
|
|
145
|
+
const [processFn, _fb, label] = processMap[mediaType] ?? [undefined, caption || 'Media', MEDIA_TYPE_LABELS[mediaType] ?? 'Media'];
|
|
146
|
+
if (shouldProcessMedia && processFn) {
|
|
156
147
|
try {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
savedPath,
|
|
162
|
-
mimeType
|
|
163
|
-
};
|
|
148
|
+
const result = await processFn(savedPath, mimeType);
|
|
149
|
+
const text = typeof result === 'string' ? result : result.text;
|
|
150
|
+
await route(`${text}\n\n[${label}: ${savedPath}]`);
|
|
151
|
+
return { caption: text, savedPath, mimeType };
|
|
164
152
|
}
|
|
165
153
|
catch (err) {
|
|
166
|
-
this.log.warn(
|
|
154
|
+
this.log.warn(`${label} processing failed: ${err}. Falling back to path.`);
|
|
167
155
|
}
|
|
168
156
|
}
|
|
169
|
-
//
|
|
170
|
-
const label = MEDIA_TYPE_LABELS[mediaType] ?? 'Media';
|
|
157
|
+
// Fallback: just include path
|
|
171
158
|
const durationSuffix = duration != null ? `, ${duration}s` : '';
|
|
172
159
|
const fallbackCaption = caption || `[${label}${durationSuffix}]`;
|
|
173
|
-
await route(`${fallbackCaption}\n\n[${label}
|
|
174
|
-
return {
|
|
175
|
-
caption: fallbackCaption,
|
|
176
|
-
savedPath,
|
|
177
|
-
mimeType,
|
|
178
|
-
};
|
|
160
|
+
await route(`${fallbackCaption}\n\n[${label}: ${savedPath}]`);
|
|
161
|
+
return { caption: fallbackCaption, savedPath, mimeType };
|
|
179
162
|
}
|
|
180
163
|
}
|
|
181
164
|
//# sourceMappingURL=base-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.js","sourceRoot":"","sources":["../../../services/channels/base-adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"base-adapter.js","sourceRoot":"","sources":["../../../services/channels/base-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Accumulates rapid messages from the same sender, flushes after a delay
|
|
4
4
|
* Prevents partial messages from triggering separate agent runs
|
|
5
5
|
*/
|
|
6
|
-
import type { NormalizedInboundMessage } from './
|
|
6
|
+
import type { NormalizedInboundMessage } from './types.js';
|
|
7
7
|
export interface DebounceConfig {
|
|
8
8
|
/** Delay in ms before flushing accumulated messages (default: 1500) */
|
|
9
9
|
delayMs?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../services/channels/debounce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../services/channels/debounce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC9E,mDAAmD;IACnD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yCAAyC;IACzC,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,wBAAwB,KAAK,IAAI,EACvF,IAAI,GAAE,cAAmB,GACxB,gBAAgB,CAkDlB"}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import type { Bus } from '../../gateway/bus.js';
|
|
20
20
|
import type { EventMap } from '../../gateway/events.js';
|
|
21
21
|
import type { AppConfig } from '../../services/config/index.js';
|
|
22
|
-
import type { NormalizedInboundMessage } from './
|
|
22
|
+
import type { NormalizedInboundMessage } from './types.js';
|
|
23
23
|
export declare class ChannelService {
|
|
24
24
|
private readonly bus;
|
|
25
25
|
private readonly config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../services/channels/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,yBAAyB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,gCAAgC,CAAC;AAM9E,OAAO,KAAK,EAAmC,wBAAwB,EAAe,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../services/channels/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,yBAAyB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,gCAAgC,CAAC;AAM9E,OAAO,KAAK,EAAmC,wBAAwB,EAAe,MAAM,YAAY,CAAC;AAoDzG,qBAAa,cAAc;IAOvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,QAAQ,CAAyB;gBAGtB,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS;IAK9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKd,iBAAiB;IAOzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBrB,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC;IA6C7F,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAqB5G,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAkBnG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC;IAuB1F,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B7E,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,gBAAgB;IAgFxB;;;OAGG;IACG,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC;YAoBF,YAAY;YAmBZ,aAAa;YAcb,kBAAkB;CAiBjC;AAID,wBAAsB,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAMvE"}
|
|
@@ -55,10 +55,10 @@ import { on, register } from '../../gateway/decorators.js';
|
|
|
55
55
|
import { createLogger } from '../../lib/logger.js';
|
|
56
56
|
import { toMessage } from '../../lib/error.js';
|
|
57
57
|
import { stripMarkdown } from '../../lib/strip-markdown.js';
|
|
58
|
-
import { parseChannelTarget } from '../../lib/
|
|
58
|
+
import { parseChannelTarget } from '../../lib/session-key.js';
|
|
59
59
|
import { paginate } from '../../lib/paginate.js';
|
|
60
60
|
import { deliverReply } from './delivery.js';
|
|
61
|
-
import { extractMediaPaths } from './media-
|
|
61
|
+
import { extractMediaPaths } from './media-paths.js';
|
|
62
62
|
import { InboundMessagePipeline } from './pipeline.js';
|
|
63
63
|
import { loadProviders } from './provider-loader.js';
|
|
64
64
|
const log = createLogger('channels');
|
|
@@ -81,6 +81,12 @@ class ChannelRegistry {
|
|
|
81
81
|
register(provider) {
|
|
82
82
|
this.providers.set(provider.type, provider);
|
|
83
83
|
}
|
|
84
|
+
has(type) {
|
|
85
|
+
return this.providers.has(type);
|
|
86
|
+
}
|
|
87
|
+
types() {
|
|
88
|
+
return [...this.providers.keys()];
|
|
89
|
+
}
|
|
84
90
|
async createAdapter(entry, deps) {
|
|
85
91
|
const provider = this.providers.get(entry.type);
|
|
86
92
|
if (!provider) {
|
|
@@ -133,11 +139,13 @@ let ChannelService = (() => {
|
|
|
133
139
|
schema: z.object({ instanceId: z.string() }),
|
|
134
140
|
})];
|
|
135
141
|
_register_decorators = [register('channel.register', {
|
|
136
|
-
description: 'Dynamically register a new channel adapter.',
|
|
142
|
+
description: 'Dynamically register a new channel adapter. `type` must match a loaded provider (e.g. telegram, whatsapp).',
|
|
137
143
|
// Flat object required: discriminatedUnion produces type:null in JSON Schema, rejected by Anthropic API.
|
|
144
|
+
// `type` is a free string validated at runtime against loaded providers — keeps this open to new
|
|
145
|
+
// providers without re-listing them here (the config union remains the authority for persistence).
|
|
138
146
|
schema: z.object({
|
|
139
147
|
id: z.string(),
|
|
140
|
-
type: z.
|
|
148
|
+
type: z.string(),
|
|
141
149
|
enabled: z.boolean().optional(),
|
|
142
150
|
model: z.string().optional(),
|
|
143
151
|
debounceMs: z.number().int().min(0).optional(),
|
|
@@ -197,13 +205,14 @@ let ChannelService = (() => {
|
|
|
197
205
|
const adapter = this.adapters.get(target.channel);
|
|
198
206
|
if (!adapter)
|
|
199
207
|
throw new Error(`No adapter for channel: ${target.channel}`);
|
|
200
|
-
log.
|
|
208
|
+
log.info(`send: ${sessionKey} (${text.length} chars) channel=${target.channel}`);
|
|
201
209
|
const cleaned = stripMarkdown(text);
|
|
202
|
-
log.info(`send: ${sessionKey} (${text.length} → ${cleaned.length} chars after stripMarkdown)`);
|
|
203
|
-
if (cleaned.length === 0) {
|
|
204
|
-
log.warn(`send: stripMarkdown resulted in empty string (original: ${text.length} chars)`);
|
|
205
|
-
}
|
|
206
210
|
await deliverReply((chunk) => adapter.send(sessionKey, chunk), cleaned);
|
|
211
|
+
// Mark session as replied so onAgentCompleted knows agent sent its own reply
|
|
212
|
+
const session = this.activeSessions.get(sessionKey);
|
|
213
|
+
if (session)
|
|
214
|
+
session.replied = true;
|
|
215
|
+
log.info(`send: completed ${sessionKey}`);
|
|
207
216
|
if (adapter.sendMedia) {
|
|
208
217
|
const files = extractMediaPaths(text);
|
|
209
218
|
for (const { filePath, mimeType } of files) {
|
|
@@ -250,6 +259,9 @@ let ChannelService = (() => {
|
|
|
250
259
|
return { instanceId: adapter.instanceId, type: adapter.type, status: adapter.status };
|
|
251
260
|
}
|
|
252
261
|
async register(params) {
|
|
262
|
+
if (!this.registry.has(params.type)) {
|
|
263
|
+
throw new Error(`Unknown channel type: ${params.type}. Loaded providers: ${this.registry.types().join(', ')}`);
|
|
264
|
+
}
|
|
253
265
|
if (this.adapters.has(params.id)) {
|
|
254
266
|
log.info(`channel already registered: ${params.id}`);
|
|
255
267
|
return;
|
|
@@ -297,8 +309,8 @@ let ChannelService = (() => {
|
|
|
297
309
|
}
|
|
298
310
|
const session = this.activeSessions.get(payload.sessionKey);
|
|
299
311
|
if (!session) {
|
|
300
|
-
// Non-channel session with no active session — ignore
|
|
301
|
-
log.
|
|
312
|
+
// Non-channel session (cron, webhook, etc.) with no active session — expected, ignore
|
|
313
|
+
log.debug(`onAgentCompleted: session not found in activeSessions: ${payload.sessionKey}`);
|
|
302
314
|
return;
|
|
303
315
|
}
|
|
304
316
|
const targetSessionKey = payload.sessionKey;
|
|
@@ -306,7 +318,7 @@ let ChannelService = (() => {
|
|
|
306
318
|
const responseText = payload.success
|
|
307
319
|
? payload.response || ''
|
|
308
320
|
: `Error: ${payload.error || 'Unknown error'}`;
|
|
309
|
-
log.info(
|
|
321
|
+
log.info(`→ ${targetSessionKey} ${payload.success ? '✓' : '✗'} (${responseLength} chars)`);
|
|
310
322
|
const cleanup = () => {
|
|
311
323
|
if (session?.reactionController) {
|
|
312
324
|
if (payload.success === false) {
|
|
@@ -319,23 +331,50 @@ let ChannelService = (() => {
|
|
|
319
331
|
}
|
|
320
332
|
session.adapter.stopTyping(targetSessionKey, true);
|
|
321
333
|
};
|
|
322
|
-
// Don't send empty responses on success
|
|
334
|
+
// Don't send empty responses on success.
|
|
335
|
+
// Agent controls reply via channel-send tool — onAgentCompleted is cleanup-only.
|
|
323
336
|
if (payload.success && !payload.response) {
|
|
324
337
|
log.debug(` → skipping send: empty response on success`);
|
|
325
338
|
cleanup();
|
|
326
339
|
return;
|
|
327
340
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
341
|
+
// Agent sends its own reply via channel-send tool.
|
|
342
|
+
// Fallback: if response is non-empty but agent didn't call channel-send, send here.
|
|
343
|
+
if (payload.success === false) {
|
|
344
|
+
// Always send errors
|
|
345
|
+
this.bus.call('channel.send', { sessionKey: targetSessionKey, text: responseText })
|
|
346
|
+
.then(({ sent }) => {
|
|
347
|
+
log.debug(`→ ${targetSessionKey} sent=${sent}`);
|
|
348
|
+
})
|
|
349
|
+
.catch(err => log.error(`failed to send reply: ${toMessage(err)}`))
|
|
350
|
+
.finally(() => {
|
|
351
|
+
if (session) {
|
|
352
|
+
log.debug(` → stopping typing (session stays alive for idle cleanup)`);
|
|
353
|
+
cleanup();
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
else if (session && !session.replied && payload.response) {
|
|
358
|
+
// Agent returned a response but didn't call channel-send — auto-send as fallback
|
|
359
|
+
log.debug(` → agent didn't call channel-send, auto-sending response (${payload.response.length} chars)`);
|
|
360
|
+
this.bus.call('channel.send', { sessionKey: targetSessionKey, text: responseText })
|
|
361
|
+
.then(({ sent }) => {
|
|
362
|
+
log.debug(`→ ${targetSessionKey} sent=${sent}`);
|
|
363
|
+
})
|
|
364
|
+
.catch(err => log.error(`failed to send reply: ${toMessage(err)}`))
|
|
365
|
+
.finally(() => {
|
|
366
|
+
if (session) {
|
|
367
|
+
log.debug(` → stopping typing (session stays alive for idle cleanup)`);
|
|
368
|
+
cleanup();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// Success with response — agent should have sent via channel-send.
|
|
374
|
+
// Just cleanup here.
|
|
375
|
+
log.debug(` → agent response delivered via channel-send (cleanup only)`);
|
|
376
|
+
cleanup();
|
|
377
|
+
}
|
|
339
378
|
}
|
|
340
379
|
// ── Inbound message handling ─────────────────────────────────────────────────
|
|
341
380
|
/**
|
|
@@ -354,7 +393,7 @@ let ChannelService = (() => {
|
|
|
354
393
|
return;
|
|
355
394
|
}
|
|
356
395
|
// Delegate to pipeline for policy orchestration
|
|
357
|
-
log.debug(`onInboundMessage:
|
|
396
|
+
log.debug(`onInboundMessage: Running pipeline process for ${sessionKey}`);
|
|
358
397
|
await this.pipeline.process(sessionKey, message, adapter, this.activeSessions);
|
|
359
398
|
}
|
|
360
399
|
// ── Channel startup ──────────────────────────────────────────────────────────
|