feat: bucle percibir->actuar — dom_click_ref/type_ref/hover_ref por #ref + auto-observe
This commit is contained in:
+100
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
@@ -20,9 +21,108 @@ func registerDomTools(s *server.MCPServer, d *deps) {
|
||||
s.AddTool(domClickHumanTool(), mcp.NewTypedToolHandler(d.handleDomClickHuman))
|
||||
s.AddTool(domClickTextTool(), mcp.NewTypedToolHandler(d.handleDomClickText))
|
||||
s.AddTool(domTypeTool(), mcp.NewTypedToolHandler(d.handleDomType))
|
||||
s.AddTool(domClickRefTool(), mcp.NewTypedToolHandler(d.handleDomClickRef))
|
||||
s.AddTool(domTypeRefTool(), mcp.NewTypedToolHandler(d.handleDomTypeRef))
|
||||
s.AddTool(domHoverRefTool(), mcp.NewTypedToolHandler(d.handleDomHoverRef))
|
||||
}
|
||||
}
|
||||
|
||||
// settleDelay es la espera breve tras una acción mutante antes de re-percibir,
|
||||
// dando tiempo a que el DOM se asiente (navegación, focus, repaint).
|
||||
const settleDelay = 400 * time.Millisecond
|
||||
|
||||
// ---- dom_click_ref (MUTA) — bucle percibir→actuar ----
|
||||
|
||||
type domClickRefArgs struct {
|
||||
Port int `json:"port"`
|
||||
Ref int `json:"ref"`
|
||||
}
|
||||
|
||||
func domClickRefTool() mcp.Tool {
|
||||
return mcp.NewTool("dom_click_ref",
|
||||
mcp.WithDescription("Click humanizado sobre el elemento por su #ref del outline de page_perceive (backendDOMNodeId estable). Usa humanización por defecto (Bézier+jitter). Devuelve el outline actualizado tras la acción (auto-observe)."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
|
||||
mcp.WithNumber("ref", mcp.Required(), mcp.Description("#ref del elemento (backendDOMNodeId) leído del outline de page_perceive.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleDomClickRef(_ context.Context, _ mcp.CallToolRequest, a domClickRefArgs) (*mcp.CallToolResult, error) {
|
||||
port := portOr(a.Port)
|
||||
// TODO: preset de humanización por sesión (human/fast/instant)
|
||||
err := d.withConn(port, func(c *browser.CDPConn) error {
|
||||
return browser.CdpClickRef(c, a.Ref, browser.MouseHumanOpts{})
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
time.Sleep(settleDelay)
|
||||
outline, _ := d.perceiveOutline(port, 4000)
|
||||
return mcp.NewToolResultText("clicked ref " + fmt.Sprint(a.Ref) + "\n\n" + outline), nil
|
||||
}
|
||||
|
||||
// ---- dom_type_ref (MUTA) — bucle percibir→actuar ----
|
||||
|
||||
type domTypeRefArgs struct {
|
||||
Port int `json:"port"`
|
||||
Ref int `json:"ref"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
func domTypeRefTool() mcp.Tool {
|
||||
return mcp.NewTool("dom_type_ref",
|
||||
mcp.WithDescription("Enfoca el elemento por su #ref del outline de page_perceive (backendDOMNodeId estable) y escribe el texto. Devuelve el outline actualizado tras la acción (auto-observe)."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
|
||||
mcp.WithNumber("ref", mcp.Required(), mcp.Description("#ref del elemento (backendDOMNodeId) leído del outline de page_perceive.")),
|
||||
mcp.WithString("text", mcp.Required(), mcp.Description("Texto a escribir en el elemento.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleDomTypeRef(_ context.Context, _ mcp.CallToolRequest, a domTypeRefArgs) (*mcp.CallToolResult, error) {
|
||||
if a.Text == "" {
|
||||
return mcp.NewToolResultError("text is required"), nil
|
||||
}
|
||||
port := portOr(a.Port)
|
||||
// TODO: preset de humanización por sesión (human/fast/instant)
|
||||
err := d.withConn(port, func(c *browser.CDPConn) error {
|
||||
return browser.CdpTypeRef(c, a.Ref, a.Text)
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
time.Sleep(settleDelay)
|
||||
outline, _ := d.perceiveOutline(port, 4000)
|
||||
return mcp.NewToolResultText("typed into ref " + fmt.Sprint(a.Ref) + "\n\n" + outline), nil
|
||||
}
|
||||
|
||||
// ---- dom_hover_ref (MUTA) — bucle percibir→actuar ----
|
||||
|
||||
type domHoverRefArgs struct {
|
||||
Port int `json:"port"`
|
||||
Ref int `json:"ref"`
|
||||
}
|
||||
|
||||
func domHoverRefTool() mcp.Tool {
|
||||
return mcp.NewTool("dom_hover_ref",
|
||||
mcp.WithDescription("Hover humanizado sobre el elemento por su #ref del outline de page_perceive (backendDOMNodeId estable). Usa humanización por defecto (Bézier+jitter). Devuelve el outline actualizado tras la acción (auto-observe)."),
|
||||
mcp.WithNumber("port", mcp.Description("CDP port. Default 9333 (Chrome isolated del MCP); usa 9222 explícito solo para adjuntarte al navegador diario.")),
|
||||
mcp.WithNumber("ref", mcp.Required(), mcp.Description("#ref del elemento (backendDOMNodeId) leído del outline de page_perceive.")),
|
||||
)
|
||||
}
|
||||
|
||||
func (d *deps) handleDomHoverRef(_ context.Context, _ mcp.CallToolRequest, a domHoverRefArgs) (*mcp.CallToolResult, error) {
|
||||
port := portOr(a.Port)
|
||||
// TODO: preset de humanización por sesión (human/fast/instant)
|
||||
err := d.withConn(port, func(c *browser.CDPConn) error {
|
||||
return browser.CdpHoverRef(c, a.Ref, browser.MouseHumanOpts{})
|
||||
})
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(err.Error()), nil
|
||||
}
|
||||
time.Sleep(settleDelay)
|
||||
outline, _ := d.perceiveOutline(port, 4000)
|
||||
return mcp.NewToolResultText("hovered ref " + fmt.Sprint(a.Ref) + "\n\n" + outline), nil
|
||||
}
|
||||
|
||||
// ---- dom_click (MUTA) ----
|
||||
|
||||
type domClickArgs struct {
|
||||
|
||||
Reference in New Issue
Block a user