feat(msteams): add MS Teams provider skeleton
- Add Microsoft 365 Agents SDK packages (@microsoft/agents-hosting, @microsoft/agents-hosting-express, @microsoft/agents-hosting-extensions-teams) - Add MSTeamsConfig type and zod schema - Create src/msteams/ provider with monitor, token, send, probe - Wire provider into gateway (server-providers.ts, server.ts) - Add msteams to all provider type unions (hooks, queue, cron, etc.) - Update implementation guide with new SDK and progress
This commit is contained in:
@@ -25,7 +25,8 @@ export type HookMappingResolved = {
|
||||
| "discord"
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage";
|
||||
| "imessage"
|
||||
| "msteams";
|
||||
to?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
@@ -65,7 +66,8 @@ export type HookAction =
|
||||
| "discord"
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage";
|
||||
| "imessage"
|
||||
| "msteams";
|
||||
to?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
|
||||
@@ -39,7 +39,8 @@ type HookDispatchers = {
|
||||
| "discord"
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage";
|
||||
| "imessage"
|
||||
| "msteams";
|
||||
to?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
|
||||
@@ -88,6 +88,14 @@ export type IMessageRuntimeStatus = {
|
||||
dbPath?: string | null;
|
||||
};
|
||||
|
||||
export type MSTeamsRuntimeStatus = {
|
||||
running: boolean;
|
||||
lastStartAt?: number | null;
|
||||
lastStopAt?: number | null;
|
||||
lastError?: string | null;
|
||||
port?: number | null;
|
||||
};
|
||||
|
||||
export type ProviderRuntimeSnapshot = {
|
||||
whatsapp: WebProviderStatus;
|
||||
whatsappAccounts?: Record<string, WebProviderStatus>;
|
||||
@@ -101,6 +109,7 @@ export type ProviderRuntimeSnapshot = {
|
||||
signalAccounts?: Record<string, SignalRuntimeStatus>;
|
||||
imessage: IMessageRuntimeStatus;
|
||||
imessageAccounts?: Record<string, IMessageRuntimeStatus>;
|
||||
msteams: MSTeamsRuntimeStatus;
|
||||
};
|
||||
|
||||
type SubsystemLogger = ReturnType<typeof createSubsystemLogger>;
|
||||
@@ -113,12 +122,14 @@ type ProviderManagerOptions = {
|
||||
logSlack: SubsystemLogger;
|
||||
logSignal: SubsystemLogger;
|
||||
logIMessage: SubsystemLogger;
|
||||
logMSTeams: SubsystemLogger;
|
||||
whatsappRuntimeEnv: RuntimeEnv;
|
||||
telegramRuntimeEnv: RuntimeEnv;
|
||||
discordRuntimeEnv: RuntimeEnv;
|
||||
slackRuntimeEnv: RuntimeEnv;
|
||||
signalRuntimeEnv: RuntimeEnv;
|
||||
imessageRuntimeEnv: RuntimeEnv;
|
||||
msteamsRuntimeEnv: RuntimeEnv;
|
||||
};
|
||||
|
||||
export type ProviderManager = {
|
||||
@@ -136,6 +147,8 @@ export type ProviderManager = {
|
||||
stopSignalProvider: (accountId?: string) => Promise<void>;
|
||||
startIMessageProvider: (accountId?: string) => Promise<void>;
|
||||
stopIMessageProvider: (accountId?: string) => Promise<void>;
|
||||
startMSTeamsProvider: () => Promise<void>;
|
||||
stopMSTeamsProvider: () => Promise<void>;
|
||||
markWhatsAppLoggedOut: (cleared: boolean, accountId?: string) => void;
|
||||
};
|
||||
|
||||
@@ -150,12 +163,14 @@ export function createProviderManager(
|
||||
logSlack,
|
||||
logSignal,
|
||||
logIMessage,
|
||||
logMSTeams,
|
||||
whatsappRuntimeEnv,
|
||||
telegramRuntimeEnv,
|
||||
discordRuntimeEnv,
|
||||
slackRuntimeEnv,
|
||||
signalRuntimeEnv,
|
||||
imessageRuntimeEnv,
|
||||
msteamsRuntimeEnv,
|
||||
} = opts;
|
||||
|
||||
const whatsappAborts = new Map<string, AbortController>();
|
||||
@@ -164,7 +179,9 @@ export function createProviderManager(
|
||||
const slackAborts = new Map<string, AbortController>();
|
||||
const signalAborts = new Map<string, AbortController>();
|
||||
const imessageAborts = new Map<string, AbortController>();
|
||||
let msteamsAbort: AbortController | null = null;
|
||||
const whatsappTasks = new Map<string, Promise<unknown>>();
|
||||
let msteamsTask: Promise<unknown> | null = null;
|
||||
const telegramTasks = new Map<string, Promise<unknown>>();
|
||||
const discordTasks = new Map<string, Promise<unknown>>();
|
||||
const slackTasks = new Map<string, Promise<unknown>>();
|
||||
@@ -224,6 +241,13 @@ export function createProviderManager(
|
||||
cliPath: null,
|
||||
dbPath: null,
|
||||
});
|
||||
let msteamsRuntime: MSTeamsRuntimeStatus = {
|
||||
running: false,
|
||||
lastStartAt: null,
|
||||
lastStopAt: null,
|
||||
lastError: null,
|
||||
port: null,
|
||||
};
|
||||
|
||||
const updateWhatsAppStatus = (accountId: string, next: WebProviderStatus) => {
|
||||
whatsappRuntimes.set(accountId, next);
|
||||
@@ -1026,6 +1050,83 @@ export function createProviderManager(
|
||||
);
|
||||
};
|
||||
|
||||
const startMSTeamsProvider = async () => {
|
||||
if (msteamsTask) return;
|
||||
const cfg = loadConfig();
|
||||
if (!cfg.msteams) {
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
running: false,
|
||||
lastError: "not configured",
|
||||
};
|
||||
if (shouldLogVerbose()) {
|
||||
logMSTeams.debug("msteams provider not configured (no msteams config)");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cfg.msteams?.enabled === false) {
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
running: false,
|
||||
lastError: "disabled",
|
||||
};
|
||||
if (shouldLogVerbose()) {
|
||||
logMSTeams.debug("msteams provider disabled (msteams.enabled=false)");
|
||||
}
|
||||
return;
|
||||
}
|
||||
const { monitorMSTeamsProvider } = await import("../msteams/index.js");
|
||||
const port = cfg.msteams?.webhook?.port ?? 3978;
|
||||
logMSTeams.info(`starting provider (port ${port})`);
|
||||
msteamsAbort = new AbortController();
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
running: true,
|
||||
lastStartAt: Date.now(),
|
||||
lastError: null,
|
||||
port,
|
||||
};
|
||||
const task = monitorMSTeamsProvider({
|
||||
cfg,
|
||||
runtime: msteamsRuntimeEnv,
|
||||
abortSignal: msteamsAbort.signal,
|
||||
})
|
||||
.catch((err) => {
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
lastError: formatError(err),
|
||||
};
|
||||
logMSTeams.error(`provider exited: ${formatError(err)}`);
|
||||
})
|
||||
.finally(() => {
|
||||
msteamsAbort = null;
|
||||
msteamsTask = null;
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
running: false,
|
||||
lastStopAt: Date.now(),
|
||||
};
|
||||
});
|
||||
msteamsTask = task;
|
||||
};
|
||||
|
||||
const stopMSTeamsProvider = async () => {
|
||||
if (!msteamsAbort && !msteamsTask) return;
|
||||
msteamsAbort?.abort();
|
||||
try {
|
||||
await msteamsTask;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
msteamsAbort = null;
|
||||
msteamsTask = null;
|
||||
msteamsRuntime = {
|
||||
...msteamsRuntime,
|
||||
running: false,
|
||||
lastStopAt: Date.now(),
|
||||
};
|
||||
};
|
||||
|
||||
const startProviders = async () => {
|
||||
await startWhatsAppProvider();
|
||||
await startDiscordProvider();
|
||||
@@ -1033,6 +1134,7 @@ export function createProviderManager(
|
||||
await startTelegramProvider();
|
||||
await startSignalProvider();
|
||||
await startIMessageProvider();
|
||||
await startMSTeamsProvider();
|
||||
};
|
||||
|
||||
const markWhatsAppLoggedOut = (cleared: boolean, accountId?: string) => {
|
||||
@@ -1180,6 +1282,7 @@ export function createProviderManager(
|
||||
signalAccounts,
|
||||
imessage,
|
||||
imessageAccounts,
|
||||
msteams: { ...msteamsRuntime },
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1198,6 +1301,8 @@ export function createProviderManager(
|
||||
stopSignalProvider,
|
||||
startIMessageProvider,
|
||||
stopIMessageProvider,
|
||||
startMSTeamsProvider,
|
||||
stopMSTeamsProvider,
|
||||
markWhatsAppLoggedOut,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ const logDiscord = logProviders.child("discord");
|
||||
const logSlack = logProviders.child("slack");
|
||||
const logSignal = logProviders.child("signal");
|
||||
const logIMessage = logProviders.child("imessage");
|
||||
const logMSTeams = logProviders.child("msteams");
|
||||
const canvasRuntime = runtimeForLogger(logCanvas);
|
||||
const whatsappRuntimeEnv = runtimeForLogger(logWhatsApp);
|
||||
const telegramRuntimeEnv = runtimeForLogger(logTelegram);
|
||||
@@ -190,6 +191,7 @@ const discordRuntimeEnv = runtimeForLogger(logDiscord);
|
||||
const slackRuntimeEnv = runtimeForLogger(logSlack);
|
||||
const signalRuntimeEnv = runtimeForLogger(logSignal);
|
||||
const imessageRuntimeEnv = runtimeForLogger(logIMessage);
|
||||
const msteamsRuntimeEnv = runtimeForLogger(logMSTeams);
|
||||
|
||||
type GatewayModelChoice = ModelCatalogEntry;
|
||||
|
||||
@@ -501,7 +503,8 @@ export async function startGatewayServer(
|
||||
| "discord"
|
||||
| "slack"
|
||||
| "signal"
|
||||
| "imessage";
|
||||
| "imessage"
|
||||
| "msteams";
|
||||
to?: string;
|
||||
model?: string;
|
||||
thinking?: string;
|
||||
@@ -756,12 +759,14 @@ export async function startGatewayServer(
|
||||
logSlack,
|
||||
logSignal,
|
||||
logIMessage,
|
||||
logMSTeams,
|
||||
whatsappRuntimeEnv,
|
||||
telegramRuntimeEnv,
|
||||
discordRuntimeEnv,
|
||||
slackRuntimeEnv,
|
||||
signalRuntimeEnv,
|
||||
imessageRuntimeEnv,
|
||||
msteamsRuntimeEnv,
|
||||
});
|
||||
const {
|
||||
getRuntimeSnapshot,
|
||||
@@ -772,12 +777,14 @@ export async function startGatewayServer(
|
||||
startSlackProvider,
|
||||
startSignalProvider,
|
||||
startIMessageProvider,
|
||||
startMSTeamsProvider,
|
||||
stopWhatsAppProvider,
|
||||
stopTelegramProvider,
|
||||
stopDiscordProvider,
|
||||
stopSlackProvider,
|
||||
stopSignalProvider,
|
||||
stopIMessageProvider,
|
||||
stopMSTeamsProvider,
|
||||
markWhatsAppLoggedOut,
|
||||
} = providerManager;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user