mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 05:12:15 +00:00
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
78 lines
1.9 KiB
TypeScript
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",
|
|
});
|
|
});
|
|
});
|