-module(pig@tool@web_fetch). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pig/tool/web_fetch.gleam"). -export([tool/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Built-in `web_fetch` tool for simple HTTP GET requests.\n" "\n" " Returns the HTTP status and response body as JSON.\n" " Intended as a ready-made tool that library users can register\n" " with `pig.with_tool(web_fetch.tool())`.\n" ). -file("src/pig/tool/web_fetch.gleam", 116). ?DOC(" Truncate a string to at most `max` characters, appending \"...\" if truncated.\n"). -spec string_truncate(binary(), integer()) -> binary(). string_truncate(S, Max) -> case string:length(S) =< Max of true -> S; false -> <<(gleam@string:slice(S, 0, Max))/binary, "..."/utf8>> end. -file("src/pig/tool/web_fetch.gleam", 108). -spec format_socket_error(gleam@httpc:connect_error()) -> binary(). format_socket_error(Err) -> case Err of {posix, Code} -> Code; {tls_alert, Code@1, Detail} -> <<<>/binary, Detail/binary>> end. -file("src/pig/tool/web_fetch.gleam", 95). ?DOC(" Format an httpc error into a human-readable string.\n"). -spec format_error(gleam@httpc:http_error()) -> binary(). format_error(Err) -> case Err of response_timeout -> <<"request timed out"/utf8>>; invalid_utf8_response -> <<"response body was not valid UTF-8"/utf8>>; {failed_to_connect, Ip4, Ip6} -> <<<<<<<<"failed to connect (ipv4: "/utf8, (format_socket_error(Ip4))/binary>>/binary, ", ipv6: "/utf8>>/binary, (format_socket_error(Ip6))/binary>>/binary, ")"/utf8>> end. -file("src/pig/tool/web_fetch.gleam", 73). ?DOC(" Convert a successful response to JSON or a ToolError for non-2xx.\n"). -spec handle_response(gleam@http@response:response(binary())) -> {ok, gleam@json:json()} | {error, pig@tool:tool_error()}. handle_response(Resp) -> case erlang:element(2, Resp) of S when (S >= 200) andalso (S < 300) -> {ok, gleam@json:object( [{<<"status"/utf8>>, gleam@json:int(erlang:element(2, Resp))}, {<<"body"/utf8>>, gleam@json:string(erlang:element(4, Resp))}] )}; Status -> {error, {tool_error, <<<<<<"HTTP "/utf8, (erlang:integer_to_binary(Status))/binary>>/binary, ": "/utf8>>/binary, (string_truncate(erlang:element(4, Resp), 500))/binary>>}} end. -file("src/pig/tool/web_fetch.gleam", 43). ?DOC(" Handler for the web_fetch tool.\n"). -spec handle(gleam@dynamic:dynamic_()) -> {ok, gleam@json:json()} | {error, pig@tool:tool_error()}. handle(Args) -> gleam@result:'try'( begin _pipe = gleam@dynamic@decode:run( Args, gleam@dynamic@decode:field( <<"url"/utf8>>, {decoder, fun gleam@dynamic@decode:decode_string/1}, fun gleam@dynamic@decode:success/1 ) ), gleam@result:map_error( _pipe, fun(_) -> {tool_error, <<"Invalid arguments: expected {\"url\": \"\"}"/utf8>>} end ) end, fun(Url) -> logging:log(info, <<"web_fetch: GET "/utf8, Url/binary>>), gleam@result:'try'( begin _pipe@1 = gleam@http@request:to(Url), gleam@result:map_error( _pipe@1, fun(_) -> {tool_error, <<"Invalid URL: "/utf8, Url/binary>>} end ) end, fun(Req) -> gleam@result:'try'( begin _pipe@2 = gleam@httpc:send(Req), gleam@result:map_error( _pipe@2, fun(Err) -> {tool_error, <<"HTTP request failed: "/utf8, (format_error(Err))/binary>>} end ) end, fun(Resp) -> handle_response(Resp) end ) end ) end ). -file("src/pig/tool/web_fetch.gleam", 30). ?DOC( " Create a `web_fetch` tool.\n" "\n" " The tool performs a GET request to the given URL and returns:\n" "\n" " ```json\n" " {\"status\": 200, \"body\": \"\"}\n" " ```\n" "\n" " Returns a `ToolError` for invalid URLs, network failures, or non-2xx responses.\n" ). -spec tool() -> pig@tool:tool(). tool() -> {tool, {tool_definition, <<"web_fetch"/utf8>>, <<"Fetch the contents of a URL via HTTP GET. "/utf8, "Returns the response status code and body."/utf8>>, jscheam@schema:object( [jscheam@schema:prop(<<"url"/utf8>>, jscheam@schema:string())] )}, fun handle/1}.