@gakr-gakr/discord 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/account-inspect-api.ts +6 -0
- package/action-runtime-api.ts +1 -0
- package/api.ts +130 -0
- package/autobot.plugin.json +15 -0
- package/channel-config-api.ts +1 -0
- package/channel-plugin-api.ts +3 -0
- package/config-api.ts +4 -0
- package/configured-state.ts +6 -0
- package/contract-api.ts +21 -0
- package/directory-contract-api.ts +4 -0
- package/doctor-contract-api.ts +1 -0
- package/index.ts +24 -0
- package/package.json +79 -0
- package/runtime-api.actions.ts +15 -0
- package/runtime-api.lookup.ts +22 -0
- package/runtime-api.monitor.ts +50 -0
- package/runtime-api.send.ts +79 -0
- package/runtime-api.threads.ts +31 -0
- package/runtime-api.ts +181 -0
- package/runtime-setter-api.ts +3 -0
- package/secret-contract-api.ts +4 -0
- package/security-audit-contract-api.ts +1 -0
- package/security-contract-api.ts +4 -0
- package/session-key-api.ts +1 -0
- package/setup-entry.ts +9 -0
- package/setup-plugin-api.ts +3 -0
- package/src/account-inspect.ts +131 -0
- package/src/accounts.ts +205 -0
- package/src/actions/handle-action.guild-admin.ts +421 -0
- package/src/actions/handle-action.ts +402 -0
- package/src/actions/runtime.guild.ts +446 -0
- package/src/actions/runtime.messaging.messages.ts +226 -0
- package/src/actions/runtime.messaging.reactions.ts +67 -0
- package/src/actions/runtime.messaging.runtime.ts +73 -0
- package/src/actions/runtime.messaging.send.ts +336 -0
- package/src/actions/runtime.messaging.shared.ts +97 -0
- package/src/actions/runtime.messaging.ts +37 -0
- package/src/actions/runtime.moderation-shared.ts +48 -0
- package/src/actions/runtime.moderation.ts +116 -0
- package/src/actions/runtime.presence.ts +117 -0
- package/src/actions/runtime.shared.ts +86 -0
- package/src/actions/runtime.ts +87 -0
- package/src/api.ts +219 -0
- package/src/approval-handler.runtime.ts +636 -0
- package/src/approval-native.ts +219 -0
- package/src/approval-runtime.ts +14 -0
- package/src/approval-shared.ts +56 -0
- package/src/audit-core.ts +178 -0
- package/src/audit.ts +32 -0
- package/src/channel-actions.runtime.ts +1 -0
- package/src/channel-actions.ts +254 -0
- package/src/channel-api.ts +29 -0
- package/src/channel.conversation.ts +159 -0
- package/src/channel.loaders.ts +50 -0
- package/src/channel.runtime.ts +1 -0
- package/src/channel.setup.ts +12 -0
- package/src/channel.ts +728 -0
- package/src/chunk.ts +321 -0
- package/src/client.ts +143 -0
- package/src/component-custom-id.ts +72 -0
- package/src/components-registry.ts +356 -0
- package/src/components.builders.ts +410 -0
- package/src/components.modal.ts +124 -0
- package/src/components.parse.ts +407 -0
- package/src/components.ts +54 -0
- package/src/components.types.ts +187 -0
- package/src/config-schema.ts +6 -0
- package/src/config-ui-hints.ts +354 -0
- package/src/conversation-identity.ts +58 -0
- package/src/delivery-retry.ts +56 -0
- package/src/directory-cache.ts +116 -0
- package/src/directory-config.ts +58 -0
- package/src/directory-live.ts +135 -0
- package/src/doctor-contract.ts +477 -0
- package/src/doctor-shared.ts +5 -0
- package/src/doctor.ts +340 -0
- package/src/draft-chunking.ts +43 -0
- package/src/draft-stream.ts +162 -0
- package/src/error-body.ts +38 -0
- package/src/exec-approvals.ts +110 -0
- package/src/gateway-logging.ts +67 -0
- package/src/group-policy.ts +113 -0
- package/src/guilds.ts +29 -0
- package/src/inbound-event-delivery.ts +135 -0
- package/src/interactive-dispatch.ts +104 -0
- package/src/internal/api.commands.ts +51 -0
- package/src/internal/api.guild.ts +164 -0
- package/src/internal/api.interactions.ts +53 -0
- package/src/internal/api.messages.ts +113 -0
- package/src/internal/api.reactions.ts +38 -0
- package/src/internal/api.ts +61 -0
- package/src/internal/api.users.ts +19 -0
- package/src/internal/api.webhooks.ts +13 -0
- package/src/internal/client.ts +310 -0
- package/src/internal/command-deploy.ts +352 -0
- package/src/internal/commands.ts +188 -0
- package/src/internal/components.base.ts +65 -0
- package/src/internal/components.message.ts +279 -0
- package/src/internal/components.modal.ts +95 -0
- package/src/internal/components.ts +31 -0
- package/src/internal/discord.ts +11 -0
- package/src/internal/embeds.ts +35 -0
- package/src/internal/entity-cache.ts +98 -0
- package/src/internal/event-queue.ts +185 -0
- package/src/internal/gateway-close-codes.ts +25 -0
- package/src/internal/gateway-dispatch.ts +96 -0
- package/src/internal/gateway-identify-limiter.ts +26 -0
- package/src/internal/gateway-lifecycle.ts +75 -0
- package/src/internal/gateway-rate-limit.ts +104 -0
- package/src/internal/gateway.ts +479 -0
- package/src/internal/interaction-dispatch.ts +162 -0
- package/src/internal/interaction-options.ts +98 -0
- package/src/internal/interaction-response.ts +53 -0
- package/src/internal/interactions.ts +378 -0
- package/src/internal/listeners.ts +91 -0
- package/src/internal/modal-fields.ts +95 -0
- package/src/internal/payload.ts +69 -0
- package/src/internal/rest-body.ts +115 -0
- package/src/internal/rest-errors.ts +88 -0
- package/src/internal/rest-routes.ts +50 -0
- package/src/internal/rest-scheduler.ts +557 -0
- package/src/internal/rest.ts +322 -0
- package/src/internal/schemas.ts +36 -0
- package/src/internal/structures.ts +280 -0
- package/src/internal/test-builders.test-support.ts +167 -0
- package/src/internal/voice.ts +49 -0
- package/src/media-detection.ts +28 -0
- package/src/mentions.ts +147 -0
- package/src/monitor/ack-reactions.ts +70 -0
- package/src/monitor/agent-components-auth.ts +7 -0
- package/src/monitor/agent-components-context.ts +154 -0
- package/src/monitor/agent-components-data.ts +224 -0
- package/src/monitor/agent-components-dm-auth.ts +177 -0
- package/src/monitor/agent-components-guild-auth.ts +322 -0
- package/src/monitor/agent-components-helpers.runtime.ts +3 -0
- package/src/monitor/agent-components-helpers.ts +34 -0
- package/src/monitor/agent-components-reply.ts +10 -0
- package/src/monitor/agent-components.deps.runtime.ts +2 -0
- package/src/monitor/agent-components.dispatch.ts +359 -0
- package/src/monitor/agent-components.handlers.ts +303 -0
- package/src/monitor/agent-components.modal.ts +160 -0
- package/src/monitor/agent-components.plugin-interactive.ts +187 -0
- package/src/monitor/agent-components.runtime.ts +14 -0
- package/src/monitor/agent-components.system-controls.ts +215 -0
- package/src/monitor/agent-components.ts +70 -0
- package/src/monitor/agent-components.types.ts +58 -0
- package/src/monitor/agent-components.wildcard-controls.ts +171 -0
- package/src/monitor/allow-list.ts +631 -0
- package/src/monitor/auto-presence.ts +356 -0
- package/src/monitor/channel-access.ts +102 -0
- package/src/monitor/commands.ts +9 -0
- package/src/monitor/dm-command-auth.ts +259 -0
- package/src/monitor/dm-command-decision.ts +49 -0
- package/src/monitor/exec-approvals.ts +161 -0
- package/src/monitor/format.ts +45 -0
- package/src/monitor/gateway-handle.ts +34 -0
- package/src/monitor/gateway-metadata.ts +298 -0
- package/src/monitor/gateway-plugin.ts +302 -0
- package/src/monitor/gateway-registry.ts +37 -0
- package/src/monitor/gateway-supervisor.ts +206 -0
- package/src/monitor/inbound-context.ts +95 -0
- package/src/monitor/inbound-dedupe.ts +79 -0
- package/src/monitor/inbound-job.ts +118 -0
- package/src/monitor/listeners.queue.ts +91 -0
- package/src/monitor/listeners.reactions.ts +594 -0
- package/src/monitor/listeners.ts +150 -0
- package/src/monitor/message-channel-info.ts +96 -0
- package/src/monitor/message-forwarded.ts +114 -0
- package/src/monitor/message-handler.batch-gate.ts +19 -0
- package/src/monitor/message-handler.context.ts +492 -0
- package/src/monitor/message-handler.dm-preflight.ts +119 -0
- package/src/monitor/message-handler.draft-preview.ts +436 -0
- package/src/monitor/message-handler.hydration.ts +198 -0
- package/src/monitor/message-handler.module-test-helpers.ts +31 -0
- package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
- package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
- package/src/monitor/message-handler.preflight-context.ts +54 -0
- package/src/monitor/message-handler.preflight-helpers.ts +164 -0
- package/src/monitor/message-handler.preflight-history.ts +23 -0
- package/src/monitor/message-handler.preflight-logging.ts +36 -0
- package/src/monitor/message-handler.preflight-pluralkit.ts +28 -0
- package/src/monitor/message-handler.preflight-runtime.ts +28 -0
- package/src/monitor/message-handler.preflight-thread.ts +49 -0
- package/src/monitor/message-handler.preflight.ts +822 -0
- package/src/monitor/message-handler.preflight.types.ts +115 -0
- package/src/monitor/message-handler.process.ts +1033 -0
- package/src/monitor/message-handler.routing-preflight.ts +112 -0
- package/src/monitor/message-handler.ts +309 -0
- package/src/monitor/message-media.ts +536 -0
- package/src/monitor/message-run-queue.ts +101 -0
- package/src/monitor/message-text.ts +171 -0
- package/src/monitor/message-utils.ts +34 -0
- package/src/monitor/model-picker-preferences.ts +184 -0
- package/src/monitor/model-picker.state.ts +364 -0
- package/src/monitor/model-picker.test-utils.ts +26 -0
- package/src/monitor/model-picker.ts +38 -0
- package/src/monitor/model-picker.view.ts +722 -0
- package/src/monitor/native-command-agent-reply.ts +125 -0
- package/src/monitor/native-command-arg-ui.ts +233 -0
- package/src/monitor/native-command-auth.ts +309 -0
- package/src/monitor/native-command-bypass.ts +13 -0
- package/src/monitor/native-command-context.ts +109 -0
- package/src/monitor/native-command-dispatch.ts +35 -0
- package/src/monitor/native-command-model-picker-apply.ts +209 -0
- package/src/monitor/native-command-model-picker-interaction.ts +516 -0
- package/src/monitor/native-command-model-picker-ui.ts +357 -0
- package/src/monitor/native-command-reply.ts +185 -0
- package/src/monitor/native-command-route.ts +91 -0
- package/src/monitor/native-command-status.ts +76 -0
- package/src/monitor/native-command-ui.ts +26 -0
- package/src/monitor/native-command-ui.types.ts +20 -0
- package/src/monitor/native-command.args.ts +45 -0
- package/src/monitor/native-command.options.ts +153 -0
- package/src/monitor/native-command.runtime.ts +51 -0
- package/src/monitor/native-command.ts +747 -0
- package/src/monitor/native-command.types.ts +9 -0
- package/src/monitor/native-interaction-channel-context.ts +50 -0
- package/src/monitor/preflight-audio.runtime.ts +9 -0
- package/src/monitor/preflight-audio.ts +130 -0
- package/src/monitor/presence-cache.ts +61 -0
- package/src/monitor/presence.ts +50 -0
- package/src/monitor/provider-session.runtime.ts +12 -0
- package/src/monitor/provider.acp.ts +89 -0
- package/src/monitor/provider.allowlist.ts +398 -0
- package/src/monitor/provider.cleanup.ts +41 -0
- package/src/monitor/provider.commands.ts +129 -0
- package/src/monitor/provider.config-log.ts +45 -0
- package/src/monitor/provider.deploy-errors.ts +362 -0
- package/src/monitor/provider.deploy.ts +221 -0
- package/src/monitor/provider.interactions.ts +160 -0
- package/src/monitor/provider.lifecycle.ts +562 -0
- package/src/monitor/provider.runtime.ts +1 -0
- package/src/monitor/provider.startup-log.ts +32 -0
- package/src/monitor/provider.startup.ts +323 -0
- package/src/monitor/provider.ts +688 -0
- package/src/monitor/reply-context.ts +64 -0
- package/src/monitor/reply-delivery.ts +216 -0
- package/src/monitor/reply-safety.ts +96 -0
- package/src/monitor/rest-fetch.ts +97 -0
- package/src/monitor/route-resolution.ts +140 -0
- package/src/monitor/sender-identity.ts +81 -0
- package/src/monitor/startup-status.ts +10 -0
- package/src/monitor/status.ts +22 -0
- package/src/monitor/system-events.ts +55 -0
- package/src/monitor/thread-bindings.config.ts +35 -0
- package/src/monitor/thread-bindings.discord-api.ts +310 -0
- package/src/monitor/thread-bindings.lifecycle.ts +354 -0
- package/src/monitor/thread-bindings.manager.ts +554 -0
- package/src/monitor/thread-bindings.messages.ts +6 -0
- package/src/monitor/thread-bindings.persona.ts +25 -0
- package/src/monitor/thread-bindings.session-adapter.ts +229 -0
- package/src/monitor/thread-bindings.session-shared.ts +59 -0
- package/src/monitor/thread-bindings.session-updates.ts +35 -0
- package/src/monitor/thread-bindings.state.ts +540 -0
- package/src/monitor/thread-bindings.ts +48 -0
- package/src/monitor/thread-bindings.types.ts +83 -0
- package/src/monitor/thread-channel-context.ts +112 -0
- package/src/monitor/thread-session-close.ts +63 -0
- package/src/monitor/thread-title.ts +181 -0
- package/src/monitor/threading.auto-thread.ts +287 -0
- package/src/monitor/threading.cache.ts +45 -0
- package/src/monitor/threading.starter.ts +288 -0
- package/src/monitor/threading.ts +20 -0
- package/src/monitor/threading.types.ts +102 -0
- package/src/monitor/timeouts.ts +84 -0
- package/src/monitor/typing.ts +17 -0
- package/src/monitor.gateway.ts +75 -0
- package/src/monitor.ts +28 -0
- package/src/network-config.ts +79 -0
- package/src/normalize.ts +86 -0
- package/src/outbound-adapter.ts +327 -0
- package/src/outbound-approval.ts +29 -0
- package/src/outbound-components.ts +86 -0
- package/src/outbound-payload.ts +208 -0
- package/src/outbound-send-context.ts +92 -0
- package/src/outbound-session-route.ts +72 -0
- package/src/pluralkit.ts +58 -0
- package/src/preview-streaming.ts +18 -0
- package/src/probe.runtime.ts +1 -0
- package/src/probe.ts +237 -0
- package/src/proxy-fetch.ts +92 -0
- package/src/proxy-request-client.ts +21 -0
- package/src/recipient-resolution.ts +39 -0
- package/src/resolve-allowlist-common.ts +39 -0
- package/src/resolve-channels.ts +369 -0
- package/src/resolve-users.ts +184 -0
- package/src/retry.ts +98 -0
- package/src/runtime-api.ts +64 -0
- package/src/runtime-config.ts +16 -0
- package/src/runtime.ts +23 -0
- package/src/secret-config-contract.ts +140 -0
- package/src/security-audit.runtime.ts +1 -0
- package/src/security-audit.ts +208 -0
- package/src/security-contract.ts +47 -0
- package/src/security-doctor.ts +20 -0
- package/src/security.ts +60 -0
- package/src/send-target-parsing.ts +14 -0
- package/src/send.channels.ts +139 -0
- package/src/send.components.ts +391 -0
- package/src/send.emojis-stickers.ts +57 -0
- package/src/send.guild.ts +170 -0
- package/src/send.message-request.ts +112 -0
- package/src/send.messages.ts +229 -0
- package/src/send.outbound.ts +459 -0
- package/src/send.permissions.ts +283 -0
- package/src/send.reactions.ts +155 -0
- package/src/send.receipt.ts +69 -0
- package/src/send.shared.ts +469 -0
- package/src/send.ts +82 -0
- package/src/send.types.ts +191 -0
- package/src/send.typing.ts +9 -0
- package/src/send.voice.ts +140 -0
- package/src/send.webhook.ts +137 -0
- package/src/session-contract.ts +3 -0
- package/src/session-key-normalization.ts +47 -0
- package/src/setup-account-state.ts +144 -0
- package/src/setup-adapter.ts +14 -0
- package/src/setup-core.ts +215 -0
- package/src/setup-runtime-helpers.ts +10 -0
- package/src/setup-surface.ts +132 -0
- package/src/shared-interactive.ts +167 -0
- package/src/shared.ts +197 -0
- package/src/status-issues.ts +201 -0
- package/src/subagent-hooks.ts +232 -0
- package/src/target-parsing.ts +70 -0
- package/src/target-resolver.ts +129 -0
- package/src/targets.ts +12 -0
- package/src/token.ts +107 -0
- package/src/ui-colors.ts +27 -0
- package/src/ui.ts +20 -0
- package/src/voice/access.ts +126 -0
- package/src/voice/audio.ts +249 -0
- package/src/voice/capture-state.ts +120 -0
- package/src/voice/command.ts +284 -0
- package/src/voice/config.ts +8 -0
- package/src/voice/ingress.ts +164 -0
- package/src/voice/manager.runtime.ts +14 -0
- package/src/voice/manager.ts +1155 -0
- package/src/voice/prompt.ts +22 -0
- package/src/voice/realtime.ts +1370 -0
- package/src/voice/receive-recovery.ts +159 -0
- package/src/voice/sanitize.ts +29 -0
- package/src/voice/sdk-runtime.ts +14 -0
- package/src/voice/segment.ts +160 -0
- package/src/voice/session.ts +81 -0
- package/src/voice/speaker-context.ts +127 -0
- package/src/voice/tts.ts +151 -0
- package/src/voice-message.ts +474 -0
- package/subagent-hooks-api.ts +27 -0
- package/test-api.ts +4 -0
- package/thread-binding-api.ts +1 -0
- package/timeouts.ts +6 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
|
|
3
|
+
type VoiceCaptureEntry = {
|
|
4
|
+
generation: number;
|
|
5
|
+
stream: Readable;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type VoiceCaptureFinalizeTimer = {
|
|
9
|
+
generation: number;
|
|
10
|
+
timer: ReturnType<typeof setTimeout>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type VoiceCaptureState = {
|
|
14
|
+
activeSpeakers: Set<string>;
|
|
15
|
+
activeCaptureStreams: Map<string, VoiceCaptureEntry>;
|
|
16
|
+
captureFinalizeTimers: Map<string, VoiceCaptureFinalizeTimer>;
|
|
17
|
+
captureGenerations: Map<string, number>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function createVoiceCaptureState(): VoiceCaptureState {
|
|
21
|
+
return {
|
|
22
|
+
activeSpeakers: new Set(),
|
|
23
|
+
activeCaptureStreams: new Map(),
|
|
24
|
+
captureFinalizeTimers: new Map(),
|
|
25
|
+
captureGenerations: new Map(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function stopVoiceCaptureState(state: VoiceCaptureState): void {
|
|
30
|
+
for (const { timer } of state.captureFinalizeTimers.values()) {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
}
|
|
33
|
+
state.captureFinalizeTimers.clear();
|
|
34
|
+
for (const { stream } of state.activeCaptureStreams.values()) {
|
|
35
|
+
stream.destroy();
|
|
36
|
+
}
|
|
37
|
+
state.activeCaptureStreams.clear();
|
|
38
|
+
state.captureGenerations.clear();
|
|
39
|
+
state.activeSpeakers.clear();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getActiveVoiceCapture(
|
|
43
|
+
state: VoiceCaptureState,
|
|
44
|
+
userId: string,
|
|
45
|
+
): VoiceCaptureEntry | undefined {
|
|
46
|
+
return state.activeCaptureStreams.get(userId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isVoiceCaptureActive(state: VoiceCaptureState, userId: string): boolean {
|
|
50
|
+
return state.activeSpeakers.has(userId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function clearVoiceCaptureFinalizeTimer(
|
|
54
|
+
state: VoiceCaptureState,
|
|
55
|
+
userId: string,
|
|
56
|
+
generation?: number,
|
|
57
|
+
): boolean {
|
|
58
|
+
const scheduled = state.captureFinalizeTimers.get(userId);
|
|
59
|
+
if (!scheduled || (generation !== undefined && scheduled.generation !== generation)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
clearTimeout(scheduled.timer);
|
|
63
|
+
state.captureFinalizeTimers.delete(userId);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function beginVoiceCapture(
|
|
68
|
+
state: VoiceCaptureState,
|
|
69
|
+
userId: string,
|
|
70
|
+
stream: Readable,
|
|
71
|
+
): number {
|
|
72
|
+
const generation = (state.captureGenerations.get(userId) ?? 0) + 1;
|
|
73
|
+
state.captureGenerations.set(userId, generation);
|
|
74
|
+
state.activeSpeakers.add(userId);
|
|
75
|
+
state.activeCaptureStreams.set(userId, { generation, stream });
|
|
76
|
+
clearVoiceCaptureFinalizeTimer(state, userId, generation);
|
|
77
|
+
return generation;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function finishVoiceCapture(
|
|
81
|
+
state: VoiceCaptureState,
|
|
82
|
+
userId: string,
|
|
83
|
+
generation: number,
|
|
84
|
+
): boolean {
|
|
85
|
+
clearVoiceCaptureFinalizeTimer(state, userId, generation);
|
|
86
|
+
const activeCapture = state.activeCaptureStreams.get(userId);
|
|
87
|
+
if (activeCapture?.generation !== generation) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
state.activeCaptureStreams.delete(userId);
|
|
91
|
+
state.activeSpeakers.delete(userId);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function scheduleVoiceCaptureFinalize(params: {
|
|
96
|
+
state: VoiceCaptureState;
|
|
97
|
+
userId: string;
|
|
98
|
+
delayMs: number;
|
|
99
|
+
onFinalize?: (capture: VoiceCaptureEntry) => void;
|
|
100
|
+
}): boolean {
|
|
101
|
+
const { state, userId, delayMs, onFinalize } = params;
|
|
102
|
+
const capture = state.activeCaptureStreams.get(userId);
|
|
103
|
+
if (!capture) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
clearVoiceCaptureFinalizeTimer(state, userId, capture.generation);
|
|
107
|
+
const timer = setTimeout(() => {
|
|
108
|
+
const activeCapture = state.activeCaptureStreams.get(userId);
|
|
109
|
+
if (!activeCapture || activeCapture.generation !== capture.generation) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
state.captureFinalizeTimers.delete(userId);
|
|
113
|
+
state.activeCaptureStreams.delete(userId);
|
|
114
|
+
state.activeSpeakers.delete(userId);
|
|
115
|
+
onFinalize?.(activeCapture);
|
|
116
|
+
activeCapture.stream.destroy();
|
|
117
|
+
}, delayMs);
|
|
118
|
+
state.captureFinalizeTimers.set(userId, { generation: capture.generation, timer });
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApplicationCommandOptionType,
|
|
3
|
+
ChannelType as DiscordChannelType,
|
|
4
|
+
type APIApplicationCommandChannelOption,
|
|
5
|
+
} from "discord-api-types/v10";
|
|
6
|
+
import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
|
|
7
|
+
import type { DiscordAccountConfig } from "autobot/plugin-sdk/config-contracts";
|
|
8
|
+
import { resolveDiscordAccountAllowFrom } from "../accounts.js";
|
|
9
|
+
import {
|
|
10
|
+
Command,
|
|
11
|
+
CommandWithSubcommands,
|
|
12
|
+
type CommandInteraction,
|
|
13
|
+
type CommandOptions,
|
|
14
|
+
} from "../internal/discord.js";
|
|
15
|
+
import { formatMention } from "../mentions.js";
|
|
16
|
+
import { resolveDiscordChannelNameSafe } from "../monitor/channel-access.js";
|
|
17
|
+
import { resolveDiscordSenderIdentity } from "../monitor/sender-identity.js";
|
|
18
|
+
import { resolveDiscordThreadLikeChannelContext } from "../monitor/thread-channel-context.js";
|
|
19
|
+
import { authorizeDiscordVoiceIngress } from "./access.js";
|
|
20
|
+
import type { DiscordVoiceManager } from "./manager.js";
|
|
21
|
+
|
|
22
|
+
const VOICE_CHANNEL_TYPES: NonNullable<APIApplicationCommandChannelOption["channel_types"]> = [
|
|
23
|
+
DiscordChannelType.GuildVoice,
|
|
24
|
+
DiscordChannelType.GuildStageVoice,
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
type VoiceCommandContext = {
|
|
28
|
+
cfg: AutoBotConfig;
|
|
29
|
+
discordConfig: DiscordAccountConfig;
|
|
30
|
+
accountId: string;
|
|
31
|
+
groupPolicy: "open" | "disabled" | "allowlist";
|
|
32
|
+
useAccessGroups: boolean;
|
|
33
|
+
getManager: () => DiscordVoiceManager | null;
|
|
34
|
+
ephemeralDefault: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type VoiceCommandChannelOverride = {
|
|
38
|
+
id: string;
|
|
39
|
+
name?: string;
|
|
40
|
+
parentId?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type VoiceCommandRuntimeContext = {
|
|
44
|
+
guildId: string;
|
|
45
|
+
manager: DiscordVoiceManager;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
async function authorizeVoiceCommand(
|
|
49
|
+
interaction: CommandInteraction,
|
|
50
|
+
params: VoiceCommandContext,
|
|
51
|
+
options?: { channelOverride?: VoiceCommandChannelOverride },
|
|
52
|
+
): Promise<{ ok: boolean; message?: string; guildId?: string }> {
|
|
53
|
+
const channelOverride = options?.channelOverride;
|
|
54
|
+
const channel = channelOverride ? undefined : interaction.channel;
|
|
55
|
+
if (!interaction.guild) {
|
|
56
|
+
return { ok: false, message: "Voice commands are only available in guilds." };
|
|
57
|
+
}
|
|
58
|
+
const user = interaction.user;
|
|
59
|
+
if (!user) {
|
|
60
|
+
return { ok: false, message: "Unable to resolve command user." };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const channelId = channelOverride?.id ?? channel?.id ?? "";
|
|
64
|
+
const channelContext = await resolveDiscordThreadLikeChannelContext({
|
|
65
|
+
client: interaction.client,
|
|
66
|
+
channel: channelOverride ?? channel,
|
|
67
|
+
channelIdFallback: channelId,
|
|
68
|
+
});
|
|
69
|
+
const channelName = channelOverride?.name ?? channelContext.channelName;
|
|
70
|
+
|
|
71
|
+
const memberRoleIds = Array.isArray(interaction.rawData.member?.roles)
|
|
72
|
+
? interaction.rawData.member.roles.map((roleId: string) => roleId)
|
|
73
|
+
: [];
|
|
74
|
+
const sender = resolveDiscordSenderIdentity({ author: user, member: interaction.rawData.member });
|
|
75
|
+
const access = await authorizeDiscordVoiceIngress({
|
|
76
|
+
cfg: params.cfg,
|
|
77
|
+
discordConfig: params.discordConfig,
|
|
78
|
+
accountId: params.accountId,
|
|
79
|
+
groupPolicy: params.groupPolicy,
|
|
80
|
+
useAccessGroups: params.useAccessGroups,
|
|
81
|
+
guild: interaction.guild,
|
|
82
|
+
guildId: interaction.guild.id,
|
|
83
|
+
channelId,
|
|
84
|
+
channelName,
|
|
85
|
+
channelSlug: channelContext.channelSlug,
|
|
86
|
+
parentId: channelOverride?.parentId ?? channelContext.threadParentId,
|
|
87
|
+
parentName: channelContext.threadParentName,
|
|
88
|
+
parentSlug: channelContext.threadParentSlug,
|
|
89
|
+
scope: channelContext.isThreadChannel ? "thread" : "channel",
|
|
90
|
+
channelLabel: channelId ? formatMention({ channelId }) : "This channel",
|
|
91
|
+
memberRoleIds,
|
|
92
|
+
ownerAllowFrom: resolveDiscordAccountAllowFrom({
|
|
93
|
+
cfg: params.cfg,
|
|
94
|
+
accountId: params.accountId,
|
|
95
|
+
}),
|
|
96
|
+
sender: {
|
|
97
|
+
id: sender.id,
|
|
98
|
+
name: sender.name,
|
|
99
|
+
tag: sender.tag,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (!access.ok) {
|
|
103
|
+
return { ok: false, message: access.message };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { ok: true, guildId: interaction.guild.id };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function resolveVoiceCommandRuntimeContext(
|
|
110
|
+
interaction: CommandInteraction,
|
|
111
|
+
params: Pick<VoiceCommandContext, "getManager">,
|
|
112
|
+
): Promise<VoiceCommandRuntimeContext | null> {
|
|
113
|
+
const guildId = interaction.guild?.id;
|
|
114
|
+
if (!guildId) {
|
|
115
|
+
await interaction.reply({
|
|
116
|
+
content: "Unable to resolve guild for this command.",
|
|
117
|
+
ephemeral: true,
|
|
118
|
+
});
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const manager = params.getManager();
|
|
122
|
+
if (!manager) {
|
|
123
|
+
await interaction.reply({
|
|
124
|
+
content: "Voice manager is not available yet.",
|
|
125
|
+
ephemeral: true,
|
|
126
|
+
});
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return { guildId, manager };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function ensureVoiceCommandAccess(params: {
|
|
133
|
+
interaction: CommandInteraction;
|
|
134
|
+
context: VoiceCommandContext;
|
|
135
|
+
channelOverride?: VoiceCommandChannelOverride;
|
|
136
|
+
}): Promise<boolean> {
|
|
137
|
+
const access = await authorizeVoiceCommand(params.interaction, params.context, {
|
|
138
|
+
channelOverride: params.channelOverride,
|
|
139
|
+
});
|
|
140
|
+
if (access.ok) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
await params.interaction.reply({
|
|
144
|
+
content: access.message ?? "Not authorized.",
|
|
145
|
+
ephemeral: true,
|
|
146
|
+
});
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function createDiscordVoiceCommand(params: VoiceCommandContext): CommandWithSubcommands {
|
|
151
|
+
const resolveSessionChannelId = (manager: DiscordVoiceManager, guildId: string) =>
|
|
152
|
+
manager.status().find((entry) => entry.guildId === guildId)?.channelId;
|
|
153
|
+
|
|
154
|
+
class JoinCommand extends Command {
|
|
155
|
+
override name = "join";
|
|
156
|
+
override description = "Join a voice channel";
|
|
157
|
+
override defer = true;
|
|
158
|
+
override ephemeral = params.ephemeralDefault;
|
|
159
|
+
override options: CommandOptions = [
|
|
160
|
+
{
|
|
161
|
+
name: "channel",
|
|
162
|
+
description: "Voice channel to join",
|
|
163
|
+
type: ApplicationCommandOptionType.Channel,
|
|
164
|
+
required: true,
|
|
165
|
+
channel_types: VOICE_CHANNEL_TYPES,
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
async run(interaction: CommandInteraction) {
|
|
170
|
+
const channel = await interaction.options.getChannel("channel", true);
|
|
171
|
+
if (!channel || !("id" in channel)) {
|
|
172
|
+
await interaction.reply({ content: "Voice channel not found.", ephemeral: true });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const access = await authorizeVoiceCommand(interaction, params, {
|
|
177
|
+
channelOverride: {
|
|
178
|
+
id: channel.id,
|
|
179
|
+
name: resolveDiscordChannelNameSafe(channel),
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
if (!access.ok) {
|
|
183
|
+
await interaction.reply({ content: access.message ?? "Not authorized.", ephemeral: true });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!isVoiceChannelType(channel.type)) {
|
|
187
|
+
await interaction.reply({ content: "That is not a voice channel.", ephemeral: true });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const guildId = access.guildId ?? ("guildId" in channel ? channel.guildId : undefined);
|
|
191
|
+
if (!guildId) {
|
|
192
|
+
await interaction.reply({
|
|
193
|
+
content: "Unable to resolve guild for this voice channel.",
|
|
194
|
+
ephemeral: true,
|
|
195
|
+
});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const manager = params.getManager();
|
|
200
|
+
if (!manager) {
|
|
201
|
+
await interaction.reply({
|
|
202
|
+
content: "Voice manager is not available yet.",
|
|
203
|
+
ephemeral: true,
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = await manager.join({ guildId, channelId: channel.id });
|
|
209
|
+
await interaction.reply({ content: result.message, ephemeral: true });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class LeaveCommand extends Command {
|
|
214
|
+
override name = "leave";
|
|
215
|
+
override description = "Leave the current voice channel";
|
|
216
|
+
override defer = true;
|
|
217
|
+
override ephemeral = params.ephemeralDefault;
|
|
218
|
+
|
|
219
|
+
async run(interaction: CommandInteraction) {
|
|
220
|
+
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
221
|
+
if (!runtimeContext) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const sessionChannelId = resolveSessionChannelId(
|
|
225
|
+
runtimeContext.manager,
|
|
226
|
+
runtimeContext.guildId,
|
|
227
|
+
);
|
|
228
|
+
const authorized = await ensureVoiceCommandAccess({
|
|
229
|
+
interaction,
|
|
230
|
+
context: params,
|
|
231
|
+
channelOverride: sessionChannelId ? { id: sessionChannelId } : undefined,
|
|
232
|
+
});
|
|
233
|
+
if (!authorized) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
|
|
237
|
+
await interaction.reply({ content: result.message, ephemeral: true });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
class StatusCommand extends Command {
|
|
242
|
+
override name = "status";
|
|
243
|
+
override description = "Show active voice sessions";
|
|
244
|
+
override defer = true;
|
|
245
|
+
override ephemeral = params.ephemeralDefault;
|
|
246
|
+
|
|
247
|
+
async run(interaction: CommandInteraction) {
|
|
248
|
+
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
249
|
+
if (!runtimeContext) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const sessions = runtimeContext.manager
|
|
253
|
+
.status()
|
|
254
|
+
.filter((entry) => entry.guildId === runtimeContext.guildId);
|
|
255
|
+
const sessionChannelId = sessions[0]?.channelId;
|
|
256
|
+
const authorized = await ensureVoiceCommandAccess({
|
|
257
|
+
interaction,
|
|
258
|
+
context: params,
|
|
259
|
+
channelOverride: sessionChannelId ? { id: sessionChannelId } : undefined,
|
|
260
|
+
});
|
|
261
|
+
if (!authorized) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (sessions.length === 0) {
|
|
265
|
+
await interaction.reply({ content: "No active voice sessions.", ephemeral: true });
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const lines = sessions.map(
|
|
269
|
+
(entry) => `• ${formatMention({ channelId: entry.channelId })} (guild ${entry.guildId})`,
|
|
270
|
+
);
|
|
271
|
+
await interaction.reply({ content: lines.join("\n"), ephemeral: true });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return new (class extends CommandWithSubcommands {
|
|
276
|
+
override name = "vc";
|
|
277
|
+
override description = "Voice channel controls";
|
|
278
|
+
subcommands = [new JoinCommand(), new LeaveCommand(), new StatusCommand()];
|
|
279
|
+
})();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function isVoiceChannelType(type: DiscordChannelType) {
|
|
283
|
+
return type === DiscordChannelType.GuildVoice || type === DiscordChannelType.GuildStageVoice;
|
|
284
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DiscordAccountConfig } from "autobot/plugin-sdk/config-contracts";
|
|
2
|
+
|
|
3
|
+
export function resolveDiscordVoiceEnabled(voice: DiscordAccountConfig["voice"]): boolean {
|
|
4
|
+
if (voice?.enabled !== undefined) {
|
|
5
|
+
return voice.enabled;
|
|
6
|
+
}
|
|
7
|
+
return voice !== undefined;
|
|
8
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { agentCommandFromIngress } from "autobot/plugin-sdk/agent-runtime";
|
|
2
|
+
import type { DiscordAccountConfig, AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
|
|
3
|
+
import { createSubsystemLogger, type RuntimeEnv } from "autobot/plugin-sdk/runtime-env";
|
|
4
|
+
import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
|
|
5
|
+
import { formatMention } from "../mentions.js";
|
|
6
|
+
import { normalizeDiscordSlug } from "../monitor/allow-list.js";
|
|
7
|
+
import { buildDiscordGroupSystemPrompt } from "../monitor/inbound-context.js";
|
|
8
|
+
import { authorizeDiscordVoiceIngress } from "./access.js";
|
|
9
|
+
import type { VoiceSessionEntry } from "./session.js";
|
|
10
|
+
import type { DiscordVoiceSpeakerContextResolver } from "./speaker-context.js";
|
|
11
|
+
|
|
12
|
+
export const DISCORD_VOICE_MESSAGE_PROVIDER = "discord-voice";
|
|
13
|
+
|
|
14
|
+
const logger = createSubsystemLogger("discord/voice");
|
|
15
|
+
|
|
16
|
+
export type DiscordVoiceIngressContext = {
|
|
17
|
+
extraSystemPrompt?: string;
|
|
18
|
+
senderIsOwner: boolean;
|
|
19
|
+
speakerLabel: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type DiscordVoiceAgentTurnResult = {
|
|
23
|
+
context: DiscordVoiceIngressContext;
|
|
24
|
+
text: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function summarizeAgentTurnPayloads(payloads: readonly unknown[]): string {
|
|
28
|
+
let textPayloads = 0;
|
|
29
|
+
let nonEmptyTextPayloads = 0;
|
|
30
|
+
let reasoningPayloads = 0;
|
|
31
|
+
let errorPayloads = 0;
|
|
32
|
+
let mediaPayloads = 0;
|
|
33
|
+
|
|
34
|
+
for (const payload of payloads) {
|
|
35
|
+
if (!payload || typeof payload !== "object") {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const record = payload as Record<string, unknown>;
|
|
39
|
+
const text = record.text;
|
|
40
|
+
if (typeof text === "string") {
|
|
41
|
+
textPayloads += 1;
|
|
42
|
+
if (text.trim()) {
|
|
43
|
+
nonEmptyTextPayloads += 1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (record.isReasoning === true) {
|
|
47
|
+
reasoningPayloads += 1;
|
|
48
|
+
}
|
|
49
|
+
if (record.isError === true) {
|
|
50
|
+
errorPayloads += 1;
|
|
51
|
+
}
|
|
52
|
+
if (
|
|
53
|
+
typeof record.mediaUrl === "string" ||
|
|
54
|
+
(Array.isArray(record.mediaUrls) && record.mediaUrls.length > 0)
|
|
55
|
+
) {
|
|
56
|
+
mediaPayloads += 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return `payloadCount=${payloads.length} textPayloads=${textPayloads} nonEmptyTextPayloads=${nonEmptyTextPayloads} reasoningPayloads=${reasoningPayloads} errorPayloads=${errorPayloads} mediaPayloads=${mediaPayloads}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function resolveDiscordVoiceIngressContext(params: {
|
|
64
|
+
entry: VoiceSessionEntry;
|
|
65
|
+
userId: string;
|
|
66
|
+
cfg: AutoBotConfig;
|
|
67
|
+
discordConfig: DiscordAccountConfig;
|
|
68
|
+
ownerAllowFrom?: string[];
|
|
69
|
+
fetchGuildName: (guildId: string) => Promise<string | undefined>;
|
|
70
|
+
speakerContext: DiscordVoiceSpeakerContextResolver;
|
|
71
|
+
}): Promise<DiscordVoiceIngressContext | null> {
|
|
72
|
+
const { entry, userId } = params;
|
|
73
|
+
if (!entry.guildName) {
|
|
74
|
+
entry.guildName = await params.fetchGuildName(entry.guildId);
|
|
75
|
+
}
|
|
76
|
+
const speaker = await params.speakerContext.resolveContext(entry.guildId, userId);
|
|
77
|
+
const speakerIdentity = await params.speakerContext.resolveIdentity(entry.guildId, userId);
|
|
78
|
+
const access = await authorizeDiscordVoiceIngress({
|
|
79
|
+
cfg: params.cfg,
|
|
80
|
+
discordConfig: params.discordConfig,
|
|
81
|
+
guildName: entry.guildName,
|
|
82
|
+
guildId: entry.guildId,
|
|
83
|
+
channelId: entry.channelId,
|
|
84
|
+
channelName: entry.channelName,
|
|
85
|
+
channelSlug: entry.channelName ? normalizeDiscordSlug(entry.channelName) : "",
|
|
86
|
+
channelLabel: formatMention({ channelId: entry.channelId }),
|
|
87
|
+
memberRoleIds: speakerIdentity.memberRoleIds,
|
|
88
|
+
ownerAllowFrom: params.ownerAllowFrom,
|
|
89
|
+
sender: {
|
|
90
|
+
id: speakerIdentity.id,
|
|
91
|
+
name: speakerIdentity.name,
|
|
92
|
+
tag: speakerIdentity.tag,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
if (!access.ok) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
extraSystemPrompt: buildDiscordGroupSystemPrompt(access.channelConfig),
|
|
100
|
+
senderIsOwner: speaker.senderIsOwner,
|
|
101
|
+
speakerLabel: speaker.label,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function runDiscordVoiceAgentTurn(params: {
|
|
106
|
+
entry: VoiceSessionEntry;
|
|
107
|
+
userId: string;
|
|
108
|
+
message: string;
|
|
109
|
+
cfg: AutoBotConfig;
|
|
110
|
+
discordConfig: DiscordAccountConfig;
|
|
111
|
+
runtime: RuntimeEnv;
|
|
112
|
+
context?: DiscordVoiceIngressContext;
|
|
113
|
+
toolsAllow?: string[];
|
|
114
|
+
ownerAllowFrom?: string[];
|
|
115
|
+
fetchGuildName: (guildId: string) => Promise<string | undefined>;
|
|
116
|
+
speakerContext: DiscordVoiceSpeakerContextResolver;
|
|
117
|
+
}): Promise<DiscordVoiceAgentTurnResult | null> {
|
|
118
|
+
const context =
|
|
119
|
+
params.context ??
|
|
120
|
+
(await resolveDiscordVoiceIngressContext({
|
|
121
|
+
entry: params.entry,
|
|
122
|
+
userId: params.userId,
|
|
123
|
+
cfg: params.cfg,
|
|
124
|
+
discordConfig: params.discordConfig,
|
|
125
|
+
ownerAllowFrom: params.ownerAllowFrom,
|
|
126
|
+
fetchGuildName: params.fetchGuildName,
|
|
127
|
+
speakerContext: params.speakerContext,
|
|
128
|
+
}));
|
|
129
|
+
if (!context) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const voiceModel = normalizeOptionalString(params.discordConfig.voice?.model);
|
|
133
|
+
const result = await agentCommandFromIngress(
|
|
134
|
+
{
|
|
135
|
+
message: params.message,
|
|
136
|
+
sessionKey: params.entry.route.sessionKey,
|
|
137
|
+
agentId: params.entry.route.agentId,
|
|
138
|
+
messageChannel: "discord",
|
|
139
|
+
messageProvider: DISCORD_VOICE_MESSAGE_PROVIDER,
|
|
140
|
+
extraSystemPrompt: context.extraSystemPrompt,
|
|
141
|
+
senderIsOwner: context.senderIsOwner,
|
|
142
|
+
allowModelOverride: Boolean(voiceModel),
|
|
143
|
+
model: voiceModel,
|
|
144
|
+
toolsAllow: params.toolsAllow,
|
|
145
|
+
deliver: false,
|
|
146
|
+
},
|
|
147
|
+
params.runtime,
|
|
148
|
+
);
|
|
149
|
+
const payloads = result.payloads ?? [];
|
|
150
|
+
const text = payloads
|
|
151
|
+
.map((payload) => payload.text)
|
|
152
|
+
.filter((entry) => typeof entry === "string" && entry.trim())
|
|
153
|
+
.join("\n")
|
|
154
|
+
.trim();
|
|
155
|
+
if (!text) {
|
|
156
|
+
logger.info(
|
|
157
|
+
`discord voice: agent turn produced no speakable payloads guild=${params.entry.guildId} channel=${params.entry.channelId} voiceSession=${params.entry.voiceSessionKey} supervisorSession=${params.entry.route.sessionKey} agent=${params.entry.route.agentId} user=${params.userId} ${summarizeAgentTurnPayloads(payloads)}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
context,
|
|
162
|
+
text,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DiscordVoiceManager as DiscordVoiceManagerImpl,
|
|
3
|
+
DiscordVoiceReadyListener as DiscordVoiceReadyListenerImpl,
|
|
4
|
+
DiscordVoiceResumedListener as DiscordVoiceResumedListenerImpl,
|
|
5
|
+
DiscordVoiceStateUpdateListener as DiscordVoiceStateUpdateListenerImpl,
|
|
6
|
+
} from "./manager.js";
|
|
7
|
+
|
|
8
|
+
export class DiscordVoiceManager extends DiscordVoiceManagerImpl {}
|
|
9
|
+
|
|
10
|
+
export class DiscordVoiceReadyListener extends DiscordVoiceReadyListenerImpl {}
|
|
11
|
+
|
|
12
|
+
export class DiscordVoiceResumedListener extends DiscordVoiceResumedListenerImpl {}
|
|
13
|
+
|
|
14
|
+
export class DiscordVoiceStateUpdateListener extends DiscordVoiceStateUpdateListenerImpl {}
|