@swarmclawai/swarmclaw 0.6.3 → 0.6.6
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 +5 -3
- package/package.json +5 -1
- package/src/app/api/chatrooms/[id]/chat/route.ts +41 -2
- package/src/app/api/chatrooms/[id]/route.ts +15 -1
- package/src/app/api/chatrooms/route.ts +15 -2
- package/src/app/api/schedules/[id]/run/route.ts +3 -0
- package/src/app/api/tasks/route.ts +24 -0
- package/src/app/api/wallets/[id]/approve/route.ts +62 -0
- package/src/app/api/wallets/[id]/balance-history/route.ts +18 -0
- package/src/app/api/wallets/[id]/route.ts +118 -0
- package/src/app/api/wallets/[id]/send/route.ts +118 -0
- package/src/app/api/wallets/[id]/transactions/route.ts +18 -0
- package/src/app/api/wallets/route.ts +74 -0
- package/src/app/globals.css +8 -0
- package/src/app/page.tsx +7 -3
- package/src/cli/index.js +15 -0
- package/src/cli/spec.js +14 -0
- package/src/components/agents/agent-avatar.tsx +15 -1
- package/src/components/agents/agent-card.tsx +1 -0
- package/src/components/agents/agent-chat-list.tsx +1 -1
- package/src/components/agents/agent-sheet.tsx +112 -26
- package/src/components/auth/access-key-gate.tsx +22 -11
- package/src/components/chat/chat-area.tsx +2 -2
- package/src/components/chat/chat-header.tsx +48 -19
- package/src/components/chat/chat-tool-toggles.tsx +1 -1
- package/src/components/chat/delegation-banner.test.ts +27 -0
- package/src/components/chat/delegation-banner.tsx +109 -23
- package/src/components/chat/message-bubble.tsx +14 -3
- package/src/components/chat/message-list.tsx +5 -4
- package/src/components/chat/streaming-bubble.tsx +3 -2
- package/src/components/chat/thinking-indicator.tsx +3 -2
- package/src/components/chat/tool-call-bubble.test.ts +28 -0
- package/src/components/chat/tool-call-bubble.tsx +13 -1
- package/src/components/chat/transfer-agent-picker.tsx +1 -1
- package/src/components/chatrooms/agent-hover-card.tsx +1 -1
- package/src/components/chatrooms/chatroom-input.tsx +7 -6
- package/src/components/chatrooms/chatroom-message.tsx +1 -1
- package/src/components/chatrooms/chatroom-sheet.tsx +1 -1
- package/src/components/chatrooms/chatroom-typing-bar.tsx +1 -1
- package/src/components/chatrooms/chatroom-view.tsx +1 -1
- package/src/components/connectors/connector-list.tsx +1 -1
- package/src/components/home/home-view.tsx +2 -1
- package/src/components/input/chat-input.tsx +5 -4
- package/src/components/knowledge/knowledge-list.tsx +1 -1
- package/src/components/knowledge/knowledge-sheet.tsx +1 -1
- package/src/components/layout/app-layout.tsx +23 -9
- package/src/components/logs/log-list.tsx +7 -7
- package/src/components/memory/memory-agent-list.tsx +1 -1
- package/src/components/memory/memory-browser.tsx +1 -0
- package/src/components/memory/memory-card.tsx +3 -2
- package/src/components/memory/memory-detail.tsx +3 -3
- package/src/components/memory/memory-sheet.tsx +2 -2
- package/src/components/projects/project-detail.tsx +4 -4
- package/src/components/secrets/secret-sheet.tsx +1 -1
- package/src/components/secrets/secrets-list.tsx +1 -1
- package/src/components/sessions/new-session-sheet.tsx +4 -3
- package/src/components/sessions/session-card.tsx +1 -1
- package/src/components/shared/agent-picker-list.tsx +1 -1
- package/src/components/shared/agent-switch-dialog.tsx +1 -1
- package/src/components/shared/settings/section-user-preferences.tsx +4 -4
- package/src/components/skills/skill-list.tsx +1 -1
- package/src/components/skills/skill-sheet.tsx +1 -1
- package/src/components/tasks/task-board.tsx +3 -3
- package/src/components/tasks/task-sheet.tsx +21 -1
- package/src/components/wallets/wallet-approval-dialog.tsx +99 -0
- package/src/components/wallets/wallet-panel.tsx +616 -0
- package/src/components/wallets/wallet-section.tsx +100 -0
- package/src/hooks/use-media-query.ts +30 -4
- package/src/lib/api-client.ts +6 -18
- package/src/lib/fetch-timeout.ts +17 -0
- package/src/lib/notification-sounds.ts +4 -4
- package/src/lib/safe-storage.ts +42 -0
- package/src/lib/server/agent-registry.ts +2 -2
- package/src/lib/server/chat-execution.ts +35 -3
- package/src/lib/server/chatroom-health.ts +60 -0
- package/src/lib/server/chatroom-helpers.test.ts +94 -0
- package/src/lib/server/chatroom-helpers.ts +64 -11
- package/src/lib/server/connectors/inbound-audio-transcription.test.ts +191 -0
- package/src/lib/server/connectors/inbound-audio-transcription.ts +261 -0
- package/src/lib/server/connectors/manager.ts +80 -2
- package/src/lib/server/connectors/whatsapp-text.test.ts +29 -0
- package/src/lib/server/connectors/whatsapp-text.ts +26 -0
- package/src/lib/server/connectors/whatsapp.ts +8 -5
- package/src/lib/server/orchestrator-lg.ts +12 -2
- package/src/lib/server/orchestrator.ts +6 -1
- package/src/lib/server/queue-followups.test.ts +224 -0
- package/src/lib/server/queue.ts +226 -24
- package/src/lib/server/scheduler.ts +3 -0
- package/src/lib/server/session-tools/chatroom.ts +11 -2
- package/src/lib/server/session-tools/context-mgmt.ts +2 -2
- package/src/lib/server/session-tools/index.ts +6 -2
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/shell.ts +1 -1
- package/src/lib/server/session-tools/wallet.ts +124 -0
- package/src/lib/server/session-tools/web-output.test.ts +29 -0
- package/src/lib/server/session-tools/web-output.ts +16 -0
- package/src/lib/server/session-tools/web.ts +7 -3
- package/src/lib/server/solana.ts +122 -0
- package/src/lib/server/storage.ts +38 -0
- package/src/lib/server/stream-agent-chat.ts +126 -63
- package/src/lib/server/task-mention.test.ts +41 -0
- package/src/lib/server/task-mention.ts +3 -2
- package/src/lib/tool-definitions.ts +1 -0
- package/src/lib/view-routes.ts +6 -1
- package/src/stores/use-app-store.ts +17 -11
- package/src/types/index.ts +60 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import removeMarkdown from 'remove-markdown'
|
|
2
|
+
|
|
3
|
+
export function stripMarkdownForPlainChat(raw: string): string {
|
|
4
|
+
const source = String(raw || '').replace(/\r\n?/g, '\n')
|
|
5
|
+
if (!source) return ''
|
|
6
|
+
|
|
7
|
+
let text = removeMarkdown(source, {
|
|
8
|
+
gfm: true,
|
|
9
|
+
useImgAltText: true,
|
|
10
|
+
replaceLinksWithURL: true,
|
|
11
|
+
separateLinksAndTexts: ': ',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
// Collapse duplicate "url: url" patterns when link label already equals URL.
|
|
15
|
+
text = text.replace(/(https?:\/\/[^\s]+): \1/g, '$1')
|
|
16
|
+
text = text.replace(/\n{3,}/g, '\n\n')
|
|
17
|
+
return text.trim()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert markdown-heavy model output into WhatsApp-friendly plain text.
|
|
22
|
+
* Uses a markdown parser package instead of ad-hoc regex-only stripping.
|
|
23
|
+
*/
|
|
24
|
+
export function formatTextForWhatsApp(raw: string): string {
|
|
25
|
+
return stripMarkdownForPlainChat(raw)
|
|
26
|
+
}
|
|
@@ -12,6 +12,7 @@ import type { Connector } from '@/types'
|
|
|
12
12
|
import type { PlatformConnector, ConnectorInstance, InboundMessage } from './types'
|
|
13
13
|
import { saveInboundMediaBuffer, mimeFromPath, isImageMime, isAudioMime } from './media'
|
|
14
14
|
import { isNoMessage } from './manager'
|
|
15
|
+
import { formatTextForWhatsApp } from './whatsapp-text'
|
|
15
16
|
|
|
16
17
|
import { DATA_DIR } from '../data-dir'
|
|
17
18
|
|
|
@@ -67,15 +68,17 @@ const whatsapp: PlatformConnector = {
|
|
|
67
68
|
hasCredentials: hasStoredCreds(authDir),
|
|
68
69
|
async sendMessage(channelId, text, options) {
|
|
69
70
|
if (!sock) throw new Error('WhatsApp connector is not connected')
|
|
71
|
+
const normalizedText = formatTextForWhatsApp(text || '')
|
|
72
|
+
const normalizedCaption = formatTextForWhatsApp(options?.caption || normalizedText)
|
|
70
73
|
// Local file path takes priority
|
|
71
74
|
if (options?.mediaPath) {
|
|
72
75
|
if (!fs.existsSync(options.mediaPath)) throw new Error(`File not found: ${options.mediaPath}`)
|
|
73
76
|
const buf = fs.readFileSync(options.mediaPath)
|
|
74
77
|
const mime = options.mimeType || mimeFromPath(options.mediaPath)
|
|
75
|
-
const caption =
|
|
78
|
+
const caption = normalizedCaption || undefined
|
|
76
79
|
const fName = options.fileName || path.basename(options.mediaPath)
|
|
77
80
|
let sent
|
|
78
|
-
if (isImageMime(mime)) {
|
|
81
|
+
if (isImageMime(mime) || mime.startsWith('video/')) {
|
|
79
82
|
try {
|
|
80
83
|
sent = await sock.sendMessage(channelId, { image: buf, caption, mimetype: mime })
|
|
81
84
|
} catch (err: unknown) {
|
|
@@ -94,7 +97,7 @@ const whatsapp: PlatformConnector = {
|
|
|
94
97
|
if (options?.imageUrl) {
|
|
95
98
|
const sent = await sock.sendMessage(channelId, {
|
|
96
99
|
image: { url: options.imageUrl },
|
|
97
|
-
caption:
|
|
100
|
+
caption: normalizedCaption || undefined,
|
|
98
101
|
})
|
|
99
102
|
if (sent?.key?.id) sentMessageIds.add(sent.key.id)
|
|
100
103
|
return { messageId: sent?.key?.id || undefined }
|
|
@@ -104,13 +107,13 @@ const whatsapp: PlatformConnector = {
|
|
|
104
107
|
document: { url: options.fileUrl },
|
|
105
108
|
fileName: options.fileName || 'attachment',
|
|
106
109
|
mimetype: options.mimeType || 'application/octet-stream',
|
|
107
|
-
caption:
|
|
110
|
+
caption: normalizedCaption || undefined,
|
|
108
111
|
})
|
|
109
112
|
if (sent?.key?.id) sentMessageIds.add(sent.key.id)
|
|
110
113
|
return { messageId: sent?.key?.id || undefined }
|
|
111
114
|
}
|
|
112
115
|
|
|
113
|
-
const payload =
|
|
116
|
+
const payload = normalizedText || normalizedCaption || ''
|
|
114
117
|
const chunks = payload.length <= 4096 ? [payload] : (payload.match(/[\s\S]{1,4000}/g) || [payload])
|
|
115
118
|
let lastMessageId: string | undefined
|
|
116
119
|
for (const chunk of chunks) {
|
|
@@ -124,7 +124,12 @@ async function executeSubTaskViaCli(agent: Agent, task: string, parentSessionId:
|
|
|
124
124
|
}
|
|
125
125
|
ss(sessions)
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
// Build system prompt with identity
|
|
128
|
+
const subPromptParts: string[] = []
|
|
129
|
+
subPromptParts.push(`## My Identity\nMy name is ${agent.name}.${agent.description ? ' ' + agent.description : ''} I should always refer to myself by this name.`)
|
|
130
|
+
if (agent.soul) subPromptParts.push(agent.soul)
|
|
131
|
+
if (agent.systemPrompt) subPromptParts.push(agent.systemPrompt)
|
|
132
|
+
const result = await callProvider(agent, subPromptParts.join('\n\n'), [{ role: 'user', text: task }])
|
|
128
133
|
|
|
129
134
|
const s2 = ls()
|
|
130
135
|
if (s2[childId]) {
|
|
@@ -348,9 +353,14 @@ export async function executeLangGraphOrchestrator(
|
|
|
348
353
|
apiKey: engine.apiKey,
|
|
349
354
|
apiEndpoint: engine.apiEndpoint,
|
|
350
355
|
})
|
|
351
|
-
// Build system message: [userPrompt] \n\n [soul] \n\n [systemPrompt] \n\n [orchestrator context]
|
|
356
|
+
// Build system message: [identity] \n\n [userPrompt] \n\n [soul] \n\n [systemPrompt] \n\n [orchestrator context]
|
|
352
357
|
const settings = loadSettings()
|
|
353
358
|
const promptParts: string[] = []
|
|
359
|
+
// Identity block
|
|
360
|
+
const orchIdentity = [`## My Identity`, `My name is ${orchestrator.name}.`]
|
|
361
|
+
if (orchestrator.description) orchIdentity.push(orchestrator.description)
|
|
362
|
+
orchIdentity.push('I should always refer to myself by this name.')
|
|
363
|
+
promptParts.push(orchIdentity.join(' '))
|
|
354
364
|
if (settings.userPrompt) promptParts.push(settings.userPrompt)
|
|
355
365
|
promptParts.push(buildCurrentDateTimePromptContext())
|
|
356
366
|
if (orchestrator.soul) promptParts.push(orchestrator.soul)
|
|
@@ -296,7 +296,12 @@ async function executeSubTask(
|
|
|
296
296
|
saveSessions(sessions)
|
|
297
297
|
|
|
298
298
|
const history = [{ role: 'user', text: task }]
|
|
299
|
-
|
|
299
|
+
// Build system prompt with identity so the agent knows who it is
|
|
300
|
+
const promptParts: string[] = []
|
|
301
|
+
promptParts.push(`## My Identity\nMy name is ${agent.name}.${agent.description ? ' ' + agent.description : ''} I should always refer to myself by this name.`)
|
|
302
|
+
if (agent.soul) promptParts.push(agent.soul)
|
|
303
|
+
if (agent.systemPrompt) promptParts.push(agent.systemPrompt)
|
|
304
|
+
const result = await callProvider(agent, promptParts.join('\n\n'), history)
|
|
300
305
|
|
|
301
306
|
childSession.messages.push({ role: 'user', text: task, time: Date.now() })
|
|
302
307
|
childSession.messages.push({ role: 'assistant', text: result, time: Date.now() })
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import type { BoardTask } from '@/types'
|
|
4
|
+
import { resolveTaskOriginConnectorFollowupTarget } from './queue'
|
|
5
|
+
|
|
6
|
+
function makeTask(partial?: Partial<BoardTask> & { createdInSessionId?: string | null }): BoardTask {
|
|
7
|
+
const now = Date.now()
|
|
8
|
+
return {
|
|
9
|
+
id: 'task-1',
|
|
10
|
+
title: 'Test task',
|
|
11
|
+
description: 'desc',
|
|
12
|
+
status: 'queued',
|
|
13
|
+
agentId: 'agent-a',
|
|
14
|
+
createdAt: now,
|
|
15
|
+
updatedAt: now,
|
|
16
|
+
...(partial || {}),
|
|
17
|
+
} as BoardTask
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type SessionFixtureMap = Record<string, {
|
|
21
|
+
messages: Array<{
|
|
22
|
+
role: string
|
|
23
|
+
text?: string
|
|
24
|
+
source?: {
|
|
25
|
+
connectorId?: string
|
|
26
|
+
channelId?: string
|
|
27
|
+
}
|
|
28
|
+
}>
|
|
29
|
+
}>
|
|
30
|
+
|
|
31
|
+
describe('resolveTaskOriginConnectorFollowupTarget', () => {
|
|
32
|
+
it('uses connector source channel from origin session and normalizes WhatsApp numbers', () => {
|
|
33
|
+
const task = makeTask({ createdInSessionId: 'session-1' })
|
|
34
|
+
const sessions = {
|
|
35
|
+
'session-1': {
|
|
36
|
+
messages: [
|
|
37
|
+
{ role: 'assistant', text: 'ok' },
|
|
38
|
+
{
|
|
39
|
+
role: 'user',
|
|
40
|
+
text: 'please update me',
|
|
41
|
+
source: {
|
|
42
|
+
connectorId: 'conn-wa',
|
|
43
|
+
channelId: '+44 7700 900123',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
const connectors = {
|
|
50
|
+
'conn-wa': {
|
|
51
|
+
id: 'conn-wa',
|
|
52
|
+
platform: 'whatsapp',
|
|
53
|
+
agentId: 'agent-a',
|
|
54
|
+
config: {},
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
const running = [
|
|
58
|
+
{
|
|
59
|
+
id: 'conn-wa',
|
|
60
|
+
platform: 'whatsapp',
|
|
61
|
+
agentId: 'agent-a',
|
|
62
|
+
supportsSend: true,
|
|
63
|
+
configuredTargets: [],
|
|
64
|
+
recentChannelId: '185200000000000@lid',
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
const target = resolveTaskOriginConnectorFollowupTarget({
|
|
69
|
+
task,
|
|
70
|
+
sessions: sessions as SessionFixtureMap,
|
|
71
|
+
connectors,
|
|
72
|
+
running,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
assert.deepEqual(target, {
|
|
76
|
+
connectorId: 'conn-wa',
|
|
77
|
+
channelId: '447700900123@s.whatsapp.net',
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('falls back to runtime recent channel when source channel is unavailable', () => {
|
|
82
|
+
const task = makeTask({ createdInSessionId: 'session-1' })
|
|
83
|
+
const sessions = {
|
|
84
|
+
'session-1': {
|
|
85
|
+
messages: [
|
|
86
|
+
{
|
|
87
|
+
role: 'user',
|
|
88
|
+
text: 'run this later',
|
|
89
|
+
source: {
|
|
90
|
+
connectorId: 'conn-telegram',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
const connectors = {
|
|
97
|
+
'conn-telegram': {
|
|
98
|
+
id: 'conn-telegram',
|
|
99
|
+
platform: 'telegram',
|
|
100
|
+
agentId: 'agent-a',
|
|
101
|
+
config: {},
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
const running = [
|
|
105
|
+
{
|
|
106
|
+
id: 'conn-telegram',
|
|
107
|
+
platform: 'telegram',
|
|
108
|
+
agentId: 'agent-a',
|
|
109
|
+
supportsSend: true,
|
|
110
|
+
configuredTargets: [],
|
|
111
|
+
recentChannelId: 'tg-chat-42',
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
const target = resolveTaskOriginConnectorFollowupTarget({
|
|
116
|
+
task,
|
|
117
|
+
sessions: sessions as SessionFixtureMap,
|
|
118
|
+
connectors,
|
|
119
|
+
running,
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
assert.deepEqual(target, {
|
|
123
|
+
connectorId: 'conn-telegram',
|
|
124
|
+
channelId: 'tg-chat-42',
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('returns null when the source connector belongs to a different agent', () => {
|
|
129
|
+
const task = makeTask({ createdInSessionId: 'session-1' })
|
|
130
|
+
const sessions = {
|
|
131
|
+
'session-1': {
|
|
132
|
+
messages: [
|
|
133
|
+
{
|
|
134
|
+
role: 'user',
|
|
135
|
+
text: 'do it',
|
|
136
|
+
source: {
|
|
137
|
+
connectorId: 'conn-wa',
|
|
138
|
+
channelId: '+15551230000',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
const connectors = {
|
|
145
|
+
'conn-wa': {
|
|
146
|
+
id: 'conn-wa',
|
|
147
|
+
platform: 'whatsapp',
|
|
148
|
+
agentId: 'different-agent',
|
|
149
|
+
config: {},
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
const running = [
|
|
153
|
+
{
|
|
154
|
+
id: 'conn-wa',
|
|
155
|
+
platform: 'whatsapp',
|
|
156
|
+
agentId: 'different-agent',
|
|
157
|
+
supportsSend: true,
|
|
158
|
+
configuredTargets: [],
|
|
159
|
+
recentChannelId: null,
|
|
160
|
+
},
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
const target = resolveTaskOriginConnectorFollowupTarget({
|
|
164
|
+
task,
|
|
165
|
+
sessions: sessions as SessionFixtureMap,
|
|
166
|
+
connectors,
|
|
167
|
+
running,
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
assert.equal(target, null)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('allows delegated tasks to follow up via the delegating agent connector', () => {
|
|
174
|
+
const task = makeTask({
|
|
175
|
+
agentId: 'worker-agent',
|
|
176
|
+
delegatedByAgentId: 'delegator-agent',
|
|
177
|
+
createdInSessionId: 'session-1',
|
|
178
|
+
})
|
|
179
|
+
const sessions = {
|
|
180
|
+
'session-1': {
|
|
181
|
+
messages: [
|
|
182
|
+
{
|
|
183
|
+
role: 'user',
|
|
184
|
+
text: 'run and update me here',
|
|
185
|
+
source: {
|
|
186
|
+
connectorId: 'conn-wa',
|
|
187
|
+
channelId: '+44 7700 900123',
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
const connectors = {
|
|
194
|
+
'conn-wa': {
|
|
195
|
+
id: 'conn-wa',
|
|
196
|
+
platform: 'whatsapp',
|
|
197
|
+
agentId: 'delegator-agent',
|
|
198
|
+
config: {},
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
const running = [
|
|
202
|
+
{
|
|
203
|
+
id: 'conn-wa',
|
|
204
|
+
platform: 'whatsapp',
|
|
205
|
+
agentId: 'delegator-agent',
|
|
206
|
+
supportsSend: true,
|
|
207
|
+
configuredTargets: [],
|
|
208
|
+
recentChannelId: null,
|
|
209
|
+
},
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
const target = resolveTaskOriginConnectorFollowupTarget({
|
|
213
|
+
task,
|
|
214
|
+
sessions: sessions as SessionFixtureMap,
|
|
215
|
+
connectors,
|
|
216
|
+
running,
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
assert.deepEqual(target, {
|
|
220
|
+
connectorId: 'conn-wa',
|
|
221
|
+
channelId: '447700900123@s.whatsapp.net',
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
})
|