visionclaw 0.1.193 → 0.1.194-dev.feat-backup-progress-reporting.1
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/dist/agent/backup-uploader.d.ts +44 -0
- package/dist/agent/backup-uploader.d.ts.map +1 -0
- package/dist/agent/backup-uploader.js +83 -0
- package/dist/agent/backup-uploader.js.map +1 -0
- package/dist/agent/backup.d.ts +7 -1
- package/dist/agent/backup.d.ts.map +1 -1
- package/dist/agent/backup.js +337 -52
- package/dist/agent/backup.js.map +1 -1
- package/dist/agent/command-handlers.d.ts +2 -0
- package/dist/agent/command-handlers.d.ts.map +1 -1
- package/dist/agent/command-handlers.js +29 -3
- package/dist/agent/command-handlers.js.map +1 -1
- package/dist/agent/context.d.ts +2 -0
- package/dist/agent/context.d.ts.map +1 -1
- package/dist/agent/context.js +11 -1
- package/dist/agent/context.js.map +1 -1
- package/dist/agent/data-collector.d.ts.map +1 -1
- package/dist/agent/data-collector.js +23 -38
- package/dist/agent/data-collector.js.map +1 -1
- package/dist/agent/loop.d.ts +3 -0
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +48 -0
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/message-format.d.ts.map +1 -1
- package/dist/agent/message-format.js +3 -0
- package/dist/agent/message-format.js.map +1 -1
- package/dist/agent/status.d.ts.map +1 -1
- package/dist/agent/status.js +2 -1
- package/dist/agent/status.js.map +1 -1
- package/dist/backup.d.ts +4 -1
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js +86 -3
- package/dist/backup.js.map +1 -1
- package/dist/calendar/google-calendar.d.ts +2 -0
- package/dist/calendar/google-calendar.d.ts.map +1 -1
- package/dist/calendar/google-calendar.js +3 -0
- package/dist/calendar/google-calendar.js.map +1 -1
- package/dist/channels/interface.d.ts +9 -0
- package/dist/channels/interface.d.ts.map +1 -1
- package/dist/channels/manager.d.ts +7 -1
- package/dist/channels/manager.d.ts.map +1 -1
- package/dist/channels/manager.js +12 -0
- package/dist/channels/manager.js.map +1 -1
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +5 -0
- package/dist/channels/telegram.js.map +1 -1
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +42 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -1
- package/dist/drive/google-drive.d.ts +1 -0
- package/dist/drive/google-drive.d.ts.map +1 -1
- package/dist/drive/google-drive.js +5 -0
- package/dist/drive/google-drive.js.map +1 -1
- package/dist/i18n/messages.d.ts +4 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/messages.js +7 -2
- package/dist/i18n/messages.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/obs/server.d.ts +7 -0
- package/dist/obs/server.d.ts.map +1 -1
- package/dist/obs/server.js +22 -0
- package/dist/obs/server.js.map +1 -1
- package/dist/onboarding/bot-profile.d.ts.map +1 -1
- package/dist/onboarding/bot-profile.js +1 -0
- package/dist/onboarding/bot-profile.js.map +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +5 -0
- package/dist/onboarding/index.js.map +1 -1
- package/dist/onboarding/prepare-mac.d.ts +1 -0
- package/dist/onboarding/prepare-mac.d.ts.map +1 -1
- package/dist/onboarding/prepare-mac.js +32 -15
- package/dist/onboarding/prepare-mac.js.map +1 -1
- package/dist/onboarding/setup-shared.d.ts.map +1 -1
- package/dist/onboarding/setup-shared.js +6 -0
- package/dist/onboarding/setup-shared.js.map +1 -1
- package/dist/onboarding/setup-steps.d.ts.map +1 -1
- package/dist/onboarding/setup-steps.js +8 -0
- package/dist/onboarding/setup-steps.js.map +1 -1
- package/dist/realtime/agent-bridge.d.ts +7 -0
- package/dist/realtime/agent-bridge.d.ts.map +1 -0
- package/dist/realtime/agent-bridge.js +31 -0
- package/dist/realtime/agent-bridge.js.map +1 -0
- package/dist/realtime/assets/index.html +1058 -0
- package/dist/realtime/assets/samples/alloy.mp3 +0 -0
- package/dist/realtime/assets/samples/ash.mp3 +0 -0
- package/dist/realtime/assets/samples/ballad.mp3 +0 -0
- package/dist/realtime/assets/samples/cedar.mp3 +0 -0
- package/dist/realtime/assets/samples/coral.mp3 +0 -0
- package/dist/realtime/assets/samples/echo.mp3 +0 -0
- package/dist/realtime/assets/samples/marin.mp3 +0 -0
- package/dist/realtime/assets/samples/sage.mp3 +0 -0
- package/dist/realtime/assets/samples/shimmer.mp3 +0 -0
- package/dist/realtime/assets/samples/verse.mp3 +0 -0
- package/dist/realtime/context.d.ts +14 -0
- package/dist/realtime/context.d.ts.map +1 -0
- package/dist/realtime/context.js +153 -0
- package/dist/realtime/context.js.map +1 -0
- package/dist/realtime/http-helpers.d.ts +5 -0
- package/dist/realtime/http-helpers.d.ts.map +1 -0
- package/dist/realtime/http-helpers.js +29 -0
- package/dist/realtime/http-helpers.js.map +1 -0
- package/dist/realtime/index.d.ts +62 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +94 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/server.d.ts +6 -0
- package/dist/realtime/server.d.ts.map +1 -0
- package/dist/realtime/server.js +476 -0
- package/dist/realtime/server.js.map +1 -0
- package/dist/realtime/telegram-auth.d.ts +2 -0
- package/dist/realtime/telegram-auth.d.ts.map +1 -0
- package/dist/realtime/telegram-auth.js +24 -0
- package/dist/realtime/telegram-auth.js.map +1 -0
- package/dist/realtime/tools.d.ts +829 -0
- package/dist/realtime/tools.d.ts.map +1 -0
- package/dist/realtime/tools.js +630 -0
- package/dist/realtime/tools.js.map +1 -0
- package/dist/realtime/types.d.ts +62 -0
- package/dist/realtime/types.d.ts.map +1 -0
- package/dist/realtime/types.js +3 -0
- package/dist/realtime/types.js.map +1 -0
- package/dist/realtime/voice-summarizer.d.ts +4 -0
- package/dist/realtime/voice-summarizer.d.ts.map +1 -0
- package/dist/realtime/voice-summarizer.js +129 -0
- package/dist/realtime/voice-summarizer.js.map +1 -0
- package/dist/restore.d.ts +5 -0
- package/dist/restore.d.ts.map +1 -1
- package/dist/restore.js +132 -16
- package/dist/restore.js.map +1 -1
- package/dist/tools/email.d.ts +1 -1
- package/dist/tools/memory.d.ts +13 -0
- package/dist/tools/memory.d.ts.map +1 -1
- package/dist/tools/memory.js +43 -43
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/stock-data.d.ts +16 -0
- package/dist/tools/stock-data.d.ts.map +1 -1
- package/dist/tools/stock-data.js +36 -38
- package/dist/tools/stock-data.js.map +1 -1
- package/dist/tools/web-fetch.d.ts +4 -0
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +95 -23
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tos-storage.d.ts +45 -0
- package/dist/tos-storage.d.ts.map +1 -0
- package/dist/tos-storage.js +134 -0
- package/dist/tos-storage.js.map +1 -0
- package/dist-agent/bundle.cjs +170934 -167547
- package/package.json +3 -2
- package/dist/agent/applied-credential-signature.d.ts +0 -53
- package/dist/agent/applied-credential-signature.d.ts.map +0 -1
- package/dist/agent/applied-credential-signature.js +0 -137
- package/dist/agent/applied-credential-signature.js.map +0 -1
- package/dist/agent/engines/claude/cli-resolver.d.ts +0 -16
- package/dist/agent/engines/claude/cli-resolver.d.ts.map +0 -1
- package/dist/agent/engines/claude/cli-resolver.js +0 -83
- package/dist/agent/engines/claude/cli-resolver.js.map +0 -1
- package/dist/agent/engines/claude/session-browser-policy.d.ts +0 -9
- package/dist/agent/engines/claude/session-browser-policy.d.ts.map +0 -1
- package/dist/agent/engines/claude/session-browser-policy.js +0 -49
- package/dist/agent/engines/claude/session-browser-policy.js.map +0 -1
- package/dist/agent/engines/claude/session.d.ts +0 -291
- package/dist/agent/engines/claude/session.d.ts.map +0 -1
- package/dist/agent/engines/claude/session.js +0 -1177
- package/dist/agent/engines/claude/session.js.map +0 -1
- package/dist/agent/engines/client-factory.d.ts +0 -63
- package/dist/agent/engines/client-factory.d.ts.map +0 -1
- package/dist/agent/engines/client-factory.js +0 -382
- package/dist/agent/engines/client-factory.js.map +0 -1
- package/dist/agent/engines/engine.d.ts +0 -8
- package/dist/agent/engines/engine.d.ts.map +0 -1
- package/dist/agent/engines/engine.js +0 -15
- package/dist/agent/engines/engine.js.map +0 -1
- package/dist/agent/engines/openai/file-session.d.ts +0 -49
- package/dist/agent/engines/openai/file-session.d.ts.map +0 -1
- package/dist/agent/engines/openai/file-session.js +0 -108
- package/dist/agent/engines/openai/file-session.js.map +0 -1
- package/dist/agent/engines/openai/file-tools.d.ts +0 -35
- package/dist/agent/engines/openai/file-tools.d.ts.map +0 -1
- package/dist/agent/engines/openai/file-tools.js +0 -194
- package/dist/agent/engines/openai/file-tools.js.map +0 -1
- package/dist/agent/engines/openai/session.d.ts +0 -190
- package/dist/agent/engines/openai/session.d.ts.map +0 -1
- package/dist/agent/engines/openai/session.js +0 -1066
- package/dist/agent/engines/openai/session.js.map +0 -1
- package/dist/agent/engines/openai/tools.d.ts +0 -13
- package/dist/agent/engines/openai/tools.d.ts.map +0 -1
- package/dist/agent/engines/openai/tools.js +0 -248
- package/dist/agent/engines/openai/tools.js.map +0 -1
- package/dist/agent/engines/session-types.d.ts +0 -146
- package/dist/agent/engines/session-types.d.ts.map +0 -1
- package/dist/agent/engines/session-types.js +0 -2
- package/dist/agent/engines/session-types.js.map +0 -1
- package/dist/agent/engines/system-prompt-log.d.ts +0 -9
- package/dist/agent/engines/system-prompt-log.d.ts.map +0 -1
- package/dist/agent/engines/system-prompt-log.js +0 -46
- package/dist/agent/engines/system-prompt-log.js.map +0 -1
- package/dist/agent/transcript/transcript-backfill.d.ts +0 -54
- package/dist/agent/transcript/transcript-backfill.d.ts.map +0 -1
- package/dist/agent/transcript/transcript-backfill.js +0 -604
- package/dist/agent/transcript/transcript-backfill.js.map +0 -1
- package/dist/agent/transcript/transcript-indexer.d.ts +0 -273
- package/dist/agent/transcript/transcript-indexer.d.ts.map +0 -1
- package/dist/agent/transcript/transcript-indexer.js +0 -1217
- package/dist/agent/transcript/transcript-indexer.js.map +0 -1
- package/dist/agent/transcript/transcript-memory-migrations.d.ts +0 -25
- package/dist/agent/transcript/transcript-memory-migrations.d.ts.map +0 -1
- package/dist/agent/transcript/transcript-memory-migrations.js +0 -87
- package/dist/agent/transcript/transcript-memory-migrations.js.map +0 -1
- package/dist/agent/transcript-memory-migrations.d.ts +0 -25
- package/dist/agent/transcript-memory-migrations.d.ts.map +0 -1
- package/dist/agent/transcript-memory-migrations.js +0 -87
- package/dist/agent/transcript-memory-migrations.js.map +0 -1
- package/dist/agent/tunnel-credential-handler.d.ts +0 -90
- package/dist/agent/tunnel-credential-handler.d.ts.map +0 -1
- package/dist/agent/tunnel-credential-handler.js +0 -162
- package/dist/agent/tunnel-credential-handler.js.map +0 -1
- package/dist/agent/usage/usage-backfill-handler.d.ts +0 -18
- package/dist/agent/usage/usage-backfill-handler.d.ts.map +0 -1
- package/dist/agent/usage/usage-backfill-handler.js +0 -69
- package/dist/agent/usage/usage-backfill-handler.js.map +0 -1
- package/dist/agent/usage/usage-gate.d.ts +0 -25
- package/dist/agent/usage/usage-gate.d.ts.map +0 -1
- package/dist/agent/usage/usage-gate.js +0 -83
- package/dist/agent/usage/usage-gate.js.map +0 -1
- package/dist/agent/usage/usage-handler.d.ts +0 -7
- package/dist/agent/usage/usage-handler.d.ts.map +0 -1
- package/dist/agent/usage/usage-handler.js +0 -28
- package/dist/agent/usage/usage-handler.js.map +0 -1
- package/dist/agent/usage/usage-report-builder.d.ts +0 -26
- package/dist/agent/usage/usage-report-builder.d.ts.map +0 -1
- package/dist/agent/usage/usage-report-builder.js +0 -80
- package/dist/agent/usage/usage-report-builder.js.map +0 -1
- package/dist/agent/usage/usage-report-queue.d.ts +0 -26
- package/dist/agent/usage/usage-report-queue.d.ts.map +0 -1
- package/dist/agent/usage/usage-report-queue.js +0 -199
- package/dist/agent/usage/usage-report-queue.js.map +0 -1
- package/dist/agent/usage/usage-report-types.d.ts +0 -41
- package/dist/agent/usage/usage-report-types.d.ts.map +0 -1
- package/dist/agent/usage/usage-report-types.js +0 -2
- package/dist/agent/usage/usage-report-types.js.map +0 -1
- package/dist/agent/usage/usage-reporter.d.ts +0 -31
- package/dist/agent/usage/usage-reporter.d.ts.map +0 -1
- package/dist/agent/usage/usage-reporter.js +0 -102
- package/dist/agent/usage/usage-reporter.js.map +0 -1
- package/dist/agent/usage-backfill-handler.d.ts +0 -18
- package/dist/agent/usage-backfill-handler.d.ts.map +0 -1
- package/dist/agent/usage-backfill-handler.js +0 -69
- package/dist/agent/usage-backfill-handler.js.map +0 -1
- package/dist/agent/usage-gate.d.ts +0 -25
- package/dist/agent/usage-gate.d.ts.map +0 -1
- package/dist/agent/usage-gate.js +0 -83
- package/dist/agent/usage-gate.js.map +0 -1
- package/dist/agent/usage-report-builder.d.ts +0 -26
- package/dist/agent/usage-report-builder.d.ts.map +0 -1
- package/dist/agent/usage-report-builder.js +0 -80
- package/dist/agent/usage-report-builder.js.map +0 -1
- package/dist/agent/usage-report-queue.d.ts +0 -26
- package/dist/agent/usage-report-queue.d.ts.map +0 -1
- package/dist/agent/usage-report-queue.js +0 -199
- package/dist/agent/usage-report-queue.js.map +0 -1
- package/dist/agent/usage-report-types.d.ts +0 -41
- package/dist/agent/usage-report-types.d.ts.map +0 -1
- package/dist/agent/usage-report-types.js +0 -2
- package/dist/agent/usage-report-types.js.map +0 -1
- package/dist/agent/usage-reporter.d.ts +0 -31
- package/dist/agent/usage-reporter.d.ts.map +0 -1
- package/dist/agent/usage-reporter.js +0 -102
- package/dist/agent/usage-reporter.js.map +0 -1
- package/dist/agent/wake-cycle-tool-tracker.d.ts +0 -39
- package/dist/agent/wake-cycle-tool-tracker.d.ts.map +0 -1
- package/dist/agent/wake-cycle-tool-tracker.js +0 -72
- package/dist/agent/wake-cycle-tool-tracker.js.map +0 -1
- package/dist/billing/payg-handler.d.ts +0 -29
- package/dist/billing/payg-handler.d.ts.map +0 -1
- package/dist/billing/payg-handler.js +0 -92
- package/dist/billing/payg-handler.js.map +0 -1
- package/dist/billing/payment-handler.d.ts +0 -24
- package/dist/billing/payment-handler.d.ts.map +0 -1
- package/dist/billing/payment-handler.js +0 -101
- package/dist/billing/payment-handler.js.map +0 -1
- package/dist/builtin-skills/catalog/phone-adb-automation/SKILL.md +0 -412
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_input.sh +0 -132
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_launch.sh +0 -166
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_screenshot.sh +0 -87
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_security_kbd.py +0 -174
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_setup.sh +0 -274
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_swipe.sh +0 -111
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_tap.sh +0 -87
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_ui_parse.py +0 -176
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_wake_unlock.sh +0 -67
- package/dist/builtin-skills/transcribe-audio/SKILL.md +0 -122
- package/dist/data-processing/convert-demo-cli.d.ts +0 -7
- package/dist/data-processing/convert-demo-cli.d.ts.map +0 -1
- package/dist/data-processing/convert-demo-cli.js +0 -30
- package/dist/data-processing/convert-demo-cli.js.map +0 -1
- package/dist/data-processing/convert-demo.d.ts +0 -26
- package/dist/data-processing/convert-demo.d.ts.map +0 -1
- package/dist/data-processing/convert-demo.js +0 -233
- package/dist/data-processing/convert-demo.js.map +0 -1
- package/dist/obs/rdp/icons/icons/app_windows.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_get.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_send.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_shared.svg +0 -4
- package/dist/obs/rdp/icons/icons/clipboard.svg +0 -4
- package/dist/obs/rdp/icons/icons/clipboard_shared.svg +0 -4
- package/dist/obs/rdp/icons/icons/control.svg +0 -4
- package/dist/obs/rdp/icons/icons/desktop.svg +0 -4
- package/dist/obs/rdp/icons/icons/display.svg +0 -4
- package/dist/obs/rdp/icons/icons/launchpad.svg +0 -4
- package/dist/obs/rdp/icons/icons/mission_control.svg +0 -4
- package/dist/obs/rdp/icons/icons/screenshot.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_actual.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_fit.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_in.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_out.svg +0 -4
- package/dist/obs/tunnel-telemetry.d.ts +0 -46
- package/dist/obs/tunnel-telemetry.d.ts.map +0 -1
- package/dist/obs/tunnel-telemetry.js +0 -70
- package/dist/obs/tunnel-telemetry.js.map +0 -1
- package/dist/onboarding/cloudflared-cert.d.ts +0 -15
- package/dist/onboarding/cloudflared-cert.d.ts.map +0 -1
- package/dist/onboarding/cloudflared-cert.js +0 -57
- package/dist/onboarding/cloudflared-cert.js.map +0 -1
- package/dist/onboarding/playwriter-extension.d.ts +0 -19
- package/dist/onboarding/playwriter-extension.d.ts.map +0 -1
- package/dist/onboarding/playwriter-extension.js +0 -246
- package/dist/onboarding/playwriter-extension.js.map +0 -1
- package/dist/service/gbox-tun.d.ts +0 -14
- package/dist/service/gbox-tun.d.ts.map +0 -1
- package/dist/service/gbox-tun.js +0 -315
- package/dist/service/gbox-tun.js.map +0 -1
- package/dist/skills/installed.d.ts +0 -11
- package/dist/skills/installed.d.ts.map +0 -1
- package/dist/skills/installed.js +0 -35
- package/dist/skills/installed.js.map +0 -1
- package/dist/tools/coordinate-resolver.d.ts +0 -30
- package/dist/tools/coordinate-resolver.d.ts.map +0 -1
- package/dist/tools/coordinate-resolver.js +0 -104
- package/dist/tools/coordinate-resolver.js.map +0 -1
- package/dist/utils/playwriter-relay.d.ts +0 -9
- package/dist/utils/playwriter-relay.d.ts.map +0 -1
- package/dist/utils/playwriter-relay.js +0 -77
- package/dist/utils/playwriter-relay.js.map +0 -1
- package/dist/utils/wechat-monitor.d.ts +0 -21
- package/dist/utils/wechat-monitor.d.ts.map +0 -1
- package/dist/utils/wechat-monitor.js +0 -88
- package/dist/utils/wechat-monitor.js.map +0 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
export declare function getVoiceDb(): DatabaseSync;
|
|
4
|
+
export interface RealtimeOwnerConfig {
|
|
5
|
+
ownerName: string;
|
|
6
|
+
ownerEmail: string;
|
|
7
|
+
timezone: string;
|
|
8
|
+
language: string;
|
|
9
|
+
telegramChatId?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadOwnerConfig(): RealtimeOwnerConfig;
|
|
12
|
+
export declare function buildRealtimeContextFromAgent(config: VisionClawConfig): string;
|
|
13
|
+
export declare function closeVoiceDb(): void;
|
|
14
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/realtime/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,wBAAgB,UAAU,IAAI,YAAY,CA4BzC;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,eAAe,IAAI,mBAAmB,CASrD;AAuED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAoC9E;AAED,wBAAgB,YAAY,IAAI,IAAI,CAKnC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { DatabaseSync } from "node:sqlite";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
import { getConfigDir, loadOwnerConfig as loadAgentOwnerConfig } from "../config/index.js";
|
|
5
|
+
import { getAgentState } from "../agent/state.js";
|
|
6
|
+
import { TOOLS } from "./tools.js";
|
|
7
|
+
let voiceDb = null;
|
|
8
|
+
export function getVoiceDb() {
|
|
9
|
+
if (voiceDb)
|
|
10
|
+
return voiceDb;
|
|
11
|
+
const dbPath = path.join(getConfigDir(), "transcript-memory.db");
|
|
12
|
+
voiceDb = new DatabaseSync(dbPath);
|
|
13
|
+
voiceDb.exec("PRAGMA journal_mode = WAL");
|
|
14
|
+
voiceDb.exec(`
|
|
15
|
+
CREATE TABLE IF NOT EXISTS voice_sessions (
|
|
16
|
+
session_id TEXT PRIMARY KEY,
|
|
17
|
+
user_id TEXT NOT NULL,
|
|
18
|
+
user_name TEXT,
|
|
19
|
+
timestamp_start TEXT NOT NULL,
|
|
20
|
+
timestamp_end TEXT NOT NULL,
|
|
21
|
+
duration INTEGER,
|
|
22
|
+
summary TEXT,
|
|
23
|
+
transcript TEXT NOT NULL,
|
|
24
|
+
message_count INTEGER NOT NULL DEFAULT 0
|
|
25
|
+
)
|
|
26
|
+
`);
|
|
27
|
+
voiceDb.exec(`
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_voice_sessions_user
|
|
29
|
+
ON voice_sessions(user_id, timestamp_start DESC)
|
|
30
|
+
`);
|
|
31
|
+
logger.system("[Realtime] SQLite database initialized (voice_sessions table ready)");
|
|
32
|
+
return voiceDb;
|
|
33
|
+
}
|
|
34
|
+
export function loadOwnerConfig() {
|
|
35
|
+
const owner = loadAgentOwnerConfig();
|
|
36
|
+
return {
|
|
37
|
+
ownerName: owner.ownerName,
|
|
38
|
+
ownerEmail: owner.ownerEmail,
|
|
39
|
+
timezone: owner.timezone ?? "UTC",
|
|
40
|
+
language: owner.language,
|
|
41
|
+
telegramChatId: owner.telegramChatId,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const REALTIME_CONTEXT_CHAR_LIMIT = 4_000;
|
|
45
|
+
const REALTIME_ACTIVITY_CHAR_LIMIT = 4_000;
|
|
46
|
+
const REALTIME_LIMITS = [
|
|
47
|
+
"No desktop control: no clicking, typing, screenshotting, or GUI automation.",
|
|
48
|
+
"No code execution, terminal access, or file edits.",
|
|
49
|
+
"No chat-app automation for WeChat, Feishu, Discord, WhatsApp, or similar apps.",
|
|
50
|
+
"No direct access to the main agent's skill catalog, MCP servers, browser automation, transcript search, or full wake context.",
|
|
51
|
+
"No ability to start, stop, restart, upgrade, or reconfigure the main agent.",
|
|
52
|
+
"No access to historical Telegram or voice transcripts; ongoing work comes only from the live status block in this prompt.",
|
|
53
|
+
];
|
|
54
|
+
function formatToolCapabilityList() {
|
|
55
|
+
return TOOLS
|
|
56
|
+
.map((tool) => `- ${tool.name}: ${tool.description}`)
|
|
57
|
+
.join("\n");
|
|
58
|
+
}
|
|
59
|
+
function formatCurrentTime(timezone) {
|
|
60
|
+
const current = new Date().toLocaleString("en-US", {
|
|
61
|
+
timeZone: timezone,
|
|
62
|
+
dateStyle: "full",
|
|
63
|
+
timeStyle: "long",
|
|
64
|
+
});
|
|
65
|
+
return `${current} (${timezone})`;
|
|
66
|
+
}
|
|
67
|
+
function trimToLimit(text, limit) {
|
|
68
|
+
if (text.length <= limit)
|
|
69
|
+
return text;
|
|
70
|
+
return text.slice(0, Math.max(0, limit - 80)).trimEnd() + "\n...[truncated for realtime context budget]";
|
|
71
|
+
}
|
|
72
|
+
function getActivitySummary() {
|
|
73
|
+
try {
|
|
74
|
+
return trimToLimit(getAgentState().activityTracker.getSummary(), REALTIME_ACTIVITY_CHAR_LIMIT);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
logger.warn(`[Realtime] Failed to read ActivityTracker: ${err instanceof Error ? err.message : String(err)}`);
|
|
78
|
+
return "Agent live status is unavailable during startup.";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function buildCompactMainAgentContext(config, owner, time) {
|
|
82
|
+
let stateLine = "unknown";
|
|
83
|
+
let openTodos = [];
|
|
84
|
+
try {
|
|
85
|
+
const state = getAgentState();
|
|
86
|
+
stateLine = state.busy ? "running a wake cycle" : "idle";
|
|
87
|
+
openTodos = state.activityTracker
|
|
88
|
+
.getTodos()
|
|
89
|
+
.filter((todo) => todo.status !== "completed")
|
|
90
|
+
.slice(0, 8)
|
|
91
|
+
.map((todo) => `- ${todo.status}: ${todo.content}`);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
logger.warn(`[Realtime] Failed to build compact main-agent context: ${err instanceof Error ? err.message : String(err)}`);
|
|
95
|
+
}
|
|
96
|
+
const lines = [
|
|
97
|
+
`Agent: ${config.agentName}`,
|
|
98
|
+
`Owner: ${owner.ownerName}${owner.ownerEmail ? ` (${owner.ownerEmail})` : ""}`,
|
|
99
|
+
`Current time: ${time}`,
|
|
100
|
+
`Main agent state at realtime session start: ${stateLine}`,
|
|
101
|
+
"This is a bounded summary generated when the realtime session started, not the full main-agent context.",
|
|
102
|
+
];
|
|
103
|
+
if (openTodos.length > 0) {
|
|
104
|
+
lines.push("Open todos from the current/last active wake cycle:", ...openTodos);
|
|
105
|
+
}
|
|
106
|
+
return trimToLimit(lines.join("\n"), REALTIME_CONTEXT_CHAR_LIMIT);
|
|
107
|
+
}
|
|
108
|
+
export function buildRealtimeContextFromAgent(config) {
|
|
109
|
+
const owner = loadOwnerConfig();
|
|
110
|
+
const time = formatCurrentTime(owner.timezone);
|
|
111
|
+
const compactContext = buildCompactMainAgentContext(config, owner, time);
|
|
112
|
+
const liveStatus = getActivitySummary();
|
|
113
|
+
const ownerEmail = owner.ownerEmail ? ` (${owner.ownerEmail})` : "";
|
|
114
|
+
return `You are the realtime voice interface for ${config.agentName}, the owner's long-running VisionClaw desktop agent. The owner (${owner.ownerName}${ownerEmail}) is speaking to you live through a Telegram Mini App.
|
|
115
|
+
|
|
116
|
+
## Authority and Trust
|
|
117
|
+
Every speaker in this voice session is the verified owner. Treat this as a short-lived voice front-end for the main agent, not as a standalone assistant.
|
|
118
|
+
|
|
119
|
+
## Current Time
|
|
120
|
+
${time}
|
|
121
|
+
Owner language: ${owner.language}
|
|
122
|
+
|
|
123
|
+
## Capabilities You Have Right Now
|
|
124
|
+
You may use only the realtime tools listed below:
|
|
125
|
+
${formatToolCapabilityList()}
|
|
126
|
+
|
|
127
|
+
## Capabilities You Do NOT Have
|
|
128
|
+
${REALTIME_LIMITS.map((limit) => `- ${limit}`).join("\n")}
|
|
129
|
+
|
|
130
|
+
## Handoff Rule
|
|
131
|
+
If the owner asks for anything outside the explicit realtime capabilities list, do not attempt it. Briefly acknowledge that the main agent will handle it. The request will be captured in this voice transcript, summarized as an open follow-up, and injected into the main agent's next wake context.
|
|
132
|
+
|
|
133
|
+
## Compact Main Agent Context
|
|
134
|
+
This bounded summary was generated when the realtime session started. It is not the full main-agent context; omitted details may still exist in the main agent.
|
|
135
|
+
${compactContext}
|
|
136
|
+
|
|
137
|
+
## Agent Live Status
|
|
138
|
+
This section is a compact live-status bridge from the main agent via ActivityTracker, using the same current-activity summary mechanism as the fast responder. It is the source of truth for what the main agent is currently doing right now, but it may simply say the agent is idle.
|
|
139
|
+
${liveStatus}
|
|
140
|
+
|
|
141
|
+
## Voice Behavior
|
|
142
|
+
Keep replies short and conversational. Ask one question at a time. When a tool is needed, give a very brief acknowledgement and call it. Confirm meaningful side effects before performing them. Never narrate raw tool payloads, IDs, URLs, or internal status unless the owner explicitly asks.`;
|
|
143
|
+
}
|
|
144
|
+
export function closeVoiceDb() {
|
|
145
|
+
if (voiceDb) {
|
|
146
|
+
try {
|
|
147
|
+
voiceDb.close();
|
|
148
|
+
}
|
|
149
|
+
catch { /* ignore */ }
|
|
150
|
+
voiceDb = null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/realtime/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type http from "node:http";
|
|
2
|
+
export declare function readBody(req: http.IncomingMessage): Promise<string>;
|
|
3
|
+
export declare function sendJson(res: http.ServerResponse, status: number, data: unknown): void;
|
|
4
|
+
export declare function sendText(res: http.ServerResponse, status: number, text: string, contentType?: string): void;
|
|
5
|
+
//# sourceMappingURL=http-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-helpers.d.ts","sourceRoot":"","sources":["../../src/realtime/http-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAOnE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAStF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,SAAe,GAAG,IAAI,CAQjH"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ── HTTP Request Helpers ─────────────────────────────────────────────────────
|
|
2
|
+
export function readBody(req) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
6
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
7
|
+
req.on("error", reject);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function sendJson(res, status, data) {
|
|
11
|
+
const body = JSON.stringify(data);
|
|
12
|
+
res.writeHead(status, {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
"Access-Control-Allow-Origin": "*",
|
|
15
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
16
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
17
|
+
});
|
|
18
|
+
res.end(body);
|
|
19
|
+
}
|
|
20
|
+
export function sendText(res, status, text, contentType = "text/plain") {
|
|
21
|
+
res.writeHead(status, {
|
|
22
|
+
"Content-Type": contentType,
|
|
23
|
+
"Access-Control-Allow-Origin": "*",
|
|
24
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
25
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
26
|
+
});
|
|
27
|
+
res.end(text);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=http-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-helpers.js","sourceRoot":"","sources":["../../src/realtime/http-helpers.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAEhF,MAAM,UAAU,QAAQ,CAAC,GAAyB;IAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAa;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,cAAc;KAC/C,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAY,EAAE,WAAW,GAAG,YAAY;IACzG,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,WAAW;QAC3B,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,cAAc;KAC/C,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type RealtimeBackend } from "./server.js";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
import { type RealtimeActiveSessionInfo, type VoiceSessionFinishedEvent, type VoiceSessionSummary, type VoiceSummaryStatus } from "./types.js";
|
|
4
|
+
export type { VoiceSessionFinishedEvent } from "./types.js";
|
|
5
|
+
/** Path prefix used for tunnel ingress routing (e.g., xicas.visionclawobs.com/realtime). */
|
|
6
|
+
export declare const REALTIME_PATH_PREFIX = "/realtime";
|
|
7
|
+
export interface RealtimeModuleHandle {
|
|
8
|
+
close: () => Promise<void>;
|
|
9
|
+
tunnelUrl: string | null;
|
|
10
|
+
/** Backend mounted under `/realtime` by the OBS HTTP server. */
|
|
11
|
+
backend: RealtimeBackend;
|
|
12
|
+
/** Get unprocessed voice transcripts (for Merge step). */
|
|
13
|
+
getUnprocessedTranscripts: () => Promise<VoiceTranscript[]>;
|
|
14
|
+
/** Mark a transcript as processed by the agent. */
|
|
15
|
+
markTranscriptProcessed: (filename: string) => Promise<void>;
|
|
16
|
+
/** Return active realtime voice session metadata for main-agent context. */
|
|
17
|
+
getActiveSessionInfo: () => RealtimeActiveSessionInfo | null;
|
|
18
|
+
/**
|
|
19
|
+
* Subscribe to voice-session-finished events (fires once per session, after
|
|
20
|
+
* summarization completes). The realtime agent bridge uses this to enqueue
|
|
21
|
+
* an internal message through the existing idle-wake / busy-interrupt path.
|
|
22
|
+
*/
|
|
23
|
+
onVoiceSessionFinished: (listener: (event: VoiceSessionFinishedEvent) => void) => void;
|
|
24
|
+
}
|
|
25
|
+
export interface VoiceTranscript {
|
|
26
|
+
filename: string;
|
|
27
|
+
schemaVersion?: number;
|
|
28
|
+
source?: string;
|
|
29
|
+
sessionId: string | null;
|
|
30
|
+
telegramUser: {
|
|
31
|
+
id: number;
|
|
32
|
+
first_name?: string;
|
|
33
|
+
username?: string;
|
|
34
|
+
} | null;
|
|
35
|
+
duration: number | null;
|
|
36
|
+
startedAt: string | null;
|
|
37
|
+
endedAt: string | null;
|
|
38
|
+
messageCount: number;
|
|
39
|
+
transcript: {
|
|
40
|
+
role: "user" | "assistant";
|
|
41
|
+
text: string;
|
|
42
|
+
timestamp: string;
|
|
43
|
+
}[];
|
|
44
|
+
summary?: VoiceSessionSummary;
|
|
45
|
+
summaryText?: string;
|
|
46
|
+
summaryStatus?: VoiceSummaryStatus;
|
|
47
|
+
summaryError?: string;
|
|
48
|
+
processedByAgent: boolean;
|
|
49
|
+
processedAt?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Start the realtime module.
|
|
53
|
+
*
|
|
54
|
+
* The realtime backend is mounted inside the OBS HTTP server (see
|
|
55
|
+
* `src/obs/server.ts`) under the `/realtime` path. This mirrors how `/rdp`
|
|
56
|
+
* is mounted: a single listening socket, served via the existing Cloudflare
|
|
57
|
+
* tunnel, so no separate port or DNS setup is required. The caller is
|
|
58
|
+
* expected to register {@link RealtimeModuleHandle.backend} with the OBS
|
|
59
|
+
* server.
|
|
60
|
+
*/
|
|
61
|
+
export declare function startRealtimeModule(config: VisionClawConfig): RealtimeModuleHandle;
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAA4D,KAAK,yBAAyB,EAAE,KAAK,yBAAyB,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACzM,YAAY,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gEAAgE;IAChE,OAAO,EAAE,eAAe,CAAC;IACzB,0DAA0D;IAC1D,yBAAyB,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC5D,mDAAmD;IACnD,uBAAuB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,4EAA4E;IAC5E,oBAAoB,EAAE,MAAM,yBAAyB,GAAG,IAAI,CAAC;IAC7D;;;;OAIG;IACH,sBAAsB,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,KAAK,IAAI,CAAC;CACxF;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9E,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,CAgClF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
import { createRealtimeBackend } from "./server.js";
|
|
5
|
+
import { getConfigDir } from "../config/index.js";
|
|
6
|
+
import { REALTIME_SIDECAR_SCHEMA_VERSION, REALTIME_SIDECAR_SOURCE } from "./types.js";
|
|
7
|
+
/** Path prefix used for tunnel ingress routing (e.g., xicas.visionclawobs.com/realtime). */
|
|
8
|
+
export const REALTIME_PATH_PREFIX = "/realtime";
|
|
9
|
+
/**
|
|
10
|
+
* Start the realtime module.
|
|
11
|
+
*
|
|
12
|
+
* The realtime backend is mounted inside the OBS HTTP server (see
|
|
13
|
+
* `src/obs/server.ts`) under the `/realtime` path. This mirrors how `/rdp`
|
|
14
|
+
* is mounted: a single listening socket, served via the existing Cloudflare
|
|
15
|
+
* tunnel, so no separate port or DNS setup is required. The caller is
|
|
16
|
+
* expected to register {@link RealtimeModuleHandle.backend} with the OBS
|
|
17
|
+
* server.
|
|
18
|
+
*/
|
|
19
|
+
export function startRealtimeModule(config) {
|
|
20
|
+
logger.system("[Realtime] Starting realtime module...");
|
|
21
|
+
const backend = createRealtimeBackend(config);
|
|
22
|
+
// Derive the public URL from the existing OBS tunnel hostname.
|
|
23
|
+
const obsTunnelHostname = config.obs.tunnelHostname;
|
|
24
|
+
const tunnelUrl = obsTunnelHostname
|
|
25
|
+
? `https://${obsTunnelHostname}${REALTIME_PATH_PREFIX}`
|
|
26
|
+
: null;
|
|
27
|
+
if (tunnelUrl) {
|
|
28
|
+
logger.system(`[Realtime] Accessible at ${tunnelUrl} (via OBS HTTP server)`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logger.warn("[Realtime] No OBS tunnel hostname — realtime only accessible locally");
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
backend,
|
|
35
|
+
tunnelUrl,
|
|
36
|
+
close: async () => {
|
|
37
|
+
await backend.close();
|
|
38
|
+
logger.system("[Realtime] Module stopped.");
|
|
39
|
+
},
|
|
40
|
+
getUnprocessedTranscripts: () => Promise.resolve(getUnprocessedTranscriptsFromDir()),
|
|
41
|
+
markTranscriptProcessed: (filename) => {
|
|
42
|
+
markTranscriptProcessedInDir(filename);
|
|
43
|
+
return Promise.resolve();
|
|
44
|
+
},
|
|
45
|
+
getActiveSessionInfo: () => backend.getActiveSessionInfo(),
|
|
46
|
+
onVoiceSessionFinished: (listener) => { backend.onVoiceSessionFinished(listener); },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// ── Transcript Processing (Merge Step) ────────────────────────────────────────
|
|
50
|
+
function getUnprocessedTranscriptsFromDir() {
|
|
51
|
+
const profileDir = getConfigDir();
|
|
52
|
+
const transcriptsDir = path.join(profileDir, "voice-transcripts");
|
|
53
|
+
if (!fs.existsSync(transcriptsDir))
|
|
54
|
+
return [];
|
|
55
|
+
const files = fs.readdirSync(transcriptsDir).filter((f) => f.endsWith(".json"));
|
|
56
|
+
const unprocessed = [];
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
try {
|
|
59
|
+
const data = JSON.parse(fs.readFileSync(path.join(transcriptsDir, file), "utf-8"));
|
|
60
|
+
const fromCurrentRealtimeFeature = data.schemaVersion === REALTIME_SIDECAR_SCHEMA_VERSION && data.source === REALTIME_SIDECAR_SOURCE;
|
|
61
|
+
const ready = data.summaryStatus === "ready" || (data.summaryStatus === "failed" && !!data.summaryText);
|
|
62
|
+
if (fromCurrentRealtimeFeature && !data.processedByAgent && ready && data.summary?.noActionable !== true) {
|
|
63
|
+
unprocessed.push({ ...data, filename: file });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
logger.warn(`[Realtime] Failed to parse transcript: ${file}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
unprocessed.sort((a, b) => (a.endedAt ?? "").localeCompare(b.endedAt ?? ""));
|
|
71
|
+
return unprocessed;
|
|
72
|
+
}
|
|
73
|
+
function markTranscriptProcessedInDir(filename) {
|
|
74
|
+
const profileDir = getConfigDir();
|
|
75
|
+
const filePath = path.join(profileDir, "voice-transcripts", filename);
|
|
76
|
+
if (!fs.existsSync(filePath)) {
|
|
77
|
+
logger.warn(`[Realtime] Transcript not found: ${filename}`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
81
|
+
data.processedByAgent = true;
|
|
82
|
+
data.processedAt = new Date().toISOString();
|
|
83
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
84
|
+
logger.system(`[Realtime] Transcript marked as processed: ${filename}`);
|
|
85
|
+
}
|
|
86
|
+
// ── Telegram Menu Button ──────────────────────────────────────────────────────
|
|
87
|
+
//
|
|
88
|
+
// The persistent chat menu button is intentionally not set by this module
|
|
89
|
+
// anymore. Instead the realtime Mini App is surfaced via the `/realtime`
|
|
90
|
+
// Telegram slash command, which sends an inline Web App button. This keeps
|
|
91
|
+
// the entry point flow consistent with /status and /tasks, and avoids the
|
|
92
|
+
// awkward UX of a permanent "Voice" button that breaks whenever the tunnel
|
|
93
|
+
// is down.
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
2
|
+
import { type RealtimeBackend, type VoiceServerHandle } from "./types.js";
|
|
3
|
+
export type { RealtimeActiveSessionInfo, RealtimeBackend } from "./types.js";
|
|
4
|
+
export declare function createRealtimeBackend(config: VisionClawConfig): RealtimeBackend;
|
|
5
|
+
export declare function startRealtimeServer(config: VisionClawConfig): VoiceServerHandle;
|
|
6
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/realtime/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAA4F,KAAK,eAAe,EAAwB,KAAK,iBAAiB,EAAwD,MAAM,YAAY,CAAC;AAChP,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqG7E,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,eAAe,CA+W/E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAgC/E"}
|