feat(msteams): add outbound sends and fix reply delivery
- Add sendMessageMSTeams for proactive messaging via CLI/gateway - Wire msteams into outbound delivery, heartbeat targets, and gateway send - Fix reply delivery to use SDK's getConversationReference() for proper bot info, avoiding "Activity Recipient undefined" errors - Use proactive messaging for replies to post as top-level messages (not threaded) by omitting activityId from conversation reference - Add lazy logger in send.ts to avoid test initialization issues
This commit is contained in:
@@ -7,6 +7,7 @@ import type { ReplyPayload } from "../../auto-reply/types.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import { sendMessageDiscord } from "../../discord/send.js";
|
||||
import { sendMessageIMessage } from "../../imessage/send.js";
|
||||
import { sendMessageMSTeams } from "../../msteams/send.js";
|
||||
import { normalizeAccountId } from "../../routing/session-key.js";
|
||||
import { sendMessageSignal } from "../../signal/send.js";
|
||||
import { sendMessageSlack } from "../../slack/send.js";
|
||||
@@ -28,6 +29,11 @@ export type OutboundSendDeps = {
|
||||
sendSlack?: typeof sendMessageSlack;
|
||||
sendSignal?: typeof sendMessageSignal;
|
||||
sendIMessage?: typeof sendMessageIMessage;
|
||||
sendMSTeams?: (
|
||||
to: string,
|
||||
text: string,
|
||||
opts?: { mediaUrl?: string },
|
||||
) => Promise<{ messageId: string; conversationId: string }>;
|
||||
};
|
||||
|
||||
export type OutboundDeliveryResult =
|
||||
@@ -36,7 +42,8 @@ export type OutboundDeliveryResult =
|
||||
| { provider: "discord"; messageId: string; channelId: string }
|
||||
| { provider: "slack"; messageId: string; channelId: string }
|
||||
| { provider: "signal"; messageId: string; timestamp?: number }
|
||||
| { provider: "imessage"; messageId: string };
|
||||
| { provider: "imessage"; messageId: string }
|
||||
| { provider: "msteams"; messageId: string; conversationId: string };
|
||||
|
||||
type Chunker = (text: string, limit: number) => string[];
|
||||
|
||||
@@ -50,6 +57,7 @@ const providerCaps: Record<
|
||||
slack: { chunker: null },
|
||||
signal: { chunker: chunkText },
|
||||
imessage: { chunker: chunkText },
|
||||
msteams: { chunker: chunkMarkdownText },
|
||||
};
|
||||
|
||||
type ProviderHandler = {
|
||||
@@ -204,6 +212,17 @@ function createProviderHandler(params: {
|
||||
})),
|
||||
}),
|
||||
},
|
||||
msteams: {
|
||||
chunker: providerCaps.msteams.chunker,
|
||||
sendText: async (text) => ({
|
||||
provider: "msteams",
|
||||
...(await deps.sendMSTeams(to, text)),
|
||||
}),
|
||||
sendMedia: async (caption, mediaUrl) => ({
|
||||
provider: "msteams",
|
||||
...(await deps.sendMSTeams(to, caption, { mediaUrl })),
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
return handlers[params.provider];
|
||||
@@ -222,6 +241,11 @@ export async function deliverOutboundPayloads(params: {
|
||||
}): Promise<OutboundDeliveryResult[]> {
|
||||
const { cfg, provider, to, payloads } = params;
|
||||
const accountId = params.accountId;
|
||||
const defaultSendMSTeams = async (
|
||||
to: string,
|
||||
text: string,
|
||||
opts?: { mediaUrl?: string },
|
||||
) => sendMessageMSTeams({ cfg, to, text, mediaUrl: opts?.mediaUrl });
|
||||
const deps = {
|
||||
sendWhatsApp: params.deps?.sendWhatsApp ?? sendMessageWhatsApp,
|
||||
sendTelegram: params.deps?.sendTelegram ?? sendMessageTelegram,
|
||||
@@ -229,6 +253,7 @@ export async function deliverOutboundPayloads(params: {
|
||||
sendSlack: params.deps?.sendSlack ?? sendMessageSlack,
|
||||
sendSignal: params.deps?.sendSignal ?? sendMessageSignal,
|
||||
sendIMessage: params.deps?.sendIMessage ?? sendMessageIMessage,
|
||||
sendMSTeams: params.deps?.sendMSTeams ?? defaultSendMSTeams,
|
||||
};
|
||||
const results: OutboundDeliveryResult[] = [];
|
||||
const handler = createProviderHandler({
|
||||
|
||||
@@ -9,6 +9,7 @@ export type OutboundProvider =
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage"
|
||||
| "msteams"
|
||||
| "none";
|
||||
|
||||
export type HeartbeatTarget = OutboundProvider | "last";
|
||||
@@ -31,6 +32,7 @@ export function resolveOutboundTarget(params: {
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage"
|
||||
| "msteams"
|
||||
| "webchat";
|
||||
to?: string;
|
||||
allowFrom?: string[];
|
||||
@@ -104,6 +106,17 @@ export function resolveOutboundTarget(params: {
|
||||
}
|
||||
return { ok: true, to: trimmed };
|
||||
}
|
||||
if (params.provider === "msteams") {
|
||||
if (!trimmed) {
|
||||
return {
|
||||
ok: false,
|
||||
error: new Error(
|
||||
"Delivering to MS Teams requires --to <conversationId|user:ID|conversation:ID>",
|
||||
),
|
||||
};
|
||||
}
|
||||
return { ok: true, to: trimmed };
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
error: new Error(
|
||||
@@ -125,6 +138,7 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
rawTarget === "slack" ||
|
||||
rawTarget === "signal" ||
|
||||
rawTarget === "imessage" ||
|
||||
rawTarget === "msteams" ||
|
||||
rawTarget === "none" ||
|
||||
rawTarget === "last"
|
||||
? rawTarget
|
||||
@@ -152,6 +166,7 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage"
|
||||
| "msteams"
|
||||
| undefined =
|
||||
target === "last"
|
||||
? lastProvider
|
||||
@@ -160,7 +175,8 @@ export function resolveHeartbeatDeliveryTarget(params: {
|
||||
target === "discord" ||
|
||||
target === "slack" ||
|
||||
target === "signal" ||
|
||||
target === "imessage"
|
||||
target === "imessage" ||
|
||||
target === "msteams"
|
||||
? target
|
||||
: undefined;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user