Files
openclaw/extensions/msteams/src/welcome-card.test.ts
Sid Uppal cd90130877 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
2026-03-23 22:03:39 -07:00

58 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildGroupWelcomeText, buildWelcomeCard } from "./welcome-card.js";
describe("buildWelcomeCard", () => {
it("builds card with default prompt starters", () => {
const card = buildWelcomeCard();
expect(card.type).toBe("AdaptiveCard");
expect(card.version).toBe("1.5");
const body = card.body as Array<{ text: string }>;
expect(body[0]?.text).toContain("OpenClaw");
const actions = card.actions as Array<{ title: string; data: unknown }>;
expect(actions.length).toBe(3);
expect(actions[0]?.title).toBe("What can you do?");
});
it("uses custom bot name", () => {
const card = buildWelcomeCard({ botName: "TestBot" });
const body = card.body as Array<{ text: string }>;
expect(body[0]?.text).toContain("TestBot");
});
it("uses custom prompt starters", () => {
const card = buildWelcomeCard({
promptStarters: ["Do X", "Do Y"],
});
const actions = card.actions as Array<{ title: string; data: unknown }>;
expect(actions.length).toBe(2);
expect(actions[0]?.title).toBe("Do X");
expect(actions[1]?.title).toBe("Do Y");
// Verify imBack data
const data = actions[0]?.data as { msteams: { type: string; value: string } };
expect(data.msteams.type).toBe("imBack");
expect(data.msteams.value).toBe("Do X");
});
it("falls back to defaults when promptStarters is empty", () => {
const card = buildWelcomeCard({ promptStarters: [] });
const actions = card.actions as Array<{ title: string }>;
expect(actions.length).toBe(3);
});
});
describe("buildGroupWelcomeText", () => {
it("includes bot name", () => {
const text = buildGroupWelcomeText("MyBot");
expect(text).toContain("MyBot");
expect(text).toContain("@MyBot");
});
it("defaults to OpenClaw", () => {
const text = buildGroupWelcomeText();
expect(text).toContain("OpenClaw");
});
});