refactor!: rename chat providers to channels
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
||||
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
|
||||
import { agentCommand } from "../../commands/agent.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import {
|
||||
@@ -10,15 +10,14 @@ import {
|
||||
} from "../../config/sessions.js";
|
||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||
import { resolveOutboundTarget } from "../../infra/outbound/targets.js";
|
||||
import { DEFAULT_CHAT_PROVIDER } from "../../providers/registry.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { resolveSendPolicy } from "../../sessions/send-policy.js";
|
||||
import {
|
||||
INTERNAL_MESSAGE_PROVIDER,
|
||||
isDeliverableMessageProvider,
|
||||
isGatewayMessageProvider,
|
||||
normalizeMessageProvider,
|
||||
} from "../../utils/message-provider.js";
|
||||
INTERNAL_MESSAGE_CHANNEL,
|
||||
isDeliverableMessageChannel,
|
||||
isGatewayMessageChannel,
|
||||
normalizeMessageChannel,
|
||||
} from "../../utils/message-channel.js";
|
||||
import { parseMessageWithAttachments } from "../chat-attachments.js";
|
||||
import {
|
||||
type AgentWaitParams,
|
||||
@@ -60,7 +59,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
fileName?: string;
|
||||
content?: unknown;
|
||||
}>;
|
||||
provider?: string;
|
||||
channel?: string;
|
||||
lane?: string;
|
||||
extraSystemPrompt?: string;
|
||||
idempotencyKey: string;
|
||||
@@ -115,21 +114,21 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const rawProvider =
|
||||
typeof request.provider === "string" ? request.provider.trim() : "";
|
||||
if (rawProvider) {
|
||||
const normalized = normalizeMessageProvider(rawProvider);
|
||||
const rawChannel =
|
||||
typeof request.channel === "string" ? request.channel.trim() : "";
|
||||
if (rawChannel) {
|
||||
const normalized = normalizeMessageChannel(rawChannel);
|
||||
if (
|
||||
normalized &&
|
||||
normalized !== "last" &&
|
||||
!isGatewayMessageProvider(normalized)
|
||||
!isGatewayMessageChannel(normalized)
|
||||
) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`invalid agent params: unknown provider: ${normalized}`,
|
||||
`invalid agent params: unknown channel: ${normalized}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -162,7 +161,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
systemSent: entry?.systemSent,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
skillsSnapshot: entry?.skillsSnapshot,
|
||||
lastProvider: entry?.lastProvider,
|
||||
lastChannel: entry?.lastChannel,
|
||||
lastTo: entry?.lastTo,
|
||||
modelOverride: entry?.modelOverride,
|
||||
providerOverride: entry?.providerOverride,
|
||||
@@ -174,7 +173,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
cfg,
|
||||
entry,
|
||||
sessionKey: requestedSessionKey,
|
||||
provider: entry?.provider,
|
||||
channel: entry?.channel,
|
||||
chatType: entry?.chatType,
|
||||
});
|
||||
if (sendPolicy === "deny") {
|
||||
@@ -213,10 +212,9 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
|
||||
const runId = idem;
|
||||
|
||||
const requestedProvider =
|
||||
normalizeMessageProvider(request.provider) ?? "last";
|
||||
const requestedChannel = normalizeMessageChannel(request.channel) ?? "last";
|
||||
|
||||
const lastProvider = sessionEntry?.lastProvider;
|
||||
const lastChannel = sessionEntry?.lastChannel;
|
||||
const lastTo =
|
||||
typeof sessionEntry?.lastTo === "string"
|
||||
? sessionEntry.lastTo.trim()
|
||||
@@ -224,24 +222,22 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
|
||||
const wantsDelivery = request.deliver === true;
|
||||
|
||||
const resolvedProvider = (() => {
|
||||
if (requestedProvider === "last") {
|
||||
const resolvedChannel = (() => {
|
||||
if (requestedChannel === "last") {
|
||||
// WebChat is not a deliverable surface. Treat it as "unset" for routing,
|
||||
// so VoiceWake and CLI callers don't get stuck with deliver=false.
|
||||
if (lastProvider && lastProvider !== INTERNAL_MESSAGE_PROVIDER) {
|
||||
return lastProvider;
|
||||
if (lastChannel && lastChannel !== INTERNAL_MESSAGE_CHANNEL) {
|
||||
return lastChannel;
|
||||
}
|
||||
return wantsDelivery
|
||||
? DEFAULT_CHAT_PROVIDER
|
||||
: INTERNAL_MESSAGE_PROVIDER;
|
||||
return wantsDelivery ? DEFAULT_CHAT_CHANNEL : INTERNAL_MESSAGE_CHANNEL;
|
||||
}
|
||||
|
||||
if (isGatewayMessageProvider(requestedProvider)) return requestedProvider;
|
||||
if (isGatewayMessageChannel(requestedChannel)) return requestedChannel;
|
||||
|
||||
if (lastProvider && lastProvider !== INTERNAL_MESSAGE_PROVIDER) {
|
||||
return lastProvider;
|
||||
if (lastChannel && lastChannel !== INTERNAL_MESSAGE_CHANNEL) {
|
||||
return lastChannel;
|
||||
}
|
||||
return wantsDelivery ? DEFAULT_CHAT_PROVIDER : INTERNAL_MESSAGE_PROVIDER;
|
||||
return wantsDelivery ? DEFAULT_CHAT_CHANNEL : INTERNAL_MESSAGE_CHANNEL;
|
||||
})();
|
||||
|
||||
const explicitTo =
|
||||
@@ -250,18 +246,18 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
: undefined;
|
||||
const deliveryTargetMode = explicitTo
|
||||
? "explicit"
|
||||
: isDeliverableMessageProvider(resolvedProvider)
|
||||
: isDeliverableMessageChannel(resolvedChannel)
|
||||
? "implicit"
|
||||
: undefined;
|
||||
let resolvedTo =
|
||||
explicitTo ||
|
||||
(isDeliverableMessageProvider(resolvedProvider)
|
||||
(isDeliverableMessageChannel(resolvedChannel)
|
||||
? lastTo || undefined
|
||||
: undefined);
|
||||
if (!resolvedTo && isDeliverableMessageProvider(resolvedProvider)) {
|
||||
if (!resolvedTo && isDeliverableMessageChannel(resolvedChannel)) {
|
||||
const cfg = cfgForAgent ?? loadConfig();
|
||||
const fallback = resolveOutboundTarget({
|
||||
provider: resolvedProvider,
|
||||
channel: resolvedChannel,
|
||||
cfg,
|
||||
accountId: sessionEntry?.lastAccountId ?? undefined,
|
||||
mode: "implicit",
|
||||
@@ -272,8 +268,7 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
|
||||
const deliver =
|
||||
request.deliver === true &&
|
||||
resolvedProvider !== INTERNAL_MESSAGE_PROVIDER;
|
||||
request.deliver === true && resolvedChannel !== INTERNAL_MESSAGE_CHANNEL;
|
||||
|
||||
const accepted = {
|
||||
runId,
|
||||
@@ -298,10 +293,10 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
thinking: request.thinking,
|
||||
deliver,
|
||||
deliveryTargetMode,
|
||||
provider: resolvedProvider,
|
||||
channel: resolvedChannel,
|
||||
timeout: request.timeout?.toString(),
|
||||
bestEffortDeliver,
|
||||
messageProvider: resolvedProvider,
|
||||
messageChannel: resolvedChannel,
|
||||
runId,
|
||||
lane: request.lane,
|
||||
extraSystemPrompt: request.extraSystemPrompt,
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import { resolveChannelDefaultAccountId } from "../../channels/plugins/helpers.js";
|
||||
import {
|
||||
type ChannelId,
|
||||
getChannelPlugin,
|
||||
listChannelPlugins,
|
||||
normalizeChannelId,
|
||||
} from "../../channels/plugins/index.js";
|
||||
import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js";
|
||||
import type {
|
||||
ChannelAccountSnapshot,
|
||||
ChannelPlugin,
|
||||
} from "../../channels/plugins/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import { loadConfig, readConfigFileSnapshot } from "../../config/config.js";
|
||||
import { getProviderActivity } from "../../infra/provider-activity.js";
|
||||
import { resolveProviderDefaultAccountId } from "../../providers/plugins/helpers.js";
|
||||
import {
|
||||
getProviderPlugin,
|
||||
listProviderPlugins,
|
||||
normalizeProviderId,
|
||||
type ProviderId,
|
||||
} from "../../providers/plugins/index.js";
|
||||
import { buildProviderAccountSnapshot } from "../../providers/plugins/status.js";
|
||||
import type {
|
||||
ProviderAccountSnapshot,
|
||||
ProviderPlugin,
|
||||
} from "../../providers/plugins/types.js";
|
||||
import { getChannelActivity } from "../../infra/channel-activity.js";
|
||||
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import {
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
formatValidationErrors,
|
||||
validateProvidersLogoutParams,
|
||||
validateProvidersStatusParams,
|
||||
validateChannelsLogoutParams,
|
||||
validateChannelsStatusParams,
|
||||
} from "../protocol/index.js";
|
||||
import { formatForLog } from "../ws-log.js";
|
||||
import type { GatewayRequestContext, GatewayRequestHandlers } from "./types.js";
|
||||
|
||||
type ProviderLogoutPayload = {
|
||||
provider: ProviderId;
|
||||
type ChannelLogoutPayload = {
|
||||
channel: ChannelId;
|
||||
accountId: string;
|
||||
cleared: boolean;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export async function logoutProviderAccount(params: {
|
||||
providerId: ProviderId;
|
||||
export async function logoutChannelAccount(params: {
|
||||
channelId: ChannelId;
|
||||
accountId?: string | null;
|
||||
cfg: ClawdbotConfig;
|
||||
context: GatewayRequestContext;
|
||||
plugin: ProviderPlugin;
|
||||
}): Promise<ProviderLogoutPayload> {
|
||||
plugin: ChannelPlugin;
|
||||
}): Promise<ChannelLogoutPayload> {
|
||||
const resolvedAccountId =
|
||||
params.accountId?.trim() ||
|
||||
params.plugin.config.defaultAccountId?.(params.cfg) ||
|
||||
@@ -48,7 +48,7 @@ export async function logoutProviderAccount(params: {
|
||||
params.cfg,
|
||||
resolvedAccountId,
|
||||
);
|
||||
await params.context.stopProvider(params.providerId, resolvedAccountId);
|
||||
await params.context.stopChannel(params.channelId, resolvedAccountId);
|
||||
const result = await params.plugin.gateway?.logoutAccount?.({
|
||||
cfg: params.cfg,
|
||||
accountId: resolvedAccountId,
|
||||
@@ -56,35 +56,35 @@ export async function logoutProviderAccount(params: {
|
||||
runtime: defaultRuntime,
|
||||
});
|
||||
if (!result) {
|
||||
throw new Error(`Provider ${params.providerId} does not support logout`);
|
||||
throw new Error(`Channel ${params.channelId} does not support logout`);
|
||||
}
|
||||
const cleared = Boolean(result.cleared);
|
||||
const loggedOut =
|
||||
typeof result.loggedOut === "boolean" ? result.loggedOut : cleared;
|
||||
if (loggedOut) {
|
||||
params.context.markProviderLoggedOut(
|
||||
params.providerId,
|
||||
params.context.markChannelLoggedOut(
|
||||
params.channelId,
|
||||
true,
|
||||
resolvedAccountId,
|
||||
);
|
||||
}
|
||||
return {
|
||||
provider: params.providerId,
|
||||
channel: params.channelId,
|
||||
accountId: resolvedAccountId,
|
||||
...result,
|
||||
cleared,
|
||||
};
|
||||
}
|
||||
|
||||
export const providersHandlers: GatewayRequestHandlers = {
|
||||
"providers.status": async ({ params, respond, context }) => {
|
||||
if (!validateProvidersStatusParams(params)) {
|
||||
export const channelsHandlers: GatewayRequestHandlers = {
|
||||
"channels.status": async ({ params, respond, context }) => {
|
||||
if (!validateChannelsStatusParams(params)) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`invalid providers.status params: ${formatValidationErrors(validateProvidersStatusParams.errors)}`,
|
||||
`invalid channels.status params: ${formatValidationErrors(validateChannelsStatusParams.errors)}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -95,18 +95,18 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
typeof timeoutMsRaw === "number" ? Math.max(1000, timeoutMsRaw) : 10_000;
|
||||
const cfg = loadConfig();
|
||||
const runtime = context.getRuntimeSnapshot();
|
||||
const plugins = listProviderPlugins();
|
||||
const pluginMap = new Map<ProviderId, ProviderPlugin>(
|
||||
const plugins = listChannelPlugins();
|
||||
const pluginMap = new Map<ChannelId, ChannelPlugin>(
|
||||
plugins.map((plugin) => [plugin.id, plugin]),
|
||||
);
|
||||
|
||||
const resolveRuntimeSnapshot = (
|
||||
providerId: ProviderId,
|
||||
channelId: ChannelId,
|
||||
accountId: string,
|
||||
defaultAccountId: string,
|
||||
): ProviderAccountSnapshot | undefined => {
|
||||
const accounts = runtime.providerAccounts[providerId];
|
||||
const defaultRuntime = runtime.providers[providerId];
|
||||
): ChannelAccountSnapshot | undefined => {
|
||||
const accounts = runtime.channelAccounts[channelId];
|
||||
const defaultRuntime = runtime.channels[channelId];
|
||||
const raw =
|
||||
accounts?.[accountId] ??
|
||||
(accountId === defaultAccountId ? defaultRuntime : undefined);
|
||||
@@ -114,30 +114,30 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
return raw;
|
||||
};
|
||||
|
||||
const isAccountEnabled = (plugin: ProviderPlugin, account: unknown) =>
|
||||
const isAccountEnabled = (plugin: ChannelPlugin, account: unknown) =>
|
||||
plugin.config.isEnabled
|
||||
? plugin.config.isEnabled(account, cfg)
|
||||
: !account ||
|
||||
typeof account !== "object" ||
|
||||
(account as { enabled?: boolean }).enabled !== false;
|
||||
|
||||
const buildProviderAccounts = async (providerId: ProviderId) => {
|
||||
const plugin = pluginMap.get(providerId);
|
||||
const buildChannelAccounts = async (channelId: ChannelId) => {
|
||||
const plugin = pluginMap.get(channelId);
|
||||
if (!plugin) {
|
||||
return {
|
||||
accounts: [] as ProviderAccountSnapshot[],
|
||||
accounts: [] as ChannelAccountSnapshot[],
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
defaultAccount: undefined as ProviderAccountSnapshot | undefined,
|
||||
defaultAccount: undefined as ChannelAccountSnapshot | undefined,
|
||||
resolvedAccounts: {} as Record<string, unknown>,
|
||||
};
|
||||
}
|
||||
const accountIds = plugin.config.listAccountIds(cfg);
|
||||
const defaultAccountId = resolveProviderDefaultAccountId({
|
||||
const defaultAccountId = resolveChannelDefaultAccountId({
|
||||
plugin,
|
||||
cfg,
|
||||
accountIds,
|
||||
});
|
||||
const accounts: ProviderAccountSnapshot[] = [];
|
||||
const accounts: ChannelAccountSnapshot[] = [];
|
||||
const resolvedAccounts: Record<string, unknown> = {};
|
||||
for (const accountId of accountIds) {
|
||||
const account = plugin.config.resolveAccount(cfg, accountId);
|
||||
@@ -175,11 +175,11 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
}
|
||||
const runtimeSnapshot = resolveRuntimeSnapshot(
|
||||
providerId,
|
||||
channelId,
|
||||
accountId,
|
||||
defaultAccountId,
|
||||
);
|
||||
const snapshot = await buildProviderAccountSnapshot({
|
||||
const snapshot = await buildChannelAccountSnapshot({
|
||||
plugin,
|
||||
cfg,
|
||||
accountId,
|
||||
@@ -188,8 +188,8 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
audit: auditResult,
|
||||
});
|
||||
if (lastProbeAt) snapshot.lastProbeAt = lastProbeAt;
|
||||
const activity = getProviderActivity({
|
||||
provider: providerId as never,
|
||||
const activity = getChannelActivity({
|
||||
channel: channelId as never,
|
||||
accountId,
|
||||
});
|
||||
if (snapshot.lastInboundAt == null) {
|
||||
@@ -208,28 +208,28 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
ts: Date.now(),
|
||||
providerOrder: plugins.map((plugin) => plugin.id),
|
||||
providerLabels: Object.fromEntries(
|
||||
channelOrder: plugins.map((plugin) => plugin.id),
|
||||
channelLabels: Object.fromEntries(
|
||||
plugins.map((plugin) => [plugin.id, plugin.meta.label]),
|
||||
),
|
||||
providers: {} as Record<string, unknown>,
|
||||
providerAccounts: {} as Record<string, unknown>,
|
||||
providerDefaultAccountId: {} as Record<string, unknown>,
|
||||
channels: {} as Record<string, unknown>,
|
||||
channelAccounts: {} as Record<string, unknown>,
|
||||
channelDefaultAccountId: {} as Record<string, unknown>,
|
||||
};
|
||||
const providersMap = payload.providers as Record<string, unknown>;
|
||||
const accountsMap = payload.providerAccounts as Record<string, unknown>;
|
||||
const defaultAccountIdMap = payload.providerDefaultAccountId as Record<
|
||||
const channelsMap = payload.channels as Record<string, unknown>;
|
||||
const accountsMap = payload.channelAccounts as Record<string, unknown>;
|
||||
const defaultAccountIdMap = payload.channelDefaultAccountId as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
for (const plugin of plugins) {
|
||||
const { accounts, defaultAccountId, defaultAccount, resolvedAccounts } =
|
||||
await buildProviderAccounts(plugin.id);
|
||||
await buildChannelAccounts(plugin.id);
|
||||
const fallbackAccount =
|
||||
resolvedAccounts[defaultAccountId] ??
|
||||
plugin.config.resolveAccount(cfg, defaultAccountId);
|
||||
const summary = plugin.status?.buildProviderSummary
|
||||
? await plugin.status.buildProviderSummary({
|
||||
const summary = plugin.status?.buildChannelSummary
|
||||
? await plugin.status.buildChannelSummary({
|
||||
account: fallbackAccount,
|
||||
cfg,
|
||||
defaultAccountId,
|
||||
@@ -237,52 +237,52 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
defaultAccount ??
|
||||
({
|
||||
accountId: defaultAccountId,
|
||||
} as ProviderAccountSnapshot),
|
||||
} as ChannelAccountSnapshot),
|
||||
})
|
||||
: {
|
||||
configured: defaultAccount?.configured ?? false,
|
||||
};
|
||||
providersMap[plugin.id] = summary;
|
||||
channelsMap[plugin.id] = summary;
|
||||
accountsMap[plugin.id] = accounts;
|
||||
defaultAccountIdMap[plugin.id] = defaultAccountId;
|
||||
}
|
||||
|
||||
respond(true, payload, undefined);
|
||||
},
|
||||
"providers.logout": async ({ params, respond, context }) => {
|
||||
if (!validateProvidersLogoutParams(params)) {
|
||||
"channels.logout": async ({ params, respond, context }) => {
|
||||
if (!validateChannelsLogoutParams(params)) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`invalid providers.logout params: ${formatValidationErrors(validateProvidersLogoutParams.errors)}`,
|
||||
`invalid channels.logout params: ${formatValidationErrors(validateChannelsLogoutParams.errors)}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const rawProvider = (params as { provider?: unknown }).provider;
|
||||
const providerId =
|
||||
typeof rawProvider === "string" ? normalizeProviderId(rawProvider) : null;
|
||||
if (!providerId) {
|
||||
const rawChannel = (params as { channel?: unknown }).channel;
|
||||
const channelId =
|
||||
typeof rawChannel === "string" ? normalizeChannelId(rawChannel) : null;
|
||||
if (!channelId) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
"invalid providers.logout provider",
|
||||
"invalid channels.logout channel",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const plugin = getProviderPlugin(providerId);
|
||||
const plugin = getChannelPlugin(channelId);
|
||||
if (!plugin?.gateway?.logoutAccount) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`provider ${providerId} does not support logout`,
|
||||
`channel ${channelId} does not support logout`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -303,8 +303,8 @@ export const providersHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const payload = await logoutProviderAccount({
|
||||
providerId,
|
||||
const payload = await logoutChannelAccount({
|
||||
channelId,
|
||||
accountId,
|
||||
cfg: snapshot.config ?? {},
|
||||
context,
|
||||
@@ -7,7 +7,7 @@ import { mergeSessionEntry, saveSessionStore } from "../../config/sessions.js";
|
||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { resolveSendPolicy } from "../../sessions/send-policy.js";
|
||||
import { INTERNAL_MESSAGE_PROVIDER } from "../../utils/message-provider.js";
|
||||
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
|
||||
import {
|
||||
abortChatRunById,
|
||||
abortChatRunsForSessionKey,
|
||||
@@ -242,7 +242,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
cfg,
|
||||
entry,
|
||||
sessionKey: p.sessionKey,
|
||||
provider: entry?.provider,
|
||||
channel: entry?.channel,
|
||||
chatType: entry?.chatType,
|
||||
});
|
||||
if (sendPolicy === "deny") {
|
||||
@@ -331,7 +331,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
thinking: p.thinking,
|
||||
deliver: p.deliver,
|
||||
timeout: Math.ceil(timeoutMs / 1000).toString(),
|
||||
messageProvider: INTERNAL_MESSAGE_PROVIDER,
|
||||
messageChannel: INTERNAL_MESSAGE_CHANNEL,
|
||||
abortSignal: abortController.signal,
|
||||
},
|
||||
defaultRuntime,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
getChannelPlugin,
|
||||
normalizeChannelId,
|
||||
} from "../../channels/plugins/index.js";
|
||||
import type { ChannelId } from "../../channels/plugins/types.js";
|
||||
import { DEFAULT_CHAT_CHANNEL } from "../../channels/registry.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
|
||||
import type { OutboundProvider } from "../../infra/outbound/targets.js";
|
||||
import type { OutboundChannel } from "../../infra/outbound/targets.js";
|
||||
import { resolveOutboundTarget } from "../../infra/outbound/targets.js";
|
||||
import { normalizePollInput } from "../../polls.js";
|
||||
import {
|
||||
getProviderPlugin,
|
||||
normalizeProviderId,
|
||||
} from "../../providers/plugins/index.js";
|
||||
import type { ProviderId } from "../../providers/plugins/types.js";
|
||||
import { DEFAULT_CHAT_PROVIDER } from "../../providers/registry.js";
|
||||
import {
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
@@ -38,7 +38,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
message: string;
|
||||
mediaUrl?: string;
|
||||
gifPlayback?: boolean;
|
||||
provider?: string;
|
||||
channel?: string;
|
||||
accountId?: string;
|
||||
idempotencyKey: string;
|
||||
};
|
||||
@@ -52,44 +52,44 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
const to = request.to.trim();
|
||||
const message = request.message.trim();
|
||||
const providerInput =
|
||||
typeof request.provider === "string" ? request.provider : undefined;
|
||||
const normalizedProvider = providerInput
|
||||
? normalizeProviderId(providerInput)
|
||||
const channelInput =
|
||||
typeof request.channel === "string" ? request.channel : undefined;
|
||||
const normalizedChannel = channelInput
|
||||
? normalizeChannelId(channelInput)
|
||||
: null;
|
||||
if (providerInput && !normalizedProvider) {
|
||||
if (channelInput && !normalizedChannel) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`unsupported provider: ${providerInput}`,
|
||||
`unsupported channel: ${channelInput}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const provider = normalizedProvider ?? DEFAULT_CHAT_PROVIDER;
|
||||
const channel = normalizedChannel ?? DEFAULT_CHAT_CHANNEL;
|
||||
const accountId =
|
||||
typeof request.accountId === "string" && request.accountId.trim().length
|
||||
? request.accountId.trim()
|
||||
: undefined;
|
||||
try {
|
||||
const outboundProvider = provider as Exclude<OutboundProvider, "none">;
|
||||
const plugin = getProviderPlugin(provider as ProviderId);
|
||||
const outboundChannel = channel as Exclude<OutboundChannel, "none">;
|
||||
const plugin = getChannelPlugin(channel as ChannelId);
|
||||
if (!plugin) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`unsupported provider: ${provider}`,
|
||||
`unsupported channel: ${channel}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const cfg = loadConfig();
|
||||
const resolved = resolveOutboundTarget({
|
||||
provider: outboundProvider,
|
||||
channel: outboundChannel,
|
||||
to,
|
||||
cfg,
|
||||
accountId,
|
||||
@@ -105,7 +105,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
const results = await deliverOutboundPayloads({
|
||||
cfg,
|
||||
provider: outboundProvider,
|
||||
channel: outboundChannel,
|
||||
to: resolved.to,
|
||||
accountId,
|
||||
payloads: [{ text: message, mediaUrl: request.mediaUrl }],
|
||||
@@ -118,7 +118,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
const payload: Record<string, unknown> = {
|
||||
runId: idem,
|
||||
messageId: result.messageId,
|
||||
provider,
|
||||
channel,
|
||||
};
|
||||
if ("chatId" in result) payload.chatId = result.chatId;
|
||||
if ("channelId" in result) payload.channelId = result.channelId;
|
||||
@@ -131,7 +131,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
ok: true,
|
||||
payload,
|
||||
});
|
||||
respond(true, payload, undefined, { provider });
|
||||
respond(true, payload, undefined, { channel });
|
||||
} catch (err) {
|
||||
const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
|
||||
context.dedupe.set(`send:${idem}`, {
|
||||
@@ -139,10 +139,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
ok: false,
|
||||
error,
|
||||
});
|
||||
respond(false, undefined, error, {
|
||||
provider,
|
||||
error: formatForLog(err),
|
||||
});
|
||||
respond(false, undefined, error, { channel, error: formatForLog(err) });
|
||||
}
|
||||
},
|
||||
poll: async ({ params, respond, context }) => {
|
||||
@@ -164,7 +161,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
options: string[];
|
||||
maxSelections?: number;
|
||||
durationHours?: number;
|
||||
provider?: string;
|
||||
channel?: string;
|
||||
accountId?: string;
|
||||
idempotencyKey: string;
|
||||
};
|
||||
@@ -177,23 +174,23 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
const to = request.to.trim();
|
||||
const providerInput =
|
||||
typeof request.provider === "string" ? request.provider : undefined;
|
||||
const normalizedProvider = providerInput
|
||||
? normalizeProviderId(providerInput)
|
||||
const channelInput =
|
||||
typeof request.channel === "string" ? request.channel : undefined;
|
||||
const normalizedChannel = channelInput
|
||||
? normalizeChannelId(channelInput)
|
||||
: null;
|
||||
if (providerInput && !normalizedProvider) {
|
||||
if (channelInput && !normalizedChannel) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`unsupported poll provider: ${providerInput}`,
|
||||
`unsupported poll channel: ${channelInput}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const provider = normalizedProvider ?? DEFAULT_CHAT_PROVIDER;
|
||||
const channel = normalizedChannel ?? DEFAULT_CHAT_CHANNEL;
|
||||
const poll = {
|
||||
question: request.question,
|
||||
options: request.options,
|
||||
@@ -205,7 +202,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
? request.accountId.trim()
|
||||
: undefined;
|
||||
try {
|
||||
const plugin = getProviderPlugin(provider as ProviderId);
|
||||
const plugin = getChannelPlugin(channel as ChannelId);
|
||||
const outbound = plugin?.outbound;
|
||||
if (!outbound?.sendPoll) {
|
||||
respond(
|
||||
@@ -213,14 +210,14 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
`unsupported poll provider: ${provider}`,
|
||||
`unsupported poll channel: ${channel}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const cfg = loadConfig();
|
||||
const resolved = resolveOutboundTarget({
|
||||
provider: provider as Exclude<OutboundProvider, "none">,
|
||||
channel: channel as Exclude<OutboundChannel, "none">,
|
||||
to,
|
||||
cfg,
|
||||
accountId,
|
||||
@@ -246,7 +243,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
const payload: Record<string, unknown> = {
|
||||
runId: idem,
|
||||
messageId: result.messageId,
|
||||
provider,
|
||||
channel,
|
||||
};
|
||||
if (result.toJid) payload.toJid = result.toJid;
|
||||
if (result.channelId) payload.channelId = result.channelId;
|
||||
@@ -257,7 +254,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
ok: true,
|
||||
payload,
|
||||
});
|
||||
respond(true, payload, undefined, { provider });
|
||||
respond(true, payload, undefined, { channel });
|
||||
} catch (err) {
|
||||
const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
|
||||
context.dedupe.set(`poll:${idem}`, {
|
||||
@@ -266,7 +263,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
||||
error,
|
||||
});
|
||||
respond(false, undefined, error, {
|
||||
provider,
|
||||
channel,
|
||||
error: formatForLog(err),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ export const sessionsHandlers: GatewayRequestHandlers = {
|
||||
contextTokens: entry?.contextTokens,
|
||||
sendPolicy: entry?.sendPolicy,
|
||||
label: entry?.label,
|
||||
lastProvider: entry?.lastProvider,
|
||||
lastChannel: entry?.lastChannel,
|
||||
lastTo: entry?.lastTo,
|
||||
skillsSnapshot: entry?.skillsSnapshot,
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
ErrorShape,
|
||||
RequestFrame,
|
||||
} from "../protocol/index.js";
|
||||
import type { ProviderRuntimeSnapshot } from "../server-providers.js";
|
||||
import type { ChannelRuntimeSnapshot } from "../server-channels.js";
|
||||
import type { DedupeEntry } from "../server-shared.js";
|
||||
|
||||
export type GatewayClient = {
|
||||
@@ -68,17 +68,17 @@ export type GatewayRequestContext = {
|
||||
wizardSessions: Map<string, WizardSession>;
|
||||
findRunningWizard: () => string | null;
|
||||
purgeWizardSession: (id: string) => void;
|
||||
getRuntimeSnapshot: () => ProviderRuntimeSnapshot;
|
||||
startProvider: (
|
||||
provider: import("../../providers/plugins/types.js").ProviderId,
|
||||
getRuntimeSnapshot: () => ChannelRuntimeSnapshot;
|
||||
startChannel: (
|
||||
channel: import("../../channels/plugins/types.js").ChannelId,
|
||||
accountId?: string,
|
||||
) => Promise<void>;
|
||||
stopProvider: (
|
||||
provider: import("../../providers/plugins/types.js").ProviderId,
|
||||
stopChannel: (
|
||||
channel: import("../../channels/plugins/types.js").ChannelId,
|
||||
accountId?: string,
|
||||
) => Promise<void>;
|
||||
markProviderLoggedOut: (
|
||||
providerId: import("../../providers/plugins/types.js").ProviderId,
|
||||
markChannelLoggedOut: (
|
||||
channelId: import("../../channels/plugins/types.js").ChannelId,
|
||||
cleared: boolean,
|
||||
accountId?: string,
|
||||
) => void;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { listProviderPlugins } from "../../providers/plugins/index.js";
|
||||
import { listChannelPlugins } from "../../channels/plugins/index.js";
|
||||
import {
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
@@ -12,7 +12,7 @@ import type { GatewayRequestHandlers } from "./types.js";
|
||||
const WEB_LOGIN_METHODS = new Set(["web.login.start", "web.login.wait"]);
|
||||
|
||||
const resolveWebLoginProvider = () =>
|
||||
listProviderPlugins().find((plugin) =>
|
||||
listChannelPlugins().find((plugin) =>
|
||||
(plugin.gatewayMethods ?? []).some((method) =>
|
||||
WEB_LOGIN_METHODS.has(method),
|
||||
),
|
||||
@@ -48,7 +48,7 @@ export const webHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
await context.stopProvider(provider.id, accountId);
|
||||
await context.stopChannel(provider.id, accountId);
|
||||
if (!provider.gateway?.loginWithQrStart) {
|
||||
respond(
|
||||
false,
|
||||
@@ -126,7 +126,7 @@ export const webHandlers: GatewayRequestHandlers = {
|
||||
accountId,
|
||||
});
|
||||
if (result.connected) {
|
||||
await context.startProvider(provider.id, accountId);
|
||||
await context.startChannel(provider.id, accountId);
|
||||
}
|
||||
respond(true, result, undefined);
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user