Files
openclaw/extensions/msteams/src/probe.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

78 lines
1.9 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { MSTeamsConfig } from "../runtime-api.js";
const hostMockState = vi.hoisted(() => ({
tokenError: null as Error | null,
}));
vi.mock("@microsoft/teams.apps", () => ({
App: class {
protected async getBotToken() {
if (hostMockState.tokenError) {
throw hostMockState.tokenError;
}
return { value: "token" };
}
protected async getAppGraphToken() {
if (hostMockState.tokenError) {
throw hostMockState.tokenError;
}
return { value: "token" };
}
},
}));
vi.mock("@microsoft/teams.api", () => ({
Client: class {},
}));
import { probeMSTeams } from "./probe.js";
describe("msteams probe", () => {
beforeEach(() => {
hostMockState.tokenError = null;
vi.stubEnv("MSTEAMS_APP_ID", "");
vi.stubEnv("MSTEAMS_APP_PASSWORD", "");
vi.stubEnv("MSTEAMS_TENANT_ID", "");
});
afterEach(() => {
vi.unstubAllEnvs();
});
it("returns an error when credentials are missing", async () => {
const cfg = { enabled: true } as unknown as MSTeamsConfig;
await expect(probeMSTeams(cfg)).resolves.toMatchObject({
ok: false,
});
});
it("validates credentials by acquiring a token", async () => {
const cfg = {
enabled: true,
appId: "app",
appPassword: "pw",
tenantId: "tenant",
} as unknown as MSTeamsConfig;
await expect(probeMSTeams(cfg)).resolves.toMatchObject({
ok: true,
appId: "app",
});
});
it("returns a helpful error when token acquisition fails", async () => {
hostMockState.tokenError = new Error("bad creds");
const cfg = {
enabled: true,
appId: "app",
appPassword: "pw",
tenantId: "tenant",
} as unknown as MSTeamsConfig;
await expect(probeMSTeams(cfg)).resolves.toMatchObject({
ok: false,
appId: "app",
error: "bad creds",
});
});
});