acp-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +9 -0
- data/README.md +81 -0
- data/lib/acp/agent_connection/client.rb +39 -0
- data/lib/acp/agent_connection/optional_method.rb +28 -0
- data/lib/acp/agent_connection.rb +122 -0
- data/lib/acp/client_connection.rb +129 -0
- data/lib/acp/sdk.rb +13 -0
- data/lib/acp/transport/reply.rb +20 -0
- data/lib/acp/transport/response_error.rb +28 -0
- data/lib/acp/transport/result.rb +35 -0
- data/lib/acp/transport/stdio.rb +207 -0
- data/lib/acp/transport.rb +4 -0
- data/lib/acp/types/agent_auth_capabilities.rb +31 -0
- data/lib/acp/types/agent_capabilities.rb +72 -0
- data/lib/acp/types/annotations.rb +46 -0
- data/lib/acp/types/audio_content.rb +46 -0
- data/lib/acp/types/auth_capabilities.rb +31 -0
- data/lib/acp/types/auth_method/terminal.rb +66 -0
- data/lib/acp/types/auth_method.rb +20 -0
- data/lib/acp/types/auth_method_agent.rb +41 -0
- data/lib/acp/types/auth_method_terminal.rb +58 -0
- data/lib/acp/types/authenticate_request.rb +31 -0
- data/lib/acp/types/authenticate_response.rb +26 -0
- data/lib/acp/types/available_command.rb +46 -0
- data/lib/acp/types/available_command_input.rb +19 -0
- data/lib/acp/types/available_commands_update.rb +34 -0
- data/lib/acp/types/blob_resource_contents.rb +41 -0
- data/lib/acp/types/boolean_config_option_capabilities.rb +26 -0
- data/lib/acp/types/boolean_property_schema.rb +41 -0
- data/lib/acp/types/cancel_notification.rb +31 -0
- data/lib/acp/types/cancel_request_notification.rb +31 -0
- data/lib/acp/types/client_capabilities.rb +65 -0
- data/lib/acp/types/client_session_capabilities.rb +36 -0
- data/lib/acp/types/close_session_request.rb +31 -0
- data/lib/acp/types/close_session_response.rb +26 -0
- data/lib/acp/types/complete_elicitation_notification.rb +31 -0
- data/lib/acp/types/config_option_update.rb +34 -0
- data/lib/acp/types/content.rb +31 -0
- data/lib/acp/types/content_block/audio.rb +52 -0
- data/lib/acp/types/content_block/image.rb +59 -0
- data/lib/acp/types/content_block/resource.rb +40 -0
- data/lib/acp/types/content_block/resource_link.rb +80 -0
- data/lib/acp/types/content_block/text.rb +40 -0
- data/lib/acp/types/content_block.rb +26 -0
- data/lib/acp/types/content_chunk.rb +40 -0
- data/lib/acp/types/cost.rb +36 -0
- data/lib/acp/types/create_elicitation_request/mode/form.rb +34 -0
- data/lib/acp/types/create_elicitation_request/mode/url.rb +40 -0
- data/lib/acp/types/create_elicitation_request/mode.rb +20 -0
- data/lib/acp/types/create_elicitation_request.rb +40 -0
- data/lib/acp/types/create_elicitation_response/action/accept.rb +26 -0
- data/lib/acp/types/create_elicitation_response/action/cancel.rb +21 -0
- data/lib/acp/types/create_elicitation_response/action/decline.rb +21 -0
- data/lib/acp/types/create_elicitation_response/action.rb +22 -0
- data/lib/acp/types/create_elicitation_response.rb +31 -0
- data/lib/acp/types/create_terminal_request.rb +72 -0
- data/lib/acp/types/create_terminal_response.rb +31 -0
- data/lib/acp/types/current_mode_update.rb +31 -0
- data/lib/acp/types/delete_session_request.rb +31 -0
- data/lib/acp/types/delete_session_response.rb +26 -0
- data/lib/acp/types/diff.rb +41 -0
- data/lib/acp/types/elicitation_accept_action.rb +26 -0
- data/lib/acp/types/elicitation_capabilities.rb +40 -0
- data/lib/acp/types/elicitation_form_capabilities.rb +26 -0
- data/lib/acp/types/elicitation_form_mode/scope.rb +22 -0
- data/lib/acp/types/elicitation_form_mode.rb +34 -0
- data/lib/acp/types/elicitation_property_schema/boolean_property_schema.rb +47 -0
- data/lib/acp/types/elicitation_property_schema/integer_property_schema.rb +66 -0
- data/lib/acp/types/elicitation_property_schema/multi_select_property_schema.rb +73 -0
- data/lib/acp/types/elicitation_property_schema/number_property_schema.rb +66 -0
- data/lib/acp/types/elicitation_property_schema/string_property_schema.rb +105 -0
- data/lib/acp/types/elicitation_property_schema.rb +26 -0
- data/lib/acp/types/elicitation_request_scope.rb +26 -0
- data/lib/acp/types/elicitation_schema.rb +65 -0
- data/lib/acp/types/elicitation_schema_type.rb +7 -0
- data/lib/acp/types/elicitation_session_scope.rb +31 -0
- data/lib/acp/types/elicitation_url_capabilities.rb +26 -0
- data/lib/acp/types/elicitation_url_mode/scope.rb +22 -0
- data/lib/acp/types/elicitation_url_mode.rb +40 -0
- data/lib/acp/types/embedded_resource.rb +40 -0
- data/lib/acp/types/embedded_resource_resource.rb +22 -0
- data/lib/acp/types/enum_option.rb +41 -0
- data/lib/acp/types/env_variable.rb +36 -0
- data/lib/acp/types/file_system_capabilities.rb +36 -0
- data/lib/acp/types/http_header.rb +36 -0
- data/lib/acp/types/image_content.rb +58 -0
- data/lib/acp/types/implementation.rb +41 -0
- data/lib/acp/types/initialize_request.rb +51 -0
- data/lib/acp/types/initialize_response.rb +58 -0
- data/lib/acp/types/integer_property_schema.rb +65 -0
- data/lib/acp/types/kill_terminal_request.rb +36 -0
- data/lib/acp/types/kill_terminal_response.rb +26 -0
- data/lib/acp/types/list_sessions_request.rb +36 -0
- data/lib/acp/types/list_sessions_response.rb +40 -0
- data/lib/acp/types/load_session_request.rb +58 -0
- data/lib/acp/types/load_session_response.rb +40 -0
- data/lib/acp/types/logout_capabilities.rb +26 -0
- data/lib/acp/types/logout_request.rb +26 -0
- data/lib/acp/types/logout_response.rb +26 -0
- data/lib/acp/types/mcp_capabilities.rb +36 -0
- data/lib/acp/types/mcp_server/http.rb +46 -0
- data/lib/acp/types/mcp_server/sse.rb +46 -0
- data/lib/acp/types/mcp_server.rb +22 -0
- data/lib/acp/types/mcp_server_http.rb +46 -0
- data/lib/acp/types/mcp_server_sse.rb +46 -0
- data/lib/acp/types/mcp_server_stdio.rb +52 -0
- data/lib/acp/types/multi_select_items/string_multi_select_items.rb +31 -0
- data/lib/acp/types/multi_select_items.rb +20 -0
- data/lib/acp/types/multi_select_property_schema.rb +72 -0
- data/lib/acp/types/new_session_request.rb +51 -0
- data/lib/acp/types/new_session_response.rb +51 -0
- data/lib/acp/types/number_property_schema.rb +65 -0
- data/lib/acp/types/permission_option.rb +41 -0
- data/lib/acp/types/permission_option_kind.rb +10 -0
- data/lib/acp/types/plan.rb +31 -0
- data/lib/acp/types/plan_entry.rb +46 -0
- data/lib/acp/types/plan_entry_priority.rb +9 -0
- data/lib/acp/types/plan_entry_status.rb +9 -0
- data/lib/acp/types/prompt_capabilities.rb +41 -0
- data/lib/acp/types/prompt_request.rb +40 -0
- data/lib/acp/types/prompt_response.rb +31 -0
- data/lib/acp/types/read_text_file_request.rb +52 -0
- data/lib/acp/types/read_text_file_response.rb +31 -0
- data/lib/acp/types/release_terminal_request.rb +36 -0
- data/lib/acp/types/release_terminal_response.rb +26 -0
- data/lib/acp/types/request_permission_outcome/cancelled.rb +21 -0
- data/lib/acp/types/request_permission_outcome/selected.rb +31 -0
- data/lib/acp/types/request_permission_outcome.rb +20 -0
- data/lib/acp/types/request_permission_request.rb +51 -0
- data/lib/acp/types/request_permission_response.rb +31 -0
- data/lib/acp/types/resource_link.rb +79 -0
- data/lib/acp/types/resume_session_request.rb +58 -0
- data/lib/acp/types/resume_session_response.rb +40 -0
- data/lib/acp/types/role.rb +8 -0
- data/lib/acp/types/selected_permission_outcome.rb +31 -0
- data/lib/acp/types/session_additional_directories_capabilities.rb +26 -0
- data/lib/acp/types/session_capabilities.rb +67 -0
- data/lib/acp/types/session_close_capabilities.rb +26 -0
- data/lib/acp/types/session_config_boolean.rb +26 -0
- data/lib/acp/types/session_config_option/kind/boolean.rb +26 -0
- data/lib/acp/types/session_config_option/kind/select.rb +34 -0
- data/lib/acp/types/session_config_option/kind.rb +20 -0
- data/lib/acp/types/session_config_option.rb +64 -0
- data/lib/acp/types/session_config_option_category.rb +10 -0
- data/lib/acp/types/session_config_options_capabilities.rb +34 -0
- data/lib/acp/types/session_config_select.rb +34 -0
- data/lib/acp/types/session_config_select_group.rb +46 -0
- data/lib/acp/types/session_config_select_option.rb +41 -0
- data/lib/acp/types/session_config_select_options.rb +22 -0
- data/lib/acp/types/session_delete_capabilities.rb +26 -0
- data/lib/acp/types/session_info.rb +65 -0
- data/lib/acp/types/session_info_update.rb +38 -0
- data/lib/acp/types/session_list_capabilities.rb +26 -0
- data/lib/acp/types/session_list_request.rb +8 -0
- data/lib/acp/types/session_list_response.rb +8 -0
- data/lib/acp/types/session_load_request.rb +8 -0
- data/lib/acp/types/session_mode.rb +41 -0
- data/lib/acp/types/session_mode_state.rb +40 -0
- data/lib/acp/types/session_new_request.rb +8 -0
- data/lib/acp/types/session_notification.rb +40 -0
- data/lib/acp/types/session_prompt_request.rb +8 -0
- data/lib/acp/types/session_resume_capabilities.rb +26 -0
- data/lib/acp/types/session_update/agent_message_chunk.rb +45 -0
- data/lib/acp/types/session_update/agent_thought_chunk.rb +45 -0
- data/lib/acp/types/session_update/available_commands_update.rb +38 -0
- data/lib/acp/types/session_update/config_option_update.rb +38 -0
- data/lib/acp/types/session_update/current_mode_update.rb +31 -0
- data/lib/acp/types/session_update/plan.rb +31 -0
- data/lib/acp/types/session_update/session_info_update.rb +39 -0
- data/lib/acp/types/session_update/tool_call.rb +97 -0
- data/lib/acp/types/session_update/tool_call_update.rb +97 -0
- data/lib/acp/types/session_update/usage_update.rb +46 -0
- data/lib/acp/types/session_update/user_message_chunk.rb +45 -0
- data/lib/acp/types/session_update.rb +38 -0
- data/lib/acp/types/set_session_config_option_request/value/boolean.rb +26 -0
- data/lib/acp/types/set_session_config_option_request/value/value_id.rb +26 -0
- data/lib/acp/types/set_session_config_option_request/value.rb +20 -0
- data/lib/acp/types/set_session_config_option_request.rb +46 -0
- data/lib/acp/types/set_session_config_option_response.rb +34 -0
- data/lib/acp/types/set_session_mode_request.rb +36 -0
- data/lib/acp/types/set_session_mode_response.rb +26 -0
- data/lib/acp/types/stop_reason.rb +11 -0
- data/lib/acp/types/string_format.rb +10 -0
- data/lib/acp/types/string_multi_select_items.rb +31 -0
- data/lib/acp/types/string_property_schema.rb +104 -0
- data/lib/acp/types/terminal.rb +31 -0
- data/lib/acp/types/terminal_exit_status.rb +36 -0
- data/lib/acp/types/terminal_output_request.rb +36 -0
- data/lib/acp/types/terminal_output_response.rb +46 -0
- data/lib/acp/types/text_content.rb +40 -0
- data/lib/acp/types/text_resource_contents.rb +41 -0
- data/lib/acp/types/titled_multi_select_items.rb +31 -0
- data/lib/acp/types/tool_call.rb +96 -0
- data/lib/acp/types/tool_call_content/content.rb +31 -0
- data/lib/acp/types/tool_call_content/diff.rb +41 -0
- data/lib/acp/types/tool_call_content/terminal.rb +31 -0
- data/lib/acp/types/tool_call_content.rb +22 -0
- data/lib/acp/types/tool_call_location.rb +36 -0
- data/lib/acp/types/tool_call_status.rb +10 -0
- data/lib/acp/types/tool_call_update.rb +96 -0
- data/lib/acp/types/tool_kind.rb +16 -0
- data/lib/acp/types/unstructured_command_input.rb +31 -0
- data/lib/acp/types/usage_update.rb +46 -0
- data/lib/acp/types/wait_for_terminal_exit_request.rb +36 -0
- data/lib/acp/types/wait_for_terminal_exit_response.rb +36 -0
- data/lib/acp/types/write_text_file_request.rb +46 -0
- data/lib/acp/types/write_text_file_response.rb +26 -0
- data/lib/acp/version.rb +5 -0
- data/sig/generated/acp/agent_connection/client.rbs +29 -0
- data/sig/generated/acp/agent_connection/optional_method.rbs +21 -0
- data/sig/generated/acp/agent_connection.rbs +65 -0
- data/sig/generated/acp/client_connection.rbs +82 -0
- data/sig/generated/acp/sdk.rbs +2 -0
- data/sig/generated/acp/transport/reply.rbs +16 -0
- data/sig/generated/acp/transport/response_error.rbs +21 -0
- data/sig/generated/acp/transport/result.rbs +25 -0
- data/sig/generated/acp/transport/stdio.rbs +116 -0
- data/sig/generated/acp/transport.rbs +4 -0
- data/sig/generated/acp/types/agent_auth_capabilities.rbs +21 -0
- data/sig/generated/acp/types/agent_capabilities.rbs +37 -0
- data/sig/generated/acp/types/annotations.rbs +29 -0
- data/sig/generated/acp/types/audio_content.rbs +29 -0
- data/sig/generated/acp/types/auth_capabilities.rbs +21 -0
- data/sig/generated/acp/types/auth_method/terminal.rbs +37 -0
- data/sig/generated/acp/types/auth_method.rbs +9 -0
- data/sig/generated/acp/types/auth_method_agent.rbs +29 -0
- data/sig/generated/acp/types/auth_method_terminal.rbs +37 -0
- data/sig/generated/acp/types/authenticate_request.rbs +21 -0
- data/sig/generated/acp/types/authenticate_response.rbs +17 -0
- data/sig/generated/acp/types/available_command.rbs +29 -0
- data/sig/generated/acp/types/available_command_input.rbs +9 -0
- data/sig/generated/acp/types/available_commands_update.rbs +21 -0
- data/sig/generated/acp/types/blob_resource_contents.rbs +29 -0
- data/sig/generated/acp/types/boolean_config_option_capabilities.rbs +17 -0
- data/sig/generated/acp/types/boolean_property_schema.rbs +29 -0
- data/sig/generated/acp/types/cancel_notification.rbs +21 -0
- data/sig/generated/acp/types/cancel_request_notification.rbs +21 -0
- data/sig/generated/acp/types/client_capabilities.rbs +37 -0
- data/sig/generated/acp/types/client_session_capabilities.rbs +21 -0
- data/sig/generated/acp/types/close_session_request.rbs +21 -0
- data/sig/generated/acp/types/close_session_response.rbs +17 -0
- data/sig/generated/acp/types/complete_elicitation_notification.rbs +21 -0
- data/sig/generated/acp/types/config_option_update.rbs +21 -0
- data/sig/generated/acp/types/content.rbs +21 -0
- data/sig/generated/acp/types/content_block/audio.rbs +29 -0
- data/sig/generated/acp/types/content_block/image.rbs +33 -0
- data/sig/generated/acp/types/content_block/resource.rbs +25 -0
- data/sig/generated/acp/types/content_block/resource_link.rbs +45 -0
- data/sig/generated/acp/types/content_block/text.rbs +25 -0
- data/sig/generated/acp/types/content_block.rbs +9 -0
- data/sig/generated/acp/types/content_chunk.rbs +25 -0
- data/sig/generated/acp/types/cost.rbs +25 -0
- data/sig/generated/acp/types/create_elicitation_request/mode/form.rbs +21 -0
- data/sig/generated/acp/types/create_elicitation_request/mode/url.rbs +25 -0
- data/sig/generated/acp/types/create_elicitation_request/mode.rbs +9 -0
- data/sig/generated/acp/types/create_elicitation_request.rbs +25 -0
- data/sig/generated/acp/types/create_elicitation_response/action/accept.rbs +17 -0
- data/sig/generated/acp/types/create_elicitation_response/action/cancel.rbs +13 -0
- data/sig/generated/acp/types/create_elicitation_response/action/decline.rbs +13 -0
- data/sig/generated/acp/types/create_elicitation_response/action.rbs +9 -0
- data/sig/generated/acp/types/create_elicitation_response.rbs +21 -0
- data/sig/generated/acp/types/create_terminal_request.rbs +41 -0
- data/sig/generated/acp/types/create_terminal_response.rbs +21 -0
- data/sig/generated/acp/types/current_mode_update.rbs +21 -0
- data/sig/generated/acp/types/delete_session_request.rbs +21 -0
- data/sig/generated/acp/types/delete_session_response.rbs +17 -0
- data/sig/generated/acp/types/diff.rbs +29 -0
- data/sig/generated/acp/types/elicitation_accept_action.rbs +17 -0
- data/sig/generated/acp/types/elicitation_capabilities.rbs +25 -0
- data/sig/generated/acp/types/elicitation_form_capabilities.rbs +17 -0
- data/sig/generated/acp/types/elicitation_form_mode/scope.rbs +9 -0
- data/sig/generated/acp/types/elicitation_form_mode.rbs +21 -0
- data/sig/generated/acp/types/elicitation_property_schema/boolean_property_schema.rbs +29 -0
- data/sig/generated/acp/types/elicitation_property_schema/integer_property_schema.rbs +37 -0
- data/sig/generated/acp/types/elicitation_property_schema/multi_select_property_schema.rbs +41 -0
- data/sig/generated/acp/types/elicitation_property_schema/number_property_schema.rbs +37 -0
- data/sig/generated/acp/types/elicitation_property_schema/string_property_schema.rbs +53 -0
- data/sig/generated/acp/types/elicitation_property_schema.rbs +9 -0
- data/sig/generated/acp/types/elicitation_request_scope.rbs +17 -0
- data/sig/generated/acp/types/elicitation_schema.rbs +37 -0
- data/sig/generated/acp/types/elicitation_schema_type.rbs +5 -0
- data/sig/generated/acp/types/elicitation_session_scope.rbs +21 -0
- data/sig/generated/acp/types/elicitation_url_capabilities.rbs +17 -0
- data/sig/generated/acp/types/elicitation_url_mode/scope.rbs +9 -0
- data/sig/generated/acp/types/elicitation_url_mode.rbs +25 -0
- data/sig/generated/acp/types/embedded_resource.rbs +25 -0
- data/sig/generated/acp/types/embedded_resource_resource.rbs +9 -0
- data/sig/generated/acp/types/enum_option.rbs +29 -0
- data/sig/generated/acp/types/env_variable.rbs +25 -0
- data/sig/generated/acp/types/file_system_capabilities.rbs +25 -0
- data/sig/generated/acp/types/http_header.rbs +25 -0
- data/sig/generated/acp/types/image_content.rbs +33 -0
- data/sig/generated/acp/types/implementation.rbs +29 -0
- data/sig/generated/acp/types/initialize_request.rbs +29 -0
- data/sig/generated/acp/types/initialize_response.rbs +33 -0
- data/sig/generated/acp/types/integer_property_schema.rbs +37 -0
- data/sig/generated/acp/types/kill_terminal_request.rbs +25 -0
- data/sig/generated/acp/types/kill_terminal_response.rbs +17 -0
- data/sig/generated/acp/types/list_sessions_request.rbs +25 -0
- data/sig/generated/acp/types/list_sessions_response.rbs +25 -0
- data/sig/generated/acp/types/load_session_request.rbs +33 -0
- data/sig/generated/acp/types/load_session_response.rbs +25 -0
- data/sig/generated/acp/types/logout_capabilities.rbs +17 -0
- data/sig/generated/acp/types/logout_request.rbs +17 -0
- data/sig/generated/acp/types/logout_response.rbs +17 -0
- data/sig/generated/acp/types/mcp_capabilities.rbs +25 -0
- data/sig/generated/acp/types/mcp_server/http.rbs +29 -0
- data/sig/generated/acp/types/mcp_server/sse.rbs +29 -0
- data/sig/generated/acp/types/mcp_server.rbs +9 -0
- data/sig/generated/acp/types/mcp_server_http.rbs +29 -0
- data/sig/generated/acp/types/mcp_server_sse.rbs +29 -0
- data/sig/generated/acp/types/mcp_server_stdio.rbs +33 -0
- data/sig/generated/acp/types/multi_select_items/string_multi_select_items.rbs +21 -0
- data/sig/generated/acp/types/multi_select_items.rbs +9 -0
- data/sig/generated/acp/types/multi_select_property_schema.rbs +41 -0
- data/sig/generated/acp/types/new_session_request.rbs +29 -0
- data/sig/generated/acp/types/new_session_response.rbs +29 -0
- data/sig/generated/acp/types/number_property_schema.rbs +37 -0
- data/sig/generated/acp/types/permission_option.rbs +29 -0
- data/sig/generated/acp/types/permission_option_kind.rbs +11 -0
- data/sig/generated/acp/types/plan.rbs +21 -0
- data/sig/generated/acp/types/plan_entry.rbs +29 -0
- data/sig/generated/acp/types/plan_entry_priority.rbs +9 -0
- data/sig/generated/acp/types/plan_entry_status.rbs +9 -0
- data/sig/generated/acp/types/prompt_capabilities.rbs +29 -0
- data/sig/generated/acp/types/prompt_request.rbs +25 -0
- data/sig/generated/acp/types/prompt_response.rbs +21 -0
- data/sig/generated/acp/types/read_text_file_request.rbs +33 -0
- data/sig/generated/acp/types/read_text_file_response.rbs +21 -0
- data/sig/generated/acp/types/release_terminal_request.rbs +25 -0
- data/sig/generated/acp/types/release_terminal_response.rbs +17 -0
- data/sig/generated/acp/types/request_permission_outcome/cancelled.rbs +13 -0
- data/sig/generated/acp/types/request_permission_outcome/selected.rbs +21 -0
- data/sig/generated/acp/types/request_permission_outcome.rbs +9 -0
- data/sig/generated/acp/types/request_permission_request.rbs +29 -0
- data/sig/generated/acp/types/request_permission_response.rbs +21 -0
- data/sig/generated/acp/types/resource_link.rbs +45 -0
- data/sig/generated/acp/types/resume_session_request.rbs +33 -0
- data/sig/generated/acp/types/resume_session_response.rbs +25 -0
- data/sig/generated/acp/types/role.rbs +7 -0
- data/sig/generated/acp/types/selected_permission_outcome.rbs +21 -0
- data/sig/generated/acp/types/session_additional_directories_capabilities.rbs +17 -0
- data/sig/generated/acp/types/session_capabilities.rbs +37 -0
- data/sig/generated/acp/types/session_close_capabilities.rbs +17 -0
- data/sig/generated/acp/types/session_config_boolean.rbs +17 -0
- data/sig/generated/acp/types/session_config_option/kind/boolean.rbs +17 -0
- data/sig/generated/acp/types/session_config_option/kind/select.rbs +21 -0
- data/sig/generated/acp/types/session_config_option/kind.rbs +9 -0
- data/sig/generated/acp/types/session_config_option.rbs +37 -0
- data/sig/generated/acp/types/session_config_option_category.rbs +11 -0
- data/sig/generated/acp/types/session_config_options_capabilities.rbs +21 -0
- data/sig/generated/acp/types/session_config_select.rbs +21 -0
- data/sig/generated/acp/types/session_config_select_group.rbs +29 -0
- data/sig/generated/acp/types/session_config_select_option.rbs +29 -0
- data/sig/generated/acp/types/session_config_select_options.rbs +9 -0
- data/sig/generated/acp/types/session_delete_capabilities.rbs +17 -0
- data/sig/generated/acp/types/session_info.rbs +37 -0
- data/sig/generated/acp/types/session_info_update.rbs +25 -0
- data/sig/generated/acp/types/session_list_capabilities.rbs +17 -0
- data/sig/generated/acp/types/session_list_request.rbs +3 -0
- data/sig/generated/acp/types/session_list_response.rbs +3 -0
- data/sig/generated/acp/types/session_load_request.rbs +3 -0
- data/sig/generated/acp/types/session_mode.rbs +29 -0
- data/sig/generated/acp/types/session_mode_state.rbs +25 -0
- data/sig/generated/acp/types/session_new_request.rbs +3 -0
- data/sig/generated/acp/types/session_notification.rbs +25 -0
- data/sig/generated/acp/types/session_prompt_request.rbs +3 -0
- data/sig/generated/acp/types/session_resume_capabilities.rbs +17 -0
- data/sig/generated/acp/types/session_update/agent_message_chunk.rbs +25 -0
- data/sig/generated/acp/types/session_update/agent_thought_chunk.rbs +25 -0
- data/sig/generated/acp/types/session_update/available_commands_update.rbs +21 -0
- data/sig/generated/acp/types/session_update/config_option_update.rbs +21 -0
- data/sig/generated/acp/types/session_update/current_mode_update.rbs +21 -0
- data/sig/generated/acp/types/session_update/plan.rbs +21 -0
- data/sig/generated/acp/types/session_update/session_info_update.rbs +25 -0
- data/sig/generated/acp/types/session_update/tool_call.rbs +49 -0
- data/sig/generated/acp/types/session_update/tool_call_update.rbs +49 -0
- data/sig/generated/acp/types/session_update/usage_update.rbs +29 -0
- data/sig/generated/acp/types/session_update/user_message_chunk.rbs +25 -0
- data/sig/generated/acp/types/session_update.rbs +9 -0
- data/sig/generated/acp/types/set_session_config_option_request/value/boolean.rbs +17 -0
- data/sig/generated/acp/types/set_session_config_option_request/value/value_id.rbs +17 -0
- data/sig/generated/acp/types/set_session_config_option_request/value.rbs +9 -0
- data/sig/generated/acp/types/set_session_config_option_request.rbs +29 -0
- data/sig/generated/acp/types/set_session_config_option_response.rbs +21 -0
- data/sig/generated/acp/types/set_session_mode_request.rbs +25 -0
- data/sig/generated/acp/types/set_session_mode_response.rbs +17 -0
- data/sig/generated/acp/types/stop_reason.rbs +13 -0
- data/sig/generated/acp/types/string_format.rbs +11 -0
- data/sig/generated/acp/types/string_multi_select_items.rbs +21 -0
- data/sig/generated/acp/types/string_property_schema.rbs +53 -0
- data/sig/generated/acp/types/terminal.rbs +21 -0
- data/sig/generated/acp/types/terminal_exit_status.rbs +25 -0
- data/sig/generated/acp/types/terminal_output_request.rbs +25 -0
- data/sig/generated/acp/types/terminal_output_response.rbs +29 -0
- data/sig/generated/acp/types/text_content.rbs +25 -0
- data/sig/generated/acp/types/text_resource_contents.rbs +29 -0
- data/sig/generated/acp/types/titled_multi_select_items.rbs +21 -0
- data/sig/generated/acp/types/tool_call.rbs +49 -0
- data/sig/generated/acp/types/tool_call_content/content.rbs +21 -0
- data/sig/generated/acp/types/tool_call_content/diff.rbs +29 -0
- data/sig/generated/acp/types/tool_call_content/terminal.rbs +21 -0
- data/sig/generated/acp/types/tool_call_content.rbs +9 -0
- data/sig/generated/acp/types/tool_call_location.rbs +25 -0
- data/sig/generated/acp/types/tool_call_status.rbs +11 -0
- data/sig/generated/acp/types/tool_call_update.rbs +49 -0
- data/sig/generated/acp/types/tool_kind.rbs +23 -0
- data/sig/generated/acp/types/unstructured_command_input.rbs +21 -0
- data/sig/generated/acp/types/usage_update.rbs +29 -0
- data/sig/generated/acp/types/wait_for_terminal_exit_request.rbs +25 -0
- data/sig/generated/acp/types/wait_for_terminal_exit_response.rbs +25 -0
- data/sig/generated/acp/types/write_text_file_request.rbs +29 -0
- data/sig/generated/acp/types/write_text_file_response.rbs +17 -0
- data/sig/generated/acp/version.rbs +5 -0
- data/sig/manual/acp/agent_connection.rbs +52 -0
- data/sig/manual/acp/client_connection.rbs +13 -0
- data/sig/manual/acp/transport/stdio.rbs +18 -0
- data/sig/manual/acp/types.rbs +2 -0
- metadata +477 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b7ee3b18dbb3a538b575c1b3309f93bd84eab3566e4491d39646dde8f0114ff6
|
|
4
|
+
data.tar.gz: ef1b3bed3a05dea92f076f4ed67e8378a3893d522db9ffe76ad445810b5fb20e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 69232d2be95232917e3f3c25c0eb890cbb2367069378e4ec415765a9606740da333b32631d3430c42fd7b5691b434329ef1ff2f6a0c19433d5149837bf4880d9
|
|
7
|
+
data.tar.gz: 256d27b3b35c9e6e569fe60098885fa878fa6e7df06ffed8330c58d5b611f198a796df6928a62c6f8c2df01e4628312e5a6408efab669511dc4a402a8ab7b6e8
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-09-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* ACP::AgentConnection with the required methods, session/load and session/list ([#14](https://github.com/bottrall/acp-sdk/issues/14)) ([565798c](https://github.com/bottrall/acp-sdk/commit/565798cffa6a0a3a09c38d28fa2cc25db881650e))
|
|
9
|
+
* ACP::ClientConnection ([#17](https://github.com/bottrall/acp-sdk/issues/17)) ([65fc83a](https://github.com/bottrall/acp-sdk/commit/65fc83a8cda8896c03090fe4bb59a59907418791)), closes [#6](https://github.com/bottrall/acp-sdk/issues/6)
|
|
10
|
+
* JSON-RPC over NDJSON stdio transport with mid-turn multiplexing ([#9](https://github.com/bottrall/acp-sdk/issues/9)) ([ef5f7db](https://github.com/bottrall/acp-sdk/commit/ef5f7db50f4272161f010f14dd99e49f2526d68b))
|
|
11
|
+
* vendor the ACP schema.json and generate the types ([#8](https://github.com/bottrall/acp-sdk/issues/8)) ([69c6ece](https://github.com/bottrall/acp-sdk/commit/69c6ece77ff1b785c8f7f20681e3af71a1cbaffa)), closes [#3](https://github.com/bottrall/acp-sdk/issues/3)
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jake Bottrall
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# acp-sdk
|
|
2
|
+
|
|
3
|
+
A standalone Ruby implementation of the [Agent Client Protocol](https://agentclientprotocol.com) (ACP): the agent side (`ACP::AgentConnection`), for exposing an agent to ACP clients such as Zed and JetBrains, and the client side (`ACP::ClientConnection`), for driving ACP agents from Ruby.
|
|
4
|
+
|
|
5
|
+
Namespace `ACP`. MIT licensed.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
Intent only. Nothing is published yet; the `acp-sdk` gem name is claimed at the first release.
|
|
10
|
+
|
|
11
|
+
This repo exists so that [riffer-rig](https://github.com/bottrall/riffer-rig) can depend on it for its `riffer acp` host. Scope for the first release: JSON-RPC over stdio, `mcpServers` and `available_commands` in, permission requests and filesystem methods out.
|
|
12
|
+
|
|
13
|
+
## Serving an agent
|
|
14
|
+
|
|
15
|
+
An agent is a plain Ruby object. `ACP::AgentConnection` answers `initialize` itself, turns each request into its generated `ACP::Types` object, calls the agent, and sends back what it returns. The factory block receives an `ACP::AgentConnection::Client` handle, which the agent keeps for sending session updates and asking permission. [`examples/echo_agent.rb`](examples/echo_agent.rb) is a complete agent; `ruby examples/echo_agent.rb` serves it on stdio.
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
connection = ACP::AgentConnection.new(
|
|
19
|
+
transport: ACP::Transport::Stdio.new(input: $stdin, output: $stdout),
|
|
20
|
+
capabilities: ACP::Types::AgentCapabilities.new(load_session: true),
|
|
21
|
+
agent_info: ACP::Types::Implementation.new(name: 'my-agent', version: '1.0.0')
|
|
22
|
+
) { |client| MyAgent.new(client:) }
|
|
23
|
+
connection.start.join
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The agent's contract:
|
|
27
|
+
|
|
28
|
+
- It defines `new_session`, `prompt` and `cancel`. `load_session` and `list_sessions` are required only when `capabilities` advertises `load_session` or `session_capabilities.list`; `start` raises `ArgumentError` when one is advertised but missing, and a method that is not advertised is answered with `-32601`. `session_created`, if defined, runs right after the `session/new` reply is sent.
|
|
29
|
+
- Each request method returns its response type or an `ACP::Transport::ResponseError`, which is sent as the error reply. Params that do not match the schema are answered with `-32602` before the agent sees them.
|
|
30
|
+
- `cancel` runs on the transport's reader thread, so it must return quickly: set a flag and let the prompt notice it.
|
|
31
|
+
- After a cancel, the agent must itself end the turn with `stopReason: cancelled`. `ACP::AgentConnection` does not enforce it.
|
|
32
|
+
- `client.capabilities` is `nil` until the client sends `initialize`.
|
|
33
|
+
|
|
34
|
+
## Driving an agent
|
|
35
|
+
|
|
36
|
+
`ACP::ClientConnection` is the other side of the same transport, for editors and for tests that drive an agent. Each method takes the request's generated `ACP::Types` object and returns its response type or the agent's `ACP::Transport::ResponseError`. `connect` sends `initialize`, which Ruby reserves for the constructor.
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
stdin, stdout, = Open3.popen2('ruby', 'examples/echo_agent.rb')
|
|
40
|
+
connection = ACP::ClientConnection.new(
|
|
41
|
+
transport: ACP::Transport::Stdio.new(input: stdout, output: stdin),
|
|
42
|
+
permission: ->(request) { ask_the_user(request) },
|
|
43
|
+
updates: ->(notification) { show(notification) }
|
|
44
|
+
)
|
|
45
|
+
connection.start
|
|
46
|
+
connection.connect(ACP::Types::InitializeRequest.new(protocol_version: 1))
|
|
47
|
+
session = connection.session_new(ACP::Types::NewSessionRequest.new(cwd: Dir.pwd, mcp_servers: []))
|
|
48
|
+
prompt = [ACP::Types::ContentBlock::Text.new(text: 'hello')]
|
|
49
|
+
response = connection.session_prompt(ACP::Types::PromptRequest.new(session_id: session.session_id, prompt:)) do |update|
|
|
50
|
+
print update.content.text if update.is_a?(ACP::Types::SessionUpdate::AgentMessageChunk)
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `session_prompt` and `session_load` yield the session's updates on the calling thread as they arrive and return once the agent replies. Updates outside those calls, such as the available commands after `session/new`, go to `updates`, which runs on the reader thread and must return quickly.
|
|
55
|
+
- `permission` answers `session/request_permission` with an `ACP::Types::RequestPermissionResponse` or an `ACP::Transport::ResponseError`. It runs on its own thread, so it may block while the user decides, and `session_cancel` can be sent meanwhile.
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
Every project chore is a script in `bin/`. The Rakefile behind them is an implementation detail; you never need to call rake directly.
|
|
60
|
+
|
|
61
|
+
| Script | What it does |
|
|
62
|
+
| --------------- | ---------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `bin/setup` | Install dependencies on a fresh checkout (gems + rbs collection) |
|
|
64
|
+
| `bin/test` | Run the test suite. Pass files and/or Minitest flags: `bin/test test/foo_test.rb -n /pattern/` |
|
|
65
|
+
| `bin/lint` | Run RuboCop. Arguments are forwarded, e.g. `bin/lint -a` |
|
|
66
|
+
| `bin/typecheck` | Check `lib/acp/types`, the rbs collection lockfile and `sig/generated` are current, then type-check with Steep |
|
|
67
|
+
| `bin/rbs` | Regenerate `sig/generated` from the inline annotations in `lib/` |
|
|
68
|
+
| `bin/types` | Regenerate `lib/acp/types` from `schema/schema.json`, then `sig/generated` |
|
|
69
|
+
| `bin/rbs-watch` | Regenerate `sig/generated` whenever `lib/` changes |
|
|
70
|
+
| `bin/ci` | Run everything CI runs, serially. Use before pushing |
|
|
71
|
+
| `bin/build` | Build the gem into `pkg/`; the publish workflow runs this before `gem push` |
|
|
72
|
+
|
|
73
|
+
## Releasing
|
|
74
|
+
|
|
75
|
+
PR titles are [conventional commits](https://www.conventionalcommits.org/) and are linted in CI: `feat:` bumps the minor version, `fix:` bumps the patch, and `feat!:` marks a breaking change (also a minor bump while we are on 0.x). `chore:`, `docs:`, `ci:`, `refactor:` and `test:` never release. Squash-merging makes the title the commit on `main`.
|
|
76
|
+
|
|
77
|
+
[release-please](https://github.com/googleapis/release-please) keeps a release PR open that bumps `lib/acp/version.rb` and writes `CHANGELOG.md`. Merging that PR tags `vX.Y.Z`, creates the GitHub Release and publishes the gem to RubyGems.org through Trusted Publishing; nothing is pushed by hand. The first release is 0.1.0.
|
|
78
|
+
|
|
79
|
+
## Maintainer
|
|
80
|
+
|
|
81
|
+
- Jake Bottrall - https://github.com/bottrall
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::AgentConnection::Client
|
|
4
|
+
# @rbs @peer: ACP::AgentConnection::_Peer
|
|
5
|
+
|
|
6
|
+
# @dynamic capabilities, capabilities=
|
|
7
|
+
attr_accessor :capabilities #: ACP::Types::ClientCapabilities?
|
|
8
|
+
|
|
9
|
+
# @rbs peer: ACP::AgentConnection::_Peer
|
|
10
|
+
# @rbs return: void
|
|
11
|
+
def initialize(peer:)
|
|
12
|
+
@peer = peer
|
|
13
|
+
@capabilities = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs session_id: String
|
|
17
|
+
# @rbs update: ACP::Types::SessionUpdate::t
|
|
18
|
+
# @rbs return: void
|
|
19
|
+
def update(session_id, update)
|
|
20
|
+
@peer.notify('session/update', ACP::Types::SessionNotification.new(session_id:, update:).to_h)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @rbs session_id: String
|
|
24
|
+
# @rbs commands: Array[ACP::Types::AvailableCommand]
|
|
25
|
+
# @rbs return: void
|
|
26
|
+
def available_commands(session_id, commands)
|
|
27
|
+
update(session_id, ACP::Types::SessionUpdate::AvailableCommandsUpdate.new(available_commands: commands))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Blocks the calling thread until the client answers or the connection
|
|
31
|
+
# closes.
|
|
32
|
+
#
|
|
33
|
+
# @rbs request: ACP::Types::RequestPermissionRequest
|
|
34
|
+
# @rbs return: ACP::Types::RequestPermissionResponse | ACP::Transport::ResponseError
|
|
35
|
+
def request_permission(request)
|
|
36
|
+
result = @peer.request('session/request_permission', request.to_h)
|
|
37
|
+
result.error || ACP::Types::RequestPermissionResponse.from_h(result.value)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::AgentConnection::OptionalMethod
|
|
4
|
+
# @rbs @capability: ^(ACP::Types::AgentCapabilities) -> boolish
|
|
5
|
+
|
|
6
|
+
# @dynamic rpc_method
|
|
7
|
+
attr_reader :rpc_method #: String
|
|
8
|
+
|
|
9
|
+
# @dynamic agent_method
|
|
10
|
+
attr_reader :agent_method #: Symbol
|
|
11
|
+
|
|
12
|
+
# @rbs rpc_method: String
|
|
13
|
+
# @rbs agent_method: Symbol
|
|
14
|
+
# @rbs &capability: (ACP::Types::AgentCapabilities) -> boolish
|
|
15
|
+
# @rbs return: void
|
|
16
|
+
def initialize(rpc_method:, agent_method:, &capability)
|
|
17
|
+
@rpc_method = rpc_method
|
|
18
|
+
@agent_method = agent_method
|
|
19
|
+
@capability = capability
|
|
20
|
+
freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @rbs capabilities: ACP::Types::AgentCapabilities
|
|
24
|
+
# @rbs return: bool
|
|
25
|
+
def advertised?(capabilities)
|
|
26
|
+
@capability.call(capabilities) ? true : false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::AgentConnection
|
|
4
|
+
# @rbs @transport: ACP::AgentConnection::_Transport
|
|
5
|
+
# @rbs @capabilities: ACP::Types::AgentCapabilities
|
|
6
|
+
# @rbs @agent_info: ACP::Types::Implementation?
|
|
7
|
+
# @rbs @auth_methods: Array[ACP::Types::AuthMethod::t]
|
|
8
|
+
# @rbs @factory: ^(ACP::AgentConnection::Client) -> ACP::AgentConnection::_Agent
|
|
9
|
+
|
|
10
|
+
PROTOCOL_VERSION = 1 #: Integer
|
|
11
|
+
INVALID_PARAMS = ACP::Transport::ResponseError.new(code: -32_602, message: 'Invalid params') #: ACP::Transport::ResponseError
|
|
12
|
+
OPTIONAL = [
|
|
13
|
+
ACP::AgentConnection::OptionalMethod.new(rpc_method: 'session/load', agent_method: :load_session, &:load_session),
|
|
14
|
+
ACP::AgentConnection::OptionalMethod.new(rpc_method: 'session/list', agent_method: :list_sessions) do |capabilities|
|
|
15
|
+
capabilities.session_capabilities&.list
|
|
16
|
+
end
|
|
17
|
+
].freeze #: Array[ACP::AgentConnection::OptionalMethod]
|
|
18
|
+
|
|
19
|
+
# @rbs transport: ACP::AgentConnection::_Transport
|
|
20
|
+
# @rbs capabilities: ACP::Types::AgentCapabilities
|
|
21
|
+
# @rbs agent_info: ACP::Types::Implementation?
|
|
22
|
+
# @rbs auth_methods: Array[ACP::Types::AuthMethod::t]
|
|
23
|
+
# @rbs &factory: (ACP::AgentConnection::Client) -> ACP::AgentConnection::_Agent
|
|
24
|
+
# @rbs return: void
|
|
25
|
+
def initialize(transport:, capabilities:, agent_info: nil, auth_methods: [], &factory)
|
|
26
|
+
@transport = transport
|
|
27
|
+
@capabilities = capabilities
|
|
28
|
+
@agent_info = agent_info
|
|
29
|
+
@auth_methods = auth_methods
|
|
30
|
+
@factory = factory
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @rbs return: Thread
|
|
34
|
+
def start
|
|
35
|
+
client = ACP::AgentConnection::Client.new(peer: @transport)
|
|
36
|
+
agent = @factory.call(client)
|
|
37
|
+
advertised, unadvertised = OPTIONAL.partition { |method| method.advertised?(@capabilities) }
|
|
38
|
+
missing = advertised.map(&:agent_method).reject { |name| agent.respond_to?(name) }
|
|
39
|
+
raise ArgumentError, "capabilities advertise methods the agent lacks: #{missing.join(', ')}" unless missing.empty?
|
|
40
|
+
|
|
41
|
+
unrouted = unadvertised.map(&:rpc_method)
|
|
42
|
+
@transport.start(requests: requests(agent, client).except(*unrouted), notifications: notifications(agent))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# @rbs agent: ACP::AgentConnection::_Agent
|
|
48
|
+
# @rbs client: ACP::AgentConnection::Client
|
|
49
|
+
# @rbs return: Hash[String, ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)]
|
|
50
|
+
def requests(agent, client)
|
|
51
|
+
# Safe: start drops the load/list handlers the capabilities do not
|
|
52
|
+
# advertise and checks the agent defines the rest.
|
|
53
|
+
full = agent #: ACP::AgentConnection::_Agent & ACP::AgentConnection::_LoadSession & ACP::AgentConnection::_ListSessions
|
|
54
|
+
{
|
|
55
|
+
'initialize' => route(ACP::Types::InitializeRequest) { |request| connect(client, request) },
|
|
56
|
+
'session/new' => route(ACP::Types::NewSessionRequest) { |request| new_session(agent, request) },
|
|
57
|
+
'session/prompt' => route(ACP::Types::PromptRequest) { |request| respond(agent.prompt(request)) },
|
|
58
|
+
'session/load' => route(ACP::Types::LoadSessionRequest) { |request| respond(full.load_session(request)) },
|
|
59
|
+
'session/list' => route(ACP::Types::ListSessionsRequest) { |request| respond(full.list_sessions(request)) }
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @rbs agent: ACP::AgentConnection::_Agent
|
|
64
|
+
# @rbs return: Hash[String, ^(untyped) -> void]
|
|
65
|
+
def notifications(agent)
|
|
66
|
+
{ 'session/cancel' => ->(params) { agent.cancel(ACP::Types::CancelNotification.from_h(params)) } }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Generated from_h raises on a missing key or a value of the wrong shape.
|
|
70
|
+
#
|
|
71
|
+
# @rbs type: ACP::AgentConnection::_Parser
|
|
72
|
+
# @rbs &handle: (untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)
|
|
73
|
+
# @rbs return: ^(untyped) -> (ACP::Transport::Result | ACP::Transport::Reply)
|
|
74
|
+
def route(type, &)
|
|
75
|
+
lambda do |params|
|
|
76
|
+
request = type.from_h(params)
|
|
77
|
+
rescue KeyError, TypeError, NoMethodError
|
|
78
|
+
ACP::Transport::Result.error(INVALID_PARAMS)
|
|
79
|
+
else
|
|
80
|
+
yield(request)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @rbs response: ACP::AgentConnection::_Response | ACP::Transport::ResponseError
|
|
85
|
+
# @rbs return: ACP::Transport::Result
|
|
86
|
+
def respond(response)
|
|
87
|
+
case response
|
|
88
|
+
when ACP::Transport::ResponseError then ACP::Transport::Result.error(response)
|
|
89
|
+
else ACP::Transport::Result.ok(response.to_h)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @rbs client: ACP::AgentConnection::Client
|
|
94
|
+
# @rbs request: ACP::Types::InitializeRequest
|
|
95
|
+
# @rbs return: ACP::Transport::Result
|
|
96
|
+
def connect(client, request)
|
|
97
|
+
client.capabilities = request.client_capabilities || ACP::Types::ClientCapabilities.new
|
|
98
|
+
respond(
|
|
99
|
+
ACP::Types::InitializeResponse.new(
|
|
100
|
+
protocol_version: PROTOCOL_VERSION,
|
|
101
|
+
agent_capabilities: @capabilities,
|
|
102
|
+
auth_methods: @auth_methods,
|
|
103
|
+
agent_info: @agent_info
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# session_created runs after the reply because the client must know the
|
|
109
|
+
# session id before updates for it (e.g. available commands) arrive.
|
|
110
|
+
#
|
|
111
|
+
# @rbs agent: ACP::AgentConnection::_Agent
|
|
112
|
+
# @rbs request: ACP::Types::NewSessionRequest
|
|
113
|
+
# @rbs return: ACP::Transport::Result | ACP::Transport::Reply
|
|
114
|
+
def new_session(agent, request)
|
|
115
|
+
response = agent.new_session(request)
|
|
116
|
+
result = respond(response)
|
|
117
|
+
return result unless response.is_a?(ACP::Types::NewSessionResponse) && agent.respond_to?(:session_created)
|
|
118
|
+
|
|
119
|
+
hook = agent #: ACP::AgentConnection::_Agent & ACP::AgentConnection::_SessionCreated
|
|
120
|
+
ACP::Transport::Reply.new(result, after: -> { hook.session_created(response) })
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::ClientConnection
|
|
4
|
+
# @rbs @transport: ACP::AgentConnection::_Transport
|
|
5
|
+
# @rbs @permission: ACP::ClientConnection::_PermissionHandler
|
|
6
|
+
# @rbs @updates: ACP::ClientConnection::_UpdateHandler
|
|
7
|
+
# @rbs @lock: Thread::Mutex
|
|
8
|
+
# @rbs @streams: Hash[String, Thread::Queue]
|
|
9
|
+
|
|
10
|
+
IGNORE = ->(_notification) {} #: ^(ACP::Types::SessionNotification) -> void
|
|
11
|
+
|
|
12
|
+
# @rbs transport: ACP::AgentConnection::_Transport
|
|
13
|
+
# @rbs permission: ACP::ClientConnection::_PermissionHandler
|
|
14
|
+
# @rbs updates: ACP::ClientConnection::_UpdateHandler
|
|
15
|
+
# @rbs return: void
|
|
16
|
+
def initialize(transport:, permission:, updates: IGNORE)
|
|
17
|
+
@transport = transport
|
|
18
|
+
@permission = permission
|
|
19
|
+
@updates = updates
|
|
20
|
+
@lock = Mutex.new
|
|
21
|
+
@streams = {}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @rbs return: Thread
|
|
25
|
+
def start
|
|
26
|
+
@transport.start(
|
|
27
|
+
requests: { 'session/request_permission' => method(:request_permission) },
|
|
28
|
+
notifications: { 'session/update' => method(:dispatch) }
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Ruby reserves initialize for the constructor, so the initialize request is
|
|
33
|
+
# sent by connect.
|
|
34
|
+
#
|
|
35
|
+
# @rbs request: ACP::Types::InitializeRequest
|
|
36
|
+
# @rbs return: ACP::Types::InitializeResponse | ACP::Transport::ResponseError
|
|
37
|
+
def connect(request)
|
|
38
|
+
parse(ACP::Types::InitializeResponse, @transport.request('initialize', request.to_h))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @rbs request: ACP::Types::NewSessionRequest
|
|
42
|
+
# @rbs return: ACP::Types::NewSessionResponse | ACP::Transport::ResponseError
|
|
43
|
+
def session_new(request)
|
|
44
|
+
parse(ACP::Types::NewSessionResponse, @transport.request('session/new', request.to_h))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @rbs request: ACP::Types::PromptRequest
|
|
48
|
+
# @rbs &block: (ACP::Types::SessionUpdate::t) -> void
|
|
49
|
+
# @rbs return: ACP::Types::PromptResponse | ACP::Transport::ResponseError
|
|
50
|
+
def session_prompt(request, &)
|
|
51
|
+
parse(ACP::Types::PromptResponse, stream(request.session_id, 'session/prompt', request.to_h, &))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @rbs request: ACP::Types::LoadSessionRequest
|
|
55
|
+
# @rbs &block: (ACP::Types::SessionUpdate::t) -> void
|
|
56
|
+
# @rbs return: ACP::Types::LoadSessionResponse | ACP::Transport::ResponseError
|
|
57
|
+
def session_load(request, &)
|
|
58
|
+
parse(ACP::Types::LoadSessionResponse, stream(request.session_id, 'session/load', request.to_h, &))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @rbs request: ACP::Types::ListSessionsRequest
|
|
62
|
+
# @rbs return: ACP::Types::ListSessionsResponse | ACP::Transport::ResponseError
|
|
63
|
+
def session_list(request)
|
|
64
|
+
parse(ACP::Types::ListSessionsResponse, @transport.request('session/list', request.to_h))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @rbs notification: ACP::Types::CancelNotification
|
|
68
|
+
# @rbs return: void
|
|
69
|
+
def session_cancel(notification)
|
|
70
|
+
@transport.notify('session/cancel', notification.to_h)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# @rbs type: ACP::AgentConnection::_Parser
|
|
76
|
+
# @rbs result: ACP::Transport::Result
|
|
77
|
+
# @rbs return: untyped
|
|
78
|
+
def parse(type, result)
|
|
79
|
+
result.error || type.from_h(result.value)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The request waits on its own thread so the caller's thread can yield each
|
|
83
|
+
# update as it arrives. The reader thread queues an update before it settles
|
|
84
|
+
# a reply sent after it, so the queue closes only after the last one.
|
|
85
|
+
#
|
|
86
|
+
# @rbs session_id: String
|
|
87
|
+
# @rbs method: String
|
|
88
|
+
# @rbs params: Hash[String, untyped]
|
|
89
|
+
# @rbs &block: (ACP::Types::SessionUpdate::t) -> void
|
|
90
|
+
# @rbs return: ACP::Transport::Result
|
|
91
|
+
def stream(session_id, method, params)
|
|
92
|
+
queue = Thread::Queue.new
|
|
93
|
+
@lock.synchronize { @streams[session_id] = queue }
|
|
94
|
+
requester = Thread.new do
|
|
95
|
+
@transport.request(method, params)
|
|
96
|
+
ensure
|
|
97
|
+
@lock.synchronize { @streams.delete(session_id)&.close }
|
|
98
|
+
end
|
|
99
|
+
while (update = queue.pop)
|
|
100
|
+
yield update
|
|
101
|
+
end
|
|
102
|
+
requester.value
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Pushes under the lock so a stream cannot close its queue between the
|
|
106
|
+
# lookup and the push.
|
|
107
|
+
#
|
|
108
|
+
# @rbs params: untyped
|
|
109
|
+
# @rbs return: void
|
|
110
|
+
def dispatch(params)
|
|
111
|
+
notification = ACP::Types::SessionNotification.from_h(params)
|
|
112
|
+
queue = @lock.synchronize { @streams[notification.session_id]&.push(notification.update) }
|
|
113
|
+
@updates.call(notification) unless queue
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @rbs params: untyped
|
|
117
|
+
# @rbs return: ACP::Transport::Result
|
|
118
|
+
def request_permission(params)
|
|
119
|
+
request = ACP::Types::RequestPermissionRequest.from_h(params)
|
|
120
|
+
rescue KeyError, TypeError, NoMethodError
|
|
121
|
+
ACP::Transport::Result.error(ACP::AgentConnection::INVALID_PARAMS)
|
|
122
|
+
else
|
|
123
|
+
response = @permission.call(request)
|
|
124
|
+
case response
|
|
125
|
+
when ACP::Transport::ResponseError then ACP::Transport::Result.error(response)
|
|
126
|
+
else ACP::Transport::Result.ok(response.to_h)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
data/lib/acp/sdk.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'zeitwerk'
|
|
4
|
+
require_relative 'version'
|
|
5
|
+
|
|
6
|
+
# The gem is `acp-sdk` but its namespace is `ACP`, so lib/acp is the root
|
|
7
|
+
# directory for ACP rather than lib for a top-level constant.
|
|
8
|
+
root = __dir__ #: String
|
|
9
|
+
loader = Zeitwerk::Loader.new
|
|
10
|
+
loader.tag = 'acp-sdk'
|
|
11
|
+
loader.push_dir(root, namespace: ACP)
|
|
12
|
+
loader.ignore(__FILE__, "#{root}/version.rb")
|
|
13
|
+
loader.setup
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# A request handler's result plus a callback the transport runs once that
|
|
4
|
+
# result is on the wire, for messages the peer must only see after the reply.
|
|
5
|
+
class ACP::Transport::Reply
|
|
6
|
+
# @dynamic result
|
|
7
|
+
attr_reader :result #: ACP::Transport::Result
|
|
8
|
+
|
|
9
|
+
# @dynamic after
|
|
10
|
+
attr_reader :after #: ^() -> void
|
|
11
|
+
|
|
12
|
+
# @rbs result: ACP::Transport::Result
|
|
13
|
+
# @rbs after: ^() -> void
|
|
14
|
+
# @rbs return: void
|
|
15
|
+
def initialize(result, after:)
|
|
16
|
+
@result = result
|
|
17
|
+
@after = after
|
|
18
|
+
freeze
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::Transport::ResponseError
|
|
4
|
+
# @dynamic code
|
|
5
|
+
attr_reader :code #: Integer
|
|
6
|
+
|
|
7
|
+
# @dynamic message
|
|
8
|
+
attr_reader :message #: String
|
|
9
|
+
|
|
10
|
+
# @dynamic data
|
|
11
|
+
attr_reader :data #: untyped
|
|
12
|
+
|
|
13
|
+
# @rbs code: Integer
|
|
14
|
+
# @rbs message: String
|
|
15
|
+
# @rbs data: untyped
|
|
16
|
+
# @rbs return: void
|
|
17
|
+
def initialize(code:, message:, data: nil)
|
|
18
|
+
@code = code
|
|
19
|
+
@message = message
|
|
20
|
+
@data = data
|
|
21
|
+
freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @rbs return: Hash[String, untyped]
|
|
25
|
+
def to_h
|
|
26
|
+
{ 'code' => code, 'message' => message, 'data' => data }.compact
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ACP::Transport::Result
|
|
4
|
+
# @dynamic value
|
|
5
|
+
attr_reader :value #: untyped
|
|
6
|
+
|
|
7
|
+
# @dynamic error
|
|
8
|
+
attr_reader :error #: ACP::Transport::ResponseError?
|
|
9
|
+
|
|
10
|
+
# @rbs value: untyped
|
|
11
|
+
# @rbs return: ACP::Transport::Result
|
|
12
|
+
def self.ok(value)
|
|
13
|
+
new(value:, error: nil)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs error: ACP::Transport::ResponseError
|
|
17
|
+
# @rbs return: ACP::Transport::Result
|
|
18
|
+
def self.error(error)
|
|
19
|
+
new(value: nil, error:)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @rbs value: untyped
|
|
23
|
+
# @rbs error: ACP::Transport::ResponseError?
|
|
24
|
+
# @rbs return: void
|
|
25
|
+
def initialize(value:, error:)
|
|
26
|
+
@value = value
|
|
27
|
+
@error = error
|
|
28
|
+
freeze
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @rbs return: bool
|
|
32
|
+
def ok?
|
|
33
|
+
error.nil?
|
|
34
|
+
end
|
|
35
|
+
end
|