From 9a6aad9348122ef915de73a17d2662d500e11bb4 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:42:07 +0000 Subject: [PATCH 1/2] [fern-generated] Update SDK Generated by Fern CLI Version: unknown Generators: - fernapi/fern-python-sdk: 4.3.19 --- README.md | 45 +- poetry.lock | 446 +- pyproject.toml | 9 +- reference.md | 13043 ---------------- requirements.txt | 1 - src/speechify/__init__.py | 535 +- src/speechify/agent/__init__.py | 56 - src/speechify/agent/admin/__init__.py | 2 - src/speechify/agent/admin/client.py | 378 - src/speechify/agent/audio_assets/__init__.py | 2 - src/speechify/agent/audio_assets/client.py | 746 - src/speechify/agent/batch_calls/__init__.py | 2 - src/speechify/agent/batch_calls/client.py | 712 - src/speechify/agent/callers/__init__.py | 2 - src/speechify/agent/callers/client.py | 1077 -- src/speechify/agent/client.py | 5859 ------- src/speechify/agent/conversations/__init__.py | 2 - src/speechify/agent/conversations/client.py | 2026 --- src/speechify/agent/flow/__init__.py | 2 - src/speechify/agent/flow/client.py | 2854 ---- src/speechify/agent/ivr_memory/__init__.py | 2 - src/speechify/agent/ivr_memory/client.py | 680 - .../agent/knowledge_bases/__init__.py | 2 - src/speechify/agent/knowledge_bases/client.py | 5114 ------ src/speechify/agent/memories/__init__.py | 2 - src/speechify/agent/memories/client.py | 148 - .../agent/outbound_calls/__init__.py | 2 - src/speechify/agent/outbound_calls/client.py | 330 - src/speechify/agent/phone_numbers/__init__.py | 2 - src/speechify/agent/phone_numbers/client.py | 1392 -- src/speechify/agent/sip_trunks/__init__.py | 2 - src/speechify/agent/sip_trunks/client.py | 718 - src/speechify/agent/tests/__init__.py | 5 - src/speechify/agent/tests/client.py | 3242 ---- src/speechify/agent/tests/types/__init__.py | 5 - .../types/update_agent_test_request_config.py | 8 - src/speechify/agent/tools/__init__.py | 5 - src/speechify/agent/tools/client.py | 1808 --- src/speechify/agent/tools/types/__init__.py | 6 - .../tools/types/create_tool_request_config.py | 9 - .../tools/types/update_tool_request_config.py | 9 - src/speechify/agent/types/__init__.py | 19 - ...e_agent_request_background_noise_preset.py | 7 - .../create_agent_request_llm_provider.py | 5 - .../create_agent_request_stt_override.py | 5 - .../types/create_agent_test_request_config.py | 8 - ...e_agent_request_background_noise_preset.py | 7 - .../update_agent_request_llm_provider.py | 5 - .../update_agent_request_stt_override.py | 7 - src/speechify/client.py | 13 +- src/speechify/core/__init__.py | 3 - src/speechify/core/pagination.py | 88 - src/speechify/errors/__init__.py | 4 - src/speechify/errors/conflict_error.py | 9 - .../errors/content_too_large_error.py | 9 - src/speechify/types/__init__.py | 509 - src/speechify/types/access_token.py | 35 - src/speechify/types/access_token_scope.py | 10 - .../types/access_token_token_type.py | 5 - src/speechify/types/agent.py | 230 - .../types/agent_background_noise_preset.py | 7 - src/speechify/types/agent_builtin.py | 76 - src/speechify/types/agent_llm_provider.py | 5 - src/speechify/types/agent_snapshot.py | 96 - .../agent_snapshot_background_noise_preset.py | 7 - src/speechify/types/agent_stt_override.py | 5 - src/speechify/types/agent_test.py | 71 - src/speechify/types/agent_test_attachment.py | 36 - src/speechify/types/agent_test_config.py | 8 - src/speechify/types/agent_test_folder.py | 41 - src/speechify/types/agent_test_run.py | 61 - src/speechify/types/agent_test_suite_run.py | 94 - .../types/agent_test_suite_run_with_runs.py | 24 - .../types/agent_test_with_last_run.py | 36 - src/speechify/types/agent_voice.py | 57 - src/speechify/types/agent_voice_gender.py | 5 - src/speechify/types/agent_voice_language.py | 28 - src/speechify/types/agent_voice_model.py | 29 - src/speechify/types/agent_voice_model_name.py | 5 - src/speechify/types/agent_voice_type.py | 5 - src/speechify/types/amd_config.py | 64 - src/speechify/types/amd_config_on_ivr.py | 33 - .../types/amd_config_on_ivr_action.py | 5 - .../types/amd_config_on_unavailable.py | 24 - .../types/amd_config_on_unavailable_action.py | 5 - .../types/amd_config_on_voicemail.py | 31 - .../types/amd_config_on_voicemail_action.py | 5 - src/speechify/types/amd_config_tuning.py | 29 - src/speechify/types/api_key.py | 53 - .../attached_knowledge_bases_response.py | 26 - .../types/attached_tools_response.py | 26 - src/speechify/types/audio_asset.py | 71 - src/speechify/types/available_phone_number.py | 48 - src/speechify/types/basic_auth_config.py | 24 - src/speechify/types/batch_call.py | 95 - src/speechify/types/batch_call_status.py | 7 - src/speechify/types/batch_recipient.py | 55 - .../types/batch_recipient_request.py | 31 - src/speechify/types/batch_recipient_status.py | 5 - src/speechify/types/batch_run_entry.py | 35 - src/speechify/types/bearer_auth_config.py | 24 - src/speechify/types/billing_entitlements.py | 63 - src/speechify/types/caller.py | 83 - src/speechify/types/caller_memory_item.py | 43 - src/speechify/types/client_tool_config.py | 28 - src/speechify/types/conversation.py | 187 - .../types/conversation_end_reason.py | 19 - .../conversation_ivr_surrender_reason.py | 19 - src/speechify/types/conversation_stats.py | 29 - src/speechify/types/conversation_status.py | 5 - src/speechify/types/conversation_transport.py | 7 - .../types/create_access_token_request.py | 25 - .../create_access_token_request_grant_type.py | 5 - .../create_access_token_request_scope.py | 10 - src/speechify/types/create_api_key_request.py | 26 - .../types/create_batch_call_response.py | 20 - .../types/create_conversation_response.py | 37 - .../types/create_credential_request.py | 31 - .../types/create_flow_template_request.py | 34 - src/speechify/types/create_invite_request.py | 31 - .../types/create_outbound_call_response.py | 38 - .../types/create_workspace_request.py | 26 - src/speechify/types/credential.py | 43 - src/speechify/types/credential_config.py | 38 - src/speechify/types/credential_kind.py | 7 - src/speechify/types/criterion_status.py | 5 - src/speechify/types/custom_headers_config.py | 25 - src/speechify/types/data_assertion.py | 47 - src/speechify/types/data_assertion_mode.py | 5 - src/speechify/types/data_assertion_result.py | 37 - .../types/data_assertion_result_mode.py | 5 - src/speechify/types/data_collection_field.py | 28 - .../types/data_collection_field_type.py | 5 - src/speechify/types/delete_caller_response.py | 33 - .../delete_memories_by_caller_response.py | 22 - src/speechify/types/dependent_agent.py | 26 - src/speechify/types/dynamic_variable.py | 43 - src/speechify/types/dynamic_variable_type.py | 5 - src/speechify/types/entitlements_response.py | 33 - src/speechify/types/evaluation.py | 56 - src/speechify/types/evaluation_config.py | 22 - src/speechify/types/evaluation_criterion.py | 25 - src/speechify/types/evaluation_kind.py | 5 - src/speechify/types/evaluation_status.py | 5 - src/speechify/types/flow_graph.py | 31 - src/speechify/types/flow_graph_input.py | 27 - src/speechify/types/flow_template.py | 45 - src/speechify/types/flow_validation_error.py | 32 - src/speechify/types/flow_validation_issue.py | 33 - src/speechify/types/flow_version.py | 42 - .../types/get_batch_call_response.py | 26 - src/speechify/types/get_caller_response.py | 24 - src/speechify/types/get_flow_response.py | 27 - .../types/get_flow_version_response.py | 20 - src/speechify/types/import_job.py | 49 - src/speechify/types/import_job_kind.py | 5 - src/speechify/types/import_job_response.py | 24 - src/speechify/types/import_job_status.py | 5 - src/speechify/types/invite.py | 71 - src/speechify/types/invite_preview.py | 54 - src/speechify/types/invites_list_response.py | 20 - src/speechify/types/ivr_menu.py | 67 - src/speechify/types/ivr_menu_list_entry.py | 44 - src/speechify/types/knowledge_base.py | 47 - src/speechify/types/knowledge_base_chunk.py | 28 - .../types/knowledge_base_document.py | 55 - .../types/knowledge_base_document_detail.py | 31 - .../knowledge_base_document_source_kind.py | 5 - .../types/knowledge_base_document_status.py | 5 - src/speechify/types/knowledge_base_folder.py | 37 - .../types/knowledge_base_search_hit.py | 28 - .../types/list_agent_builtins_response.py | 20 - .../list_agent_test_attachments_response.py | 20 - .../types/list_agent_test_folders_response.py | 20 - .../types/list_agent_test_runs_response.py | 20 - .../types/list_agent_tests_response.py | 20 - src/speechify/types/list_agents_response.py | 20 - .../types/list_audio_assets_response.py | 20 - .../types/list_batch_calls_response.py | 20 - .../list_caller_conversations_response.py | 24 - .../types/list_caller_memories_response.py | 24 - src/speechify/types/list_callers_response.py | 24 - .../types/list_conversations_response.py | 20 - .../types/list_credentials_response.py | 20 - .../types/list_dynamic_variables_response.py | 36 - .../types/list_evaluations_response.py | 20 - .../types/list_flow_templates_response.py | 20 - .../types/list_flow_versions_response.py | 20 - .../types/list_import_jobs_response.py | 20 - .../types/list_ivr_menus_response.py | 20 - .../list_knowledge_base_chunks_response.py | 20 - .../list_knowledge_base_documents_response.py | 20 - .../list_knowledge_base_folders_response.py | 26 - .../types/list_knowledge_bases_response.py | 20 - src/speechify/types/list_memories_response.py | 20 - src/speechify/types/list_messages_response.py | 20 - .../types/list_phone_numbers_response.py | 27 - .../types/list_recent_callees_response.py | 24 - .../types/list_refresh_history_response.py | 20 - .../types/list_retrieval_logs_response.py | 24 - .../types/list_sip_trunks_response.py | 27 - .../types/list_suite_runs_response.py | 26 - .../types/list_system_builtins_response.py | 20 - src/speechify/types/list_tests_response.py | 26 - .../list_tool_attached_agents_response.py | 25 - src/speechify/types/list_tools_response.py | 26 - .../types/list_webhook_deliveries_response.py | 24 - src/speechify/types/llm_provider.py | 5 - src/speechify/types/mcp_auth.py | 68 - src/speechify/types/mcp_auth_bearer.py | 27 - src/speechify/types/mcp_auth_none.py | 17 - src/speechify/types/mcp_auth_o_auth2.py | 34 - src/speechify/types/mcp_auth_type.py | 5 - .../types/mcp_probe_error_details.py | 44 - .../types/mcp_probe_error_details_stage.py | 8 - src/speechify/types/mcp_probe_result.py | 37 - src/speechify/types/mcp_probe_tool.py | 24 - src/speechify/types/mcp_tool_config.py | 31 - src/speechify/types/mcp_transport.py | 5 - src/speechify/types/member.py | 49 - src/speechify/types/member_role.py | 5 - src/speechify/types/members_list_response.py | 20 - src/speechify/types/memory.py | 69 - src/speechify/types/message.py | 38 - src/speechify/types/message_role.py | 5 - src/speechify/types/mocking_strategy.py | 5 - src/speechify/types/no_match_behavior.py | 5 - .../types/o_auth2client_credentials_config.py | 29 - src/speechify/types/o_auth2jwt_config.py | 31 - src/speechify/types/o_auth_error.py | 21 - src/speechify/types/o_auth_error_error.py | 10 - src/speechify/types/pagination_meta.py | 36 - src/speechify/types/parameter_check.py | 41 - src/speechify/types/parameter_check_mode.py | 5 - src/speechify/types/parameter_check_result.py | 35 - src/speechify/types/phone_number.py | 75 - .../types/phone_number_capability.py | 5 - src/speechify/types/phone_number_source.py | 7 - src/speechify/types/recent_callee.py | 32 - src/speechify/types/refresh_config.py | 30 - src/speechify/types/refresh_history_entry.py | 33 - .../types/refresh_history_entry_status.py | 7 - src/speechify/types/reply_config.py | 75 - src/speechify/types/reply_result.py | 42 - src/speechify/types/retrieval_log_entry.py | 38 - src/speechify/types/retrieval_log_result.py | 37 - .../types/run_agent_tests_response.py | 32 - src/speechify/types/run_batch_response.py | 25 - ...search_available_phone_numbers_response.py | 27 - .../types/search_knowledge_bases_response.py | 20 - .../types/shadow_conversation_response.py | 51 - src/speechify/types/simulation_config.py | 68 - .../types/simulation_criterion_result.py | 41 - .../simulation_criterion_result_status.py | 5 - src/speechify/types/simulation_message.py | 25 - .../types/simulation_message_role.py | 5 - src/speechify/types/simulation_result.py | 84 - .../types/simulation_result_sentiment.py | 5 - src/speechify/types/simulation_tool_call.py | 38 - src/speechify/types/sip_media_encryption.py | 5 - src/speechify/types/sip_transport.py | 5 - src/speechify/types/sip_trunk.py | 91 - src/speechify/types/sip_trunk_direction.py | 5 - src/speechify/types/sip_trunk_kind.py | 5 - src/speechify/types/suite_child_run.py | 34 - src/speechify/types/suite_run_trigger.py | 5 - src/speechify/types/system_builtin.py | 3 - src/speechify/types/system_builtin_info.py | 33 - src/speechify/types/system_tool_config.py | 33 - src/speechify/types/system_variable_doc.py | 33 - src/speechify/types/tenant.py | 77 - src/speechify/types/tenants_list_response.py | 20 - .../types/test_run_config_override.py | 47 - src/speechify/types/test_run_result.py | 39 - src/speechify/types/test_run_status.py | 5 - src/speechify/types/test_stats.py | 34 - src/speechify/types/test_stats_bucket.py | 30 - src/speechify/types/test_type.py | 5 - src/speechify/types/tool.py | 43 - src/speechify/types/tool_attached_agent.py | 33 - src/speechify/types/tool_call_config.py | 65 - src/speechify/types/tool_call_result.py | 51 - src/speechify/types/tool_config.py | 9 - src/speechify/types/tool_kind.py | 5 - src/speechify/types/tool_mock.py | 41 - src/speechify/types/tool_mock_config.py | 32 - src/speechify/types/tool_param.py | 28 - src/speechify/types/tool_param_type.py | 5 - .../types/transfer_ownership_request.py | 28 - src/speechify/types/twilio_import_spec.py | 35 - .../update_billing_contact_email_request.py | 28 - .../update_billing_contact_name_request.py | 29 - .../types/update_member_role_request.py | 20 - .../types/update_sip_trunk_request.py | 36 - .../types/update_workspace_request.py | 27 - .../types/upload_audio_asset_response.py | 20 - src/speechify/types/webhook_delivery.py | 47 - .../types/webhook_delivery_status.py | 5 - src/speechify/types/webhook_probe_result.py | 56 - src/speechify/types/webhook_tool_config.py | 49 - .../types/webhook_tool_config_method.py | 5 - src/speechify/types/widget_config.py | 39 - src/speechify/types/widget_config_avatar.py | 25 - .../types/widget_config_avatar_type.py | 5 - src/speechify/types/widget_config_style.py | 5 - src/speechify/types/widget_config_terms.py | 20 - src/speechify/types/widget_config_text.py | 23 - src/speechify/types/widget_config_theme.py | 5 - .../types/widget_config_transcript.py | 19 - 309 files changed, 185 insertions(+), 49309 deletions(-) delete mode 100644 src/speechify/agent/__init__.py delete mode 100644 src/speechify/agent/admin/__init__.py delete mode 100644 src/speechify/agent/admin/client.py delete mode 100644 src/speechify/agent/audio_assets/__init__.py delete mode 100644 src/speechify/agent/audio_assets/client.py delete mode 100644 src/speechify/agent/batch_calls/__init__.py delete mode 100644 src/speechify/agent/batch_calls/client.py delete mode 100644 src/speechify/agent/callers/__init__.py delete mode 100644 src/speechify/agent/callers/client.py delete mode 100644 src/speechify/agent/client.py delete mode 100644 src/speechify/agent/conversations/__init__.py delete mode 100644 src/speechify/agent/conversations/client.py delete mode 100644 src/speechify/agent/flow/__init__.py delete mode 100644 src/speechify/agent/flow/client.py delete mode 100644 src/speechify/agent/ivr_memory/__init__.py delete mode 100644 src/speechify/agent/ivr_memory/client.py delete mode 100644 src/speechify/agent/knowledge_bases/__init__.py delete mode 100644 src/speechify/agent/knowledge_bases/client.py delete mode 100644 src/speechify/agent/memories/__init__.py delete mode 100644 src/speechify/agent/memories/client.py delete mode 100644 src/speechify/agent/outbound_calls/__init__.py delete mode 100644 src/speechify/agent/outbound_calls/client.py delete mode 100644 src/speechify/agent/phone_numbers/__init__.py delete mode 100644 src/speechify/agent/phone_numbers/client.py delete mode 100644 src/speechify/agent/sip_trunks/__init__.py delete mode 100644 src/speechify/agent/sip_trunks/client.py delete mode 100644 src/speechify/agent/tests/__init__.py delete mode 100644 src/speechify/agent/tests/client.py delete mode 100644 src/speechify/agent/tests/types/__init__.py delete mode 100644 src/speechify/agent/tests/types/update_agent_test_request_config.py delete mode 100644 src/speechify/agent/tools/__init__.py delete mode 100644 src/speechify/agent/tools/client.py delete mode 100644 src/speechify/agent/tools/types/__init__.py delete mode 100644 src/speechify/agent/tools/types/create_tool_request_config.py delete mode 100644 src/speechify/agent/tools/types/update_tool_request_config.py delete mode 100644 src/speechify/agent/types/__init__.py delete mode 100644 src/speechify/agent/types/create_agent_request_background_noise_preset.py delete mode 100644 src/speechify/agent/types/create_agent_request_llm_provider.py delete mode 100644 src/speechify/agent/types/create_agent_request_stt_override.py delete mode 100644 src/speechify/agent/types/create_agent_test_request_config.py delete mode 100644 src/speechify/agent/types/update_agent_request_background_noise_preset.py delete mode 100644 src/speechify/agent/types/update_agent_request_llm_provider.py delete mode 100644 src/speechify/agent/types/update_agent_request_stt_override.py delete mode 100644 src/speechify/core/pagination.py delete mode 100644 src/speechify/errors/conflict_error.py delete mode 100644 src/speechify/errors/content_too_large_error.py delete mode 100644 src/speechify/types/access_token.py delete mode 100644 src/speechify/types/access_token_scope.py delete mode 100644 src/speechify/types/access_token_token_type.py delete mode 100644 src/speechify/types/agent.py delete mode 100644 src/speechify/types/agent_background_noise_preset.py delete mode 100644 src/speechify/types/agent_builtin.py delete mode 100644 src/speechify/types/agent_llm_provider.py delete mode 100644 src/speechify/types/agent_snapshot.py delete mode 100644 src/speechify/types/agent_snapshot_background_noise_preset.py delete mode 100644 src/speechify/types/agent_stt_override.py delete mode 100644 src/speechify/types/agent_test.py delete mode 100644 src/speechify/types/agent_test_attachment.py delete mode 100644 src/speechify/types/agent_test_config.py delete mode 100644 src/speechify/types/agent_test_folder.py delete mode 100644 src/speechify/types/agent_test_run.py delete mode 100644 src/speechify/types/agent_test_suite_run.py delete mode 100644 src/speechify/types/agent_test_suite_run_with_runs.py delete mode 100644 src/speechify/types/agent_test_with_last_run.py delete mode 100644 src/speechify/types/agent_voice.py delete mode 100644 src/speechify/types/agent_voice_gender.py delete mode 100644 src/speechify/types/agent_voice_language.py delete mode 100644 src/speechify/types/agent_voice_model.py delete mode 100644 src/speechify/types/agent_voice_model_name.py delete mode 100644 src/speechify/types/agent_voice_type.py delete mode 100644 src/speechify/types/amd_config.py delete mode 100644 src/speechify/types/amd_config_on_ivr.py delete mode 100644 src/speechify/types/amd_config_on_ivr_action.py delete mode 100644 src/speechify/types/amd_config_on_unavailable.py delete mode 100644 src/speechify/types/amd_config_on_unavailable_action.py delete mode 100644 src/speechify/types/amd_config_on_voicemail.py delete mode 100644 src/speechify/types/amd_config_on_voicemail_action.py delete mode 100644 src/speechify/types/amd_config_tuning.py delete mode 100644 src/speechify/types/api_key.py delete mode 100644 src/speechify/types/attached_knowledge_bases_response.py delete mode 100644 src/speechify/types/attached_tools_response.py delete mode 100644 src/speechify/types/audio_asset.py delete mode 100644 src/speechify/types/available_phone_number.py delete mode 100644 src/speechify/types/basic_auth_config.py delete mode 100644 src/speechify/types/batch_call.py delete mode 100644 src/speechify/types/batch_call_status.py delete mode 100644 src/speechify/types/batch_recipient.py delete mode 100644 src/speechify/types/batch_recipient_request.py delete mode 100644 src/speechify/types/batch_recipient_status.py delete mode 100644 src/speechify/types/batch_run_entry.py delete mode 100644 src/speechify/types/bearer_auth_config.py delete mode 100644 src/speechify/types/billing_entitlements.py delete mode 100644 src/speechify/types/caller.py delete mode 100644 src/speechify/types/caller_memory_item.py delete mode 100644 src/speechify/types/client_tool_config.py delete mode 100644 src/speechify/types/conversation.py delete mode 100644 src/speechify/types/conversation_end_reason.py delete mode 100644 src/speechify/types/conversation_ivr_surrender_reason.py delete mode 100644 src/speechify/types/conversation_stats.py delete mode 100644 src/speechify/types/conversation_status.py delete mode 100644 src/speechify/types/conversation_transport.py delete mode 100644 src/speechify/types/create_access_token_request.py delete mode 100644 src/speechify/types/create_access_token_request_grant_type.py delete mode 100644 src/speechify/types/create_access_token_request_scope.py delete mode 100644 src/speechify/types/create_api_key_request.py delete mode 100644 src/speechify/types/create_batch_call_response.py delete mode 100644 src/speechify/types/create_conversation_response.py delete mode 100644 src/speechify/types/create_credential_request.py delete mode 100644 src/speechify/types/create_flow_template_request.py delete mode 100644 src/speechify/types/create_invite_request.py delete mode 100644 src/speechify/types/create_outbound_call_response.py delete mode 100644 src/speechify/types/create_workspace_request.py delete mode 100644 src/speechify/types/credential.py delete mode 100644 src/speechify/types/credential_config.py delete mode 100644 src/speechify/types/credential_kind.py delete mode 100644 src/speechify/types/criterion_status.py delete mode 100644 src/speechify/types/custom_headers_config.py delete mode 100644 src/speechify/types/data_assertion.py delete mode 100644 src/speechify/types/data_assertion_mode.py delete mode 100644 src/speechify/types/data_assertion_result.py delete mode 100644 src/speechify/types/data_assertion_result_mode.py delete mode 100644 src/speechify/types/data_collection_field.py delete mode 100644 src/speechify/types/data_collection_field_type.py delete mode 100644 src/speechify/types/delete_caller_response.py delete mode 100644 src/speechify/types/delete_memories_by_caller_response.py delete mode 100644 src/speechify/types/dependent_agent.py delete mode 100644 src/speechify/types/dynamic_variable.py delete mode 100644 src/speechify/types/dynamic_variable_type.py delete mode 100644 src/speechify/types/entitlements_response.py delete mode 100644 src/speechify/types/evaluation.py delete mode 100644 src/speechify/types/evaluation_config.py delete mode 100644 src/speechify/types/evaluation_criterion.py delete mode 100644 src/speechify/types/evaluation_kind.py delete mode 100644 src/speechify/types/evaluation_status.py delete mode 100644 src/speechify/types/flow_graph.py delete mode 100644 src/speechify/types/flow_graph_input.py delete mode 100644 src/speechify/types/flow_template.py delete mode 100644 src/speechify/types/flow_validation_error.py delete mode 100644 src/speechify/types/flow_validation_issue.py delete mode 100644 src/speechify/types/flow_version.py delete mode 100644 src/speechify/types/get_batch_call_response.py delete mode 100644 src/speechify/types/get_caller_response.py delete mode 100644 src/speechify/types/get_flow_response.py delete mode 100644 src/speechify/types/get_flow_version_response.py delete mode 100644 src/speechify/types/import_job.py delete mode 100644 src/speechify/types/import_job_kind.py delete mode 100644 src/speechify/types/import_job_response.py delete mode 100644 src/speechify/types/import_job_status.py delete mode 100644 src/speechify/types/invite.py delete mode 100644 src/speechify/types/invite_preview.py delete mode 100644 src/speechify/types/invites_list_response.py delete mode 100644 src/speechify/types/ivr_menu.py delete mode 100644 src/speechify/types/ivr_menu_list_entry.py delete mode 100644 src/speechify/types/knowledge_base.py delete mode 100644 src/speechify/types/knowledge_base_chunk.py delete mode 100644 src/speechify/types/knowledge_base_document.py delete mode 100644 src/speechify/types/knowledge_base_document_detail.py delete mode 100644 src/speechify/types/knowledge_base_document_source_kind.py delete mode 100644 src/speechify/types/knowledge_base_document_status.py delete mode 100644 src/speechify/types/knowledge_base_folder.py delete mode 100644 src/speechify/types/knowledge_base_search_hit.py delete mode 100644 src/speechify/types/list_agent_builtins_response.py delete mode 100644 src/speechify/types/list_agent_test_attachments_response.py delete mode 100644 src/speechify/types/list_agent_test_folders_response.py delete mode 100644 src/speechify/types/list_agent_test_runs_response.py delete mode 100644 src/speechify/types/list_agent_tests_response.py delete mode 100644 src/speechify/types/list_agents_response.py delete mode 100644 src/speechify/types/list_audio_assets_response.py delete mode 100644 src/speechify/types/list_batch_calls_response.py delete mode 100644 src/speechify/types/list_caller_conversations_response.py delete mode 100644 src/speechify/types/list_caller_memories_response.py delete mode 100644 src/speechify/types/list_callers_response.py delete mode 100644 src/speechify/types/list_conversations_response.py delete mode 100644 src/speechify/types/list_credentials_response.py delete mode 100644 src/speechify/types/list_dynamic_variables_response.py delete mode 100644 src/speechify/types/list_evaluations_response.py delete mode 100644 src/speechify/types/list_flow_templates_response.py delete mode 100644 src/speechify/types/list_flow_versions_response.py delete mode 100644 src/speechify/types/list_import_jobs_response.py delete mode 100644 src/speechify/types/list_ivr_menus_response.py delete mode 100644 src/speechify/types/list_knowledge_base_chunks_response.py delete mode 100644 src/speechify/types/list_knowledge_base_documents_response.py delete mode 100644 src/speechify/types/list_knowledge_base_folders_response.py delete mode 100644 src/speechify/types/list_knowledge_bases_response.py delete mode 100644 src/speechify/types/list_memories_response.py delete mode 100644 src/speechify/types/list_messages_response.py delete mode 100644 src/speechify/types/list_phone_numbers_response.py delete mode 100644 src/speechify/types/list_recent_callees_response.py delete mode 100644 src/speechify/types/list_refresh_history_response.py delete mode 100644 src/speechify/types/list_retrieval_logs_response.py delete mode 100644 src/speechify/types/list_sip_trunks_response.py delete mode 100644 src/speechify/types/list_suite_runs_response.py delete mode 100644 src/speechify/types/list_system_builtins_response.py delete mode 100644 src/speechify/types/list_tests_response.py delete mode 100644 src/speechify/types/list_tool_attached_agents_response.py delete mode 100644 src/speechify/types/list_tools_response.py delete mode 100644 src/speechify/types/list_webhook_deliveries_response.py delete mode 100644 src/speechify/types/llm_provider.py delete mode 100644 src/speechify/types/mcp_auth.py delete mode 100644 src/speechify/types/mcp_auth_bearer.py delete mode 100644 src/speechify/types/mcp_auth_none.py delete mode 100644 src/speechify/types/mcp_auth_o_auth2.py delete mode 100644 src/speechify/types/mcp_auth_type.py delete mode 100644 src/speechify/types/mcp_probe_error_details.py delete mode 100644 src/speechify/types/mcp_probe_error_details_stage.py delete mode 100644 src/speechify/types/mcp_probe_result.py delete mode 100644 src/speechify/types/mcp_probe_tool.py delete mode 100644 src/speechify/types/mcp_tool_config.py delete mode 100644 src/speechify/types/mcp_transport.py delete mode 100644 src/speechify/types/member.py delete mode 100644 src/speechify/types/member_role.py delete mode 100644 src/speechify/types/members_list_response.py delete mode 100644 src/speechify/types/memory.py delete mode 100644 src/speechify/types/message.py delete mode 100644 src/speechify/types/message_role.py delete mode 100644 src/speechify/types/mocking_strategy.py delete mode 100644 src/speechify/types/no_match_behavior.py delete mode 100644 src/speechify/types/o_auth2client_credentials_config.py delete mode 100644 src/speechify/types/o_auth2jwt_config.py delete mode 100644 src/speechify/types/o_auth_error.py delete mode 100644 src/speechify/types/o_auth_error_error.py delete mode 100644 src/speechify/types/pagination_meta.py delete mode 100644 src/speechify/types/parameter_check.py delete mode 100644 src/speechify/types/parameter_check_mode.py delete mode 100644 src/speechify/types/parameter_check_result.py delete mode 100644 src/speechify/types/phone_number.py delete mode 100644 src/speechify/types/phone_number_capability.py delete mode 100644 src/speechify/types/phone_number_source.py delete mode 100644 src/speechify/types/recent_callee.py delete mode 100644 src/speechify/types/refresh_config.py delete mode 100644 src/speechify/types/refresh_history_entry.py delete mode 100644 src/speechify/types/refresh_history_entry_status.py delete mode 100644 src/speechify/types/reply_config.py delete mode 100644 src/speechify/types/reply_result.py delete mode 100644 src/speechify/types/retrieval_log_entry.py delete mode 100644 src/speechify/types/retrieval_log_result.py delete mode 100644 src/speechify/types/run_agent_tests_response.py delete mode 100644 src/speechify/types/run_batch_response.py delete mode 100644 src/speechify/types/search_available_phone_numbers_response.py delete mode 100644 src/speechify/types/search_knowledge_bases_response.py delete mode 100644 src/speechify/types/shadow_conversation_response.py delete mode 100644 src/speechify/types/simulation_config.py delete mode 100644 src/speechify/types/simulation_criterion_result.py delete mode 100644 src/speechify/types/simulation_criterion_result_status.py delete mode 100644 src/speechify/types/simulation_message.py delete mode 100644 src/speechify/types/simulation_message_role.py delete mode 100644 src/speechify/types/simulation_result.py delete mode 100644 src/speechify/types/simulation_result_sentiment.py delete mode 100644 src/speechify/types/simulation_tool_call.py delete mode 100644 src/speechify/types/sip_media_encryption.py delete mode 100644 src/speechify/types/sip_transport.py delete mode 100644 src/speechify/types/sip_trunk.py delete mode 100644 src/speechify/types/sip_trunk_direction.py delete mode 100644 src/speechify/types/sip_trunk_kind.py delete mode 100644 src/speechify/types/suite_child_run.py delete mode 100644 src/speechify/types/suite_run_trigger.py delete mode 100644 src/speechify/types/system_builtin.py delete mode 100644 src/speechify/types/system_builtin_info.py delete mode 100644 src/speechify/types/system_tool_config.py delete mode 100644 src/speechify/types/system_variable_doc.py delete mode 100644 src/speechify/types/tenant.py delete mode 100644 src/speechify/types/tenants_list_response.py delete mode 100644 src/speechify/types/test_run_config_override.py delete mode 100644 src/speechify/types/test_run_result.py delete mode 100644 src/speechify/types/test_run_status.py delete mode 100644 src/speechify/types/test_stats.py delete mode 100644 src/speechify/types/test_stats_bucket.py delete mode 100644 src/speechify/types/test_type.py delete mode 100644 src/speechify/types/tool.py delete mode 100644 src/speechify/types/tool_attached_agent.py delete mode 100644 src/speechify/types/tool_call_config.py delete mode 100644 src/speechify/types/tool_call_result.py delete mode 100644 src/speechify/types/tool_config.py delete mode 100644 src/speechify/types/tool_kind.py delete mode 100644 src/speechify/types/tool_mock.py delete mode 100644 src/speechify/types/tool_mock_config.py delete mode 100644 src/speechify/types/tool_param.py delete mode 100644 src/speechify/types/tool_param_type.py delete mode 100644 src/speechify/types/transfer_ownership_request.py delete mode 100644 src/speechify/types/twilio_import_spec.py delete mode 100644 src/speechify/types/update_billing_contact_email_request.py delete mode 100644 src/speechify/types/update_billing_contact_name_request.py delete mode 100644 src/speechify/types/update_member_role_request.py delete mode 100644 src/speechify/types/update_sip_trunk_request.py delete mode 100644 src/speechify/types/update_workspace_request.py delete mode 100644 src/speechify/types/upload_audio_asset_response.py delete mode 100644 src/speechify/types/webhook_delivery.py delete mode 100644 src/speechify/types/webhook_delivery_status.py delete mode 100644 src/speechify/types/webhook_probe_result.py delete mode 100644 src/speechify/types/webhook_tool_config.py delete mode 100644 src/speechify/types/webhook_tool_config_method.py delete mode 100644 src/speechify/types/widget_config.py delete mode 100644 src/speechify/types/widget_config_avatar.py delete mode 100644 src/speechify/types/widget_config_avatar_type.py delete mode 100644 src/speechify/types/widget_config_style.py delete mode 100644 src/speechify/types/widget_config_terms.py delete mode 100644 src/speechify/types/widget_config_text.py delete mode 100644 src/speechify/types/widget_config_theme.py delete mode 100644 src/speechify/types/widget_config_transcript.py diff --git a/README.md b/README.md index 50fbf27..b6c5d9f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ The Speechifyinc Python library provides convenient access to the Speechifyinc A - [Usage](#usage) - [Async Client](#async-client) - [Exception Handling](#exception-handling) -- [Pagination](#pagination) - [Advanced](#advanced) - [Retries](#retries) - [Timeouts](#timeouts) @@ -44,11 +43,11 @@ from speechify import Speechify client = Speechify( token="YOUR_TOKEN", ) -client.agent.create( - name="name", - prompt="prompt", - first_message="first_message", - voice_id="voice_id", +client.tts.audio.speech( + audio_format="mp3", + input="Hello! This is the Speechify text-to-speech API.", + model="simba-english", + voice_id="george", ) ``` @@ -67,11 +66,11 @@ client = AsyncSpeechify( async def main() -> None: - await client.agent.create( - name="name", - prompt="prompt", - first_message="first_message", - voice_id="voice_id", + await client.tts.audio.speech( + audio_format="mp3", + input="Hello! This is the Speechify text-to-speech API.", + model="simba-english", + voice_id="george", ) @@ -87,30 +86,12 @@ will be thrown. from speechify.core.api_error import ApiError try: - client.agent.create(...) + client.tts.audio.speech(...) except ApiError as e: print(e.status_code) print(e.body) ``` -## Pagination - -Paginated requests will return a `SyncPager` or `AsyncPager`, which can be used as generators for the underlying object. - -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.tools.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page -``` - ## Advanced ### Retries @@ -128,7 +109,7 @@ A request is deemed retryable when any of the following HTTP status codes is ret Use the `max_retries` request option to configure this behavior. ```python -client.agent.create(..., request_options={ +client.tts.audio.speech(..., request_options={ "max_retries": 1 }) ``` @@ -148,7 +129,7 @@ client = Speechify( # Override timeout for a specific method -client.agent.create(..., request_options={ +client.tts.audio.speech(..., request_options={ "timeout_in_seconds": 1 }) ``` diff --git a/poetry.lock b/poetry.lock index 03a0363..0474c73 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,16 +1,5 @@ # This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. -[[package]] -name = "aiofiles" -version = "25.1.0" -description = "File support for asyncio." -optional = false -python-versions = ">=3.9" -files = [ - {file = "aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695"}, - {file = "aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2"}, -] - [[package]] name = "annotated-types" version = "0.7.0" @@ -22,34 +11,40 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "anyio" -version = "4.12.1" -description = "High-level concurrency and networking framework on top of asyncio or Trio" +version = "4.5.2" +description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c"}, - {file = "anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703"}, + {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"}, + {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -trio = ["trio (>=0.31.0)", "trio (>=0.32.0)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2026.5.20" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" files = [ - {file = "certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897"}, - {file = "certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] @@ -138,13 +133,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "idna" -version = "3.18" +version = "3.15" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, - {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, + {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, + {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, ] [package.extras] @@ -161,27 +156,6 @@ files = [ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] -[[package]] -name = "livekit" -version = "1.1.10" -description = "Python Real-time SDK for LiveKit" -optional = false -python-versions = ">=3.9.0" -files = [ - {file = "livekit-1.1.10-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:495b23988673bf6571fd0faaf621416e973fa1d302b1acccd479e0461cac924d"}, - {file = "livekit-1.1.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7bd85dda5c8b11458b3447cbb02630af7bb267d424c65c89d2e6d736905147d1"}, - {file = "livekit-1.1.10-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:b05299fa0a4c98d8d57f0013367adad70a84dd5fc9c46e4a7f3df5352c81b6c1"}, - {file = "livekit-1.1.10-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:29f58fe30dc181c45b0a9c929beaacacde0b2253fa6e597547508d5269e9012b"}, - {file = "livekit-1.1.10-py3-none-win_amd64.whl", hash = "sha256:13ac0c8498e0e5bc41292526966fd6ad86baa66e1915778b128cf7e953b107fc"}, - {file = "livekit-1.1.10.tar.gz", hash = "sha256:202101c49a1fbc1d771d5dfb884c77f42c01dafc411d12224b992fac78a843cb"}, -] - -[package.dependencies] -aiofiles = ">=24" -numpy = ">=1.26" -protobuf = ">=4.25.0" -types-protobuf = ">=3" - [[package]] name = "mypy" version = "1.0.1" @@ -239,60 +213,6 @@ files = [ {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] -[[package]] -name = "numpy" -version = "2.0.2" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = ">=3.9" -files = [ - {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, - {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, - {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, - {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, - {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, - {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, - {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, - {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, - {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, - {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, - {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, - {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, - {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, - {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, - {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, - {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, - {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, - {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, - {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, - {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, - {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, - {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, - {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, - {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, - {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, - {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, - {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, - {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, - {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, - {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, - {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, - {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, - {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, - {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, - {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, - {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, - {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, - {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, - {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, - {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, - {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, - {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, - {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, -] - [[package]] name = "packaging" version = "26.2" @@ -306,54 +226,34 @@ files = [ [[package]] name = "pluggy" -version = "1.6.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, - {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["coverage", "pytest", "pytest-benchmark"] - -[[package]] -name = "protobuf" -version = "6.33.6" -description = "" -optional = false -python-versions = ">=3.9" -files = [ - {file = "protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3"}, - {file = "protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326"}, - {file = "protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a"}, - {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2"}, - {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3"}, - {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593"}, - {file = "protobuf-6.33.6-cp39-cp39-win32.whl", hash = "sha256:bd56799fb262994b2c2faa1799693c95cc2e22c62f56fb43af311cae45d26f0e"}, - {file = "protobuf-6.33.6-cp39-cp39-win_amd64.whl", hash = "sha256:f443a394af5ed23672bc6c486be138628fbe5c651ccbc536873d7da23d1868cf"}, - {file = "protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901"}, - {file = "protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135"}, -] +testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.13.4" +version = "2.10.6" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba"}, - {file = "pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.46.4" -typing-extensions = ">=4.14.1" -typing-inspection = ">=0.4.2" +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -361,135 +261,115 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.46.4" +version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4"}, - {file = "pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39"}, - {file = "pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d"}, - {file = "pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf"}, - {file = "pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594"}, - {file = "pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d"}, - {file = "pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2"}, - {file = "pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a"}, - {file = "pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008"}, - {file = "pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d"}, - {file = "pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb"}, - {file = "pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596"}, - {file = "pydantic_core-2.46.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fd8b3d9fd264be37976686c7f65cd52a83f5e84f4bfd2adf9c1d469676bbb6ae"}, - {file = "pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f444c499b3eefd3a92e348059471ea0c3a6e303d9c1cec09fa748fd9f895201"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3447661d99f75a3683a4cf5c87da72f2161964611864dbbeac7fbb118bb4bfc0"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b9bab013d1c7a79d3501ff86d0bc9c31bf587db4551677b96bec07df78c6b15"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d995260fdf4e1db774581b4900e0f832abe3c7c84996726bbc161b19c8f29e76"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13a646d65d09fbf1bc6b3a9635d30095c8e7e5cc419ff35ecc563c5fd04cd49"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432c179df7874eeb73307aad2df0755e1ae0efa61ff0ea89b93e194411ae3928"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:e68b7a074f65a2fd746c52a7ce6142ab7006074ac269ace0c25cd8ba171f8066"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4a05d69cba51d852c5c3e92758653245a50c0b646ced0cf05bd793ed592839d6"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:228ee9bae8bef5b1e97ec58302f80357c37199e0d0a99174e138d28e6957b9d9"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:10e17cbb10a330363733efc4d7c4d0dd827ac0909b8f6a6542298fed1ea62f29"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:91a06d2e259ecfbd8c901d70c3c507900458498142b3026a296b7de4d1322cc9"}, - {file = "pydantic_core-2.46.4-cp39-cp39-win32.whl", hash = "sha256:d80ee3d731373b24cebbc10d689ca4ee1875caf0d5703a245db18efd4dd37fc1"}, - {file = "pydantic_core-2.46.4-cp39-cp39-win_amd64.whl", hash = "sha256:3be77f45df024d789a672ae34f8b06fb346c4f9f46ea714956660ea4862e89ac"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983"}, - {file = "pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] [package.dependencies] -typing-extensions = ">=4.14.1" +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pytest" @@ -583,6 +463,17 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + [[package]] name = "tomli" version = "2.4.1" @@ -639,54 +530,29 @@ files = [ {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, ] -[[package]] -name = "types-protobuf" -version = "6.32.1.20251210" -description = "Typing stubs for protobuf" -optional = false -python-versions = ">=3.9" -files = [ - {file = "types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140"}, - {file = "types_protobuf-6.32.1.20251210.tar.gz", hash = "sha256:c698bb3f020274b1a2798ae09dc773728ce3f75209a35187bd11916ebfde6763"}, -] - [[package]] name = "types-python-dateutil" -version = "2.9.0.20260124" +version = "2.9.0.20241206" description = "Typing stubs for python-dateutil" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "types_python_dateutil-2.9.0.20260124-py3-none-any.whl", hash = "sha256:f802977ae08bf2260142e7ca1ab9d4403772a254409f7bbdf652229997124951"}, - {file = "types_python_dateutil-2.9.0.20260124.tar.gz", hash = "sha256:7d2db9f860820c30e5b8152bfe78dbdf795f7d1c6176057424e8b3fdd1f581af"}, + {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, + {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, ] [[package]] name = "typing-extensions" -version = "4.15.0" -description = "Backported and Experimental Type Hints for Python 3.9+" -optional = false -python-versions = ">=3.9" -files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -description = "Runtime typing introspection tools" +version = "4.13.2" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, - {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, ] -[package.dependencies] -typing-extensions = ">=4.12.0" - [metadata] lock-version = "2.0" -python-versions = ">=3.9" -content-hash = "bcb69b3dc92a4cfe51225e0458007de660bb7d193d3ecbf46bc052a030ebc92e" +python-versions = "^3.8" +content-hash = "6f6c191c1028d17a97fdfa84cedfd3cef94b5d63d98b8c1d333b3398eeea9055" diff --git a/pyproject.toml b/pyproject.toml index 9246d68..2615901 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[project] +name = "speechify-api" + [tool.poetry] name = "speechify-api" version = "1.2.4" @@ -19,6 +22,7 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -35,15 +39,14 @@ packages = [ { include = "speechify", from = "src"} ] -[tool.poetry.urls] +[project.urls] Documentation = 'https://docs.speechify.ai/api-reference' Homepage = 'https://docs.speechify.ai' Repository = 'https://github.com/speechifyinc/speechify-api-sdk-python' [tool.poetry.dependencies] -python = ">=3.9" +python = "^3.8" httpx = ">=0.21.2" -livekit = ">=1.1,<2" pydantic = ">= 1.9.2" pydantic-core = "^2.18.2" typing_extensions = ">= 4.0.0" diff --git a/reference.md b/reference.md index 59e0ded..fb5f4ee 100644 --- a/reference.md +++ b/reference.md @@ -1,13047 +1,4 @@ # Reference -## Agent -
client.agent.list() -
-
- -#### 📝 Description - -
-
- -
-
- -List voice agents owned by the caller. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a voice agent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.create( - name="name", - prompt="prompt", - first_message="first_message", - voice_id="voice_id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**prompt:** `str` - -
-
- -
-
- -**first_message:** `str` — Greeting spoken verbatim at session start when included in the agent's flow graph. - -
-
- -
-
- -**voice_id:** `str` — Voice slug from the VMS catalog (see GET /v1/voices). Required — the server rejects writes with an unknown or empty slug. - -
-
- -
-
- -**slug:** `typing.Optional[str]` — Optional. Server derives slug from name with a random suffix when omitted; if you supply your own, a collision returns 400 'slug already taken'. - -
-
- -
-
- -**language:** `typing.Optional[str]` — ISO 639-1 code. Defaults to 'en' when omitted. - -
-
- -
-
- -**llm_provider:** `typing.Optional[CreateAgentRequestLlmProvider]` - -LLM backend. Leave empty (or omit both `llm_provider` and -`llm_model`) to use the platform default (today: Speechify -Kimi K2.6, resolved server-side at dispatch). When set, -must be paired with a non-empty `llm_model`; mixing a -populated provider with an empty model is rejected as a -400. `custom` additionally requires `llm_base_url`. - -
-
- -
-
- -**llm_model:** `typing.Optional[str]` - -Chat model slug. Leave empty to use the platform default. -For `openai` / `speechify` the (provider, model) pair must -be in the allowed table; for `custom` it is free-form. - -
-
- -
-
- -**llm_base_url:** `typing.Optional[str]` - -Custom OpenAI/vLLM-compatible endpoint base URL. Required -when `llm_provider` is `custom`, rejected otherwise. - -
-
- -
-
- -**llm_api_key:** `typing.Optional[str]` - -Bearer key for the custom endpoint. Write-only - stored -encrypted, never returned (GET exposes `llm_api_key_set`). -Optional even for `custom` (keyless endpoints); rejected -for any other provider. - -
-
- -
-
- -**llm_extra_body:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Optional JSON object forwarded verbatim to the custom -endpoint as the chat.completions `extra_body` (reasoning / -sampling knobs). Valid only when `llm_provider` is -`custom`. - -
-
- -
-
- -**temperature:** `typing.Optional[float]` — Sampling temperature in the range 0.0–1.0. Defaults to 0.5 when omitted. - -
-
- -
-
- -**widget_config:** `typing.Optional[WidgetConfig]` - -
-
- -
-
- -**is_public:** `typing.Optional[bool]` — Defaults to false when omitted. - -
-
- -
-
- -**allowed_origins:** `typing.Optional[typing.Sequence[str]]` - -
-
- -
-
- -**hostname_allowlist:** `typing.Optional[typing.Sequence[str]]` — Optional per-agent hostname allowlist (see Agent schema). - -
-
- -
-
- -**memory_enabled:** `typing.Optional[bool]` — Defaults to false when omitted. - -
-
- -
-
- -**memory_retention_days:** `typing.Optional[int]` — Defaults to 90 when omitted. - -
-
- -
-
- -**webhook_url:** `typing.Optional[str]` — Customer-facing post-call webhook URL. - -
-
- -
-
- -**webhook_secret:** `typing.Optional[str]` - -HMAC-SHA256 secret seed. Write-only — never echoed back on -reads; clients see `webhook_secret_set: true` instead. - -
-
- -
-
- -**amd:** `typing.Optional[AmdConfig]` — AMD routing config. Optional on create; omitted means AMD off. See AMDConfig schema. - -
-
- -
-
- -**save_audio_recording:** `typing.Optional[bool]` — When set, opts the agent into per-conversation audio recording. Defaults to false when omitted. - -
-
- -
-
- -**navigator_mode:** `typing.Optional[bool]` — When set, opts the agent into IVR-tuned turn handling. Defaults to false when omitted. - -
-
- -
-
- -**ivr_memory_enabled:** `typing.Optional[bool]` — When omitted, defaults to true. Set to false to opt-out of the IVR-memory cache lookup for this agent. - -
-
- -
-
- -**tts_speaking_rate:** `typing.Optional[float]` - -
-
- -
-
- -**tts_playback_rate:** `typing.Optional[float]` - -Post-process pitch-preserving time-stretch on the synthesized -audio. See the field on Agent for semantics. - -
-
- -
-
- -**response_delay_seconds:** `typing.Optional[float]` - -Per-agent override for the worker's endpointing min_delay on -the VAD path (seconds). See the field on Agent for semantics. -Range 0.0..5.0; null means use the stack default. - -
-
- -
-
- -**inactivity_timeout_seconds:** `typing.Optional[int]` - -Per-agent silence-tolerance override in seconds. Send `0` -to clear the override and fall back to the platform -default. Negative values are rejected. - -
-
- -
-
- -**background_noise_preset:** `typing.Optional[CreateAgentRequestBackgroundNoisePreset]` - -Pre-mixed ambient bed slug. Send empty string ("") to -disable the bed, which also clears `background_noise_volume`. - -
-
- -
-
- -**background_noise_volume:** `typing.Optional[float]` - -Volume of the background-noise bed (0..1). Ignored when -`background_noise_preset` is empty. - -
-
- -
-
- -**stt_override:** `typing.Optional[CreateAgentRequestSttOverride]` - -Optional non-default streaming-STT stack for this agent. -Omit to use the worker's default stack (today: whisper-v3). -See the Agent schema for the full option semantics. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_agent_voices() -
-
- -#### 📝 Description - -
-
- -
-
- -List the curated voice catalogue available for voice agents. -Matches the `ai-api-agents` VMS scope one-for-one, so the same -slug set is accepted by POST/PATCH /v1/agents. Personal -(cloned) voices are NOT included — they stay on -`GET /v1/voices`. The JSON layout intentionally mirrors the -TTS `/v1/voices` shape so the console feeds both endpoints -into the same voice-picker component. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_agent_voices() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a voice agent by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a voice agent. Conversations and attached tools remain. Tests whose only agent is this one are deleted with it; tests also attached to other agents survive, minus the attachment. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a voice agent. Only fields present on the request body are changed. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.update( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**prompt:** `typing.Optional[str]` - -
-
- -
-
- -**first_message:** `typing.Optional[str]` - -
-
- -
-
- -**language:** `typing.Optional[str]` - -
-
- -
-
- -**llm_provider:** `typing.Optional[UpdateAgentRequestLlmProvider]` - -LLM backend. Send an empty string together with -`llm_model: ""` to clear the pair to the platform default -(today: Speechify Kimi K2.6). Sending one populated and -one empty is rejected as a 400. Omit both to leave the -stored pair unchanged. Switching to a non-`custom` provider -clears any stored `llm_base_url` / `llm_api_key` / -`llm_extra_body`. - -
-
- -
-
- -**llm_model:** `typing.Optional[str]` - -Chat model slug. Empty string + empty `llm_provider` -clears the pair to the platform default. For `openai` / -`speechify` the (provider, model) pair must be in the -allowed table; for `custom` it is free-form. - -
-
- -
-
- -**llm_base_url:** `typing.Optional[str]` - -Custom-endpoint base URL. Required when the resulting -provider is `custom`, rejected otherwise. - -
-
- -
-
- -**llm_api_key:** `typing.Optional[str]` - -Bearer key for the custom endpoint. Write-only. Omit to -keep the stored key, send "" to clear it, send a value to -replace it. Rejected for non-`custom` providers. - -
-
- -
-
- -**llm_extra_body:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -JSON object forwarded to the custom endpoint as -chat.completions `extra_body`. Omit to leave unchanged; -a JSON object (including `{}`) replaces it. Valid only -when the resulting provider is `custom`. - -
-
- -
-
- -**voice_id:** `typing.Optional[str]` - -
-
- -
-
- -**temperature:** `typing.Optional[float]` — Sampling temperature in the range 0.0–1.0. Omit to leave unchanged. - -
-
- -
-
- -**widget_config:** `typing.Optional[WidgetConfig]` - -
-
- -
-
- -**is_public:** `typing.Optional[bool]` - -
-
- -
-
- -**allowed_origins:** `typing.Optional[typing.Sequence[str]]` - -
-
- -
-
- -**hostname_allowlist:** `typing.Optional[typing.Sequence[str]]` - -When supplied, replaces the stored list. Pass an empty -array to clear enforcement (public agent is open again). -Omit the field to leave the existing value unchanged. - -
-
- -
-
- -**memory_enabled:** `typing.Optional[bool]` - -
-
- -
-
- -**memory_retention_days:** `typing.Optional[int]` - -
-
- -
-
- -**webhook_url:** `typing.Optional[str]` - -
-
- -
-
- -**webhook_secret:** `typing.Optional[str]` — Rotate the HMAC secret. Write-only. - -
-
- -
-
- -**amd:** `typing.Optional[AmdConfig]` — AMD routing config (PATCH-replace, wholesale). Omit to leave the stored config unchanged. - -
-
- -
-
- -**save_audio_recording:** `typing.Optional[bool]` - -
-
- -
-
- -**navigator_mode:** `typing.Optional[bool]` - -
-
- -
-
- -**ivr_memory_enabled:** `typing.Optional[bool]` — Per-agent kill switch for the IVR-memory cache lookup. nil/omit = unchanged. - -
-
- -
-
- -**tts_speaking_rate:** `typing.Optional[float]` - -
-
- -
-
- -**clear_tts_speaking_rate:** `typing.Optional[bool]` - -Two-headed clear: PATCH cannot distinguish "absent" from -"explicit null" reliably across stacks. Setting this to -`true` resets `tts_speaking_rate` to the voice default. -If both are sent, `clear_tts_speaking_rate` wins. - -
-
- -
-
- -**tts_playback_rate:** `typing.Optional[float]` - -
-
- -
-
- -**clear_tts_playback_rate:** `typing.Optional[bool]` - -Two-headed clear, mirroring `clear_tts_speaking_rate`. -Setting this to `true` resets `tts_playback_rate` to null -(no post-process). If both fields are sent, -`clear_tts_playback_rate` wins. - -
-
- -
-
- -**response_delay_seconds:** `typing.Optional[float]` - -Per-agent silence-wait override (seconds). See the field -on Agent for semantics. Range 0.0..5.0; null is allowed -but `clear_response_delay_seconds=true` is the canonical -way to revert to the stack default. - -
-
- -
-
- -**clear_response_delay_seconds:** `typing.Optional[bool]` - -Two-headed clear, mirroring `clear_tts_playback_rate`. -Setting this to `true` resets `response_delay_seconds` to -null (revert to the stack default). If both are sent, -`clear_response_delay_seconds` wins. - -
-
- -
-
- -**inactivity_timeout_seconds:** `typing.Optional[int]` - -Per-agent silence-tolerance override. Send `0` to clear -the override and fall back to the platform default. -Negative values are rejected. - -
-
- -
-
- -**background_noise_preset:** `typing.Optional[UpdateAgentRequestBackgroundNoisePreset]` - -Pre-mixed ambient bed slug. Send empty string ("") to -disable the bed, which also clears `background_noise_volume`. - -
-
- -
-
- -**background_noise_volume:** `typing.Optional[float]` - -Volume of the background-noise bed (0..1). Ignored when -the preset is empty; clearing the preset also clears -this field server-side. - -
-
- -
-
- -**stt_override:** `typing.Optional[UpdateAgentRequestSttOverride]` - -Streaming-STT stack override. Send an empty string ("") to -clear the override and fall back to the worker default -(today: whisper-v3). Any non-empty value must be a known -stack name. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_tools(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List tools currently attached to the agent. Bare list — an -agent's tool attachment count is bounded by configuration, so -this endpoint does not paginate. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_tools( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.attach_tool(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Attach an existing tool to the agent so the LLM can call it. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.attach_tool( - id="id", - tool_id="toolId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**tool_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.detach_tool(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Detach a tool from the agent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.detach_tool( - id="id", - tool_id="toolId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**tool_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.get_evaluation_config(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the agent's post-call evaluation criteria + data-collection config. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.get_evaluation_config( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.update_evaluation_config(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Replace the agent's evaluation criteria + data-collection fields. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import DataCollectionField, EvaluationCriterion, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.update_evaluation_config( - id="id", - criteria=[ - EvaluationCriterion( - id="id", - name="name", - description="description", - ) - ], - data_collection=[ - DataCollectionField( - key="key", - description="description", - type="string", - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**criteria:** `typing.Sequence[EvaluationCriterion]` - -
-
- -
-
- -**data_collection:** `typing.Sequence[DataCollectionField]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.get_dynamic_variables(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the agent's customer-scope dynamic variables and the read-only -catalogue of reserved `system__*` keys. The system variables list is -provided so editor UIs can render the reference list without maintaining -a client-side copy of the catalogue. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.get_dynamic_variables( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.update_dynamic_variables(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Replace the agent's customer-scope dynamic variable definitions. -The supplied list overwrites the stored list wholesale (same -semantics as `updateEvaluationConfig`). Pass an empty array to -clear all variables. Up to 20 variables per agent. Keys must -match `[a-zA-Z0-9_]+` and must not start with the reserved -`system__` prefix. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import DynamicVariable, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.update_dynamic_variables( - id="id", - variables=[ - DynamicVariable( - key="product_name", - type="string", - default="Speechify", - description="Product the agent is supporting.", - ), - DynamicVariable( - key="support_tier", - type="number", - default=1, - ), - DynamicVariable( - key="account_metadata", - type="json", - description="Arbitrary account context injected into tool bodies.", - ), - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**variables:** `typing.Sequence[DynamicVariable]` — The new variable list. Replaces the existing list entirely. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_builtins(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List every builtin instance configured on this agent. Each row -is one instance of a worker-resident capability (`end_call`, -`play_audio`, etc.) bound to this specific agent with its own -LLM-facing name, description, and per-call config. Same builtin -may appear N times on one agent — typically two `play_audio` -rows bound to different audio assets. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_builtins( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.create_builtin(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new builtin instance on this agent. `builtin` must -resolve to one of the names returned by -`GET /v1/agents/tools/system-builtins`; unknown values are rejected. -`name` is the LLM-facing identifier the model uses to call the -tool; it must match the tool-name regex and be unique within -the agent's builtin set. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.create_builtin( - id="id", - builtin="builtin", - name="name", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**builtin:** `SystemBuiltin` - -
-
- -
-
- -**name:** `str` — LLM-facing tool name. Must match the tool-name regex and be unique within the agent's builtin set. - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**config:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Per-instance configuration matching the per-builtin schema. - -
-
- -
-
- -**params:** `typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]]` — Per-call parameter descriptors. - -
-
- -
-
- -**enabled:** `typing.Optional[bool]` — Defaults to true on the server when omitted. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.get_builtin(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Fetch one builtin instance by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.get_builtin( - id="id", - builtin_id="builtinId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**builtin_id:** `str` — Agent builtin instance ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.delete_builtin(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a builtin instance from this agent. Idempotent on -already-deleted ids (404). Does NOT detach references from -flow nodes that name the instance; the worker logs and skips -on missing-row at session start (fail-soft). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.delete_builtin( - id="id", - builtin_id="builtinId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**builtin_id:** `str` — Agent builtin instance ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.update_builtin(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a builtin instance. All fields optional; omitting a -field leaves it unchanged. The underlying `builtin` (which -capability the instance maps to) is intentionally NOT -patchable — change of identity would surprise the worker, so -the customer should delete and recreate instead. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.update_builtin( - id="id", - builtin_id="builtinId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**builtin_id:** `str` — Agent builtin instance ID. - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**config:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Per-instance configuration matching the per-builtin schema. - -
-
- -
-
- -**params:** `typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]]` — Per-call parameter descriptors. - -
-
- -
-
- -**enabled:** `typing.Optional[bool]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.create_conversation(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Start a new voice conversation with the agent. Returns a realtime -voice session + short-lived client token so the caller can -connect the audio pipeline directly. The agent is dispatched -server-side; no additional client action required. - -Pass `dynamic_variables` to supply per-session values that override -the agent's stored variable defaults for this one conversation. -Keys in the `system__` namespace are rejected at this boundary. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.create_conversation( - id="agent_01HS...", - dynamic_variables={ - "product_name": "Acme Pro", - "support_tier": 2, - "account_metadata": {"plan": "enterprise", "seats": 50}, - }, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**transport:** `typing.Optional[str]` — Transport hint. Omit to use the agent's default. - -
-
- -
-
- -**dynamic_variables:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Per-session variable overrides that merge on top of the agent's -stored variable defaults for this one conversation. Keys in the -reserved `system__` namespace are rejected. Values must match the -declared type of the corresponding variable definition on the agent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.create_session(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Mint a realtime voice session for the given agent. Widget-friendly -counterpart to `createConversation` — same response shape, dual -authentication: - -* **Authenticated (Bearer)**: works for any agent the caller - owns. Typical server-to-server flow where the embedding - site's backend mints a token and hands it to the browser so - the API key never reaches the client. -* **Unauthenticated**: works only when `agent.is_public = true` - AND the request's `Origin` header matches `agent.allowed_origins` - (or that list is empty). When `agent.hostname_allowlist` is - non-empty, the `Origin` hostname must additionally be a - member of that list. Used directly by the - `` web component. - -Responds with the same `CreateConversationResponse` as -`createConversation`. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.create_session( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**user_identity:** `typing.Optional[str]` — Opaque identifier for the end-user (e.g. your app's user ID). Stamped onto the conversation. Optional - defaults to an anonymous per-session ID. - -
-
- -
-
- -**dynamic_variables:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Per-session variable overrides that merge on top of the agent's -stored variable defaults for this one session. Keys in the -reserved `system__` namespace are rejected at this boundary. -Values must match the declared type of the corresponding variable -definition on the agent (a `string` type expects a JSON string, -`number` expects a JSON number, etc.). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_agent_knowledge_bases(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List knowledge bases attached to an agent. Bare list — the -attachment count is bounded by configuration, not by data -scale, so this endpoint does not paginate. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_agent_knowledge_bases( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.attach_knowledge_base(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Attach a knowledge base to an agent. The `search_knowledge` tool -is auto-registered on the next conversation and can only query the -attached knowledge bases. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.attach_knowledge_base( - id="id", - kb_id="kbId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**kb_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.detach_knowledge_base(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Detach a knowledge base from an agent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.detach_knowledge_base( - id="id", - kb_id="kbId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**kb_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_memories(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List per-caller memories extracted for an agent. Memories are -written post-call by the built-in extractor when `memory_enabled` -is true on the agent; the list is sorted newest-first. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_memories( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Maximum rows to return. Defaults to 100, capped at 200. - -
-
- -
-
- -**offset:** `typing.Optional[int]` — Number of rows to skip. Combine with `limit` to page through older memories. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.delete_memories_by_caller(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete every memory ever extracted for a specific caller on -this agent. Privacy / GDPR surface. Returns the count of rows -soft-deleted; rows become permanently unreachable immediately -and are hard-deleted by the retention job after the tenant's -configured retention window. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.delete_memories_by_caller( - id="id", - agent_id="agent_id", - caller_identity="caller_identity", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**agent_id:** `str` - -
-
- -
-
- -**caller_identity:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.list_tests(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List all tests configured for the agent. Each entry includes the -most recent run so the console can render pass/fail badges without -an extra round-trip. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.list_tests( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.create_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new test for the agent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import ParameterCheck, Speechify, ToolCallConfig - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.create_test( - id="agent_01HS...", - name="Order lookup by id", - description="Agent looks up the order id supplied via test variables.", - type="tool", - config=ToolCallConfig( - context="Look up order {{order_id}} for {{customer_name}}", - expected_tool="lookup_order", - parameter_checks=[ - ParameterCheck( - path="order_id", - mode="exact", - expected='"{{order_id}}"', - ) - ], - ), - variables={"order_id": "ORD-123", "customer_name": "Alice"}, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**name:** `str` — Short human-readable label for the test. - -
-
- -
-
- -**type:** `TestType` - -
-
- -
-
- -**config:** `CreateAgentTestRequestConfig` — Type-specific configuration. Must match the shape for the given `type`. - -
-
- -
-
- -**description:** `typing.Optional[str]` — Optional longer description of what this test verifies. - -
-
- -
-
- -**tool_mock_config:** `typing.Optional[ToolMockConfig]` — Optional tool-mocking config applied during every run of this test. - -
-
- -
-
- -**variables:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Per-test variable values substituted into string fields of the -config at run-start. Keys use the same rules as agent-level -`DynamicVariable` keys. - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Prefixed wire identifier (`folder_<26 char Crockford base32>`) -of the folder to place the test in. Omit / null for root. - -
-
- -
-
- -**attached_agent_ids:** `typing.Optional[typing.Sequence[str]]` - -Optional list of additional agents this test should also run -against. The owner agent (path param) is always attached -implicitly. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.run_all_tests(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Enqueue runs for every test on the agent concurrently. Up to 50 -tests are dispatched in one call. Each returned run starts in -`queued` status; poll `GET /v1/agents/tests/runs/{id}` for the terminal -result. - -An optional request body runs the whole suite against -a proposed config: a `config_override` (prompt / model / tools) -applied to every test without editing the tests, and/or a -`flow_version_id` to target a specific flow version instead of -the agent's active flow. Omit the body to run against the -agent's live config and active flow. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.run_all_tests( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Agent ID. - -
-
- -
-
- -**config_override:** `typing.Optional[TestRunConfigOverride]` - -
-
- -
-
- -**flow_version_id:** `typing.Optional[str]` - -Targets a specific flow version (an `agent_versions` row) -instead of the agent's active flow — version-targeted -regression. Must be a flow version of the agent under test. -Raw UUID; flow versions carry no prefixed wire id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.get_widget_config(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Return the embed-widget appearance config for an agent. Works -unauthenticated for public agents; the body is cosmetic only. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.get_widget_config( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Tools -
client.agent.tools.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List tools in the caller's workspace, most recently updated -first. Cursor-paginated: omit `cursor` to fetch the first page. -Default page size is 50 and max is 200. Walk pages while -`has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.tools.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max tools per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a tool. For webhook tools, the response includes the HMAC -`webhook_secret` exactly once — store it immediately; subsequent -reads return a masked placeholder. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import ClientToolConfig, Speechify, ToolParam - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.create( - name="navigate_to", - description="Scroll the page to a named section.", - kind="client", - config=ClientToolConfig( - timeout_ms=4000, - params=[ - ToolParam( - name="section", - type="string", - description="Section name", - required=True, - enum=["pricing", "docs", "contact"], - ) - ], - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**description:** `str` - -
-
- -
-
- -**kind:** `ToolKind` - -
-
- -
-
- -**config:** `CreateToolRequestConfig` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a tool by ID. Webhook secrets are always masked here. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a tool. Agents that had it attached get a soft-detach. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a tool. Tool kind is immutable — create a new tool to change it. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.update( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**config:** `typing.Optional[UpdateToolRequestConfig]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.list_attached_agents(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List the agents in the caller's workspace that currently have -this tool attached. Useful before deleting a tool, to surface -which agents will lose access. Soft-deleted agents are filtered -out. Bounded by the number of agents per workspace (tens), so -the response is not paginated. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.list_attached_agents( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.rotate_secret(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Rotate the HMAC signing secret on a webhook tool. The tool id -is preserved so attached agents keep working; only the secret -rolls. The new plaintext is returned on `webhook_secret` -exactly once — store it immediately, subsequent reads always -return the masked placeholder. The previous secret is -invalidated immediately on success. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.rotate_secret( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.list_system_builtins() -
-
- -#### 📝 Description - -
-
- -
-
- -Read-only catalogue of every system builtin the worker knows -about. The console fetches this at runtime rather than -maintaining a parallel client-side list; the server -is the single source of truth for the label and description -copy a customer sees in the builtin-instance picker. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.list_system_builtins() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.test_mcp_connection(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Probe a customer-supplied MCP server config without persisting -anything. The server opens the configured transport, runs the -`initialize` + `list_tools` handshake, and returns either the -discovered tool catalogue or a structured error string. Pass -`tool_id` from the edit-form flow when the auth payload carries -`_set` markers but no plaintext, so the server can hydrate the -stored secret from the encrypted column before probing. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import McpAuth_None, McpToolConfig, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.test_mcp_connection( - config=McpToolConfig( - endpoint="endpoint", - auth=McpAuth_None(), - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**config:** `McpToolConfig` - -
-
- -
-
- -**tool_id:** `typing.Optional[str]` - -Optional `tool_` id of the existing tool to hydrate -stored secrets from. Raw UUIDs and other-resource prefixes are -rejected. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tools.test_webhook_connection(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Probe a customer-supplied webhook tool config without persisting -anything. The server fires the exact request shape the worker -sends on a real invocation — same JSON body, same HMAC-SHA256 -signature — with an empty argument set, and reports the -endpoint's status code, latency, and a truncated response body, -or a transport-level failure reason. The probe carries an -`X-Speechify-Webhook-Test: true` header so a careful endpoint -can recognise the test and skip its real side effect. Pass -`tool_id` from the edit-form flow so the server signs the probe -with the tool's stored HMAC secret. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify, WebhookToolConfig - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tools.test_webhook_connection( - config=WebhookToolConfig( - url="url", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**config:** `WebhookToolConfig` - -
-
- -
-
- -**tool_id:** `typing.Optional[str]` - -Optional `tool_` id of the existing tool to sign -the probe with. Raw UUIDs and other-resource prefixes are -rejected. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent AudioAssets -
client.agent.audio_assets.list() -
-
- -#### 📝 Description - -
-
- -
-
- -List every non-deleted audio asset in the caller's workspace. -Audio assets are pre-recorded WAV clips (intro jingles, legal -disclaimers, hold cues) referenced from `play_audio` flow nodes -and the corresponding system builtin. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.audio_assets.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.audio_assets.upload(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Upload a new audio asset. The body is a multipart/form-data -request with a single `file` field carrying the WAV bytes. - -The WAV is validated server-side against a strict format -contract — PCM 16-bit signed, mono, 48000 Hz, ≤30s, ≤4 MiB — -before any bytes hit storage. The strict shape matches the -LiveKit room sample rate so the worker reads bytes straight -into `rtc.AudioFrame` with no decode dependency on either side; -convert MP3 sources with `ffmpeg -i in.mp3 -ar 48000 -ac 1 --sample_fmt s16 out.wav`. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.audio_assets.upload() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**file:** `from __future__ import annotations - -core.File` — See core.File for more documentation - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.audio_assets.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Fetch one audio asset's metadata. Returns 404 for missing, -soft-deleted, or foreign-tenant assets — existence information -is never leaked across tenants. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.audio_assets.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Audio asset ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.audio_assets.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-delete an audio asset. The underlying GCS object is -retained so any flow node or tool still referencing the asset -keeps working until the config is updated; the worker logs -and skips on missing-row at session start (fail-soft). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.audio_assets.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Audio asset ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.audio_assets.get_bytes(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Stream the raw WAV bytes for an audio asset. Byte-stream -sibling of the metadata endpoint at /v1/agents/audio-assets/{id}. -The LiveKit worker fetches through here for the play_audio -builtin; SDK consumers can also download originals. Returns 404 -for missing / soft-deleted / foreign-tenant assets. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.audio_assets.get_bytes( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Audio asset ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response. - -
-
-
-
- - -
-
-
- -## Agent IvrMemory -
client.agent.ivr_memory.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List the active IVR menus the caller's workspace has learned. -One row per (fingerprint, tenant). -Invalidated rows and the cross-tenant shared slot are excluded. -Sorted by `last_observed_at` DESC so the freshest IVRs land at -the top. Capped at 200 rows. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.ivr_memory.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**fingerprint:** `typing.Optional[str]` — Optional SHA-256 fingerprint hash to narrow the list to one menu. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.ivr_memory.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Fetch one menu's full shape. Returns 404 for missing, -soft-deleted, or foreign-tenant menus — existence information -is never leaked across tenants. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.ivr_memory.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — IVR menu ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.ivr_memory.update_label(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Re-label one option in the stored menu_tree, matched on the -supplied DTMF value. The label is what the console displays in -the detail panel and what the worker reads back at navigate -time to surface the option semantically. Unknown DTMF values -are a no-op (the response echoes the unchanged menu). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.ivr_memory.update_label( - id="id", - dtmf="dtmf", - label="label", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — IVR menu ID. - -
-
- -
-
- -**dtmf:** `str` — DTMF value of the option to relabel (e.g. "1", "*", "#"). - -
-
- -
-
- -**label:** `str` — New label. Capped at 256 chars server-side. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.ivr_memory.invalidate(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-invalidate the named menu. Future lookups skip it; the -next discovery for the same fingerprint replaces it (clearing -the invalidation). Idempotent: re-invalidating -an already-invalidated row returns 404. - -Reason is optional and is captured in structured logs for -operator triage. A future audit table may persist it. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.ivr_memory.invalidate( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — IVR menu ID. - -
-
- -
-
- -**reason:** `typing.Optional[str]` — Operator-debug cause string. Bounded to 256 chars. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Callers -
client.agent.callers.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List the workspace's callers, ordered by most-recently-seen first. -A caller is the per-(tenant, agent, identity) entity that owns -long-term memories and conversation history. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.callers.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Narrow the list to callers attached to one agent. - -
-
- -
-
- -**q:** `typing.Optional[str]` - -Identity-prefix search. Filters to rows where `identity LIKE q + '%'` -(`%`/`_` characters in the input are escaped as literals). - -
-
- -
-
- -**last_seen_after:** `typing.Optional[dt.datetime]` - -RFC 3339 timestamp. Narrows to callers active strictly AFTER the -supplied moment. Useful for "active this week / month" filters. - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.callers.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Fetch a single caller by id. Returns 404 for soft-deleted or -foreign-tenant rows — GDPR-purged callers appear as "not found" -to the API. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.callers.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Caller ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.callers.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-delete the caller AND cascade soft-delete every memory row -pointing at it. Conversations survive (forensic / billing records) -but their caller pointer surfaces as "deleted" through the API. - -Idempotent — re-deleting an already-purged caller returns -`{caller_purged: 0, memories_purged: 0}`. Audit row counts -accompany every response so a privacy operator has direct -evidence of the purge without re-querying. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.callers.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Caller ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.callers.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update the customer-editable fields on a caller. PATCH semantics: -omitted fields are unchanged, present fields overwrite. To clear -a nullable field (`display_name`, `external_ref`) pass an empty -string. `metadata` REPLACES the existing JSONB blob when supplied. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.callers.update( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Caller ID. - -
-
- -
-
- -**display_name:** `typing.Optional[str]` — Operator-editable display name. Empty string clears the column. - -
-
- -
-
- -**external_ref:** `typing.Optional[str]` — Optional handle into the customer's own CRM. Empty string clears the column. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Replacement metadata JSONB. Must not be `null`. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.callers.list_memories(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List one page of memories belonging to the caller, newest first. -Soft-deleted memories AND memories whose parent caller is -soft-deleted are hidden — the GDPR purge semantics require the -API to behave as if those rows do not exist. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.callers.list_memories( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Caller ID. - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.callers.list_conversations(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List one page of conversations belonging to the caller, newest -started first. Same wire envelope as the workspace-wide -`GET /v1/agents/conversations`, narrowed to one caller. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.callers.list_conversations( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Caller ID. - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Conversations -
client.agent.conversations.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List conversations owned by the caller, ordered by most recent. -Cursor-paginated: omit `cursor` to fetch the first page; pass the -previous response's `next_cursor` back to fetch the next page. -Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.conversations.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max conversations per page (default 50, max 200). - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Filter to conversations for this agent. - -
-
- -
-
- -**status:** `typing.Optional[ConversationStatus]` — Filter by conversation status. - -
-
- -
-
- -**transport:** `typing.Optional[ConversationTransport]` — Filter by transport. - -
-
- -
-
- -**caller_identity:** `typing.Optional[str]` — Filter by caller identity. - -
-
- -
-
- -**search:** `typing.Optional[str]` — Free-text search across conversation content. - -
-
- -
-
- -**started_after:** `typing.Optional[dt.datetime]` — Only conversations started at or after this RFC 3339 timestamp. - -
-
- -
-
- -**started_before:** `typing.Optional[dt.datetime]` — Only conversations started at or before this RFC 3339 timestamp. - -
-
- -
-
- -**duration_min_ms:** `typing.Optional[int]` — Minimum conversation duration in milliseconds. - -
-
- -
-
- -**duration_max_ms:** `typing.Optional[int]` — Maximum conversation duration in milliseconds. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.stats(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Aggregated counts and averages over the caller's conversations, scoped by the same filters as the list endpoint. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.conversations.stats() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Filter to conversations for this agent. - -
-
- -
-
- -**status:** `typing.Optional[ConversationStatus]` — Filter by conversation status. - -
-
- -
-
- -**transport:** `typing.Optional[ConversationTransport]` — Filter by transport. - -
-
- -
-
- -**caller_identity:** `typing.Optional[str]` — Filter by caller identity. - -
-
- -
-
- -**search:** `typing.Optional[str]` — Free-text search across conversation content. - -
-
- -
-
- -**started_after:** `typing.Optional[dt.datetime]` — Only conversations started at or after this RFC 3339 timestamp. - -
-
- -
-
- -**started_before:** `typing.Optional[dt.datetime]` — Only conversations started at or before this RFC 3339 timestamp. - -
-
- -
-
- -**duration_min_ms:** `typing.Optional[int]` — Minimum conversation duration in milliseconds. - -
-
- -
-
- -**duration_max_ms:** `typing.Optional[int]` — Maximum conversation duration in milliseconds. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.recent_callees(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Distinct phone numbers the caller's workspace has dialled on -outbound calls, ordered by most recent. Feeds the batch-calls -composer's "Suggested from history" surface. Cursor-paginated: -omit `cursor` to fetch the first page. Default page size is 50 -and max is 200. Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.conversations.recent_callees() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max number of distinct phone numbers per page. Defaults to 50; clamped to 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a conversation by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.conversations.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.list_messages(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve the transcript for a conversation in started_at order -(oldest first). Cursor-paginated: omit `cursor` to fetch the -first page. Default page size is 50 and max is 200. Walk pages -while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.conversations.list_messages( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max messages per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.list_evaluations(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve post-call evaluation results for a conversation. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.conversations.list_evaluations( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.stream_recording(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Proxy the GCS-stored audio recording for a conversation through -the Cloud Run service identity. Returns OGG/Opus bytes (LiveKit -room-composite egress default). The response is streamed so a -long recording does not buffer in memory; `
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.conversations.stream_recording( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.list_webhook_deliveries(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List post-call webhook delivery attempts for a conversation, -newest first. Rows appear once the LiveKit `room_finished` -webhook has fired and the post-call webhook has been -dispatched to the agent's configured URL. One row per -`(conversation, webhook-url)`, updated in place across retries. -Cursor-paginated: omit `cursor` to fetch the first page. -Default page size is 50 and max is 200. Walk pages while -`has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.conversations.list_webhook_deliveries( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max deliveries per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.list_retrieval_log(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Per-conversation retrieval log, newest first — one row per -`search_knowledge` invocation made during the call. Each entry -records the query, ranked chunks (denormalised so deletions -don't render history unreadable), `top_k`, and hit count. -Powers the Retrieval panel on the conversation detail view. -Cursor-paginated: omit `cursor` to fetch the first page. -Default page size is 50 and max is 200. Walk pages while -`has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.conversations.list_retrieval_log( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max retrieval log entries per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.conversations.list_memories(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List memories extracted from a specific conversation. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.conversations.list_memories( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Admin -
client.agent.admin.shadow_token(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Mint a listen-only LiveKit access token so an authorized observer -can join an ongoing voice-agent conversation as a hidden -participant. Caller must be an `owner` or `admin` of the -workspace the conversation belongs to. The token cannot publish -audio or data; the observer is invisible to the caller and the -agent. Speechify support engineers reach this endpoint the same -way as any other observer — by being granted the owner/admin -role on the customer's workspace (typically under an NDA-backed -support arrangement). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.admin.shadow_token( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.admin.force_end(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Force-terminate the LiveKit room for an ongoing conversation. -Idempotent: rooms that LiveKit has already cleaned up return -204 the same as a successful first-time termination. Same -owner/admin role gating as the shadow-token endpoint. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.admin.force_end( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent KnowledgeBases -
client.agent.knowledge_bases.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List knowledge bases owned by the caller. Cursor-paginated: -omit `cursor` to fetch the first page. The default page size is -50 and the max is 200; values outside that range are clamped. -Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.knowledge_bases.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max knowledge bases per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new knowledge base. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create( - name="name", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` — Human-readable label. - -
-
- -
-
- -**description:** `typing.Optional[str]` — Optional description. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a knowledge base by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-delete a knowledge base. Documents and chunks are cascaded. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a knowledge base. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.update( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.list_documents(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List documents ingested into a knowledge base. Cursor-paginated: -omit `cursor` to fetch the first page. Default page size is 50 -and max is 200. Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.knowledge_bases.list_documents( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder filter: omit for root-level documents, pass `all` for -every document in the KB, or a folder id to scope to that -folder. - -
-
- -
-
- -**q:** `typing.Optional[str]` — Substring match on filename and source_url. - -
-
- -
-
- -**source_kind:** `typing.Optional[str]` — Comma-separated source kinds (file|url|text). - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max documents per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.upload_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Upload a document (PDF, plain text, markdown, or HTML) to a -knowledge base. The document is extracted, chunked, embedded, and -indexed synchronously; expect a few seconds per MB of input. -Maximum 10 MB per upload. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.upload_document( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**file:** `from __future__ import annotations - -core.File` — See core.File for more documentation - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.get_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a document by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.get_document( - id="id", - doc_id="docId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.delete_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a document and all its chunks. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.delete_document( - id="id", - doc_id="docId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.update_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a document. Currently supports moving the document -between folders via `folder_id`. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.update_document( - id="id", - doc_id="docId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Destination folder. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null moves the -document to the knowledge base root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.list_chunks(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List the chunks for a document. Cursor-paginated: omit `cursor` -to fetch the first page. Default page size is 50 and max is 200. -Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.knowledge_bases.list_chunks( - id="id", - doc_id="docId", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max chunks per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_text_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a document from inline pasted text. Content is chunked, -embedded, and indexed synchronously. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_text_document( - id="id", - name="name", - content="content", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**content:** `str` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder to drop the document into. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted = root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_url_document(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Fetch a URL via Firecrawl and ingest the rendered content as a -document. The fetch happens synchronously; expect a few -seconds per page. Use the sitemap / crawl endpoints for -multi-page imports. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_url_document( - id="id", - url="url", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**url:** `str` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder to drop the document into. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted = root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_sitemap_import(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Kick off an async sitemap import. Returns 202 with the import -job row; client polls `GET /{id}/imports` for progress. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_sitemap_import( - id="id", - url="url", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**url:** `str` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder to import the documents into. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted = root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_crawl_import(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Kick off an async website crawl. Returns 202 with the import -job row; client polls `GET /{id}/imports` for progress. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_crawl_import( - id="id", - url="url", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**url:** `str` - -
-
- -
-
- -**max_pages:** `typing.Optional[int]` - -
-
- -
-
- -**max_depth:** `typing.Optional[int]` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder to import the documents into. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted = root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_url_batch_import(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Kick off an async multi-URL import. Accepts 1..N URLs in a -single job (capped per-deployment, default 50) and runs the -same per-URL pipeline as the sitemap worker. Returns 202 with -the import job row; client polls `GET /{id}/imports` for -progress. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_url_batch_import( - id="id", - urls=["urls"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**urls:** `typing.Sequence[str]` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Folder to import the documents into. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted = root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.list_import_jobs(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List import jobs (sitemap / crawl / refresh) for a knowledge base. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.list_import_jobs( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.cancel_import_job(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Cancel a non-terminal import job. Idempotent on terminal jobs -(completed / failed / cancelled) — the cancel call returns the -unchanged row. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.cancel_import_job( - id="id", - import_id="importId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**import_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.batch_delete_documents(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete multiple documents in a single transaction. All ids -must belong to the supplied knowledge base; mismatches fail -the request with 400 before any rows are touched. Capped at -200 ids per call. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.batch_delete_documents( - id="id", - ids=["ids"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**ids:** `typing.Sequence[str]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.batch_move_documents(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Move multiple documents into a folder in a single transaction. -Pass `folder_id: null` to move every doc to root. Capped at -200 ids per call. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.batch_move_documents( - id="id", - ids=["ids"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**ids:** `typing.Sequence[str]` - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Destination folder. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null moves every -document to the knowledge base root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.update_refresh_config(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update the per-document auto-refresh state. Only meaningful -for url-sourced documents; file and text rows reject the -request. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.update_refresh_config( - id="id", - doc_id="docId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**enabled:** `typing.Optional[bool]` - -
-
- -
-
- -**interval_days:** `typing.Optional[int]` - -
-
- -
-
- -**auto_remove_enabled:** `typing.Optional[bool]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.list_refresh_history(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List recent auto-refresh attempts for a document. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.list_refresh_history( - id="id", - doc_id="docId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**doc_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.list_folders(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List folders inside a knowledge base. Root-level folders have -`parent_folder_id: null`. Cursor-paginated: omit `cursor` to -fetch the first page. Default page size is 50 and max is 200. -The console builds the folder tree from `parent_folder_id`, so -consumers should walk every page until `has_more` is `false` -before rendering the tree. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.knowledge_bases.list_folders( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max folders per page (default 50, max 200). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.create_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a folder inside a knowledge base. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.create_folder( - id="id", - name="name", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**parent_folder_id:** `typing.Optional[str]` - -Parent folder. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`); null/omitted creates a -root-level folder. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.delete_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a folder. Documents inside the folder are moved to root -(not deleted). Sub-folders are detached likewise. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.delete_folder( - id="id", - folder_id="folderId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**folder_id:** `str` - -
-
- -
-
- -**force:** `typing.Optional[bool]` — When true, delete the folder even if it still contains documents or sub-folders; contents are moved to root. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.update_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a folder. Pass `parent_folder_id: null` to move to -root; omit the field to leave it unchanged. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.update_folder( - id="id", - folder_id="folderId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**folder_id:** `str` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**parent_folder_id:** `typing.Optional[str]` - -Folder to reparent under. Prefixed wire identifier -(`kfolder_<26 char Crockford base32>`). - -
-
- -
-
- -**clear_parent_folder_id:** `typing.Optional[bool]` - -When `true`, moves the folder to root (clears -`parent_folder_id`). Wins over `parent_folder_id` when both -are sent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.knowledge_bases.search(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Semantic search across a caller-owned list of knowledge bases. -Returns ranked chunks with source filename and a cosine-similarity -score. Limited to 50 results per request. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.knowledge_bases.search( - query="query", - kb_ids=["kb_ids"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**query:** `str` — Natural-language search query. - -
-
- -
-
- -**kb_ids:** `typing.Sequence[str]` — Knowledge bases to search across. Results scoped to caller-owned entries; unknown IDs are silently ignored. - -
-
- -
-
- -**top_k:** `typing.Optional[int]` — Max hits to return (default 5, capped at 50). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Memories -
client.agent.memories.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-delete one memory row. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.memories.delete( - memory_id="memoryId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**memory_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Tests -
client.agent.tests.get_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a test by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.get_test( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.delete_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a test and all its run history. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.delete_test( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.update_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a test. Only fields present on the request body are changed. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.update_test( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test ID. - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**config:** `typing.Optional[UpdateAgentTestRequestConfig]` — Replaces the test config when present. - -
-
- -
-
- -**tool_mock_config:** `typing.Optional[ToolMockConfig]` — Replaces the tool-mock config when present. - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` - -Prefixed wire identifier (`folder_<26 char Crockford base32>`) -of the folder to move the test into. - -
-
- -
-
- -**clear_folder_id:** `typing.Optional[bool]` - -When `true`, moves the test back to root (clears -`folder_id`). Wins over `folder_id` when both are sent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.list_test_runs(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List one page of run history for a test, newest first. -Paginate by passing `cursor` from the previous response. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.tests.list_test_runs( - id="id", -) -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test ID. - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.run_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Enqueue a single run of the test. The returned run starts in -`queued` status. Poll `GET /v1/agents/tests/runs/{id}` until the status -reaches a terminal state (`passed`, `failed`, or `error`). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.run_test( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test ID. - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Run the test against this agent instead of the test's default agent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.get_test_run(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a single test run by ID. Poll this endpoint until -`status` reaches a terminal state (`passed`, `failed`, or `error`). -The `result` field is populated on terminal states. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.get_test_run( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Test run ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.list_suite_runs(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List one page of suite runs (test invocations), newest first. -A suite run groups every test run dispatched by one Run All, -batch, or resubmit call. Paginate by passing `cursor` from the -previous response. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.tests.list_suite_runs() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Narrow the list to the suite runs of one agent. - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.get_suite_run(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a suite run by ID with its child runs and the derived -aggregate status and pass/fail/error counts. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.get_suite_run( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Suite run ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.resubmit_suite_run(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Re-run the failed and errored tests of a suite run as a fresh -suite run, linked back to the original via -`parent_suite_run_id`. Returns 400 when the suite run has no -failed or errored tests to re-run. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.resubmit_suite_run( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Suite run ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.list_all_tests(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Workspace-wide list of tests across every agent the caller owns. -Supports filters (agent, type, last-run status, folder), full-text -search on name/description, and cursor pagination. Each row carries -its newest run and attached agent IDs so the list renders without -N+1 round-trips. Walk pages while `has_more` is true. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.tests.list_all_tests() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` — Comma-separated agent IDs to filter on. - -
-
- -
-
- -**type:** `typing.Optional[str]` — Comma-separated test types (reply|tool|simulation). - -
-
- -
-
- -**status:** `typing.Optional[str]` — Comma-separated last-run statuses. - -
-
- -
-
- -**folder_id:** `typing.Optional[str]` — Folder ID to filter on, or "root" for unfiled tests. - -
-
- -
-
- -**updated_after:** `typing.Optional[str]` — Only return tests updated after this RFC3339 timestamp. - -
-
- -
-
- -**q:** `typing.Optional[str]` — Substring match on name or description. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max tests per page (default 50, max 200). - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque pagination cursor from a previous response. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.get_test_stats(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Aggregate pass-rate metrics over the last N days. Returns dense -daily buckets (one entry per day, zero-filled) plus totals and a -per-type breakdown. Powers the header chart on the global tests -page. Default window is 30 days, max 90. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.get_test_stats() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**window_days:** `typing.Optional[int]` — Trailing window in days (default 30, max 90). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.run_tests_batch(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Queue runs for every (test, agent) pair in the body. Entries -without an `agent_id` fan out to every agent the test is -attached to. Total expanded runs are capped at 100 per call. -Each entry in the response is a queued run; poll -`GET /v1/agents/tests/runs/{id}` for each. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import BatchRunEntry, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.run_tests_batch( - entries=[ - BatchRunEntry( - test_id="test_01ky612y9cb7dbaj638x46msxv", - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**entries:** `typing.Sequence[BatchRunEntry]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.list_test_attachments(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List every agent a test is attached to. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.list_test_attachments( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.attach_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Attach a test to an additional agent. After this call, the test -will also run as part of that agent's regression suite (and -against its prompt + tool config when invoked with -`agent_id = {agentId}`). Idempotent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.attach_test( - id="id", - agent_id="agentId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**agent_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.detach_test(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Detach a test from an agent. The owner agent (the agent the test -was authored against) cannot be detached; delete the test -instead. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.detach_test( - id="id", - agent_id="agentId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**agent_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.list_test_folders() -
-
- -#### 📝 Description - -
-
- -
-
- -List every test folder the caller owns. Flat list; build the tree client-side. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.list_test_folders() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.create_test_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a test folder. Max depth is 3. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.create_test_folder( - name="name", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**parent_folder_id:** `typing.Optional[str]` - -Prefixed wire identifier (`folder_<26 char Crockford base32>`) -of the parent folder. Omit / null for a root-level folder. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.delete_test_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Soft-delete a folder. Child tests drop back to root. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.delete_test_folder( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.tests.update_test_folder(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Rename or reparent a test folder. Cycles are rejected. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.tests.update_test_folder( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**parent_folder_id:** `typing.Optional[str]` - -Prefixed wire identifier (`folder_<26 char Crockford base32>`) -of the folder to reparent this folder under. - -
-
- -
-
- -**clear_parent_folder_id:** `typing.Optional[bool]` - -When `true`, reparents this folder to root (clears -`parent_folder_id`). Wins over `parent_folder_id` when -both are sent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent PhoneNumbers -
client.agent.phone_numbers.list() -
-
- -#### 📝 Description - -
-
- -
-
- -List all phone numbers in the caller's workspace. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.import_(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Import a phone number into the workspace. The `source` field -determines the provisioning path: - -- `livekit` - LiveKit purchases the number on your behalf. US - inbound only. Quickest path for local testing. -- `twilio` - Provide your Twilio Account SID, Auth Token, and - the E.164 number you already own. We provision an Elastic SIP - Trunk on your Twilio account automatically. -- `byoc` - Provide an existing SIP trunk ID. The number is - registered against that trunk. - -Returns 402 when the workspace has reached the 100-number cap. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify, TwilioImportSpec - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.import_( - e164="+12025551234", - source="twilio", - label="Support line", - agent_id="agent_01HS...", - twilio=TwilioImportSpec( - account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - auth_token="your_twilio_auth_token", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**e164:** `str` - -The phone number in E.164 format. For `source=livekit` this -is the number you want LiveKit to purchase. For `source=twilio` -and `source=byoc` it is the number you already own. - -
-
- -
-
- -**source:** `PhoneNumberSource` - -
-
- -
-
- -**label:** `typing.Optional[str]` — Optional human-readable label. - -
-
- -
-
- -**trunk_id:** `typing.Optional[str]` - -For `source=byoc`: the SIP trunk to bind this number to. -Prefixed wire identifier (`trunk_<26 char Crockford base32>`). -Not required for `source=livekit` or `source=twilio`. - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` - -Optional agent to bind on import. Prefixed wire identifier -(`agent_<26 char Crockford base32>`). - -
-
- -
-
- -**twilio:** `typing.Optional[TwilioImportSpec]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.search_available(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Search carrier inventory for phone numbers available to purchase. -Currently restricted to the US (`country=US`); pass `area_code` -to narrow to a specific NPA. The returned numbers are not held; -a subsequent `POST /v1/agents/phone-numbers/purchase` against the same -E.164 may fail with 4xx if the number has been taken in the -meantime. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.search_available() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**country:** `typing.Optional[str]` — ISO-3166 alpha-2 country code. Defaults to "US"; only "US" is supported in v1. - -
-
- -
-
- -**area_code:** `typing.Optional[str]` — Three-digit NPA to filter inventory to a region. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Max results to return. Capped at 50. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.purchase(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Purchase a phone number on Speechify's master Twilio account. -The number is billed to Speechify until released. A plan that -includes no purchased numbers (e.g. Free) returns 402; a plan -that has used its full included quota returns 422. This is -independent of the overall 100-number cap. -`e164` must come from a recent `SearchAvailablePhoneNumbers` -response — carriers reject buys against numbers that are no -longer in inventory. The returned phone number is wired for -both inbound (when `agent_id` is set, or after a later -`PATCH`) and outbound calls (via the workspace's shared -outbound trunk). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.purchase( - e164="+14155552671", - label="Sales line", - agent_id="agent_01HS...", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**e164:** `str` — The E.164 number to buy. Must currently be in carrier inventory. - -
-
- -
-
- -**label:** `typing.Optional[str]` — Optional human-readable label. - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` - -Optional agent to bind the number to at purchase time. -Prefixed wire identifier (`agent_<26 char Crockford base32>`). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a phone number by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a phone number from the workspace. For Twilio and LiveKit -numbers this also deprovisions the backing SIP trunk and dispatch -rule on LiveKit Cloud. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.phone_numbers.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a phone number. Only `label` and `agent_id` are mutable; -`source` and `e164` are immutable after import. Pass `null` for -`agent_id` to unbind the number from its current agent. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.phone_numbers.update( - id="id", - label="After-hours line", - agent_id="agent_01HS4X9VBCDEF1234567890AB", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**label:** `typing.Optional[str]` — New label. Pass an empty string to clear. - -
-
- -
-
- -**agent_id:** `typing.Optional[str]` - -Agent to bind the number to. Prefixed wire identifier -(`agent_<26 char Crockford base32>`). - -
-
- -
-
- -**clear_agent_id:** `typing.Optional[bool]` - -When `true`, unbinds the current agent (clears `agent_id`). -Wins over `agent_id` when both are sent. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent SipTrunks -
client.agent.sip_trunks.list() -
-
- -#### 📝 Description - -
-
- -
-
- -List all SIP trunks in the caller's workspace. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.sip_trunks.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.sip_trunks.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a SIP trunk. For `kind=byoc` supply `sip_address` plus -optional digest credentials and IP allowlist. For `kind=twilio` -use `ImportPhoneNumber` with a `twilio` spec instead - trunk -creation is handled automatically. Returns 402 when the workspace -has reached the 20-trunk cap. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.sip_trunks.create( - name="Telnyx BYOC", - kind="byoc", - direction="both", - sip_address="sip.telnyx.com", - auth_username="myuser", - auth_password="mypassword", - transport="auto", - media_encryption="allow", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` — Human-readable name for the trunk. - -
-
- -
-
- -**kind:** `SipTrunkKind` - -
-
- -
-
- -**direction:** `SipTrunkDirection` - -
-
- -
-
- -**sip_address:** `typing.Optional[str]` — SIP endpoint hostname. Required for `kind=byoc`. - -
-
- -
-
- -**auth_username:** `typing.Optional[str]` — SIP digest auth username. - -
-
- -
-
- -**auth_password:** `typing.Optional[str]` — SIP digest auth password. Write-only. - -
-
- -
-
- -**allowed_addresses:** `typing.Optional[typing.Sequence[str]]` — IP / CIDR allowlist for inbound connections. Empty means any source is accepted. - -
-
- -
-
- -**destination_country:** `typing.Optional[str]` — ISO 3166-1 alpha-2 country for the outbound dial plan. - -
-
- -
-
- -**transport:** `typing.Optional[SipTransport]` - -
-
- -
-
- -**media_encryption:** `typing.Optional[SipMediaEncryption]` - -
-
- -
-
- -**credentials:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` — Provider-specific credential blob (for future extensibility). - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.sip_trunks.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a SIP trunk by ID. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.sip_trunks.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.sip_trunks.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a SIP trunk. This also removes the backing LiveKit inbound -trunk, outbound trunk, and dispatch rule if they were provisioned -by us. Phone numbers attached to this trunk are left in place but -become non-functional until rebound to a new trunk. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.sip_trunks.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent OutboundCalls -
client.agent.outbound_calls.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Place an outbound call from an agent to a phone number. LiveKit -originates the SIP INVITE through the outbound trunk bound to the -agent's workspace; the agent worker is dispatched into the room -automatically. - -The response is returned as soon as LiveKit accepts the INVITE. -Poll `GET /v1/agents/conversations/{conversation_id}` for status -transitions: `pending` → `active` (answered) → `completed`. - -Requires a Twilio or BYOC trunk. LiveKit-native numbers are -inbound-only. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.outbound_calls.create( - agent_id="agent_01HS...", - to="+41791234567", - dynamic_variables={ - "customer_name": '"Alice"', - "order_id": '"ORD-8821"', - "outstanding_balance": "142.50", - }, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**agent_id:** `str` — ID of the agent that handles the answered call. - -
-
- -
-
- -**to:** `str` — Destination phone number in E.164 format (e.g. `+12025559876`). - -
-
- -
-
- -**caller_id_number:** `typing.Optional[str]` - -The number shown to the callee as caller ID, in E.164 format. -Defaults to the first outbound-capable number in the workspace. -Useful for multi-number campaigns where you want to rotate -caller IDs. - -
-
- -
-
- -**dtmf_prefix:** `typing.Optional[str]` - -DTMF digits dialed automatically after the call is answered, -before the agent begins speaking. Use this for IVR navigation -(e.g. `1ww2` presses 1, waits two seconds, presses 2). `w` -is a half-second pause; `W` is a one-second pause. - -
-
- -
-
- -**dynamic_variables:** `typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]` - -Per-call variable overrides merged on top of the agent's stored -defaults. Keys must not use the reserved `system__` prefix. -Useful for injecting per-call context (customer name, order ID) -into the agent prompt. - -
-
- -
-
- -**ringing_timeout_ms:** `typing.Optional[int]` - -How long to wait for the callee to answer before abandoning, -in milliseconds. Defaults to 30000 (30s). Capped at 80000 (80s). - -
-
- -
-
- -**amd:** `typing.Optional[AmdConfig]` - -Optional per-call override for the AMD routing config. When -set, wholesale-replaces the agent's stored AMD shape for -this single call (PATCH-replace, not merge). Unlocks the -batch-campaign pattern: one agent dialling many recipients -with per-row tailored voicemail messages via the existing -dynamic_variables substitution. Validation rules match -the agent-update boundary. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent BatchCalls -
client.agent.batch_calls.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns one page of batch calls for the workspace, newest first. -Paginate by passing `cursor` from the previous response. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -response = client.agent.batch_calls.list() -for item in response: - yield item -# alternatively, you can paginate page-by-page -for page in response.iter_pages(): - yield page - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**cursor:** `typing.Optional[str]` — Opaque cursor from a prior response's `next_cursor`. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Page size. Defaults to 50; capped at 200. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.batch_calls.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Dial a list of phone numbers through one of your voice agents in a -single request. Each recipient can receive personalised dynamic -variables that your agent prompt references via `{{key}}` placeholders. -Batches can run immediately or be scheduled up to 30 days in advance. - -Accepts `application/json` or `multipart/form-data` (with a CSV file). -Max 1000 recipients per batch. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -import datetime - -from speechify import BatchRecipientRequest, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.batch_calls.create( - name="Monday morning follow-ups", - agent_id="agent_01HS...", - scheduled_at=datetime.datetime.fromisoformat( - "2025-05-05 09:00:00+00:00", - ), - recipients=[ - BatchRecipientRequest( - phone="+14155551234", - dynamic_vars={"first_name": "Alice"}, - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` — Human-readable batch name. - -
-
- -
-
- -**agent_id:** `str` — Agent that handles each call. - -
-
- -
-
- -**recipients:** `typing.Sequence[BatchRecipientRequest]` - -
-
- -
-
- -**phone_number_id:** `typing.Optional[str]` — Caller-ID override. Falls back to the agent's bound number. - -
-
- -
-
- -**scheduled_at:** `typing.Optional[dt.datetime]` — Schedule the batch for a future time (RFC 3339). Omit to start immediately. - -
-
- -
-
- -**ringing_timeout_ms:** `typing.Optional[int]` - -Ringing timeout in milliseconds applied to every call in the -batch (how long each recipient rings before the dial gives -up). Range 1000-80000 (1-80s). Omit to use the 30s default. -The console collects this in seconds and converts to -milliseconds. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.batch_calls.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Returns the batch row plus all recipients so the detail view renders -without a second round-trip. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.batch_calls.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Batch call ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.batch_calls.cancel(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Cancels a scheduled or pending batch before it starts dialing. -Returns 409 if the batch is already running or completed. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.batch_calls.cancel( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Batch call ID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Agent Flow -
client.agent.flow.get_flow(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Return the agent's flow graph: the current draft (if any), the -active published graph (if any), and the version history. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.get_flow( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.update_flow(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Replace the agent's draft flow graph. The graph is validated -before it is stored; publish it separately to make it active. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.update_flow( - id="agent_01k7m6etzwf057j6w0zmdsgppr", - nodes=[{"key": "value"}], - edges=[{"key": "value"}], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**nodes:** `typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]` - -
-
- -
-
- -**edges:** `typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**notes:** `typing.Optional[str]` - -
-
- -
-
- -**variables:** `typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]]` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.discard_draft(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Discard the agent's unpublished draft flow graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.discard_draft( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.publish(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Publish the agent's draft graph as a new active flow version. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.publish( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**notes:** `typing.Optional[str]` — Optional changelog note recorded on the published version. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.rollback(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Publish a prior flow version as the active graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.rollback( - id="agent_01k7m6etzwf057j6w0zmdsgppr", - version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**version_id:** `str` — The flow version to roll back to. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.deactivate(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Deactivate the agent's published flow so the agent runs the synthesized default flow. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.deactivate( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.list_versions(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List every published flow version for the agent, newest first. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.list_versions( - id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.get_version(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Return the full flow graph for a specific published version. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.get_version( - id="agent_01k7m6etzwf057j6w0zmdsgppr", - version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Prefixed agent id. - -
-
- -
-
- -**version_id:** `str` — Flow version UUID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.get_schema() -
-
- -#### 📝 Description - -
-
- -
-
- -Return the JSON Schema describing the flow graph node taxonomy. -Unauthenticated; flow editors fetch it to validate graphs client-side. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.get_schema() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.list_templates() -
-
- -#### 📝 Description - -
-
- -
-
- -List the reusable flow templates available to the workspace. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.list_templates() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.create_template(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a reusable flow template from a graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import FlowGraphInput, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.create_template( - key="key", - name="name", - graph=FlowGraphInput( - nodes=[{"key": "value"}], - edges=[{"key": "value"}], - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**key:** `str` - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**graph:** `FlowGraphInput` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**category:** `typing.Optional[str]` — Defaults to "custom" when omitted. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.get_template(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Retrieve a flow template by id. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.get_template( - id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Flow template UUID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.delete_template(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a flow template. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.delete_template( - id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Flow template UUID. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.update_template(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Replace a flow template. The whole template is replaced, not patched field-by-field. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import FlowGraphInput, Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.update_template( - id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d", - key="key", - name="name", - graph=FlowGraphInput( - nodes=[{"key": "value"}], - edges=[{"key": "value"}], - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Flow template UUID. - -
-
- -
-
- -**key:** `str` - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**graph:** `FlowGraphInput` - -
-
- -
-
- -**description:** `typing.Optional[str]` - -
-
- -
-
- -**category:** `typing.Optional[str]` — Defaults to "custom" when omitted. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.agent.flow.clone_template(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Clone a flow template onto an agent as a new draft graph. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from speechify import Speechify - -client = Speechify( - token="YOUR_TOKEN", -) -client.agent.flow.clone_template( - id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d", - agent_id="agent_01k7m6etzwf057j6w0zmdsgppr", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — Flow template UUID. - -
-
- -
-
- -**agent_id:** `str` — The agent that receives the cloned graph as a new draft. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- ## Tts Audio
client.tts.audio.speech(...)
diff --git a/requirements.txt b/requirements.txt index ef32414..f502f1b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ httpx>=0.21.2 -livekit>=1.1,<2 pydantic>= 1.9.2 pydantic-core==^2.18.2 typing_extensions>= 4.0.0 diff --git a/src/speechify/__init__.py b/src/speechify/__init__.py index 86863a2..4c530dd 100644 --- a/src/speechify/__init__.py +++ b/src/speechify/__init__.py @@ -1,113 +1,15 @@ # This file was auto-generated by Fern from our API Definition. from .types import ( - AccessToken, - AccessTokenScope, - AccessTokenTokenType, - Agent, - AgentBackgroundNoisePreset, - AgentBuiltin, - AgentLlmProvider, - AgentSnapshot, - AgentSnapshotBackgroundNoisePreset, - AgentSttOverride, - AgentTest, - AgentTestAttachment, - AgentTestConfig, - AgentTestFolder, - AgentTestRun, - AgentTestSuiteRun, - AgentTestSuiteRunWithRuns, - AgentTestWithLastRun, - AgentVoice, - AgentVoiceGender, - AgentVoiceLanguage, - AgentVoiceModel, - AgentVoiceModelName, - AgentVoiceType, - AmdConfig, - AmdConfigOnIvr, - AmdConfigOnIvrAction, - AmdConfigOnUnavailable, - AmdConfigOnUnavailableAction, - AmdConfigOnVoicemail, - AmdConfigOnVoicemailAction, - AmdConfigTuning, - ApiKey, - AttachedKnowledgeBasesResponse, - AttachedToolsResponse, - AudioAsset, - AvailablePhoneNumber, - BasicAuthConfig, - BatchCall, - BatchCallStatus, - BatchRecipient, - BatchRecipientRequest, - BatchRecipientStatus, - BatchRunEntry, - BearerAuthConfig, - BillingEntitlements, - Caller, - CallerMemoryItem, - ClientToolConfig, - Conversation, - ConversationEndReason, - ConversationIvrSurrenderReason, - ConversationStats, - ConversationStatus, - ConversationTransport, - CreateAccessTokenRequest, - CreateAccessTokenRequestGrantType, - CreateAccessTokenRequestScope, - CreateApiKeyRequest, - CreateBatchCallResponse, - CreateConversationResponse, - CreateCredentialRequest, - CreateFlowTemplateRequest, - CreateInviteRequest, - CreateOutboundCallResponse, CreateVoiceLanguage, CreateVoiceModel, CreateVoiceModelName, - CreateWorkspaceRequest, CreatedVoice, CreatedVoiceGender, CreatedVoiceType, - Credential, - CredentialConfig, - CredentialKind, - CriterionStatus, - CustomHeadersConfig, - DataAssertion, - DataAssertionMode, - DataAssertionResult, - DataAssertionResultMode, - DataCollectionField, - DataCollectionFieldType, - DeleteCallerResponse, - DeleteMemoriesByCallerResponse, - DependentAgent, - DynamicVariable, - DynamicVariableType, - EntitlementsResponse, Error, ErrorCode, ErrorDetail, - Evaluation, - EvaluationConfig, - EvaluationCriterion, - EvaluationKind, - EvaluationStatus, - FlowGraph, - FlowGraphInput, - FlowTemplate, - FlowValidationError, - FlowValidationIssue, - FlowVersion, - GetBatchCallResponse, - GetCallerResponse, - GetFlowResponse, - GetFlowVersionResponse, GetSpeechOptionsRequest, GetSpeechResponse, GetSpeechResponseAudioFormat, @@ -118,172 +20,12 @@ GetVoiceType, GetVoicesModel, GetVoicesModelName, - ImportJob, - ImportJobKind, - ImportJobResponse, - ImportJobStatus, - Invite, - InvitePreview, - InvitesListResponse, - IvrMenu, - IvrMenuListEntry, - KnowledgeBase, - KnowledgeBaseChunk, - KnowledgeBaseDocument, - KnowledgeBaseDocumentDetail, - KnowledgeBaseDocumentSourceKind, - KnowledgeBaseDocumentStatus, - KnowledgeBaseFolder, - KnowledgeBaseSearchHit, - ListAgentBuiltinsResponse, - ListAgentTestAttachmentsResponse, - ListAgentTestFoldersResponse, - ListAgentTestRunsResponse, - ListAgentTestsResponse, - ListAgentsResponse, - ListAudioAssetsResponse, - ListBatchCallsResponse, - ListCallerConversationsResponse, - ListCallerMemoriesResponse, - ListCallersResponse, - ListConversationsResponse, - ListCredentialsResponse, - ListDynamicVariablesResponse, - ListEvaluationsResponse, - ListFlowTemplatesResponse, - ListFlowVersionsResponse, - ListImportJobsResponse, - ListIvrMenusResponse, - ListKnowledgeBaseChunksResponse, - ListKnowledgeBaseDocumentsResponse, - ListKnowledgeBaseFoldersResponse, - ListKnowledgeBasesResponse, - ListMemoriesResponse, - ListMessagesResponse, - ListPhoneNumbersResponse, - ListRecentCalleesResponse, - ListRefreshHistoryResponse, - ListRetrievalLogsResponse, - ListSipTrunksResponse, - ListSuiteRunsResponse, - ListSystemBuiltinsResponse, - ListTestsResponse, - ListToolAttachedAgentsResponse, - ListToolsResponse, - ListWebhookDeliveriesResponse, - LlmProvider, - McpAuth, - McpAuthBearer, - McpAuthNone, - McpAuthOAuth2, - McpAuthType, - McpAuth_Bearer, - McpAuth_None, - McpAuth_Oauth2ClientCredentials, - McpProbeErrorDetails, - McpProbeErrorDetailsStage, - McpProbeResult, - McpProbeTool, - McpToolConfig, - McpTransport, - Member, - MemberRole, - MembersListResponse, - Memory, - Message, - MessageRole, - MockingStrategy, NestedChunk, - NoMatchBehavior, - OAuth2ClientCredentialsConfig, - OAuth2JwtConfig, - OAuthError, - OAuthErrorError, - PaginationMeta, - ParameterCheck, - ParameterCheckMode, - ParameterCheckResult, - PhoneNumber, - PhoneNumberCapability, - PhoneNumberSource, - RecentCallee, - RefreshConfig, - RefreshHistoryEntry, - RefreshHistoryEntryStatus, - ReplyConfig, - ReplyResult, - RetrievalLogEntry, - RetrievalLogResult, - RunAgentTestsResponse, - RunBatchResponse, - SearchAvailablePhoneNumbersResponse, - SearchKnowledgeBasesResponse, - ShadowConversationResponse, - SimulationConfig, - SimulationCriterionResult, - SimulationCriterionResultStatus, - SimulationMessage, - SimulationMessageRole, - SimulationResult, - SimulationResultSentiment, - SimulationToolCall, - SipMediaEncryption, - SipTransport, - SipTrunk, - SipTrunkDirection, - SipTrunkKind, SpeechMarks, - SuiteChildRun, - SuiteRunTrigger, - SystemBuiltin, - SystemBuiltinInfo, - SystemToolConfig, - SystemVariableDoc, - Tenant, - TenantsListResponse, - TestRunConfigOverride, - TestRunResult, - TestRunStatus, - TestStats, - TestStatsBucket, - TestType, - Tool, - ToolAttachedAgent, - ToolCallConfig, - ToolCallResult, - ToolConfig, - ToolKind, - ToolMock, - ToolMockConfig, - ToolParam, - ToolParamType, - TransferOwnershipRequest, - TwilioImportSpec, - UpdateBillingContactEmailRequest, - UpdateBillingContactNameRequest, - UpdateMemberRoleRequest, - UpdateSipTrunkRequest, - UpdateWorkspaceRequest, - UploadAudioAssetResponse, - WebhookDelivery, - WebhookDeliveryStatus, - WebhookProbeResult, - WebhookToolConfig, - WebhookToolConfigMethod, - WidgetConfig, - WidgetConfigAvatar, - WidgetConfigAvatarType, - WidgetConfigStyle, - WidgetConfigTerms, - WidgetConfigText, - WidgetConfigTheme, - WidgetConfigTranscript, ) from .errors import ( BadGatewayError, BadRequestError, - ConflictError, - ContentTooLargeError, ForbiddenError, InternalServerError, NotFoundError, @@ -293,138 +35,25 @@ UnauthorizedError, UnprocessableEntityError, ) -from . import agent, tts -from .agent import ( - CreateAgentRequestBackgroundNoisePreset, - CreateAgentRequestLlmProvider, - CreateAgentRequestSttOverride, - CreateAgentTestRequestConfig, - UpdateAgentRequestBackgroundNoisePreset, - UpdateAgentRequestLlmProvider, - UpdateAgentRequestSttOverride, -) +from . import tts from .client import AsyncSpeechify, Speechify from .environment import SpeechifyEnvironment from .version import __version__ __all__ = [ - "AccessToken", - "AccessTokenScope", - "AccessTokenTokenType", - "Agent", - "AgentBackgroundNoisePreset", - "AgentBuiltin", - "AgentLlmProvider", - "AgentSnapshot", - "AgentSnapshotBackgroundNoisePreset", - "AgentSttOverride", - "AgentTest", - "AgentTestAttachment", - "AgentTestConfig", - "AgentTestFolder", - "AgentTestRun", - "AgentTestSuiteRun", - "AgentTestSuiteRunWithRuns", - "AgentTestWithLastRun", - "AgentVoice", - "AgentVoiceGender", - "AgentVoiceLanguage", - "AgentVoiceModel", - "AgentVoiceModelName", - "AgentVoiceType", - "AmdConfig", - "AmdConfigOnIvr", - "AmdConfigOnIvrAction", - "AmdConfigOnUnavailable", - "AmdConfigOnUnavailableAction", - "AmdConfigOnVoicemail", - "AmdConfigOnVoicemailAction", - "AmdConfigTuning", - "ApiKey", "AsyncSpeechify", - "AttachedKnowledgeBasesResponse", - "AttachedToolsResponse", - "AudioAsset", - "AvailablePhoneNumber", "BadGatewayError", "BadRequestError", - "BasicAuthConfig", - "BatchCall", - "BatchCallStatus", - "BatchRecipient", - "BatchRecipientRequest", - "BatchRecipientStatus", - "BatchRunEntry", - "BearerAuthConfig", - "BillingEntitlements", - "Caller", - "CallerMemoryItem", - "ClientToolConfig", - "ConflictError", - "ContentTooLargeError", - "Conversation", - "ConversationEndReason", - "ConversationIvrSurrenderReason", - "ConversationStats", - "ConversationStatus", - "ConversationTransport", - "CreateAccessTokenRequest", - "CreateAccessTokenRequestGrantType", - "CreateAccessTokenRequestScope", - "CreateAgentRequestBackgroundNoisePreset", - "CreateAgentRequestLlmProvider", - "CreateAgentRequestSttOverride", - "CreateAgentTestRequestConfig", - "CreateApiKeyRequest", - "CreateBatchCallResponse", - "CreateConversationResponse", - "CreateCredentialRequest", - "CreateFlowTemplateRequest", - "CreateInviteRequest", - "CreateOutboundCallResponse", "CreateVoiceLanguage", "CreateVoiceModel", "CreateVoiceModelName", - "CreateWorkspaceRequest", "CreatedVoice", "CreatedVoiceGender", "CreatedVoiceType", - "Credential", - "CredentialConfig", - "CredentialKind", - "CriterionStatus", - "CustomHeadersConfig", - "DataAssertion", - "DataAssertionMode", - "DataAssertionResult", - "DataAssertionResultMode", - "DataCollectionField", - "DataCollectionFieldType", - "DeleteCallerResponse", - "DeleteMemoriesByCallerResponse", - "DependentAgent", - "DynamicVariable", - "DynamicVariableType", - "EntitlementsResponse", "Error", "ErrorCode", "ErrorDetail", - "Evaluation", - "EvaluationConfig", - "EvaluationCriterion", - "EvaluationKind", - "EvaluationStatus", - "FlowGraph", - "FlowGraphInput", - "FlowTemplate", - "FlowValidationError", - "FlowValidationIssue", - "FlowVersion", "ForbiddenError", - "GetBatchCallResponse", - "GetCallerResponse", - "GetFlowResponse", - "GetFlowVersionResponse", "GetSpeechOptionsRequest", "GetSpeechResponse", "GetSpeechResponseAudioFormat", @@ -435,179 +64,17 @@ "GetVoiceType", "GetVoicesModel", "GetVoicesModelName", - "ImportJob", - "ImportJobKind", - "ImportJobResponse", - "ImportJobStatus", "InternalServerError", - "Invite", - "InvitePreview", - "InvitesListResponse", - "IvrMenu", - "IvrMenuListEntry", - "KnowledgeBase", - "KnowledgeBaseChunk", - "KnowledgeBaseDocument", - "KnowledgeBaseDocumentDetail", - "KnowledgeBaseDocumentSourceKind", - "KnowledgeBaseDocumentStatus", - "KnowledgeBaseFolder", - "KnowledgeBaseSearchHit", - "ListAgentBuiltinsResponse", - "ListAgentTestAttachmentsResponse", - "ListAgentTestFoldersResponse", - "ListAgentTestRunsResponse", - "ListAgentTestsResponse", - "ListAgentsResponse", - "ListAudioAssetsResponse", - "ListBatchCallsResponse", - "ListCallerConversationsResponse", - "ListCallerMemoriesResponse", - "ListCallersResponse", - "ListConversationsResponse", - "ListCredentialsResponse", - "ListDynamicVariablesResponse", - "ListEvaluationsResponse", - "ListFlowTemplatesResponse", - "ListFlowVersionsResponse", - "ListImportJobsResponse", - "ListIvrMenusResponse", - "ListKnowledgeBaseChunksResponse", - "ListKnowledgeBaseDocumentsResponse", - "ListKnowledgeBaseFoldersResponse", - "ListKnowledgeBasesResponse", - "ListMemoriesResponse", - "ListMessagesResponse", - "ListPhoneNumbersResponse", - "ListRecentCalleesResponse", - "ListRefreshHistoryResponse", - "ListRetrievalLogsResponse", - "ListSipTrunksResponse", - "ListSuiteRunsResponse", - "ListSystemBuiltinsResponse", - "ListTestsResponse", - "ListToolAttachedAgentsResponse", - "ListToolsResponse", - "ListWebhookDeliveriesResponse", - "LlmProvider", - "McpAuth", - "McpAuthBearer", - "McpAuthNone", - "McpAuthOAuth2", - "McpAuthType", - "McpAuth_Bearer", - "McpAuth_None", - "McpAuth_Oauth2ClientCredentials", - "McpProbeErrorDetails", - "McpProbeErrorDetailsStage", - "McpProbeResult", - "McpProbeTool", - "McpToolConfig", - "McpTransport", - "Member", - "MemberRole", - "MembersListResponse", - "Memory", - "Message", - "MessageRole", - "MockingStrategy", "NestedChunk", - "NoMatchBehavior", "NotFoundError", - "OAuth2ClientCredentialsConfig", - "OAuth2JwtConfig", - "OAuthError", - "OAuthErrorError", - "PaginationMeta", - "ParameterCheck", - "ParameterCheckMode", - "ParameterCheckResult", "PaymentRequiredError", - "PhoneNumber", - "PhoneNumberCapability", - "PhoneNumberSource", - "RecentCallee", - "RefreshConfig", - "RefreshHistoryEntry", - "RefreshHistoryEntryStatus", - "ReplyConfig", - "ReplyResult", - "RetrievalLogEntry", - "RetrievalLogResult", - "RunAgentTestsResponse", - "RunBatchResponse", - "SearchAvailablePhoneNumbersResponse", - "SearchKnowledgeBasesResponse", "ServiceUnavailableError", - "ShadowConversationResponse", - "SimulationConfig", - "SimulationCriterionResult", - "SimulationCriterionResultStatus", - "SimulationMessage", - "SimulationMessageRole", - "SimulationResult", - "SimulationResultSentiment", - "SimulationToolCall", - "SipMediaEncryption", - "SipTransport", - "SipTrunk", - "SipTrunkDirection", - "SipTrunkKind", "SpeechMarks", "Speechify", "SpeechifyEnvironment", - "SuiteChildRun", - "SuiteRunTrigger", - "SystemBuiltin", - "SystemBuiltinInfo", - "SystemToolConfig", - "SystemVariableDoc", - "Tenant", - "TenantsListResponse", - "TestRunConfigOverride", - "TestRunResult", - "TestRunStatus", - "TestStats", - "TestStatsBucket", - "TestType", "TooManyRequestsError", - "Tool", - "ToolAttachedAgent", - "ToolCallConfig", - "ToolCallResult", - "ToolConfig", - "ToolKind", - "ToolMock", - "ToolMockConfig", - "ToolParam", - "ToolParamType", - "TransferOwnershipRequest", - "TwilioImportSpec", "UnauthorizedError", "UnprocessableEntityError", - "UpdateAgentRequestBackgroundNoisePreset", - "UpdateAgentRequestLlmProvider", - "UpdateAgentRequestSttOverride", - "UpdateBillingContactEmailRequest", - "UpdateBillingContactNameRequest", - "UpdateMemberRoleRequest", - "UpdateSipTrunkRequest", - "UpdateWorkspaceRequest", - "UploadAudioAssetResponse", - "WebhookDelivery", - "WebhookDeliveryStatus", - "WebhookProbeResult", - "WebhookToolConfig", - "WebhookToolConfigMethod", - "WidgetConfig", - "WidgetConfigAvatar", - "WidgetConfigAvatarType", - "WidgetConfigStyle", - "WidgetConfigTerms", - "WidgetConfigText", - "WidgetConfigTheme", - "WidgetConfigTranscript", "__version__", - "agent", "tts", ] diff --git a/src/speechify/agent/__init__.py b/src/speechify/agent/__init__.py deleted file mode 100644 index 747e44e..0000000 --- a/src/speechify/agent/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - CreateAgentRequestBackgroundNoisePreset, - CreateAgentRequestLlmProvider, - CreateAgentRequestSttOverride, - CreateAgentTestRequestConfig, - UpdateAgentRequestBackgroundNoisePreset, - UpdateAgentRequestLlmProvider, - UpdateAgentRequestSttOverride, -) -from . import ( - admin, - audio_assets, - batch_calls, - callers, - conversations, - flow, - ivr_memory, - knowledge_bases, - memories, - outbound_calls, - phone_numbers, - sip_trunks, - tests, - tools, -) -from .tests import UpdateAgentTestRequestConfig -from .tools import CreateToolRequestConfig, UpdateToolRequestConfig - -__all__ = [ - "CreateAgentRequestBackgroundNoisePreset", - "CreateAgentRequestLlmProvider", - "CreateAgentRequestSttOverride", - "CreateAgentTestRequestConfig", - "CreateToolRequestConfig", - "UpdateAgentRequestBackgroundNoisePreset", - "UpdateAgentRequestLlmProvider", - "UpdateAgentRequestSttOverride", - "UpdateAgentTestRequestConfig", - "UpdateToolRequestConfig", - "admin", - "audio_assets", - "batch_calls", - "callers", - "conversations", - "flow", - "ivr_memory", - "knowledge_bases", - "memories", - "outbound_calls", - "phone_numbers", - "sip_trunks", - "tests", - "tools", -] diff --git a/src/speechify/agent/admin/__init__.py b/src/speechify/agent/admin/__init__.py deleted file mode 100644 index f3ea265..0000000 --- a/src/speechify/agent/admin/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/speechify/agent/admin/client.py b/src/speechify/agent/admin/client.py deleted file mode 100644 index 04c2451..0000000 --- a/src/speechify/agent/admin/client.py +++ /dev/null @@ -1,378 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ...core.client_wrapper import SyncClientWrapper -import typing -from ...core.request_options import RequestOptions -from ...types.shadow_conversation_response import ShadowConversationResponse -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import parse_obj_as -from ...errors.unauthorized_error import UnauthorizedError -from ...errors.forbidden_error import ForbiddenError -from ...types.error import Error -from ...errors.not_found_error import NotFoundError -from ...errors.conflict_error import ConflictError -from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper - - -class AdminClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def shadow_token( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ShadowConversationResponse: - """ - Mint a listen-only LiveKit access token so an authorized observer - can join an ongoing voice-agent conversation as a hidden - participant. Caller must be an `owner` or `admin` of the - workspace the conversation belongs to. The token cannot publish - audio or data; the observer is invisible to the caller and the - agent. Speechify support engineers reach this endpoint the same - way as any other observer — by being granted the owner/admin - role on the customer's workspace (typically under an NDA-backed - support arrangement). - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ShadowConversationResponse - Shadow-call connection details. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.admin.shadow_token( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/shadow-token", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ShadowConversationResponse, - parse_obj_as( - type_=ShadowConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 409: - raise ConflictError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def force_end(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Force-terminate the LiveKit room for an ongoing conversation. - Idempotent: rooms that LiveKit has already cleaned up return - 204 the same as a successful first-time termination. Same - owner/admin role gating as the shadow-token endpoint. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.admin.force_end( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/end", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncAdminClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def shadow_token( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ShadowConversationResponse: - """ - Mint a listen-only LiveKit access token so an authorized observer - can join an ongoing voice-agent conversation as a hidden - participant. Caller must be an `owner` or `admin` of the - workspace the conversation belongs to. The token cannot publish - audio or data; the observer is invisible to the caller and the - agent. Speechify support engineers reach this endpoint the same - way as any other observer — by being granted the owner/admin - role on the customer's workspace (typically under an NDA-backed - support arrangement). - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ShadowConversationResponse - Shadow-call connection details. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.admin.shadow_token( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/shadow-token", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ShadowConversationResponse, - parse_obj_as( - type_=ShadowConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 409: - raise ConflictError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def force_end(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Force-terminate the LiveKit room for an ongoing conversation. - Idempotent: rooms that LiveKit has already cleaned up return - 204 the same as a successful first-time termination. Same - owner/admin role gating as the shadow-token endpoint. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.admin.force_end( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/end", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/speechify/agent/audio_assets/__init__.py b/src/speechify/agent/audio_assets/__init__.py deleted file mode 100644 index f3ea265..0000000 --- a/src/speechify/agent/audio_assets/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/speechify/agent/audio_assets/client.py b/src/speechify/agent/audio_assets/client.py deleted file mode 100644 index c849e1d..0000000 --- a/src/speechify/agent/audio_assets/client.py +++ /dev/null @@ -1,746 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from ...core.client_wrapper import SyncClientWrapper -from ...core.request_options import RequestOptions -from ...types.list_audio_assets_response import ListAudioAssetsResponse -from ...core.pydantic_utilities import parse_obj_as -from ...errors.unauthorized_error import UnauthorizedError -from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ... import core -from ...types.upload_audio_asset_response import UploadAudioAssetResponse -from ...errors.bad_request_error import BadRequestError -from ...types.audio_asset import AudioAsset -from ...core.jsonable_encoder import jsonable_encoder -from ...errors.not_found_error import NotFoundError -from ...core.client_wrapper import AsyncClientWrapper - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class AudioAssetsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListAudioAssetsResponse: - """ - List every non-deleted audio asset in the caller's workspace. - Audio assets are pre-recorded WAV clips (intro jingles, legal - disclaimers, hold cues) referenced from `play_audio` flow nodes - and the corresponding system builtin. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAudioAssetsResponse - A list of audio assets. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.audio_assets.list() - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/audio-assets", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAudioAssetsResponse, - parse_obj_as( - type_=ListAudioAssetsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def upload( - self, *, file: core.File, request_options: typing.Optional[RequestOptions] = None - ) -> UploadAudioAssetResponse: - """ - Upload a new audio asset. The body is a multipart/form-data - request with a single `file` field carrying the WAV bytes. - - The WAV is validated server-side against a strict format - contract — PCM 16-bit signed, mono, 48000 Hz, ≤30s, ≤4 MiB — - before any bytes hit storage. The strict shape matches the - LiveKit room sample rate so the worker reads bytes straight - into `rtc.AudioFrame` with no decode dependency on either side; - convert MP3 sources with `ffmpeg -i in.mp3 -ar 48000 -ac 1 - -sample_fmt s16 out.wav`. - - Parameters - ---------- - file : core.File - See core.File for more documentation - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UploadAudioAssetResponse - The uploaded asset's metadata. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.audio_assets.upload() - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/audio-assets", - method="POST", - data={}, - files={ - "file": file, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - UploadAudioAssetResponse, - parse_obj_as( - type_=UploadAudioAssetResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AudioAsset: - """ - Fetch one audio asset's metadata. Returns 404 for missing, - soft-deleted, or foreign-tenant assets — existence information - is never leaked across tenants. - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AudioAsset - The audio asset's metadata. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.audio_assets.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/audio-assets/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AudioAsset, - parse_obj_as( - type_=AudioAsset, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Soft-delete an audio asset. The underlying GCS object is - retained so any flow node or tool still referencing the asset - keeps working until the config is updated; the worker logs - and skips on missing-row at session start (fail-soft). - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.audio_assets.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/audio-assets/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_bytes(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> typing.Iterator[bytes]: - """ - Stream the raw WAV bytes for an audio asset. Byte-stream - sibling of the metadata endpoint at /v1/agents/audio-assets/{id}. - The LiveKit worker fetches through here for the play_audio - builtin; SDK consumers can also download originals. Returns 404 - for missing / soft-deleted / foreign-tenant assets. - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response. - - Yields - ------ - typing.Iterator[bytes] - The raw audio bytes (PCM 16-bit signed, mono, 48 kHz, WAV-wrapped). - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.audio_assets.get_bytes( - id="id", - ) - """ - with self._client_wrapper.httpx_client.stream( - f"v1/agents/audio-assets/{jsonable_encoder(id)}/bytes", - method="GET", - request_options=request_options, - ) as _response: - try: - if 200 <= _response.status_code < 300: - _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None - for _chunk in _response.iter_bytes(chunk_size=_chunk_size): - yield _chunk - return - _response.read() - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncAudioAssetsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListAudioAssetsResponse: - """ - List every non-deleted audio asset in the caller's workspace. - Audio assets are pre-recorded WAV clips (intro jingles, legal - disclaimers, hold cues) referenced from `play_audio` flow nodes - and the corresponding system builtin. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAudioAssetsResponse - A list of audio assets. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.audio_assets.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/audio-assets", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAudioAssetsResponse, - parse_obj_as( - type_=ListAudioAssetsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def upload( - self, *, file: core.File, request_options: typing.Optional[RequestOptions] = None - ) -> UploadAudioAssetResponse: - """ - Upload a new audio asset. The body is a multipart/form-data - request with a single `file` field carrying the WAV bytes. - - The WAV is validated server-side against a strict format - contract — PCM 16-bit signed, mono, 48000 Hz, ≤30s, ≤4 MiB — - before any bytes hit storage. The strict shape matches the - LiveKit room sample rate so the worker reads bytes straight - into `rtc.AudioFrame` with no decode dependency on either side; - convert MP3 sources with `ffmpeg -i in.mp3 -ar 48000 -ac 1 - -sample_fmt s16 out.wav`. - - Parameters - ---------- - file : core.File - See core.File for more documentation - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - UploadAudioAssetResponse - The uploaded asset's metadata. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.audio_assets.upload() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/audio-assets", - method="POST", - data={}, - files={ - "file": file, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - UploadAudioAssetResponse, - parse_obj_as( - type_=UploadAudioAssetResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AudioAsset: - """ - Fetch one audio asset's metadata. Returns 404 for missing, - soft-deleted, or foreign-tenant assets — existence information - is never leaked across tenants. - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AudioAsset - The audio asset's metadata. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.audio_assets.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/audio-assets/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AudioAsset, - parse_obj_as( - type_=AudioAsset, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Soft-delete an audio asset. The underlying GCS object is - retained so any flow node or tool still referencing the asset - keeps working until the config is updated; the worker logs - and skips on missing-row at session start (fail-soft). - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.audio_assets.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/audio-assets/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_bytes( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.AsyncIterator[bytes]: - """ - Stream the raw WAV bytes for an audio asset. Byte-stream - sibling of the metadata endpoint at /v1/agents/audio-assets/{id}. - The LiveKit worker fetches through here for the play_audio - builtin; SDK consumers can also download originals. Returns 404 - for missing / soft-deleted / foreign-tenant assets. - - Parameters - ---------- - id : str - Audio asset ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response. - - Yields - ------ - typing.AsyncIterator[bytes] - The raw audio bytes (PCM 16-bit signed, mono, 48 kHz, WAV-wrapped). - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.audio_assets.get_bytes( - id="id", - ) - - - asyncio.run(main()) - """ - async with self._client_wrapper.httpx_client.stream( - f"v1/agents/audio-assets/{jsonable_encoder(id)}/bytes", - method="GET", - request_options=request_options, - ) as _response: - try: - if 200 <= _response.status_code < 300: - _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None - async for _chunk in _response.aiter_bytes(chunk_size=_chunk_size): - yield _chunk - return - await _response.aread() - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/speechify/agent/batch_calls/__init__.py b/src/speechify/agent/batch_calls/__init__.py deleted file mode 100644 index f3ea265..0000000 --- a/src/speechify/agent/batch_calls/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/speechify/agent/batch_calls/client.py b/src/speechify/agent/batch_calls/client.py deleted file mode 100644 index bc964a6..0000000 --- a/src/speechify/agent/batch_calls/client.py +++ /dev/null @@ -1,712 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from ...core.client_wrapper import SyncClientWrapper -from ...core.request_options import RequestOptions -from ...core.pagination import SyncPager -from ...types.batch_call import BatchCall -from ...types.list_batch_calls_response import ListBatchCallsResponse -from ...core.pydantic_utilities import parse_obj_as -from ...errors.bad_request_error import BadRequestError -from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ...types.batch_recipient_request import BatchRecipientRequest -import datetime as dt -from ...types.create_batch_call_response import CreateBatchCallResponse -from ...core.serialization import convert_and_respect_annotation_metadata -from ...types.get_batch_call_response import GetBatchCallResponse -from ...core.jsonable_encoder import jsonable_encoder -from ...errors.not_found_error import NotFoundError -from ...errors.conflict_error import ConflictError -from ...types.error import Error -from ...core.client_wrapper import AsyncClientWrapper -from ...core.pagination import AsyncPager - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class BatchCallsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[BatchCall]: - """ - Returns one page of batch calls for the workspace, newest first. - Paginate by passing `cursor` from the previous response. - - Parameters - ---------- - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[BatchCall] - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.batch_calls.list() - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/batch-calls", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListBatchCallsResponse, - parse_obj_as( - type_=ListBatchCallsResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list( - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.batches - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create( - self, - *, - name: str, - agent_id: str, - recipients: typing.Sequence[BatchRecipientRequest], - phone_number_id: typing.Optional[str] = OMIT, - scheduled_at: typing.Optional[dt.datetime] = OMIT, - ringing_timeout_ms: typing.Optional[int] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateBatchCallResponse: - """ - Dial a list of phone numbers through one of your voice agents in a - single request. Each recipient can receive personalised dynamic - variables that your agent prompt references via `{{key}}` placeholders. - Batches can run immediately or be scheduled up to 30 days in advance. - - Accepts `application/json` or `multipart/form-data` (with a CSV file). - Max 1000 recipients per batch. - - Parameters - ---------- - name : str - Human-readable batch name. - - agent_id : str - Agent that handles each call. - - recipients : typing.Sequence[BatchRecipientRequest] - - phone_number_id : typing.Optional[str] - Caller-ID override. Falls back to the agent's bound number. - - scheduled_at : typing.Optional[dt.datetime] - Schedule the batch for a future time (RFC 3339). Omit to start immediately. - - ringing_timeout_ms : typing.Optional[int] - Ringing timeout in milliseconds applied to every call in the - batch (how long each recipient rings before the dial gives - up). Range 1000-80000 (1-80s). Omit to use the 30s default. - The console collects this in seconds and converts to - milliseconds. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateBatchCallResponse - Batch accepted for processing. - - Examples - -------- - from speechify import BatchRecipientRequest, Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.batch_calls.create( - name="Appointment reminders", - agent_id="agent_01HS...", - recipients=[ - BatchRecipientRequest( - phone="+14155551234", - dynamic_vars={ - "first_name": "Alice", - "appointment_date": "May 5th at 2pm", - }, - ), - BatchRecipientRequest( - phone="+14155555678", - dynamic_vars={ - "first_name": "Bob", - "appointment_date": "May 6th at 10am", - }, - ), - ], - ) - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/batch-calls", - method="POST", - json={ - "name": name, - "agent_id": agent_id, - "phone_number_id": phone_number_id, - "scheduled_at": scheduled_at, - "ringing_timeout_ms": ringing_timeout_ms, - "recipients": convert_and_respect_annotation_metadata( - object_=recipients, annotation=typing.Sequence[BatchRecipientRequest], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateBatchCallResponse, - parse_obj_as( - type_=CreateBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetBatchCallResponse: - """ - Returns the batch row plus all recipients so the detail view renders - without a second round-trip. - - Parameters - ---------- - id : str - Batch call ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetBatchCallResponse - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.batch_calls.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/batch-calls/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetBatchCallResponse, - parse_obj_as( - type_=GetBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def cancel(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> CreateBatchCallResponse: - """ - Cancels a scheduled or pending batch before it starts dialing. - Returns 409 if the batch is already running or completed. - - Parameters - ---------- - id : str - Batch call ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateBatchCallResponse - Batch cancelled. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.batch_calls.cancel( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/batch-calls/{jsonable_encoder(id)}/cancel", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateBatchCallResponse, - parse_obj_as( - type_=CreateBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 409: - raise ConflictError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncBatchCallsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncPager[BatchCall]: - """ - Returns one page of batch calls for the workspace, newest first. - Paginate by passing `cursor` from the previous response. - - Parameters - ---------- - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncPager[BatchCall] - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - response = await client.agent.batch_calls.list() - async for item in response: - yield item - # alternatively, you can paginate page-by-page - async for page in response.iter_pages(): - yield page - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/batch-calls", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListBatchCallsResponse, - parse_obj_as( - type_=ListBatchCallsResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list( - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.batches - return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create( - self, - *, - name: str, - agent_id: str, - recipients: typing.Sequence[BatchRecipientRequest], - phone_number_id: typing.Optional[str] = OMIT, - scheduled_at: typing.Optional[dt.datetime] = OMIT, - ringing_timeout_ms: typing.Optional[int] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateBatchCallResponse: - """ - Dial a list of phone numbers through one of your voice agents in a - single request. Each recipient can receive personalised dynamic - variables that your agent prompt references via `{{key}}` placeholders. - Batches can run immediately or be scheduled up to 30 days in advance. - - Accepts `application/json` or `multipart/form-data` (with a CSV file). - Max 1000 recipients per batch. - - Parameters - ---------- - name : str - Human-readable batch name. - - agent_id : str - Agent that handles each call. - - recipients : typing.Sequence[BatchRecipientRequest] - - phone_number_id : typing.Optional[str] - Caller-ID override. Falls back to the agent's bound number. - - scheduled_at : typing.Optional[dt.datetime] - Schedule the batch for a future time (RFC 3339). Omit to start immediately. - - ringing_timeout_ms : typing.Optional[int] - Ringing timeout in milliseconds applied to every call in the - batch (how long each recipient rings before the dial gives - up). Range 1000-80000 (1-80s). Omit to use the 30s default. - The console collects this in seconds and converts to - milliseconds. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateBatchCallResponse - Batch accepted for processing. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify, BatchRecipientRequest - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.batch_calls.create( - name="Appointment reminders", - agent_id="agent_01HS...", - recipients=[ - BatchRecipientRequest( - phone="+14155551234", - dynamic_vars={ - "first_name": "Alice", - "appointment_date": "May 5th at 2pm", - }, - ), - BatchRecipientRequest( - phone="+14155555678", - dynamic_vars={ - "first_name": "Bob", - "appointment_date": "May 6th at 10am", - }, - ), - ], - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/batch-calls", - method="POST", - json={ - "name": name, - "agent_id": agent_id, - "phone_number_id": phone_number_id, - "scheduled_at": scheduled_at, - "ringing_timeout_ms": ringing_timeout_ms, - "recipients": convert_and_respect_annotation_metadata( - object_=recipients, annotation=typing.Sequence[BatchRecipientRequest], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateBatchCallResponse, - parse_obj_as( - type_=CreateBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetBatchCallResponse: - """ - Returns the batch row plus all recipients so the detail view renders - without a second round-trip. - - Parameters - ---------- - id : str - Batch call ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetBatchCallResponse - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.batch_calls.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/batch-calls/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetBatchCallResponse, - parse_obj_as( - type_=GetBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def cancel( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> CreateBatchCallResponse: - """ - Cancels a scheduled or pending batch before it starts dialing. - Returns 409 if the batch is already running or completed. - - Parameters - ---------- - id : str - Batch call ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateBatchCallResponse - Batch cancelled. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.batch_calls.cancel( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/batch-calls/{jsonable_encoder(id)}/cancel", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateBatchCallResponse, - parse_obj_as( - type_=CreateBatchCallResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 409: - raise ConflictError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/speechify/agent/callers/__init__.py b/src/speechify/agent/callers/__init__.py deleted file mode 100644 index f3ea265..0000000 --- a/src/speechify/agent/callers/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/speechify/agent/callers/client.py b/src/speechify/agent/callers/client.py deleted file mode 100644 index 40664e8..0000000 --- a/src/speechify/agent/callers/client.py +++ /dev/null @@ -1,1077 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from ...core.client_wrapper import SyncClientWrapper -import datetime as dt -from ...core.request_options import RequestOptions -from ...core.pagination import SyncPager -from ...types.caller import Caller -from ...core.datetime_utils import serialize_datetime -from ...types.list_callers_response import ListCallersResponse -from ...core.pydantic_utilities import parse_obj_as -from ...errors.bad_request_error import BadRequestError -from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ...types.get_caller_response import GetCallerResponse -from ...core.jsonable_encoder import jsonable_encoder -from ...errors.not_found_error import NotFoundError -from ...types.delete_caller_response import DeleteCallerResponse -from ...types.caller_memory_item import CallerMemoryItem -from ...types.list_caller_memories_response import ListCallerMemoriesResponse -from ...types.conversation import Conversation -from ...types.list_caller_conversations_response import ListCallerConversationsResponse -from ...core.client_wrapper import AsyncClientWrapper -from ...core.pagination import AsyncPager - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class CallersClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - agent_id: typing.Optional[str] = None, - q: typing.Optional[str] = None, - last_seen_after: typing.Optional[dt.datetime] = None, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[Caller]: - """ - List the workspace's callers, ordered by most-recently-seen first. - A caller is the per-(tenant, agent, identity) entity that owns - long-term memories and conversation history. - - Parameters - ---------- - agent_id : typing.Optional[str] - Narrow the list to callers attached to one agent. - - q : typing.Optional[str] - Identity-prefix search. Filters to rows where `identity LIKE q + '%'` - (`%`/`_` characters in the input are escaped as literals). - - last_seen_after : typing.Optional[dt.datetime] - RFC 3339 timestamp. Narrows to callers active strictly AFTER the - supplied moment. Useful for "active this week / month" filters. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[Caller] - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.callers.list() - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/callers", - method="GET", - params={ - "agent_id": agent_id, - "q": q, - "last_seen_after": serialize_datetime(last_seen_after) if last_seen_after is not None else None, - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallersResponse, - parse_obj_as( - type_=ListCallersResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list( - agent_id=agent_id, - q=q, - last_seen_after=last_seen_after, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.callers - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetCallerResponse: - """ - Fetch a single caller by id. Returns 404 for soft-deleted or - foreign-tenant rows — GDPR-purged callers appear as "not found" - to the API. - - Parameters - ---------- - id : str - Caller ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCallerResponse - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.callers.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetCallerResponse, - parse_obj_as( - type_=GetCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> DeleteCallerResponse: - """ - Soft-delete the caller AND cascade soft-delete every memory row - pointing at it. Conversations survive (forensic / billing records) - but their caller pointer surfaces as "deleted" through the API. - - Idempotent — re-deleting an already-purged caller returns - `{caller_purged: 0, memories_purged: 0}`. Audit row counts - accompany every response so a privacy operator has direct - evidence of the purge without re-querying. - - Parameters - ---------- - id : str - Caller ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteCallerResponse - Soft-delete completed; row counts in the body. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.callers.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - DeleteCallerResponse, - parse_obj_as( - type_=DeleteCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update( - self, - id: str, - *, - display_name: typing.Optional[str] = OMIT, - external_ref: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetCallerResponse: - """ - Update the customer-editable fields on a caller. PATCH semantics: - omitted fields are unchanged, present fields overwrite. To clear - a nullable field (`display_name`, `external_ref`) pass an empty - string. `metadata` REPLACES the existing JSONB blob when supplied. - - Parameters - ---------- - id : str - Caller ID. - - display_name : typing.Optional[str] - Operator-editable display name. Empty string clears the column. - - external_ref : typing.Optional[str] - Optional handle into the customer's own CRM. Empty string clears the column. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Replacement metadata JSONB. Must not be `null`. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCallerResponse - The refreshed caller row. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.callers.update( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="PATCH", - json={ - "display_name": display_name, - "external_ref": external_ref, - "metadata": metadata, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetCallerResponse, - parse_obj_as( - type_=GetCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_memories( - self, - id: str, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[CallerMemoryItem]: - """ - List one page of memories belonging to the caller, newest first. - Soft-deleted memories AND memories whose parent caller is - soft-deleted are hidden — the GDPR purge semantics require the - API to behave as if those rows do not exist. - - Parameters - ---------- - id : str - Caller ID. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[CallerMemoryItem] - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.callers.list_memories( - id="id", - ) - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}/memories", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallerMemoriesResponse, - parse_obj_as( - type_=ListCallerMemoriesResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list_memories( - id, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.memories - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_conversations( - self, - id: str, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[Conversation]: - """ - List one page of conversations belonging to the caller, newest - started first. Same wire envelope as the workspace-wide - `GET /v1/agents/conversations`, narrowed to one caller. - - Parameters - ---------- - id : str - Caller ID. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[Conversation] - OK - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.callers.list_conversations( - id="id", - ) - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}/conversations", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallerConversationsResponse, - parse_obj_as( - type_=ListCallerConversationsResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list_conversations( - id, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.conversations - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncCallersClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, - *, - agent_id: typing.Optional[str] = None, - q: typing.Optional[str] = None, - last_seen_after: typing.Optional[dt.datetime] = None, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncPager[Caller]: - """ - List the workspace's callers, ordered by most-recently-seen first. - A caller is the per-(tenant, agent, identity) entity that owns - long-term memories and conversation history. - - Parameters - ---------- - agent_id : typing.Optional[str] - Narrow the list to callers attached to one agent. - - q : typing.Optional[str] - Identity-prefix search. Filters to rows where `identity LIKE q + '%'` - (`%`/`_` characters in the input are escaped as literals). - - last_seen_after : typing.Optional[dt.datetime] - RFC 3339 timestamp. Narrows to callers active strictly AFTER the - supplied moment. Useful for "active this week / month" filters. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncPager[Caller] - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - response = await client.agent.callers.list() - async for item in response: - yield item - # alternatively, you can paginate page-by-page - async for page in response.iter_pages(): - yield page - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/callers", - method="GET", - params={ - "agent_id": agent_id, - "q": q, - "last_seen_after": serialize_datetime(last_seen_after) if last_seen_after is not None else None, - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallersResponse, - parse_obj_as( - type_=ListCallersResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list( - agent_id=agent_id, - q=q, - last_seen_after=last_seen_after, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.callers - return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetCallerResponse: - """ - Fetch a single caller by id. Returns 404 for soft-deleted or - foreign-tenant rows — GDPR-purged callers appear as "not found" - to the API. - - Parameters - ---------- - id : str - Caller ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCallerResponse - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.callers.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetCallerResponse, - parse_obj_as( - type_=GetCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> DeleteCallerResponse: - """ - Soft-delete the caller AND cascade soft-delete every memory row - pointing at it. Conversations survive (forensic / billing records) - but their caller pointer surfaces as "deleted" through the API. - - Idempotent — re-deleting an already-purged caller returns - `{caller_purged: 0, memories_purged: 0}`. Audit row counts - accompany every response so a privacy operator has direct - evidence of the purge without re-querying. - - Parameters - ---------- - id : str - Caller ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteCallerResponse - Soft-delete completed; row counts in the body. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.callers.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - DeleteCallerResponse, - parse_obj_as( - type_=DeleteCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update( - self, - id: str, - *, - display_name: typing.Optional[str] = OMIT, - external_ref: typing.Optional[str] = OMIT, - metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetCallerResponse: - """ - Update the customer-editable fields on a caller. PATCH semantics: - omitted fields are unchanged, present fields overwrite. To clear - a nullable field (`display_name`, `external_ref`) pass an empty - string. `metadata` REPLACES the existing JSONB blob when supplied. - - Parameters - ---------- - id : str - Caller ID. - - display_name : typing.Optional[str] - Operator-editable display name. Empty string clears the column. - - external_ref : typing.Optional[str] - Optional handle into the customer's own CRM. Empty string clears the column. - - metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Replacement metadata JSONB. Must not be `null`. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCallerResponse - The refreshed caller row. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.callers.update( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}", - method="PATCH", - json={ - "display_name": display_name, - "external_ref": external_ref, - "metadata": metadata, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetCallerResponse, - parse_obj_as( - type_=GetCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_memories( - self, - id: str, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncPager[CallerMemoryItem]: - """ - List one page of memories belonging to the caller, newest first. - Soft-deleted memories AND memories whose parent caller is - soft-deleted are hidden — the GDPR purge semantics require the - API to behave as if those rows do not exist. - - Parameters - ---------- - id : str - Caller ID. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncPager[CallerMemoryItem] - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - response = await client.agent.callers.list_memories( - id="id", - ) - async for item in response: - yield item - # alternatively, you can paginate page-by-page - async for page in response.iter_pages(): - yield page - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}/memories", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallerMemoriesResponse, - parse_obj_as( - type_=ListCallerMemoriesResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list_memories( - id, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.memories - return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_conversations( - self, - id: str, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> AsyncPager[Conversation]: - """ - List one page of conversations belonging to the caller, newest - started first. Same wire envelope as the workspace-wide - `GET /v1/agents/conversations`, narrowed to one caller. - - Parameters - ---------- - id : str - Caller ID. - - cursor : typing.Optional[str] - Opaque cursor from a prior response's `next_cursor`. - - limit : typing.Optional[int] - Page size. Defaults to 50; capped at 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AsyncPager[Conversation] - OK - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - response = await client.agent.callers.list_conversations( - id="id", - ) - async for item in response: - yield item - # alternatively, you can paginate page-by-page - async for page in response.iter_pages(): - yield page - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/callers/{jsonable_encoder(id)}/conversations", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListCallerConversationsResponse, - parse_obj_as( - type_=ListCallerConversationsResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list_conversations( - id, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.conversations - return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/speechify/agent/client.py b/src/speechify/agent/client.py deleted file mode 100644 index fda375a..0000000 --- a/src/speechify/agent/client.py +++ /dev/null @@ -1,5859 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from ..core.client_wrapper import SyncClientWrapper -from .tools.client import ToolsClient -from .audio_assets.client import AudioAssetsClient -from .ivr_memory.client import IvrMemoryClient -from .callers.client import CallersClient -from .conversations.client import ConversationsClient -from .admin.client import AdminClient -from .knowledge_bases.client import KnowledgeBasesClient -from .memories.client import MemoriesClient -from .tests.client import TestsClient -from .phone_numbers.client import PhoneNumbersClient -from .sip_trunks.client import SipTrunksClient -from .outbound_calls.client import OutboundCallsClient -from .batch_calls.client import BatchCallsClient -from .flow.client import FlowClient -from ..core.request_options import RequestOptions -from ..types.list_agents_response import ListAgentsResponse -from ..core.pydantic_utilities import parse_obj_as -from ..errors.unauthorized_error import UnauthorizedError -from json.decoder import JSONDecodeError -from ..core.api_error import ApiError -from .types.create_agent_request_llm_provider import CreateAgentRequestLlmProvider -from ..types.widget_config import WidgetConfig -from ..types.amd_config import AmdConfig -from .types.create_agent_request_background_noise_preset import CreateAgentRequestBackgroundNoisePreset -from .types.create_agent_request_stt_override import CreateAgentRequestSttOverride -from ..types.agent import Agent -from ..core.serialization import convert_and_respect_annotation_metadata -from ..errors.bad_request_error import BadRequestError -from ..types.agent_voice import AgentVoice -from ..core.jsonable_encoder import jsonable_encoder -from ..errors.not_found_error import NotFoundError -from .types.update_agent_request_llm_provider import UpdateAgentRequestLlmProvider -from .types.update_agent_request_background_noise_preset import UpdateAgentRequestBackgroundNoisePreset -from .types.update_agent_request_stt_override import UpdateAgentRequestSttOverride -from ..types.attached_tools_response import AttachedToolsResponse -from ..types.evaluation_config import EvaluationConfig -from ..types.evaluation_criterion import EvaluationCriterion -from ..types.data_collection_field import DataCollectionField -from ..types.list_dynamic_variables_response import ListDynamicVariablesResponse -from ..types.dynamic_variable import DynamicVariable -from ..types.list_agent_builtins_response import ListAgentBuiltinsResponse -from ..types.system_builtin import SystemBuiltin -from ..types.agent_builtin import AgentBuiltin -from ..types.create_conversation_response import CreateConversationResponse -from ..errors.forbidden_error import ForbiddenError -from ..types.error import Error -from ..types.attached_knowledge_bases_response import AttachedKnowledgeBasesResponse -from ..types.list_memories_response import ListMemoriesResponse -from ..types.delete_memories_by_caller_response import DeleteMemoriesByCallerResponse -from ..types.list_agent_tests_response import ListAgentTestsResponse -from ..types.test_type import TestType -from .types.create_agent_test_request_config import CreateAgentTestRequestConfig -from ..types.tool_mock_config import ToolMockConfig -from ..types.agent_test import AgentTest -from ..types.test_run_config_override import TestRunConfigOverride -from ..types.run_agent_tests_response import RunAgentTestsResponse -from ..errors.internal_server_error import InternalServerError -from ..core.client_wrapper import AsyncClientWrapper -from .tools.client import AsyncToolsClient -from .audio_assets.client import AsyncAudioAssetsClient -from .ivr_memory.client import AsyncIvrMemoryClient -from .callers.client import AsyncCallersClient -from .conversations.client import AsyncConversationsClient -from .admin.client import AsyncAdminClient -from .knowledge_bases.client import AsyncKnowledgeBasesClient -from .memories.client import AsyncMemoriesClient -from .tests.client import AsyncTestsClient -from .phone_numbers.client import AsyncPhoneNumbersClient -from .sip_trunks.client import AsyncSipTrunksClient -from .outbound_calls.client import AsyncOutboundCallsClient -from .batch_calls.client import AsyncBatchCallsClient -from .flow.client import AsyncFlowClient - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class AgentClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - self.tools = ToolsClient(client_wrapper=self._client_wrapper) - self.audio_assets = AudioAssetsClient(client_wrapper=self._client_wrapper) - self.ivr_memory = IvrMemoryClient(client_wrapper=self._client_wrapper) - self.callers = CallersClient(client_wrapper=self._client_wrapper) - self.conversations = ConversationsClient(client_wrapper=self._client_wrapper) - self.admin = AdminClient(client_wrapper=self._client_wrapper) - self.knowledge_bases = KnowledgeBasesClient(client_wrapper=self._client_wrapper) - self.memories = MemoriesClient(client_wrapper=self._client_wrapper) - self.tests = TestsClient(client_wrapper=self._client_wrapper) - self.phone_numbers = PhoneNumbersClient(client_wrapper=self._client_wrapper) - self.sip_trunks = SipTrunksClient(client_wrapper=self._client_wrapper) - self.outbound_calls = OutboundCallsClient(client_wrapper=self._client_wrapper) - self.batch_calls = BatchCallsClient(client_wrapper=self._client_wrapper) - self.flow = FlowClient(client_wrapper=self._client_wrapper) - - def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListAgentsResponse: - """ - List voice agents owned by the caller. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentsResponse - A list of voice agents. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list() - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentsResponse, - parse_obj_as( - type_=ListAgentsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create( - self, - *, - name: str, - prompt: str, - first_message: str, - voice_id: str, - slug: typing.Optional[str] = OMIT, - language: typing.Optional[str] = OMIT, - llm_provider: typing.Optional[CreateAgentRequestLlmProvider] = OMIT, - llm_model: typing.Optional[str] = OMIT, - llm_base_url: typing.Optional[str] = OMIT, - llm_api_key: typing.Optional[str] = OMIT, - llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - temperature: typing.Optional[float] = OMIT, - widget_config: typing.Optional[WidgetConfig] = OMIT, - is_public: typing.Optional[bool] = OMIT, - allowed_origins: typing.Optional[typing.Sequence[str]] = OMIT, - hostname_allowlist: typing.Optional[typing.Sequence[str]] = OMIT, - memory_enabled: typing.Optional[bool] = OMIT, - memory_retention_days: typing.Optional[int] = OMIT, - webhook_url: typing.Optional[str] = OMIT, - webhook_secret: typing.Optional[str] = OMIT, - amd: typing.Optional[AmdConfig] = OMIT, - save_audio_recording: typing.Optional[bool] = OMIT, - navigator_mode: typing.Optional[bool] = OMIT, - ivr_memory_enabled: typing.Optional[bool] = OMIT, - tts_speaking_rate: typing.Optional[float] = OMIT, - tts_playback_rate: typing.Optional[float] = OMIT, - response_delay_seconds: typing.Optional[float] = OMIT, - inactivity_timeout_seconds: typing.Optional[int] = OMIT, - background_noise_preset: typing.Optional[CreateAgentRequestBackgroundNoisePreset] = OMIT, - background_noise_volume: typing.Optional[float] = OMIT, - stt_override: typing.Optional[CreateAgentRequestSttOverride] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Agent: - """ - Create a voice agent. - - Parameters - ---------- - name : str - - prompt : str - - first_message : str - Greeting spoken verbatim at session start when included in the agent's flow graph. - - voice_id : str - Voice slug from the VMS catalog (see GET /v1/voices). Required — the server rejects writes with an unknown or empty slug. - - slug : typing.Optional[str] - Optional. Server derives slug from name with a random suffix when omitted; if you supply your own, a collision returns 400 'slug already taken'. - - language : typing.Optional[str] - ISO 639-1 code. Defaults to 'en' when omitted. - - llm_provider : typing.Optional[CreateAgentRequestLlmProvider] - LLM backend. Leave empty (or omit both `llm_provider` and - `llm_model`) to use the platform default (today: Speechify - Kimi K2.6, resolved server-side at dispatch). When set, - must be paired with a non-empty `llm_model`; mixing a - populated provider with an empty model is rejected as a - 400. `custom` additionally requires `llm_base_url`. - - llm_model : typing.Optional[str] - Chat model slug. Leave empty to use the platform default. - For `openai` / `speechify` the (provider, model) pair must - be in the allowed table; for `custom` it is free-form. - - llm_base_url : typing.Optional[str] - Custom OpenAI/vLLM-compatible endpoint base URL. Required - when `llm_provider` is `custom`, rejected otherwise. - - llm_api_key : typing.Optional[str] - Bearer key for the custom endpoint. Write-only - stored - encrypted, never returned (GET exposes `llm_api_key_set`). - Optional even for `custom` (keyless endpoints); rejected - for any other provider. - - llm_extra_body : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional JSON object forwarded verbatim to the custom - endpoint as the chat.completions `extra_body` (reasoning / - sampling knobs). Valid only when `llm_provider` is - `custom`. - - temperature : typing.Optional[float] - Sampling temperature in the range 0.0–1.0. Defaults to 0.5 when omitted. - - widget_config : typing.Optional[WidgetConfig] - - is_public : typing.Optional[bool] - Defaults to false when omitted. - - allowed_origins : typing.Optional[typing.Sequence[str]] - - hostname_allowlist : typing.Optional[typing.Sequence[str]] - Optional per-agent hostname allowlist (see Agent schema). - - memory_enabled : typing.Optional[bool] - Defaults to false when omitted. - - memory_retention_days : typing.Optional[int] - Defaults to 90 when omitted. - - webhook_url : typing.Optional[str] - Customer-facing post-call webhook URL. - - webhook_secret : typing.Optional[str] - HMAC-SHA256 secret seed. Write-only — never echoed back on - reads; clients see `webhook_secret_set: true` instead. - - amd : typing.Optional[AmdConfig] - AMD routing config. Optional on create; omitted means AMD off. See AMDConfig schema. - - save_audio_recording : typing.Optional[bool] - When set, opts the agent into per-conversation audio recording. Defaults to false when omitted. - - navigator_mode : typing.Optional[bool] - When set, opts the agent into IVR-tuned turn handling. Defaults to false when omitted. - - ivr_memory_enabled : typing.Optional[bool] - When omitted, defaults to true. Set to false to opt-out of the IVR-memory cache lookup for this agent. - - tts_speaking_rate : typing.Optional[float] - - tts_playback_rate : typing.Optional[float] - Post-process pitch-preserving time-stretch on the synthesized - audio. See the field on Agent for semantics. - - response_delay_seconds : typing.Optional[float] - Per-agent override for the worker's endpointing min_delay on - the VAD path (seconds). See the field on Agent for semantics. - Range 0.0..5.0; null means use the stack default. - - inactivity_timeout_seconds : typing.Optional[int] - Per-agent silence-tolerance override in seconds. Send `0` - to clear the override and fall back to the platform - default. Negative values are rejected. - - background_noise_preset : typing.Optional[CreateAgentRequestBackgroundNoisePreset] - Pre-mixed ambient bed slug. Send empty string ("") to - disable the bed, which also clears `background_noise_volume`. - - background_noise_volume : typing.Optional[float] - Volume of the background-noise bed (0..1). Ignored when - `background_noise_preset` is empty. - - stt_override : typing.Optional[CreateAgentRequestSttOverride] - Optional non-default streaming-STT stack for this agent. - Omit to use the worker's default stack (today: whisper-v3). - See the Agent schema for the full option semantics. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The created agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.create( - name="name", - prompt="prompt", - first_message="first_message", - voice_id="voice_id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents", - method="POST", - json={ - "name": name, - "slug": slug, - "prompt": prompt, - "first_message": first_message, - "language": language, - "llm_provider": llm_provider, - "llm_model": llm_model, - "llm_base_url": llm_base_url, - "llm_api_key": llm_api_key, - "llm_extra_body": llm_extra_body, - "voice_id": voice_id, - "temperature": temperature, - "widget_config": convert_and_respect_annotation_metadata( - object_=widget_config, annotation=WidgetConfig, direction="write" - ), - "is_public": is_public, - "allowed_origins": allowed_origins, - "hostname_allowlist": hostname_allowlist, - "memory_enabled": memory_enabled, - "memory_retention_days": memory_retention_days, - "webhook_url": webhook_url, - "webhook_secret": webhook_secret, - "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"), - "save_audio_recording": save_audio_recording, - "navigator_mode": navigator_mode, - "ivr_memory_enabled": ivr_memory_enabled, - "tts_speaking_rate": tts_speaking_rate, - "tts_playback_rate": tts_playback_rate, - "response_delay_seconds": response_delay_seconds, - "inactivity_timeout_seconds": inactivity_timeout_seconds, - "background_noise_preset": background_noise_preset, - "background_noise_volume": background_noise_volume, - "stt_override": stt_override, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_agent_voices(self, *, request_options: typing.Optional[RequestOptions] = None) -> typing.List[AgentVoice]: - """ - List the curated voice catalogue available for voice agents. - Matches the `ai-api-agents` VMS scope one-for-one, so the same - slug set is accepted by POST/PATCH /v1/agents. Personal - (cloned) voices are NOT included — they stay on - `GET /v1/voices`. The JSON layout intentionally mirrors the - TTS `/v1/voices` shape so the console feeds both endpoints - into the same voice-picker component. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[AgentVoice] - The curated agent voice catalogue. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_agent_voices() - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/voices", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[AgentVoice], - parse_obj_as( - type_=typing.List[AgentVoice], # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Agent: - """ - Retrieve a voice agent by ID. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The requested agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Delete a voice agent. Conversations and attached tools remain. Tests whose only agent is this one are deleted with it; tests also attached to other agents survive, minus the attachment. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update( - self, - id: str, - *, - name: typing.Optional[str] = OMIT, - prompt: typing.Optional[str] = OMIT, - first_message: typing.Optional[str] = OMIT, - language: typing.Optional[str] = OMIT, - llm_provider: typing.Optional[UpdateAgentRequestLlmProvider] = OMIT, - llm_model: typing.Optional[str] = OMIT, - llm_base_url: typing.Optional[str] = OMIT, - llm_api_key: typing.Optional[str] = OMIT, - llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - voice_id: typing.Optional[str] = OMIT, - temperature: typing.Optional[float] = OMIT, - widget_config: typing.Optional[WidgetConfig] = OMIT, - is_public: typing.Optional[bool] = OMIT, - allowed_origins: typing.Optional[typing.Sequence[str]] = OMIT, - hostname_allowlist: typing.Optional[typing.Sequence[str]] = OMIT, - memory_enabled: typing.Optional[bool] = OMIT, - memory_retention_days: typing.Optional[int] = OMIT, - webhook_url: typing.Optional[str] = OMIT, - webhook_secret: typing.Optional[str] = OMIT, - amd: typing.Optional[AmdConfig] = OMIT, - save_audio_recording: typing.Optional[bool] = OMIT, - navigator_mode: typing.Optional[bool] = OMIT, - ivr_memory_enabled: typing.Optional[bool] = OMIT, - tts_speaking_rate: typing.Optional[float] = OMIT, - clear_tts_speaking_rate: typing.Optional[bool] = OMIT, - tts_playback_rate: typing.Optional[float] = OMIT, - clear_tts_playback_rate: typing.Optional[bool] = OMIT, - response_delay_seconds: typing.Optional[float] = OMIT, - clear_response_delay_seconds: typing.Optional[bool] = OMIT, - inactivity_timeout_seconds: typing.Optional[int] = OMIT, - background_noise_preset: typing.Optional[UpdateAgentRequestBackgroundNoisePreset] = OMIT, - background_noise_volume: typing.Optional[float] = OMIT, - stt_override: typing.Optional[UpdateAgentRequestSttOverride] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Agent: - """ - Update a voice agent. Only fields present on the request body are changed. - - Parameters - ---------- - id : str - - name : typing.Optional[str] - - prompt : typing.Optional[str] - - first_message : typing.Optional[str] - - language : typing.Optional[str] - - llm_provider : typing.Optional[UpdateAgentRequestLlmProvider] - LLM backend. Send an empty string together with - `llm_model: ""` to clear the pair to the platform default - (today: Speechify Kimi K2.6). Sending one populated and - one empty is rejected as a 400. Omit both to leave the - stored pair unchanged. Switching to a non-`custom` provider - clears any stored `llm_base_url` / `llm_api_key` / - `llm_extra_body`. - - llm_model : typing.Optional[str] - Chat model slug. Empty string + empty `llm_provider` - clears the pair to the platform default. For `openai` / - `speechify` the (provider, model) pair must be in the - allowed table; for `custom` it is free-form. - - llm_base_url : typing.Optional[str] - Custom-endpoint base URL. Required when the resulting - provider is `custom`, rejected otherwise. - - llm_api_key : typing.Optional[str] - Bearer key for the custom endpoint. Write-only. Omit to - keep the stored key, send "" to clear it, send a value to - replace it. Rejected for non-`custom` providers. - - llm_extra_body : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - JSON object forwarded to the custom endpoint as - chat.completions `extra_body`. Omit to leave unchanged; - a JSON object (including `{}`) replaces it. Valid only - when the resulting provider is `custom`. - - voice_id : typing.Optional[str] - - temperature : typing.Optional[float] - Sampling temperature in the range 0.0–1.0. Omit to leave unchanged. - - widget_config : typing.Optional[WidgetConfig] - - is_public : typing.Optional[bool] - - allowed_origins : typing.Optional[typing.Sequence[str]] - - hostname_allowlist : typing.Optional[typing.Sequence[str]] - When supplied, replaces the stored list. Pass an empty - array to clear enforcement (public agent is open again). - Omit the field to leave the existing value unchanged. - - memory_enabled : typing.Optional[bool] - - memory_retention_days : typing.Optional[int] - - webhook_url : typing.Optional[str] - - webhook_secret : typing.Optional[str] - Rotate the HMAC secret. Write-only. - - amd : typing.Optional[AmdConfig] - AMD routing config (PATCH-replace, wholesale). Omit to leave the stored config unchanged. - - save_audio_recording : typing.Optional[bool] - - navigator_mode : typing.Optional[bool] - - ivr_memory_enabled : typing.Optional[bool] - Per-agent kill switch for the IVR-memory cache lookup. nil/omit = unchanged. - - tts_speaking_rate : typing.Optional[float] - - clear_tts_speaking_rate : typing.Optional[bool] - Two-headed clear: PATCH cannot distinguish "absent" from - "explicit null" reliably across stacks. Setting this to - `true` resets `tts_speaking_rate` to the voice default. - If both are sent, `clear_tts_speaking_rate` wins. - - tts_playback_rate : typing.Optional[float] - - clear_tts_playback_rate : typing.Optional[bool] - Two-headed clear, mirroring `clear_tts_speaking_rate`. - Setting this to `true` resets `tts_playback_rate` to null - (no post-process). If both fields are sent, - `clear_tts_playback_rate` wins. - - response_delay_seconds : typing.Optional[float] - Per-agent silence-wait override (seconds). See the field - on Agent for semantics. Range 0.0..5.0; null is allowed - but `clear_response_delay_seconds=true` is the canonical - way to revert to the stack default. - - clear_response_delay_seconds : typing.Optional[bool] - Two-headed clear, mirroring `clear_tts_playback_rate`. - Setting this to `true` resets `response_delay_seconds` to - null (revert to the stack default). If both are sent, - `clear_response_delay_seconds` wins. - - inactivity_timeout_seconds : typing.Optional[int] - Per-agent silence-tolerance override. Send `0` to clear - the override and fall back to the platform default. - Negative values are rejected. - - background_noise_preset : typing.Optional[UpdateAgentRequestBackgroundNoisePreset] - Pre-mixed ambient bed slug. Send empty string ("") to - disable the bed, which also clears `background_noise_volume`. - - background_noise_volume : typing.Optional[float] - Volume of the background-noise bed (0..1). Ignored when - the preset is empty; clearing the preset also clears - this field server-side. - - stt_override : typing.Optional[UpdateAgentRequestSttOverride] - Streaming-STT stack override. Send an empty string ("") to - clear the override and fall back to the worker default - (today: whisper-v3). Any non-empty value must be a known - stack name. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The updated agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.update( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="PATCH", - json={ - "name": name, - "prompt": prompt, - "first_message": first_message, - "language": language, - "llm_provider": llm_provider, - "llm_model": llm_model, - "llm_base_url": llm_base_url, - "llm_api_key": llm_api_key, - "llm_extra_body": llm_extra_body, - "voice_id": voice_id, - "temperature": temperature, - "widget_config": convert_and_respect_annotation_metadata( - object_=widget_config, annotation=WidgetConfig, direction="write" - ), - "is_public": is_public, - "allowed_origins": allowed_origins, - "hostname_allowlist": hostname_allowlist, - "memory_enabled": memory_enabled, - "memory_retention_days": memory_retention_days, - "webhook_url": webhook_url, - "webhook_secret": webhook_secret, - "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"), - "save_audio_recording": save_audio_recording, - "navigator_mode": navigator_mode, - "ivr_memory_enabled": ivr_memory_enabled, - "tts_speaking_rate": tts_speaking_rate, - "clear_tts_speaking_rate": clear_tts_speaking_rate, - "tts_playback_rate": tts_playback_rate, - "clear_tts_playback_rate": clear_tts_playback_rate, - "response_delay_seconds": response_delay_seconds, - "clear_response_delay_seconds": clear_response_delay_seconds, - "inactivity_timeout_seconds": inactivity_timeout_seconds, - "background_noise_preset": background_noise_preset, - "background_noise_volume": background_noise_volume, - "stt_override": stt_override, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_tools(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AttachedToolsResponse: - """ - List tools currently attached to the agent. Bare list — an - agent's tool attachment count is bounded by configuration, so - this endpoint does not paginate. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedToolsResponse - Attached tools for the agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_tools( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AttachedToolsResponse, - parse_obj_as( - type_=AttachedToolsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def attach_tool(self, id: str, tool_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Attach an existing tool to the agent so the LLM can call it. - - Parameters - ---------- - id : str - - tool_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.attach_tool( - id="id", - tool_id="toolId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools/{jsonable_encoder(tool_id)}", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def detach_tool(self, id: str, tool_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Detach a tool from the agent. - - Parameters - ---------- - id : str - - tool_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.detach_tool( - id="id", - tool_id="toolId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools/{jsonable_encoder(tool_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_evaluation_config( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EvaluationConfig: - """ - Retrieve the agent's post-call evaluation criteria + data-collection config. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EvaluationConfig - The evaluation config for the agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.get_evaluation_config( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/evaluation-config", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - EvaluationConfig, - parse_obj_as( - type_=EvaluationConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_evaluation_config( - self, - id: str, - *, - criteria: typing.Sequence[EvaluationCriterion], - data_collection: typing.Sequence[DataCollectionField], - request_options: typing.Optional[RequestOptions] = None, - ) -> EvaluationConfig: - """ - Replace the agent's evaluation criteria + data-collection fields. - - Parameters - ---------- - id : str - - criteria : typing.Sequence[EvaluationCriterion] - - data_collection : typing.Sequence[DataCollectionField] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EvaluationConfig - The updated evaluation config. - - Examples - -------- - from speechify import DataCollectionField, EvaluationCriterion, Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.update_evaluation_config( - id="id", - criteria=[ - EvaluationCriterion( - id="id", - name="name", - description="description", - ) - ], - data_collection=[ - DataCollectionField( - key="key", - description="description", - type="string", - ) - ], - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/evaluation-config", - method="PATCH", - json={ - "criteria": convert_and_respect_annotation_metadata( - object_=criteria, annotation=typing.Sequence[EvaluationCriterion], direction="write" - ), - "data_collection": convert_and_respect_annotation_metadata( - object_=data_collection, annotation=typing.Sequence[DataCollectionField], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - EvaluationConfig, - parse_obj_as( - type_=EvaluationConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_dynamic_variables( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListDynamicVariablesResponse: - """ - Retrieve the agent's customer-scope dynamic variables and the read-only - catalogue of reserved `system__*` keys. The system variables list is - provided so editor UIs can render the reference list without maintaining - a client-side copy of the catalogue. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListDynamicVariablesResponse - The agent's variable catalogue. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.get_dynamic_variables( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/variables", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListDynamicVariablesResponse, - parse_obj_as( - type_=ListDynamicVariablesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_dynamic_variables( - self, - id: str, - *, - variables: typing.Sequence[DynamicVariable], - request_options: typing.Optional[RequestOptions] = None, - ) -> ListDynamicVariablesResponse: - """ - Replace the agent's customer-scope dynamic variable definitions. - The supplied list overwrites the stored list wholesale (same - semantics as `updateEvaluationConfig`). Pass an empty array to - clear all variables. Up to 20 variables per agent. Keys must - match `[a-zA-Z0-9_]+` and must not start with the reserved - `system__` prefix. - - Parameters - ---------- - id : str - - variables : typing.Sequence[DynamicVariable] - The new variable list. Replaces the existing list entirely. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListDynamicVariablesResponse - The updated variable catalogue. - - Examples - -------- - from speechify import DynamicVariable, Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.update_dynamic_variables( - id="id", - variables=[ - DynamicVariable( - key="product_name", - type="string", - default="Speechify", - description="Product the agent is supporting.", - ), - DynamicVariable( - key="support_tier", - type="number", - default=1, - ), - DynamicVariable( - key="account_metadata", - type="json", - description="Arbitrary account context injected into tool bodies.", - ), - ], - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/variables", - method="PATCH", - json={ - "variables": convert_and_respect_annotation_metadata( - object_=variables, annotation=typing.Sequence[DynamicVariable], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListDynamicVariablesResponse, - parse_obj_as( - type_=ListDynamicVariablesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_builtins( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListAgentBuiltinsResponse: - """ - List every builtin instance configured on this agent. Each row - is one instance of a worker-resident capability (`end_call`, - `play_audio`, etc.) bound to this specific agent with its own - LLM-facing name, description, and per-call config. Same builtin - may appear N times on one agent — typically two `play_audio` - rows bound to different audio assets. - - Parameters - ---------- - id : str - Agent ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentBuiltinsResponse - The agent's builtin instances. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_builtins( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentBuiltinsResponse, - parse_obj_as( - type_=ListAgentBuiltinsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_builtin( - self, - id: str, - *, - builtin: SystemBuiltin, - name: str, - description: typing.Optional[str] = OMIT, - config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - params: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT, - enabled: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentBuiltin: - """ - Create a new builtin instance on this agent. `builtin` must - resolve to one of the names returned by - `GET /v1/agents/tools/system-builtins`; unknown values are rejected. - `name` is the LLM-facing identifier the model uses to call the - tool; it must match the tool-name regex and be unique within - the agent's builtin set. - - Parameters - ---------- - id : str - Agent ID. - - builtin : SystemBuiltin - - name : str - LLM-facing tool name. Must match the tool-name regex and be unique within the agent's builtin set. - - description : typing.Optional[str] - - config : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-instance configuration matching the per-builtin schema. - - params : typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] - Per-call parameter descriptors. - - enabled : typing.Optional[bool] - Defaults to true on the server when omitted. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The created builtin instance. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.create_builtin( - id="id", - builtin="builtin", - name="name", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins", - method="POST", - json={ - "builtin": builtin, - "name": name, - "description": description, - "config": config, - "params": params, - "enabled": enabled, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_builtin( - self, id: str, builtin_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AgentBuiltin: - """ - Fetch one builtin instance by ID. - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The builtin instance. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.get_builtin( - id="id", - builtin_id="builtinId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_builtin( - self, id: str, builtin_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a builtin instance from this agent. Idempotent on - already-deleted ids (404). Does NOT detach references from - flow nodes that name the instance; the worker logs and skips - on missing-row at session start (fail-soft). - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.delete_builtin( - id="id", - builtin_id="builtinId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_builtin( - self, - id: str, - builtin_id: str, - *, - name: typing.Optional[str] = OMIT, - description: typing.Optional[str] = OMIT, - config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - params: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT, - enabled: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentBuiltin: - """ - Update a builtin instance. All fields optional; omitting a - field leaves it unchanged. The underlying `builtin` (which - capability the instance maps to) is intentionally NOT - patchable — change of identity would surprise the worker, so - the customer should delete and recreate instead. - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - name : typing.Optional[str] - - description : typing.Optional[str] - - config : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-instance configuration matching the per-builtin schema. - - params : typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] - Per-call parameter descriptors. - - enabled : typing.Optional[bool] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The updated builtin instance. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.update_builtin( - id="id", - builtin_id="builtinId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="PATCH", - json={ - "name": name, - "description": description, - "config": config, - "params": params, - "enabled": enabled, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_conversation( - self, - id: str, - *, - transport: typing.Optional[str] = OMIT, - dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateConversationResponse: - """ - Start a new voice conversation with the agent. Returns a realtime - voice session + short-lived client token so the caller can - connect the audio pipeline directly. The agent is dispatched - server-side; no additional client action required. - - Pass `dynamic_variables` to supply per-session values that override - the agent's stored variable defaults for this one conversation. - Keys in the `system__` namespace are rejected at this boundary. - - Parameters - ---------- - id : str - - transport : typing.Optional[str] - Transport hint. Omit to use the agent's default. - - dynamic_variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-session variable overrides that merge on top of the agent's - stored variable defaults for this one conversation. Keys in the - reserved `system__` namespace are rejected. Values must match the - declared type of the corresponding variable definition on the agent. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateConversationResponse - The created conversation with its realtime session token. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.create_conversation( - id="agent_01HS...", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/conversations", - method="POST", - json={ - "transport": transport, - "dynamic_variables": dynamic_variables, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateConversationResponse, - parse_obj_as( - type_=CreateConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_session( - self, - id: str, - *, - user_identity: typing.Optional[str] = OMIT, - dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateConversationResponse: - """ - Mint a realtime voice session for the given agent. Widget-friendly - counterpart to `createConversation` — same response shape, dual - authentication: - - * **Authenticated (Bearer)**: works for any agent the caller - owns. Typical server-to-server flow where the embedding - site's backend mints a token and hands it to the browser so - the API key never reaches the client. - * **Unauthenticated**: works only when `agent.is_public = true` - AND the request's `Origin` header matches `agent.allowed_origins` - (or that list is empty). When `agent.hostname_allowlist` is - non-empty, the `Origin` hostname must additionally be a - member of that list. Used directly by the - `` web component. - - Responds with the same `CreateConversationResponse` as - `createConversation`. - - Parameters - ---------- - id : str - - user_identity : typing.Optional[str] - Opaque identifier for the end-user (e.g. your app's user ID). Stamped onto the conversation. Optional - defaults to an anonymous per-session ID. - - dynamic_variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-session variable overrides that merge on top of the agent's - stored variable defaults for this one session. Keys in the - reserved `system__` namespace are rejected at this boundary. - Values must match the declared type of the corresponding variable - definition on the agent (a `string` type expects a JSON string, - `number` expects a JSON number, etc.). - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateConversationResponse - The created session with its realtime token + URL. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.create_session( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/sessions", - method="POST", - json={ - "user_identity": user_identity, - "dynamic_variables": dynamic_variables, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateConversationResponse, - parse_obj_as( - type_=CreateConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_agent_knowledge_bases( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AttachedKnowledgeBasesResponse: - """ - List knowledge bases attached to an agent. Bare list — the - attachment count is bounded by configuration, not by data - scale, so this endpoint does not paginate. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedKnowledgeBasesResponse - The knowledge bases attached to the agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_agent_knowledge_bases( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AttachedKnowledgeBasesResponse, - parse_obj_as( - type_=AttachedKnowledgeBasesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def attach_knowledge_base( - self, id: str, kb_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Attach a knowledge base to an agent. The `search_knowledge` tool - is auto-registered on the next conversation and can only query the - attached knowledge bases. - - Parameters - ---------- - id : str - - kb_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.attach_knowledge_base( - id="id", - kb_id="kbId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases/{jsonable_encoder(kb_id)}", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def detach_knowledge_base( - self, id: str, kb_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Detach a knowledge base from an agent. - - Parameters - ---------- - id : str - - kb_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.detach_knowledge_base( - id="id", - kb_id="kbId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases/{jsonable_encoder(kb_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_memories( - self, - id: str, - *, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ListMemoriesResponse: - """ - List per-caller memories extracted for an agent. Memories are - written post-call by the built-in extractor when `memory_enabled` - is true on the agent; the list is sorted newest-first. - - Parameters - ---------- - id : str - - limit : typing.Optional[int] - Maximum rows to return. Defaults to 100, capped at 200. - - offset : typing.Optional[int] - Number of rows to skip. Combine with `limit` to page through older memories. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListMemoriesResponse - Memories for the agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_memories( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/memories", - method="GET", - params={ - "limit": limit, - "offset": offset, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListMemoriesResponse, - parse_obj_as( - type_=ListMemoriesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_memories_by_caller( - self, id: str, *, agent_id: str, caller_identity: str, request_options: typing.Optional[RequestOptions] = None - ) -> DeleteMemoriesByCallerResponse: - """ - Delete every memory ever extracted for a specific caller on - this agent. Privacy / GDPR surface. Returns the count of rows - soft-deleted; rows become permanently unreachable immediately - and are hard-deleted by the retention job after the tenant's - configured retention window. - - Parameters - ---------- - id : str - - agent_id : str - - caller_identity : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteMemoriesByCallerResponse - Deletion summary. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.delete_memories_by_caller( - id="id", - agent_id="agent_id", - caller_identity="caller_identity", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/memories/delete", - method="POST", - json={ - "agent_id": agent_id, - "caller_identity": caller_identity, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - DeleteMemoriesByCallerResponse, - parse_obj_as( - type_=DeleteMemoriesByCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_tests(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> ListAgentTestsResponse: - """ - List all tests configured for the agent. Each entry includes the - most recent run so the console can render pass/fail badges without - an extra round-trip. - - Parameters - ---------- - id : str - Agent ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentTestsResponse - Tests for the agent with last-run summaries. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.list_tests( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentTestsResponse, - parse_obj_as( - type_=ListAgentTestsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_test( - self, - id: str, - *, - name: str, - type: TestType, - config: CreateAgentTestRequestConfig, - description: typing.Optional[str] = OMIT, - tool_mock_config: typing.Optional[ToolMockConfig] = OMIT, - variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - folder_id: typing.Optional[str] = OMIT, - attached_agent_ids: typing.Optional[typing.Sequence[str]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentTest: - """ - Create a new test for the agent. - - Parameters - ---------- - id : str - Agent ID. - - name : str - Short human-readable label for the test. - - type : TestType - - config : CreateAgentTestRequestConfig - Type-specific configuration. Must match the shape for the given `type`. - - description : typing.Optional[str] - Optional longer description of what this test verifies. - - tool_mock_config : typing.Optional[ToolMockConfig] - Optional tool-mocking config applied during every run of this test. - - variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-test variable values substituted into string fields of the - config at run-start. Keys use the same rules as agent-level - `DynamicVariable` keys. - - folder_id : typing.Optional[str] - Prefixed wire identifier (`folder_<26 char Crockford base32>`) - of the folder to place the test in. Omit / null for root. - - attached_agent_ids : typing.Optional[typing.Sequence[str]] - Optional list of additional agents this test should also run - against. The owner agent (path param) is always attached - implicitly. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentTest - The created test. - - Examples - -------- - from speechify import ReplyConfig, Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.create_test( - id="agent_01HS...", - name="Greet caller by name", - description="Agent should use the caller's name when it is provided.", - type="reply", - config=ReplyConfig( - context="Hi, I am Alice. I need help with my order.", - success_criteria="The agent addresses Alice by name in its response.", - success_examples=[ - "Hi Alice! I would be happy to help with your order.", - "Sure thing, Alice - let me look that up for you.", - ], - failure_examples=[ - "Hello! How can I help you today?", - "I can help you with that order.", - ], - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests", - method="POST", - json={ - "name": name, - "description": description, - "type": type, - "config": convert_and_respect_annotation_metadata( - object_=config, annotation=CreateAgentTestRequestConfig, direction="write" - ), - "tool_mock_config": convert_and_respect_annotation_metadata( - object_=tool_mock_config, annotation=ToolMockConfig, direction="write" - ), - "variables": variables, - "folder_id": folder_id, - "attached_agent_ids": attached_agent_ids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentTest, - parse_obj_as( - type_=AgentTest, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def run_all_tests( - self, - id: str, - *, - config_override: typing.Optional[TestRunConfigOverride] = OMIT, - flow_version_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> RunAgentTestsResponse: - """ - Enqueue runs for every test on the agent concurrently. Up to 50 - tests are dispatched in one call. Each returned run starts in - `queued` status; poll `GET /v1/agents/tests/runs/{id}` for the terminal - result. - - An optional request body runs the whole suite against - a proposed config: a `config_override` (prompt / model / tools) - applied to every test without editing the tests, and/or a - `flow_version_id` to target a specific flow version instead of - the agent's active flow. Omit the body to run against the - agent's live config and active flow. - - Parameters - ---------- - id : str - Agent ID. - - config_override : typing.Optional[TestRunConfigOverride] - - flow_version_id : typing.Optional[str] - Targets a specific flow version (an `agent_versions` row) - instead of the agent's active flow — version-targeted - regression. Must be a flow version of the agent under test. - Raw UUID; flow versions carry no prefixed wire id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - RunAgentTestsResponse - Queued runs for all tests on the agent. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.run_all_tests( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests/runs", - method="POST", - json={ - "config_override": convert_and_respect_annotation_metadata( - object_=config_override, annotation=TestRunConfigOverride, direction="write" - ), - "flow_version_id": flow_version_id, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - RunAgentTestsResponse, - parse_obj_as( - type_=RunAgentTestsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_widget_config(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> WidgetConfig: - """ - Return the embed-widget appearance config for an agent. Works - unauthenticated for public agents; the body is cosmetic only. - - Parameters - ---------- - id : str - Prefixed agent id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - WidgetConfig - The agent's widget configuration. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.get_widget_config( - id="agent_01k7m6etzwf057j6w0zmdsgppr", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/widget-config", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - WidgetConfig, - parse_obj_as( - type_=WidgetConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncAgentClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - self.tools = AsyncToolsClient(client_wrapper=self._client_wrapper) - self.audio_assets = AsyncAudioAssetsClient(client_wrapper=self._client_wrapper) - self.ivr_memory = AsyncIvrMemoryClient(client_wrapper=self._client_wrapper) - self.callers = AsyncCallersClient(client_wrapper=self._client_wrapper) - self.conversations = AsyncConversationsClient(client_wrapper=self._client_wrapper) - self.admin = AsyncAdminClient(client_wrapper=self._client_wrapper) - self.knowledge_bases = AsyncKnowledgeBasesClient(client_wrapper=self._client_wrapper) - self.memories = AsyncMemoriesClient(client_wrapper=self._client_wrapper) - self.tests = AsyncTestsClient(client_wrapper=self._client_wrapper) - self.phone_numbers = AsyncPhoneNumbersClient(client_wrapper=self._client_wrapper) - self.sip_trunks = AsyncSipTrunksClient(client_wrapper=self._client_wrapper) - self.outbound_calls = AsyncOutboundCallsClient(client_wrapper=self._client_wrapper) - self.batch_calls = AsyncBatchCallsClient(client_wrapper=self._client_wrapper) - self.flow = AsyncFlowClient(client_wrapper=self._client_wrapper) - - async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListAgentsResponse: - """ - List voice agents owned by the caller. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentsResponse - A list of voice agents. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentsResponse, - parse_obj_as( - type_=ListAgentsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create( - self, - *, - name: str, - prompt: str, - first_message: str, - voice_id: str, - slug: typing.Optional[str] = OMIT, - language: typing.Optional[str] = OMIT, - llm_provider: typing.Optional[CreateAgentRequestLlmProvider] = OMIT, - llm_model: typing.Optional[str] = OMIT, - llm_base_url: typing.Optional[str] = OMIT, - llm_api_key: typing.Optional[str] = OMIT, - llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - temperature: typing.Optional[float] = OMIT, - widget_config: typing.Optional[WidgetConfig] = OMIT, - is_public: typing.Optional[bool] = OMIT, - allowed_origins: typing.Optional[typing.Sequence[str]] = OMIT, - hostname_allowlist: typing.Optional[typing.Sequence[str]] = OMIT, - memory_enabled: typing.Optional[bool] = OMIT, - memory_retention_days: typing.Optional[int] = OMIT, - webhook_url: typing.Optional[str] = OMIT, - webhook_secret: typing.Optional[str] = OMIT, - amd: typing.Optional[AmdConfig] = OMIT, - save_audio_recording: typing.Optional[bool] = OMIT, - navigator_mode: typing.Optional[bool] = OMIT, - ivr_memory_enabled: typing.Optional[bool] = OMIT, - tts_speaking_rate: typing.Optional[float] = OMIT, - tts_playback_rate: typing.Optional[float] = OMIT, - response_delay_seconds: typing.Optional[float] = OMIT, - inactivity_timeout_seconds: typing.Optional[int] = OMIT, - background_noise_preset: typing.Optional[CreateAgentRequestBackgroundNoisePreset] = OMIT, - background_noise_volume: typing.Optional[float] = OMIT, - stt_override: typing.Optional[CreateAgentRequestSttOverride] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Agent: - """ - Create a voice agent. - - Parameters - ---------- - name : str - - prompt : str - - first_message : str - Greeting spoken verbatim at session start when included in the agent's flow graph. - - voice_id : str - Voice slug from the VMS catalog (see GET /v1/voices). Required — the server rejects writes with an unknown or empty slug. - - slug : typing.Optional[str] - Optional. Server derives slug from name with a random suffix when omitted; if you supply your own, a collision returns 400 'slug already taken'. - - language : typing.Optional[str] - ISO 639-1 code. Defaults to 'en' when omitted. - - llm_provider : typing.Optional[CreateAgentRequestLlmProvider] - LLM backend. Leave empty (or omit both `llm_provider` and - `llm_model`) to use the platform default (today: Speechify - Kimi K2.6, resolved server-side at dispatch). When set, - must be paired with a non-empty `llm_model`; mixing a - populated provider with an empty model is rejected as a - 400. `custom` additionally requires `llm_base_url`. - - llm_model : typing.Optional[str] - Chat model slug. Leave empty to use the platform default. - For `openai` / `speechify` the (provider, model) pair must - be in the allowed table; for `custom` it is free-form. - - llm_base_url : typing.Optional[str] - Custom OpenAI/vLLM-compatible endpoint base URL. Required - when `llm_provider` is `custom`, rejected otherwise. - - llm_api_key : typing.Optional[str] - Bearer key for the custom endpoint. Write-only - stored - encrypted, never returned (GET exposes `llm_api_key_set`). - Optional even for `custom` (keyless endpoints); rejected - for any other provider. - - llm_extra_body : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Optional JSON object forwarded verbatim to the custom - endpoint as the chat.completions `extra_body` (reasoning / - sampling knobs). Valid only when `llm_provider` is - `custom`. - - temperature : typing.Optional[float] - Sampling temperature in the range 0.0–1.0. Defaults to 0.5 when omitted. - - widget_config : typing.Optional[WidgetConfig] - - is_public : typing.Optional[bool] - Defaults to false when omitted. - - allowed_origins : typing.Optional[typing.Sequence[str]] - - hostname_allowlist : typing.Optional[typing.Sequence[str]] - Optional per-agent hostname allowlist (see Agent schema). - - memory_enabled : typing.Optional[bool] - Defaults to false when omitted. - - memory_retention_days : typing.Optional[int] - Defaults to 90 when omitted. - - webhook_url : typing.Optional[str] - Customer-facing post-call webhook URL. - - webhook_secret : typing.Optional[str] - HMAC-SHA256 secret seed. Write-only — never echoed back on - reads; clients see `webhook_secret_set: true` instead. - - amd : typing.Optional[AmdConfig] - AMD routing config. Optional on create; omitted means AMD off. See AMDConfig schema. - - save_audio_recording : typing.Optional[bool] - When set, opts the agent into per-conversation audio recording. Defaults to false when omitted. - - navigator_mode : typing.Optional[bool] - When set, opts the agent into IVR-tuned turn handling. Defaults to false when omitted. - - ivr_memory_enabled : typing.Optional[bool] - When omitted, defaults to true. Set to false to opt-out of the IVR-memory cache lookup for this agent. - - tts_speaking_rate : typing.Optional[float] - - tts_playback_rate : typing.Optional[float] - Post-process pitch-preserving time-stretch on the synthesized - audio. See the field on Agent for semantics. - - response_delay_seconds : typing.Optional[float] - Per-agent override for the worker's endpointing min_delay on - the VAD path (seconds). See the field on Agent for semantics. - Range 0.0..5.0; null means use the stack default. - - inactivity_timeout_seconds : typing.Optional[int] - Per-agent silence-tolerance override in seconds. Send `0` - to clear the override and fall back to the platform - default. Negative values are rejected. - - background_noise_preset : typing.Optional[CreateAgentRequestBackgroundNoisePreset] - Pre-mixed ambient bed slug. Send empty string ("") to - disable the bed, which also clears `background_noise_volume`. - - background_noise_volume : typing.Optional[float] - Volume of the background-noise bed (0..1). Ignored when - `background_noise_preset` is empty. - - stt_override : typing.Optional[CreateAgentRequestSttOverride] - Optional non-default streaming-STT stack for this agent. - Omit to use the worker's default stack (today: whisper-v3). - See the Agent schema for the full option semantics. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The created agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.create( - name="name", - prompt="prompt", - first_message="first_message", - voice_id="voice_id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents", - method="POST", - json={ - "name": name, - "slug": slug, - "prompt": prompt, - "first_message": first_message, - "language": language, - "llm_provider": llm_provider, - "llm_model": llm_model, - "llm_base_url": llm_base_url, - "llm_api_key": llm_api_key, - "llm_extra_body": llm_extra_body, - "voice_id": voice_id, - "temperature": temperature, - "widget_config": convert_and_respect_annotation_metadata( - object_=widget_config, annotation=WidgetConfig, direction="write" - ), - "is_public": is_public, - "allowed_origins": allowed_origins, - "hostname_allowlist": hostname_allowlist, - "memory_enabled": memory_enabled, - "memory_retention_days": memory_retention_days, - "webhook_url": webhook_url, - "webhook_secret": webhook_secret, - "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"), - "save_audio_recording": save_audio_recording, - "navigator_mode": navigator_mode, - "ivr_memory_enabled": ivr_memory_enabled, - "tts_speaking_rate": tts_speaking_rate, - "tts_playback_rate": tts_playback_rate, - "response_delay_seconds": response_delay_seconds, - "inactivity_timeout_seconds": inactivity_timeout_seconds, - "background_noise_preset": background_noise_preset, - "background_noise_volume": background_noise_volume, - "stt_override": stt_override, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_agent_voices( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.List[AgentVoice]: - """ - List the curated voice catalogue available for voice agents. - Matches the `ai-api-agents` VMS scope one-for-one, so the same - slug set is accepted by POST/PATCH /v1/agents. Personal - (cloned) voices are NOT included — they stay on - `GET /v1/voices`. The JSON layout intentionally mirrors the - TTS `/v1/voices` shape so the console feeds both endpoints - into the same voice-picker component. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - typing.List[AgentVoice] - The curated agent voice catalogue. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_agent_voices() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/agents/voices", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - typing.List[AgentVoice], - parse_obj_as( - type_=typing.List[AgentVoice], # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Agent: - """ - Retrieve a voice agent by ID. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The requested agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None: - """ - Delete a voice agent. Conversations and attached tools remain. Tests whose only agent is this one are deleted with it; tests also attached to other agents survive, minus the attachment. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update( - self, - id: str, - *, - name: typing.Optional[str] = OMIT, - prompt: typing.Optional[str] = OMIT, - first_message: typing.Optional[str] = OMIT, - language: typing.Optional[str] = OMIT, - llm_provider: typing.Optional[UpdateAgentRequestLlmProvider] = OMIT, - llm_model: typing.Optional[str] = OMIT, - llm_base_url: typing.Optional[str] = OMIT, - llm_api_key: typing.Optional[str] = OMIT, - llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - voice_id: typing.Optional[str] = OMIT, - temperature: typing.Optional[float] = OMIT, - widget_config: typing.Optional[WidgetConfig] = OMIT, - is_public: typing.Optional[bool] = OMIT, - allowed_origins: typing.Optional[typing.Sequence[str]] = OMIT, - hostname_allowlist: typing.Optional[typing.Sequence[str]] = OMIT, - memory_enabled: typing.Optional[bool] = OMIT, - memory_retention_days: typing.Optional[int] = OMIT, - webhook_url: typing.Optional[str] = OMIT, - webhook_secret: typing.Optional[str] = OMIT, - amd: typing.Optional[AmdConfig] = OMIT, - save_audio_recording: typing.Optional[bool] = OMIT, - navigator_mode: typing.Optional[bool] = OMIT, - ivr_memory_enabled: typing.Optional[bool] = OMIT, - tts_speaking_rate: typing.Optional[float] = OMIT, - clear_tts_speaking_rate: typing.Optional[bool] = OMIT, - tts_playback_rate: typing.Optional[float] = OMIT, - clear_tts_playback_rate: typing.Optional[bool] = OMIT, - response_delay_seconds: typing.Optional[float] = OMIT, - clear_response_delay_seconds: typing.Optional[bool] = OMIT, - inactivity_timeout_seconds: typing.Optional[int] = OMIT, - background_noise_preset: typing.Optional[UpdateAgentRequestBackgroundNoisePreset] = OMIT, - background_noise_volume: typing.Optional[float] = OMIT, - stt_override: typing.Optional[UpdateAgentRequestSttOverride] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Agent: - """ - Update a voice agent. Only fields present on the request body are changed. - - Parameters - ---------- - id : str - - name : typing.Optional[str] - - prompt : typing.Optional[str] - - first_message : typing.Optional[str] - - language : typing.Optional[str] - - llm_provider : typing.Optional[UpdateAgentRequestLlmProvider] - LLM backend. Send an empty string together with - `llm_model: ""` to clear the pair to the platform default - (today: Speechify Kimi K2.6). Sending one populated and - one empty is rejected as a 400. Omit both to leave the - stored pair unchanged. Switching to a non-`custom` provider - clears any stored `llm_base_url` / `llm_api_key` / - `llm_extra_body`. - - llm_model : typing.Optional[str] - Chat model slug. Empty string + empty `llm_provider` - clears the pair to the platform default. For `openai` / - `speechify` the (provider, model) pair must be in the - allowed table; for `custom` it is free-form. - - llm_base_url : typing.Optional[str] - Custom-endpoint base URL. Required when the resulting - provider is `custom`, rejected otherwise. - - llm_api_key : typing.Optional[str] - Bearer key for the custom endpoint. Write-only. Omit to - keep the stored key, send "" to clear it, send a value to - replace it. Rejected for non-`custom` providers. - - llm_extra_body : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - JSON object forwarded to the custom endpoint as - chat.completions `extra_body`. Omit to leave unchanged; - a JSON object (including `{}`) replaces it. Valid only - when the resulting provider is `custom`. - - voice_id : typing.Optional[str] - - temperature : typing.Optional[float] - Sampling temperature in the range 0.0–1.0. Omit to leave unchanged. - - widget_config : typing.Optional[WidgetConfig] - - is_public : typing.Optional[bool] - - allowed_origins : typing.Optional[typing.Sequence[str]] - - hostname_allowlist : typing.Optional[typing.Sequence[str]] - When supplied, replaces the stored list. Pass an empty - array to clear enforcement (public agent is open again). - Omit the field to leave the existing value unchanged. - - memory_enabled : typing.Optional[bool] - - memory_retention_days : typing.Optional[int] - - webhook_url : typing.Optional[str] - - webhook_secret : typing.Optional[str] - Rotate the HMAC secret. Write-only. - - amd : typing.Optional[AmdConfig] - AMD routing config (PATCH-replace, wholesale). Omit to leave the stored config unchanged. - - save_audio_recording : typing.Optional[bool] - - navigator_mode : typing.Optional[bool] - - ivr_memory_enabled : typing.Optional[bool] - Per-agent kill switch for the IVR-memory cache lookup. nil/omit = unchanged. - - tts_speaking_rate : typing.Optional[float] - - clear_tts_speaking_rate : typing.Optional[bool] - Two-headed clear: PATCH cannot distinguish "absent" from - "explicit null" reliably across stacks. Setting this to - `true` resets `tts_speaking_rate` to the voice default. - If both are sent, `clear_tts_speaking_rate` wins. - - tts_playback_rate : typing.Optional[float] - - clear_tts_playback_rate : typing.Optional[bool] - Two-headed clear, mirroring `clear_tts_speaking_rate`. - Setting this to `true` resets `tts_playback_rate` to null - (no post-process). If both fields are sent, - `clear_tts_playback_rate` wins. - - response_delay_seconds : typing.Optional[float] - Per-agent silence-wait override (seconds). See the field - on Agent for semantics. Range 0.0..5.0; null is allowed - but `clear_response_delay_seconds=true` is the canonical - way to revert to the stack default. - - clear_response_delay_seconds : typing.Optional[bool] - Two-headed clear, mirroring `clear_tts_playback_rate`. - Setting this to `true` resets `response_delay_seconds` to - null (revert to the stack default). If both are sent, - `clear_response_delay_seconds` wins. - - inactivity_timeout_seconds : typing.Optional[int] - Per-agent silence-tolerance override. Send `0` to clear - the override and fall back to the platform default. - Negative values are rejected. - - background_noise_preset : typing.Optional[UpdateAgentRequestBackgroundNoisePreset] - Pre-mixed ambient bed slug. Send empty string ("") to - disable the bed, which also clears `background_noise_volume`. - - background_noise_volume : typing.Optional[float] - Volume of the background-noise bed (0..1). Ignored when - the preset is empty; clearing the preset also clears - this field server-side. - - stt_override : typing.Optional[UpdateAgentRequestSttOverride] - Streaming-STT stack override. Send an empty string ("") to - clear the override and fall back to the worker default - (today: whisper-v3). Any non-empty value must be a known - stack name. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Agent - The updated agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.update( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}", - method="PATCH", - json={ - "name": name, - "prompt": prompt, - "first_message": first_message, - "language": language, - "llm_provider": llm_provider, - "llm_model": llm_model, - "llm_base_url": llm_base_url, - "llm_api_key": llm_api_key, - "llm_extra_body": llm_extra_body, - "voice_id": voice_id, - "temperature": temperature, - "widget_config": convert_and_respect_annotation_metadata( - object_=widget_config, annotation=WidgetConfig, direction="write" - ), - "is_public": is_public, - "allowed_origins": allowed_origins, - "hostname_allowlist": hostname_allowlist, - "memory_enabled": memory_enabled, - "memory_retention_days": memory_retention_days, - "webhook_url": webhook_url, - "webhook_secret": webhook_secret, - "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"), - "save_audio_recording": save_audio_recording, - "navigator_mode": navigator_mode, - "ivr_memory_enabled": ivr_memory_enabled, - "tts_speaking_rate": tts_speaking_rate, - "clear_tts_speaking_rate": clear_tts_speaking_rate, - "tts_playback_rate": tts_playback_rate, - "clear_tts_playback_rate": clear_tts_playback_rate, - "response_delay_seconds": response_delay_seconds, - "clear_response_delay_seconds": clear_response_delay_seconds, - "inactivity_timeout_seconds": inactivity_timeout_seconds, - "background_noise_preset": background_noise_preset, - "background_noise_volume": background_noise_volume, - "stt_override": stt_override, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Agent, - parse_obj_as( - type_=Agent, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_tools( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AttachedToolsResponse: - """ - List tools currently attached to the agent. Bare list — an - agent's tool attachment count is bounded by configuration, so - this endpoint does not paginate. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedToolsResponse - Attached tools for the agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_tools( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AttachedToolsResponse, - parse_obj_as( - type_=AttachedToolsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def attach_tool( - self, id: str, tool_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Attach an existing tool to the agent so the LLM can call it. - - Parameters - ---------- - id : str - - tool_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.attach_tool( - id="id", - tool_id="toolId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools/{jsonable_encoder(tool_id)}", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def detach_tool( - self, id: str, tool_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Detach a tool from the agent. - - Parameters - ---------- - id : str - - tool_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.detach_tool( - id="id", - tool_id="toolId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tools/{jsonable_encoder(tool_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_evaluation_config( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EvaluationConfig: - """ - Retrieve the agent's post-call evaluation criteria + data-collection config. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EvaluationConfig - The evaluation config for the agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.get_evaluation_config( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/evaluation-config", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - EvaluationConfig, - parse_obj_as( - type_=EvaluationConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_evaluation_config( - self, - id: str, - *, - criteria: typing.Sequence[EvaluationCriterion], - data_collection: typing.Sequence[DataCollectionField], - request_options: typing.Optional[RequestOptions] = None, - ) -> EvaluationConfig: - """ - Replace the agent's evaluation criteria + data-collection fields. - - Parameters - ---------- - id : str - - criteria : typing.Sequence[EvaluationCriterion] - - data_collection : typing.Sequence[DataCollectionField] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EvaluationConfig - The updated evaluation config. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify, DataCollectionField, EvaluationCriterion - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.update_evaluation_config( - id="id", - criteria=[ - EvaluationCriterion( - id="id", - name="name", - description="description", - ) - ], - data_collection=[ - DataCollectionField( - key="key", - description="description", - type="string", - ) - ], - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/evaluation-config", - method="PATCH", - json={ - "criteria": convert_and_respect_annotation_metadata( - object_=criteria, annotation=typing.Sequence[EvaluationCriterion], direction="write" - ), - "data_collection": convert_and_respect_annotation_metadata( - object_=data_collection, annotation=typing.Sequence[DataCollectionField], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - EvaluationConfig, - parse_obj_as( - type_=EvaluationConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_dynamic_variables( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListDynamicVariablesResponse: - """ - Retrieve the agent's customer-scope dynamic variables and the read-only - catalogue of reserved `system__*` keys. The system variables list is - provided so editor UIs can render the reference list without maintaining - a client-side copy of the catalogue. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListDynamicVariablesResponse - The agent's variable catalogue. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.get_dynamic_variables( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/variables", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListDynamicVariablesResponse, - parse_obj_as( - type_=ListDynamicVariablesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_dynamic_variables( - self, - id: str, - *, - variables: typing.Sequence[DynamicVariable], - request_options: typing.Optional[RequestOptions] = None, - ) -> ListDynamicVariablesResponse: - """ - Replace the agent's customer-scope dynamic variable definitions. - The supplied list overwrites the stored list wholesale (same - semantics as `updateEvaluationConfig`). Pass an empty array to - clear all variables. Up to 20 variables per agent. Keys must - match `[a-zA-Z0-9_]+` and must not start with the reserved - `system__` prefix. - - Parameters - ---------- - id : str - - variables : typing.Sequence[DynamicVariable] - The new variable list. Replaces the existing list entirely. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListDynamicVariablesResponse - The updated variable catalogue. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify, DynamicVariable - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.update_dynamic_variables( - id="id", - variables=[ - DynamicVariable( - key="product_name", - type="string", - default="Speechify", - description="Product the agent is supporting.", - ), - DynamicVariable( - key="support_tier", - type="number", - default=1, - ), - DynamicVariable( - key="account_metadata", - type="json", - description="Arbitrary account context injected into tool bodies.", - ), - ], - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/variables", - method="PATCH", - json={ - "variables": convert_and_respect_annotation_metadata( - object_=variables, annotation=typing.Sequence[DynamicVariable], direction="write" - ), - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListDynamicVariablesResponse, - parse_obj_as( - type_=ListDynamicVariablesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_builtins( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListAgentBuiltinsResponse: - """ - List every builtin instance configured on this agent. Each row - is one instance of a worker-resident capability (`end_call`, - `play_audio`, etc.) bound to this specific agent with its own - LLM-facing name, description, and per-call config. Same builtin - may appear N times on one agent — typically two `play_audio` - rows bound to different audio assets. - - Parameters - ---------- - id : str - Agent ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentBuiltinsResponse - The agent's builtin instances. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_builtins( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentBuiltinsResponse, - parse_obj_as( - type_=ListAgentBuiltinsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_builtin( - self, - id: str, - *, - builtin: SystemBuiltin, - name: str, - description: typing.Optional[str] = OMIT, - config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - params: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT, - enabled: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentBuiltin: - """ - Create a new builtin instance on this agent. `builtin` must - resolve to one of the names returned by - `GET /v1/agents/tools/system-builtins`; unknown values are rejected. - `name` is the LLM-facing identifier the model uses to call the - tool; it must match the tool-name regex and be unique within - the agent's builtin set. - - Parameters - ---------- - id : str - Agent ID. - - builtin : SystemBuiltin - - name : str - LLM-facing tool name. Must match the tool-name regex and be unique within the agent's builtin set. - - description : typing.Optional[str] - - config : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-instance configuration matching the per-builtin schema. - - params : typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] - Per-call parameter descriptors. - - enabled : typing.Optional[bool] - Defaults to true on the server when omitted. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The created builtin instance. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.create_builtin( - id="id", - builtin="builtin", - name="name", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins", - method="POST", - json={ - "builtin": builtin, - "name": name, - "description": description, - "config": config, - "params": params, - "enabled": enabled, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_builtin( - self, id: str, builtin_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AgentBuiltin: - """ - Fetch one builtin instance by ID. - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The builtin instance. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.get_builtin( - id="id", - builtin_id="builtinId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_builtin( - self, id: str, builtin_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a builtin instance from this agent. Idempotent on - already-deleted ids (404). Does NOT detach references from - flow nodes that name the instance; the worker logs and skips - on missing-row at session start (fail-soft). - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.delete_builtin( - id="id", - builtin_id="builtinId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_builtin( - self, - id: str, - builtin_id: str, - *, - name: typing.Optional[str] = OMIT, - description: typing.Optional[str] = OMIT, - config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - params: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT, - enabled: typing.Optional[bool] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentBuiltin: - """ - Update a builtin instance. All fields optional; omitting a - field leaves it unchanged. The underlying `builtin` (which - capability the instance maps to) is intentionally NOT - patchable — change of identity would surprise the worker, so - the customer should delete and recreate instead. - - Parameters - ---------- - id : str - Agent ID. - - builtin_id : str - Agent builtin instance ID. - - name : typing.Optional[str] - - description : typing.Optional[str] - - config : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-instance configuration matching the per-builtin schema. - - params : typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] - Per-call parameter descriptors. - - enabled : typing.Optional[bool] - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentBuiltin - The updated builtin instance. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.update_builtin( - id="id", - builtin_id="builtinId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/builtins/{jsonable_encoder(builtin_id)}", - method="PATCH", - json={ - "name": name, - "description": description, - "config": config, - "params": params, - "enabled": enabled, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentBuiltin, - parse_obj_as( - type_=AgentBuiltin, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_conversation( - self, - id: str, - *, - transport: typing.Optional[str] = OMIT, - dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateConversationResponse: - """ - Start a new voice conversation with the agent. Returns a realtime - voice session + short-lived client token so the caller can - connect the audio pipeline directly. The agent is dispatched - server-side; no additional client action required. - - Pass `dynamic_variables` to supply per-session values that override - the agent's stored variable defaults for this one conversation. - Keys in the `system__` namespace are rejected at this boundary. - - Parameters - ---------- - id : str - - transport : typing.Optional[str] - Transport hint. Omit to use the agent's default. - - dynamic_variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-session variable overrides that merge on top of the agent's - stored variable defaults for this one conversation. Keys in the - reserved `system__` namespace are rejected. Values must match the - declared type of the corresponding variable definition on the agent. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateConversationResponse - The created conversation with its realtime session token. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.create_conversation( - id="agent_01HS...", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/conversations", - method="POST", - json={ - "transport": transport, - "dynamic_variables": dynamic_variables, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateConversationResponse, - parse_obj_as( - type_=CreateConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_session( - self, - id: str, - *, - user_identity: typing.Optional[str] = OMIT, - dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateConversationResponse: - """ - Mint a realtime voice session for the given agent. Widget-friendly - counterpart to `createConversation` — same response shape, dual - authentication: - - * **Authenticated (Bearer)**: works for any agent the caller - owns. Typical server-to-server flow where the embedding - site's backend mints a token and hands it to the browser so - the API key never reaches the client. - * **Unauthenticated**: works only when `agent.is_public = true` - AND the request's `Origin` header matches `agent.allowed_origins` - (or that list is empty). When `agent.hostname_allowlist` is - non-empty, the `Origin` hostname must additionally be a - member of that list. Used directly by the - `` web component. - - Responds with the same `CreateConversationResponse` as - `createConversation`. - - Parameters - ---------- - id : str - - user_identity : typing.Optional[str] - Opaque identifier for the end-user (e.g. your app's user ID). Stamped onto the conversation. Optional - defaults to an anonymous per-session ID. - - dynamic_variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-session variable overrides that merge on top of the agent's - stored variable defaults for this one session. Keys in the - reserved `system__` namespace are rejected at this boundary. - Values must match the declared type of the corresponding variable - definition on the agent (a `string` type expects a JSON string, - `number` expects a JSON number, etc.). - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateConversationResponse - The created session with its realtime token + URL. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.create_session( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/sessions", - method="POST", - json={ - "user_identity": user_identity, - "dynamic_variables": dynamic_variables, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - CreateConversationResponse, - parse_obj_as( - type_=CreateConversationResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 403: - raise ForbiddenError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_agent_knowledge_bases( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AttachedKnowledgeBasesResponse: - """ - List knowledge bases attached to an agent. Bare list — the - attachment count is bounded by configuration, not by data - scale, so this endpoint does not paginate. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AttachedKnowledgeBasesResponse - The knowledge bases attached to the agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_agent_knowledge_bases( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AttachedKnowledgeBasesResponse, - parse_obj_as( - type_=AttachedKnowledgeBasesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def attach_knowledge_base( - self, id: str, kb_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Attach a knowledge base to an agent. The `search_knowledge` tool - is auto-registered on the next conversation and can only query the - attached knowledge bases. - - Parameters - ---------- - id : str - - kb_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.attach_knowledge_base( - id="id", - kb_id="kbId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases/{jsonable_encoder(kb_id)}", - method="POST", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def detach_knowledge_base( - self, id: str, kb_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Detach a knowledge base from an agent. - - Parameters - ---------- - id : str - - kb_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.detach_knowledge_base( - id="id", - kb_id="kbId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/knowledge-bases/{jsonable_encoder(kb_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_memories( - self, - id: str, - *, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ListMemoriesResponse: - """ - List per-caller memories extracted for an agent. Memories are - written post-call by the built-in extractor when `memory_enabled` - is true on the agent; the list is sorted newest-first. - - Parameters - ---------- - id : str - - limit : typing.Optional[int] - Maximum rows to return. Defaults to 100, capped at 200. - - offset : typing.Optional[int] - Number of rows to skip. Combine with `limit` to page through older memories. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListMemoriesResponse - Memories for the agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_memories( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/memories", - method="GET", - params={ - "limit": limit, - "offset": offset, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListMemoriesResponse, - parse_obj_as( - type_=ListMemoriesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_memories_by_caller( - self, id: str, *, agent_id: str, caller_identity: str, request_options: typing.Optional[RequestOptions] = None - ) -> DeleteMemoriesByCallerResponse: - """ - Delete every memory ever extracted for a specific caller on - this agent. Privacy / GDPR surface. Returns the count of rows - soft-deleted; rows become permanently unreachable immediately - and are hard-deleted by the retention job after the tenant's - configured retention window. - - Parameters - ---------- - id : str - - agent_id : str - - caller_identity : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteMemoriesByCallerResponse - Deletion summary. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.delete_memories_by_caller( - id="id", - agent_id="agent_id", - caller_identity="caller_identity", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/memories/delete", - method="POST", - json={ - "agent_id": agent_id, - "caller_identity": caller_identity, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - DeleteMemoriesByCallerResponse, - parse_obj_as( - type_=DeleteMemoriesByCallerResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_tests( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListAgentTestsResponse: - """ - List all tests configured for the agent. Each entry includes the - most recent run so the console can render pass/fail badges without - an extra round-trip. - - Parameters - ---------- - id : str - Agent ID. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListAgentTestsResponse - Tests for the agent with last-run summaries. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.list_tests( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListAgentTestsResponse, - parse_obj_as( - type_=ListAgentTestsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_test( - self, - id: str, - *, - name: str, - type: TestType, - config: CreateAgentTestRequestConfig, - description: typing.Optional[str] = OMIT, - tool_mock_config: typing.Optional[ToolMockConfig] = OMIT, - variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT, - folder_id: typing.Optional[str] = OMIT, - attached_agent_ids: typing.Optional[typing.Sequence[str]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> AgentTest: - """ - Create a new test for the agent. - - Parameters - ---------- - id : str - Agent ID. - - name : str - Short human-readable label for the test. - - type : TestType - - config : CreateAgentTestRequestConfig - Type-specific configuration. Must match the shape for the given `type`. - - description : typing.Optional[str] - Optional longer description of what this test verifies. - - tool_mock_config : typing.Optional[ToolMockConfig] - Optional tool-mocking config applied during every run of this test. - - variables : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] - Per-test variable values substituted into string fields of the - config at run-start. Keys use the same rules as agent-level - `DynamicVariable` keys. - - folder_id : typing.Optional[str] - Prefixed wire identifier (`folder_<26 char Crockford base32>`) - of the folder to place the test in. Omit / null for root. - - attached_agent_ids : typing.Optional[typing.Sequence[str]] - Optional list of additional agents this test should also run - against. The owner agent (path param) is always attached - implicitly. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AgentTest - The created test. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify, ReplyConfig - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.create_test( - id="agent_01HS...", - name="Greet caller by name", - description="Agent should use the caller's name when it is provided.", - type="reply", - config=ReplyConfig( - context="Hi, I am Alice. I need help with my order.", - success_criteria="The agent addresses Alice by name in its response.", - success_examples=[ - "Hi Alice! I would be happy to help with your order.", - "Sure thing, Alice - let me look that up for you.", - ], - failure_examples=[ - "Hello! How can I help you today?", - "I can help you with that order.", - ], - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests", - method="POST", - json={ - "name": name, - "description": description, - "type": type, - "config": convert_and_respect_annotation_metadata( - object_=config, annotation=CreateAgentTestRequestConfig, direction="write" - ), - "tool_mock_config": convert_and_respect_annotation_metadata( - object_=tool_mock_config, annotation=ToolMockConfig, direction="write" - ), - "variables": variables, - "folder_id": folder_id, - "attached_agent_ids": attached_agent_ids, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - AgentTest, - parse_obj_as( - type_=AgentTest, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def run_all_tests( - self, - id: str, - *, - config_override: typing.Optional[TestRunConfigOverride] = OMIT, - flow_version_id: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> RunAgentTestsResponse: - """ - Enqueue runs for every test on the agent concurrently. Up to 50 - tests are dispatched in one call. Each returned run starts in - `queued` status; poll `GET /v1/agents/tests/runs/{id}` for the terminal - result. - - An optional request body runs the whole suite against - a proposed config: a `config_override` (prompt / model / tools) - applied to every test without editing the tests, and/or a - `flow_version_id` to target a specific flow version instead of - the agent's active flow. Omit the body to run against the - agent's live config and active flow. - - Parameters - ---------- - id : str - Agent ID. - - config_override : typing.Optional[TestRunConfigOverride] - - flow_version_id : typing.Optional[str] - Targets a specific flow version (an `agent_versions` row) - instead of the agent's active flow — version-targeted - regression. Must be a flow version of the agent under test. - Raw UUID; flow versions carry no prefixed wire id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - RunAgentTestsResponse - Queued runs for all tests on the agent. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.run_all_tests( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/tests/runs", - method="POST", - json={ - "config_override": convert_and_respect_annotation_metadata( - object_=config_override, annotation=TestRunConfigOverride, direction="write" - ), - "flow_version_id": flow_version_id, - }, - headers={ - "content-type": "application/json", - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - RunAgentTestsResponse, - parse_obj_as( - type_=RunAgentTestsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_widget_config( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> WidgetConfig: - """ - Return the embed-widget appearance config for an agent. Works - unauthenticated for public agents; the body is cosmetic only. - - Parameters - ---------- - id : str - Prefixed agent id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - WidgetConfig - The agent's widget configuration. - - Examples - -------- - import asyncio - - from speechify import AsyncSpeechify - - client = AsyncSpeechify( - token="YOUR_TOKEN", - ) - - - async def main() -> None: - await client.agent.get_widget_config( - id="agent_01k7m6etzwf057j6w0zmdsgppr", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/agents/{jsonable_encoder(id)}/widget-config", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - WidgetConfig, - parse_obj_as( - type_=WidgetConfig, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - Error, - parse_obj_as( - type_=Error, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/speechify/agent/conversations/__init__.py b/src/speechify/agent/conversations/__init__.py deleted file mode 100644 index f3ea265..0000000 --- a/src/speechify/agent/conversations/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - diff --git a/src/speechify/agent/conversations/client.py b/src/speechify/agent/conversations/client.py deleted file mode 100644 index 75d62ca..0000000 --- a/src/speechify/agent/conversations/client.py +++ /dev/null @@ -1,2026 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ...core.client_wrapper import SyncClientWrapper -import typing -from ...types.conversation_status import ConversationStatus -from ...types.conversation_transport import ConversationTransport -import datetime as dt -from ...core.request_options import RequestOptions -from ...core.pagination import SyncPager -from ...types.conversation import Conversation -from ...core.datetime_utils import serialize_datetime -from ...types.list_conversations_response import ListConversationsResponse -from ...core.pydantic_utilities import parse_obj_as -from ...errors.unauthorized_error import UnauthorizedError -from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ...types.conversation_stats import ConversationStats -from ...types.recent_callee import RecentCallee -from ...types.list_recent_callees_response import ListRecentCalleesResponse -from ...errors.bad_request_error import BadRequestError -from ...core.jsonable_encoder import jsonable_encoder -from ...errors.not_found_error import NotFoundError -from ...types.message import Message -from ...types.list_messages_response import ListMessagesResponse -from ...types.list_evaluations_response import ListEvaluationsResponse -from ...types.webhook_delivery import WebhookDelivery -from ...types.list_webhook_deliveries_response import ListWebhookDeliveriesResponse -from ...types.retrieval_log_entry import RetrievalLogEntry -from ...types.list_retrieval_logs_response import ListRetrievalLogsResponse -from ...types.list_memories_response import ListMemoriesResponse -from ...core.client_wrapper import AsyncClientWrapper -from ...core.pagination import AsyncPager - - -class ConversationsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - agent_id: typing.Optional[str] = None, - status: typing.Optional[ConversationStatus] = None, - transport: typing.Optional[ConversationTransport] = None, - caller_identity: typing.Optional[str] = None, - search: typing.Optional[str] = None, - started_after: typing.Optional[dt.datetime] = None, - started_before: typing.Optional[dt.datetime] = None, - duration_min_ms: typing.Optional[int] = None, - duration_max_ms: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[Conversation]: - """ - List conversations owned by the caller, ordered by most recent. - Cursor-paginated: omit `cursor` to fetch the first page; pass the - previous response's `next_cursor` back to fetch the next page. - Walk pages while `has_more` is true. - - Parameters - ---------- - cursor : typing.Optional[str] - Opaque pagination cursor from a previous response. - - limit : typing.Optional[int] - Max conversations per page (default 50, max 200). - - agent_id : typing.Optional[str] - Filter to conversations for this agent. - - status : typing.Optional[ConversationStatus] - Filter by conversation status. - - transport : typing.Optional[ConversationTransport] - Filter by transport. - - caller_identity : typing.Optional[str] - Filter by caller identity. - - search : typing.Optional[str] - Free-text search across conversation content. - - started_after : typing.Optional[dt.datetime] - Only conversations started at or after this RFC 3339 timestamp. - - started_before : typing.Optional[dt.datetime] - Only conversations started at or before this RFC 3339 timestamp. - - duration_min_ms : typing.Optional[int] - Minimum conversation duration in milliseconds. - - duration_max_ms : typing.Optional[int] - Maximum conversation duration in milliseconds. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[Conversation] - A list of conversations. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.conversations.list() - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/conversations", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - "agent_id": agent_id, - "status": status, - "transport": transport, - "caller_identity": caller_identity, - "search": search, - "started_after": serialize_datetime(started_after) if started_after is not None else None, - "started_before": serialize_datetime(started_before) if started_before is not None else None, - "duration_min_ms": duration_min_ms, - "duration_max_ms": duration_max_ms, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListConversationsResponse, - parse_obj_as( - type_=ListConversationsResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list( - cursor=_parsed_next, - limit=limit, - agent_id=agent_id, - status=status, - transport=transport, - caller_identity=caller_identity, - search=search, - started_after=started_after, - started_before=started_before, - duration_min_ms=duration_min_ms, - duration_max_ms=duration_max_ms, - request_options=request_options, - ) - _items = _parsed_response.conversations - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def stats( - self, - *, - agent_id: typing.Optional[str] = None, - status: typing.Optional[ConversationStatus] = None, - transport: typing.Optional[ConversationTransport] = None, - caller_identity: typing.Optional[str] = None, - search: typing.Optional[str] = None, - started_after: typing.Optional[dt.datetime] = None, - started_before: typing.Optional[dt.datetime] = None, - duration_min_ms: typing.Optional[int] = None, - duration_max_ms: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ConversationStats: - """ - Aggregated counts and averages over the caller's conversations, scoped by the same filters as the list endpoint. - - Parameters - ---------- - agent_id : typing.Optional[str] - Filter to conversations for this agent. - - status : typing.Optional[ConversationStatus] - Filter by conversation status. - - transport : typing.Optional[ConversationTransport] - Filter by transport. - - caller_identity : typing.Optional[str] - Filter by caller identity. - - search : typing.Optional[str] - Free-text search across conversation content. - - started_after : typing.Optional[dt.datetime] - Only conversations started at or after this RFC 3339 timestamp. - - started_before : typing.Optional[dt.datetime] - Only conversations started at or before this RFC 3339 timestamp. - - duration_min_ms : typing.Optional[int] - Minimum conversation duration in milliseconds. - - duration_max_ms : typing.Optional[int] - Maximum conversation duration in milliseconds. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ConversationStats - Stats for the matched conversations. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.conversations.stats() - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/conversations/stats", - method="GET", - params={ - "agent_id": agent_id, - "status": status, - "transport": transport, - "caller_identity": caller_identity, - "search": search, - "started_after": serialize_datetime(started_after) if started_after is not None else None, - "started_before": serialize_datetime(started_before) if started_before is not None else None, - "duration_min_ms": duration_min_ms, - "duration_max_ms": duration_max_ms, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ConversationStats, - parse_obj_as( - type_=ConversationStats, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def recent_callees( - self, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[RecentCallee]: - """ - Distinct phone numbers the caller's workspace has dialled on - outbound calls, ordered by most recent. Feeds the batch-calls - composer's "Suggested from history" surface. Cursor-paginated: - omit `cursor` to fetch the first page. Default page size is 50 - and max is 200. Walk pages while `has_more` is true. - - Parameters - ---------- - cursor : typing.Optional[str] - Opaque pagination cursor from a previous response. - - limit : typing.Optional[int] - Max number of distinct phone numbers per page. Defaults to 50; clamped to 200. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[RecentCallee] - Recent callees for the caller's workspace. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.conversations.recent_callees() - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - "v1/agents/conversations/recent-callees", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListRecentCalleesResponse, - parse_obj_as( - type_=ListRecentCalleesResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.recent_callees( - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.callees - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Conversation: - """ - Retrieve a conversation by ID. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Conversation - The requested conversation. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.conversations.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - Conversation, - parse_obj_as( - type_=Conversation, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_messages( - self, - id: str, - *, - cursor: typing.Optional[str] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> SyncPager[Message]: - """ - Retrieve the transcript for a conversation in started_at order - (oldest first). Cursor-paginated: omit `cursor` to fetch the - first page. Default page size is 50 and max is 200. Walk pages - while `has_more` is true. - - Parameters - ---------- - id : str - - cursor : typing.Optional[str] - Opaque pagination cursor from a previous response. - - limit : typing.Optional[int] - Max messages per page (default 50, max 200). - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SyncPager[Message] - The messages for the conversation. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - response = client.agent.conversations.list_messages( - id="id", - ) - for item in response: - yield item - # alternatively, you can paginate page-by-page - for page in response.iter_pages(): - yield page - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/messages", - method="GET", - params={ - "cursor": cursor, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - _parsed_response = typing.cast( - ListMessagesResponse, - parse_obj_as( - type_=ListMessagesResponse, # type: ignore - object_=_response.json(), - ), - ) - _parsed_next = _parsed_response.next_cursor - _has_next = _parsed_next is not None and _parsed_next != "" - _get_next = lambda: self.list_messages( - id, - cursor=_parsed_next, - limit=limit, - request_options=request_options, - ) - _items = _parsed_response.messages - return SyncPager(has_next=_has_next, items=_items, get_next=_get_next) - if _response.status_code == 400: - raise BadRequestError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_evaluations( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ListEvaluationsResponse: - """ - Retrieve post-call evaluation results for a conversation. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListEvaluationsResponse - The evaluations for the conversation. - - Examples - -------- - from speechify import Speechify - - client = Speechify( - token="YOUR_TOKEN", - ) - client.agent.conversations.list_evaluations( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/agents/conversations/{jsonable_encoder(id)}/evaluations", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListEvaluationsResponse, - parse_obj_as( - type_=ListEvaluationsResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 401: - raise UnauthorizedError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFoundError( - typing.cast( - typing.Optional[typing.Any], - parse_obj_as( - type_=typing.Optional[typing.Any], # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def stream_recording( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> typing.Iterator[bytes]: - """ - Proxy the GCS-stored audio recording for a conversation through - the Cloud Run service identity. Returns OGG/Opus bytes (LiveKit - room-composite egress default). The response is streamed so a - long recording does not buffer in memory; `