Download src/hk_api_agents_h.erl from Snapkitty/hyperkitty-chromium: direct link, hf CLI and curl.
- Browser
- Download file 6.32 kB
-
https://huggingface.co/Snapkitty/hyperkitty-chromium/resolve/main/src/hk_api_agents_h.erl
- Command line
-
hf download hf://Snapkitty/hyperkitty-chromium/src/hk_api_agents_h.erl
-
curl -L -o hk_api_agents_h.erl https://huggingface.co/Snapkitty/hyperkitty-chromium/resolve/main/src/hk_api_agents_h.erl
6.32 kB
| % SPDX-License-Identifier: LicenseRef-Sovereign-Leviathan-SL-AGPL3-001 | |
| % Licensing: see LICENSE in the repository root. | |
| %%%------------------------------------------------------------------- | |
| %%% @doc `/agents' API domain. | |
| %%% | |
| %%% POST /api/agents create an agent | |
| %%% GET /api/agents list agents | |
| %%% GET /api/agents/:id describe one agent | |
| %%% POST /api/agents/:id/objective assign its objective | |
| %%% POST /api/agents/:id/actions run one loop iteration (a tool call) | |
| %%% POST /api/agents/:id/complete mark completed | |
| %%% POST /api/agents/:id/terminate terminate | |
| %%% | |
| %%% Every POST here goes through `hk_api_util:run_operation/4', so | |
| %%% every mutating call returns an `operation_id' alongside its | |
| %%% result -- including a failed one, per the "every mutating | |
| %%% operation should return an operation identifier" requirement | |
| %%% (an operation identifier is returned whether the operation | |
| %%% succeeded or not; only its `status' differs). | |
| %%% @end | |
| %%%------------------------------------------------------------------- | |
| -module(hk_api_agents_h). | |
| -export([init/2]). | |
| init(Req0 = #{method := <<"POST">>}, collection) -> | |
| RequestId = hk_api_util:request_id(Req0), | |
| {ok, Body, Req1} = hk_api_util:read_json_body(Req0), | |
| Capabilities = parse_capabilities(maps:get(<<"capabilities">>, Body, [])), | |
| Limits = maps:get(<<"limits">>, Body, #{}), | |
| Req = hk_api_util:run_operation(agent_create, RequestId, fun() -> | |
| AgentId = hk_id:new(<<"agent">>), | |
| case hk_agent_fsm_sup:start_agent(#{agent_id => AgentId, capabilities => Capabilities, | |
| limits => atomize_limit_keys(Limits)}) of | |
| {ok, _Pid} -> {ok, {agent, AgentId}, #{agent_id => AgentId}}; | |
| {error, Reason} -> {error, Reason} | |
| end | |
| end, Req1), | |
| {ok, Req, collection}; | |
| init(Req0 = #{method := <<"GET">>}, collection) -> | |
| Described = [describe_or_skip(Id) || {Id, _Pid} <- hk_agent_registry:list_agents()], | |
| Agents = [M || {true, M} <- Described], | |
| Req = hk_api_util:reply_json(200, #{agents => Agents}, Req0), | |
| {ok, Req, collection}; | |
| init(Req0 = #{method := <<"GET">>}, item) -> | |
| AgentId = cowboy_req:binding(id, Req0), | |
| Req = case lookup_agent(AgentId) of | |
| {ok, Pid} -> | |
| {ok, Agent} = hk_agent_fsm:describe(Pid), | |
| hk_api_util:reply_json(200, hk_schema:to_map(Agent), Req0); | |
| {error, not_found} -> | |
| hk_api_util:reply_error(404, agent_not_found, Req0) | |
| end, | |
| {ok, Req, item}; | |
| init(Req0 = #{method := <<"POST">>}, objective) -> | |
| AgentId = cowboy_req:binding(id, Req0), | |
| RequestId = hk_api_util:request_id(Req0), | |
| {ok, Body, Req1} = hk_api_util:read_json_body(Req0), | |
| Description = maps:get(<<"description">>, Body, <<>>), | |
| Req = hk_api_util:run_operation(agent_assign_objective, RequestId, fun() -> | |
| case lookup_agent(AgentId) of | |
| {ok, Pid} -> | |
| case hk_agent_fsm:assign_objective(Pid, Description) of | |
| ok -> {ok, {agent, AgentId}, #{agent_id => AgentId}}; | |
| {error, Reason} -> {error, Reason} | |
| end; | |
| {error, Reason} -> {error, Reason} | |
| end | |
| end, Req1), | |
| {ok, Req, objective}; | |
| init(Req0 = #{method := <<"POST">>}, actions) -> | |
| AgentId = cowboy_req:binding(id, Req0), | |
| RequestId = hk_api_util:request_id(Req0), | |
| {ok, Body, Req1} = hk_api_util:read_json_body(Req0), | |
| Tool = binary_to_atom(maps:get(<<"tool">>, Body, <<"browser">>), utf8), | |
| Op = binary_to_atom(maps:get(<<"op">>, Body, <<"read_page">>), utf8), | |
| Args = atomize_arg_keys(maps:get(<<"args">>, Body, #{})), | |
| Req = hk_api_util:run_operation(agent_action, RequestId, fun() -> | |
| case lookup_agent(AgentId) of | |
| {ok, Pid} -> | |
| case hk_agent_fsm:next_action(Pid, Tool, Op, Args) of | |
| {ok, Result} -> {ok, {agent, AgentId}, #{observation => Result}}; | |
| {error, Reason} -> {error, Reason} | |
| end; | |
| {error, Reason} -> {error, Reason} | |
| end | |
| end, Req1), | |
| {ok, Req, actions}; | |
| init(Req0 = #{method := <<"POST">>}, complete) -> | |
| AgentId = cowboy_req:binding(id, Req0), | |
| RequestId = hk_api_util:request_id(Req0), | |
| {ok, Body, Req1} = hk_api_util:read_json_body(Req0), | |
| Result = maps:get(<<"result">>, Body, null), | |
| Req = hk_api_util:run_operation(agent_complete, RequestId, fun() -> | |
| case lookup_agent(AgentId) of | |
| {ok, Pid} -> ok = hk_agent_fsm:complete(Pid, Result), {ok, {agent, AgentId}, #{}}; | |
| {error, Reason} -> {error, Reason} | |
| end | |
| end, Req1), | |
| {ok, Req, complete}; | |
| init(Req0 = #{method := <<"POST">>}, terminate) -> | |
| AgentId = cowboy_req:binding(id, Req0), | |
| RequestId = hk_api_util:request_id(Req0), | |
| {ok, Body, Req1} = hk_api_util:read_json_body(Req0), | |
| Reason0 = maps:get(<<"reason">>, Body, <<"operator_requested">>), | |
| Req = hk_api_util:run_operation(agent_terminate, RequestId, fun() -> | |
| case lookup_agent(AgentId) of | |
| {ok, Pid} -> ok = hk_agent_fsm:terminate_agent(Pid, Reason0), {ok, {agent, AgentId}, #{}}; | |
| {error, Reason} -> {error, Reason} | |
| end | |
| end, Req1), | |
| {ok, Req, terminate}; | |
| init(Req0, State) -> | |
| Req = hk_api_util:reply_error(405, method_not_allowed, Req0), | |
| {ok, Req, State}. | |
| %%% internal | |
| lookup_agent(undefined) -> {error, missing_agent_id}; | |
| lookup_agent(AgentId) -> hk_agent_registry:lookup(AgentId). | |
| describe_or_skip(AgentId) -> | |
| case lookup_agent(AgentId) of | |
| {ok, Pid} -> | |
| case catch hk_agent_fsm:describe(Pid) of | |
| {ok, Agent} -> {true, hk_schema:to_map(Agent)}; | |
| _ -> false | |
| end; | |
| _ -> false | |
| end. | |
| parse_capabilities(List) when is_list(List) -> | |
| [binary_to_atom(C, utf8) || C <- List, is_binary(C)]; | |
| parse_capabilities(_) -> | |
| []. | |
| atomize_limit_keys(Map) when is_map(Map) -> | |
| maps:fold(fun(K, V, Acc) -> Acc#{binary_to_atom(K, utf8) => V} end, #{}, Map); | |
| atomize_limit_keys(_) -> #{}. | |
| atomize_arg_keys(Map) when is_map(Map) -> | |
| maps:fold(fun(K, V, Acc) -> Acc#{binary_to_atom(K, utf8) => V} end, #{}, Map); | |
| atomize_arg_keys(_) -> #{}. | |