11/// <reference types="vite/client" />
22import { describe , expect , test } from "vitest" ;
33import { Agent , createTool , stepCountIs , mockModel } from "@convex-dev/agent" ;
4- import { anyApi , actionGeneric } from "convex/server" ;
5- import type { ApiFromModules , ActionBuilder } from "convex/server" ;
4+ import { anyApi , actionGeneric , mutationGeneric } from "convex/server" ;
5+ import type { ApiFromModules , ActionBuilder , MutationBuilder } from "convex/server" ;
6+ import { v } from "convex/values" ;
67import { components } from "./_generated/api.js" ;
78import { initConvexTest } from "./setup.test.js" ;
89import { z } from "zod/v4" ;
@@ -11,6 +12,7 @@ import { rawRequestResponseHandler } from "./debugging/rawRequestResponseHandler
1112import type { DataModel } from "./_generated/dataModel.js" ;
1213
1314const action = actionGeneric as ActionBuilder < DataModel , "public" > ;
15+ const mutation = mutationGeneric as MutationBuilder < DataModel , "public" > ;
1416
1517// Same tools as the example approval agent
1618const deleteFileTool = createTool ( {
@@ -162,10 +164,10 @@ export const testApproveE2E = action({
162164 ) ;
163165
164166 // Step 2: Approve (same as handleApproval in the example)
165- const { messageId } = await testApprovalAgent . approveToolCall ( ctx , {
166- threadId : thread . threadId ,
167- approvalId : approvalPart . approvalId ,
168- } ) ;
167+ const { messageId } = await ctx . runMutation (
168+ anyApi [ "approval.test" ] . submitApprovalForTestApprovalAgent ,
169+ { threadId : thread . threadId , approvalId : approvalPart . approvalId } ,
170+ ) ;
169171
170172 // Step 3: Continue with streamText (same as handleApproval continuation)
171173 const result2 = await testApprovalAgent . streamText (
@@ -216,11 +218,14 @@ export const testDenyE2E = action({
216218 ( p : any ) => p . type === "tool-approval-request" ,
217219 ) ;
218220
219- const { messageId } = await testDenialAgent . denyToolCall ( ctx , {
220- threadId : thread . threadId ,
221- approvalId : approvalPart . approvalId ,
222- reason : "This file is important" ,
223- } ) ;
221+ const { messageId } = await ctx . runMutation (
222+ anyApi [ "approval.test" ] . submitDenialForTestDenialAgent ,
223+ {
224+ threadId : thread . threadId ,
225+ approvalId : approvalPart . approvalId ,
226+ reason : "This file is important" ,
227+ } ,
228+ ) ;
224229
225230 const result2 = await testDenialAgent . streamText (
226231 ctx ,
@@ -281,12 +286,9 @@ export const testMultiToolApproveE2E = action({
281286 // This is the scenario that requires mergeApprovalResponseMessages.
282287 let lastMessageId : string | undefined ;
283288 for ( const { approvalId } of approvalParts ) {
284- const { messageId } = await testMultiToolApprovalAgent . approveToolCall (
285- ctx ,
286- {
287- threadId : thread . threadId ,
288- approvalId,
289- } ,
289+ const { messageId } = await ctx . runMutation (
290+ anyApi [ "approval.test" ] . submitApprovalForTestMultiToolAgent ,
291+ { threadId : thread . threadId , approvalId } ,
290292 ) ;
291293 lastMessageId = messageId ;
292294 }
@@ -313,11 +315,51 @@ export const testMultiToolApproveE2E = action({
313315 } ,
314316} ) ;
315317
318+ export const submitApprovalForTestApprovalAgent = mutation ( {
319+ args : {
320+ threadId : v . string ( ) ,
321+ approvalId : v . string ( ) ,
322+ reason : v . optional ( v . string ( ) ) ,
323+ } ,
324+ handler : async ( ctx , { threadId, approvalId, reason } ) => {
325+ return testApprovalAgent . approveToolCall ( ctx , { threadId, approvalId, reason } ) ;
326+ } ,
327+ } ) ;
328+
329+ export const submitDenialForTestDenialAgent = mutation ( {
330+ args : {
331+ threadId : v . string ( ) ,
332+ approvalId : v . string ( ) ,
333+ reason : v . optional ( v . string ( ) ) ,
334+ } ,
335+ handler : async ( ctx , { threadId, approvalId, reason } ) => {
336+ return testDenialAgent . denyToolCall ( ctx , { threadId, approvalId, reason } ) ;
337+ } ,
338+ } ) ;
339+
340+ export const submitApprovalForTestMultiToolAgent = mutation ( {
341+ args : {
342+ threadId : v . string ( ) ,
343+ approvalId : v . string ( ) ,
344+ reason : v . optional ( v . string ( ) ) ,
345+ } ,
346+ handler : async ( ctx , { threadId, approvalId, reason } ) => {
347+ return testMultiToolApprovalAgent . approveToolCall ( ctx , {
348+ threadId,
349+ approvalId,
350+ reason,
351+ } ) ;
352+ } ,
353+ } ) ;
354+
316355const testApi : ApiFromModules < {
317356 fns : {
318357 testApproveE2E : typeof testApproveE2E ;
319358 testDenyE2E : typeof testDenyE2E ;
320359 testMultiToolApproveE2E : typeof testMultiToolApproveE2E ;
360+ submitApprovalForTestApprovalAgent : typeof submitApprovalForTestApprovalAgent ;
361+ submitDenialForTestDenialAgent : typeof submitDenialForTestDenialAgent ;
362+ submitApprovalForTestMultiToolAgent : typeof submitApprovalForTestMultiToolAgent ;
321363 } ;
322364} > [ "fns" ] = anyApi [ "approval.test" ] as any ;
323365
0 commit comments