signalwire-sdk 3.2.0.dev94__tar.gz → 3.2.0.dev96__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.
- {signalwire_sdk-3.2.0.dev94/signalwire/signalwire_sdk.egg-info → signalwire_sdk-3.2.0.dev96}/PKG-INFO +1 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/pyproject.toml +1 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/__init__.py +7 -5
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/agent_server.py +10 -2
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/logging_config.py +24 -3
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/web_mixin.py +6 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_service.py +6 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/call.py +20 -7
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/client.py +148 -10
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/constants.py +8 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/_base.py +80 -15
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/_pagination.py +11 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/calling_resources_generated.py +348 -55
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/chat_resources_generated.py +9 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/datasphere_resources_generated.py +55 -9
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/fabric_resources_generated.py +296 -62
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/fax_resources_generated.py +2 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/logs_resources_generated.py +8 -2
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/message_resources_generated.py +2 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/messages_resources_generated.py +16 -2
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/project_resources_generated.py +23 -4
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/projects_resources_generated.py +22 -4
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/pubsub_resources_generated.py +9 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/relay_rest_resources_generated.py +362 -85
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/video_resources_generated.py +154 -36
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/voice_resources_generated.py +10 -2
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96/signalwire/signalwire_sdk.egg-info}/PKG-INFO +1 -1
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/LICENSE +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/man/sw-agent-init.1 +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/man/sw-search.1 +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/man/swaig-test.1 +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/setup.cfg +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/setup.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/agents/bedrock.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/build_search.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/config.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/core/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/core/agent_loader.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/core/argparse_helpers.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/core/dynamic_config.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/core/service_loader.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/dokku.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/execution/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/execution/datamap_exec.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/execution/webhook_exec.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/init_project.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/output/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/output/output_formatter.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/output/swml_dump.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/simulation/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/simulation/data_generation.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/simulation/data_overrides.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/simulation/mock_env.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/swaig_test_wrapper.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/test_swaig.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/cli/types.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/_agent_host.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/config/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/deployment/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/deployment/handlers/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/prompt/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/prompt/manager.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/routing/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/security/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/swml/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/tools/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/tools/decorator.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/tools/registry.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent/tools/type_inference.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/agent_base.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/auth_handler.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/config_loader.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/contexts.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/data_map.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/function_result.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/_mixin_host.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/ai_config_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/auth_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/mcp_server_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/prompt_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/serverless_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/skill_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/state_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/mixins/tool_mixin.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/pom_builder.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/post_prompt_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security/security_utils.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security/session_manager.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security/webhook_middleware.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security/webhook_validator.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/security_config.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/skill_base.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/skill_manager.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swaig_actions_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swaig_function.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swaig_request_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_builder.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_handler.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_renderer.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_verbs_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/web.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/livewire/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/livewire/plugins.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/mcp_gateway/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/mcp_gateway/gateway_service.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/mcp_gateway/mcp_manager.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/mcp_gateway/session_manager.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/pom/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/pom/pom.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/pom/pom_tool.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/concierge.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/faq_bot.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/info_gatherer.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/receptionist.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/prefabs/survey.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/py.typed +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/event.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/message.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/protocol_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/_request_options.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/call_handler.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/client.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/_client_tree_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/addresses.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/calling.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/calling_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/chat.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/chat_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/datasphere.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/datasphere_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/fabric.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/fabric_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/fax_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/imported_numbers.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/logs.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/logs_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/lookup.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/message_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/messages_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/mfa.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/number_groups.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/phone_numbers.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/project.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/project_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/projects_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/pubsub.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/pubsub_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/queues.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/recordings.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/registry.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/relay_rest_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/short_codes.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/sip_profile.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/swml_webhooks_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/verified_callers.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/video.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/video_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/namespaces/voice_types_generated.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/schema.json +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/document_processor.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/index_builder.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/migration.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/models.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/pgvector_backend.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/query_processor.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/search_engine.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/search/search_service.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/api_ninjas_trivia/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/api_ninjas_trivia/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/api_ninjas_trivia/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/claude_skills/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/claude_skills/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/claude_skills/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere_serverless/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere_serverless/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datasphere_serverless/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datetime/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datetime/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/datetime/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/google_maps/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/google_maps/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/info_gatherer/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/info_gatherer/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/info_gatherer/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/joke/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/joke/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/joke/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/math/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/math/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/math/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/mcp_gateway/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/mcp_gateway/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/mcp_gateway/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/native_vector_search/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/native_vector_search/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/native_vector_search/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/play_background_file/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/play_background_file/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/play_background_file/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/registry.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/spider/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/spider/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/spider/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/swml_transfer/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/swml_transfer/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/swml_transfer/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/weather_api/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/weather_api/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/weather_api/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/web_search/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/web_search/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/web_search/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/web_search/skill_improved.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/web_search/skill_original.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/wikipedia_search/README.md +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/wikipedia_search/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/skills/wikipedia_search/skill.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/pom_utils.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/schema_utils.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/token_generators.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/url_validator.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/utils/validators.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/web/__init__.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/web/web_service.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire_sdk.egg-info/SOURCES.txt +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire_sdk.egg-info/dependency_links.txt +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire_sdk.egg-info/entry_points.txt +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire_sdk.egg-info/requires.txt +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire_sdk.egg-info/top_level.txt +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/tests/test_examples.py +0 -0
- {signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/tests/test_mcp_integration.py +0 -0
|
@@ -14,8 +14,12 @@ A package for building AI agents using SignalWire's AI and SWML capabilities.
|
|
|
14
14
|
|
|
15
15
|
from typing import TYPE_CHECKING, Any
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
17
|
+
# Library-safe logging: importing signalwire installs ONLY a NullHandler on the
|
|
18
|
+
# `signalwire` namespace logger (done at logging_config module load). It does NOT
|
|
19
|
+
# configure global logging — that would hijack the host application's logging (its
|
|
20
|
+
# structlog config, its root/generic-named loggers). The app opts in to SDK log
|
|
21
|
+
# OUTPUT by calling configure_logging() explicitly; the server/CLI entry points do.
|
|
22
|
+
from .core.logging_config import configure_logging # noqa: F401 (re-exported)
|
|
19
23
|
|
|
20
24
|
if TYPE_CHECKING:
|
|
21
25
|
from signalwire.rest.client import RestClient as _RestClient
|
|
@@ -48,9 +52,7 @@ if TYPE_CHECKING:
|
|
|
48
52
|
from signalwire.utils.schema_utils import SchemaValidationError
|
|
49
53
|
from signalwire.web import WebService
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
__version__ = "3.2.0.dev94"
|
|
55
|
+
__version__ = "3.2.0.dev96"
|
|
54
56
|
|
|
55
57
|
# §6.2-python (owner decision: NO packaging split — one package, all deps required;
|
|
56
58
|
# IMPORT-TIME behavior only): the agent/web symbols are lazy-imported via module
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/agent_server.py
RENAMED
|
@@ -68,7 +68,7 @@ class AgentServer:
|
|
|
68
68
|
self.app = FastAPI(
|
|
69
69
|
title="SignalWire AI Agents",
|
|
70
70
|
description="Hosted SignalWire AI Agents",
|
|
71
|
-
version="3.2.0.
|
|
71
|
+
version="3.2.0.dev96",
|
|
72
72
|
redirect_slashes=False,
|
|
73
73
|
docs_url=None,
|
|
74
74
|
redoc_url=None,
|
|
@@ -372,7 +372,15 @@ class AgentServer:
|
|
|
372
372
|
|
|
373
373
|
# Imported lazily here so tests can patch
|
|
374
374
|
# signalwire.core.logging_config.get_execution_mode at call time.
|
|
375
|
-
from signalwire.core.logging_config import
|
|
375
|
+
from signalwire.core.logging_config import (
|
|
376
|
+
configure_logging,
|
|
377
|
+
get_execution_mode,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# Opt-in to SDK logging OUTPUT at the run entry point (import is
|
|
381
|
+
# library-safe / silent; running is where the app wants logs). This also
|
|
382
|
+
# applies the CGI-off / auto detection that configure_logging performs.
|
|
383
|
+
configure_logging()
|
|
376
384
|
|
|
377
385
|
# Detect execution mode
|
|
378
386
|
mode = get_execution_mode()
|
|
@@ -43,6 +43,25 @@ def strip_control_chars(
|
|
|
43
43
|
_logging_configured = False
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def _install_library_null_handler() -> None:
|
|
47
|
+
"""Attach a NullHandler to the ``signalwire`` namespace logger (the standard
|
|
48
|
+
library pattern for a well-behaved library, per the stdlib logging HOWTO).
|
|
49
|
+
|
|
50
|
+
This is the ONLY logging side effect of importing the SDK. It makes the SDK's
|
|
51
|
+
own loggers silent-by-default (no "No handlers could be found" warning) WITHOUT
|
|
52
|
+
touching the root logger, the host application's structlog config, or any
|
|
53
|
+
host-owned logger — so ``import signalwire`` never hijacks the app's logging.
|
|
54
|
+
The app opts in to SDK log OUTPUT by calling ``configure_logging()`` explicitly
|
|
55
|
+
(the server/CLI entry points do this)."""
|
|
56
|
+
sw_logger = logging.getLogger("signalwire")
|
|
57
|
+
if not any(isinstance(h, logging.NullHandler) for h in sw_logger.handlers):
|
|
58
|
+
sw_logger.addHandler(logging.NullHandler())
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Import-time side effect: ONLY the library NullHandler. NOT global configuration.
|
|
62
|
+
_install_library_null_handler()
|
|
63
|
+
|
|
64
|
+
|
|
46
65
|
def get_execution_mode() -> str:
|
|
47
66
|
"""
|
|
48
67
|
Determine the execution mode based on environment variables
|
|
@@ -307,7 +326,9 @@ def get_logger(name: str) -> Any:
|
|
|
307
326
|
Returns:
|
|
308
327
|
A structlog BoundLogger that supports .bind(), .info(), .debug(), etc.
|
|
309
328
|
"""
|
|
310
|
-
#
|
|
311
|
-
|
|
312
|
-
|
|
329
|
+
# Library-safe: do NOT auto-configure global logging here. Every SDK module
|
|
330
|
+
# calls get_logger() at import, so auto-configuring would hijack the host
|
|
331
|
+
# app's logging the moment any SDK submodule is imported. The SDK's own
|
|
332
|
+
# logger carries a NullHandler (installed at module load) so it's silent by
|
|
333
|
+
# default; the app opts in to SDK output via configure_logging().
|
|
313
334
|
return structlog.get_logger(name)
|
|
@@ -204,6 +204,12 @@ class WebMixin(_HostTyped): # type: ignore[misc] # _HostTyped is object at run
|
|
|
204
204
|
"""
|
|
205
205
|
import uvicorn
|
|
206
206
|
|
|
207
|
+
# Opt-in to SDK logging OUTPUT at the serve entry point (importing the SDK
|
|
208
|
+
# is library-safe / silent; running a server is where the app wants logs).
|
|
209
|
+
from signalwire.core.logging_config import configure_logging
|
|
210
|
+
|
|
211
|
+
configure_logging()
|
|
212
|
+
|
|
207
213
|
if self._app is None:
|
|
208
214
|
# Create a FastAPI app with explicit redirect_slashes=False
|
|
209
215
|
app = FastAPI(
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/core/swml_service.py
RENAMED
|
@@ -1200,6 +1200,12 @@ class SWMLService(ToolMixin):
|
|
|
1200
1200
|
"""
|
|
1201
1201
|
import uvicorn
|
|
1202
1202
|
|
|
1203
|
+
# Opt-in to SDK logging OUTPUT at the serve entry point (import is
|
|
1204
|
+
# library-safe / silent; serving is where the app wants logs).
|
|
1205
|
+
from signalwire.core.logging_config import configure_logging
|
|
1206
|
+
|
|
1207
|
+
configure_logging()
|
|
1208
|
+
|
|
1203
1209
|
# Store SSL configuration (override environment if explicitly provided)
|
|
1204
1210
|
if ssl_enabled is not None:
|
|
1205
1211
|
self.ssl_enabled = ssl_enabled
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/call.py
RENAMED
|
@@ -112,9 +112,15 @@ class Action:
|
|
|
112
112
|
)
|
|
113
113
|
|
|
114
114
|
async def wait(self, timeout: float | None = None) -> RelayEvent:
|
|
115
|
-
"""Wait for the action to complete. Returns the terminal event.
|
|
115
|
+
"""Wait for the action to complete. Returns the terminal event.
|
|
116
|
+
|
|
117
|
+
Raises ``asyncio.TimeoutError`` if ``timeout`` is exceeded. A timed-out
|
|
118
|
+
wait does NOT poison the action: ``self._done`` is shielded so the
|
|
119
|
+
``wait_for`` cancellation stops the wait, not the underlying completion
|
|
120
|
+
future — the still-pending terminal event resolves the action normally
|
|
121
|
+
and a subsequent ``wait()`` returns it (mirrors ``Message.wait``)."""
|
|
116
122
|
if timeout is not None:
|
|
117
|
-
return await asyncio.wait_for(self._done, timeout=timeout)
|
|
123
|
+
return await asyncio.wait_for(asyncio.shield(self._done), timeout=timeout)
|
|
118
124
|
return await self._done
|
|
119
125
|
|
|
120
126
|
@property
|
|
@@ -377,9 +383,14 @@ class Call:
|
|
|
377
383
|
The outer JSON-RPC method is ``"calling.<method>"`` (e.g.
|
|
378
384
|
``"calling.answer"``) with ``node_id`` and ``call_id`` in params.
|
|
379
385
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
386
|
+
A2 contract (the documented behavior — only "call gone" is swallowed):
|
|
387
|
+
a **404** or **410** server error means the call no longer exists, so the
|
|
388
|
+
verb is a no-op and returns ``{}`` (the caller's action can't proceed but
|
|
389
|
+
that isn't an error worth raising). **Every other non-2xx server error
|
|
390
|
+
RAISES** — the previous code swallowed ALL errors carrying a ``code``,
|
|
391
|
+
which hid real failures (auth, bad params, server faults) the developer
|
|
392
|
+
must see. The docstring/contract always promised 404/410-only; the code
|
|
393
|
+
now matches it.
|
|
383
394
|
"""
|
|
384
395
|
rpc_method = f"calling.{method}"
|
|
385
396
|
params: dict[str, Any] = {
|
|
@@ -392,11 +403,13 @@ class Call:
|
|
|
392
403
|
return await self._client.execute(rpc_method, params)
|
|
393
404
|
except Exception as exc:
|
|
394
405
|
code = getattr(exc, "code", None)
|
|
395
|
-
if code
|
|
406
|
+
if code in (404, 410):
|
|
407
|
+
# Call gone — swallow per the documented contract, return no-op.
|
|
396
408
|
logger.warning(
|
|
397
|
-
f"Call {self.call_id}
|
|
409
|
+
f"Call {self.call_id} gone during {method} (code={code}): {exc}"
|
|
398
410
|
)
|
|
399
411
|
return {}
|
|
412
|
+
# Any other server error (or a non-coded exception) propagates.
|
|
400
413
|
raise
|
|
401
414
|
|
|
402
415
|
# ------------------------------------------------------------------
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/client.py
RENAMED
|
@@ -24,6 +24,7 @@ import asyncio
|
|
|
24
24
|
import json
|
|
25
25
|
import os
|
|
26
26
|
import re
|
|
27
|
+
import ssl as ssl_module
|
|
27
28
|
import uuid
|
|
28
29
|
from typing import Any, TYPE_CHECKING
|
|
29
30
|
from collections.abc import Callable, Coroutine
|
|
@@ -60,6 +61,7 @@ from .constants import (
|
|
|
60
61
|
METHOD_SIGNALWIRE_RECEIVE,
|
|
61
62
|
METHOD_SIGNALWIRE_UNRECEIVE,
|
|
62
63
|
RECONNECT_BACKOFF_FACTOR,
|
|
64
|
+
RECONNECT_MAX_AUTH_ATTEMPTS,
|
|
63
65
|
RECONNECT_MAX_DELAY,
|
|
64
66
|
RECONNECT_MIN_DELAY,
|
|
65
67
|
)
|
|
@@ -100,6 +102,48 @@ except ValueError:
|
|
|
100
102
|
_active_clients: set[int] = set()
|
|
101
103
|
|
|
102
104
|
|
|
105
|
+
# Credential-bearing JSON keys whose VALUES must never appear in debug logs
|
|
106
|
+
# (SECRET-SCRUB, A6/enterprise): the raw RELAY frames carry the connect
|
|
107
|
+
# authentication (project/token/jwt_token) and the server's encrypted
|
|
108
|
+
# ``authorization_state`` re-auth blob. Logging a raw frame verbatim leaks these.
|
|
109
|
+
_SCRUB_KEYS = ("token", "project", "jwt_token", "authorization_state")
|
|
110
|
+
_SCRUB_RE = re.compile(
|
|
111
|
+
r'("(?:' + "|".join(_SCRUB_KEYS) + r')"\s*:\s*)"(?:\\.|[^"\\])*"'
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _scrub_frame(raw: object) -> str:
|
|
116
|
+
"""Return a log-safe repr of a raw RELAY frame with credential VALUES masked.
|
|
117
|
+
|
|
118
|
+
Masks the string values of ``token``/``project``/``jwt_token``/
|
|
119
|
+
``authorization_state`` keys wherever they appear in the (JSON) frame, so a
|
|
120
|
+
``SIGNALWIRE_LOG_LEVEL=debug`` session never emits live credentials or the
|
|
121
|
+
re-auth blob. Non-string / structural content is preserved so the frame stays
|
|
122
|
+
diagnostic."""
|
|
123
|
+
text = (
|
|
124
|
+
raw.decode("utf-8", "replace")
|
|
125
|
+
if isinstance(raw, (bytes, bytearray))
|
|
126
|
+
else str(raw)
|
|
127
|
+
)
|
|
128
|
+
return _SCRUB_RE.sub(r'\1"***"', text)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _build_relay_ssl_context() -> ssl_module.SSLContext | None:
|
|
132
|
+
"""Return a TLS context trusting SIGNALWIRE_RELAY_CA_FILE, or None.
|
|
133
|
+
|
|
134
|
+
A5 fleet CA-var contract: when SIGNALWIRE_RELAY_CA_FILE names a CA bundle,
|
|
135
|
+
build a default client TLS context that loads it as the trust root for the
|
|
136
|
+
RELAY WebSocket connection. Unset → None (websockets uses the system trust
|
|
137
|
+
store). Kept module-level so the connect path stays readable and the behavior
|
|
138
|
+
is unit-testable without a live socket."""
|
|
139
|
+
ca_file = os.environ.get("SIGNALWIRE_RELAY_CA_FILE")
|
|
140
|
+
if not ca_file:
|
|
141
|
+
return None
|
|
142
|
+
ctx = ssl_module.create_default_context()
|
|
143
|
+
ctx.load_verify_locations(cafile=ca_file)
|
|
144
|
+
return ctx
|
|
145
|
+
|
|
146
|
+
|
|
103
147
|
class RelayClient:
|
|
104
148
|
"""Manages a WebSocket connection to SignalWire RELAY.
|
|
105
149
|
|
|
@@ -134,12 +178,24 @@ class RelayClient:
|
|
|
134
178
|
# JWT auth — project/token not required (project_id is inside the token)
|
|
135
179
|
if not self.project:
|
|
136
180
|
self.project = ""
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
181
|
+
else:
|
|
182
|
+
# A6 credential contract: fail fast pre-connect with a PER-VARIABLE
|
|
183
|
+
# actionable error — name exactly which credential is missing and the
|
|
184
|
+
# env var that supplies it, so the caller fixes the right one (a
|
|
185
|
+
# combined "project and token" message misleads when only one is
|
|
186
|
+
# absent). JWT is the alternative for both.
|
|
187
|
+
if not self.project:
|
|
188
|
+
raise ValueError(
|
|
189
|
+
"project is required. Pass project=... or set the "
|
|
190
|
+
"SIGNALWIRE_PROJECT_ID env var (or use jwt_token / "
|
|
191
|
+
"SIGNALWIRE_JWT_TOKEN for JWT auth)."
|
|
192
|
+
)
|
|
193
|
+
if not self.token:
|
|
194
|
+
raise ValueError(
|
|
195
|
+
"token is required. Pass token=... or set the "
|
|
196
|
+
"SIGNALWIRE_API_TOKEN env var (or use jwt_token / "
|
|
197
|
+
"SIGNALWIRE_JWT_TOKEN for JWT auth)."
|
|
198
|
+
)
|
|
143
199
|
|
|
144
200
|
# Validate host to prevent SSRF / header injection
|
|
145
201
|
if any(c in self.host for c in ("@", "/", "?", "\r", "\n", " ")):
|
|
@@ -205,6 +261,12 @@ class RelayClient:
|
|
|
205
261
|
self._execute_queue: list[
|
|
206
262
|
tuple[dict[str, Any], asyncio.Future[dict[str, Any]]]
|
|
207
263
|
] = []
|
|
264
|
+
# A6 bounded-reconnect state: whether authentication has ever succeeded
|
|
265
|
+
# (a drop after this is a TRANSIENT loss → reconnect indefinitely), and
|
|
266
|
+
# the count of consecutive auth rejections before any success (a
|
|
267
|
+
# PERMANENT credential failure → bounded, then raise).
|
|
268
|
+
self._authenticated_ever: bool = False
|
|
269
|
+
self._auth_reject_attempts: int = 0
|
|
208
270
|
|
|
209
271
|
def __del__(self) -> None:
|
|
210
272
|
_active_clients.discard(id(self))
|
|
@@ -228,6 +290,30 @@ class RelayClient:
|
|
|
228
290
|
task.add_done_callback(self._bg_tasks.discard)
|
|
229
291
|
return task
|
|
230
292
|
|
|
293
|
+
def _scrub_log(self, text: str) -> str:
|
|
294
|
+
"""Log-safe repr with live credential VALUES masked wherever they appear.
|
|
295
|
+
|
|
296
|
+
Composes over :func:`_scrub_frame` (the key-shape mask, ``"token":"..."``)
|
|
297
|
+
and then masks any *verbatim* occurrence of THIS connection's live
|
|
298
|
+
credential values (project / token / jwt_token / authorization_state).
|
|
299
|
+
The key-shape pass alone misses a credential value the server reflects
|
|
300
|
+
into a NON-credential field (e.g. an auth-response ``identity`` derived
|
|
301
|
+
from the project, or the raw ``identity=`` diagnostic) — so a
|
|
302
|
+
``SIGNALWIRE_LOG_LEVEL=debug`` session must never emit the raw value even
|
|
303
|
+
there. Defense-in-depth: value-masking is stronger than, and additive to,
|
|
304
|
+
the key-shape scrub.
|
|
305
|
+
"""
|
|
306
|
+
out = _scrub_frame(text)
|
|
307
|
+
for value in (
|
|
308
|
+
self.project,
|
|
309
|
+
self.token,
|
|
310
|
+
self.jwt_token,
|
|
311
|
+
self._authorization_state,
|
|
312
|
+
):
|
|
313
|
+
if value:
|
|
314
|
+
out = out.replace(value, "***")
|
|
315
|
+
return out
|
|
316
|
+
|
|
231
317
|
@property
|
|
232
318
|
def relay_protocol(self) -> str:
|
|
233
319
|
"""Server-assigned protocol string from the connect response."""
|
|
@@ -268,8 +354,20 @@ class RelayClient:
|
|
|
268
354
|
uri = f"wss://{self.host}"
|
|
269
355
|
logger.info(f"Connecting to {uri}")
|
|
270
356
|
|
|
357
|
+
# A5 (fleet CA-var contract, hard-cut no aliases): a custom CA bundle for
|
|
358
|
+
# the RELAY WebSocket transport is supplied via SIGNALWIRE_RELAY_CA_FILE.
|
|
359
|
+
# When set, build a TLS context that trusts it; unset → websockets' default
|
|
360
|
+
# (system trust store). This is the RELAY half of the fleet-standard pair
|
|
361
|
+
# (SIGNALWIRE_REST_CA_FILE is the REST half).
|
|
362
|
+
ssl_context = _build_relay_ssl_context()
|
|
363
|
+
|
|
271
364
|
self._ws = await websockets.connect(
|
|
272
|
-
uri,
|
|
365
|
+
uri,
|
|
366
|
+
ping_interval=None,
|
|
367
|
+
max_size=10 * 1024 * 1024,
|
|
368
|
+
# ssl_context is None when SIGNALWIRE_RELAY_CA_FILE is unset, which
|
|
369
|
+
# tells websockets to use its default (system trust store) for wss://.
|
|
370
|
+
ssl=ssl_context,
|
|
273
371
|
)
|
|
274
372
|
self._connected = True
|
|
275
373
|
self._reconnect_delay = RECONNECT_MIN_DELAY
|
|
@@ -318,6 +416,12 @@ class RelayClient:
|
|
|
318
416
|
|
|
319
417
|
result = await self._send_request(METHOD_SIGNALWIRE_CONNECT, params)
|
|
320
418
|
|
|
419
|
+
# Authentication succeeded: from here on a connection drop is a
|
|
420
|
+
# transient loss (reconnect indefinitely), not a credential failure.
|
|
421
|
+
# Reset the permanent-auth-failure counter (A6 bounded reconnect).
|
|
422
|
+
self._authenticated_ever = True
|
|
423
|
+
self._auth_reject_attempts = 0
|
|
424
|
+
|
|
321
425
|
# Capture server-assigned protocol and identity
|
|
322
426
|
self._relay_protocol = result.get("protocol", self._relay_protocol)
|
|
323
427
|
self._identity = result.get("identity", self._identity)
|
|
@@ -327,7 +431,10 @@ class RelayClient:
|
|
|
327
431
|
# session. Internal-only — not part of the public surface.
|
|
328
432
|
self._session_id = result.get("sessionid", self._session_id)
|
|
329
433
|
logger.debug(
|
|
330
|
-
|
|
434
|
+
self._scrub_log(
|
|
435
|
+
f"Auth response: protocol={self._relay_protocol} "
|
|
436
|
+
f"identity={self._identity}"
|
|
437
|
+
)
|
|
331
438
|
)
|
|
332
439
|
|
|
333
440
|
async def disconnect(self) -> None:
|
|
@@ -587,6 +694,30 @@ class RelayClient:
|
|
|
587
694
|
await self._recv_task
|
|
588
695
|
except asyncio.CancelledError:
|
|
589
696
|
break
|
|
697
|
+
except RelayError as exc:
|
|
698
|
+
# A6 bounded reconnect: a RelayError out of connect() before we
|
|
699
|
+
# ever authenticated is a PERMANENT credential rejection (the
|
|
700
|
+
# server refused the connect creds), NOT a transient blip.
|
|
701
|
+
# Bound the retries and then RAISE the server's message — never
|
|
702
|
+
# loop forever on bad creds, never silent exit-0. A transport
|
|
703
|
+
# error (ConnectionRefused/OSError, server not up yet) is caught
|
|
704
|
+
# by the broad handler below and keeps reconnecting.
|
|
705
|
+
if not self._authenticated_ever:
|
|
706
|
+
self._auth_reject_attempts += 1
|
|
707
|
+
if self._auth_reject_attempts >= RECONNECT_MAX_AUTH_ATTEMPTS:
|
|
708
|
+
logger.error(
|
|
709
|
+
"RELAY authentication rejected "
|
|
710
|
+
f"{self._auth_reject_attempts} time(s); giving up: {exc}"
|
|
711
|
+
)
|
|
712
|
+
await self.disconnect()
|
|
713
|
+
raise
|
|
714
|
+
logger.warning(
|
|
715
|
+
"RELAY authentication rejected "
|
|
716
|
+
f"({self._auth_reject_attempts}/{RECONNECT_MAX_AUTH_ATTEMPTS}); "
|
|
717
|
+
f"retrying: {exc}"
|
|
718
|
+
)
|
|
719
|
+
else:
|
|
720
|
+
logger.exception("Connection error")
|
|
590
721
|
except Exception:
|
|
591
722
|
logger.exception("Connection error")
|
|
592
723
|
|
|
@@ -721,10 +852,17 @@ class RelayClient:
|
|
|
721
852
|
try:
|
|
722
853
|
msg = json.loads(raw)
|
|
723
854
|
except json.JSONDecodeError:
|
|
724
|
-
logger.warning(
|
|
855
|
+
logger.warning(
|
|
856
|
+
f"Invalid JSON received: {self._scrub_log(str(raw))!r}"
|
|
857
|
+
)
|
|
725
858
|
continue
|
|
726
859
|
|
|
727
|
-
|
|
860
|
+
# SECRET-SCRUB: mask credential/authorization_state values so a
|
|
861
|
+
# debug-level log never leaks live creds or the re-auth blob —
|
|
862
|
+
# including a value the server reflects into a non-credential
|
|
863
|
+
# field (e.g. identity derived from the project). _scrub_log
|
|
864
|
+
# composes the key-shape mask with verbatim value-masking.
|
|
865
|
+
logger.debug(f"<< {self._scrub_log(str(raw))}")
|
|
728
866
|
await self._handle_message(msg)
|
|
729
867
|
except websockets.exceptions.ConnectionClosed:
|
|
730
868
|
logger.info("WebSocket connection closed")
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/relay/constants.py
RENAMED
|
@@ -115,6 +115,14 @@ ROOM_STATE_LEAVE = "leave"
|
|
|
115
115
|
RECONNECT_MIN_DELAY = 1.0
|
|
116
116
|
RECONNECT_MAX_DELAY = 30.0
|
|
117
117
|
RECONNECT_BACKOFF_FACTOR = 2.0
|
|
118
|
+
# A6 credential-failure contract (bounded reconnect): a transient connection
|
|
119
|
+
# loss reconnects indefinitely (a server blip must self-heal), but a PERMANENT
|
|
120
|
+
# authentication rejection (the server refuses the credentials — a 401-class
|
|
121
|
+
# error frame to signalwire.connect, before we have ever authenticated) must
|
|
122
|
+
# NOT loop forever. After this many consecutive auth rejections with no
|
|
123
|
+
# intervening successful auth, _run_forever re-raises the server's message and
|
|
124
|
+
# stops — never an infinite reconnect on bad creds, never a silent exit-0.
|
|
125
|
+
RECONNECT_MAX_AUTH_ATTEMPTS = 3
|
|
118
126
|
|
|
119
127
|
# Default host
|
|
120
128
|
DEFAULT_RELAY_HOST = "relay.signalwire.com"
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/_base.py
RENAMED
|
@@ -9,6 +9,7 @@ See LICENSE file in the project root for full license information.
|
|
|
9
9
|
HTTP client infrastructure and base resource classes for the REST client.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
import os
|
|
12
13
|
import time
|
|
13
14
|
from importlib.metadata import PackageNotFoundError, version
|
|
14
15
|
from typing import Any, Generic, TypeVar, cast
|
|
@@ -153,6 +154,15 @@ class HttpClient:
|
|
|
153
154
|
self._request_options = request_options
|
|
154
155
|
self._session = requests.Session()
|
|
155
156
|
self._session.auth = (project, token)
|
|
157
|
+
# A5 (fleet CA-var contract, hard-cut no aliases): a custom CA bundle for
|
|
158
|
+
# the REST transport is supplied via SIGNALWIRE_REST_CA_FILE. When set, it
|
|
159
|
+
# becomes the session's verify bundle (requests uses it for TLS
|
|
160
|
+
# verification of the platform cert). Unset → requests' default trust
|
|
161
|
+
# store. This is the REST half of the fleet-standard pair
|
|
162
|
+
# (SIGNALWIRE_RELAY_CA_FILE is the RELAY half).
|
|
163
|
+
_rest_ca_file = os.environ.get("SIGNALWIRE_REST_CA_FILE")
|
|
164
|
+
if _rest_ca_file:
|
|
165
|
+
self._session.verify = _rest_ca_file
|
|
156
166
|
self._session.headers.update(
|
|
157
167
|
{
|
|
158
168
|
"Content-Type": "application/json",
|
|
@@ -332,10 +342,21 @@ class ReadResource(BaseResource, Generic[TList, TItem]):
|
|
|
332
342
|
defined once here.
|
|
333
343
|
"""
|
|
334
344
|
|
|
335
|
-
def list(
|
|
336
|
-
|
|
345
|
+
def list(
|
|
346
|
+
self, *, request_options: RequestOptions | None = None, **params: Any
|
|
347
|
+
) -> TList:
|
|
348
|
+
return cast(
|
|
349
|
+
TList,
|
|
350
|
+
self._http.get(
|
|
351
|
+
self._base_path,
|
|
352
|
+
params=params or None,
|
|
353
|
+
request_options=request_options,
|
|
354
|
+
),
|
|
355
|
+
)
|
|
337
356
|
|
|
338
|
-
def paginate(
|
|
357
|
+
def paginate(
|
|
358
|
+
self, *, request_options: RequestOptions | None = None, **params: Any
|
|
359
|
+
) -> PaginatedIterator:
|
|
339
360
|
"""Iterate every item across all pages of this resource's list endpoint.
|
|
340
361
|
|
|
341
362
|
``list()`` returns a single raw page (the server's first response). For
|
|
@@ -347,14 +368,24 @@ class ReadResource(BaseResource, Generic[TList, TItem]):
|
|
|
347
368
|
|
|
348
369
|
Wires the resource layer to the tested ``PaginatedIterator`` (which walks
|
|
349
370
|
``resp["data"]`` and follows ``resp["links"]["next"]``), so callers no
|
|
350
|
-
longer hand-construct the path + token loop.
|
|
371
|
+
longer hand-construct the path + token loop. ``request_options`` (a per-call
|
|
372
|
+
timeout / retry / header override) is applied to EVERY page fetch.
|
|
351
373
|
"""
|
|
352
374
|
return PaginatedIterator(
|
|
353
|
-
self._http,
|
|
375
|
+
self._http,
|
|
376
|
+
self._base_path,
|
|
377
|
+
params=params or None,
|
|
378
|
+
data_key="data",
|
|
379
|
+
request_options=request_options,
|
|
354
380
|
)
|
|
355
381
|
|
|
356
|
-
def get(
|
|
357
|
-
|
|
382
|
+
def get(
|
|
383
|
+
self, resource_id: str, *, request_options: RequestOptions | None = None
|
|
384
|
+
) -> TItem:
|
|
385
|
+
return cast(
|
|
386
|
+
TItem,
|
|
387
|
+
self._http.get(self._path(resource_id), request_options=request_options),
|
|
388
|
+
)
|
|
358
389
|
|
|
359
390
|
|
|
360
391
|
class CrudResource(ReadResource[TList, TItem], Generic[TList, TItem, TCreate, TUpdate]):
|
|
@@ -369,7 +400,9 @@ class CrudResource(ReadResource[TList, TItem], Generic[TList, TItem, TCreate, TU
|
|
|
369
400
|
|
|
370
401
|
_update_method = "PATCH"
|
|
371
402
|
|
|
372
|
-
def create(
|
|
403
|
+
def create(
|
|
404
|
+
self, *, request_options: RequestOptions | None = None, **kwargs: Any
|
|
405
|
+
) -> TItem:
|
|
373
406
|
# Honest fallback: the body accepts arbitrary wire fields and at runtime
|
|
374
407
|
# is a plain dict. Concrete resources override this with a generated
|
|
375
408
|
# CLOSED typed signature (explicit spec fields + an ``extras`` door); the
|
|
@@ -377,26 +410,58 @@ class CrudResource(ReadResource[TList, TItem], Generic[TList, TItem, TCreate, TU
|
|
|
377
410
|
# TCreate shape to the signature oracle, NOT this base method body. (A
|
|
378
411
|
# bare ``**kwargs: TCreate`` here is wrong — it would type each kwarg
|
|
379
412
|
# VALUE as a whole TCreate — and is what the generated overrides replace.)
|
|
380
|
-
return cast(
|
|
413
|
+
return cast(
|
|
414
|
+
TItem,
|
|
415
|
+
self._http.post(
|
|
416
|
+
self._base_path, body=kwargs, request_options=request_options
|
|
417
|
+
),
|
|
418
|
+
)
|
|
381
419
|
|
|
382
|
-
def update(
|
|
420
|
+
def update(
|
|
421
|
+
self,
|
|
422
|
+
resource_id: str,
|
|
423
|
+
/,
|
|
424
|
+
*,
|
|
425
|
+
request_options: RequestOptions | None = None,
|
|
426
|
+
**kwargs: Any,
|
|
427
|
+
) -> TItem:
|
|
383
428
|
# resource_id is positional-only so a subclass may rename it without an LSP
|
|
384
429
|
# override conflict. Same contract as ``create``: honest ``**kwargs: Any``
|
|
385
430
|
# fallback; the concrete generated override carries the closed typed shape, the
|
|
386
431
|
# binding carries TUpdate for the oracle.
|
|
387
432
|
method = getattr(self._http, self._update_method.lower())
|
|
388
|
-
return cast(
|
|
433
|
+
return cast(
|
|
434
|
+
TItem,
|
|
435
|
+
method(
|
|
436
|
+
self._path(resource_id),
|
|
437
|
+
body=kwargs,
|
|
438
|
+
request_options=request_options,
|
|
439
|
+
),
|
|
440
|
+
)
|
|
389
441
|
|
|
390
|
-
def delete(
|
|
391
|
-
|
|
442
|
+
def delete(
|
|
443
|
+
self, resource_id: str, *, request_options: RequestOptions | None = None
|
|
444
|
+
) -> TItem:
|
|
445
|
+
return cast(
|
|
446
|
+
TItem,
|
|
447
|
+
self._http.delete(self._path(resource_id), request_options=request_options),
|
|
448
|
+
)
|
|
392
449
|
|
|
393
450
|
|
|
394
451
|
class CrudWithAddresses(CrudResource[TList, TItem, TCreate, TUpdate]):
|
|
395
452
|
"""CRUD resource that also supports listing addresses."""
|
|
396
453
|
|
|
397
|
-
def list_addresses(
|
|
454
|
+
def list_addresses(
|
|
455
|
+
self,
|
|
456
|
+
resource_id: str,
|
|
457
|
+
*,
|
|
458
|
+
request_options: RequestOptions | None = None,
|
|
459
|
+
**params: Any,
|
|
460
|
+
) -> Any:
|
|
398
461
|
return self._http.get(
|
|
399
|
-
self._path(resource_id, "addresses"),
|
|
462
|
+
self._path(resource_id, "addresses"),
|
|
463
|
+
params=params or None,
|
|
464
|
+
request_options=request_options,
|
|
400
465
|
)
|
|
401
466
|
|
|
402
467
|
|
{signalwire_sdk-3.2.0.dev94 → signalwire_sdk-3.2.0.dev96}/signalwire/signalwire/rest/_pagination.py
RENAMED
|
@@ -11,6 +11,8 @@ Pagination support for list endpoints that return paged results.
|
|
|
11
11
|
|
|
12
12
|
from typing import TYPE_CHECKING, Any
|
|
13
13
|
|
|
14
|
+
from signalwire.rest._request_options import RequestOptions
|
|
15
|
+
|
|
14
16
|
if TYPE_CHECKING:
|
|
15
17
|
# Type-only import: _base imports this module (ReadResource.paginate), so a
|
|
16
18
|
# runtime `from ._base import HttpClient` would be a circular import. HttpClient
|
|
@@ -32,11 +34,15 @@ class PaginatedIterator:
|
|
|
32
34
|
path: str,
|
|
33
35
|
params: dict[str, Any] | None = None,
|
|
34
36
|
data_key: str = "data",
|
|
37
|
+
request_options: RequestOptions | None = None,
|
|
35
38
|
) -> None:
|
|
36
39
|
self._http = http
|
|
37
40
|
self._path = path
|
|
38
41
|
self._params: dict[str, Any] = dict(params or {})
|
|
39
42
|
self._data_key = data_key
|
|
43
|
+
# Per-call request options (timeout / retry / headers) applied to every
|
|
44
|
+
# page fetch this iterator performs.
|
|
45
|
+
self._request_options = request_options
|
|
40
46
|
self._current_page: Any = None
|
|
41
47
|
self._items: list[Any] = []
|
|
42
48
|
self._index = 0
|
|
@@ -61,7 +67,11 @@ class PaginatedIterator:
|
|
|
61
67
|
return item
|
|
62
68
|
|
|
63
69
|
def _fetch_next(self) -> None:
|
|
64
|
-
resp = self._http.get(
|
|
70
|
+
resp = self._http.get(
|
|
71
|
+
self._path,
|
|
72
|
+
params=self._params or None,
|
|
73
|
+
request_options=self._request_options,
|
|
74
|
+
)
|
|
65
75
|
data = resp.get(self._data_key, [])
|
|
66
76
|
self._items.extend(data)
|
|
67
77
|
|