opc-agent 4.1.0 → 4.1.2
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/.github/ISSUE_TEMPLATE/bug_report.md +20 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +14 -14
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -13
- package/CHANGELOG.md +48 -48
- package/CONTRIBUTING.md +36 -36
- package/README.zh-CN.md +497 -497
- package/USABILITY-ISSUES.md +73 -0
- package/dist/channels/web.js +8 -2
- package/dist/channels/wechat.js +6 -6
- package/dist/cli.js +200 -85
- package/dist/core/runtime.js +37 -15
- package/dist/deploy/index.js +56 -56
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +105 -10
- package/dist/memory/deepbrain.d.ts +1 -1
- package/dist/memory/deepbrain.js +95 -4
- package/dist/scheduler/cron-engine.js +3 -36
- package/dist/studio/server.js +30 -1
- package/dist/studio-ui/index.html +230 -10
- package/dist/ui/components.js +105 -105
- package/examples/README.md +22 -22
- package/examples/basic-agent.ts +90 -90
- package/examples/brain-integration.ts +71 -71
- package/examples/multi-channel.ts +74 -74
- package/fix-sidebar.mjs +188 -188
- package/install.ps1 +154 -154
- package/install.sh +164 -164
- package/package.json +1 -1
- package/scripts/install.ps1 +31 -31
- package/scripts/install.sh +40 -40
- package/serve-studio.js +13 -13
- package/serve-test.js +25 -25
- package/src/channels/dingtalk.ts +46 -46
- package/src/channels/email.ts +351 -351
- package/src/channels/feishu.ts +349 -349
- package/src/channels/googlechat.ts +42 -42
- package/src/channels/imessage.ts +31 -31
- package/src/channels/irc.ts +82 -82
- package/src/channels/line.ts +32 -32
- package/src/channels/matrix.ts +33 -33
- package/src/channels/mattermost.ts +57 -57
- package/src/channels/msteams.ts +32 -32
- package/src/channels/nostr.ts +32 -32
- package/src/channels/qq.ts +33 -33
- package/src/channels/signal.ts +32 -32
- package/src/channels/sms.ts +33 -33
- package/src/channels/telegram.ts +616 -616
- package/src/channels/twitch.ts +65 -65
- package/src/channels/voice-call.ts +100 -100
- package/src/channels/web.ts +8 -2
- package/src/channels/websocket.ts +399 -399
- package/src/channels/wechat.ts +329 -329
- package/src/channels/whatsapp.ts +32 -32
- package/src/cli/chat.ts +99 -99
- package/src/cli/setup.ts +314 -314
- package/src/cli.ts +195 -92
- package/src/core/agent.ts +476 -476
- package/src/core/api-server.ts +277 -277
- package/src/core/audio.ts +98 -98
- package/src/core/collaboration.ts +275 -275
- package/src/core/context-discovery.ts +85 -85
- package/src/core/context-refs.ts +140 -140
- package/src/core/gateway.ts +106 -106
- package/src/core/heartbeat.ts +51 -51
- package/src/core/hooks.ts +105 -105
- package/src/core/ide-bridge.ts +133 -133
- package/src/core/node-network.ts +86 -86
- package/src/core/profiles.ts +122 -122
- package/src/core/runtime.ts +25 -0
- package/src/core/scheduler.ts +187 -187
- package/src/core/session-manager.ts +137 -137
- package/src/core/subagent.ts +98 -98
- package/src/core/vision.ts +180 -180
- package/src/core/workflow-graph.ts +365 -365
- package/src/daemon.ts +96 -96
- package/src/deploy/index.ts +255 -255
- package/src/doctor.ts +98 -11
- package/src/eval/index.ts +211 -211
- package/src/eval/suites/basic.json +16 -16
- package/src/eval/suites/memory.json +12 -12
- package/src/eval/suites/safety.json +14 -14
- package/src/hub/brain-seed.ts +54 -54
- package/src/hub/client.ts +60 -60
- package/src/mcp/servers/calculator-mcp.ts +65 -65
- package/src/mcp/servers/crypto-mcp.ts +73 -73
- package/src/mcp/servers/database-mcp.ts +72 -72
- package/src/mcp/servers/datetime-mcp.ts +69 -69
- package/src/mcp/servers/filesystem.ts +66 -66
- package/src/mcp/servers/github-mcp.ts +58 -58
- package/src/mcp/servers/index.ts +63 -63
- package/src/mcp/servers/json-mcp.ts +102 -102
- package/src/mcp/servers/memory-mcp.ts +56 -56
- package/src/mcp/servers/regex-mcp.ts +53 -53
- package/src/mcp/servers/web-mcp.ts +49 -49
- package/src/memory/context-compressor.ts +189 -189
- package/src/memory/deepbrain.ts +99 -5
- package/src/memory/seed-loader.ts +212 -212
- package/src/memory/user-profiler.ts +215 -215
- package/src/plugins/content-filter.ts +23 -23
- package/src/plugins/logger.ts +18 -18
- package/src/plugins/rate-limiter.ts +38 -38
- package/src/protocols/a2a/client.ts +132 -132
- package/src/protocols/a2a/index.ts +8 -8
- package/src/protocols/a2a/server.ts +333 -333
- package/src/protocols/a2a/types.ts +88 -88
- package/src/protocols/a2a/utils.ts +50 -50
- package/src/protocols/agui/client.ts +83 -83
- package/src/protocols/agui/index.ts +4 -4
- package/src/protocols/agui/server.ts +218 -218
- package/src/protocols/agui/types.ts +153 -153
- package/src/protocols/index.ts +2 -2
- package/src/protocols/mcp/agent-tools.ts +134 -134
- package/src/protocols/mcp/index.ts +8 -8
- package/src/protocols/mcp/server.ts +262 -262
- package/src/protocols/mcp/types.ts +69 -69
- package/src/providers/index.ts +632 -632
- package/src/publish/index.ts +376 -376
- package/src/scheduler/cron-engine.ts +191 -191
- package/src/scheduler/index.ts +2 -2
- package/src/schema/oad.ts +217 -217
- package/src/security/approval.ts +131 -131
- package/src/security/approvals.ts +143 -143
- package/src/security/elevated.ts +105 -105
- package/src/security/guardrails.ts +248 -248
- package/src/security/index.ts +9 -9
- package/src/security/keys.ts +87 -87
- package/src/security/secrets.ts +129 -129
- package/src/skills/builtin/index.ts +408 -408
- package/src/skills/marketplace.ts +113 -113
- package/src/skills/types.ts +42 -42
- package/src/studio/server.ts +31 -1
- package/src/studio/templates-data.ts +178 -178
- package/src/studio-ui/index.html +230 -10
- package/src/telemetry/index.ts +324 -324
- package/src/tools/builtin/browser.ts +299 -299
- package/src/tools/builtin/datetime.ts +41 -41
- package/src/tools/builtin/file.ts +107 -107
- package/src/tools/builtin/home-assistant.ts +116 -116
- package/src/tools/builtin/rl-tools.ts +243 -243
- package/src/tools/builtin/shell.ts +43 -43
- package/src/tools/builtin/vision.ts +64 -64
- package/src/tools/builtin/web-search.ts +126 -126
- package/src/tools/builtin/web.ts +35 -35
- package/src/tools/document-processor.ts +213 -213
- package/src/tools/image-generator.ts +150 -150
- package/src/tools/integrations/calendar.ts +73 -73
- package/src/tools/integrations/code-exec.ts +39 -39
- package/src/tools/integrations/csv-analyzer.ts +92 -92
- package/src/tools/integrations/database.ts +44 -44
- package/src/tools/integrations/email-send.ts +76 -76
- package/src/tools/integrations/git-tool.ts +42 -42
- package/src/tools/integrations/github-tool.ts +76 -76
- package/src/tools/integrations/image-gen.ts +56 -56
- package/src/tools/integrations/index.ts +92 -92
- package/src/tools/integrations/jira.ts +83 -83
- package/src/tools/integrations/notion.ts +71 -71
- package/src/tools/integrations/npm-tool.ts +48 -48
- package/src/tools/integrations/pdf-reader.ts +58 -58
- package/src/tools/integrations/slack.ts +65 -65
- package/src/tools/integrations/summarizer.ts +49 -49
- package/src/tools/integrations/translator.ts +48 -48
- package/src/tools/integrations/trello.ts +60 -60
- package/src/tools/integrations/vector-search.ts +42 -42
- package/src/tools/integrations/web-scraper.ts +47 -47
- package/src/tools/integrations/web-search.ts +58 -58
- package/src/tools/integrations/webhook.ts +38 -38
- package/src/tools/mcp-client.ts +131 -131
- package/src/tools/web-scraper.ts +179 -179
- package/src/tools/web-search.ts +180 -180
- package/src/ui/components.ts +127 -127
- package/srv-out.txt +1 -1
- package/templates/ecommerce-assistant/README.md +45 -45
- package/templates/ecommerce-assistant/oad.yaml +47 -47
- package/templates/tech-support/README.md +43 -43
- package/templates/tech-support/oad.yaml +45 -45
- package/test-agent/Dockerfile +9 -9
- package/test-agent/README.md +50 -50
- package/test-agent/agent.yaml +23 -23
- package/test-agent/docker-compose.yml +11 -11
- package/test-agent/oad.yaml +31 -31
- package/test-agent/package-lock.json +1492 -1492
- package/test-agent/package.json +17 -17
- package/test-agent/src/index.ts +24 -24
- package/test-agent/src/skills/echo.ts +15 -15
- package/test-agent/tsconfig.json +24 -24
- package/test-full.js +43 -43
- package/test-sidebar.js +22 -22
- package/test-studio3.js +75 -75
- package/test-studio4.js +41 -41
- package/tests/a2a-protocol.test.ts +285 -285
- package/tests/agui-protocol.test.ts +246 -246
- package/tests/api-server.test.ts +148 -148
- package/tests/approvals.test.ts +89 -89
- package/tests/audio.test.ts +40 -40
- package/tests/brain-seed-extended.test.ts +490 -490
- package/tests/brain-seed.test.ts +239 -239
- package/tests/browser.test.ts +179 -179
- package/tests/channels/discord.test.ts +79 -79
- package/tests/channels/email.test.ts +148 -148
- package/tests/channels/feishu.test.ts +123 -123
- package/tests/channels/telegram.test.ts +129 -129
- package/tests/channels/websocket.test.ts +53 -53
- package/tests/channels/wechat.test.ts +170 -170
- package/tests/channels-extra.test.ts +45 -45
- package/tests/chat-cli.test.ts +160 -160
- package/tests/cli.test.ts +46 -46
- package/tests/context-compressor.test.ts +172 -172
- package/tests/context-refs.test.ts +121 -121
- package/tests/cron-engine.test.ts +101 -101
- package/tests/daemon.test.ts +135 -135
- package/tests/deepbrain-wire.test.ts +234 -234
- package/tests/deploy-and-dag.test.ts +196 -196
- package/tests/doctor.test.ts +38 -38
- package/tests/document-processor.test.ts +69 -69
- package/tests/e2e-nocode.test.ts +442 -442
- package/tests/elevated.test.ts +69 -69
- package/tests/eval.test.ts +173 -173
- package/tests/gateway.test.ts +63 -63
- package/tests/guardrails.test.ts +177 -177
- package/tests/home-assistant.test.ts +40 -40
- package/tests/hooks.test.ts +79 -79
- package/tests/ide-bridge.test.ts +38 -38
- package/tests/image-generator.test.ts +84 -84
- package/tests/init-role.test.ts +124 -124
- package/tests/integrations.test.ts +249 -249
- package/tests/mcp-client.test.ts +92 -92
- package/tests/mcp-server.test.ts +178 -178
- package/tests/mcp-servers.test.ts +260 -260
- package/tests/node-network.test.ts +74 -74
- package/tests/plugin-a2a-enhanced.test.ts +230 -230
- package/tests/profiles.test.ts +61 -61
- package/tests/publish.test.ts +231 -231
- package/tests/rl-tools.test.ts +93 -93
- package/tests/sandbox-manager.test.ts +46 -46
- package/tests/scheduler.test.ts +200 -200
- package/tests/secrets.test.ts +107 -107
- package/tests/security-enhanced.test.ts +233 -233
- package/tests/settings-api.test.ts +148 -148
- package/tests/setup.test.ts +73 -73
- package/tests/subagent.test.ts +193 -193
- package/tests/telegram-discord.test.ts +60 -60
- package/tests/telemetry.test.ts +186 -186
- package/tests/user-profiler.test.ts +169 -169
- package/tests/v090-features.test.ts +254 -254
- package/tests/vision.test.ts +61 -61
- package/tests/voice-call.test.ts +47 -47
- package/tests/voice-enhanced.test.ts +169 -169
- package/tests/voice-interaction.test.ts +38 -38
- package/tests/web-search.test.ts +155 -155
- package/tests/workflow-graph.test.ts +279 -279
- package/tutorial/customer-service-agent/README.md +612 -612
- package/tutorial/customer-service-agent/SOUL.md +26 -26
- package/tutorial/customer-service-agent/agent.yaml +63 -63
- package/tutorial/customer-service-agent/package.json +19 -19
- package/tutorial/customer-service-agent/src/index.ts +69 -69
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -27
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -22
- package/tutorial/customer-service-agent/tsconfig.json +14 -14
|
@@ -1,129 +1,129 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { TelegramChannel } from '../../src/channels/telegram';
|
|
3
|
-
|
|
4
|
-
describe('TelegramChannel', () => {
|
|
5
|
-
it('constructor sets token from config', () => {
|
|
6
|
-
const ch = new TelegramChannel({ token: 'test-token-123' });
|
|
7
|
-
expect((ch as any).token).toBe('test-token-123');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('constructor defaults to polling mode', () => {
|
|
11
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
12
|
-
expect((ch as any).mode).toBe('polling');
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('constructor reads token from env var', () => {
|
|
16
|
-
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
17
|
-
process.env.TELEGRAM_BOT_TOKEN = 'env-token';
|
|
18
|
-
const ch = new TelegramChannel({});
|
|
19
|
-
expect((ch as any).token).toBe('env-token');
|
|
20
|
-
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
21
|
-
else delete process.env.TELEGRAM_BOT_TOKEN;
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('constructor sets webhook mode', () => {
|
|
25
|
-
const ch = new TelegramChannel({ token: 'tok', mode: 'webhook', webhookUrl: 'https://x.com' });
|
|
26
|
-
expect((ch as any).mode).toBe('webhook');
|
|
27
|
-
expect((ch as any).webhookUrl).toBe('https://x.com');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('constructor defaults port to 3001', () => {
|
|
31
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
32
|
-
expect((ch as any).port).toBe(3001);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('constructor uses custom port', () => {
|
|
36
|
-
const ch = new TelegramChannel({ token: 'tok', port: 8080 });
|
|
37
|
-
expect((ch as any).port).toBe(8080);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('type is telegram', () => {
|
|
41
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
42
|
-
expect(ch.type).toBe('telegram');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('processUpdate extracts message text', async () => {
|
|
46
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
47
|
-
const messages: any[] = [];
|
|
48
|
-
(ch as any).handler = async (msg: any) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() }; };
|
|
49
|
-
// Mock sendMessage to avoid actual API call
|
|
50
|
-
(ch as any).sendMessage = vi.fn();
|
|
51
|
-
await (ch as any).processUpdate({
|
|
52
|
-
message: { message_id: 1, text: 'hello', date: 1000, chat: { id: 123 }, from: { id: 456, first_name: 'Test' } },
|
|
53
|
-
});
|
|
54
|
-
expect(messages).toHaveLength(1);
|
|
55
|
-
expect(messages[0].content).toBe('hello');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('processUpdate handles edited_message', async () => {
|
|
59
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
60
|
-
const messages: any[] = [];
|
|
61
|
-
(ch as any).handler = async (msg: any) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() }; };
|
|
62
|
-
(ch as any).sendMessage = vi.fn();
|
|
63
|
-
await (ch as any).processUpdate({
|
|
64
|
-
edited_message: { message_id: 2, text: 'edited', date: 1000, chat: { id: 123 }, from: { id: 456, first_name: 'Test' } },
|
|
65
|
-
});
|
|
66
|
-
expect(messages).toHaveLength(1);
|
|
67
|
-
expect(messages[0].content).toBe('edited');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('processUpdate ignores non-text updates', async () => {
|
|
71
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
72
|
-
const messages: any[] = [];
|
|
73
|
-
ch.onMessage(async (msg) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() } as any; });
|
|
74
|
-
(ch as any).sendMessage = vi.fn();
|
|
75
|
-
await (ch as any).processUpdate({
|
|
76
|
-
message: { message_id: 3, photo: [{}], date: 1000, chat: { id: 123 }, from: { id: 456 } },
|
|
77
|
-
});
|
|
78
|
-
expect(messages).toHaveLength(0);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('processUpdate ignores update without handler', async () => {
|
|
82
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
83
|
-
// Should not throw
|
|
84
|
-
await (ch as any).processUpdate({
|
|
85
|
-
message: { message_id: 4, text: 'hello', date: 1000, chat: { id: 123 }, from: { id: 456 } },
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('offset starts at 0', () => {
|
|
90
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
91
|
-
expect((ch as any).offset).toBe(0);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('missing token results in empty string', () => {
|
|
95
|
-
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
96
|
-
delete process.env.TELEGRAM_BOT_TOKEN;
|
|
97
|
-
const ch = new TelegramChannel({});
|
|
98
|
-
expect((ch as any).token).toBe('');
|
|
99
|
-
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('start with no token warns but does not throw', async () => {
|
|
103
|
-
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
104
|
-
delete process.env.TELEGRAM_BOT_TOKEN;
|
|
105
|
-
const ch = new TelegramChannel({});
|
|
106
|
-
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
107
|
-
await ch.start();
|
|
108
|
-
expect(spy).toHaveBeenCalled();
|
|
109
|
-
spy.mockRestore();
|
|
110
|
-
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('sendMessage is a function', () => {
|
|
114
|
-
const ch = new TelegramChannel({ token: 'tok' });
|
|
115
|
-
expect(typeof (ch as any).sendMessage === 'function' || typeof (ch as any).apiCall === 'function').toBe(true);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('long message chunking helper if available', () => {
|
|
119
|
-
// Test the concept - messages over 4096 chars should be split
|
|
120
|
-
const longText = 'a'.repeat(5000);
|
|
121
|
-
const chunks: string[] = [];
|
|
122
|
-
for (let i = 0; i < longText.length; i += 4096) {
|
|
123
|
-
chunks.push(longText.slice(i, i + 4096));
|
|
124
|
-
}
|
|
125
|
-
expect(chunks).toHaveLength(2);
|
|
126
|
-
expect(chunks[0].length).toBe(4096);
|
|
127
|
-
expect(chunks[1].length).toBe(904);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { TelegramChannel } from '../../src/channels/telegram';
|
|
3
|
+
|
|
4
|
+
describe('TelegramChannel', () => {
|
|
5
|
+
it('constructor sets token from config', () => {
|
|
6
|
+
const ch = new TelegramChannel({ token: 'test-token-123' });
|
|
7
|
+
expect((ch as any).token).toBe('test-token-123');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('constructor defaults to polling mode', () => {
|
|
11
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
12
|
+
expect((ch as any).mode).toBe('polling');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('constructor reads token from env var', () => {
|
|
16
|
+
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
17
|
+
process.env.TELEGRAM_BOT_TOKEN = 'env-token';
|
|
18
|
+
const ch = new TelegramChannel({});
|
|
19
|
+
expect((ch as any).token).toBe('env-token');
|
|
20
|
+
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
21
|
+
else delete process.env.TELEGRAM_BOT_TOKEN;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('constructor sets webhook mode', () => {
|
|
25
|
+
const ch = new TelegramChannel({ token: 'tok', mode: 'webhook', webhookUrl: 'https://x.com' });
|
|
26
|
+
expect((ch as any).mode).toBe('webhook');
|
|
27
|
+
expect((ch as any).webhookUrl).toBe('https://x.com');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('constructor defaults port to 3001', () => {
|
|
31
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
32
|
+
expect((ch as any).port).toBe(3001);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('constructor uses custom port', () => {
|
|
36
|
+
const ch = new TelegramChannel({ token: 'tok', port: 8080 });
|
|
37
|
+
expect((ch as any).port).toBe(8080);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('type is telegram', () => {
|
|
41
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
42
|
+
expect(ch.type).toBe('telegram');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('processUpdate extracts message text', async () => {
|
|
46
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
47
|
+
const messages: any[] = [];
|
|
48
|
+
(ch as any).handler = async (msg: any) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() }; };
|
|
49
|
+
// Mock sendMessage to avoid actual API call
|
|
50
|
+
(ch as any).sendMessage = vi.fn();
|
|
51
|
+
await (ch as any).processUpdate({
|
|
52
|
+
message: { message_id: 1, text: 'hello', date: 1000, chat: { id: 123 }, from: { id: 456, first_name: 'Test' } },
|
|
53
|
+
});
|
|
54
|
+
expect(messages).toHaveLength(1);
|
|
55
|
+
expect(messages[0].content).toBe('hello');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('processUpdate handles edited_message', async () => {
|
|
59
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
60
|
+
const messages: any[] = [];
|
|
61
|
+
(ch as any).handler = async (msg: any) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() }; };
|
|
62
|
+
(ch as any).sendMessage = vi.fn();
|
|
63
|
+
await (ch as any).processUpdate({
|
|
64
|
+
edited_message: { message_id: 2, text: 'edited', date: 1000, chat: { id: 123 }, from: { id: 456, first_name: 'Test' } },
|
|
65
|
+
});
|
|
66
|
+
expect(messages).toHaveLength(1);
|
|
67
|
+
expect(messages[0].content).toBe('edited');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('processUpdate ignores non-text updates', async () => {
|
|
71
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
72
|
+
const messages: any[] = [];
|
|
73
|
+
ch.onMessage(async (msg) => { messages.push(msg); return { id: 'r', role: 'assistant', content: 'ok', timestamp: Date.now() } as any; });
|
|
74
|
+
(ch as any).sendMessage = vi.fn();
|
|
75
|
+
await (ch as any).processUpdate({
|
|
76
|
+
message: { message_id: 3, photo: [{}], date: 1000, chat: { id: 123 }, from: { id: 456 } },
|
|
77
|
+
});
|
|
78
|
+
expect(messages).toHaveLength(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('processUpdate ignores update without handler', async () => {
|
|
82
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
83
|
+
// Should not throw
|
|
84
|
+
await (ch as any).processUpdate({
|
|
85
|
+
message: { message_id: 4, text: 'hello', date: 1000, chat: { id: 123 }, from: { id: 456 } },
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('offset starts at 0', () => {
|
|
90
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
91
|
+
expect((ch as any).offset).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('missing token results in empty string', () => {
|
|
95
|
+
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
96
|
+
delete process.env.TELEGRAM_BOT_TOKEN;
|
|
97
|
+
const ch = new TelegramChannel({});
|
|
98
|
+
expect((ch as any).token).toBe('');
|
|
99
|
+
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('start with no token warns but does not throw', async () => {
|
|
103
|
+
const orig = process.env.TELEGRAM_BOT_TOKEN;
|
|
104
|
+
delete process.env.TELEGRAM_BOT_TOKEN;
|
|
105
|
+
const ch = new TelegramChannel({});
|
|
106
|
+
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
107
|
+
await ch.start();
|
|
108
|
+
expect(spy).toHaveBeenCalled();
|
|
109
|
+
spy.mockRestore();
|
|
110
|
+
if (orig) process.env.TELEGRAM_BOT_TOKEN = orig;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('sendMessage is a function', () => {
|
|
114
|
+
const ch = new TelegramChannel({ token: 'tok' });
|
|
115
|
+
expect(typeof (ch as any).sendMessage === 'function' || typeof (ch as any).apiCall === 'function').toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('long message chunking helper if available', () => {
|
|
119
|
+
// Test the concept - messages over 4096 chars should be split
|
|
120
|
+
const longText = 'a'.repeat(5000);
|
|
121
|
+
const chunks: string[] = [];
|
|
122
|
+
for (let i = 0; i < longText.length; i += 4096) {
|
|
123
|
+
chunks.push(longText.slice(i, i + 4096));
|
|
124
|
+
}
|
|
125
|
+
expect(chunks).toHaveLength(2);
|
|
126
|
+
expect(chunks[0].length).toBe(4096);
|
|
127
|
+
expect(chunks[1].length).toBe(904);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { WebSocketChannel } from '../../src/channels/websocket';
|
|
3
|
-
|
|
4
|
-
// We can't easily test WebSocket server without starting it,
|
|
5
|
-
// but we can test the room management and config logic.
|
|
6
|
-
|
|
7
|
-
describe('WebSocketChannel', () => {
|
|
8
|
-
describe('constructor', () => {
|
|
9
|
-
it('should accept port number', () => {
|
|
10
|
-
const channel = new WebSocketChannel(4000);
|
|
11
|
-
expect(channel.type).toBe('websocket');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('should accept config object', () => {
|
|
15
|
-
const channel = new WebSocketChannel({
|
|
16
|
-
port: 4000,
|
|
17
|
-
heartbeatInterval: 15000,
|
|
18
|
-
authTokens: ['secret'],
|
|
19
|
-
maxClientsPerRoom: 50,
|
|
20
|
-
});
|
|
21
|
-
expect(channel.type).toBe('websocket');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should use defaults', () => {
|
|
25
|
-
const channel = new WebSocketChannel();
|
|
26
|
-
expect(channel.type).toBe('websocket');
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('getStats', () => {
|
|
31
|
-
it('should return empty stats initially', () => {
|
|
32
|
-
const channel = new WebSocketChannel(4001);
|
|
33
|
-
const stats = channel.getStats();
|
|
34
|
-
expect(stats.clients).toBe(0);
|
|
35
|
-
expect(stats.rooms).toBe(0);
|
|
36
|
-
expect(stats.roomDetails).toEqual({});
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe('getRooms', () => {
|
|
41
|
-
it('should return empty array initially', () => {
|
|
42
|
-
const channel = new WebSocketChannel(4002);
|
|
43
|
-
expect(channel.getRooms()).toEqual([]);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('getRoomMembers', () => {
|
|
48
|
-
it('should return empty for non-existent room', () => {
|
|
49
|
-
const channel = new WebSocketChannel(4003);
|
|
50
|
-
expect(channel.getRoomMembers('nonexistent')).toEqual([]);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { WebSocketChannel } from '../../src/channels/websocket';
|
|
3
|
+
|
|
4
|
+
// We can't easily test WebSocket server without starting it,
|
|
5
|
+
// but we can test the room management and config logic.
|
|
6
|
+
|
|
7
|
+
describe('WebSocketChannel', () => {
|
|
8
|
+
describe('constructor', () => {
|
|
9
|
+
it('should accept port number', () => {
|
|
10
|
+
const channel = new WebSocketChannel(4000);
|
|
11
|
+
expect(channel.type).toBe('websocket');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should accept config object', () => {
|
|
15
|
+
const channel = new WebSocketChannel({
|
|
16
|
+
port: 4000,
|
|
17
|
+
heartbeatInterval: 15000,
|
|
18
|
+
authTokens: ['secret'],
|
|
19
|
+
maxClientsPerRoom: 50,
|
|
20
|
+
});
|
|
21
|
+
expect(channel.type).toBe('websocket');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should use defaults', () => {
|
|
25
|
+
const channel = new WebSocketChannel();
|
|
26
|
+
expect(channel.type).toBe('websocket');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('getStats', () => {
|
|
31
|
+
it('should return empty stats initially', () => {
|
|
32
|
+
const channel = new WebSocketChannel(4001);
|
|
33
|
+
const stats = channel.getStats();
|
|
34
|
+
expect(stats.clients).toBe(0);
|
|
35
|
+
expect(stats.rooms).toBe(0);
|
|
36
|
+
expect(stats.roomDetails).toEqual({});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('getRooms', () => {
|
|
41
|
+
it('should return empty array initially', () => {
|
|
42
|
+
const channel = new WebSocketChannel(4002);
|
|
43
|
+
expect(channel.getRooms()).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('getRoomMembers', () => {
|
|
48
|
+
it('should return empty for non-existent room', () => {
|
|
49
|
+
const channel = new WebSocketChannel(4003);
|
|
50
|
+
expect(channel.getRoomMembers('nonexistent')).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|