mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-06 23:11:21 +08:00
refactor: replace copy with set alias
This commit is contained in:
@@ -61,9 +61,25 @@ func (s *MCPServer4XTDriver) GetToolByAction(actionMethod option.ActionName) Act
|
|||||||
if s.actionToolMap == nil {
|
if s.actionToolMap == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
actionMethod = getActionNameByAlias(actionMethod)
|
||||||
return s.actionToolMap[actionMethod]
|
return s.actionToolMap[actionMethod]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getActionNameByAlias(actionMethod option.ActionName) option.ActionName {
|
||||||
|
switch strings.ToLower(string(actionMethod)) {
|
||||||
|
case "terminal_app":
|
||||||
|
return option.ACTION_AppTerminate
|
||||||
|
case "open_app":
|
||||||
|
return option.ACTION_AppLaunch
|
||||||
|
case "text":
|
||||||
|
return option.ACTION_Input
|
||||||
|
case "tap":
|
||||||
|
return option.ACTION_TapXY
|
||||||
|
default:
|
||||||
|
return actionMethod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// registerTools registers all MCP tools.
|
// registerTools registers all MCP tools.
|
||||||
func (s *MCPServer4XTDriver) registerTools() {
|
func (s *MCPServer4XTDriver) registerTools() {
|
||||||
// Device Tool
|
// Device Tool
|
||||||
@@ -71,7 +87,6 @@ func (s *MCPServer4XTDriver) registerTools() {
|
|||||||
s.registerTool(&ToolSelectDevice{}) // SelectDevice
|
s.registerTool(&ToolSelectDevice{}) // SelectDevice
|
||||||
|
|
||||||
// Touch Tools
|
// Touch Tools
|
||||||
s.registerTool(&ToolTap{}) // tap
|
|
||||||
s.registerTool(&ToolTapXY{}) // tap xy
|
s.registerTool(&ToolTapXY{}) // tap xy
|
||||||
s.registerTool(&ToolTapAbsXY{}) // tap abs xy
|
s.registerTool(&ToolTapAbsXY{}) // tap abs xy
|
||||||
s.registerTool(&ToolTapByOCR{}) // tap by OCR
|
s.registerTool(&ToolTapByOCR{}) // tap by OCR
|
||||||
@@ -89,7 +104,6 @@ func (s *MCPServer4XTDriver) registerTools() {
|
|||||||
|
|
||||||
// Input Tools
|
// Input Tools
|
||||||
s.registerTool(&ToolInput{})
|
s.registerTool(&ToolInput{})
|
||||||
s.registerTool(&ToolText{})
|
|
||||||
s.registerTool(&ToolBackspace{})
|
s.registerTool(&ToolBackspace{})
|
||||||
s.registerTool(&ToolSetIme{})
|
s.registerTool(&ToolSetIme{})
|
||||||
|
|
||||||
@@ -101,9 +115,7 @@ func (s *MCPServer4XTDriver) registerTools() {
|
|||||||
// App Tools
|
// App Tools
|
||||||
s.registerTool(&ToolListPackages{}) // ListPackages
|
s.registerTool(&ToolListPackages{}) // ListPackages
|
||||||
s.registerTool(&ToolLaunchApp{}) // LaunchApp
|
s.registerTool(&ToolLaunchApp{}) // LaunchApp
|
||||||
s.registerTool(&ToolOpenApp{}) // OpenApp
|
|
||||||
s.registerTool(&ToolTerminateApp{}) // TerminateApp
|
s.registerTool(&ToolTerminateApp{}) // TerminateApp
|
||||||
s.registerTool(&ToolTerminateAppNew{}) // TerminateApp (new)
|
|
||||||
s.registerTool(&ToolColdLaunch{}) // ColdLaunch
|
s.registerTool(&ToolColdLaunch{}) // ColdLaunch
|
||||||
s.registerTool(&ToolAppInstall{}) // AppInstall
|
s.registerTool(&ToolAppInstall{}) // AppInstall
|
||||||
s.registerTool(&ToolAppUninstall{}) // AppUninstall
|
s.registerTool(&ToolAppUninstall{}) // AppUninstall
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ func TestToolInterfaces(t *testing.T) {
|
|||||||
tools := []ActionTool{
|
tools := []ActionTool{
|
||||||
&ToolListAvailableDevices{},
|
&ToolListAvailableDevices{},
|
||||||
&ToolSelectDevice{},
|
&ToolSelectDevice{},
|
||||||
&ToolTap{},
|
|
||||||
&ToolTapXY{},
|
&ToolTapXY{},
|
||||||
&ToolTapAbsXY{},
|
&ToolTapAbsXY{},
|
||||||
&ToolTapByOCR{},
|
&ToolTapByOCR{},
|
||||||
@@ -93,7 +92,6 @@ func TestToolInterfaces(t *testing.T) {
|
|||||||
&ToolSwipeToTapTexts{},
|
&ToolSwipeToTapTexts{},
|
||||||
&ToolDrag{},
|
&ToolDrag{},
|
||||||
&ToolInput{},
|
&ToolInput{},
|
||||||
&ToolText{},
|
|
||||||
&ToolBackspace{},
|
&ToolBackspace{},
|
||||||
&ToolScreenShot{},
|
&ToolScreenShot{},
|
||||||
&ToolGetScreenSize{},
|
&ToolGetScreenSize{},
|
||||||
@@ -102,9 +100,7 @@ func TestToolInterfaces(t *testing.T) {
|
|||||||
&ToolBack{},
|
&ToolBack{},
|
||||||
&ToolListPackages{},
|
&ToolListPackages{},
|
||||||
&ToolLaunchApp{},
|
&ToolLaunchApp{},
|
||||||
&ToolOpenApp{},
|
|
||||||
&ToolTerminateApp{},
|
&ToolTerminateApp{},
|
||||||
&ToolTerminateAppNew{},
|
|
||||||
&ToolColdLaunch{},
|
&ToolColdLaunch{},
|
||||||
&ToolAppInstall{},
|
&ToolAppInstall{},
|
||||||
&ToolAppUninstall{},
|
&ToolAppUninstall{},
|
||||||
@@ -246,45 +242,6 @@ func TestToolSelectDevice(t *testing.T) {
|
|||||||
assert.Equal(t, string(option.ACTION_SelectDevice), request.Params.Name)
|
assert.Equal(t, string(option.ACTION_SelectDevice), request.Params.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestToolTap tests the ToolTap implementation
|
|
||||||
func TestToolTap(t *testing.T) {
|
|
||||||
tool := &ToolTap{}
|
|
||||||
|
|
||||||
// Test Name
|
|
||||||
assert.Equal(t, option.ACTION_Tap, tool.Name())
|
|
||||||
|
|
||||||
// Test Description
|
|
||||||
assert.NotEmpty(t, tool.Description())
|
|
||||||
|
|
||||||
// Test Options
|
|
||||||
options := tool.Options()
|
|
||||||
assert.NotNil(t, options)
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with valid params
|
|
||||||
action := option.MobileAction{
|
|
||||||
Method: option.ACTION_Tap,
|
|
||||||
Params: []float64{0.5, 0.6},
|
|
||||||
ActionOptions: option.ActionOptions{
|
|
||||||
Duration: 1.5,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
request, err := tool.ConvertActionToCallToolRequest(action)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, string(option.ACTION_Tap), request.Params.Name)
|
|
||||||
args := request.GetArguments()
|
|
||||||
assert.Equal(t, 0.5, args["x"])
|
|
||||||
assert.Equal(t, 0.6, args["y"])
|
|
||||||
assert.Equal(t, 1.5, args["duration"])
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with invalid params
|
|
||||||
invalidAction := option.MobileAction{
|
|
||||||
Method: option.ACTION_Tap,
|
|
||||||
Params: "invalid",
|
|
||||||
}
|
|
||||||
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestToolTapXY tests the ToolTapXY implementation
|
// TestToolTapXY tests the ToolTapXY implementation
|
||||||
func TestToolTapXY(t *testing.T) {
|
func TestToolTapXY(t *testing.T) {
|
||||||
tool := &ToolTapXY{}
|
tool := &ToolTapXY{}
|
||||||
@@ -827,31 +784,6 @@ func TestToolInput(t *testing.T) {
|
|||||||
assert.Equal(t, "Hello World", request.GetArguments()["text"])
|
assert.Equal(t, "Hello World", request.GetArguments()["text"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestToolText tests the ToolText implementation
|
|
||||||
func TestToolText(t *testing.T) {
|
|
||||||
tool := &ToolText{}
|
|
||||||
|
|
||||||
// Test Name
|
|
||||||
assert.Equal(t, option.ACTION_Text, tool.Name())
|
|
||||||
|
|
||||||
// Test Description
|
|
||||||
assert.NotEmpty(t, tool.Description())
|
|
||||||
|
|
||||||
// Test Options
|
|
||||||
options := tool.Options()
|
|
||||||
assert.NotNil(t, options)
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with valid params
|
|
||||||
action := option.MobileAction{
|
|
||||||
Method: option.ACTION_Text,
|
|
||||||
Params: "Hello World",
|
|
||||||
}
|
|
||||||
request, err := tool.ConvertActionToCallToolRequest(action)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, string(option.ACTION_Text), request.Params.Name)
|
|
||||||
assert.Equal(t, "Hello World", request.GetArguments()["text"])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestToolBackspace tests the ToolBackspace implementation
|
// TestToolBackspace tests the ToolBackspace implementation
|
||||||
func TestToolBackspace(t *testing.T) {
|
func TestToolBackspace(t *testing.T) {
|
||||||
tool := &ToolBackspace{}
|
tool := &ToolBackspace{}
|
||||||
@@ -1086,39 +1018,6 @@ func TestToolLaunchApp(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestToolOpenApp tests the ToolOpenApp implementation
|
|
||||||
func TestToolOpenApp(t *testing.T) {
|
|
||||||
tool := &ToolOpenApp{}
|
|
||||||
|
|
||||||
// Test Name
|
|
||||||
assert.Equal(t, option.ACTION_OpenApp, tool.Name())
|
|
||||||
|
|
||||||
// Test Description
|
|
||||||
assert.NotEmpty(t, tool.Description())
|
|
||||||
|
|
||||||
// Test Options
|
|
||||||
options := tool.Options()
|
|
||||||
assert.NotNil(t, options)
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with valid params
|
|
||||||
action := option.MobileAction{
|
|
||||||
Method: option.ACTION_OpenApp,
|
|
||||||
Params: "com.example.app",
|
|
||||||
}
|
|
||||||
request, err := tool.ConvertActionToCallToolRequest(action)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, string(option.ACTION_OpenApp), request.Params.Name)
|
|
||||||
assert.Equal(t, "com.example.app", request.GetArguments()["packageName"])
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with invalid params
|
|
||||||
invalidAction := option.MobileAction{
|
|
||||||
Method: option.ACTION_OpenApp,
|
|
||||||
Params: 123, // should be string
|
|
||||||
}
|
|
||||||
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestToolTerminateApp tests the ToolTerminateApp implementation
|
// TestToolTerminateApp tests the ToolTerminateApp implementation
|
||||||
func TestToolTerminateApp(t *testing.T) {
|
func TestToolTerminateApp(t *testing.T) {
|
||||||
tool := &ToolTerminateApp{}
|
tool := &ToolTerminateApp{}
|
||||||
@@ -1152,39 +1051,6 @@ func TestToolTerminateApp(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestToolTerminateAppNew tests the ToolTerminateAppNew implementation
|
|
||||||
func TestToolTerminateAppNew(t *testing.T) {
|
|
||||||
tool := &ToolTerminateAppNew{}
|
|
||||||
|
|
||||||
// Test Name
|
|
||||||
assert.Equal(t, option.ACTION_TerminateApp, tool.Name())
|
|
||||||
|
|
||||||
// Test Description
|
|
||||||
assert.NotEmpty(t, tool.Description())
|
|
||||||
|
|
||||||
// Test Options
|
|
||||||
options := tool.Options()
|
|
||||||
assert.NotNil(t, options)
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with valid params
|
|
||||||
action := option.MobileAction{
|
|
||||||
Method: option.ACTION_TerminateApp,
|
|
||||||
Params: "com.example.app",
|
|
||||||
}
|
|
||||||
request, err := tool.ConvertActionToCallToolRequest(action)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, string(option.ACTION_TerminateApp), request.Params.Name)
|
|
||||||
assert.Equal(t, "com.example.app", request.GetArguments()["packageName"])
|
|
||||||
|
|
||||||
// Test ConvertActionToCallToolRequest with invalid params
|
|
||||||
invalidAction := option.MobileAction{
|
|
||||||
Method: option.ACTION_TerminateApp,
|
|
||||||
Params: []int{1, 2, 3}, // should be string
|
|
||||||
}
|
|
||||||
_, err = tool.ConvertActionToCallToolRequest(invalidAction)
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestToolColdLaunch tests the ToolColdLaunch implementation
|
// TestToolColdLaunch tests the ToolColdLaunch implementation
|
||||||
func TestToolColdLaunch(t *testing.T) {
|
func TestToolColdLaunch(t *testing.T) {
|
||||||
tool := &ToolColdLaunch{}
|
tool := &ToolColdLaunch{}
|
||||||
|
|||||||
@@ -395,131 +395,6 @@ func (t *ToolGetForegroundApp) ConvertActionToCallToolRequest(action option.Mobi
|
|||||||
return BuildMCPCallToolRequest(t.Name(), map[string]any{}, action), nil
|
return BuildMCPCallToolRequest(t.Name(), map[string]any{}, action), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToolOpenApp implements the open_app tool call.
|
|
||||||
type ToolOpenApp struct {
|
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
|
||||||
PackageName string `json:"packageName" desc:"Package name of the opened app"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolOpenApp) Name() option.ActionName {
|
|
||||||
return option.ACTION_OpenApp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolOpenApp) Description() string {
|
|
||||||
return "Open an app on mobile device using its package name and wait for the app to load"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolOpenApp) Options() []mcp.ToolOption {
|
|
||||||
unifiedReq := &option.ActionOptions{}
|
|
||||||
return unifiedReq.GetMCPOptions(option.ACTION_OpenApp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolOpenApp) Implement() server.ToolHandlerFunc {
|
|
||||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
arguments := request.GetArguments()
|
|
||||||
driverExt, err := setupXTDriver(ctx, arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setup driver failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unifiedReq, err := parseActionOptions(arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if unifiedReq.PackageName == "" {
|
|
||||||
return nil, fmt.Errorf("package_name is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open app action logic
|
|
||||||
err = driverExt.AppLaunch(unifiedReq.PackageName)
|
|
||||||
if err != nil {
|
|
||||||
return NewMCPErrorResponse(fmt.Sprintf("Open app failed: %s", err.Error())), err
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("Successfully opened app: %s", unifiedReq.PackageName)
|
|
||||||
returnData := ToolOpenApp{PackageName: unifiedReq.PackageName}
|
|
||||||
|
|
||||||
return NewMCPSuccessResponse(message, &returnData), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolOpenApp) ConvertActionToCallToolRequest(action option.MobileAction) (mcp.CallToolRequest, error) {
|
|
||||||
if packageName, ok := action.Params.(string); ok {
|
|
||||||
arguments := map[string]any{
|
|
||||||
"packageName": packageName,
|
|
||||||
}
|
|
||||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
|
||||||
}
|
|
||||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid open app params: %v", action.Params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToolTerminateAppNew implements the terminal_app tool call.
|
|
||||||
type ToolTerminateAppNew struct {
|
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
|
||||||
PackageName string `json:"packageName" desc:"Package name of the terminated app"`
|
|
||||||
WasRunning bool `json:"wasRunning" desc:"Whether the app was actually running before termination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTerminateAppNew) Name() option.ActionName {
|
|
||||||
return option.ACTION_TerminateApp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTerminateAppNew) Description() string {
|
|
||||||
return "Terminate a running app on mobile device using its package name"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTerminateAppNew) Options() []mcp.ToolOption {
|
|
||||||
unifiedReq := &option.ActionOptions{}
|
|
||||||
return unifiedReq.GetMCPOptions(option.ACTION_TerminateApp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTerminateAppNew) Implement() server.ToolHandlerFunc {
|
|
||||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
arguments := request.GetArguments()
|
|
||||||
driverExt, err := setupXTDriver(ctx, arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setup driver failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unifiedReq, err := parseActionOptions(arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if unifiedReq.PackageName == "" {
|
|
||||||
return nil, fmt.Errorf("package_name is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate app action logic
|
|
||||||
success, err := driverExt.AppTerminate(unifiedReq.PackageName)
|
|
||||||
if err != nil {
|
|
||||||
return NewMCPErrorResponse(fmt.Sprintf("Terminate app failed: %s", err.Error())), err
|
|
||||||
}
|
|
||||||
if !success {
|
|
||||||
log.Warn().Str("packageName", unifiedReq.PackageName).Msg("app was not running")
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("Successfully terminated app: %s", unifiedReq.PackageName)
|
|
||||||
returnData := ToolTerminateAppNew{
|
|
||||||
PackageName: unifiedReq.PackageName,
|
|
||||||
WasRunning: success,
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewMCPSuccessResponse(message, &returnData), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTerminateAppNew) ConvertActionToCallToolRequest(action option.MobileAction) (mcp.CallToolRequest, error) {
|
|
||||||
if packageName, ok := action.Params.(string); ok {
|
|
||||||
arguments := map[string]any{
|
|
||||||
"packageName": packageName,
|
|
||||||
}
|
|
||||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
|
||||||
}
|
|
||||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid terminate app params: %v", action.Params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToolColdLaunch implements the cold_launch tool call.
|
// ToolColdLaunch implements the cold_launch tool call.
|
||||||
type ToolColdLaunch struct {
|
type ToolColdLaunch struct {
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
// Return data fields - these define the structure of data returned by this tool
|
||||||
|
|||||||
@@ -124,65 +124,6 @@ func (t *ToolSetIme) ConvertActionToCallToolRequest(action option.MobileAction)
|
|||||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid set ime params: %v", action.Params)
|
return mcp.CallToolRequest{}, fmt.Errorf("invalid set ime params: %v", action.Params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToolText implements the text tool call.
|
|
||||||
type ToolText struct {
|
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
|
||||||
Text string `json:"text" desc:"Text that was input"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolText) Name() option.ActionName {
|
|
||||||
return option.ACTION_Text
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolText) Description() string {
|
|
||||||
return "Input text into the currently focused element or input field"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolText) Options() []mcp.ToolOption {
|
|
||||||
unifiedReq := &option.ActionOptions{}
|
|
||||||
return unifiedReq.GetMCPOptions(option.ACTION_Text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolText) Implement() server.ToolHandlerFunc {
|
|
||||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
arguments := request.GetArguments()
|
|
||||||
driverExt, err := setupXTDriver(ctx, arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setup driver failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unifiedReq, err := parseActionOptions(arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if unifiedReq.Text == "" {
|
|
||||||
return nil, fmt.Errorf("text is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := unifiedReq.Options()
|
|
||||||
|
|
||||||
// Text input action logic
|
|
||||||
err = driverExt.Input(unifiedReq.Text, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return NewMCPErrorResponse(fmt.Sprintf("Text input failed: %s", err.Error())), err
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("Successfully input text: %s", unifiedReq.Text)
|
|
||||||
returnData := ToolText{Text: unifiedReq.Text}
|
|
||||||
|
|
||||||
return NewMCPSuccessResponse(message, &returnData), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolText) ConvertActionToCallToolRequest(action option.MobileAction) (mcp.CallToolRequest, error) {
|
|
||||||
text := fmt.Sprintf("%v", action.Params)
|
|
||||||
arguments := map[string]any{
|
|
||||||
"text": text,
|
|
||||||
}
|
|
||||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToolBackspace implements the backspace tool call.
|
// ToolBackspace implements the backspace tool call.
|
||||||
type ToolBackspace struct {
|
type ToolBackspace struct {
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
// Return data fields - these define the structure of data returned by this tool
|
||||||
|
|||||||
@@ -84,79 +84,6 @@ func (t *ToolTapXY) ConvertActionToCallToolRequest(action option.MobileAction) (
|
|||||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid tap params: %v", action.Params)
|
return mcp.CallToolRequest{}, fmt.Errorf("invalid tap params: %v", action.Params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToolTap implements the tap tool call.
|
|
||||||
type ToolTap struct {
|
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
|
||||||
X float64 `json:"x" desc:"X coordinate where tap was performed"`
|
|
||||||
Y float64 `json:"y" desc:"Y coordinate where tap was performed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTap) Name() option.ActionName {
|
|
||||||
return option.ACTION_Tap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTap) Description() string {
|
|
||||||
return "Tap on the screen at given relative coordinates (0.0-1.0 range)"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTap) Options() []mcp.ToolOption {
|
|
||||||
unifiedReq := &option.ActionOptions{}
|
|
||||||
return unifiedReq.GetMCPOptions(option.ACTION_Tap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTap) Implement() server.ToolHandlerFunc {
|
|
||||||
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
arguments := request.GetArguments()
|
|
||||||
driverExt, err := setupXTDriver(ctx, arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("setup driver failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unifiedReq, err := parseActionOptions(arguments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build all options from request arguments
|
|
||||||
opts := unifiedReq.Options()
|
|
||||||
|
|
||||||
// Validate required parameters
|
|
||||||
if unifiedReq.X == 0 || unifiedReq.Y == 0 {
|
|
||||||
return nil, fmt.Errorf("x and y coordinates are required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tap action logic
|
|
||||||
err = driverExt.TapXY(unifiedReq.X, unifiedReq.Y, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return NewMCPErrorResponse(fmt.Sprintf("Tap failed: %s", err.Error())), err
|
|
||||||
}
|
|
||||||
|
|
||||||
message := fmt.Sprintf("Successfully tapped at coordinates (%.2f, %.2f)", unifiedReq.X, unifiedReq.Y)
|
|
||||||
returnData := ToolTap{
|
|
||||||
X: unifiedReq.X,
|
|
||||||
Y: unifiedReq.Y,
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewMCPSuccessResponse(message, &returnData), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ToolTap) ConvertActionToCallToolRequest(action option.MobileAction) (mcp.CallToolRequest, error) {
|
|
||||||
if params, err := builtin.ConvertToFloat64Slice(action.Params); err == nil && len(params) == 2 {
|
|
||||||
x, y := params[0], params[1]
|
|
||||||
arguments := map[string]any{
|
|
||||||
"x": x,
|
|
||||||
"y": y,
|
|
||||||
}
|
|
||||||
// Add duration if available from action options
|
|
||||||
if duration := action.ActionOptions.Duration; duration > 0 {
|
|
||||||
arguments["duration"] = duration
|
|
||||||
}
|
|
||||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
|
||||||
}
|
|
||||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid tap params: %v", action.Params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToolTapAbsXY implements the tap_abs_xy tool call.
|
// ToolTapAbsXY implements the tap_abs_xy tool call.
|
||||||
type ToolTapAbsXY struct {
|
type ToolTapAbsXY struct {
|
||||||
// Return data fields - these define the structure of data returned by this tool
|
// Return data fields - these define the structure of data returned by this tool
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ const (
|
|||||||
ACTION_AppClear ActionName = "app_clear"
|
ACTION_AppClear ActionName = "app_clear"
|
||||||
ACTION_AppStart ActionName = "app_start"
|
ACTION_AppStart ActionName = "app_start"
|
||||||
ACTION_AppLaunch ActionName = "app_launch" // 启动 app 并堵塞等待 app 首屏加载完成
|
ACTION_AppLaunch ActionName = "app_launch" // 启动 app 并堵塞等待 app 首屏加载完成
|
||||||
ACTION_OpenApp ActionName = "open_app" // 启动 app 并堵塞等待 app 首屏加载完成
|
|
||||||
ACTION_AppTerminate ActionName = "app_terminate"
|
ACTION_AppTerminate ActionName = "app_terminate"
|
||||||
ACTION_TerminateApp ActionName = "terminal_app"
|
|
||||||
ACTION_ColdLaunch ActionName = "cold_launch"
|
ACTION_ColdLaunch ActionName = "cold_launch"
|
||||||
ACTION_AppStop ActionName = "app_stop"
|
ACTION_AppStop ActionName = "app_stop"
|
||||||
ACTION_ScreenShot ActionName = "screenshot"
|
ACTION_ScreenShot ActionName = "screenshot"
|
||||||
@@ -61,7 +59,6 @@ const (
|
|||||||
|
|
||||||
// UI handling
|
// UI handling
|
||||||
ACTION_Home ActionName = "home"
|
ACTION_Home ActionName = "home"
|
||||||
ACTION_Tap ActionName = "tap" // generic tap action
|
|
||||||
ACTION_TapXY ActionName = "tap_xy"
|
ACTION_TapXY ActionName = "tap_xy"
|
||||||
ACTION_TapAbsXY ActionName = "tap_abs_xy"
|
ACTION_TapAbsXY ActionName = "tap_abs_xy"
|
||||||
ACTION_TapByOCR ActionName = "tap_ocr"
|
ACTION_TapByOCR ActionName = "tap_ocr"
|
||||||
@@ -73,7 +70,6 @@ const (
|
|||||||
ACTION_SwipeCoordinate ActionName = "swipe_coordinate" // swipe by coordinates (fromX, fromY, toX, toY)
|
ACTION_SwipeCoordinate ActionName = "swipe_coordinate" // swipe by coordinates (fromX, fromY, toX, toY)
|
||||||
ACTION_Drag ActionName = "drag"
|
ACTION_Drag ActionName = "drag"
|
||||||
ACTION_Input ActionName = "input"
|
ACTION_Input ActionName = "input"
|
||||||
ACTION_Text ActionName = "text"
|
|
||||||
ACTION_PressButton ActionName = "press_button"
|
ACTION_PressButton ActionName = "press_button"
|
||||||
ACTION_Back ActionName = "back"
|
ACTION_Back ActionName = "back"
|
||||||
ACTION_KeyCode ActionName = "keycode"
|
ACTION_KeyCode ActionName = "keycode"
|
||||||
@@ -605,7 +601,6 @@ func WithOutputSchema(schema interface{}) ActionOption {
|
|||||||
func (o *ActionOptions) GetMCPOptions(actionType ActionName) []mcp.ToolOption {
|
func (o *ActionOptions) GetMCPOptions(actionType ActionName) []mcp.ToolOption {
|
||||||
// Define field mappings for different action types
|
// Define field mappings for different action types
|
||||||
fieldMappings := map[ActionName][]string{
|
fieldMappings := map[ActionName][]string{
|
||||||
ACTION_Tap: {"platform", "serial", "x", "y", "duration"},
|
|
||||||
ACTION_TapXY: {"platform", "serial", "x", "y", "duration"},
|
ACTION_TapXY: {"platform", "serial", "x", "y", "duration"},
|
||||||
ACTION_TapAbsXY: {"platform", "serial", "x", "y", "duration"},
|
ACTION_TapAbsXY: {"platform", "serial", "x", "y", "duration"},
|
||||||
ACTION_TapByOCR: {"platform", "serial", "text", "ignoreNotFoundError", "maxRetryTimes", "index", "regex", "tapRandomRect"},
|
ACTION_TapByOCR: {"platform", "serial", "text", "ignoreNotFoundError", "maxRetryTimes", "index", "regex", "tapRandomRect"},
|
||||||
@@ -616,12 +611,9 @@ func (o *ActionOptions) GetMCPOptions(actionType ActionName) []mcp.ToolOption {
|
|||||||
ACTION_Swipe: {"platform", "serial", "direction", "fromX", "fromY", "toX", "toY", "duration", "pressDuration"},
|
ACTION_Swipe: {"platform", "serial", "direction", "fromX", "fromY", "toX", "toY", "duration", "pressDuration"},
|
||||||
ACTION_Drag: {"platform", "serial", "fromX", "fromY", "toX", "toY", "duration", "pressDuration"},
|
ACTION_Drag: {"platform", "serial", "fromX", "fromY", "toX", "toY", "duration", "pressDuration"},
|
||||||
ACTION_Input: {"platform", "serial", "text", "frequency"},
|
ACTION_Input: {"platform", "serial", "text", "frequency"},
|
||||||
ACTION_Text: {"platform", "serial", "text", "frequency"},
|
|
||||||
ACTION_Backspace: {"platform", "serial", "count"},
|
ACTION_Backspace: {"platform", "serial", "count"},
|
||||||
ACTION_AppLaunch: {"platform", "serial", "packageName"},
|
ACTION_AppLaunch: {"platform", "serial", "packageName"},
|
||||||
ACTION_OpenApp: {"platform", "serial", "packageName"},
|
|
||||||
ACTION_AppTerminate: {"platform", "serial", "packageName"},
|
ACTION_AppTerminate: {"platform", "serial", "packageName"},
|
||||||
ACTION_TerminateApp: {"platform", "serial", "packageName"},
|
|
||||||
ACTION_ColdLaunch: {"platform", "serial", "packageName"},
|
ACTION_ColdLaunch: {"platform", "serial", "packageName"},
|
||||||
ACTION_AppInstall: {"platform", "serial", "appUrl", "packageName"},
|
ACTION_AppInstall: {"platform", "serial", "appUrl", "packageName"},
|
||||||
ACTION_AppUninstall: {"platform", "serial", "packageName"},
|
ACTION_AppUninstall: {"platform", "serial", "packageName"},
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ func NewXTDriver(driver IDriver, opts ...option.AIServiceOption) (*XTDriver, err
|
|||||||
if driverExt.LLMService != nil {
|
if driverExt.LLMService != nil {
|
||||||
mcpTools := driverExt.client.Server.ListTools()
|
mcpTools := driverExt.client.Server.ListTools()
|
||||||
einoTools := ai.ConvertMCPToolsToEinoToolInfos(mcpTools, "uixt")
|
einoTools := ai.ConvertMCPToolsToEinoToolInfos(mcpTools, "uixt")
|
||||||
if err := driverExt.LLMService.RegisterTools(einoTools); err != nil {
|
if err = driverExt.LLMService.RegisterTools(einoTools); err != nil {
|
||||||
log.Warn().Err(err).Msg("failed to register uixt tools")
|
log.Warn().Err(err).Msg("failed to register uixt tools to LLM service")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user