





















@@ -94,12 +94,57 @@ function createActivityHandler() {
9494return { handler, run };
9595}
969697+async function runAdaptiveCardInvoke(
98+registered: MSTeamsActivityHandler & {
99+run: NonNullable<MSTeamsActivityHandler["run"]>;
100+},
101+value: unknown,
102+) {
103+await registered.run({
104+activity: {
105+id: "invoke-1",
106+type: "invoke",
107+name: "adaptiveCard/action",
108+channelId: "msteams",
109+serviceUrl: "https://service.example.test",
110+from: {
111+id: "user-bf",
112+aadObjectId: "user-aad",
113+name: "User",
114+},
115+recipient: {
116+id: "bot-id",
117+name: "Bot",
118+},
119+conversation: {
120+id: "19:personal-chat;messageid=abc123",
121+conversationType: "personal",
122+},
123+channelData: {},
124+attachments: [],
125+ value,
126+},
127+sendActivity: vi.fn(async () => ({ id: "activity-id" })),
128+sendActivities: async () => [],
129+} as unknown as MSTeamsTurnContext);
130+}
131+132+function lastDispatchedCtxPayload(): Record<string, unknown> {
133+const dispatched = runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher.mock.calls.at(
134+-1,
135+)?.[0] as { ctxPayload?: Record<string, unknown> } | undefined;
136+if (!dispatched?.ctxPayload) {
137+throw new Error("expected dispatched context payload");
138+}
139+return dispatched.ctxPayload;
140+}
141+97142describe("msteams adaptive card action invoke", () => {
98143beforeEach(() => {
99144runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher.mockClear();
100145});
101146102-it("forwards adaptive card invoke values to the agent as message text", async () => {
147+it("forwards adaptive card submitted data to the agent as message text", async () => {
103148const deps = createDeps();
104149const { handler, run } = createActivityHandler();
105150const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
@@ -116,44 +161,117 @@ describe("msteams adaptive card action invoke", () => {
116161trigger: "button-click",
117162};
118163119-await registered.run({
120-activity: {
121-id: "invoke-1",
122-type: "invoke",
123-name: "adaptiveCard/action",
124-channelId: "msteams",
125-serviceUrl: "https://service.example.test",
126-from: {
127-id: "user-bf",
128-aadObjectId: "user-aad",
129-name: "User",
130-},
131-recipient: {
132-id: "bot-id",
133-name: "Bot",
134-},
135-conversation: {
136-id: "19:personal-chat;messageid=abc123",
137-conversationType: "personal",
138-},
139-channelData: {},
140-attachments: [],
141-value: payload,
142-},
143-sendActivity: vi.fn(async () => ({ id: "activity-id" })),
144-sendActivities: async () => [],
145-} as unknown as MSTeamsTurnContext);
164+await runAdaptiveCardInvoke(registered, payload);
146165147166expect(run).not.toHaveBeenCalled();
148167expect(runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher).toHaveBeenCalledTimes(
1491681,
150169);
151-const dispatched = runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher.mock
152-.calls[0]?.[0] as { ctxPayload?: Record<string, unknown> } | undefined;
153-expect(dispatched?.ctxPayload?.RawBody).toBe(JSON.stringify(payload));
154-expect(dispatched?.ctxPayload?.BodyForAgent).toBe(JSON.stringify(payload));
155-expect(dispatched?.ctxPayload?.CommandBody).toBe(JSON.stringify(payload));
156-expect(dispatched?.ctxPayload?.SessionKey).toBe("msteams:direct:user-aad");
157-expect(dispatched?.ctxPayload?.SenderId).toBe("user-aad");
170+const expectedBody = JSON.stringify(payload.action.data);
171+const ctxPayload = lastDispatchedCtxPayload();
172+expect(ctxPayload.RawBody).toBe(expectedBody);
173+expect(ctxPayload.BodyForAgent).toBe(expectedBody);
174+expect(ctxPayload.CommandBody).toBe(expectedBody);
175+expect(ctxPayload.SessionKey).toBe("msteams:direct:user-aad");
176+expect(ctxPayload.SenderId).toBe("user-aad");
177+});
178+179+it("routes Teams imBack actions as the submitted message text", async () => {
180+const deps = createDeps();
181+const { handler } = createActivityHandler();
182+const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
183+run: NonNullable<MSTeamsActivityHandler["run"]>;
184+};
185+186+await runAdaptiveCardInvoke(registered, {
187+action: {
188+type: "Action.Submit",
189+data: { msteams: { type: "imBack", value: "Summarize my last meeting" } },
190+},
191+});
192+193+const ctxPayload = lastDispatchedCtxPayload();
194+expect(ctxPayload.BodyForAgent).toBe("Summarize my last meeting");
195+expect(ctxPayload.CommandBody).toBe("Summarize my last meeting");
196+});
197+198+it("routes typed command submit actions as command text", async () => {
199+const deps = createDeps();
200+const { handler } = createActivityHandler();
201+const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
202+run: NonNullable<MSTeamsActivityHandler["run"]>;
203+};
204+205+await runAdaptiveCardInvoke(registered, {
206+action: {
207+type: "Action.Submit",
208+data: "/codex plugins menu",
209+},
210+});
211+212+const ctxPayload = lastDispatchedCtxPayload();
213+expect(ctxPayload.BodyForAgent).toBe("/codex plugins menu");
214+expect(ctxPayload.CommandBody).toBe("/codex plugins menu");
215+});
216+217+it("preserves legacy presentation submit values as structured data", async () => {
218+const deps = createDeps();
219+const { handler } = createActivityHandler();
220+const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
221+run: NonNullable<MSTeamsActivityHandler["run"]>;
222+};
223+const data = { value: "/codex permissions yolo", label: "Run" };
224+225+await runAdaptiveCardInvoke(registered, {
226+action: {
227+type: "Action.Submit",
228+ data,
229+},
230+});
231+232+const ctxPayload = lastDispatchedCtxPayload();
233+expect(ctxPayload.BodyForAgent).toBe(JSON.stringify(data));
234+expect(ctxPayload.CommandBody).toBe(JSON.stringify(data));
235+});
236+237+it("preserves arbitrary submitted data with a value field", async () => {
238+const deps = createDeps();
239+const { handler } = createActivityHandler();
240+const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
241+run: NonNullable<MSTeamsActivityHandler["run"]>;
242+};
243+const data = { value: "selected", formId: "deploy-approval", choices: ["canary"] };
244+245+await runAdaptiveCardInvoke(registered, {
246+action: {
247+type: "Action.Submit",
248+ data,
249+},
250+});
251+252+const ctxPayload = lastDispatchedCtxPayload();
253+expect(ctxPayload.BodyForAgent).toBe(JSON.stringify(data));
254+expect(ctxPayload.CommandBody).toBe(JSON.stringify(data));
255+});
256+257+it("preserves generic Action.Execute verb metadata", async () => {
258+const deps = createDeps();
259+const { handler } = createActivityHandler();
260+const registered = registerMSTeamsHandlers(handler, deps) as MSTeamsActivityHandler & {
261+run: NonNullable<MSTeamsActivityHandler["run"]>;
262+};
263+const payload = {
264+action: {
265+type: "Action.Execute",
266+verb: "ticket.approve",
267+data: { ticketId: "ticket-123" },
268+},
269+};
270+271+await runAdaptiveCardInvoke(registered, payload);
272+273+const ctxPayload = lastDispatchedCtxPayload();
274+expect(ctxPayload.BodyForAgent).toBe(JSON.stringify(payload));
275+expect(ctxPayload.CommandBody).toBe(JSON.stringify(payload));
158276});
159277});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。