@krischoichoi/channel-telegram 0.6.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 +129 -0
- package/lib/adapter.d.ts +94 -0
- package/lib/adapter.d.ts.map +1 -0
- package/lib/adapter.js +417 -0
- package/lib/adapter.js.map +1 -0
- package/lib/api-error.d.ts +74 -0
- package/lib/api-error.d.ts.map +1 -0
- package/lib/api-error.js +103 -0
- package/lib/api-error.js.map +1 -0
- package/lib/config.d.ts +115 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +67 -0
- package/lib/config.js.map +1 -0
- package/lib/definition.d.ts +59 -0
- package/lib/definition.d.ts.map +1 -0
- package/lib/definition.js +158 -0
- package/lib/definition.js.map +1 -0
- package/lib/inbound.d.ts +61 -0
- package/lib/inbound.d.ts.map +1 -0
- package/lib/inbound.js +125 -0
- package/lib/inbound.js.map +1 -0
- package/lib/index.d.ts +52 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +114 -0
- package/lib/index.js.map +1 -0
- package/lib/manifest.d.ts +16 -0
- package/lib/manifest.d.ts.map +1 -0
- package/lib/manifest.js +26 -0
- package/lib/manifest.js.map +1 -0
- package/lib/mapper.d.ts +51 -0
- package/lib/mapper.d.ts.map +1 -0
- package/lib/mapper.js +314 -0
- package/lib/mapper.js.map +1 -0
- package/lib/media-hydrator.d.ts +46 -0
- package/lib/media-hydrator.d.ts.map +1 -0
- package/lib/media-hydrator.js +85 -0
- package/lib/media-hydrator.js.map +1 -0
- package/lib/outbound.d.ts +42 -0
- package/lib/outbound.d.ts.map +1 -0
- package/lib/outbound.js +215 -0
- package/lib/outbound.js.map +1 -0
- package/lib/render/html.d.ts +13 -0
- package/lib/render/html.d.ts.map +1 -0
- package/lib/render/html.js +110 -0
- package/lib/render/html.js.map +1 -0
- package/lib/render/index.d.ts +64 -0
- package/lib/render/index.d.ts.map +1 -0
- package/lib/render/index.js +76 -0
- package/lib/render/index.js.map +1 -0
- package/lib/render/markdown.d.ts +38 -0
- package/lib/render/markdown.d.ts.map +1 -0
- package/lib/render/markdown.js +187 -0
- package/lib/render/markdown.js.map +1 -0
- package/lib/render/plain.d.ts +43 -0
- package/lib/render/plain.d.ts.map +1 -0
- package/lib/render/plain.js +97 -0
- package/lib/render/plain.js.map +1 -0
- package/lib/render/segment.d.ts +39 -0
- package/lib/render/segment.d.ts.map +1 -0
- package/lib/render/segment.js +117 -0
- package/lib/render/segment.js.map +1 -0
- package/lib/rich-message.d.ts +75 -0
- package/lib/rich-message.d.ts.map +1 -0
- package/lib/rich-message.js +11 -0
- package/lib/rich-message.js.map +1 -0
- package/lib/rich-streaming-reply.d.ts +69 -0
- package/lib/rich-streaming-reply.d.ts.map +1 -0
- package/lib/rich-streaming-reply.js +207 -0
- package/lib/rich-streaming-reply.js.map +1 -0
- package/lib/streaming-reply.d.ts +98 -0
- package/lib/streaming-reply.d.ts.map +1 -0
- package/lib/streaming-reply.js +274 -0
- package/lib/streaming-reply.js.map +1 -0
- package/lib/transport.d.ts +38 -0
- package/lib/transport.d.ts.map +1 -0
- package/lib/transport.js +91 -0
- package/lib/transport.js.map +1 -0
- package/lib/upstream.d.ts +174 -0
- package/lib/upstream.d.ts.map +1 -0
- package/lib/upstream.js +452 -0
- package/lib/upstream.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# @krischoichoi/channel-telegram
|
|
2
|
+
|
|
3
|
+
Telegram Bot API channel adapter for DeepSeek Harness.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @krischoichoi/channel-telegram
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Bundled community channel
|
|
12
|
+
|
|
13
|
+
This package is part of the community-maintained `@krischoichoi/dsh-channels` bundle.
|
|
14
|
+
It is not an official DeepSeek Harness or Telegram package.
|
|
15
|
+
It implements the same Channel Contract as weixin / qq / dingtalk / lark,
|
|
16
|
+
with no changes to channel-core, channel-harness or the other adapters.
|
|
17
|
+
Setup and credentials go through the Channel Control Plane; the bot token is
|
|
18
|
+
stored via `ctx.credentials` (`tokenRef`), never in profile config.
|
|
19
|
+
|
|
20
|
+
> The bundle patch inserts this adapter as `channels-telegram` and the Web settings
|
|
21
|
+
> panel shows it with the other bundled channels.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Contract coverage:
|
|
25
|
+
|
|
26
|
+
- `ChannelAdapter` contract (`start` / `stop` / `send` / `getHealth` / capabilities)
|
|
27
|
+
- `runChannelAdapterContract` — the testkit's full contract suite passes
|
|
28
|
+
- Cordis plugin shape (`name` / `inject` / `apply` via `ctx.effect`)
|
|
29
|
+
- Schemastery `Config` with an injectable `HttpTransport` (offline fake in tests)
|
|
30
|
+
- Fixture-driven mapper tests (`fixtures/telegram/*.json`, Bot API 10.2 shapes)
|
|
31
|
+
- M4 governance: `readonly manifest` class field + `manifest.ts` for
|
|
32
|
+
`channels doctor` compatibility checks
|
|
33
|
+
|
|
34
|
+
The adapter remains `experimental` until its real-platform live gate passes;
|
|
35
|
+
offline contract tests and fixtures do not by themselves justify `tested`.
|
|
36
|
+
|
|
37
|
+
## Pointing it at a real bot
|
|
38
|
+
|
|
39
|
+
In your profile config:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"plugins": {
|
|
44
|
+
"channel-telegram": {
|
|
45
|
+
"enabled": true,
|
|
46
|
+
"accountId": "main",
|
|
47
|
+
"baseUrl": "https://api.telegram.org",
|
|
48
|
+
"tokenRef": "TELEGRAM_BOT_TOKEN",
|
|
49
|
+
"longPollTimeoutMs": 25000
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The token is a **secret** resolved through `ctx.credentials` (`tokenRef`): it is never logged (bearer-style path segments are
|
|
56
|
+
redacted in transport error messages) and it only ever appears in the Bot API
|
|
57
|
+
request path built by the upstream driver. It is never written into fixture
|
|
58
|
+
files.
|
|
59
|
+
|
|
60
|
+
Inbound delivery currently uses Telegram Bot API long polling (`getUpdates`),
|
|
61
|
+
matching OpenClaw's local-install default. Startup removes an existing webhook
|
|
62
|
+
before polling because Telegram makes webhook and `getUpdates` delivery mutually
|
|
63
|
+
exclusive. This is an operational takeover of the Bot's update receiver: do not
|
|
64
|
+
reuse the same Bot for another webhook consumer. A hosted webhook transport is
|
|
65
|
+
not implemented yet.
|
|
66
|
+
|
|
67
|
+
## Capabilities
|
|
68
|
+
|
|
69
|
+
| capability | value |
|
|
70
|
+
| ------------ | --------- |
|
|
71
|
+
| text / image / file / audio / video | ✅ |
|
|
72
|
+
| markdown | ✅ Rich Markdown |
|
|
73
|
+
| reactions | ❌ |
|
|
74
|
+
| cards | ❌ |
|
|
75
|
+
| threads | ✅ |
|
|
76
|
+
| interactive actions | ✅ (inline keyboard buttons via `callback_query`) |
|
|
77
|
+
| streaming | DM Rich Draft; group plain preview + rich final edit; set `streaming.enabled: false` for buffered |
|
|
78
|
+
|
|
79
|
+
## Known limits
|
|
80
|
+
|
|
81
|
+
- Minimum supported upstream is Telegram Bot API 10.2. Older or pinned custom
|
|
82
|
+
Bot API servers are not supported; use `formatting.mode: plain` only as an
|
|
83
|
+
explicit presentation choice, not as an old-server compatibility mode.
|
|
84
|
+
- `getUpdates` subscribes to `message` and `callback_query`. Button interactions
|
|
85
|
+
are currently intended only for callback queries carrying `message.chat`;
|
|
86
|
+
inline-message callbacks without chat context are not a supported routing
|
|
87
|
+
surface and require a mapper hardening change before release.
|
|
88
|
+
- The ordinary message mapper still needs a complete zod trust-boundary schema;
|
|
89
|
+
the current partial envelope validation and TypeScript casts are an identified
|
|
90
|
+
release blocker, not evidence that arbitrary Telegram updates are supported.
|
|
91
|
+
- Media sends validate the Bot API `ok` envelope and returned `message_id`; an
|
|
92
|
+
`ok: false` response is surfaced as a delivery failure. Offline coverage does
|
|
93
|
+
not replace the required real-bot live gate.
|
|
94
|
+
- Inbound image, file, audio, and video media hydrate bytes through
|
|
95
|
+
`getFile`/download when declared as byte-capable. Failures retain
|
|
96
|
+
`resourceRef` plus ingress-failure metadata.
|
|
97
|
+
- Telegram albums (`media_group_id`) are intentionally delivered one update at
|
|
98
|
+
a time. Each image is downloaded, dispatched, retried and acknowledged
|
|
99
|
+
independently; no cross-update buffering or delayed album aggregation is
|
|
100
|
+
performed.
|
|
101
|
+
- Media captions are preserved as a text part before the image or document, so
|
|
102
|
+
the model receives both the caption and the shared attachment representation.
|
|
103
|
+
- Media outbound accepts trusted `localData` via `multipart/form-data`, a
|
|
104
|
+
public `url`, or a platform `file_id` (`resourceRef`). Multiple supported
|
|
105
|
+
media parts are sent sequentially; an unsupported part fails the send rather
|
|
106
|
+
than being silently dropped.
|
|
107
|
+
- Inbound media maps Telegram `file_id` to the contract's `resourceRef` carrier
|
|
108
|
+
(an opaque platform handle), never to `url` — `url` is reserved for real
|
|
109
|
+
`http(s)` URLs.
|
|
110
|
+
- `beginAuth`/`pollAuth` are omitted: auth is token-driven (getMe() check at start).
|
|
111
|
+
- Forum topics preserve `message_thread_id`; `chat.type === 'channel'`
|
|
112
|
+
currently maps to a `dm` conversation.
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
pnpm --filter @krischoichoi/channel-telegram build
|
|
118
|
+
pnpm --filter @krischoichoi/channel-telegram typecheck
|
|
119
|
+
pnpm --filter @krischoichoi/channel-telegram test
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Related
|
|
123
|
+
|
|
124
|
+
- [Repository root](../../README.md)
|
|
125
|
+
- [Adapter authoring guide](../../docs/adapter-authoring.md)
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
[MIT](../../LICENSE)
|
package/lib/adapter.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram channel adapter.
|
|
3
|
+
*
|
|
4
|
+
* Maps the Telegram Bot API (through the upstream driver) to the Channel
|
|
5
|
+
* Contract. All network/lifecycle resources live behind the upstream driver
|
|
6
|
+
* and are aborted via the adapter context signal. The adapter never touches
|
|
7
|
+
* Harness Agent APIs.
|
|
8
|
+
*
|
|
9
|
+
* Auth is token-driven: when a token is resolved (via `deps.token`, the
|
|
10
|
+
* credential seam, or the deprecated plaintext `config.token`), `start`
|
|
11
|
+
* verifies it with getMe() and launches the long-poll receive loop; without a
|
|
12
|
+
* token the adapter reports health 'down' and skips the loop entirely.
|
|
13
|
+
* `beginAuth`/`pollAuth` are intentionally not implemented — there is no
|
|
14
|
+
* interactive flow in V1; token rotation can slot in behind the same optional
|
|
15
|
+
* contract methods later.
|
|
16
|
+
*
|
|
17
|
+
* Streaming is `edit`: ReplyRouter opens a `TelegramStreamingReply` which sends
|
|
18
|
+
* one message and edits it in place with `editMessageText` as full-text
|
|
19
|
+
* previews arrive. Set `config.streaming.enabled: false` to force the buffered
|
|
20
|
+
* send-once strategy.
|
|
21
|
+
*/
|
|
22
|
+
import type { ChannelAdapter, ChannelAdapterContext, ChannelCapabilities, ChannelHealth, ChannelTarget, CreateReplyOptions, OutboundMessage, ReplyHandle, SendResult, StreamingMode } from '@krischoichoi/channel-core';
|
|
23
|
+
import type { TelegramConfig } from './config.js';
|
|
24
|
+
import { type HttpTransport } from './transport.js';
|
|
25
|
+
import { type TelegramManifest } from './manifest.js';
|
|
26
|
+
export interface TelegramAdapterDeps {
|
|
27
|
+
transport?: HttpTransport;
|
|
28
|
+
/**
|
|
29
|
+
* Resolved Telegram Bot API token. The plugin resolves it via
|
|
30
|
+
* `ctx.credentials` and hands it in; profile config never carries it.
|
|
31
|
+
*/
|
|
32
|
+
token?: string;
|
|
33
|
+
/** Injectable clock (tests). */
|
|
34
|
+
now?: () => number;
|
|
35
|
+
}
|
|
36
|
+
export declare class TelegramAdapter implements ChannelAdapter {
|
|
37
|
+
private readonly config;
|
|
38
|
+
readonly id = "telegram";
|
|
39
|
+
/** Upstream compatibility manifest (read structurally by `channels doctor`). */
|
|
40
|
+
readonly manifest: TelegramManifest;
|
|
41
|
+
readonly capabilities: ChannelCapabilities;
|
|
42
|
+
readonly outboxCapabilities: {
|
|
43
|
+
proactiveText: boolean;
|
|
44
|
+
proactiveMedia: boolean;
|
|
45
|
+
};
|
|
46
|
+
private ctx?;
|
|
47
|
+
private upstream;
|
|
48
|
+
private inbound;
|
|
49
|
+
private outbound;
|
|
50
|
+
private started;
|
|
51
|
+
private stopped;
|
|
52
|
+
private receiveLoop?;
|
|
53
|
+
private receiveAbort?;
|
|
54
|
+
private removeContextAbortListener?;
|
|
55
|
+
/** One start/refresh lifecycle per chat/topic target, including in-flight starts. */
|
|
56
|
+
private readonly typingStates;
|
|
57
|
+
private connected;
|
|
58
|
+
private authState;
|
|
59
|
+
/** Public bot identity used only for reliable inbound mention activation. */
|
|
60
|
+
private botIdentity?;
|
|
61
|
+
/** getUpdates acknowledgement cursor, shared with the driver across retries. */
|
|
62
|
+
private readonly cursor;
|
|
63
|
+
private readonly now;
|
|
64
|
+
/** Resolved token used by the upstream driver (deps credential wins over legacy config). */
|
|
65
|
+
private readonly token;
|
|
66
|
+
/** Resolved once so outbound, streaming and explicit edits use one policy. */
|
|
67
|
+
private readonly formattingMode;
|
|
68
|
+
constructor(config: TelegramConfig, deps?: TelegramAdapterDeps);
|
|
69
|
+
start(ctx: ChannelAdapterContext): Promise<void>;
|
|
70
|
+
private createInboundProcessor;
|
|
71
|
+
stop(): Promise<void>;
|
|
72
|
+
send(target: ChannelTarget, message: OutboundMessage): Promise<SendResult>;
|
|
73
|
+
/** Start Telegram's transient typing indicator and refresh it per chat/topic. */
|
|
74
|
+
startTypingForTarget(target: ChannelTarget): Promise<void>;
|
|
75
|
+
/** Telegram has no explicit stop action; clearing refresh lets it expire. */
|
|
76
|
+
stopTypingForTarget(target: ChannelTarget): Promise<void>;
|
|
77
|
+
private sendTyping;
|
|
78
|
+
private clearTypingStates;
|
|
79
|
+
resolveStreamingMode(target: ChannelTarget): StreamingMode;
|
|
80
|
+
createReply(target: ChannelTarget, _options?: CreateReplyOptions): Promise<ReplyHandle>;
|
|
81
|
+
/**
|
|
82
|
+
* Optional in-place edit of an already-sent message (plan §15.3): either
|
|
83
|
+
* update the interactive keyboard (`editMessageReplyMarkup`) or the text
|
|
84
|
+
* (`editMessageText`).
|
|
85
|
+
*/
|
|
86
|
+
edit(target: ChannelTarget, messageId: string, message: OutboundMessage): Promise<SendResult>;
|
|
87
|
+
getHealth(): Promise<ChannelHealth>;
|
|
88
|
+
/** Long-poll receive loop with exponential backoff on failure. */
|
|
89
|
+
private startReceiveLoop;
|
|
90
|
+
private runReceiveLoop;
|
|
91
|
+
private emitAuth;
|
|
92
|
+
private emitConnection;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/lib/adapter.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { ChannelError } from '@krischoichoi/channel-core';
|
|
2
|
+
import { FetchTransport } from './transport.js';
|
|
3
|
+
import { HttpTelegramUpstream, } from './upstream.js';
|
|
4
|
+
import { InboundProcessor } from './inbound.js';
|
|
5
|
+
import { OutboundSender } from './outbound.js';
|
|
6
|
+
import { TelegramStreamingReply } from './streaming-reply.js';
|
|
7
|
+
import { TelegramRichStreamingReply } from './rich-streaming-reply.js';
|
|
8
|
+
import { actionsToReplyMarkup } from './outbound.js';
|
|
9
|
+
import { manifest as telegramManifest } from './manifest.js';
|
|
10
|
+
import { resolveMode } from './render/index.js';
|
|
11
|
+
export class TelegramAdapter {
|
|
12
|
+
config;
|
|
13
|
+
id = 'telegram';
|
|
14
|
+
/** Upstream compatibility manifest (read structurally by `channels doctor`). */
|
|
15
|
+
manifest = telegramManifest;
|
|
16
|
+
capabilities = {
|
|
17
|
+
text: true,
|
|
18
|
+
image: true,
|
|
19
|
+
file: true,
|
|
20
|
+
audio: true,
|
|
21
|
+
video: true,
|
|
22
|
+
// Rich Markdown (Bot API 10.1/10.2 sendRichMessage / HTML / MarkdownV2) is
|
|
23
|
+
// genuinely rendered, not just parse_mode in a body (plan §Phase 3).
|
|
24
|
+
markdown: true,
|
|
25
|
+
cards: false,
|
|
26
|
+
reactions: false,
|
|
27
|
+
threads: true,
|
|
28
|
+
// Inline buttons + callback_query interactions are supported (plan §5).
|
|
29
|
+
interactiveActions: true,
|
|
30
|
+
// Telegram can edit sent messages with editMessageText and can stream rich
|
|
31
|
+
// drafts natively for DMs; `resolveStreamingMode` picks per target.
|
|
32
|
+
streaming: 'edit',
|
|
33
|
+
maxTextLength: 4096,
|
|
34
|
+
// Directional media precision. Inbound:
|
|
35
|
+
// every binary kind is hydrated to real bytes (`resourceRef` -> getFile ->
|
|
36
|
+
// /file/bot... -> localData) before emit. Outbound: sendPhoto /
|
|
37
|
+
// sendDocument / sendAudio / sendVideo all accept byte uploads
|
|
38
|
+
// (multipart) or references, so every kind can send real bytes.
|
|
39
|
+
// Platform-level size limits (e.g. Bot API cloud upload caps) are a
|
|
40
|
+
// separate concern from this directional declaration.
|
|
41
|
+
media: {
|
|
42
|
+
inbound: {
|
|
43
|
+
image: 'bytes',
|
|
44
|
+
file: 'bytes',
|
|
45
|
+
audio: 'bytes',
|
|
46
|
+
video: 'bytes',
|
|
47
|
+
},
|
|
48
|
+
outbound: {
|
|
49
|
+
image: 'bytes',
|
|
50
|
+
file: 'bytes',
|
|
51
|
+
audio: 'bytes',
|
|
52
|
+
video: 'bytes',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
outboxCapabilities = { proactiveText: true, proactiveMedia: true };
|
|
57
|
+
ctx;
|
|
58
|
+
upstream;
|
|
59
|
+
inbound;
|
|
60
|
+
outbound;
|
|
61
|
+
started = false;
|
|
62
|
+
stopped = false;
|
|
63
|
+
receiveLoop;
|
|
64
|
+
receiveAbort;
|
|
65
|
+
removeContextAbortListener;
|
|
66
|
+
/** One start/refresh lifecycle per chat/topic target, including in-flight starts. */
|
|
67
|
+
typingStates = new Map();
|
|
68
|
+
connected = false;
|
|
69
|
+
authState = 'unauthenticated';
|
|
70
|
+
/** Public bot identity used only for reliable inbound mention activation. */
|
|
71
|
+
botIdentity;
|
|
72
|
+
/** getUpdates acknowledgement cursor, shared with the driver across retries. */
|
|
73
|
+
cursor = { offset: 0 };
|
|
74
|
+
now;
|
|
75
|
+
/** Resolved token used by the upstream driver (deps credential wins over legacy config). */
|
|
76
|
+
token;
|
|
77
|
+
/** Resolved once so outbound, streaming and explicit edits use one policy. */
|
|
78
|
+
formattingMode;
|
|
79
|
+
constructor(config, deps = {}) {
|
|
80
|
+
this.config = config;
|
|
81
|
+
this.now = deps.now ?? Date.now;
|
|
82
|
+
const transport = deps.transport ?? new FetchTransport(config.baseUrl, { timeoutMs: config.timeoutMs });
|
|
83
|
+
const token = deps.token ?? config.token;
|
|
84
|
+
this.upstream = new HttpTelegramUpstream({
|
|
85
|
+
transport,
|
|
86
|
+
token,
|
|
87
|
+
longPollTimeoutMs: config.longPollTimeoutMs,
|
|
88
|
+
});
|
|
89
|
+
this.token = token;
|
|
90
|
+
this.formattingMode = resolveMode(config.formatting.mode);
|
|
91
|
+
}
|
|
92
|
+
async start(ctx) {
|
|
93
|
+
if (this.started)
|
|
94
|
+
return;
|
|
95
|
+
this.ctx = ctx;
|
|
96
|
+
this.stopped = false;
|
|
97
|
+
this.connected = false;
|
|
98
|
+
this.botIdentity = undefined;
|
|
99
|
+
this.cursor.offset = 0;
|
|
100
|
+
this.inbound = this.createInboundProcessor();
|
|
101
|
+
this.receiveAbort = new AbortController();
|
|
102
|
+
const abortReceive = () => this.receiveAbort?.abort();
|
|
103
|
+
if (ctx.signal.aborted)
|
|
104
|
+
abortReceive();
|
|
105
|
+
else {
|
|
106
|
+
ctx.signal.addEventListener('abort', abortReceive, { once: true });
|
|
107
|
+
this.removeContextAbortListener = () => ctx.signal.removeEventListener('abort', abortReceive);
|
|
108
|
+
}
|
|
109
|
+
this.outbound = new OutboundSender(this.upstream, ctx.logger, {
|
|
110
|
+
formatting: { ...this.config.formatting, mode: this.formattingMode },
|
|
111
|
+
});
|
|
112
|
+
if (this.token) {
|
|
113
|
+
try {
|
|
114
|
+
const bot = await this.upstream.getMe();
|
|
115
|
+
this.botIdentity = {
|
|
116
|
+
id: bot.id,
|
|
117
|
+
...(bot.username ? { username: bot.username } : {}),
|
|
118
|
+
};
|
|
119
|
+
// Polling starts only after getMe, so replace the pre-auth processor
|
|
120
|
+
// with one carrying the trusted identity used by mention detection.
|
|
121
|
+
this.inbound = this.createInboundProcessor();
|
|
122
|
+
this.authState = 'authenticated';
|
|
123
|
+
this.emitAuth('authenticated');
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
this.authState = 'failed';
|
|
127
|
+
this.emitAuth('failed');
|
|
128
|
+
this.ctx.logger.error('[channel-telegram] auth check failed; receive loop disabled', error instanceof Error ? error.message : error);
|
|
129
|
+
this.started = true;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
// getUpdates and webhooks are mutually exclusive. Preserve queued
|
|
134
|
+
// updates while switching this bot to the local polling transport.
|
|
135
|
+
await this.upstream.deleteWebhook();
|
|
136
|
+
this.emitConnection('connecting');
|
|
137
|
+
this.startReceiveLoop();
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
this.ctx.logger.error('[channel-telegram] polling setup failed; receive loop disabled', error instanceof Error ? error.message : error);
|
|
141
|
+
this.emitConnection('disconnected');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
this.authState = 'unauthenticated';
|
|
146
|
+
this.emitAuth('unknown');
|
|
147
|
+
}
|
|
148
|
+
this.started = true;
|
|
149
|
+
}
|
|
150
|
+
createInboundProcessor() {
|
|
151
|
+
return new InboundProcessor({
|
|
152
|
+
ctx: this.ctx,
|
|
153
|
+
meta: {
|
|
154
|
+
channel: this.id,
|
|
155
|
+
accountId: this.config.accountId,
|
|
156
|
+
...(this.botIdentity ? { bot: this.botIdentity } : {}),
|
|
157
|
+
},
|
|
158
|
+
dedupEnabled: this.config.dedup.enabled,
|
|
159
|
+
dedupWindowMs: this.config.dedup.windowMs,
|
|
160
|
+
files: this.upstream,
|
|
161
|
+
maxDownloadBytes: this.config.maxDownloadBytes,
|
|
162
|
+
now: this.now,
|
|
163
|
+
// Best-effort callback ACK (clears the button spinner; never blocks on
|
|
164
|
+
// agent resolution — plan §12.2).
|
|
165
|
+
ackCallback: (callbackId) => this.upstream.answerCallbackQuery({ callback_query_id: callbackId }),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async stop() {
|
|
169
|
+
if (!this.started || this.stopped)
|
|
170
|
+
return;
|
|
171
|
+
this.stopped = true;
|
|
172
|
+
this.started = false;
|
|
173
|
+
this.connected = false;
|
|
174
|
+
this.clearTypingStates();
|
|
175
|
+
this.receiveAbort?.abort();
|
|
176
|
+
this.receiveAbort = undefined;
|
|
177
|
+
this.removeContextAbortListener?.();
|
|
178
|
+
this.removeContextAbortListener = undefined;
|
|
179
|
+
const loop = this.receiveLoop;
|
|
180
|
+
this.receiveLoop = undefined;
|
|
181
|
+
if (loop)
|
|
182
|
+
await loop.catch(() => undefined);
|
|
183
|
+
this.emitConnection('closed');
|
|
184
|
+
}
|
|
185
|
+
async send(target, message) {
|
|
186
|
+
if (!this.started || !this.outbound) {
|
|
187
|
+
throw new ChannelError('CHANNEL_NOT_STARTED', 'telegram adapter is not started');
|
|
188
|
+
}
|
|
189
|
+
return this.outbound.send(target, message);
|
|
190
|
+
}
|
|
191
|
+
/** Start Telegram's transient typing indicator and refresh it per chat/topic. */
|
|
192
|
+
async startTypingForTarget(target) {
|
|
193
|
+
if (!this.started || this.stopped || !this.config.typing.enabled)
|
|
194
|
+
return;
|
|
195
|
+
const key = typingKey(target);
|
|
196
|
+
if (this.typingStates.has(key))
|
|
197
|
+
return;
|
|
198
|
+
const state = {};
|
|
199
|
+
this.typingStates.set(key, state);
|
|
200
|
+
// Let the lifecycle caller decide how to handle an immediate failure. Do
|
|
201
|
+
// not create a refresh timer unless Telegram accepted the initial action.
|
|
202
|
+
try {
|
|
203
|
+
await this.sendTyping(target);
|
|
204
|
+
if (!this.started || this.stopped || this.typingStates.get(key) !== state)
|
|
205
|
+
return;
|
|
206
|
+
state.timer = setInterval(() => {
|
|
207
|
+
// Refresh failures are isolated from the timer; the harness owns the
|
|
208
|
+
// best-effort boundary for the immediate action below.
|
|
209
|
+
void this.sendTyping(target).catch((error) => {
|
|
210
|
+
this.ctx?.logger.debug('[channel-telegram] typing refresh failed', error instanceof Error ? error.message : error);
|
|
211
|
+
});
|
|
212
|
+
}, this.config.typing.refreshMs);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (this.typingStates.get(key) === state)
|
|
216
|
+
this.typingStates.delete(key);
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/** Telegram has no explicit stop action; clearing refresh lets it expire. */
|
|
221
|
+
async stopTypingForTarget(target) {
|
|
222
|
+
const key = typingKey(target);
|
|
223
|
+
const state = this.typingStates.get(key);
|
|
224
|
+
if (!state)
|
|
225
|
+
return;
|
|
226
|
+
this.typingStates.delete(key);
|
|
227
|
+
if (state.timer)
|
|
228
|
+
clearInterval(state.timer);
|
|
229
|
+
}
|
|
230
|
+
async sendTyping(target) {
|
|
231
|
+
await this.upstream.sendChatAction(target.conversationId, 'typing', {
|
|
232
|
+
...(target.threadId ? { messageThreadId: target.threadId } : {}),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
clearTypingStates() {
|
|
236
|
+
for (const state of this.typingStates.values()) {
|
|
237
|
+
if (state.timer)
|
|
238
|
+
clearInterval(state.timer);
|
|
239
|
+
}
|
|
240
|
+
this.typingStates.clear();
|
|
241
|
+
}
|
|
242
|
+
resolveStreamingMode(target) {
|
|
243
|
+
// `streaming.enabled: false` is a hard off-switch: it forces the buffered
|
|
244
|
+
// send-once strategy even though streaming is available.
|
|
245
|
+
if (!this.config.streaming.enabled)
|
|
246
|
+
return 'buffered';
|
|
247
|
+
// Private DMs with rich output use the native sendRichMessageDraft flow.
|
|
248
|
+
const rich = this.formattingMode === 'rich-markdown';
|
|
249
|
+
if (rich && target.conversationType === 'dm')
|
|
250
|
+
return 'native';
|
|
251
|
+
// Everything else edits one message in place.
|
|
252
|
+
return 'edit';
|
|
253
|
+
}
|
|
254
|
+
async createReply(target, _options) {
|
|
255
|
+
if (!this.started || !this.ctx) {
|
|
256
|
+
throw new ChannelError('CHANNEL_NOT_STARTED', 'telegram adapter is not started');
|
|
257
|
+
}
|
|
258
|
+
const mode = this.formattingMode;
|
|
259
|
+
const rich = mode === 'rich-markdown';
|
|
260
|
+
// Native rich draft streaming for private DMs (plan §6.1).
|
|
261
|
+
if (rich && target.conversationType === 'dm') {
|
|
262
|
+
const reply = new TelegramRichStreamingReply(this.upstream, target, this.config.streaming.placeholder, { formatting: { mode } });
|
|
263
|
+
await reply.start();
|
|
264
|
+
return reply;
|
|
265
|
+
}
|
|
266
|
+
// Group (or plain config): plain edit preview; finish upgrades the same
|
|
267
|
+
// message to a Rich Message when rich output is active (plan §6.2).
|
|
268
|
+
const reply = new TelegramStreamingReply(this.upstream, target, this.config.streaming.placeholder, { formatting: { mode }, richFinal: rich && target.conversationType !== 'dm' });
|
|
269
|
+
// Send the placeholder immediately so the user sees the bot is working;
|
|
270
|
+
// subsequent full-text previews edit this same message in place.
|
|
271
|
+
await reply.start();
|
|
272
|
+
return reply;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Optional in-place edit of an already-sent message (plan §15.3): either
|
|
276
|
+
* update the interactive keyboard (`editMessageReplyMarkup`) or the text
|
|
277
|
+
* (`editMessageText`).
|
|
278
|
+
*/
|
|
279
|
+
async edit(target, messageId, message) {
|
|
280
|
+
if (!this.started) {
|
|
281
|
+
throw new ChannelError('CHANNEL_NOT_STARTED', 'telegram adapter is not started');
|
|
282
|
+
}
|
|
283
|
+
if (message.text !== undefined) {
|
|
284
|
+
const markup = message.actions === undefined
|
|
285
|
+
? undefined
|
|
286
|
+
: actionsToReplyMarkup(message.actions) ?? { inline_keyboard: [] };
|
|
287
|
+
const mode = this.formattingMode;
|
|
288
|
+
const raw = mode === 'rich-markdown'
|
|
289
|
+
? await this.upstream.editMessageRich(target.conversationId, messageId, { markdown: message.text }, markup)
|
|
290
|
+
: await this.upstream.editMessageText(target.conversationId, messageId, message.text, markup ? { replyMarkup: markup } : undefined);
|
|
291
|
+
return { delivered: true, raw };
|
|
292
|
+
}
|
|
293
|
+
if (message.actions !== undefined) {
|
|
294
|
+
const markup = actionsToReplyMarkup(message.actions) ?? { inline_keyboard: [] };
|
|
295
|
+
const raw = await this.upstream.editMessageReplyMarkup(target.conversationId, messageId, markup);
|
|
296
|
+
return { delivered: true, raw };
|
|
297
|
+
}
|
|
298
|
+
return { delivered: true };
|
|
299
|
+
}
|
|
300
|
+
async getHealth() {
|
|
301
|
+
if (!this.started) {
|
|
302
|
+
return { status: 'down', detail: 'telegram adapter is not started', authenticated: false };
|
|
303
|
+
}
|
|
304
|
+
if (this.authState === 'authenticated' && this.connected) {
|
|
305
|
+
return { status: 'ok', detail: 'connected', connection: 'connected', authenticated: true };
|
|
306
|
+
}
|
|
307
|
+
if (this.authState === 'authenticated') {
|
|
308
|
+
return {
|
|
309
|
+
status: 'down',
|
|
310
|
+
detail: 'authenticated but receive loop down',
|
|
311
|
+
connection: 'disconnected',
|
|
312
|
+
authenticated: true,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
if (this.authState === 'failed') {
|
|
316
|
+
return { status: 'down', detail: 'authentication failed', authenticated: false };
|
|
317
|
+
}
|
|
318
|
+
return { status: 'down', detail: 'not configured: no bot token', authenticated: false };
|
|
319
|
+
}
|
|
320
|
+
/** Long-poll receive loop with exponential backoff on failure. */
|
|
321
|
+
startReceiveLoop() {
|
|
322
|
+
if (this.receiveLoop)
|
|
323
|
+
return;
|
|
324
|
+
this.receiveLoop = this.runReceiveLoop();
|
|
325
|
+
}
|
|
326
|
+
async runReceiveLoop() {
|
|
327
|
+
let attempt = 0;
|
|
328
|
+
const signal = this.receiveAbort?.signal;
|
|
329
|
+
if (!signal)
|
|
330
|
+
return;
|
|
331
|
+
while (!this.stopped && !signal.aborted) {
|
|
332
|
+
try {
|
|
333
|
+
await this.upstream.getUpdates(this.cursor, signal, async (raw) => {
|
|
334
|
+
try {
|
|
335
|
+
await this.inbound.handle(raw);
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
// Reset transient processor state before retrying the unacked
|
|
339
|
+
// update after the receive loop reconnects.
|
|
340
|
+
this.inbound = this.createInboundProcessor();
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
}, () => {
|
|
344
|
+
if (!this.connected) {
|
|
345
|
+
this.connected = true;
|
|
346
|
+
this.emitConnection('connected');
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
attempt = 0;
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
if (this.stopped || signal.aborted)
|
|
353
|
+
break;
|
|
354
|
+
attempt += 1;
|
|
355
|
+
this.connected = false;
|
|
356
|
+
this.emitConnection('reconnecting');
|
|
357
|
+
if (!this.config.reconnect.enabled || attempt > this.config.reconnect.maxRetries) {
|
|
358
|
+
this.ctx.logger.warn('[channel-telegram] reconnect budget exhausted');
|
|
359
|
+
this.emitConnection('disconnected');
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
const delay = Math.min(this.config.reconnect.baseDelayMs * 2 ** Math.min(attempt - 1, 8), this.config.reconnect.maxDelayMs);
|
|
363
|
+
this.ctx.logger.warn(`[channel-telegram] receive loop error; retry in ${delay}ms`, error);
|
|
364
|
+
await sleep(delay, signal);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
this.connected = false;
|
|
368
|
+
if (!this.stopped && !signal.aborted) {
|
|
369
|
+
this.emitConnection('disconnected');
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
emitAuth(state) {
|
|
373
|
+
if (!this.ctx)
|
|
374
|
+
return;
|
|
375
|
+
void this.ctx
|
|
376
|
+
.emit({
|
|
377
|
+
type: 'auth.changed',
|
|
378
|
+
channel: this.id,
|
|
379
|
+
accountId: this.config.accountId,
|
|
380
|
+
state,
|
|
381
|
+
})
|
|
382
|
+
.catch(() => undefined);
|
|
383
|
+
}
|
|
384
|
+
emitConnection(state) {
|
|
385
|
+
if (!this.ctx)
|
|
386
|
+
return;
|
|
387
|
+
void this.ctx
|
|
388
|
+
.emit({
|
|
389
|
+
type: 'connection.changed',
|
|
390
|
+
channel: this.id,
|
|
391
|
+
accountId: this.config.accountId,
|
|
392
|
+
state,
|
|
393
|
+
})
|
|
394
|
+
.catch(() => undefined);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function sleep(ms, signal) {
|
|
398
|
+
return new Promise((resolve) => {
|
|
399
|
+
if (signal?.aborted) {
|
|
400
|
+
resolve();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const timer = setTimeout(() => {
|
|
404
|
+
signal?.removeEventListener('abort', onAbort);
|
|
405
|
+
resolve();
|
|
406
|
+
}, ms);
|
|
407
|
+
const onAbort = () => {
|
|
408
|
+
clearTimeout(timer);
|
|
409
|
+
resolve();
|
|
410
|
+
};
|
|
411
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
function typingKey(target) {
|
|
415
|
+
return JSON.stringify([target.conversationId, target.threadId ?? null]);
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|