mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 06:20:22 +00:00
msteams: implement Teams AI agent UX best practices (#51808)
Migrates the Teams extension from @microsoft/agents-hosting to the official Teams SDK (@microsoft/teams.apps + @microsoft/teams.api) and implements Microsoft's AI UX best practices for Teams agents. - AI-generated label on all bot messages (Teams native badge + thumbs up/down) - Streaming responses in 1:1 chats via Teams streaminfo protocol - Welcome card with configurable prompt starters on bot install - Feedback with reflective learning (negative feedback triggers background reflection) - Typing indicators for personal + group chats (disabled for channels) - Informative status updates (progress bar while LLM processes) - JWT validation via Teams SDK createServiceTokenValidator - User-Agent: teams.ts[apps]/<sdk-version> OpenClaw/<version> on outbound requests - Fix copy-pasted image downloads (smba.trafficmanager.net auth allowlist) - Pre-parse auth gate (reject unauthenticated requests before body parsing) - Reflection dispatcher lifecycle fix (prevent leaked dispatchers) - Colon-safe session filenames (Windows compatibility) - Cooldown cache eviction (prevent unbounded memory growth) Closes #51806
This commit is contained in:
@@ -324,6 +324,11 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract clientInfo entity (Teams sends this on every activity with timezone, locale, etc.)
|
||||
const clientInfo = activity.entities?.find((e) => e.type === "clientInfo") as
|
||||
| { timezone?: string; locale?: string; country?: string; platform?: string }
|
||||
| undefined;
|
||||
|
||||
// Build conversation reference for proactive replies.
|
||||
const agent = activity.recipient;
|
||||
const conversationRef: StoredConversationReference = {
|
||||
@@ -340,6 +345,8 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
|
||||
channelId: activity.channelId,
|
||||
serviceUrl: activity.serviceUrl,
|
||||
locale: activity.locale,
|
||||
// Only set timezone if present (preserve previously stored value on next upsert)
|
||||
...(clientInfo?.timezone ? { timezone: clientInfo.timezone } : {}),
|
||||
};
|
||||
conversationStore.upsert(conversationId, conversationRef).catch((err) => {
|
||||
log.debug?.("failed to save conversation reference", {
|
||||
@@ -575,10 +582,26 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
|
||||
sharePointSiteId,
|
||||
});
|
||||
|
||||
// Use Teams clientInfo timezone if no explicit userTimezone is configured.
|
||||
// This ensures the agent knows the sender's timezone for time-aware responses
|
||||
// and proactive sends within the same session.
|
||||
// Apply Teams clientInfo timezone if no explicit userTimezone is configured.
|
||||
const senderTimezone = clientInfo?.timezone || conversationRef.timezone;
|
||||
const effectiveCfg =
|
||||
senderTimezone && !cfg.agents?.defaults?.userTimezone
|
||||
? {
|
||||
...cfg,
|
||||
agents: {
|
||||
...cfg.agents,
|
||||
defaults: { ...cfg.agents?.defaults, userTimezone: senderTimezone },
|
||||
},
|
||||
}
|
||||
: cfg;
|
||||
|
||||
log.info("dispatching to agent", { sessionKey: route.sessionKey });
|
||||
try {
|
||||
const { queuedFinal, counts } = await dispatchReplyFromConfigWithSettledDispatcher({
|
||||
cfg,
|
||||
cfg: effectiveCfg,
|
||||
ctxPayload,
|
||||
dispatcher,
|
||||
onSettled: () => markDispatchIdle(),
|
||||
|
||||
Reference in New Issue
Block a user