qoder-agent-sdk 1.0.2__tar.gz → 1.0.5__tar.gz
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.
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/PKG-INFO +1 -1
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/pyproject.toml +1 -1
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/__init__.py +17 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_cli_version.py +1 -1
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/client.py +2 -7
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/cloud_agent.py +7 -3
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/query.py +241 -5
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/transport/subprocess_cli.py +4 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_version.py +1 -1
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/client.py +47 -7
- qoder_agent_sdk-1.0.5/src/qoder_agent_sdk/plugins.py +126 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/types.py +120 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_client.py +2 -2
- qoder_agent_sdk-1.0.5/tests/test_initialize_model_catalog.py +165 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_tool_callbacks.py +27 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_transport.py +48 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_types.py +13 -0
- qoder_agent_sdk-1.0.5/tests/test_usage_info.py +138 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/.gitignore +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/LICENSE +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/README.md +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_bundled/.gitignore +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_errors.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/auth_helpers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/mcp_handler.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/mcp_serialize.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/message_parser.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/sdk_mcp_transport.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/session_mutations.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/sessions.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/transport/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/py.typed +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/query.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/settings.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/_shared/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/_shared/dotenv.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/_shared/e2e.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/_shared/e2e_env.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/_shared/fake_qodercli.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_description.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_disallowed_tools.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_effort.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_initial_prompt.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_max_turns.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_mcp_servers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_model.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_permission_mode.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_prompt.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_skills.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_agent_tools.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_disallowed_tools_empty.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_effort_max.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_empty_agents.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_initial_prompt_empty.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_many_agents.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_max_turns_zero.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_multi_agent_task_isolation.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_permission_mode_default.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_tools_empty.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_tools_non_existent.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_boundary_unregistered_session_agent.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_register_custom_subagent.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_session_agent.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_session_agent_from_sdk_agents.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_subagent_isolated_context.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_subagent_tool_call_agent_selection.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_subagent_tool_call_prompt.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_subagent_tool_call_timeout.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/agents/test_supported_agents_list.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/contract/test_subprocess_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/e2e/test_access_token_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/e2e/test_job_token_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/e2e/test_qodercli_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/unit/test_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/auth/unit/test_dotenv.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/functional/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/functional/_helpers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/functional/test_client_multi_turn_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/functional/test_create_agent_session_stream.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/functional/test_multi_turn_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/cloud_agent/test_cloud_agent_query.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_compact.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_config_change.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_cwd_changed.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_decision_merge.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_elicitation.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_elicitation_result.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_file_changed.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_hooks_e2e.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_instructions_loaded.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_notification.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_permission_denied.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_permission_request.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_post_tool_use.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_post_tool_use_failure.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_pre_tool_use.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_session_end.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_session_start.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_setup.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_stop.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_stop_failure.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_subagent.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_task_completed.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_task_created.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_teammate_idle.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_user_prompt_submit.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/hooks/functional/test_worktree.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/_e2e.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_can_use_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_client_and_streaming.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_external_prompt_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_options_and_modes.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_permission_modes.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_permission_request_hook_allow_skips_can_use_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_permission_request_hook_deny_fires_denied.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_permission_updates.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_settings_and_mcp_policy.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/permissions/test_streaming_async_iterable_can_use_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_bogus_plugin_dir.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_broken_plugin_content.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_local_plugin_init.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_multiple_plugin_dirs.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_plugin_contributes_resources.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_reload_plugins_commands.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_reload_plugins_error_count.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/test_reload_plugins_response_shape.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/unit/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/unit/test_plugin_dir_argv.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/unit/test_reload_plugins_control_request.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/plugins_loading_control/unit/test_settings_passthrough.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_at_file_reference.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_client_multi_turn_io.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_compact_context.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_multimodal_content_blocks.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_partial_stream_events.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_query_stream_turns_io.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_server_output_style_info.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_stream_user_message_io.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_string_prompt_io.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_io/test_system_prompt.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/fixtures/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/fixtures/elicit_mcp_server.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/fixtures/fake_oauth_mcp_server.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/fixtures/minimal_mcp_server.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/fixtures/sse_mcp_server.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_allowed_mcp_server_names_exempts_sdk.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_allowed_mcp_server_names_filters_stdio.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_control_request_timeout_does_not_poison_runner.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_elicitation_hook_probe.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_elicitation_result_hook_probe.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_elicitation_url_mode_unsupported.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_http_server_public_deepwiki.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_http_sse_bogus_url_not_crashing.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_mcp_server_status_metadata_fields.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_mcp_server_status_point_in_time_snapshot.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_mcp_status_empty_when_no_servers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_mixed_inprocess_and_stdio_servers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_mixed_three_way_transports.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_authenticate_custom_redirect_uri.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_authenticate_returns_url_with_dcr.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_authenticate_silent_refresh.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_clear_auth_resets_to_needs_auth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_inject_token_connects.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_needs_auth_status.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_submit_callback_completes_flow.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_oauth_token_persists_across_sessions.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_permission_prompt_tool_probe.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_annotations_not_echoed_in_status.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_close_tears_down_transport.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_multi_turn_reuse.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_multiple_servers_isolated.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_server_connected_status.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sdk_mcp_tool_description_passthrough.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_server_name_special_chars_prefix.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_sse_server_headers_and_connection.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_stdio_grandchild_reclaim_on_close.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_stdio_server_lifecycle.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/functional/test_strict_mcp_config_blocks_external_config.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_cli_args_allowed_mcp_server_names.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_cli_args_mcp_config.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_cli_args_permission_prompt_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_cli_args_strict_mcp_config.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_create_sdk_mcp_server.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_handler_accepts_extra_helper.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_inbound_elicitation_callback.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_inbound_elicitation_default_cancel.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_inbound_get_model_policy.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_mcp_authenticate_response_variants.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_mcp_server_status_request.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_mcp_server_status_timeout.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_mcp_toggle_and_reconnect_requests.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_sdk_mcp_handler_extra_signal.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_sdk_mcp_handler_non_content_normalization.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_mcp/unit/test_sdk_server_split_from_process_servers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/test_list_available_models_rich_fields.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/test_model_policy_e2e.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/test_model_selection_e2e_logging.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/functional/test_model_selection_logging.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/unit/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/unit/test_list_byok_providers.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/query_model_policy/unit/test_pull_suppresses_model_flag.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_capture_checkpoint_uuid_from_stream.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_enable_file_checkpointing.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_mid_stream_rewind.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_multiple_checkpoints_rewind.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_replay_user_messages_checkpoint_uuid.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_resume_session_rewind.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_bash_changes_not_tracked.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_cross_session_rejected.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_directory_ops_not_undone.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_dry_run_with_checkpoint.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_files_success.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_local_files_only.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_malformed_message_id.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_preserves_conversation.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_stats.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_unknown_message.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/rewind_api/test_rewind_without_checkpointing.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_continue_latest_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_fork_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_new_client_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_new_query_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_new_session_with_session_id.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/session_control/test_resume_session.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_agent_preloaded_skills.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_builtin_skills_visibility.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_default_skills_policy.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_enable_all_skills.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_enable_named_skills.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_plugin_skill_in_init.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/test_settings_skill_overrides.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/unit/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/skills_loading_control/unit/test_skills_argv.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_build_wheel.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_control_request_timeout.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_download_cli.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_errors.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_integration.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_mcp_dynamic.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_mcp_large_output.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_mcp_oauth.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_message_parser.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_permission_alignment.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_query.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_rate_limit_event_repro.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_sdk_mcp_integration.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_sdk_mcp_routing.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_session_mutations.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_sessions.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_streaming_client.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/test_subprocess_buffering.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/__init__.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/conftest.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_allowedTools_disallowedTools_conflict_priority.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_canUseTool_throws_error.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_concurrent_multiple_tool_uses.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_createSdkMcpServer_many_tools.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_handler_long_running_vs_controlRequestTimeoutMs.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_handler_returns_large_content.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_handler_returns_malformed_result.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_handler_returns_undefined.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_model_calls_unknown_tool_functional.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_tool_input_deeply_nested_schema.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_boundary_tool_input_many_fields.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_createSdkMcpServer_empty_tools.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_createSdkMcpServer_mcpServers_option.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_createSdkMcpServer_multiple_tools.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_createSdkMcpServer_name_routes_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_createSdkMcpServer_version.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_handler_isError_true.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_handler_isError_with_structured_data.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_handler_throws_async_rejection.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_handler_throws_non_Error.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_handler_throws_sync_Error.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_error_isError_allows_agent_retry.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_allowedTools_permits_mcp_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_allowedTools_server_pattern.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_allow_passthrough.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_conditional_on_input.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_deny.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_deny_with_interrupt.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_receives_mcp_toolName_format.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_updatedInput.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_canUseTool_updatedPermissions.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_disallowedTools_blocks_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_mode_bypassPermissions_with_mcp_tool.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_postToolUse_hook_additionalContext.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_permission_preToolUse_hook_updatedInput.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_return_empty_content_array.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_return_image_content.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_return_multiple_content_blocks.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_return_text_content.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_destructiveHint.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_handler_receives_args_and_returns_content.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_input_schema_describe.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_input_schema_nested.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_input_schema_zod_shape.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_name_and_description.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_openWorldHint.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_tool_readOnlyHint.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_createSdkMcpServer.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_createSdkMcpServer_duplicate_tool_name.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_createSdkMcpServer_empty_server_name.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_createSdkMcpServer_empty_tool_description.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_createSdkMcpServer_empty_tool_name.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_mcp_handler.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_sdk_mcp_transport.py +0 -0
- {qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/tests/tools/test_unit_tool_helper.py +0 -0
|
@@ -61,6 +61,7 @@ from .auth import (
|
|
|
61
61
|
qodercli_auth,
|
|
62
62
|
)
|
|
63
63
|
from .client import QoderSDKClient
|
|
64
|
+
from .plugins import PluginError, disable_plugin, enable_plugin, list_plugins
|
|
64
65
|
from .query import query
|
|
65
66
|
from .settings import filter_escalating_default_mode
|
|
66
67
|
from .types import (
|
|
@@ -154,7 +155,9 @@ from .types import (
|
|
|
154
155
|
PermissionResultAllow,
|
|
155
156
|
PermissionResultDeny,
|
|
156
157
|
PermissionUpdate,
|
|
158
|
+
PluginDetails,
|
|
157
159
|
PluginInfo,
|
|
160
|
+
PluginResources,
|
|
158
161
|
PostCompactHookInput,
|
|
159
162
|
PostToolUseFailureHookInput,
|
|
160
163
|
PostToolUseFailureHookSpecificOutput,
|
|
@@ -217,6 +220,10 @@ from .types import (
|
|
|
217
220
|
ToolProgressMessage,
|
|
218
221
|
ToolResultBlock,
|
|
219
222
|
ToolUseBlock,
|
|
223
|
+
UsageAddOnQuotaBucket,
|
|
224
|
+
UsageInfo,
|
|
225
|
+
UsageOrgResourcePackage,
|
|
226
|
+
UsageQuotaBucket,
|
|
220
227
|
UserMessage,
|
|
221
228
|
UserPromptSubmitHookInput,
|
|
222
229
|
UserPromptSubmitHookSpecificOutput,
|
|
@@ -823,6 +830,10 @@ __all__ = [
|
|
|
823
830
|
"ContentBlock",
|
|
824
831
|
"ContextUsageCategory",
|
|
825
832
|
"ContextUsageResponse",
|
|
833
|
+
"UsageAddOnQuotaBucket",
|
|
834
|
+
"UsageInfo",
|
|
835
|
+
"UsageOrgResourcePackage",
|
|
836
|
+
"UsageQuotaBucket",
|
|
826
837
|
# Tool callbacks
|
|
827
838
|
"CanUseTool",
|
|
828
839
|
"ToolPermissionContext",
|
|
@@ -902,7 +913,13 @@ __all__ = [
|
|
|
902
913
|
# Plugin support
|
|
903
914
|
"SdkPluginConfig",
|
|
904
915
|
"PluginInfo",
|
|
916
|
+
"PluginDetails",
|
|
917
|
+
"PluginResources",
|
|
905
918
|
"ReloadPluginsResponse",
|
|
919
|
+
"list_plugins",
|
|
920
|
+
"enable_plugin",
|
|
921
|
+
"disable_plugin",
|
|
922
|
+
"PluginError",
|
|
906
923
|
# File checkpointing
|
|
907
924
|
"RewindFilesResult",
|
|
908
925
|
# Session listing
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Internal client implementation."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import os
|
|
5
4
|
from collections.abc import AsyncIterable, AsyncIterator
|
|
6
5
|
from dataclasses import asdict, replace
|
|
7
6
|
from typing import Any
|
|
@@ -14,7 +13,7 @@ from ..types import (
|
|
|
14
13
|
)
|
|
15
14
|
from .auth_helpers import get_fetch_job_token, once_callback
|
|
16
15
|
from .message_parser import parse_message
|
|
17
|
-
from .query import Query
|
|
16
|
+
from .query import Query, resolve_initialize_timeout
|
|
18
17
|
from .transport import Transport
|
|
19
18
|
from .transport.subprocess_cli import SubprocessCLITransport
|
|
20
19
|
|
|
@@ -99,11 +98,7 @@ class InternalClient:
|
|
|
99
98
|
for name, agent_def in configured_options.agents.items()
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
initialize_timeout_ms = int(
|
|
104
|
-
os.environ.get("QODER_STREAM_CLOSE_TIMEOUT", "60000")
|
|
105
|
-
)
|
|
106
|
-
initialize_timeout = max(initialize_timeout_ms / 1000.0, 60.0)
|
|
101
|
+
initialize_timeout = resolve_initialize_timeout()
|
|
107
102
|
|
|
108
103
|
# Create Query to handle control protocol
|
|
109
104
|
# Always use streaming mode internally (matching TypeScript SDK)
|
{qoder_agent_sdk-1.0.2 → qoder_agent_sdk-1.0.5}/src/qoder_agent_sdk/_internal/cloud_agent.py
RENAMED
|
@@ -768,9 +768,7 @@ class CloudAgentQuery:
|
|
|
768
768
|
if self._result_emitted or self._closed:
|
|
769
769
|
return
|
|
770
770
|
self._result_emitted = True
|
|
771
|
-
self._queue.put_nowait(
|
|
772
|
-
ResultMessage(**self._build_result_base(), **kwargs)
|
|
773
|
-
)
|
|
771
|
+
self._queue.put_nowait(ResultMessage(**self._build_result_base(), **kwargs))
|
|
774
772
|
|
|
775
773
|
def _build_result_base(self) -> dict[str, Any]:
|
|
776
774
|
elapsed_ms = int((time.monotonic() - self._started_at) * 1000)
|
|
@@ -936,6 +934,9 @@ class CloudAgentClientSession:
|
|
|
936
934
|
async def set_model(self, _model: str | None = None) -> None:
|
|
937
935
|
self._unsupported("set_model")
|
|
938
936
|
|
|
937
|
+
async def set_proxy(self, _proxy: str | None = None) -> None:
|
|
938
|
+
self._unsupported("set_proxy")
|
|
939
|
+
|
|
939
940
|
async def get_available_models(self) -> list[Any]:
|
|
940
941
|
self._unsupported("get_available_models")
|
|
941
942
|
|
|
@@ -987,6 +988,9 @@ class CloudAgentClientSession:
|
|
|
987
988
|
async def get_context_usage(self) -> Any:
|
|
988
989
|
self._unsupported("get_context_usage")
|
|
989
990
|
|
|
991
|
+
async def get_usage_info(self) -> None:
|
|
992
|
+
return None
|
|
993
|
+
|
|
990
994
|
async def _run_turn(self, prompt: str | AsyncIterable[dict[str, Any]]) -> None:
|
|
991
995
|
async with self._turn_lock:
|
|
992
996
|
if self._closed or self._turn_options is None:
|
|
@@ -36,11 +36,16 @@ from ..types import (
|
|
|
36
36
|
PermissionMode,
|
|
37
37
|
PermissionResultAllow,
|
|
38
38
|
PermissionResultDeny,
|
|
39
|
+
PluginDetails,
|
|
39
40
|
SDKControlPermissionRequest,
|
|
40
41
|
SDKControlRequest,
|
|
41
42
|
SDKControlResponse,
|
|
42
43
|
SDKHookCallbackRequest,
|
|
43
44
|
ToolPermissionContext,
|
|
45
|
+
UsageAddOnQuotaBucket,
|
|
46
|
+
UsageInfo,
|
|
47
|
+
UsageOrgResourcePackage,
|
|
48
|
+
UsageQuotaBucket,
|
|
44
49
|
)
|
|
45
50
|
from .mcp_serialize import serialize_mcp_servers
|
|
46
51
|
from .transport import Transport
|
|
@@ -50,6 +55,29 @@ if TYPE_CHECKING:
|
|
|
50
55
|
|
|
51
56
|
logger = logging.getLogger(__name__)
|
|
52
57
|
|
|
58
|
+
INITIALIZE_TIMEOUT_MS = 120_000
|
|
59
|
+
INITIALIZE_TIMEOUT = INITIALIZE_TIMEOUT_MS / 1000.0
|
|
60
|
+
CATALOG_READY_INITIALIZE_MIN_TIMEOUT_MS = INITIALIZE_TIMEOUT_MS
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def resolve_initialize_timeout() -> float:
|
|
64
|
+
"""Resolve the initialize timeout from env var or default.
|
|
65
|
+
|
|
66
|
+
Shared by ``QoderSDKClient.connect()`` and ``InternalClient.process_query()``
|
|
67
|
+
to avoid duplicating the env-var lookup and floor logic.
|
|
68
|
+
"""
|
|
69
|
+
_timeout_env = os.environ.get("QODER_STREAM_CLOSE_TIMEOUT")
|
|
70
|
+
initialize_timeout_ms = (
|
|
71
|
+
int(_timeout_env) if _timeout_env is not None else INITIALIZE_TIMEOUT_MS
|
|
72
|
+
)
|
|
73
|
+
return max(initialize_timeout_ms / 1000.0, 60.0)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ControlProtocolError(Exception):
|
|
77
|
+
def __init__(self, message: str, code: str | None = None) -> None:
|
|
78
|
+
super().__init__(message)
|
|
79
|
+
self.code = code
|
|
80
|
+
|
|
53
81
|
|
|
54
82
|
def _normalize_oauth_resolution(
|
|
55
83
|
resolution: McpOAuthResolution,
|
|
@@ -252,6 +280,161 @@ def _normalize_control_error(err: Exception) -> tuple[str, str | None]:
|
|
|
252
280
|
return message, None
|
|
253
281
|
|
|
254
282
|
|
|
283
|
+
def _error_payload_from_exception(err: Exception) -> dict[str, Any]:
|
|
284
|
+
message, code = _normalize_control_error(err)
|
|
285
|
+
payload: dict[str, Any] = {"type": "error", "error": message}
|
|
286
|
+
if code:
|
|
287
|
+
payload["code"] = code
|
|
288
|
+
return payload
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _exception_from_error_payload(message: dict[str, Any]) -> Exception:
|
|
292
|
+
error = message.get("error", "Unknown error")
|
|
293
|
+
code = message.get("code")
|
|
294
|
+
return ControlProtocolError(
|
|
295
|
+
error if isinstance(error, str) else str(error),
|
|
296
|
+
code if isinstance(code, str) and code else None,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _record_or_none(value: Any) -> dict[str, Any] | None:
|
|
301
|
+
return value if isinstance(value, dict) else None
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _read_str(source: dict[str, Any] | None, key: str) -> str | None:
|
|
305
|
+
value = source.get(key) if source is not None else None
|
|
306
|
+
return value if isinstance(value, str) else None
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _read_bool(source: dict[str, Any] | None, key: str) -> bool | None:
|
|
310
|
+
value = source.get(key) if source is not None else None
|
|
311
|
+
return value if isinstance(value, bool) else None
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _read_number(source: dict[str, Any] | None, key: str) -> float | None:
|
|
315
|
+
value = source.get(key) if source is not None else None
|
|
316
|
+
if isinstance(value, bool):
|
|
317
|
+
return None
|
|
318
|
+
if isinstance(value, (int, float)):
|
|
319
|
+
return float(value)
|
|
320
|
+
if isinstance(value, str) and value.strip():
|
|
321
|
+
try:
|
|
322
|
+
return float(value)
|
|
323
|
+
except ValueError:
|
|
324
|
+
return None
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _normalize_usage_quota_bucket(value: Any) -> UsageQuotaBucket | None:
|
|
329
|
+
source = _record_or_none(value)
|
|
330
|
+
total = _read_number(source, "total")
|
|
331
|
+
used = _read_number(source, "used")
|
|
332
|
+
remaining = _read_number(source, "remaining")
|
|
333
|
+
percentage = _read_number(source, "percentage")
|
|
334
|
+
unit = _read_str(source, "unit")
|
|
335
|
+
if (
|
|
336
|
+
total is None
|
|
337
|
+
or used is None
|
|
338
|
+
or remaining is None
|
|
339
|
+
or percentage is None
|
|
340
|
+
or unit is None
|
|
341
|
+
):
|
|
342
|
+
return None
|
|
343
|
+
return {
|
|
344
|
+
"total": total,
|
|
345
|
+
"used": used,
|
|
346
|
+
"remaining": remaining,
|
|
347
|
+
"percentage": percentage,
|
|
348
|
+
"unit": unit,
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _normalize_usage_add_on_quota(value: Any) -> UsageAddOnQuotaBucket | None:
|
|
353
|
+
source = _record_or_none(value)
|
|
354
|
+
quota = _normalize_usage_quota_bucket(source)
|
|
355
|
+
detail_url = _read_str(source, "detailUrl")
|
|
356
|
+
if quota is None or detail_url is None:
|
|
357
|
+
return None
|
|
358
|
+
return {**quota, "detailUrl": detail_url}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _normalize_usage_org_resource_package(
|
|
362
|
+
value: Any,
|
|
363
|
+
) -> UsageOrgResourcePackage | None:
|
|
364
|
+
source = _record_or_none(value)
|
|
365
|
+
used = _read_number(source, "used")
|
|
366
|
+
cap = _read_number(source, "cap")
|
|
367
|
+
remaining = _read_number(source, "remaining")
|
|
368
|
+
percentage = _read_number(source, "percentage")
|
|
369
|
+
available = _read_bool(source, "available")
|
|
370
|
+
unit = _read_str(source, "unit")
|
|
371
|
+
if (
|
|
372
|
+
used is None
|
|
373
|
+
or cap is None
|
|
374
|
+
or remaining is None
|
|
375
|
+
or percentage is None
|
|
376
|
+
or available is None
|
|
377
|
+
or unit is None
|
|
378
|
+
):
|
|
379
|
+
return None
|
|
380
|
+
return {
|
|
381
|
+
"used": used,
|
|
382
|
+
"cap": cap,
|
|
383
|
+
"remaining": remaining,
|
|
384
|
+
"percentage": percentage,
|
|
385
|
+
"available": available,
|
|
386
|
+
"unit": unit,
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _normalize_usage_info(value: Any) -> UsageInfo | None:
|
|
391
|
+
source = _record_or_none(value)
|
|
392
|
+
user_id = _read_str(source, "userId")
|
|
393
|
+
user_type = _read_str(source, "userType")
|
|
394
|
+
total_usage_percentage = _read_number(source, "totalUsagePercentage")
|
|
395
|
+
is_highest_tier = _read_bool(source, "isHighestTier")
|
|
396
|
+
expires_at = _read_number(source, "expiresAt")
|
|
397
|
+
upgrade_url = _read_str(source, "upgradeUrl")
|
|
398
|
+
user_quota = _normalize_usage_quota_bucket(
|
|
399
|
+
source.get("userQuota") if source is not None else None
|
|
400
|
+
)
|
|
401
|
+
add_on_quota = _normalize_usage_add_on_quota(
|
|
402
|
+
source.get("addOnQuota") if source is not None else None
|
|
403
|
+
)
|
|
404
|
+
is_quota_exceeded = _read_bool(source, "isQuotaExceeded")
|
|
405
|
+
is_plan_quota_prorated = _read_bool(source, "isPlanQuotaProrated")
|
|
406
|
+
org_resource_package = _normalize_usage_org_resource_package(
|
|
407
|
+
source.get("orgResourcePackage") if source is not None else None
|
|
408
|
+
)
|
|
409
|
+
if (
|
|
410
|
+
user_id is None
|
|
411
|
+
or user_type is None
|
|
412
|
+
or total_usage_percentage is None
|
|
413
|
+
or is_highest_tier is None
|
|
414
|
+
or expires_at is None
|
|
415
|
+
or upgrade_url is None
|
|
416
|
+
or user_quota is None
|
|
417
|
+
or add_on_quota is None
|
|
418
|
+
or is_quota_exceeded is None
|
|
419
|
+
or is_plan_quota_prorated is None
|
|
420
|
+
or org_resource_package is None
|
|
421
|
+
):
|
|
422
|
+
return None
|
|
423
|
+
return {
|
|
424
|
+
"userId": user_id,
|
|
425
|
+
"userType": user_type,
|
|
426
|
+
"totalUsagePercentage": total_usage_percentage,
|
|
427
|
+
"isHighestTier": is_highest_tier,
|
|
428
|
+
"expiresAt": expires_at,
|
|
429
|
+
"upgradeUrl": upgrade_url,
|
|
430
|
+
"userQuota": user_quota,
|
|
431
|
+
"addOnQuota": add_on_quota,
|
|
432
|
+
"isQuotaExceeded": is_quota_exceeded,
|
|
433
|
+
"isPlanQuotaProrated": is_plan_quota_prorated,
|
|
434
|
+
"orgResourcePackage": org_resource_package,
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
|
|
255
438
|
def _resolve_exit_plan_mode_details(
|
|
256
439
|
request: SDKControlPermissionRequest,
|
|
257
440
|
) -> ExitPlanModeApprovalDetails | None:
|
|
@@ -323,7 +506,7 @@ class Query:
|
|
|
323
506
|
| None = None,
|
|
324
507
|
hooks: dict[str, list[dict[str, Any]]] | None = None,
|
|
325
508
|
sdk_mcp_servers: dict[str, "McpServer"] | None = None,
|
|
326
|
-
initialize_timeout: float =
|
|
509
|
+
initialize_timeout: float = INITIALIZE_TIMEOUT,
|
|
327
510
|
agents: dict[str, dict[str, Any]] | None = None,
|
|
328
511
|
enable_file_checkpointing: bool | None = None,
|
|
329
512
|
on_mcp_oauth_required: OnMcpOAuthRequired | None = None,
|
|
@@ -394,6 +577,7 @@ class Query:
|
|
|
394
577
|
self._initialized = False
|
|
395
578
|
self._closed = False
|
|
396
579
|
self._initialization_result: dict[str, Any] | None = None
|
|
580
|
+
self._initialization_task: asyncio.Task[dict[str, Any] | None] | None = None
|
|
397
581
|
# Query observes auth failures in stream-json messages. Keep a local
|
|
398
582
|
# guard because the transport may also observe an auth-error exit code,
|
|
399
583
|
# while the client wrapper protects the final user callback.
|
|
@@ -410,6 +594,21 @@ class Query:
|
|
|
410
594
|
"""
|
|
411
595
|
if not self.is_streaming_mode:
|
|
412
596
|
return None
|
|
597
|
+
if self._initialized:
|
|
598
|
+
return self._initialization_result
|
|
599
|
+
if self._initialization_task is not None:
|
|
600
|
+
return await self._initialization_task
|
|
601
|
+
|
|
602
|
+
loop = asyncio.get_running_loop()
|
|
603
|
+
self._initialization_task = loop.create_task(self._perform_initialize())
|
|
604
|
+
try:
|
|
605
|
+
return await self._initialization_task
|
|
606
|
+
finally:
|
|
607
|
+
if not self._initialized:
|
|
608
|
+
self._initialization_task = None
|
|
609
|
+
|
|
610
|
+
async def _perform_initialize(self) -> dict[str, Any] | None:
|
|
611
|
+
initialize_timeout_ms = int(self._initialize_timeout * 1000)
|
|
413
612
|
|
|
414
613
|
# Build hooks configuration for initialization
|
|
415
614
|
hooks_config: dict[str, Any] = {}
|
|
@@ -437,7 +636,10 @@ class Query:
|
|
|
437
636
|
"type": "initialize",
|
|
438
637
|
"subtype": "initialize",
|
|
439
638
|
"modelPolicyProvider": False,
|
|
639
|
+
"initializeTimeoutMs": initialize_timeout_ms,
|
|
440
640
|
}
|
|
641
|
+
if initialize_timeout_ms >= CATALOG_READY_INITIALIZE_MIN_TIMEOUT_MS:
|
|
642
|
+
request["supportsCatalogReadyInitialize"] = True
|
|
441
643
|
if self.resolve_model is not None:
|
|
442
644
|
request["modelPolicyProvider"] = True
|
|
443
645
|
logger.debug("initialize: pull-mode enabled (modelPolicyProvider=True)")
|
|
@@ -540,8 +742,8 @@ class Query:
|
|
|
540
742
|
if request_id in self.pending_control_responses:
|
|
541
743
|
event = self.pending_control_responses[request_id]
|
|
542
744
|
if response.get("subtype") == "error":
|
|
543
|
-
self.pending_control_results[request_id] =
|
|
544
|
-
response
|
|
745
|
+
self.pending_control_results[request_id] = (
|
|
746
|
+
_exception_from_error_payload(response)
|
|
545
747
|
)
|
|
546
748
|
else:
|
|
547
749
|
self.pending_control_results[request_id] = response
|
|
@@ -600,7 +802,7 @@ class Query:
|
|
|
600
802
|
self.pending_control_results[request_id] = e
|
|
601
803
|
event.set()
|
|
602
804
|
# Put error in stream so iterators can handle it
|
|
603
|
-
await self._message_send.send(
|
|
805
|
+
await self._message_send.send(_error_payload_from_exception(e))
|
|
604
806
|
finally:
|
|
605
807
|
# Unblock any waiters (e.g. string-prompt path waiting for first
|
|
606
808
|
# result) so they don't stall for the full timeout on early exit.
|
|
@@ -1263,6 +1465,15 @@ class Query:
|
|
|
1263
1465
|
"""Get a breakdown of current context window usage by category."""
|
|
1264
1466
|
return await self._send_control_request({"subtype": "get_context_usage"})
|
|
1265
1467
|
|
|
1468
|
+
async def get_usage_info(self) -> UsageInfo | None:
|
|
1469
|
+
"""Get account quota and usage information."""
|
|
1470
|
+
try:
|
|
1471
|
+
resp = await self._send_control_request({"subtype": "get_usage_info"})
|
|
1472
|
+
except Exception:
|
|
1473
|
+
# Compat: older CLIs reject unknown control subtypes.
|
|
1474
|
+
return None
|
|
1475
|
+
return _normalize_usage_info(resp.get("usage"))
|
|
1476
|
+
|
|
1266
1477
|
async def interrupt(self) -> None:
|
|
1267
1478
|
"""Send interrupt control request."""
|
|
1268
1479
|
await self._send_control_request({"subtype": "interrupt"})
|
|
@@ -1285,6 +1496,15 @@ class Query:
|
|
|
1285
1496
|
}
|
|
1286
1497
|
)
|
|
1287
1498
|
|
|
1499
|
+
async def set_proxy(self, proxy: str | None = None) -> None:
|
|
1500
|
+
"""Set or clear the proxy for the running CLI session."""
|
|
1501
|
+
await self._send_control_request(
|
|
1502
|
+
{
|
|
1503
|
+
"subtype": "set_proxy",
|
|
1504
|
+
"proxy": proxy,
|
|
1505
|
+
}
|
|
1506
|
+
)
|
|
1507
|
+
|
|
1288
1508
|
async def get_available_models(self) -> list[ModelInfo]:
|
|
1289
1509
|
"""Query the CLI for the list of available models.
|
|
1290
1510
|
|
|
@@ -1377,6 +1597,11 @@ class Query:
|
|
|
1377
1597
|
"""
|
|
1378
1598
|
return await self._send_control_request({"subtype": "reload_plugins"})
|
|
1379
1599
|
|
|
1600
|
+
async def list_plugins(self) -> list[PluginDetails]:
|
|
1601
|
+
"""List plugins loaded in the current session."""
|
|
1602
|
+
result = await self._send_control_request({"subtype": "list_plugins"})
|
|
1603
|
+
return cast(list[PluginDetails], result["plugins"])
|
|
1604
|
+
|
|
1380
1605
|
async def reconnect_mcp_server(self, server_name: str) -> None:
|
|
1381
1606
|
"""Reconnect a disconnected or failed MCP server.
|
|
1382
1607
|
|
|
@@ -1576,6 +1801,8 @@ class Query:
|
|
|
1576
1801
|
before closing stdin to allow bidirectional control protocol communication.
|
|
1577
1802
|
"""
|
|
1578
1803
|
try:
|
|
1804
|
+
await self.initialize()
|
|
1805
|
+
|
|
1579
1806
|
async for message in stream:
|
|
1580
1807
|
if self._closed:
|
|
1581
1808
|
break
|
|
@@ -1584,6 +1811,10 @@ class Query:
|
|
|
1584
1811
|
await self.wait_for_result_and_end_input()
|
|
1585
1812
|
except Exception as e:
|
|
1586
1813
|
logger.debug(f"Error streaming input: {e}")
|
|
1814
|
+
try:
|
|
1815
|
+
await self._message_send.send(_error_payload_from_exception(e))
|
|
1816
|
+
finally:
|
|
1817
|
+
await self.transport.end_input()
|
|
1587
1818
|
|
|
1588
1819
|
async def receive_messages(self) -> AsyncIterator[dict[str, Any]]:
|
|
1589
1820
|
"""Receive SDK messages (not control messages)."""
|
|
@@ -1592,13 +1823,18 @@ class Query:
|
|
|
1592
1823
|
if message.get("type") == "end":
|
|
1593
1824
|
break
|
|
1594
1825
|
elif message.get("type") == "error":
|
|
1595
|
-
raise
|
|
1826
|
+
raise _exception_from_error_payload(message)
|
|
1596
1827
|
|
|
1597
1828
|
yield message
|
|
1598
1829
|
|
|
1599
1830
|
async def close(self) -> None:
|
|
1600
1831
|
"""Close the query and transport."""
|
|
1601
1832
|
self._closed = True
|
|
1833
|
+
if (
|
|
1834
|
+
self._initialization_task is not None
|
|
1835
|
+
and not self._initialization_task.done()
|
|
1836
|
+
):
|
|
1837
|
+
self._initialization_task.cancel()
|
|
1602
1838
|
for task in list(self._child_tasks):
|
|
1603
1839
|
task.cancel()
|
|
1604
1840
|
if self._read_task is not None and not self._read_task.done():
|
|
@@ -44,6 +44,7 @@ logger = logging.getLogger(__name__)
|
|
|
44
44
|
_DEFAULT_MAX_BUFFER_SIZE = 1024 * 1024 # 1MB buffer limit
|
|
45
45
|
MINIMUM_RUNTIME_VERSION = "0.2.0"
|
|
46
46
|
CLI_EXIT_CODE_AUTH_ERROR = 41
|
|
47
|
+
PROXY_ENV_VARS = ("HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy")
|
|
47
48
|
|
|
48
49
|
_PERMISSION_POLICY_TO_RULE_KEY = {
|
|
49
50
|
"always_allow": "allow",
|
|
@@ -683,6 +684,9 @@ class SubprocessCLITransport(Transport):
|
|
|
683
684
|
process_env[key] = value
|
|
684
685
|
else:
|
|
685
686
|
process_env.pop(key, None)
|
|
687
|
+
if self._options.proxy is not None:
|
|
688
|
+
for key in PROXY_ENV_VARS:
|
|
689
|
+
process_env[key] = self._options.proxy
|
|
686
690
|
if self._auth_payload_path is not None:
|
|
687
691
|
process_env["QODER_SDK_AUTH_PAYLOAD_FILE"] = str(
|
|
688
692
|
self._auth_payload_path
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Qoder SDK client for interactive agent sessions."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import os
|
|
5
4
|
from collections.abc import AsyncIterable, AsyncIterator
|
|
6
5
|
from dataclasses import asdict, replace
|
|
7
6
|
from typing import Any, cast
|
|
@@ -20,10 +19,12 @@ from .types import (
|
|
|
20
19
|
ModelInfo,
|
|
21
20
|
OAuthToken,
|
|
22
21
|
PermissionMode,
|
|
22
|
+
PluginDetails,
|
|
23
23
|
QoderAgentOptions,
|
|
24
24
|
ReloadPluginsResponse,
|
|
25
25
|
ResultMessage,
|
|
26
26
|
RewindFilesResult,
|
|
27
|
+
UsageInfo,
|
|
27
28
|
)
|
|
28
29
|
|
|
29
30
|
|
|
@@ -98,7 +99,7 @@ class QoderSDKClient:
|
|
|
98
99
|
await self._query.connect(prompt=prompt)
|
|
99
100
|
return
|
|
100
101
|
|
|
101
|
-
from ._internal.query import Query
|
|
102
|
+
from ._internal.query import Query, resolve_initialize_timeout
|
|
102
103
|
from ._internal.transport.subprocess_cli import SubprocessCLITransport
|
|
103
104
|
|
|
104
105
|
# Auto-connect with empty async iterable if no prompt is provided
|
|
@@ -148,11 +149,7 @@ class QoderSDKClient:
|
|
|
148
149
|
if isinstance(config, dict) and config.get("type") == "sdk":
|
|
149
150
|
sdk_mcp_servers[name] = config["instance"] # type: ignore[typeddict-item]
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
initialize_timeout_ms = int(
|
|
153
|
-
os.environ.get("QODER_STREAM_CLOSE_TIMEOUT", "60000")
|
|
154
|
-
)
|
|
155
|
-
initialize_timeout = max(initialize_timeout_ms / 1000.0, 60.0)
|
|
152
|
+
initialize_timeout = resolve_initialize_timeout()
|
|
156
153
|
|
|
157
154
|
# Convert agents to dict format for initialize request
|
|
158
155
|
agents_dict: dict[str, dict[str, Any]] | None = None
|
|
@@ -313,6 +310,18 @@ class QoderSDKClient:
|
|
|
313
310
|
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
314
311
|
await self._query.set_model(model)
|
|
315
312
|
|
|
313
|
+
async def set_proxy(self, proxy: str | None = None) -> None:
|
|
314
|
+
"""Set or clear the proxy during conversation.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
proxy: Proxy URL for the running qodercli session. Supports
|
|
318
|
+
``http://``, ``https://``, ``socks5://``, and ``socks://``.
|
|
319
|
+
Pass ``None`` or an empty string to clear the proxy.
|
|
320
|
+
"""
|
|
321
|
+
if not self._query:
|
|
322
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
323
|
+
await self._query.set_proxy(proxy)
|
|
324
|
+
|
|
316
325
|
async def get_available_models(self) -> list[ModelInfo]:
|
|
317
326
|
"""Query the CLI for the list of available models.
|
|
318
327
|
|
|
@@ -461,6 +470,13 @@ class QoderSDKClient:
|
|
|
461
470
|
result = await self._query.reload_plugins()
|
|
462
471
|
return cast(ReloadPluginsResponse, result)
|
|
463
472
|
|
|
473
|
+
async def list_plugins(self) -> list[PluginDetails]:
|
|
474
|
+
"""List plugins loaded in the current session."""
|
|
475
|
+
if not self._query:
|
|
476
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
477
|
+
result: list[PluginDetails] = await self._query.list_plugins()
|
|
478
|
+
return result
|
|
479
|
+
|
|
464
480
|
async def reconnect_mcp_server(self, server_name: str) -> None:
|
|
465
481
|
"""Reconnect a disconnected or failed MCP server (only works with streaming mode).
|
|
466
482
|
|
|
@@ -696,6 +712,30 @@ class QoderSDKClient:
|
|
|
696
712
|
result: ContextUsageResponse = await self._query.get_context_usage()
|
|
697
713
|
return result
|
|
698
714
|
|
|
715
|
+
async def get_usage_info(self) -> UsageInfo | None:
|
|
716
|
+
"""Get current account quota and usage information.
|
|
717
|
+
|
|
718
|
+
Returns the same account usage payload exposed by the CLI's usage API.
|
|
719
|
+
Missing required fields are not synthesized by the SDK; when the
|
|
720
|
+
running CLI cannot provide a complete usage payload this returns
|
|
721
|
+
``None``.
|
|
722
|
+
|
|
723
|
+
Returns:
|
|
724
|
+
UsageInfo dictionary, or ``None`` when unavailable.
|
|
725
|
+
|
|
726
|
+
Example:
|
|
727
|
+
```python
|
|
728
|
+
async with QoderSDKClient() as client:
|
|
729
|
+
usage = await client.get_usage_info()
|
|
730
|
+
if usage is not None:
|
|
731
|
+
print(usage["totalUsagePercentage"])
|
|
732
|
+
```
|
|
733
|
+
"""
|
|
734
|
+
if not self._query:
|
|
735
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
736
|
+
result = await self._query.get_usage_info()
|
|
737
|
+
return cast(UsageInfo | None, result)
|
|
738
|
+
|
|
699
739
|
async def get_server_info(self) -> dict[str, Any] | None:
|
|
700
740
|
"""Get server initialization info including available commands and output styles.
|
|
701
741
|
|