@goodandready/dsh-messenger-gateway 0.4.11 → 0.4.12
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/lib/client.js +16 -3
- package/lib/config.js +1 -0
- package/lib/gateway.js +46 -31
- package/lib/index.js +116 -72
- package/lib/stream.js +4 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -17,6 +17,15 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
const ROW_ID = 'dsh-messenger-gateway'
|
|
18
18
|
const ROW_CONFIG_KEY = PKG + '#' + ROW_ID
|
|
19
19
|
|
|
20
|
+
function timeoutSignal(ms) {
|
|
21
|
+
if (typeof AbortSignal?.timeout === 'function') {
|
|
22
|
+
return AbortSignal.timeout(ms)
|
|
23
|
+
}
|
|
24
|
+
const controller = new AbortController()
|
|
25
|
+
setTimeout(() => controller.abort(new Error('TimeoutError')), ms)
|
|
26
|
+
return controller.signal
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
const en = {
|
|
21
30
|
title: 'Messenger gateway',
|
|
22
31
|
description: 'Telegram bot: text, voice, photos, documents, and interactive asks.',
|
|
@@ -593,7 +602,7 @@ window.__ModuleLoader__.load({
|
|
|
593
602
|
|
|
594
603
|
const loadStatus = React.useCallback(async () => {
|
|
595
604
|
try {
|
|
596
|
-
const res = await fetch(`${ROUTE_PREFIX}/status`, { cache: 'no-store' })
|
|
605
|
+
const res = await fetch(`${ROUTE_PREFIX}/status`, { cache: 'no-store', signal: timeoutSignal(10000) })
|
|
597
606
|
const data = await res.json().catch(() => ({}))
|
|
598
607
|
if (res.ok && data.ok) {
|
|
599
608
|
setStatus(data)
|
|
@@ -605,7 +614,7 @@ window.__ModuleLoader__.load({
|
|
|
605
614
|
|
|
606
615
|
const loadPairing = React.useCallback(async () => {
|
|
607
616
|
try {
|
|
608
|
-
const res = await fetch(`${ROUTE_PREFIX}/pairing`, { credentials: 'same-origin', cache: 'no-store' })
|
|
617
|
+
const res = await fetch(`${ROUTE_PREFIX}/pairing`, { credentials: 'same-origin', cache: 'no-store', signal: timeoutSignal(10000) })
|
|
609
618
|
const data = await res.json().catch(() => ({}))
|
|
610
619
|
if (res.ok && data.ok) setPending(Array.isArray(data.pending) ? data.pending : [])
|
|
611
620
|
} catch (err) {
|
|
@@ -626,7 +635,7 @@ window.__ModuleLoader__.load({
|
|
|
626
635
|
const loadUpdateStatus = React.useCallback(async () => {
|
|
627
636
|
setUpdateState((s) => ({ ...s, checking: true, error: '' }))
|
|
628
637
|
try {
|
|
629
|
-
const res = await fetch(`${ROUTE_PREFIX}/update`, { cache: 'no-store' })
|
|
638
|
+
const res = await fetch(`${ROUTE_PREFIX}/update`, { cache: 'no-store', signal: timeoutSignal(15000) })
|
|
630
639
|
const data = await res.json().catch(() => ({}))
|
|
631
640
|
if (res.ok && data.ok) {
|
|
632
641
|
setUpdateState((s) => ({
|
|
@@ -655,6 +664,7 @@ window.__ModuleLoader__.load({
|
|
|
655
664
|
'Content-Type': 'application/json',
|
|
656
665
|
'x-dsh-plugin-update': '1',
|
|
657
666
|
},
|
|
667
|
+
signal: timeoutSignal(60000),
|
|
658
668
|
})
|
|
659
669
|
const data = await res.json().catch(() => ({}))
|
|
660
670
|
if (!res.ok || !data.ok) throw new Error(data.error || `HTTP ${res.status}`)
|
|
@@ -689,6 +699,7 @@ window.__ModuleLoader__.load({
|
|
|
689
699
|
credentials: 'same-origin',
|
|
690
700
|
headers: { 'Content-Type': 'application/json' },
|
|
691
701
|
body: JSON.stringify({ timeoutMs: 8000 }),
|
|
702
|
+
signal: timeoutSignal(15000),
|
|
692
703
|
})
|
|
693
704
|
const data = await res.json().catch(() => ({}))
|
|
694
705
|
if (!data.ok) throw new Error(data.error || `HTTP ${res.status}`)
|
|
@@ -1348,6 +1359,7 @@ window.__ModuleLoader__.load({
|
|
|
1348
1359
|
credentials: 'same-origin',
|
|
1349
1360
|
headers: { 'Content-Type': 'application/json' },
|
|
1350
1361
|
body: JSON.stringify({ code: row.code }),
|
|
1362
|
+
signal: timeoutSignal(15000),
|
|
1351
1363
|
})
|
|
1352
1364
|
const data = await res.json()
|
|
1353
1365
|
if (!res.ok || !data.ok) throw new Error(data.error || res.status)
|
|
@@ -1376,6 +1388,7 @@ window.__ModuleLoader__.load({
|
|
|
1376
1388
|
credentials: 'same-origin',
|
|
1377
1389
|
headers: { 'Content-Type': 'application/json' },
|
|
1378
1390
|
body: JSON.stringify({ code: row.code }),
|
|
1391
|
+
signal: timeoutSignal(15000),
|
|
1379
1392
|
})
|
|
1380
1393
|
const data = await res.json()
|
|
1381
1394
|
if (!res.ok || !data.ok) throw new Error(data.error || res.status)
|
package/lib/config.js
CHANGED
|
@@ -9,6 +9,7 @@ const HomeEntry = z.object({
|
|
|
9
9
|
export const PluginConfig = z.object({
|
|
10
10
|
enabled: z.boolean().volatile().default(true),
|
|
11
11
|
internalBaseURL: z.string().volatile().default('http://127.0.0.1:3080'),
|
|
12
|
+
defaultLocale: z.union([z.const('en'), z.const('zh')]).default('en').description('Default language for bot messages and notifications (en, zh)'),
|
|
12
13
|
telegram: z.object({
|
|
13
14
|
enabled: z.boolean().default(false),
|
|
14
15
|
botToken: z.string().role('secret').default(''),
|
package/lib/gateway.js
CHANGED
|
@@ -182,40 +182,55 @@ export class Gateway {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
185
|
+
handleHostEvent(session, event) {
|
|
186
|
+
if (!session || !event) return
|
|
187
|
+
if (this.config.telegram?.forumMirrorEnabled) {
|
|
188
|
+
if (event.type === 'turn/start' || event.type === 'session/create') {
|
|
189
|
+
this.mirrorSessionToForumTopic(session).catch?.((e) => this.logger?.debug?.('mirror error:', e?.message || e))
|
|
190
|
+
} else if (event.type === 'turn/end') {
|
|
191
|
+
this.relayTurnToForumMirror(session, event).catch?.((e) => this.logger?.debug?.('relay mirror error:', e?.message || e))
|
|
193
192
|
}
|
|
193
|
+
}
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
} else if (event.type === 'tool/call') {
|
|
210
|
-
collector.toolName = extractToolName(event.data) || collector.toolName
|
|
211
|
-
collector.onStream?.(collector.streamText || '', collector.toolName)
|
|
212
|
-
} else if (event.type === 'tool/result') {
|
|
213
|
-
collector.toolName = ''
|
|
214
|
-
collector.onStream?.(collector.streamText || '', '')
|
|
215
|
-
} else if (event.type === 'turn/end') {
|
|
216
|
-
collector.reason = event.data.reason
|
|
195
|
+
const collector = this.pending.get(session.id)
|
|
196
|
+
if (!collector) return
|
|
197
|
+
if (event.type === 'assistant/message') {
|
|
198
|
+
const msg = event.data?.message || event.data
|
|
199
|
+
const text = assistantText(msg)
|
|
200
|
+
if (text) collector.lastText = text
|
|
201
|
+
const extra = collectAssistantParts(msg)
|
|
202
|
+
for (const img of extra.images) collector.images.push(img)
|
|
203
|
+
} else if (event.type === 'assistant/chunk') {
|
|
204
|
+
const delta = extractTextDelta(event.data?.chunk || event.data)
|
|
205
|
+
if (delta) {
|
|
206
|
+
collector.streamText = (collector.streamText || '') + delta
|
|
207
|
+
collector.onStream?.(collector.streamText, collector.toolName)
|
|
217
208
|
}
|
|
218
|
-
})
|
|
209
|
+
} else if (event.type === 'tool/call') {
|
|
210
|
+
collector.toolName = extractToolName(event.data) || collector.toolName
|
|
211
|
+
collector.onStream?.(collector.streamText || '', collector.toolName)
|
|
212
|
+
} else if (event.type === 'tool/result') {
|
|
213
|
+
collector.toolName = ''
|
|
214
|
+
collector.onStream?.(collector.streamText || '', '')
|
|
215
|
+
} else if (event.type === 'turn/end') {
|
|
216
|
+
collector.reason = event.data?.reason || event.data
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async start() {
|
|
221
|
+
const onHost = (session, event) => this.handleHostEvent(session, event)
|
|
222
|
+
const unsubs = [
|
|
223
|
+
this.ctx.on('session/event', onHost),
|
|
224
|
+
this.ctx.on('turn/end', (session, data) => onHost(session, { type: 'turn/end', data })),
|
|
225
|
+
this.ctx.on('turn/start', (session, data) => onHost(session, { type: 'turn/start', data })),
|
|
226
|
+
this.ctx.on('assistant/message', (session, message) => onHost(session, { type: 'assistant/message', data: { message } })),
|
|
227
|
+
this.ctx.on('assistant/chunk', (session, chunk) => onHost(session, { type: 'assistant/chunk', data: { chunk } })),
|
|
228
|
+
]
|
|
229
|
+
this.disposeListener = () => {
|
|
230
|
+
for (const un of unsubs) {
|
|
231
|
+
if (typeof un === 'function') un()
|
|
232
|
+
}
|
|
233
|
+
}
|
|
219
234
|
const adapters = createAdapters({
|
|
220
235
|
config: this.config,
|
|
221
236
|
onMessage: (input) => this.handleMessage(input),
|
package/lib/index.js
CHANGED
|
@@ -149,7 +149,57 @@ export function apply(ctx, config) {
|
|
|
149
149
|
const turnStarts = new Map()
|
|
150
150
|
const getWebServer = () => ctx.get?.('webServer') || ctx.webServer
|
|
151
151
|
|
|
152
|
+
let webhookRouteDispose = null
|
|
153
|
+
let currentWebhookPath = ''
|
|
154
|
+
|
|
155
|
+
const webhookPath = () => {
|
|
156
|
+
const p = String(source().telegram?.webhookPath || '').trim()
|
|
157
|
+
return p || '/dsh-messenger-gateway/telegram/webhook'
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const syncWebhookRoute = () => {
|
|
161
|
+
const targetPath = webhookPath()
|
|
162
|
+
if (targetPath === currentWebhookPath && webhookRouteDispose) return
|
|
163
|
+
if (typeof webhookRouteDispose === 'function') {
|
|
164
|
+
try { webhookRouteDispose() } catch (e) { /* ignore */ }
|
|
165
|
+
webhookRouteDispose = null
|
|
166
|
+
}
|
|
167
|
+
currentWebhookPath = targetPath
|
|
168
|
+
const ws = getWebServer()
|
|
169
|
+
if (!ws?.register) return
|
|
170
|
+
webhookRouteDispose = ws.register({
|
|
171
|
+
kind: 'exact',
|
|
172
|
+
path: targetPath,
|
|
173
|
+
handler: async (req, res) => {
|
|
174
|
+
if (req.method !== 'POST') return writeJson(res, 405, { ok: false, error: 'POST only' })
|
|
175
|
+
const cfg = source().telegram || {}
|
|
176
|
+
if (cfg.transport !== 'webhook') return writeJson(res, 404, { ok: false, error: 'webhook transport disabled' })
|
|
177
|
+
const secret = String(cfg.webhookSecret || '').trim()
|
|
178
|
+
if (!secret) {
|
|
179
|
+
return writeJson(res, 403, { ok: false, error: 'webhook secret not configured' })
|
|
180
|
+
}
|
|
181
|
+
const hdr = String(req.headers['x-telegram-bot-api-secret-token'] || '')
|
|
182
|
+
if (!timingSafeCompare(hdr, secret)) {
|
|
183
|
+
return writeJson(res, 403, { ok: false, error: 'bad secret' })
|
|
184
|
+
}
|
|
185
|
+
const gw = getGw()
|
|
186
|
+
const adapter = gw?.getAdapter?.('telegram')
|
|
187
|
+
if (!adapter?.handleWebhookUpdate) return writeJson(res, 503, { ok: false, error: 'telegram adapter unavailable' })
|
|
188
|
+
const parsed = await readJsonSafe(req, res, 2_097_152)
|
|
189
|
+
if (!parsed.ok) return
|
|
190
|
+
const update = parsed.data
|
|
191
|
+
try {
|
|
192
|
+
await adapter.handleWebhookUpdate(update)
|
|
193
|
+
writeJson(res, 200, { ok: true })
|
|
194
|
+
} catch (err) {
|
|
195
|
+
writeJson(res, 500, { ok: false, error: err.message })
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
152
201
|
const sync = () => {
|
|
202
|
+
syncWebhookRoute()
|
|
153
203
|
if (gateway) { gateway.stop(); gateway = undefined }
|
|
154
204
|
const effective = source()
|
|
155
205
|
if (effective.enabled === false) return
|
|
@@ -292,51 +342,69 @@ export function apply(ctx, config) {
|
|
|
292
342
|
const gw = getGw()
|
|
293
343
|
if (gw) gw.syncTelegramCommands().catch((err) => ctx.logger?.debug?.(`sync telegram commands on skills change: ${err?.message || err}`))
|
|
294
344
|
}
|
|
295
|
-
const
|
|
296
|
-
|
|
345
|
+
const unbind1 = ctx.on('skills/change', onSkillsChange)
|
|
346
|
+
const unbind2 = ctx.on('skills/updated', onSkillsChange)
|
|
347
|
+
const unbind3 = ctx.on('skills/update', onSkillsChange)
|
|
348
|
+
return () => {
|
|
349
|
+
if (typeof unbind1 === 'function') unbind1()
|
|
350
|
+
if (typeof unbind2 === 'function') unbind2()
|
|
351
|
+
if (typeof unbind3 === 'function') unbind3()
|
|
352
|
+
}
|
|
297
353
|
}, 'dsh-messenger-gateway: dynamic skills sync')
|
|
298
354
|
|
|
299
355
|
// Notify → Telegram home bridge (non-msgw sessions only)
|
|
300
|
-
ctx.effect(() =>
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
356
|
+
ctx.effect(() => {
|
|
357
|
+
const handleNotify = (session, event) => {
|
|
358
|
+
if (!session || !event) return
|
|
359
|
+
const cfg = source().telegram?.notifyBridge
|
|
360
|
+
if (!cfg?.enabled) return
|
|
361
|
+
if (event.type === 'turn/start') {
|
|
362
|
+
const now = Date.now()
|
|
363
|
+
if (turnStarts.size > 50) {
|
|
364
|
+
for (const [sid, ts] of turnStarts.entries()) {
|
|
365
|
+
if (now - ts > 7_200_000) turnStarts.delete(sid)
|
|
366
|
+
}
|
|
308
367
|
}
|
|
368
|
+
turnStarts.set(String(session.id), now)
|
|
369
|
+
return
|
|
370
|
+
}
|
|
371
|
+
if (event.type !== 'turn/end') return
|
|
372
|
+
const prefixes = cfg.excludeSessionPrefixes || ['msgw-']
|
|
373
|
+
if (isExcludedSession(session.id, prefixes)) return
|
|
374
|
+
const reason = event.data?.reason
|
|
375
|
+
const kind = reason?.kind === 'completed' ? 'task_done' : 'error'
|
|
376
|
+
const events = new Set(cfg.events?.length ? cfg.events : ['task_done', 'error'])
|
|
377
|
+
if (!events.has(kind)) return
|
|
378
|
+
const gw = getGw()
|
|
379
|
+
if (!gw) return
|
|
380
|
+
const started = turnStarts.get(String(session.id))
|
|
381
|
+
turnStarts.delete(String(session.id))
|
|
382
|
+
const dur = started ? Math.round((Date.now() - started) / 1000) : null
|
|
383
|
+
const title = kind === 'task_done' ? 'Task completed' : 'Agent error'
|
|
384
|
+
const lines = [
|
|
385
|
+
`【${title}】`,
|
|
386
|
+
`session: ${session.id}`,
|
|
387
|
+
]
|
|
388
|
+
if (dur != null) lines.push(`duration: ${dur}s`)
|
|
389
|
+
if (reason?.kind === 'error') {
|
|
390
|
+
lines.push(`error: ${reason.error?.message || reason.error?.code || 'unknown'}`)
|
|
309
391
|
}
|
|
310
|
-
|
|
311
|
-
|
|
392
|
+
const homeName = cfg.home || 'default'
|
|
393
|
+
const home = gw.messenger.home?.() || null
|
|
394
|
+
if (home && gw.isMuted?.(home.chatId)) return
|
|
395
|
+
gw.messengerSend({ platform: 'telegram', home: homeName }, { text: lines.join('\n') })
|
|
396
|
+
.catch((e) => ctx.logger?.warn?.(`notify bridge: ${e.message}`))
|
|
312
397
|
}
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (!gw) return
|
|
322
|
-
const started = turnStarts.get(String(session.id))
|
|
323
|
-
turnStarts.delete(String(session.id))
|
|
324
|
-
const dur = started ? Math.round((Date.now() - started) / 1000) : null
|
|
325
|
-
const title = kind === 'task_done' ? 'Task completed' : 'Agent error'
|
|
326
|
-
const lines = [
|
|
327
|
-
`【${title}】`,
|
|
328
|
-
`session: ${session.id}`,
|
|
329
|
-
]
|
|
330
|
-
if (dur != null) lines.push(`duration: ${dur}s`)
|
|
331
|
-
if (reason?.kind === 'error') {
|
|
332
|
-
lines.push(`error: ${reason.error?.message || reason.error?.code || 'unknown'}`)
|
|
398
|
+
|
|
399
|
+
const un1 = ctx.on('session/event', handleNotify)
|
|
400
|
+
const un2 = ctx.on('turn/end', (session, data) => handleNotify(session, { type: 'turn/end', data }))
|
|
401
|
+
const un3 = ctx.on('turn/start', (session, data) => handleNotify(session, { type: 'turn/start', data }))
|
|
402
|
+
return () => {
|
|
403
|
+
if (typeof un1 === 'function') un1()
|
|
404
|
+
if (typeof un2 === 'function') un2()
|
|
405
|
+
if (typeof un3 === 'function') un3()
|
|
333
406
|
}
|
|
334
|
-
|
|
335
|
-
const home = gw.messenger.home?.() || null
|
|
336
|
-
if (home && gw.isMuted?.(home.chatId)) return
|
|
337
|
-
gw.messengerSend({ platform: 'telegram', home: homeName }, { text: lines.join('\n') })
|
|
338
|
-
.catch((e) => ctx.logger?.warn?.(`notify bridge: ${e.message}`))
|
|
339
|
-
}), 'dsh-messenger-gateway: notify bridge')
|
|
407
|
+
}, 'dsh-messenger-gateway: notify bridge')
|
|
340
408
|
|
|
341
409
|
ctx.effect(() => getWebServer().register({
|
|
342
410
|
kind: 'exact', path: '/dsh-messenger-gateway/status',
|
|
@@ -538,39 +606,12 @@ export function apply(ctx, config) {
|
|
|
538
606
|
},
|
|
539
607
|
}), 'dsh-messenger-gateway: pairing reject')
|
|
540
608
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
kind: 'exact', path: webhookPath(),
|
|
548
|
-
handler: async (req, res) => {
|
|
549
|
-
if (req.method !== 'POST') return writeJson(res, 405, { ok: false, error: 'POST only' })
|
|
550
|
-
const cfg = source().telegram || {}
|
|
551
|
-
if (cfg.transport !== 'webhook') return writeJson(res, 404, { ok: false, error: 'webhook transport disabled' })
|
|
552
|
-
const secret = String(cfg.webhookSecret || '').trim()
|
|
553
|
-
if (!secret) {
|
|
554
|
-
return writeJson(res, 403, { ok: false, error: 'webhook secret not configured' })
|
|
555
|
-
}
|
|
556
|
-
const hdr = String(req.headers['x-telegram-bot-api-secret-token'] || '')
|
|
557
|
-
if (!timingSafeCompare(hdr, secret)) {
|
|
558
|
-
return writeJson(res, 403, { ok: false, error: 'bad secret' })
|
|
559
|
-
}
|
|
560
|
-
const gw = getGw()
|
|
561
|
-
const adapter = gw?.getAdapter?.('telegram')
|
|
562
|
-
if (!adapter?.handleWebhookUpdate) return writeJson(res, 503, { ok: false, error: 'telegram adapter unavailable' })
|
|
563
|
-
const parsed = await readJsonSafe(req, res, 2_097_152)
|
|
564
|
-
if (!parsed.ok) return
|
|
565
|
-
const update = parsed.data
|
|
566
|
-
try {
|
|
567
|
-
await adapter.handleWebhookUpdate(update)
|
|
568
|
-
writeJson(res, 200, { ok: true })
|
|
569
|
-
} catch (err) {
|
|
570
|
-
writeJson(res, 500, { ok: false, error: err.message })
|
|
571
|
-
}
|
|
572
|
-
},
|
|
573
|
-
}), 'dsh-messenger-gateway: telegram webhook')
|
|
609
|
+
ctx.effect(() => () => {
|
|
610
|
+
if (typeof webhookRouteDispose === 'function') {
|
|
611
|
+
try { webhookRouteDispose() } catch (e) { /* ignore */ }
|
|
612
|
+
webhookRouteDispose = null
|
|
613
|
+
}
|
|
614
|
+
}, 'dsh-messenger-gateway: telegram webhook')
|
|
574
615
|
|
|
575
616
|
registerMessengerRoute(ctx, getGw, '/dsh-messenger-gateway/messenger/send', 'send', source)
|
|
576
617
|
registerMessengerRoute(ctx, getGw, '/dsh-messenger-gateway/messenger/progress', 'progress', source)
|
|
@@ -583,6 +624,9 @@ export function apply(ctx, config) {
|
|
|
583
624
|
endpoint: '/dsh-messenger-gateway/update',
|
|
584
625
|
}), 'dsh-messenger-gateway: plugin updater')
|
|
585
626
|
|
|
586
|
-
ctx.on('dispose', () => {
|
|
627
|
+
ctx.on('dispose', () => {
|
|
628
|
+
if (gateway) gateway.stop()
|
|
629
|
+
if (typeof webhookRouteDispose === 'function') webhookRouteDispose()
|
|
630
|
+
})
|
|
587
631
|
sync()
|
|
588
632
|
}
|
package/lib/stream.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/** Helpers for Telegram streaming edits + progress. */
|
|
2
2
|
|
|
3
3
|
export function extractTextDelta(chunk) {
|
|
4
|
+
if (typeof chunk === 'string') return chunk
|
|
4
5
|
if (!chunk || typeof chunk !== 'object') return ''
|
|
5
6
|
if (chunk.type === 'text-delta' && typeof chunk.text === 'string') return chunk.text
|
|
7
|
+
if (chunk.type === 'text' && typeof chunk.text === 'string') return chunk.text
|
|
8
|
+
if (!chunk.type && typeof chunk.text === 'string') return chunk.text
|
|
9
|
+
if (!chunk.type && typeof chunk.delta === 'string') return chunk.delta
|
|
6
10
|
return ''
|
|
7
11
|
}
|
|
8
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-messenger-gateway",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"description": "Telegram messenger bridge for DeepSeek Harness: sessions, steer, homes, inline asks, notify bridge, and optional TTS voice notes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|