






















@@ -1,7 +1,251 @@
1-import { describe, expect, it } from "vitest";
1+import { describe, expect, it, vi } from "vitest";
22import { matrixApprovalNativeRuntime } from "./approval-handler.runtime.js";
3344describe("matrixApprovalNativeRuntime", () => {
5+it("sends versioned Matrix approval content with pending exec approvals", async () => {
6+const sendSingleTextMessage = vi.fn().mockResolvedValue({
7+messageId: "$approval",
8+primaryMessageId: "$approval",
9+messageIds: ["$approval"],
10+roomId: "!room:example.org",
11+});
12+const reactMessage = vi.fn().mockResolvedValue(undefined);
13+const pendingPayload = await matrixApprovalNativeRuntime.presentation.buildPendingPayload({
14+cfg: {} as never,
15+accountId: "default",
16+context: { client: {} as never },
17+request: {
18+id: "req-1",
19+request: {
20+command: "echo hi",
21+cwd: "/repo",
22+host: "gateway",
23+agentId: "agent-1",
24+},
25+createdAtMs: 0,
26+expiresAtMs: 1_000,
27+},
28+approvalKind: "exec",
29+nowMs: 100,
30+view: {
31+approvalKind: "exec",
32+approvalId: "req-1",
33+phase: "pending",
34+title: "Exec Approval Required",
35+description: "A command needs your approval.",
36+metadata: [],
37+ask: "on-request",
38+agentId: "agent-1",
39+commandText: "echo hi",
40+commandPreview: "echo hi",
41+cwd: "/repo",
42+host: "gateway",
43+actions: [
44+{
45+decision: "allow-once",
46+label: "Allow Once",
47+style: "success",
48+command: "/approve req-1 allow-once",
49+},
50+{
51+decision: "deny",
52+label: "Deny",
53+style: "danger",
54+command: "/approve req-1 deny",
55+},
56+],
57+expiresAtMs: 1_000,
58+} as never,
59+});
60+61+await matrixApprovalNativeRuntime.transport.deliverPending({
62+cfg: {} as never,
63+accountId: "default",
64+context: {
65+client: {} as never,
66+deps: {
67+ sendSingleTextMessage,
68+ reactMessage,
69+},
70+},
71+request: {} as never,
72+approvalKind: "exec",
73+preparedTarget: {
74+to: "room:!room:example.org",
75+roomId: "!room:example.org",
76+},
77+ pendingPayload,
78+});
79+80+expect(sendSingleTextMessage).toHaveBeenCalledWith(
81+"room:!room:example.org",
82+expect.stringContaining("echo hi"),
83+expect.objectContaining({
84+extraContent: {
85+"com.openclaw.approval": expect.objectContaining({
86+version: 1,
87+type: "approval.request",
88+state: "pending",
89+id: "req-1",
90+kind: "exec",
91+commandText: "echo hi",
92+cwd: "/repo",
93+agentId: "agent-1",
94+allowedDecisions: ["allow-once", "deny"],
95+}),
96+},
97+}),
98+);
99+});
100+101+it("includes plugin approval fields in Matrix approval content", async () => {
102+const pendingPayload = await matrixApprovalNativeRuntime.presentation.buildPendingPayload({
103+cfg: {} as never,
104+accountId: "default",
105+context: { client: {} as never },
106+request: {
107+id: "plugin:req-1",
108+request: {
109+title: "Plugin Approval Required",
110+description: "Approve the tool call.",
111+severity: "critical",
112+toolName: "deploy",
113+pluginId: "ops",
114+agentId: "agent-1",
115+},
116+createdAtMs: 0,
117+expiresAtMs: 1_000,
118+},
119+approvalKind: "plugin",
120+nowMs: 100,
121+view: {
122+approvalKind: "plugin",
123+approvalId: "plugin:req-1",
124+phase: "pending",
125+title: "Plugin Approval Required",
126+description: "Approve the tool call.",
127+metadata: [],
128+agentId: "agent-1",
129+pluginId: "ops",
130+toolName: "deploy",
131+severity: "critical",
132+actions: [
133+{
134+decision: "allow-once",
135+label: "Allow Once",
136+style: "success",
137+command: "/approve plugin:req-1 allow-once",
138+},
139+],
140+expiresAtMs: 1_000,
141+} as never,
142+});
143+144+expect(pendingPayload).toMatchObject({
145+extraContent: {
146+"com.openclaw.approval": {
147+version: 1,
148+type: "approval.request",
149+state: "pending",
150+id: "plugin:req-1",
151+kind: "plugin",
152+pluginId: "ops",
153+toolName: "deploy",
154+agentId: "agent-1",
155+severity: "critical",
156+},
157+},
158+});
159+});
160+161+it("falls back to chunked Matrix delivery when approval content exceeds one event", async () => {
162+const sendSingleTextMessage = vi
163+.fn()
164+.mockRejectedValue(new Error("Matrix single-message text exceeds limit (5000 > 4000)"));
165+const sendMessage = vi.fn().mockResolvedValue({
166+messageId: "$last",
167+primaryMessageId: "$primary",
168+messageIds: ["$primary", "$last"],
169+roomId: "!room:example.org",
170+});
171+const reactMessage = vi.fn().mockResolvedValue(undefined);
172+const pendingPayload = await matrixApprovalNativeRuntime.presentation.buildPendingPayload({
173+cfg: {} as never,
174+accountId: "default",
175+context: { client: {} as never },
176+request: {
177+id: "req-1",
178+request: {
179+command: "echo hi",
180+},
181+createdAtMs: 0,
182+expiresAtMs: 1_000,
183+},
184+approvalKind: "exec",
185+nowMs: 100,
186+view: {
187+approvalKind: "exec",
188+approvalId: "req-1",
189+phase: "pending",
190+title: "Exec Approval Required",
191+description: "A command needs your approval.",
192+metadata: [],
193+commandText: "echo hi",
194+actions: [
195+{
196+decision: "allow-once",
197+label: "Allow Once",
198+style: "success",
199+command: "/approve req-1 allow-once",
200+},
201+],
202+expiresAtMs: 1_000,
203+} as never,
204+});
205+206+const entry = await matrixApprovalNativeRuntime.transport.deliverPending({
207+cfg: {} as never,
208+accountId: "default",
209+context: {
210+client: {} as never,
211+deps: {
212+ sendSingleTextMessage,
213+ sendMessage,
214+ reactMessage,
215+},
216+},
217+request: {} as never,
218+approvalKind: "exec",
219+preparedTarget: {
220+to: "room:!room:example.org",
221+roomId: "!room:example.org",
222+},
223+ pendingPayload,
224+});
225+226+expect(sendMessage).toHaveBeenCalledWith(
227+"room:!room:example.org",
228+pendingPayload.text,
229+expect.objectContaining({
230+accountId: "default",
231+extraContent: pendingPayload.extraContent,
232+}),
233+);
234+expect(reactMessage).toHaveBeenCalledWith(
235+"!room:example.org",
236+"$primary",
237+expect.any(String),
238+expect.objectContaining({
239+accountId: "default",
240+}),
241+);
242+expect(entry).toMatchObject({
243+roomId: "!room:example.org",
244+messageIds: ["$primary", "$last"],
245+reactionEventId: "$primary",
246+});
247+});
248+5249it("uses a longer code fence when resolved commands contain triple backticks", async () => {
6250const result = await matrixApprovalNativeRuntime.presentation.buildResolvedResult({
7251cfg: {} as never,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。