--- id: cdp_get_ax_outline_go_browser name: cdp_get_ax_outline kind: function lang: go domain: browser version: "1.0.0" purity: impure signature: "func CdpGetAXOutline(c *CDPConn, frameID string, maxChars int) (string, error)" description: "Percibe la pagina (o un iframe via frameID) como outline accesible indentado y accionable reusando la conexion CDP viva del pool. Envia Accessibility.enable + getFullAXTree, poda el arbol y lo renderiza con #ref=backendDOMNodeId en roles accionables. Replica al caracter el pipeline Python cdp_get_ax_tree -> trim_ax_tree -> render_ax_outline pero nativo en Go, sin subprocess ni venv." tags: [browser, cdp, ax, accessibility, perceive, iframe, navegator] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [] tested: true tests: ["TestRenderAXOutline_ActionableRoleCarriesRef", "TestRenderAXOutline_InputShowsValue", "TestRenderAXOutline_SkipRoleElevatesChildren", "TestRenderAXOutline_IndentationPerLevel", "TestRenderAXOutline_TruncationAddsSuffix", "TestTrimAXTree_DiscardsIgnored", "TestTrimAXTree_CollapsesSameRoleSingleChild", "TestAxoPyRepr", "TestAxoParseNodes"] test_file_path: "functions/browser/cdp_get_ax_outline_test.go" file_path: "functions/browser/cdp_get_ax_outline.go" params: - name: c desc: "Conexion CDP viva (*CDPConn) del pool, ya conectada al tab/target objetivo. No abre WebSocket nuevo: reusa la del pool. Nil devuelve error." - name: frameID desc: "frameId CDP del iframe a percibir. Cadena vacia ('') percibe el arbol completo de la pagina (depth -1). Con valor, obtiene el AX tree DENTRO de ese iframe." - name: maxChars desc: "Limite de caracteres del outline. >0 trunca y añade '\\n…[outline truncado]'. <=0 = sin limite." output: "Outline accesible multi-linea: 2 espacios de indentacion por nivel, 'role \"name\"' por nodo, ' = '\\''value'\\''' en inputs, y marcador ' #ref=' en roles accionables. Cadena vacia si no hay nodos utiles." --- ## Ejemplo ```go // c es una *CDPConn viva del pool (la misma que usa el browser_mcp). // Percibir la pagina entera, truncando a 8000 chars: outline, err := CdpGetAXOutline(c, "", 8000) if err != nil { log.Fatal(err) } fmt.Println(outline) // WebArea "Example Domain" // heading "Example Domain" // link "More information..." #ref=128 // Percibir DENTRO de un iframe concreto (frameId del frame tree): inner, err := CdpGetAXOutline(c, "F1A2B3C4D5E6", 0) // 0 = sin limite ``` ## Cuando usarla - Cuando necesites **percibir la pagina (o un iframe) como outline accionable** para que un LLM decida sobre `#ref` sin reventar el contexto. - **Reemplaza el subprocess Python** `fn run cdp_perceive_outline`: es nativo Go, reusa la conexion CDP viva del pool y no arranca el venv en cada percepcion (mas rapido y sin dependencia de runtime `fn`/venv). - Pasa `frameID` cuando el contenido objetivo vive dentro de un iframe; deja `frameID=""` para la pagina top-level. - El `#ref` que devuelve (backendDOMNodeId) se pasa luego a `cdp_click_ref` / `cdp_type_ref` / `cdp_hover_ref`. ## Gotchas - **Impura**: requiere un Chrome vivo con CDP accesible y el dominio `Accessibility` disponible. `Accessibility.enable` se envia siempre (idempotente). - **Conexion nula** devuelve error inmediato; no intenta reconectar. - **OOPIF cross-origin**: un iframe de distinto origen corre en un target (proceso) separado. Si `Accessibility.getFullAXTree` con ese `frameId` no devuelve nodos, probablemente necesites una `*CDPConn` adjunta al target del frame, no el `frameId` desde el target padre. - **`#ref` = backendDOMNodeId**: estable mientras el nodo DOM viva, pero si la pagina re-renderiza ese subarbol el ref puede invalidarse. Percibe de nuevo tras una mutacion grande antes de actuar. - El outline omite roles `none`/`presentation`/`ignored` y nodos `ignored=true`, y eleva sus hijos al nivel actual; un arbol con todo ignorado devuelve cadena vacia. - Guard de profundidad 60 y guard de ciclo: arboles patologicos no cuelgan, pero pueden quedar recortados a partir de la profundidad 60.