acp-sdk 0.8.0 → 0.10.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 +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +18 -4
- data/lib/acp/agent_connection/client.rb +31 -1
- data/lib/acp/agent_connection/optional_method/disable_provider.rb +23 -0
- data/lib/acp/agent_connection/optional_method/fork_session.rb +23 -0
- data/lib/acp/agent_connection/optional_method/list_providers.rb +23 -0
- data/lib/acp/agent_connection/optional_method/set_provider.rb +23 -0
- data/lib/acp/agent_connection.rb +73 -3
- data/lib/acp/client_connection.rb +108 -9
- data/lib/acp/request_error.rb +10 -0
- data/lib/acp/sdk.rb +3 -1
- data/lib/acp/transport/cancellation.rb +42 -0
- data/lib/acp/transport/stdio.rb +72 -1
- data/lib/acp/types/unstable/accept_nes_notification.rb +41 -0
- data/lib/acp/types/unstable/agent_capabilities.rb +122 -0
- data/lib/acp/types/unstable/client_capabilities.rb +127 -0
- data/lib/acp/types/unstable/client_nes_capabilities.rb +62 -0
- data/lib/acp/types/unstable/client_session_capabilities.rb +57 -0
- data/lib/acp/types/unstable/close_nes_request.rb +35 -0
- data/lib/acp/types/unstable/close_nes_response.rb +27 -0
- data/lib/acp/types/unstable/compaction_status.rb +11 -0
- data/lib/acp/types/unstable/compaction_summary_chunk.rb +41 -0
- data/lib/acp/types/unstable/compaction_update.rb +62 -0
- data/lib/acp/types/unstable/did_change_document_notification.rb +65 -0
- data/lib/acp/types/unstable/did_close_document_notification.rb +41 -0
- data/lib/acp/types/unstable/did_focus_document_notification.rb +74 -0
- data/lib/acp/types/unstable/did_open_document_notification.rb +66 -0
- data/lib/acp/types/unstable/did_save_document_notification.rb +41 -0
- data/lib/acp/types/unstable/disable_provider_request.rb +35 -0
- data/lib/acp/types/unstable/disable_provider_response.rb +27 -0
- data/lib/acp/types/unstable/fork_session_request.rb +69 -0
- data/lib/acp/types/unstable/fork_session_response.rb +55 -0
- data/lib/acp/types/unstable/idle_state_update.rb +46 -0
- data/lib/acp/types/unstable/initialize_response.rb +72 -0
- data/lib/acp/types/unstable/list_providers_request.rb +27 -0
- data/lib/acp/types/unstable/list_providers_response.rb +35 -0
- data/lib/acp/types/unstable/llm_protocol.rb +12 -0
- data/lib/acp/types/unstable/mcp_capabilities.rb +47 -0
- data/lib/acp/types/unstable/mcp_error.rb +41 -0
- data/lib/acp/types/unstable/mcp_server/acp.rb +41 -0
- data/lib/acp/types/unstable/mcp_server/http.rb +50 -0
- data/lib/acp/types/unstable/mcp_server/sse.rb +50 -0
- data/lib/acp/types/unstable/mcp_server.rb +25 -0
- data/lib/acp/types/unstable/mcp_server_acp.rb +41 -0
- data/lib/acp/types/unstable/message_mcp_notification.rb +59 -0
- data/lib/acp/types/unstable/message_mcp_request.rb +59 -0
- data/lib/acp/types/unstable/message_mcp_response/error.rb +35 -0
- data/lib/acp/types/unstable/message_mcp_response/result.rb +32 -0
- data/lib/acp/types/unstable/message_mcp_response.rb +23 -0
- data/lib/acp/types/unstable/nes_capabilities.rb +51 -0
- data/lib/acp/types/unstable/nes_context_capabilities.rb +111 -0
- data/lib/acp/types/unstable/nes_diagnostic.rb +57 -0
- data/lib/acp/types/unstable/nes_diagnostic_severity.rb +11 -0
- data/lib/acp/types/unstable/nes_diagnostics_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_document_did_change_capabilities.rb +35 -0
- data/lib/acp/types/unstable/nes_document_did_close_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_document_did_focus_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_document_did_open_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_document_did_save_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_document_event_capabilities.rb +91 -0
- data/lib/acp/types/unstable/nes_edit_history_capabilities.rb +35 -0
- data/lib/acp/types/unstable/nes_edit_history_entry.rb +41 -0
- data/lib/acp/types/unstable/nes_edit_suggestion.rb +67 -0
- data/lib/acp/types/unstable/nes_event_capabilities.rb +40 -0
- data/lib/acp/types/unstable/nes_excerpt.rb +47 -0
- data/lib/acp/types/unstable/nes_jump_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_jump_suggestion.rb +51 -0
- data/lib/acp/types/unstable/nes_open_file.rb +64 -0
- data/lib/acp/types/unstable/nes_open_files_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_recent_file.rb +47 -0
- data/lib/acp/types/unstable/nes_recent_files_capabilities.rb +35 -0
- data/lib/acp/types/unstable/nes_reject_reason.rb +11 -0
- data/lib/acp/types/unstable/nes_related_snippet.rb +40 -0
- data/lib/acp/types/unstable/nes_related_snippets_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_rename_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_rename_suggestion.rb +57 -0
- data/lib/acp/types/unstable/nes_repository.rb +47 -0
- data/lib/acp/types/unstable/nes_search_and_replace_capabilities.rb +27 -0
- data/lib/acp/types/unstable/nes_search_and_replace_suggestion.rb +66 -0
- data/lib/acp/types/unstable/nes_suggest_context.rb +95 -0
- data/lib/acp/types/unstable/nes_suggestion/edit.rb +68 -0
- data/lib/acp/types/unstable/nes_suggestion/jump.rb +51 -0
- data/lib/acp/types/unstable/nes_suggestion/rename.rb +64 -0
- data/lib/acp/types/unstable/nes_suggestion/searchandreplace.rb +67 -0
- data/lib/acp/types/unstable/nes_suggestion.rb +25 -0
- data/lib/acp/types/unstable/nes_text_edit.rb +41 -0
- data/lib/acp/types/unstable/nes_trigger_kind.rb +10 -0
- data/lib/acp/types/unstable/nes_user_action.rb +63 -0
- data/lib/acp/types/unstable/nes_user_actions_capabilities.rb +35 -0
- data/lib/acp/types/unstable/notice.rb +47 -0
- data/lib/acp/types/unstable/notice_severity.rb +10 -0
- data/lib/acp/types/unstable/plan_capabilities.rb +27 -0
- data/lib/acp/types/unstable/plan_file.rb +41 -0
- data/lib/acp/types/unstable/plan_items.rb +44 -0
- data/lib/acp/types/unstable/plan_markdown.rb +41 -0
- data/lib/acp/types/unstable/plan_removed.rb +32 -0
- data/lib/acp/types/unstable/plan_update.rb +39 -0
- data/lib/acp/types/unstable/plan_update_content/file.rb +41 -0
- data/lib/acp/types/unstable/plan_update_content/items.rb +44 -0
- data/lib/acp/types/unstable/plan_update_content/markdown.rb +41 -0
- data/lib/acp/types/unstable/plan_update_content.rb +23 -0
- data/lib/acp/types/unstable/position.rb +41 -0
- data/lib/acp/types/unstable/position_encoding_kind.rb +10 -0
- data/lib/acp/types/unstable/prompt_response.rb +45 -0
- data/lib/acp/types/unstable/provider_current_config.rb +41 -0
- data/lib/acp/types/unstable/provider_info.rb +64 -0
- data/lib/acp/types/unstable/providers_capabilities.rb +27 -0
- data/lib/acp/types/unstable/range.rb +41 -0
- data/lib/acp/types/unstable/reject_nes_notification.rb +52 -0
- data/lib/acp/types/unstable/requires_action_state_update.rb +27 -0
- data/lib/acp/types/unstable/running_state_update.rb +27 -0
- data/lib/acp/types/unstable/session_cancel_capabilities.rb +27 -0
- data/lib/acp/types/unstable/session_capabilities.rb +93 -0
- data/lib/acp/types/unstable/session_fork_capabilities.rb +27 -0
- data/lib/acp/types/unstable/session_message.rb +62 -0
- data/lib/acp/types/unstable/session_message_chunk.rb +59 -0
- data/lib/acp/types/unstable/session_update/agent_message_chunk.rb +46 -0
- data/lib/acp/types/unstable/session_update/agent_thought_chunk.rb +46 -0
- data/lib/acp/types/unstable/session_update/available_commands_update.rb +42 -0
- data/lib/acp/types/unstable/session_update/compaction_summary_chunk.rb +46 -0
- data/lib/acp/types/unstable/session_update/compaction_update.rb +63 -0
- data/lib/acp/types/unstable/session_update/config_option_update.rb +42 -0
- data/lib/acp/types/unstable/session_update/current_mode_update.rb +35 -0
- data/lib/acp/types/unstable/session_update/notice.rb +53 -0
- data/lib/acp/types/unstable/session_update/plan.rb +35 -0
- data/lib/acp/types/unstable/session_update/plan_removed.rb +32 -0
- data/lib/acp/types/unstable/session_update/plan_update.rb +39 -0
- data/lib/acp/types/unstable/session_update/session_info_update.rb +49 -0
- data/lib/acp/types/unstable/session_update/session_message.rb +63 -0
- data/lib/acp/types/unstable/session_update/session_message_chunk.rb +60 -0
- data/lib/acp/types/unstable/session_update/subagent_update.rb +72 -0
- data/lib/acp/types/unstable/session_update/tool_call.rb +122 -0
- data/lib/acp/types/unstable/session_update/tool_call_update.rb +122 -0
- data/lib/acp/types/unstable/session_update/usage_update.rb +47 -0
- data/lib/acp/types/unstable/session_update/user_message_chunk.rb +46 -0
- data/lib/acp/types/unstable/session_update.rb +55 -0
- data/lib/acp/types/unstable/set_provider_request.rb +62 -0
- data/lib/acp/types/unstable/set_provider_response.rb +27 -0
- data/lib/acp/types/unstable/start_nes_request.rb +64 -0
- data/lib/acp/types/unstable/start_nes_response.rb +35 -0
- data/lib/acp/types/unstable/state_update/idle.rb +46 -0
- data/lib/acp/types/unstable/state_update/requires_action.rb +27 -0
- data/lib/acp/types/unstable/state_update/running.rb +27 -0
- data/lib/acp/types/unstable/state_update/unknown.rb +27 -0
- data/lib/acp/types/unstable/state_update.rb +25 -0
- data/lib/acp/types/unstable/subagent_capabilities.rb +27 -0
- data/lib/acp/types/unstable/subagent_session_capabilities.rb +40 -0
- data/lib/acp/types/unstable/subagent_update.rb +71 -0
- data/lib/acp/types/unstable/suggest_nes_request.rb +93 -0
- data/lib/acp/types/unstable/suggest_nes_response.rb +35 -0
- data/lib/acp/types/unstable/text_document_content_change_event.rb +41 -0
- data/lib/acp/types/unstable/text_document_sync_kind.rb +9 -0
- data/lib/acp/types/unstable/unknown_state_update.rb +27 -0
- data/lib/acp/types/unstable/usage.rb +91 -0
- data/lib/acp/types/unstable/workspace_folder.rb +41 -0
- data/lib/acp/types/unstable.rb +155 -0
- data/lib/acp/version.rb +1 -1
- data/sig/generated/acp/agent_connection/client.rbs +20 -1
- data/sig/generated/acp/agent_connection/optional_method/disable_provider.rbs +13 -0
- data/sig/generated/acp/agent_connection/optional_method/fork_session.rbs +13 -0
- data/sig/generated/acp/agent_connection/optional_method/list_providers.rbs +13 -0
- data/sig/generated/acp/agent_connection/optional_method/set_provider.rbs +13 -0
- data/sig/generated/acp/agent_connection.rbs +29 -0
- data/sig/generated/acp/client_connection.rbs +57 -1
- data/sig/generated/acp/request_error.rbs +8 -0
- data/sig/generated/acp/transport/cancellation.rbs +32 -0
- data/sig/generated/acp/transport/stdio.rbs +42 -0
- data/sig/generated/acp/types/unstable/accept_nes_notification.rbs +25 -0
- data/sig/generated/acp/types/unstable/agent_capabilities.rbs +49 -0
- data/sig/generated/acp/types/unstable/client_capabilities.rbs +53 -0
- data/sig/generated/acp/types/unstable/client_nes_capabilities.rbs +29 -0
- data/sig/generated/acp/types/unstable/client_session_capabilities.rbs +29 -0
- data/sig/generated/acp/types/unstable/close_nes_request.rbs +21 -0
- data/sig/generated/acp/types/unstable/close_nes_response.rbs +17 -0
- data/sig/generated/acp/types/unstable/compaction_status.rbs +11 -0
- data/sig/generated/acp/types/unstable/compaction_summary_chunk.rbs +25 -0
- data/sig/generated/acp/types/unstable/compaction_update.rbs +33 -0
- data/sig/generated/acp/types/unstable/did_change_document_notification.rbs +33 -0
- data/sig/generated/acp/types/unstable/did_close_document_notification.rbs +25 -0
- data/sig/generated/acp/types/unstable/did_focus_document_notification.rbs +37 -0
- data/sig/generated/acp/types/unstable/did_open_document_notification.rbs +37 -0
- data/sig/generated/acp/types/unstable/did_save_document_notification.rbs +25 -0
- data/sig/generated/acp/types/unstable/disable_provider_request.rbs +21 -0
- data/sig/generated/acp/types/unstable/disable_provider_response.rbs +17 -0
- data/sig/generated/acp/types/unstable/fork_session_request.rbs +33 -0
- data/sig/generated/acp/types/unstable/fork_session_response.rbs +29 -0
- data/sig/generated/acp/types/unstable/idle_state_update.rbs +25 -0
- data/sig/generated/acp/types/unstable/initialize_response.rbs +33 -0
- data/sig/generated/acp/types/unstable/list_providers_request.rbs +17 -0
- data/sig/generated/acp/types/unstable/list_providers_response.rbs +21 -0
- data/sig/generated/acp/types/unstable/llm_protocol.rbs +13 -0
- data/sig/generated/acp/types/unstable/mcp_capabilities.rbs +29 -0
- data/sig/generated/acp/types/unstable/mcp_error.rbs +25 -0
- data/sig/generated/acp/types/unstable/mcp_server/acp.rbs +25 -0
- data/sig/generated/acp/types/unstable/mcp_server/http.rbs +29 -0
- data/sig/generated/acp/types/unstable/mcp_server/sse.rbs +29 -0
- data/sig/generated/acp/types/unstable/mcp_server.rbs +9 -0
- data/sig/generated/acp/types/unstable/mcp_server_acp.rbs +25 -0
- data/sig/generated/acp/types/unstable/message_mcp_notification.rbs +33 -0
- data/sig/generated/acp/types/unstable/message_mcp_request.rbs +33 -0
- data/sig/generated/acp/types/unstable/message_mcp_response/error.rbs +21 -0
- data/sig/generated/acp/types/unstable/message_mcp_response/result.rbs +21 -0
- data/sig/generated/acp/types/unstable/message_mcp_response.rbs +9 -0
- data/sig/generated/acp/types/unstable/nes_capabilities.rbs +25 -0
- data/sig/generated/acp/types/unstable/nes_context_capabilities.rbs +41 -0
- data/sig/generated/acp/types/unstable/nes_diagnostic.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_diagnostic_severity.rbs +11 -0
- data/sig/generated/acp/types/unstable/nes_diagnostics_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_document_did_change_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/nes_document_did_close_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_document_did_focus_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_document_did_open_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_document_did_save_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_document_event_capabilities.rbs +37 -0
- data/sig/generated/acp/types/unstable/nes_edit_history_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/nes_edit_history_entry.rbs +25 -0
- data/sig/generated/acp/types/unstable/nes_edit_suggestion.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_event_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/nes_excerpt.rbs +29 -0
- data/sig/generated/acp/types/unstable/nes_jump_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_jump_suggestion.rbs +29 -0
- data/sig/generated/acp/types/unstable/nes_open_file.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_open_files_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_recent_file.rbs +29 -0
- data/sig/generated/acp/types/unstable/nes_recent_files_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/nes_reject_reason.rbs +11 -0
- data/sig/generated/acp/types/unstable/nes_related_snippet.rbs +25 -0
- data/sig/generated/acp/types/unstable/nes_related_snippets_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_rename_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_rename_suggestion.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_repository.rbs +29 -0
- data/sig/generated/acp/types/unstable/nes_search_and_replace_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/nes_search_and_replace_suggestion.rbs +37 -0
- data/sig/generated/acp/types/unstable/nes_suggest_context.rbs +41 -0
- data/sig/generated/acp/types/unstable/nes_suggestion/edit.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_suggestion/jump.rbs +29 -0
- data/sig/generated/acp/types/unstable/nes_suggestion/rename.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_suggestion/searchandreplace.rbs +37 -0
- data/sig/generated/acp/types/unstable/nes_suggestion.rbs +9 -0
- data/sig/generated/acp/types/unstable/nes_text_edit.rbs +25 -0
- data/sig/generated/acp/types/unstable/nes_trigger_kind.rbs +9 -0
- data/sig/generated/acp/types/unstable/nes_user_action.rbs +33 -0
- data/sig/generated/acp/types/unstable/nes_user_actions_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/notice.rbs +29 -0
- data/sig/generated/acp/types/unstable/notice_severity.rbs +9 -0
- data/sig/generated/acp/types/unstable/plan_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/plan_file.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_items.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_markdown.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_removed.rbs +21 -0
- data/sig/generated/acp/types/unstable/plan_update.rbs +21 -0
- data/sig/generated/acp/types/unstable/plan_update_content/file.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_update_content/items.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_update_content/markdown.rbs +25 -0
- data/sig/generated/acp/types/unstable/plan_update_content.rbs +9 -0
- data/sig/generated/acp/types/unstable/position.rbs +25 -0
- data/sig/generated/acp/types/unstable/position_encoding_kind.rbs +9 -0
- data/sig/generated/acp/types/unstable/prompt_response.rbs +25 -0
- data/sig/generated/acp/types/unstable/provider_current_config.rbs +25 -0
- data/sig/generated/acp/types/unstable/provider_info.rbs +33 -0
- data/sig/generated/acp/types/unstable/providers_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/range.rbs +25 -0
- data/sig/generated/acp/types/unstable/reject_nes_notification.rbs +29 -0
- data/sig/generated/acp/types/unstable/requires_action_state_update.rbs +17 -0
- data/sig/generated/acp/types/unstable/running_state_update.rbs +17 -0
- data/sig/generated/acp/types/unstable/session_cancel_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/session_capabilities.rbs +41 -0
- data/sig/generated/acp/types/unstable/session_fork_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/session_message.rbs +33 -0
- data/sig/generated/acp/types/unstable/session_message_chunk.rbs +33 -0
- data/sig/generated/acp/types/unstable/session_update/agent_message_chunk.rbs +25 -0
- data/sig/generated/acp/types/unstable/session_update/agent_thought_chunk.rbs +25 -0
- data/sig/generated/acp/types/unstable/session_update/available_commands_update.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/compaction_summary_chunk.rbs +25 -0
- data/sig/generated/acp/types/unstable/session_update/compaction_update.rbs +33 -0
- data/sig/generated/acp/types/unstable/session_update/config_option_update.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/current_mode_update.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/notice.rbs +29 -0
- data/sig/generated/acp/types/unstable/session_update/plan.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/plan_removed.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/plan_update.rbs +21 -0
- data/sig/generated/acp/types/unstable/session_update/session_info_update.rbs +25 -0
- data/sig/generated/acp/types/unstable/session_update/session_message.rbs +33 -0
- data/sig/generated/acp/types/unstable/session_update/session_message_chunk.rbs +33 -0
- data/sig/generated/acp/types/unstable/session_update/subagent_update.rbs +37 -0
- data/sig/generated/acp/types/unstable/session_update/tool_call.rbs +53 -0
- data/sig/generated/acp/types/unstable/session_update/tool_call_update.rbs +53 -0
- data/sig/generated/acp/types/unstable/session_update/usage_update.rbs +29 -0
- data/sig/generated/acp/types/unstable/session_update/user_message_chunk.rbs +25 -0
- data/sig/generated/acp/types/unstable/session_update.rbs +9 -0
- data/sig/generated/acp/types/unstable/set_provider_request.rbs +33 -0
- data/sig/generated/acp/types/unstable/set_provider_response.rbs +17 -0
- data/sig/generated/acp/types/unstable/start_nes_request.rbs +29 -0
- data/sig/generated/acp/types/unstable/start_nes_response.rbs +21 -0
- data/sig/generated/acp/types/unstable/state_update/idle.rbs +25 -0
- data/sig/generated/acp/types/unstable/state_update/requires_action.rbs +17 -0
- data/sig/generated/acp/types/unstable/state_update/running.rbs +17 -0
- data/sig/generated/acp/types/unstable/state_update/unknown.rbs +17 -0
- data/sig/generated/acp/types/unstable/state_update.rbs +9 -0
- data/sig/generated/acp/types/unstable/subagent_capabilities.rbs +17 -0
- data/sig/generated/acp/types/unstable/subagent_session_capabilities.rbs +21 -0
- data/sig/generated/acp/types/unstable/subagent_update.rbs +37 -0
- data/sig/generated/acp/types/unstable/suggest_nes_request.rbs +45 -0
- data/sig/generated/acp/types/unstable/suggest_nes_response.rbs +21 -0
- data/sig/generated/acp/types/unstable/text_document_content_change_event.rbs +25 -0
- data/sig/generated/acp/types/unstable/text_document_sync_kind.rbs +7 -0
- data/sig/generated/acp/types/unstable/unknown_state_update.rbs +17 -0
- data/sig/generated/acp/types/unstable/usage.rbs +41 -0
- data/sig/generated/acp/types/unstable/workspace_folder.rbs +25 -0
- data/sig/generated/acp/types/unstable.rbs +4 -0
- data/sig/manual/acp/agent_connection/optional_method/disable_provider.rbs +6 -0
- data/sig/manual/acp/agent_connection/optional_method/fork_session.rbs +6 -0
- data/sig/manual/acp/agent_connection/optional_method/list_providers.rbs +6 -0
- data/sig/manual/acp/agent_connection/optional_method/set_provider.rbs +6 -0
- data/sig/manual/acp/agent_connection.rbs +30 -0
- metadata +302 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0d983006184ce11ac51e9361062aa6878c01d348645f41fe226423db5d72e8b
|
|
4
|
+
data.tar.gz: 0d50ff69cb0c6cc743d75dcd3fd943a9ddeaa4469a8f1e8d6e54be811e3c3b39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4296fbbf1fa985cb3913f2019528c06658fd8fcac285a238abf79073d2d5eb13d081e69da57f05476569967189f732c804f6dc851e291709c0b4052572b17d9f
|
|
7
|
+
data.tar.gz: 8f0a5bedfa32615f867111297c4fc593f2b567fd77a55e76dda4eabe57bd8494e225de93b470f1ac294f4b99a57797fda4d7f69704693fb8cd322e65fe650f59
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0](https://github.com/bottrall/acp-sdk/compare/v0.9.0...v0.10.0) (2026-10-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* MCP-over-ACP mcp/message (unstable) ([#89](https://github.com/bottrall/acp-sdk/issues/89)) ([3d6d30c](https://github.com/bottrall/acp-sdk/commit/3d6d30c6e31e88dd0fe78e08a5bc4308948cacdd))
|
|
9
|
+
* providers/list, providers/set and providers/disable (unstable) ([#88](https://github.com/bottrall/acp-sdk/issues/88)) ([eac16f7](https://github.com/bottrall/acp-sdk/commit/eac16f78809ea5a677835c6fe064063dcb64c162)), closes [#50](https://github.com/bottrall/acp-sdk/issues/50)
|
|
10
|
+
* request cancellation on the agent and client connections ([#85](https://github.com/bottrall/acp-sdk/issues/85)) ([58ae0ab](https://github.com/bottrall/acp-sdk/commit/58ae0abe6387e2887482ec14e361cfac91cd54ea))
|
|
11
|
+
* session/fork (unstable) ([#86](https://github.com/bottrall/acp-sdk/issues/86)) ([9868cb6](https://github.com/bottrall/acp-sdk/commit/9868cb666a8111c414bf3b041167d6aa022e1e95)), closes [#49](https://github.com/bottrall/acp-sdk/issues/49)
|
|
12
|
+
* support all currently supported Ruby versions ([#90](https://github.com/bottrall/acp-sdk/issues/90)) ([343d07b](https://github.com/bottrall/acp-sdk/commit/343d07b9e6d98b1c24201c5eef8b250858c0626b)), closes [#73](https://github.com/bottrall/acp-sdk/issues/73)
|
|
13
|
+
|
|
14
|
+
## [0.9.0](https://github.com/bottrall/acp-sdk/compare/v0.8.0...v0.9.0) (2026-10-07)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* $/cancel_request in ACP::Transport::Stdio ([#82](https://github.com/bottrall/acp-sdk/issues/82)) ([8679883](https://github.com/bottrall/acp-sdk/commit/86798837ce9e35949c7cc3770e52f3191d81bc6f))
|
|
20
|
+
* opt-in types for the unstable schema ([#83](https://github.com/bottrall/acp-sdk/issues/83)) ([a49a5cc](https://github.com/bottrall/acp-sdk/commit/a49a5ccba84e599fc8fae95fe2336a4eb3169835))
|
|
21
|
+
|
|
3
22
|
## [0.8.0](https://github.com/bottrall/acp-sdk/compare/v0.7.0...v0.8.0) (2026-10-06)
|
|
4
23
|
|
|
5
24
|
|
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Every ACP request, response and notification is a generated Ruby class under `AC
|
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
|
-
Requires Ruby 4
|
|
14
|
+
Requires Ruby 3.4 or later (CI tests 3.4 and 4.0).
|
|
15
15
|
|
|
16
16
|
Add the gem to your Gemfile:
|
|
17
17
|
|
|
@@ -48,11 +48,12 @@ connection.start.join
|
|
|
48
48
|
|
|
49
49
|
The agent's contract:
|
|
50
50
|
|
|
51
|
-
- It defines `new_session`, `prompt` and `cancel`. `load_session`, `list_sessions`, `resume_session`, `close_session` and `delete_session` are required only when `capabilities` advertises `load_session` or `session_capabilities.list`, `.resume`, `.close` or `.delete`, and `authenticate` only when `auth_methods` is non-empty, and `logout` only when `capabilities` advertises `auth.logout`; `start` raises `ArgumentError` when one is advertised but missing, and a method that is not advertised is answered with `-32601`. `change_session_mode` and `change_session_config_option` are optional, since modes and config options are offered per session rather than in `initialize`; `session/set_mode` and `session/set_config_option` are answered with `-32601` when the agent does not define them. `session_created`, if defined, runs right after the `session/new` reply is sent.
|
|
51
|
+
- It defines `new_session`, `prompt` and `cancel`. `load_session`, `list_sessions`, `resume_session`, `close_session` and `delete_session` are required only when `capabilities` advertises `load_session` or `session_capabilities.list`, `.resume`, `.close` or `.delete`, and `authenticate` only when `auth_methods` is non-empty, and `logout` only when `capabilities` advertises `auth.logout`; `start` raises `ArgumentError` when one is advertised but missing, and a method that is not advertised is answered with `-32601`. `change_session_mode` and `change_session_config_option` are optional, since modes and config options are offered per session rather than in `initialize`; `session/set_mode` and `session/set_config_option` are answered with `-32601` when the agent does not define them. `session_created`, if defined, runs right after the `session/new` reply is sent. `fork_session` is the same shape but unstable: `session/fork` routes only when the caller has opted into the unstable types with `require 'acp/types/unstable'` and `capabilities` advertises `session_capabilities.fork`, and is answered with `-32601` otherwise. `list_providers`, `set_provider` and `disable_provider` are the same shape but unstable too: `providers/list`, `providers/set` and `providers/disable` route only when the caller has opted into the unstable types with `require 'acp/types/unstable'` and `capabilities` advertises `providers`, and are answered with `-32601` otherwise.
|
|
52
52
|
- Each request method returns its response type or an `ACP::RequestError`, which is sent as the error reply. Params that do not match the schema are answered with `-32602` before the agent sees them, with `data` naming the failing path, e.g. `{ errors: ['sessionId: expected String, got Integer'] }`.
|
|
53
53
|
- A handler that raises is answered with `-32603` and the message `Internal error`. Nothing from the exception reaches the peer — its class and message are logged to the transport's logger instead, since messages can interpolate paths, queries or credentials. Return an `ACP::RequestError` from the handler when the peer should see a real error message.
|
|
54
|
-
- `cancel` runs on the transport's reader thread, so it must return quickly: set a flag and let the prompt notice it.
|
|
54
|
+
- `cancel` runs on the transport's reader thread, so it must return quickly: set a flag and let the prompt notice it, and call `client.cancel_requests` to cancel the connection's outstanding requests to the client — a blocked `request_permission` or `wait_for_terminal_exit`, say. That sends `$/cancel_request` for each one, and the blocked call returns once the client answers it, with its response or the `-32800` error.
|
|
55
55
|
- After a cancel, the agent must itself end the turn with `stopReason: cancelled`. `ACP::AgentConnection` does not enforce it.
|
|
56
|
+
- `client.cancelled?` is true in a handler when the client cancelled the request it is serving with `$/cancel_request`. The handler can end early by returning `ACP::RequestError.request_cancelled`, which is answered as `-32800`, or return a normal response, which is sent as-is — the transport sends exactly one response either way.
|
|
56
57
|
- `client.capabilities` is `nil` until the client sends `initialize`.
|
|
57
58
|
- `client.read_text_file` and `client.write_text_file` take an `ACP::Types::ReadTextFileRequest` or `ACP::Types::WriteTextFileRequest` and return the response type or an `ACP::RequestError`. Unless `client.capabilities` advertises `fs.read_text_file` or `fs.write_text_file`, they return `-32601` without sending anything to the client.
|
|
58
59
|
- `client.create_terminal`, `client.terminal_output`, `client.wait_for_terminal_exit`, `client.kill_terminal` and `client.release_terminal` take the matching `ACP::Types` request (`CreateTerminalRequest`, `TerminalOutputRequest`, `WaitForTerminalExitRequest`, `KillTerminalRequest`, `ReleaseTerminalRequest`) and return its response type or an `ACP::RequestError`. Unless `client.capabilities` advertises `terminal`, they return `-32601` without sending anything to the client. The agent must release every terminal it creates.
|
|
@@ -64,7 +65,7 @@ Extensions are `_`-prefixed methods outside the spec. `AgentConnection` takes `e
|
|
|
64
65
|
|
|
65
66
|
## Driving an agent
|
|
66
67
|
|
|
67
|
-
`ACP::ClientConnection` is the other side of the same transport. Each method takes the request's generated `ACP::Types` object and returns its response type or the agent's `ACP::RequestError`. `connect` sends `initialize`, since Ruby reserves that name for the constructor, and `authenticate` and `logout` send their namesake methods. `session_set_mode` sends `session/set_mode`, and `session_set_config_option` sends `session/set_config_option` and returns the session's complete option list, which replaces any state held from an earlier reply. A handler that raises is answered with `-32603` and the message `Internal error`, and the exception is only logged to the transport's logger.
|
|
68
|
+
`ACP::ClientConnection` is the other side of the same transport. Each method takes the request's generated `ACP::Types` object and returns its response type or the agent's `ACP::RequestError`. `connect` sends `initialize`, since Ruby reserves that name for the constructor, and `authenticate` and `logout` send their namesake methods. `session_set_mode` sends `session/set_mode`, and `session_set_config_option` sends `session/set_config_option` and returns the session's complete option list, which replaces any state held from an earlier reply. `session_fork` sends `session/fork`; it is unstable, so the request and response types exist only under `ACP::Types::Unstable` and calling it before `require 'acp/types/unstable'` raises `NameError`. `providers_list`, `providers_set` and `providers_disable` send `providers/list`, `providers/set` and `providers/disable` on the same unstable terms. A handler that raises is answered with `-32603` and the message `Internal error`, and the exception is only logged to the transport's logger.
|
|
68
69
|
|
|
69
70
|
`ACP::AgentProcess.spawn` starts a command with args, env and cwd, wires its stdio to a new `ACP::ClientConnection` and starts it. The block receives the connection and the process handle (`pid`, plus `stderr` when captured), and the child is terminated — after its stdin is closed, with TERM and then KILL if it will not exit — when the block exits, so a raised block cannot leak the process. Without a block, `spawn` returns the process and calling `terminate` is yours. `stderr` is `:inherit` by default, so the child writes to your stderr; pass `:capture` to collect it on the process instead.
|
|
70
71
|
|
|
@@ -105,12 +106,25 @@ connection = ACP::ClientConnection.new(
|
|
|
105
106
|
|
|
106
107
|
- `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. `session_resume` does not take a block: the agent must not replay history on resume, so unlike `session_load` there is nothing to stream. `session_close` and `session_delete` end the session, discarding it on the agent, and return once the agent replies.
|
|
107
108
|
- `permission` answers `session/request_permission` with an `ACP::Types::RequestPermissionResponse` or an `ACP::RequestError`. It runs on its own thread, so it may block while the user decides, and `session_cancel` can be sent meanwhile.
|
|
109
|
+
- The agent may cancel any outstanding request with `$/cancel_request`: a handler that can end early checks `connection.cancelled?` — close over the connection when constructing it — and returns `ACP::RequestError.request_cancelled`, which is answered as `-32800`. The permission handler still sees the cancel on its own thread. Whatever the handler returns, the transport sends exactly one response.
|
|
108
110
|
- `read_text_file` and `write_text_file` answer the agent's `fs/read_text_file` and `fs/write_text_file` with an `ACP::Types::ReadTextFileResponse`, an `ACP::Types::WriteTextFileResponse` or an `ACP::RequestError`. They are routed by the `fs` capabilities `connect` sends: a method the client does not advertise is answered with `-32601` without reaching the handler, and `connect` raises `ArgumentError` — before sending `initialize` — when the request advertises a capability that has no handler.
|
|
109
111
|
- `create_terminal`, `terminal_output`, `wait_for_terminal_exit`, `kill_terminal` and `release_terminal` answer the agent's `terminal/create`, `terminal/output`, `terminal/wait_for_exit`, `terminal/kill` and `terminal/release` with the matching `ACP::Types` response or an `ACP::RequestError`. They are routed by the `terminal` capability `connect` sends, the same way as `fs`: a method the client does not advertise is answered with `-32601` without reaching the handler, and `connect` raises `ArgumentError` — before sending `initialize` — when the request advertises `terminal` with any of the five missing. The transport serves each request on its own thread, so `wait_for_terminal_exit` may block without holding up the others.
|
|
110
112
|
- `elicitation` answers the agent's `elicitation/create` with an `ACP::Types::CreateElicitationResponse` or an `ACP::RequestError`, serving both form and url mode, and `complete_elicitation` receives the agent's `elicitation/complete` notification. They are routed by the `elicitation` capabilities `connect` sends: a request whose mode the client does not advertise is answered with `-32602` without reaching the handler, and `connect` raises `ArgumentError` — before sending `initialize` — when the request advertises `elicitation.form` or `elicitation.url` with no `elicitation` handler. The client tracks the elicitation ids of the url-mode requests it serves, so a completion for an unknown or already-completed id is ignored. `complete_elicitation` runs on the reader thread and must return quickly; it may be omitted, in which case completions are only tracked.
|
|
111
113
|
|
|
112
114
|
Extensions work the same way in both directions: `extension_requests` and `extension_notifications` are hashes keyed by the raw `_`-prefixed wire name, `ext_request` sends one to the agent and returns its result as-is, and `ext_notify` sends an extension notification. A handler name without the `_` prefix raises `ArgumentError`, and an extension request nothing answers gets `-32601`.
|
|
113
115
|
|
|
116
|
+
## Unstable types
|
|
117
|
+
|
|
118
|
+
Some protocol features are not part of the spec yet, so their schema lives in a separate unstable file: draft session updates (`plan_update`, `plan_removed`, `notice`, `compaction_update`, `compaction_summary_chunk`, `subagent_update`, `session_message`, `session_message_chunk`), `PromptResponse#usage`, the NE (next edit) and provider methods, and the matching capabilities. They are generated under `ACP::Types::Unstable` and load only when you opt in:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
require 'acp/types/unstable'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Until then, referencing `ACP::Types::Unstable` is a `NameError`, and the stable `ACP::Types` namespace is byte-identical either way: types the unstable schema shares with the stable one resolve to the same generated classes, so opting in adds names without changing or duplicating any stable one.
|
|
125
|
+
|
|
126
|
+
These types are **unstable**: they are not part of the ACP spec, agents and clients must not rely on the peer supporting them, and any of them may change or disappear between releases without a major version bump. When a stable schema absorbs one of them, the unstable twin goes away and the stable name stays.
|
|
127
|
+
|
|
114
128
|
## Contributing
|
|
115
129
|
|
|
116
130
|
Bug reports and pull requests are welcome on [GitHub](https://github.com/bottrall/acp-sdk). See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and workflow. Everyone interacting in the project is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
|
|
@@ -2,14 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
class ACP::AgentConnection::Client
|
|
4
4
|
# @rbs @peer: ACP::AgentConnection::_Peer
|
|
5
|
+
# @rbs @mcp_advertised: bool
|
|
5
6
|
|
|
6
7
|
# @dynamic capabilities, capabilities=
|
|
7
8
|
attr_accessor :capabilities #: ACP::Types::ClientCapabilities?
|
|
8
9
|
|
|
9
10
|
# @rbs peer: ACP::AgentConnection::_Peer
|
|
11
|
+
# @rbs mcp_advertised: bool
|
|
10
12
|
# @rbs return: void
|
|
11
|
-
def initialize(peer:)
|
|
13
|
+
def initialize(peer:, mcp_advertised: false)
|
|
12
14
|
@peer = peer
|
|
15
|
+
# The agent's own initialize advertisement of mcpCapabilities.acp, which
|
|
16
|
+
# licenses this side's mcp/message sends; the client's advertisement is
|
|
17
|
+
# the separate capabilities accessor.
|
|
18
|
+
@mcp_advertised = mcp_advertised
|
|
13
19
|
@capabilities = nil
|
|
14
20
|
end
|
|
15
21
|
|
|
@@ -36,6 +42,18 @@ class ACP::AgentConnection::Client
|
|
|
36
42
|
call('session/request_permission', ACP::Types::RequestPermissionResponse, request)
|
|
37
43
|
end
|
|
38
44
|
|
|
45
|
+
# @rbs return: void
|
|
46
|
+
def cancel_requests
|
|
47
|
+
@peer.cancel_requests
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Always false off a handler thread.
|
|
51
|
+
#
|
|
52
|
+
# @rbs return: bool
|
|
53
|
+
def cancelled?
|
|
54
|
+
!!@peer.cancellation&.cancelled?
|
|
55
|
+
end
|
|
56
|
+
|
|
39
57
|
# @rbs request: ACP::Types::ReadTextFileRequest
|
|
40
58
|
# @rbs return: ACP::Types::ReadTextFileResponse | ACP::RequestError
|
|
41
59
|
def read_text_file(request)
|
|
@@ -105,6 +123,18 @@ class ACP::AgentConnection::Client
|
|
|
105
123
|
@peer.notify('elicitation/complete', notification.to_h)
|
|
106
124
|
end
|
|
107
125
|
|
|
126
|
+
# Sends one inner MCP operation to the client's declared ACP MCP server. The
|
|
127
|
+
# reply's result may be null, and a reply matching neither carrier branch
|
|
128
|
+
# comes back as the raw hash.
|
|
129
|
+
#
|
|
130
|
+
# @rbs request: ACP::Types::Unstable::MessageMcpRequest
|
|
131
|
+
# @rbs return: (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError)
|
|
132
|
+
def mcp_message(request)
|
|
133
|
+
return ACP::RequestError.unadvertised_agent('mcpCapabilities.acp') unless @mcp_advertised
|
|
134
|
+
|
|
135
|
+
call('mcp/message', ACP::Types::Unstable::MessageMcpResponse, request)
|
|
136
|
+
end
|
|
137
|
+
|
|
108
138
|
# Sends an extension request, keyed by its raw `_`-prefixed wire name, and
|
|
109
139
|
# returns the client's reply as-is: extension methods have no schema to
|
|
110
140
|
# parse the result into.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ACP::AgentConnection::OptionalMethod::DisableProvider
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs return: String
|
|
7
|
+
def rpc_method
|
|
8
|
+
'providers/disable'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @rbs return: Symbol
|
|
12
|
+
def agent_method
|
|
13
|
+
:disable_provider
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs initialize_response: ACP::Types::InitializeResponse
|
|
17
|
+
# @rbs return: bool
|
|
18
|
+
def advertised?(initialize_response)
|
|
19
|
+
capabilities = initialize_response.agent_capabilities #: ACP::Types::AgentCapabilities | ACP::Types::Unstable::AgentCapabilities?
|
|
20
|
+
providers = capabilities.is_a?(ACP::Types::Unstable::AgentCapabilities) ? capabilities.providers : nil #: ACP::Types::Unstable::ProvidersCapabilities?
|
|
21
|
+
providers ? true : false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ACP::AgentConnection::OptionalMethod::ForkSession
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs return: String
|
|
7
|
+
def rpc_method
|
|
8
|
+
'session/fork'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @rbs return: Symbol
|
|
12
|
+
def agent_method
|
|
13
|
+
:fork_session
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs initialize_response: ACP::Types::InitializeResponse
|
|
17
|
+
# @rbs return: bool
|
|
18
|
+
def advertised?(initialize_response)
|
|
19
|
+
session = initialize_response.agent_capabilities&.session_capabilities #: ACP::Types::SessionCapabilities | ACP::Types::Unstable::SessionCapabilities?
|
|
20
|
+
fork = session.is_a?(ACP::Types::Unstable::SessionCapabilities) ? session.fork : nil #: ACP::Types::Unstable::SessionForkCapabilities?
|
|
21
|
+
fork ? true : false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ACP::AgentConnection::OptionalMethod::ListProviders
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs return: String
|
|
7
|
+
def rpc_method
|
|
8
|
+
'providers/list'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @rbs return: Symbol
|
|
12
|
+
def agent_method
|
|
13
|
+
:list_providers
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs initialize_response: ACP::Types::InitializeResponse
|
|
17
|
+
# @rbs return: bool
|
|
18
|
+
def advertised?(initialize_response)
|
|
19
|
+
capabilities = initialize_response.agent_capabilities #: ACP::Types::AgentCapabilities | ACP::Types::Unstable::AgentCapabilities?
|
|
20
|
+
providers = capabilities.is_a?(ACP::Types::Unstable::AgentCapabilities) ? capabilities.providers : nil #: ACP::Types::Unstable::ProvidersCapabilities?
|
|
21
|
+
providers ? true : false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ACP::AgentConnection::OptionalMethod::SetProvider
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
# @rbs return: String
|
|
7
|
+
def rpc_method
|
|
8
|
+
'providers/set'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @rbs return: Symbol
|
|
12
|
+
def agent_method
|
|
13
|
+
:set_provider
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs initialize_response: ACP::Types::InitializeResponse
|
|
17
|
+
# @rbs return: bool
|
|
18
|
+
def advertised?(initialize_response)
|
|
19
|
+
capabilities = initialize_response.agent_capabilities #: ACP::Types::AgentCapabilities | ACP::Types::Unstable::AgentCapabilities?
|
|
20
|
+
providers = capabilities.is_a?(ACP::Types::Unstable::AgentCapabilities) ? capabilities.providers : nil #: ACP::Types::Unstable::ProvidersCapabilities?
|
|
21
|
+
providers ? true : false
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/acp/agent_connection.rb
CHANGED
|
@@ -61,15 +61,21 @@ class ACP::AgentConnection
|
|
|
61
61
|
|
|
62
62
|
# @rbs return: Thread
|
|
63
63
|
def start
|
|
64
|
-
client = ACP::AgentConnection::Client.new(peer: @transport)
|
|
64
|
+
client = ACP::AgentConnection::Client.new(peer: @transport, mcp_advertised: mcp_acp_advertised?)
|
|
65
65
|
agent = @factory.call(client)
|
|
66
66
|
# Routes are fixed before a client connects, so the check sees the
|
|
67
67
|
# unfiltered auth methods: a terminal-capable client still needs
|
|
68
68
|
# authenticate routed.
|
|
69
|
-
advertised, unadvertised =
|
|
69
|
+
advertised, unadvertised = optional_methods.partition do |method|
|
|
70
|
+
method.advertised?(initialize_response(@auth_methods))
|
|
71
|
+
end
|
|
70
72
|
missing = advertised.map(&:agent_method).reject { |name| agent.respond_to?(name) }
|
|
71
73
|
raise ArgumentError, "initialize advertises methods the agent lacks: #{missing.join(', ')}" unless missing.empty?
|
|
72
74
|
|
|
75
|
+
if mcp_acp_advertised? && !agent.respond_to?(:mcp_message_notification)
|
|
76
|
+
raise ArgumentError, 'initialize advertises mcpCapabilities.acp but the agent lacks mcp_message_notification'
|
|
77
|
+
end
|
|
78
|
+
|
|
73
79
|
unrouted = unadvertised.map(&:rpc_method) + PER_SESSION.reject { |_, name| agent.respond_to?(name) }.keys
|
|
74
80
|
@transport.start(
|
|
75
81
|
requests: requests(agent, client).except(*unrouted).merge(@extension_requests),
|
|
@@ -101,13 +107,49 @@ class ACP::AgentConnection
|
|
|
101
107
|
'session/set_config_option' => route(ACP::Types::SetSessionConfigOptionRequest) do |request|
|
|
102
108
|
full.change_session_config_option(request)
|
|
103
109
|
end
|
|
110
|
+
}.merge(unstable_requests(full))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The unstable request types are referenced while the hash is built, so
|
|
114
|
+
# without the guard start would raise NameError even for an agent that never
|
|
115
|
+
# advertises fork or providers.
|
|
116
|
+
#
|
|
117
|
+
# @rbs full: ACP::AgentConnection::_FullAgent
|
|
118
|
+
# @rbs return: Hash[String, ^(untyped) -> (ACP::AgentConnection::_Response | ACP::RequestError | ACP::Transport::Reply)]
|
|
119
|
+
def unstable_requests(full)
|
|
120
|
+
return {} unless defined?(ACP::Types::Unstable)
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
'session/fork' => route(ACP::Types::Unstable::ForkSessionRequest) { |request| full.fork_session(request) },
|
|
124
|
+
'providers/list' => route(ACP::Types::Unstable::ListProvidersRequest) { |request| full.list_providers(request) },
|
|
125
|
+
'providers/set' => route(ACP::Types::Unstable::SetProviderRequest) { |request| full.set_provider(request) },
|
|
126
|
+
'providers/disable' => route(ACP::Types::Unstable::DisableProviderRequest) { |request| full.disable_provider(request) }
|
|
104
127
|
}
|
|
105
128
|
end
|
|
106
129
|
|
|
130
|
+
# ForkSession's and the provider methods' advertised? reference the unstable
|
|
131
|
+
# types, so they can only be probed when the caller opted in with
|
|
132
|
+
# `require 'acp/types/unstable'`.
|
|
133
|
+
#
|
|
134
|
+
# @rbs return: Array[ACP::AgentConnection::_OptionalMethod]
|
|
135
|
+
def optional_methods
|
|
136
|
+
return OPTIONAL unless defined?(ACP::Types::Unstable)
|
|
137
|
+
|
|
138
|
+
OPTIONAL + [
|
|
139
|
+
ACP::AgentConnection::OptionalMethod::ForkSession,
|
|
140
|
+
ACP::AgentConnection::OptionalMethod::ListProviders,
|
|
141
|
+
ACP::AgentConnection::OptionalMethod::SetProvider,
|
|
142
|
+
ACP::AgentConnection::OptionalMethod::DisableProvider
|
|
143
|
+
]
|
|
144
|
+
end
|
|
145
|
+
|
|
107
146
|
# @rbs agent: ACP::AgentConnection::_Agent
|
|
108
147
|
# @rbs return: Hash[String, ^(untyped) -> void]
|
|
109
148
|
def notifications(agent)
|
|
110
|
-
{ 'session/cancel' => ->(params) { cancel(agent, params) } }
|
|
149
|
+
routes = { 'session/cancel' => ->(params) { cancel(agent, params) } }
|
|
150
|
+
return routes unless mcp_acp_advertised?
|
|
151
|
+
|
|
152
|
+
routes.merge('mcp/message' => ->(params) { mcp_message_notification(agent, params) })
|
|
111
153
|
end
|
|
112
154
|
|
|
113
155
|
# A notification has no reply to carry a parse failure.
|
|
@@ -123,6 +165,34 @@ class ACP::AgentConnection
|
|
|
123
165
|
agent.cancel(notification)
|
|
124
166
|
end
|
|
125
167
|
|
|
168
|
+
# The unstable gates reference the unstable types, so they can only be
|
|
169
|
+
# probed when the caller opted in with `require 'acp/types/unstable'`; the
|
|
170
|
+
# stable McpCapabilities has no acp field at all.
|
|
171
|
+
#
|
|
172
|
+
# @rbs return: bool
|
|
173
|
+
def mcp_acp_advertised?
|
|
174
|
+
return false unless defined?(ACP::Types::Unstable)
|
|
175
|
+
|
|
176
|
+
mcp = @capabilities.mcp_capabilities #: ACP::Types::McpCapabilities | ACP::Types::Unstable::McpCapabilities?
|
|
177
|
+
return false unless mcp.is_a?(ACP::Types::Unstable::McpCapabilities)
|
|
178
|
+
|
|
179
|
+
mcp.acp ? true : false
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# A notification has no reply to carry a parse failure.
|
|
183
|
+
#
|
|
184
|
+
# @rbs agent: ACP::AgentConnection::_Agent
|
|
185
|
+
# @rbs params: untyped
|
|
186
|
+
# @rbs return: void
|
|
187
|
+
def mcp_message_notification(agent, params)
|
|
188
|
+
notification = ACP::Types::Unstable::MessageMcpNotification.from_h(params)
|
|
189
|
+
rescue ACP::Types::ParseError, KeyError, TypeError, NoMethodError => e
|
|
190
|
+
@logger.warn("dropped malformed mcp/message: #{e.class}: #{e.message}")
|
|
191
|
+
else
|
|
192
|
+
hook = agent #: ACP::AgentConnection::_Agent & ACP::AgentConnection::_McpMessageNotification
|
|
193
|
+
hook.mcp_message_notification(notification)
|
|
194
|
+
end
|
|
195
|
+
|
|
126
196
|
# Generated from_h raises on a missing key or a value of the wrong shape.
|
|
127
197
|
#
|
|
128
198
|
# @rbs type: ACP::AgentConnection::_Parser
|
|
@@ -15,6 +15,9 @@ class ACP::ClientConnection
|
|
|
15
15
|
# (ACP::Types::CreateElicitationResponse | ACP::RequestError))?
|
|
16
16
|
# @rbs @complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
|
|
17
17
|
# @rbs @updates: ACP::ClientConnection::_UpdateHandler
|
|
18
|
+
# @rbs @mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) ->
|
|
19
|
+
# (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
|
|
20
|
+
# @rbs @mcp_advertised: bool?
|
|
18
21
|
# @rbs @fs_capabilities: ACP::Types::FileSystemCapabilities?
|
|
19
22
|
# @rbs @terminal: bool?
|
|
20
23
|
# @rbs @elicitation_capabilities: ACP::Types::ElicitationCapabilities?
|
|
@@ -48,6 +51,8 @@ class ACP::ClientConnection
|
|
|
48
51
|
# (ACP::Types::CreateElicitationResponse | ACP::RequestError))?
|
|
49
52
|
# @rbs complete_elicitation: (^(ACP::Types::CompleteElicitationNotification) -> void)?
|
|
50
53
|
# @rbs updates: ACP::ClientConnection::_UpdateHandler
|
|
54
|
+
# @rbs mcp_message: (^(ACP::Types::Unstable::MessageMcpRequest) ->
|
|
55
|
+
# (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError))?
|
|
51
56
|
# @rbs extension_requests: Hash[String, ^(untyped) -> untyped]
|
|
52
57
|
# @rbs extension_notifications: Hash[String, ^(untyped) -> void]
|
|
53
58
|
# @rbs logger: ACP::Transport::_Logger
|
|
@@ -65,6 +70,7 @@ class ACP::ClientConnection
|
|
|
65
70
|
elicitation: nil,
|
|
66
71
|
complete_elicitation: nil,
|
|
67
72
|
updates: IGNORE,
|
|
73
|
+
mcp_message: nil,
|
|
68
74
|
extension_requests: {},
|
|
69
75
|
extension_notifications: {},
|
|
70
76
|
logger: ACP::Transport::StderrLogger.new
|
|
@@ -81,6 +87,8 @@ class ACP::ClientConnection
|
|
|
81
87
|
@elicitation = elicitation
|
|
82
88
|
@complete_elicitation = complete_elicitation
|
|
83
89
|
@updates = updates
|
|
90
|
+
@mcp_message = mcp_message
|
|
91
|
+
@mcp_advertised = nil
|
|
84
92
|
@fs_capabilities = nil
|
|
85
93
|
@terminal = nil
|
|
86
94
|
@elicitation_capabilities = nil
|
|
@@ -108,7 +116,7 @@ class ACP::ClientConnection
|
|
|
108
116
|
'terminal/kill' => method(:kill_terminal),
|
|
109
117
|
'terminal/release' => method(:release_terminal),
|
|
110
118
|
'elicitation/create' => method(:create_elicitation)
|
|
111
|
-
}.merge(@extension_requests),
|
|
119
|
+
}.merge(mcp_requests).merge(@extension_requests),
|
|
112
120
|
notifications: { 'session/update' => method(:dispatch),
|
|
113
121
|
'elicitation/complete' => method(:complete_elicitation) }.merge(@extension_notifications)
|
|
114
122
|
)
|
|
@@ -141,16 +149,17 @@ class ACP::ClientConnection
|
|
|
141
149
|
@fs_capabilities = capabilities
|
|
142
150
|
@terminal = terminal
|
|
143
151
|
@elicitation_capabilities = elicitation
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
result = @transport.request('initialize', request.to_h)
|
|
153
|
+
response = parse(ACP::Types::InitializeResponse, result)
|
|
154
|
+
return response if response.is_a?(ACP::RequestError)
|
|
146
155
|
|
|
147
|
-
|
|
156
|
+
@mcp_advertised = agent_mcp_advertised?(result)
|
|
157
|
+
return response if response.protocol_version == PROTOCOL_VERSION
|
|
148
158
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
end
|
|
159
|
+
ACP::RequestError.unsupported_protocol_version(
|
|
160
|
+
requested: request.protocol_version,
|
|
161
|
+
returned: response.protocol_version
|
|
162
|
+
)
|
|
154
163
|
end
|
|
155
164
|
|
|
156
165
|
# @rbs request: ACP::Types::NewSessionRequest
|
|
@@ -200,6 +209,30 @@ class ACP::ClientConnection
|
|
|
200
209
|
parse(ACP::Types::DeleteSessionResponse, @transport.request('session/delete', request.to_h))
|
|
201
210
|
end
|
|
202
211
|
|
|
212
|
+
# @rbs request: ACP::Types::Unstable::ForkSessionRequest
|
|
213
|
+
# @rbs return: (ACP::Types::Unstable::ForkSessionResponse | ACP::RequestError)
|
|
214
|
+
def session_fork(request)
|
|
215
|
+
parse(ACP::Types::Unstable::ForkSessionResponse, @transport.request('session/fork', request.to_h))
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# @rbs request: ACP::Types::Unstable::ListProvidersRequest
|
|
219
|
+
# @rbs return: (ACP::Types::Unstable::ListProvidersResponse | ACP::RequestError)
|
|
220
|
+
def providers_list(request)
|
|
221
|
+
parse(ACP::Types::Unstable::ListProvidersResponse, @transport.request('providers/list', request.to_h))
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @rbs request: ACP::Types::Unstable::SetProviderRequest
|
|
225
|
+
# @rbs return: (ACP::Types::Unstable::SetProviderResponse | ACP::RequestError)
|
|
226
|
+
def providers_set(request)
|
|
227
|
+
parse(ACP::Types::Unstable::SetProviderResponse, @transport.request('providers/set', request.to_h))
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# @rbs request: ACP::Types::Unstable::DisableProviderRequest
|
|
231
|
+
# @rbs return: (ACP::Types::Unstable::DisableProviderResponse | ACP::RequestError)
|
|
232
|
+
def providers_disable(request)
|
|
233
|
+
parse(ACP::Types::Unstable::DisableProviderResponse, @transport.request('providers/disable', request.to_h))
|
|
234
|
+
end
|
|
235
|
+
|
|
203
236
|
# The spec requires a pending session/request_permission to be answered with
|
|
204
237
|
# the cancelled outcome once the turn is cancelled, so every queue registered
|
|
205
238
|
# for the session gets one before this returns. The notification goes first
|
|
@@ -252,6 +285,13 @@ class ACP::ClientConnection
|
|
|
252
285
|
@transport.request(method, params)
|
|
253
286
|
end
|
|
254
287
|
|
|
288
|
+
# Always false off a handler thread.
|
|
289
|
+
#
|
|
290
|
+
# @rbs return: bool
|
|
291
|
+
def cancelled?
|
|
292
|
+
!!@transport.cancellation&.cancelled?
|
|
293
|
+
end
|
|
294
|
+
|
|
255
295
|
# @rbs method: String
|
|
256
296
|
# @rbs params: untyped
|
|
257
297
|
# @rbs return: void
|
|
@@ -260,8 +300,44 @@ class ACP::ClientConnection
|
|
|
260
300
|
@transport.notify(method, params)
|
|
261
301
|
end
|
|
262
302
|
|
|
303
|
+
# Unlike the mcp/message serve route, this send is not gated: a notification
|
|
304
|
+
# has no reply to carry a refusal, and the agent drops what it did not
|
|
305
|
+
# advertise.
|
|
306
|
+
#
|
|
307
|
+
# @rbs notification: ACP::Types::Unstable::MessageMcpNotification
|
|
308
|
+
# @rbs return: void
|
|
309
|
+
def mcp_message_notification(notification)
|
|
310
|
+
@transport.notify('mcp/message', notification.to_h)
|
|
311
|
+
end
|
|
312
|
+
|
|
263
313
|
private
|
|
264
314
|
|
|
315
|
+
# The route is only registered when a handler serves it, but the agent's
|
|
316
|
+
# advertisement is only known after connect, so an unadvertised request
|
|
317
|
+
# still reaches the route and is refused there.
|
|
318
|
+
#
|
|
319
|
+
# @rbs return: Hash[String, ACP::Transport::Stdio::_Handler]
|
|
320
|
+
def mcp_requests
|
|
321
|
+
return {} unless @mcp_message
|
|
322
|
+
|
|
323
|
+
{ 'mcp/message' => method(:mcp_message) }
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# The stable McpCapabilities has no acp field, so the gate re-reads the raw
|
|
327
|
+
# initialize reply with the unstable types when they are opted into.
|
|
328
|
+
#
|
|
329
|
+
# @rbs result: (Hash[String, untyped] | ACP::RequestError)
|
|
330
|
+
# @rbs return: bool
|
|
331
|
+
def agent_mcp_advertised?(result)
|
|
332
|
+
return false unless defined?(ACP::Types::Unstable)
|
|
333
|
+
return false unless result.is_a?(Hash)
|
|
334
|
+
|
|
335
|
+
mcp = ACP::Types::Unstable::McpCapabilities.from_h(result['agentCapabilities']['mcpCapabilities'] || {})
|
|
336
|
+
mcp.acp ? true : false
|
|
337
|
+
rescue ACP::Types::ParseError, KeyError, TypeError, NoMethodError
|
|
338
|
+
false
|
|
339
|
+
end
|
|
340
|
+
|
|
265
341
|
# @rbs type: ACP::AgentConnection::_Parser
|
|
266
342
|
# @rbs result: (Hash[String, untyped] | ACP::RequestError)
|
|
267
343
|
# @rbs return: untyped
|
|
@@ -340,7 +416,11 @@ class ACP::ClientConnection
|
|
|
340
416
|
else
|
|
341
417
|
replies = Thread::Queue.new
|
|
342
418
|
register_permission(request.session_id, replies)
|
|
419
|
+
# The handler runs on this connection's own thread, so the serving
|
|
420
|
+
# identity must be carried over for cancelled? to see the cancel there.
|
|
421
|
+
serving = @transport.cancellation
|
|
343
422
|
Thread.new do
|
|
423
|
+
ACP::Transport::Cancellation.current = serving
|
|
344
424
|
# A raised StandardError is not a returned ACP::RequestError, so the two
|
|
345
425
|
# need distinct shapes on the queue.
|
|
346
426
|
replies << begin
|
|
@@ -490,6 +570,25 @@ class ACP::ClientConnection
|
|
|
490
570
|
handler.call(request)
|
|
491
571
|
end
|
|
492
572
|
|
|
573
|
+
# The route is registered at start, before connect records the agent's
|
|
574
|
+
# advertisement, so an unadvertised request answers -32601 until then.
|
|
575
|
+
#
|
|
576
|
+
# @rbs params: untyped
|
|
577
|
+
# @rbs return: (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError)
|
|
578
|
+
def mcp_message(params)
|
|
579
|
+
return ACP::RequestError.unadvertised_agent('mcpCapabilities.acp') unless @mcp_advertised
|
|
580
|
+
|
|
581
|
+
request = ACP::Types::Unstable::MessageMcpRequest.from_h(params)
|
|
582
|
+
rescue ACP::Types::ParseError => e
|
|
583
|
+
ACP::RequestError.invalid_params([e.message])
|
|
584
|
+
rescue KeyError, TypeError, NoMethodError
|
|
585
|
+
ACP::RequestError.invalid_params
|
|
586
|
+
else
|
|
587
|
+
# Safe: the route is only registered when a handler serves it.
|
|
588
|
+
handler = @mcp_message #: ^(ACP::Types::Unstable::MessageMcpRequest) -> (ACP::Types::Unstable::MessageMcpResponse::t | ACP::RequestError)
|
|
589
|
+
handler.call(request)
|
|
590
|
+
end
|
|
591
|
+
|
|
493
592
|
# The routes are registered at start, before connect records the advertised
|
|
494
593
|
# capabilities, so a request for an unadvertised mode answers -32602.
|
|
495
594
|
#
|
data/lib/acp/request_error.rb
CHANGED
|
@@ -82,6 +82,16 @@ class ACP::RequestError
|
|
|
82
82
|
new(code: INVALID_PARAMS, message: "Client does not advertise #{mode}")
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# unadvertised names a capability of the client's, this one a capability of
|
|
86
|
+
# the agent's: the same method-not-found code, with a message naming which
|
|
87
|
+
# side's advertisement is missing.
|
|
88
|
+
#
|
|
89
|
+
# @rbs capability: String
|
|
90
|
+
# @rbs return: ACP::RequestError
|
|
91
|
+
def self.unadvertised_agent(capability)
|
|
92
|
+
new(code: METHOD_NOT_FOUND, message: "Agent does not advertise #{capability}")
|
|
93
|
+
end
|
|
94
|
+
|
|
85
95
|
# @rbs return: ACP::RequestError
|
|
86
96
|
def self.internal_error
|
|
87
97
|
new(code: INTERNAL_ERROR, message: 'Internal error')
|
data/lib/acp/sdk.rb
CHANGED
|
@@ -9,5 +9,7 @@ root = __dir__ #: String
|
|
|
9
9
|
loader = Zeitwerk::Loader.new
|
|
10
10
|
loader.tag = 'acp-sdk'
|
|
11
11
|
loader.push_dir(root, namespace: ACP)
|
|
12
|
-
|
|
12
|
+
# The unstable types load only through `require 'acp/types/unstable'`, so
|
|
13
|
+
# Zeitwerk must not map them.
|
|
14
|
+
loader.ignore(__FILE__, "#{root}/version.rb", "#{root}/types/unstable.rb", "#{root}/types/unstable")
|
|
13
15
|
loader.setup
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Whether the peer cancelled one request. The transport creates one per served
|
|
4
|
+
# request, marks it when the peer's $/cancel_request arrives, and hands it to
|
|
5
|
+
# the serving thread, whose handler can observe it and end the request early.
|
|
6
|
+
class ACP::Transport::Cancellation
|
|
7
|
+
KEY = :acp_serving_cancellation #: Symbol
|
|
8
|
+
|
|
9
|
+
# Connections read this to expose the serving state to their handlers and
|
|
10
|
+
# write it to carry serving identity onto a thread they spawn; nil off a
|
|
11
|
+
# serve thread.
|
|
12
|
+
#
|
|
13
|
+
# @rbs return: ACP::Transport::Cancellation?
|
|
14
|
+
def self.current
|
|
15
|
+
Thread.current[KEY] #: ACP::Transport::Cancellation?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @rbs cancellation: ACP::Transport::Cancellation?
|
|
19
|
+
# @rbs return: void
|
|
20
|
+
def self.current=(cancellation)
|
|
21
|
+
Thread.current[KEY] = cancellation
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @rbs @lock: Thread::Mutex
|
|
25
|
+
# @rbs @cancelled: bool
|
|
26
|
+
|
|
27
|
+
# @rbs return: void
|
|
28
|
+
def initialize
|
|
29
|
+
@lock = Mutex.new
|
|
30
|
+
@cancelled = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @rbs return: void
|
|
34
|
+
def cancel
|
|
35
|
+
@lock.synchronize { @cancelled = true }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @rbs return: bool
|
|
39
|
+
def cancelled?
|
|
40
|
+
@lock.synchronize { @cancelled }
|
|
41
|
+
end
|
|
42
|
+
end
|