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; `` consumers
-can seek directly. Only present when the agent had
-`save_audio_recording` enabled at session start.
-
-
-
-
-
-#### 🔌 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; `` consumers
- can seek directly. Only present when the agent had
- `save_audio_recording` enabled at session start.
-
- 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.
-
- Yields
- ------
- typing.Iterator[bytes]
- The recorded audio.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.conversations.stream_recording(
- id="id",
- )
- """
- with self._client_wrapper.httpx_client.stream(
- f"v1/agents/conversations/{jsonable_encoder(id)}/recording",
- 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)
-
- def list_webhook_deliveries(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[WebhookDelivery]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[WebhookDelivery]
- The post-call webhook deliveries for the conversation.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/conversations/{jsonable_encoder(id)}/webhook-deliveries",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListWebhookDeliveriesResponse,
- parse_obj_as(
- type_=ListWebhookDeliveriesResponse, # 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_webhook_deliveries(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.deliveries
- 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_retrieval_log(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[RetrievalLogEntry]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[RetrievalLogEntry]
- The retrieval log entries for the conversation.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/conversations/{jsonable_encoder(id)}/retrieval-log",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListRetrievalLogsResponse,
- parse_obj_as(
- type_=ListRetrievalLogsResponse, # 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_retrieval_log(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.entries
- 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_memories(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListMemoriesResponse:
- """
- List memories extracted from a specific conversation.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListMemoriesResponse
- Memories written during this conversation.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.conversations.list_memories(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/conversations/{jsonable_encoder(id)}/memories",
- method="GET",
- 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)
-
-
-class AsyncConversationsClient:
- 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,
- 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,
- ) -> AsyncPager[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
- -------
- AsyncPager[Conversation]
- A list of conversations.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.conversations.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/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 AsyncPager(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)
-
- async 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
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.conversations.stats()
-
-
- asyncio.run(main())
- """
- _response = await 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)
-
- async def recent_callees(
- self,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[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
- -------
- AsyncPager[RecentCallee]
- Recent callees for the caller's workspace.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.conversations.recent_callees()
- 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/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 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(),
- ),
- )
- )
- 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) -> Conversation:
- """
- Retrieve a conversation by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Conversation
- The requested conversation.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.conversations.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await 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)
-
- async def list_messages(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[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
- -------
- AsyncPager[Message]
- The messages for the conversation.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.conversations.list_messages(
- 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/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 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(),
- ),
- )
- )
- 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_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
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.conversations.list_evaluations(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await 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)
-
- async def stream_recording(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> typing.AsyncIterator[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; `` consumers
- can seek directly. Only present when the agent had
- `save_audio_recording` enabled at session start.
-
- 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.
-
- Yields
- ------
- typing.AsyncIterator[bytes]
- The recorded audio.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.conversations.stream_recording(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- async with self._client_wrapper.httpx_client.stream(
- f"v1/agents/conversations/{jsonable_encoder(id)}/recording",
- 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)
-
- async def list_webhook_deliveries(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[WebhookDelivery]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[WebhookDelivery]
- The post-call webhook deliveries for the conversation.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.conversations.list_webhook_deliveries(
- 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/conversations/{jsonable_encoder(id)}/webhook-deliveries",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListWebhookDeliveriesResponse,
- parse_obj_as(
- type_=ListWebhookDeliveriesResponse, # 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_webhook_deliveries(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.deliveries
- 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(),
- ),
- )
- )
- 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_retrieval_log(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[RetrievalLogEntry]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[RetrievalLogEntry]
- The retrieval log entries for the conversation.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.conversations.list_retrieval_log(
- 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/conversations/{jsonable_encoder(id)}/retrieval-log",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListRetrievalLogsResponse,
- parse_obj_as(
- type_=ListRetrievalLogsResponse, # 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_retrieval_log(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.entries
- 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(),
- ),
- )
- )
- 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, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListMemoriesResponse:
- """
- List memories extracted from a specific conversation.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListMemoriesResponse
- Memories written during this conversation.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.conversations.list_memories(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/conversations/{jsonable_encoder(id)}/memories",
- method="GET",
- 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)
diff --git a/src/speechify/agent/flow/__init__.py b/src/speechify/agent/flow/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/flow/__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/flow/client.py b/src/speechify/agent/flow/client.py
deleted file mode 100644
index efb120c..0000000
--- a/src/speechify/agent/flow/client.py
+++ /dev/null
@@ -1,2854 +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.get_flow_response import GetFlowResponse
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.pydantic_utilities import parse_obj_as
-from ...errors.unauthorized_error import UnauthorizedError
-from ...errors.not_found_error import NotFoundError
-from ...errors.internal_server_error import InternalServerError
-from ...types.error import Error
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
-from ...types.flow_graph import FlowGraph
-from ...errors.bad_request_error import BadRequestError
-from ...errors.conflict_error import ConflictError
-from ...types.flow_version import FlowVersion
-from ...types.list_flow_versions_response import ListFlowVersionsResponse
-from ...types.get_flow_version_response import GetFlowVersionResponse
-from ...types.list_flow_templates_response import ListFlowTemplatesResponse
-from ...types.flow_graph_input import FlowGraphInput
-from ...types.flow_template import FlowTemplate
-from ...core.serialization import convert_and_respect_annotation_metadata
-from ...core.client_wrapper import AsyncClientWrapper
-
-# this is used as the default value for optional parameters
-OMIT = typing.cast(typing.Any, ...)
-
-
-class FlowClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def get_flow(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetFlowResponse:
- """
- Return the agent's flow graph: the current draft (if any), the
- active published graph (if any), and the version history.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetFlowResponse
- The draft graph, active graph, and version history.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.get_flow(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetFlowResponse,
- parse_obj_as(
- type_=GetFlowResponse, # 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(),
- ),
- )
- )
- 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)
-
- def update_flow(
- self,
- id: str,
- *,
- nodes: typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]],
- edges: typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]],
- name: typing.Optional[str] = OMIT,
- notes: typing.Optional[str] = OMIT,
- variables: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowGraph:
- """
- Replace the agent's draft flow graph. The graph is validated
- before it is stored; publish it separately to make it active.
-
- 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.
-
- Returns
- -------
- FlowGraph
- The stored draft graph.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.update_flow(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- nodes=[{"key": "value"}],
- edges=[{"key": "value"}],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow",
- method="PUT",
- json={
- "name": name,
- "notes": notes,
- "nodes": nodes,
- "edges": edges,
- "variables": variables,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowGraph,
- parse_obj_as(
- type_=FlowGraph, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- def discard_draft(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Discard the agent's unpublished draft flow graph.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.discard_draft(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/draft",
- 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(),
- ),
- )
- )
- 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)
-
- def publish(
- self, id: str, *, notes: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowVersion:
- """
- Publish the agent's draft graph as a new active flow version.
-
- 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.
-
- Returns
- -------
- FlowVersion
- The newly published flow version.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.publish(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/publish",
- method="POST",
- json={
- "notes": notes,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowVersion,
- parse_obj_as(
- type_=FlowVersion, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- def rollback(
- self, id: str, *, version_id: str, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowVersion:
- """
- Publish a prior flow version as the active graph.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- version_id : str
- The flow version to roll back to.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- FlowVersion
- The flow version that is now active.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.rollback(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/rollback",
- method="POST",
- json={
- "version_id": version_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowVersion,
- parse_obj_as(
- type_=FlowVersion, # 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(),
- ),
- )
- )
- 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)
-
- def deactivate(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Deactivate the agent's published flow so the agent runs the synthesized default flow.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.deactivate(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/deactivate",
- 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(),
- ),
- )
- )
- 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)
-
- def list_versions(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListFlowVersionsResponse:
- """
- List every published flow version for the agent, newest first.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListFlowVersionsResponse
- The agent's flow version history.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.list_versions(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/versions",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListFlowVersionsResponse,
- parse_obj_as(
- type_=ListFlowVersionsResponse, # 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(),
- ),
- )
- )
- 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)
-
- def get_version(
- self, id: str, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> GetFlowVersionResponse:
- """
- Return the full flow graph for a specific published version.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- version_id : str
- Flow version UUID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetFlowVersionResponse
- The requested flow version's graph.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.get_version(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/versions/{jsonable_encoder(version_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetFlowVersionResponse,
- parse_obj_as(
- type_=GetFlowVersionResponse, # 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(),
- ),
- )
- )
- 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)
-
- def get_schema(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> typing.Dict[str, typing.Optional[typing.Any]]:
- """
- Return the JSON Schema describing the flow graph node taxonomy.
- Unauthenticated; flow editors fetch it to validate graphs client-side.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- typing.Dict[str, typing.Optional[typing.Any]]
- A JSON Schema document for the flow graph.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.get_schema()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/flow/schema",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- typing.Dict[str, typing.Optional[typing.Any]],
- parse_obj_as(
- type_=typing.Dict[str, 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)
-
- def list_templates(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListFlowTemplatesResponse:
- """
- List the reusable flow templates available to the workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListFlowTemplatesResponse
- The available flow templates.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.list_templates()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/flow/templates",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListFlowTemplatesResponse,
- parse_obj_as(
- type_=ListFlowTemplatesResponse, # 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 == 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)
-
- def create_template(
- self,
- *,
- key: str,
- name: str,
- graph: FlowGraphInput,
- description: typing.Optional[str] = OMIT,
- category: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowTemplate:
- """
- Create a reusable flow template from a graph.
-
- 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.
-
- Returns
- -------
- FlowTemplate
- The created flow template.
-
- Examples
- --------
- 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"}],
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/flow/templates",
- method="POST",
- json={
- "key": key,
- "name": name,
- "description": description,
- "category": category,
- "graph": convert_and_respect_annotation_metadata(
- object_=graph, annotation=FlowGraphInput, direction="write"
- ),
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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 == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- def get_template(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> FlowTemplate:
- """
- Retrieve a flow template by id.
-
- Parameters
- ----------
- id : str
- Flow template UUID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- FlowTemplate
- The requested flow template.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.get_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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(),
- ),
- )
- )
- 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)
-
- def delete_template(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a flow template.
-
- Parameters
- ----------
- id : str
- Flow template UUID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.delete_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{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(),
- ),
- )
- )
- 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)
-
- def update_template(
- self,
- id: str,
- *,
- key: str,
- name: str,
- graph: FlowGraphInput,
- description: typing.Optional[str] = OMIT,
- category: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowTemplate:
- """
- Replace a flow template. The whole template is replaced, not patched field-by-field.
-
- 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.
-
- Returns
- -------
- FlowTemplate
- The updated flow template.
-
- Examples
- --------
- 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"}],
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "key": key,
- "name": name,
- "description": description,
- "category": category,
- "graph": convert_and_respect_annotation_metadata(
- object_=graph, annotation=FlowGraphInput, direction="write"
- ),
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- def clone_template(
- self, id: str, *, agent_id: str, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowGraph:
- """
- Clone a flow template onto an agent as a new draft graph.
-
- 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.
-
- Returns
- -------
- FlowGraph
- The agent's new draft graph.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.flow.clone_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- agent_id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}/clone",
- method="POST",
- json={
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowGraph,
- parse_obj_as(
- type_=FlowGraph, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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 AsyncFlowClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def get_flow(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetFlowResponse:
- """
- Return the agent's flow graph: the current draft (if any), the
- active published graph (if any), and the version history.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetFlowResponse
- The draft graph, active graph, and version history.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.get_flow(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetFlowResponse,
- parse_obj_as(
- type_=GetFlowResponse, # 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(),
- ),
- )
- )
- 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)
-
- async def update_flow(
- self,
- id: str,
- *,
- nodes: typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]],
- edges: typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]],
- name: typing.Optional[str] = OMIT,
- notes: typing.Optional[str] = OMIT,
- variables: typing.Optional[typing.Sequence[typing.Dict[str, typing.Optional[typing.Any]]]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowGraph:
- """
- Replace the agent's draft flow graph. The graph is validated
- before it is stored; publish it separately to make it active.
-
- 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.
-
- Returns
- -------
- FlowGraph
- The stored draft graph.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.update_flow(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- nodes=[{"key": "value"}],
- edges=[{"key": "value"}],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow",
- method="PUT",
- json={
- "name": name,
- "notes": notes,
- "nodes": nodes,
- "edges": edges,
- "variables": variables,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowGraph,
- parse_obj_as(
- type_=FlowGraph, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- async def discard_draft(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Discard the agent's unpublished draft flow graph.
-
- Parameters
- ----------
- id : str
- Prefixed agent 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.flow.discard_draft(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/draft",
- 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(),
- ),
- )
- )
- 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)
-
- async def publish(
- self, id: str, *, notes: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowVersion:
- """
- Publish the agent's draft graph as a new active flow version.
-
- 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.
-
- Returns
- -------
- FlowVersion
- The newly published flow version.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.publish(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/publish",
- method="POST",
- json={
- "notes": notes,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowVersion,
- parse_obj_as(
- type_=FlowVersion, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- async def rollback(
- self, id: str, *, version_id: str, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowVersion:
- """
- Publish a prior flow version as the active graph.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- version_id : str
- The flow version to roll back to.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- FlowVersion
- The flow version that is now active.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.rollback(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/rollback",
- method="POST",
- json={
- "version_id": version_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowVersion,
- parse_obj_as(
- type_=FlowVersion, # 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(),
- ),
- )
- )
- 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)
-
- async def deactivate(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Deactivate the agent's published flow so the agent runs the synthesized default flow.
-
- Parameters
- ----------
- id : str
- Prefixed agent 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.flow.deactivate(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/deactivate",
- 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(),
- ),
- )
- )
- 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)
-
- async def list_versions(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListFlowVersionsResponse:
- """
- List every published flow version for the agent, newest first.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListFlowVersionsResponse
- The agent's flow version history.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.list_versions(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/versions",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListFlowVersionsResponse,
- parse_obj_as(
- type_=ListFlowVersionsResponse, # 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(),
- ),
- )
- )
- 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)
-
- async def get_version(
- self, id: str, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> GetFlowVersionResponse:
- """
- Return the full flow graph for a specific published version.
-
- Parameters
- ----------
- id : str
- Prefixed agent id.
-
- version_id : str
- Flow version UUID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- GetFlowVersionResponse
- The requested flow version's graph.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.get_version(
- id="agent_01k7m6etzwf057j6w0zmdsgppr",
- version_id="9c1e8a40-3b2d-4f6a-8e11-2a7d5c9f0b34",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/{jsonable_encoder(id)}/flow/versions/{jsonable_encoder(version_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- GetFlowVersionResponse,
- parse_obj_as(
- type_=GetFlowVersionResponse, # 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(),
- ),
- )
- )
- 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)
-
- async def get_schema(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> typing.Dict[str, typing.Optional[typing.Any]]:
- """
- Return the JSON Schema describing the flow graph node taxonomy.
- Unauthenticated; flow editors fetch it to validate graphs client-side.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- typing.Dict[str, typing.Optional[typing.Any]]
- A JSON Schema document for the flow graph.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.get_schema()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/flow/schema",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- typing.Dict[str, typing.Optional[typing.Any]],
- parse_obj_as(
- type_=typing.Dict[str, 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)
-
- async def list_templates(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListFlowTemplatesResponse:
- """
- List the reusable flow templates available to the workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListFlowTemplatesResponse
- The available flow templates.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.list_templates()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/flow/templates",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListFlowTemplatesResponse,
- parse_obj_as(
- type_=ListFlowTemplatesResponse, # 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 == 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)
-
- async def create_template(
- self,
- *,
- key: str,
- name: str,
- graph: FlowGraphInput,
- description: typing.Optional[str] = OMIT,
- category: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowTemplate:
- """
- Create a reusable flow template from a graph.
-
- 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.
-
- Returns
- -------
- FlowTemplate
- The created flow template.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, FlowGraphInput
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.create_template(
- key="key",
- name="name",
- graph=FlowGraphInput(
- nodes=[{"key": "value"}],
- edges=[{"key": "value"}],
- ),
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/flow/templates",
- method="POST",
- json={
- "key": key,
- "name": name,
- "description": description,
- "category": category,
- "graph": convert_and_respect_annotation_metadata(
- object_=graph, annotation=FlowGraphInput, direction="write"
- ),
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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 == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- async def get_template(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> FlowTemplate:
- """
- Retrieve a flow template by id.
-
- Parameters
- ----------
- id : str
- Flow template UUID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- FlowTemplate
- The requested flow template.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.get_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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(),
- ),
- )
- )
- 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)
-
- async def delete_template(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a flow template.
-
- Parameters
- ----------
- id : str
- Flow template UUID.
-
- 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.flow.delete_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{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(),
- ),
- )
- )
- 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)
-
- async def update_template(
- self,
- id: str,
- *,
- key: str,
- name: str,
- graph: FlowGraphInput,
- description: typing.Optional[str] = OMIT,
- category: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> FlowTemplate:
- """
- Replace a flow template. The whole template is replaced, not patched field-by-field.
-
- 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.
-
- Returns
- -------
- FlowTemplate
- The updated flow template.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, FlowGraphInput
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.update_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- key="key",
- name="name",
- graph=FlowGraphInput(
- nodes=[{"key": "value"}],
- edges=[{"key": "value"}],
- ),
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "key": key,
- "name": name,
- "description": description,
- "category": category,
- "graph": convert_and_respect_annotation_metadata(
- object_=graph, annotation=FlowGraphInput, direction="write"
- ),
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowTemplate,
- parse_obj_as(
- type_=FlowTemplate, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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)
-
- async def clone_template(
- self, id: str, *, agent_id: str, request_options: typing.Optional[RequestOptions] = None
- ) -> FlowGraph:
- """
- Clone a flow template onto an agent as a new draft graph.
-
- 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.
-
- Returns
- -------
- FlowGraph
- The agent's new draft graph.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.flow.clone_template(
- id="3f7b1c20-9d4e-4a18-b6c2-8e0f1a2b3c4d",
- agent_id="agent_01k7m6etzwf057j6w0zmdsgppr",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/flow/templates/{jsonable_encoder(id)}/clone",
- method="POST",
- json={
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- FlowGraph,
- parse_obj_as(
- type_=FlowGraph, # 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(),
- ),
- )
- )
- if _response.status_code == 409:
- raise ConflictError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # 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/ivr_memory/__init__.py b/src/speechify/agent/ivr_memory/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/ivr_memory/__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/ivr_memory/client.py b/src/speechify/agent/ivr_memory/client.py
deleted file mode 100644
index baa1c60..0000000
--- a/src/speechify/agent/ivr_memory/client.py
+++ /dev/null
@@ -1,680 +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_ivr_menus_response import ListIvrMenusResponse
-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.ivr_menu import IvrMenu
-from ...core.jsonable_encoder import jsonable_encoder
-from ...errors.not_found_error import NotFoundError
-from ...errors.bad_request_error import BadRequestError
-from ...core.client_wrapper import AsyncClientWrapper
-
-# this is used as the default value for optional parameters
-OMIT = typing.cast(typing.Any, ...)
-
-
-class IvrMemoryClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def list(
- self, *, fingerprint: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> ListIvrMenusResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- ListIvrMenusResponse
- A list of cached IVR menus.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.ivr_memory.list()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/ivr-menus",
- method="GET",
- params={
- "fingerprint": fingerprint,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListIvrMenusResponse,
- parse_obj_as(
- type_=ListIvrMenusResponse, # 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) -> IvrMenu:
- """
- Fetch one menu's full shape. Returns 404 for missing,
- soft-deleted, or foreign-tenant menus — existence information
- is never leaked across tenants.
-
- Parameters
- ----------
- id : str
- IVR menu ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- IvrMenu
- The IVR menu detail.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.ivr_memory.get(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- IvrMenu,
- parse_obj_as(
- type_=IvrMenu, # 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_label(
- self, id: str, *, dtmf: str, label: str, request_options: typing.Optional[RequestOptions] = None
- ) -> IvrMenu:
- """
- 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).
-
- 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.
-
- Returns
- -------
- IvrMenu
- The refreshed menu shape.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.ivr_memory.update_label(
- id="id",
- dtmf="dtmf",
- label="label",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "dtmf": dtmf,
- "label": label,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- IvrMenu,
- parse_obj_as(
- type_=IvrMenu, # 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 invalidate(
- self, id: str, *, reason: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- 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.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.ivr_memory.invalidate(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}/invalidate",
- method="POST",
- json={
- "reason": reason,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- 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)
-
-
-class AsyncIvrMemoryClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def list(
- self, *, fingerprint: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> ListIvrMenusResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- ListIvrMenusResponse
- A list of cached IVR menus.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.ivr_memory.list()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/ivr-menus",
- method="GET",
- params={
- "fingerprint": fingerprint,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListIvrMenusResponse,
- parse_obj_as(
- type_=ListIvrMenusResponse, # 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) -> IvrMenu:
- """
- Fetch one menu's full shape. Returns 404 for missing,
- soft-deleted, or foreign-tenant menus — existence information
- is never leaked across tenants.
-
- Parameters
- ----------
- id : str
- IVR menu ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- IvrMenu
- The IVR menu detail.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.ivr_memory.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- IvrMenu,
- parse_obj_as(
- type_=IvrMenu, # 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_label(
- self, id: str, *, dtmf: str, label: str, request_options: typing.Optional[RequestOptions] = None
- ) -> IvrMenu:
- """
- 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).
-
- 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.
-
- Returns
- -------
- IvrMenu
- The refreshed menu shape.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.ivr_memory.update_label(
- id="id",
- dtmf="dtmf",
- label="label",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "dtmf": dtmf,
- "label": label,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- IvrMenu,
- parse_obj_as(
- type_=IvrMenu, # 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 invalidate(
- self, id: str, *, reason: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- 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.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.ivr_memory.invalidate(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/ivr-menus/{jsonable_encoder(id)}/invalidate",
- method="POST",
- json={
- "reason": reason,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- 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)
diff --git a/src/speechify/agent/knowledge_bases/__init__.py b/src/speechify/agent/knowledge_bases/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/knowledge_bases/__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/knowledge_bases/client.py b/src/speechify/agent/knowledge_bases/client.py
deleted file mode 100644
index 144984d..0000000
--- a/src/speechify/agent/knowledge_bases/client.py
+++ /dev/null
@@ -1,5114 +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.knowledge_base import KnowledgeBase
-from ...types.list_knowledge_bases_response import ListKnowledgeBasesResponse
-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 ...errors.bad_request_error import BadRequestError
-from ...core.jsonable_encoder import jsonable_encoder
-from ...errors.not_found_error import NotFoundError
-from ...types.knowledge_base_document import KnowledgeBaseDocument
-from ...types.list_knowledge_base_documents_response import ListKnowledgeBaseDocumentsResponse
-from ... import core
-from ...errors.content_too_large_error import ContentTooLargeError
-from ...types.error import Error
-from ...types.knowledge_base_document_detail import KnowledgeBaseDocumentDetail
-from ...types.knowledge_base_chunk import KnowledgeBaseChunk
-from ...types.list_knowledge_base_chunks_response import ListKnowledgeBaseChunksResponse
-from ...types.import_job_response import ImportJobResponse
-from ...types.list_import_jobs_response import ListImportJobsResponse
-from ...types.import_job import ImportJob
-from ...types.refresh_config import RefreshConfig
-from ...types.list_refresh_history_response import ListRefreshHistoryResponse
-from ...types.knowledge_base_folder import KnowledgeBaseFolder
-from ...types.list_knowledge_base_folders_response import ListKnowledgeBaseFoldersResponse
-from ...types.search_knowledge_bases_response import SearchKnowledgeBasesResponse
-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 KnowledgeBasesClient:
- 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[KnowledgeBase]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[KnowledgeBase]
- The knowledge bases for the caller.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/knowledge-bases",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBasesResponse,
- parse_obj_as(
- type_=ListKnowledgeBasesResponse, # 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.knowledge_bases
- 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 create(
- self,
- *,
- name: str,
- description: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBase:
- """
- Create a new knowledge base.
-
- Parameters
- ----------
- name : str
- Human-readable label.
-
- description : typing.Optional[str]
- Optional description.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The created knowledge base.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create(
- name="name",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/knowledge-bases",
- method="POST",
- json={
- "name": name,
- "description": description,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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) -> KnowledgeBase:
- """
- Retrieve a knowledge base by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The requested knowledge base.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.get(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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 a knowledge base. Documents and chunks are cascaded.
-
- 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.knowledge_bases.delete(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{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,
- description: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBase:
- """
- Update a knowledge base.
-
- Parameters
- ----------
- id : str
-
- name : typing.Optional[str]
-
- description : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The updated knowledge base.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.update(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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_documents(
- self,
- id: str,
- *,
- folder_id: typing.Optional[str] = None,
- q: typing.Optional[str] = None,
- source_kind: typing.Optional[str] = None,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[KnowledgeBaseDocument]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[KnowledgeBaseDocument]
- The documents in the knowledge base.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents",
- method="GET",
- params={
- "folder_id": folder_id,
- "q": q,
- "source_kind": source_kind,
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseDocumentsResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseDocumentsResponse, # 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_documents(
- id,
- folder_id=folder_id,
- q=q,
- source_kind=source_kind,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.documents
- 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(),
- ),
- )
- )
- 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 upload_document(
- self, id: str, *, file: core.File, request_options: typing.Optional[RequestOptions] = None
- ) -> KnowledgeBaseDocument:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- file : core.File
- See core.File for more documentation
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBaseDocument
- The ingested document record.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.upload_document(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents",
- method="POST",
- data={},
- files={
- "file": file,
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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(),
- ),
- )
- )
- if _response.status_code == 413:
- raise ContentTooLargeError(
- 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 get_document(
- self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> KnowledgeBaseDocumentDetail:
- """
- Retrieve a document by ID.
-
- Parameters
- ----------
- id : str
-
- doc_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBaseDocumentDetail
- The document record.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.get_document(
- id="id",
- doc_id="docId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocumentDetail,
- parse_obj_as(
- type_=KnowledgeBaseDocumentDetail, # 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_document(self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a document and all its chunks.
-
- Parameters
- ----------
- id : str
-
- doc_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.delete_document(
- id="id",
- doc_id="docId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_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_document(
- self,
- id: str,
- doc_id: str,
- *,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- Update a document. Currently supports moving the document
- between folders via `folder_id`.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.update_document(
- id="id",
- doc_id="docId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}",
- method="PATCH",
- json={
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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_chunks(
- self,
- id: str,
- doc_id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[KnowledgeBaseChunk]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[KnowledgeBaseChunk]
- The chunks for the document.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/chunks",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseChunksResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseChunksResponse, # 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_chunks(
- id,
- doc_id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.chunks
- 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(),
- ),
- )
- )
- 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_text_document(
- self,
- id: str,
- *,
- name: str,
- content: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseDocument:
- """
- Create a document from inline pasted text. Content is chunked,
- embedded, and indexed synchronously.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseDocument
- The created document.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_text_document(
- id="id",
- name="name",
- content="content",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/text",
- method="POST",
- json={
- "name": name,
- "content": content,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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_url_document(
- self,
- id: str,
- *,
- url: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseDocument:
- """
- 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.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseDocument
- The created document.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_url_document(
- id="id",
- url="url",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/url",
- method="POST",
- json={
- "url": url,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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_sitemap_import(
- self,
- id: str,
- *,
- url: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- Kick off an async sitemap import. Returns 202 with the import
- job row; client polls `GET /{id}/imports` for progress.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_sitemap_import(
- id="id",
- url="url",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/sitemap",
- method="POST",
- json={
- "url": url,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_crawl_import(
- self,
- id: str,
- *,
- url: str,
- max_pages: typing.Optional[int] = OMIT,
- max_depth: typing.Optional[int] = OMIT,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- Kick off an async website crawl. Returns 202 with the import
- job row; client polls `GET /{id}/imports` for progress.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_crawl_import(
- id="id",
- url="url",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/crawl",
- method="POST",
- json={
- "url": url,
- "max_pages": max_pages,
- "max_depth": max_depth,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_url_batch_import(
- self,
- id: str,
- *,
- urls: typing.Sequence[str],
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_url_batch_import(
- id="id",
- urls=["urls"],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/urls",
- method="POST",
- json={
- "urls": urls,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_import_jobs(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListImportJobsResponse:
- """
- List import jobs (sitemap / crawl / refresh) for a knowledge base.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListImportJobsResponse
- The import jobs for the knowledge base.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.list_import_jobs(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/imports",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListImportJobsResponse,
- parse_obj_as(
- type_=ListImportJobsResponse, # 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 cancel_import_job(
- self, id: str, import_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ImportJob:
- """
- Cancel a non-terminal import job. Idempotent on terminal jobs
- (completed / failed / cancelled) — the cancel call returns the
- unchanged row.
-
- Parameters
- ----------
- id : str
-
- import_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ImportJob
- The (possibly already-terminal) import job row.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.cancel_import_job(
- id="id",
- import_id="importId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/imports/{jsonable_encoder(import_id)}/cancel",
- method="POST",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJob,
- parse_obj_as(
- type_=ImportJob, # 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 batch_delete_documents(
- self, id: str, *, ids: typing.Sequence[str], request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- ids : typing.Sequence[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.batch_delete_documents(
- id="id",
- ids=["ids"],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/batch",
- method="DELETE",
- json={
- "ids": ids,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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 batch_move_documents(
- self,
- id: str,
- *,
- ids: typing.Sequence[str],
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- 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.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.batch_move_documents(
- id="id",
- ids=["ids"],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/batch/move",
- method="PATCH",
- json={
- "ids": ids,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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 update_refresh_config(
- self,
- id: str,
- doc_id: str,
- *,
- enabled: typing.Optional[bool] = OMIT,
- interval_days: typing.Optional[int] = OMIT,
- auto_remove_enabled: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> RefreshConfig:
- """
- Update the per-document auto-refresh state. Only meaningful
- for url-sourced documents; file and text rows reject the
- request.
-
- 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.
-
- Returns
- -------
- RefreshConfig
- The updated refresh config.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.update_refresh_config(
- id="id",
- doc_id="docId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/refresh-config",
- method="PATCH",
- json={
- "enabled": enabled,
- "interval_days": interval_days,
- "auto_remove_enabled": auto_remove_enabled,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- RefreshConfig,
- parse_obj_as(
- type_=RefreshConfig, # 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_refresh_history(
- self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListRefreshHistoryResponse:
- """
- List recent auto-refresh attempts for a document.
-
- Parameters
- ----------
- id : str
-
- doc_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListRefreshHistoryResponse
- Recent refresh attempts for the document.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.list_refresh_history(
- id="id",
- doc_id="docId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/refresh-history",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListRefreshHistoryResponse,
- parse_obj_as(
- type_=ListRefreshHistoryResponse, # 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_folders(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[KnowledgeBaseFolder]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[KnowledgeBaseFolder]
- Folders in the knowledge base.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseFoldersResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseFoldersResponse, # 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_folders(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.folders
- 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(),
- ),
- )
- )
- 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_folder(
- self,
- id: str,
- *,
- name: str,
- parent_folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseFolder:
- """
- Create a folder inside a knowledge base.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseFolder
- The created folder.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.create_folder(
- id="id",
- name="name",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders",
- method="POST",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseFolder,
- parse_obj_as(
- type_=KnowledgeBaseFolder, # 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 delete_folder(
- self,
- id: str,
- folder_id: str,
- *,
- force: typing.Optional[bool] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- Delete a folder. Documents inside the folder are moved to root
- (not deleted). Sub-folders are detached likewise.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.delete_folder(
- id="id",
- folder_id="folderId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders/{jsonable_encoder(folder_id)}",
- method="DELETE",
- params={
- "force": force,
- },
- 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_folder(
- self,
- id: str,
- folder_id: str,
- *,
- name: typing.Optional[str] = OMIT,
- parent_folder_id: typing.Optional[str] = OMIT,
- clear_parent_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseFolder:
- """
- Update a folder. Pass `parent_folder_id: null` to move to
- root; omit the field to leave it unchanged.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseFolder
- The updated folder.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.update_folder(
- id="id",
- folder_id="folderId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders/{jsonable_encoder(folder_id)}",
- method="PATCH",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- "clear_parent_folder_id": clear_parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseFolder,
- parse_obj_as(
- type_=KnowledgeBaseFolder, # 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 search(
- self,
- *,
- query: str,
- kb_ids: typing.Sequence[str],
- top_k: typing.Optional[int] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SearchKnowledgeBasesResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SearchKnowledgeBasesResponse
- Ranked search hits across the selected knowledge bases.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.knowledge_bases.search(
- query="query",
- kb_ids=["kb_ids"],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/knowledge-bases/search",
- method="POST",
- json={
- "query": query,
- "kb_ids": kb_ids,
- "top_k": top_k,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SearchKnowledgeBasesResponse,
- parse_obj_as(
- type_=SearchKnowledgeBasesResponse, # 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)
-
-
-class AsyncKnowledgeBasesClient:
- 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[KnowledgeBase]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[KnowledgeBase]
- The knowledge bases for the caller.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.knowledge_bases.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/knowledge-bases",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBasesResponse,
- parse_obj_as(
- type_=ListKnowledgeBasesResponse, # 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.knowledge_bases
- return AsyncPager(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)
-
- async def create(
- self,
- *,
- name: str,
- description: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBase:
- """
- Create a new knowledge base.
-
- Parameters
- ----------
- name : str
- Human-readable label.
-
- description : typing.Optional[str]
- Optional description.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The created knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create(
- name="name",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/knowledge-bases",
- method="POST",
- json={
- "name": name,
- "description": description,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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) -> KnowledgeBase:
- """
- Retrieve a knowledge base by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The requested knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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 a knowledge base. Documents and chunks are cascaded.
-
- 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.knowledge_bases.delete(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{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,
- description: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBase:
- """
- Update a knowledge base.
-
- Parameters
- ----------
- id : str
-
- name : typing.Optional[str]
-
- description : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBase
- The updated knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.update(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBase,
- parse_obj_as(
- type_=KnowledgeBase, # 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_documents(
- self,
- id: str,
- *,
- folder_id: typing.Optional[str] = None,
- q: typing.Optional[str] = None,
- source_kind: typing.Optional[str] = None,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[KnowledgeBaseDocument]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[KnowledgeBaseDocument]
- The documents in the knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.knowledge_bases.list_documents(
- 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/knowledge-bases/{jsonable_encoder(id)}/documents",
- method="GET",
- params={
- "folder_id": folder_id,
- "q": q,
- "source_kind": source_kind,
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseDocumentsResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseDocumentsResponse, # 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_documents(
- id,
- folder_id=folder_id,
- q=q,
- source_kind=source_kind,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.documents
- return AsyncPager(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(),
- ),
- )
- )
- 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 upload_document(
- self, id: str, *, file: core.File, request_options: typing.Optional[RequestOptions] = None
- ) -> KnowledgeBaseDocument:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- file : core.File
- See core.File for more documentation
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBaseDocument
- The ingested document record.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.upload_document(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents",
- method="POST",
- data={},
- files={
- "file": file,
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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(),
- ),
- )
- )
- if _response.status_code == 413:
- raise ContentTooLargeError(
- 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 get_document(
- self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> KnowledgeBaseDocumentDetail:
- """
- Retrieve a document by ID.
-
- Parameters
- ----------
- id : str
-
- doc_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- KnowledgeBaseDocumentDetail
- The document record.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.get_document(
- id="id",
- doc_id="docId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocumentDetail,
- parse_obj_as(
- type_=KnowledgeBaseDocumentDetail, # 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_document(
- self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Delete a document and all its chunks.
-
- Parameters
- ----------
- id : str
-
- doc_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.knowledge_bases.delete_document(
- id="id",
- doc_id="docId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_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_document(
- self,
- id: str,
- doc_id: str,
- *,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- Update a document. Currently supports moving the document
- between folders via `folder_id`.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.update_document(
- id="id",
- doc_id="docId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}",
- method="PATCH",
- json={
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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_chunks(
- self,
- id: str,
- doc_id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[KnowledgeBaseChunk]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[KnowledgeBaseChunk]
- The chunks for the document.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.knowledge_bases.list_chunks(
- id="id",
- doc_id="docId",
- )
- 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/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/chunks",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseChunksResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseChunksResponse, # 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_chunks(
- id,
- doc_id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.chunks
- return AsyncPager(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(),
- ),
- )
- )
- 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_text_document(
- self,
- id: str,
- *,
- name: str,
- content: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseDocument:
- """
- Create a document from inline pasted text. Content is chunked,
- embedded, and indexed synchronously.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseDocument
- The created document.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_text_document(
- id="id",
- name="name",
- content="content",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/text",
- method="POST",
- json={
- "name": name,
- "content": content,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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_url_document(
- self,
- id: str,
- *,
- url: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseDocument:
- """
- 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.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseDocument
- The created document.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_url_document(
- id="id",
- url="url",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/url",
- method="POST",
- json={
- "url": url,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseDocument,
- parse_obj_as(
- type_=KnowledgeBaseDocument, # 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_sitemap_import(
- self,
- id: str,
- *,
- url: str,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- Kick off an async sitemap import. Returns 202 with the import
- job row; client polls `GET /{id}/imports` for progress.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_sitemap_import(
- id="id",
- url="url",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/sitemap",
- method="POST",
- json={
- "url": url,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_crawl_import(
- self,
- id: str,
- *,
- url: str,
- max_pages: typing.Optional[int] = OMIT,
- max_depth: typing.Optional[int] = OMIT,
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- Kick off an async website crawl. Returns 202 with the import
- job row; client polls `GET /{id}/imports` for progress.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_crawl_import(
- id="id",
- url="url",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/crawl",
- method="POST",
- json={
- "url": url,
- "max_pages": max_pages,
- "max_depth": max_depth,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_url_batch_import(
- self,
- id: str,
- *,
- urls: typing.Sequence[str],
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ImportJobResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- ImportJobResponse
- Import job queued.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_url_batch_import(
- id="id",
- urls=["urls"],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/urls",
- method="POST",
- json={
- "urls": urls,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJobResponse,
- parse_obj_as(
- type_=ImportJobResponse, # 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_import_jobs(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListImportJobsResponse:
- """
- List import jobs (sitemap / crawl / refresh) for a knowledge base.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListImportJobsResponse
- The import jobs for the knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.list_import_jobs(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/imports",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListImportJobsResponse,
- parse_obj_as(
- type_=ListImportJobsResponse, # 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 cancel_import_job(
- self, id: str, import_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ImportJob:
- """
- Cancel a non-terminal import job. Idempotent on terminal jobs
- (completed / failed / cancelled) — the cancel call returns the
- unchanged row.
-
- Parameters
- ----------
- id : str
-
- import_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ImportJob
- The (possibly already-terminal) import job row.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.cancel_import_job(
- id="id",
- import_id="importId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/imports/{jsonable_encoder(import_id)}/cancel",
- method="POST",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ImportJob,
- parse_obj_as(
- type_=ImportJob, # 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 batch_delete_documents(
- self, id: str, *, ids: typing.Sequence[str], request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- ids : typing.Sequence[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.knowledge_bases.batch_delete_documents(
- id="id",
- ids=["ids"],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/batch",
- method="DELETE",
- json={
- "ids": ids,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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 batch_move_documents(
- self,
- id: str,
- *,
- ids: typing.Sequence[str],
- folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- 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.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.batch_move_documents(
- id="id",
- ids=["ids"],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/batch/move",
- method="PATCH",
- json={
- "ids": ids,
- "folder_id": folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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 update_refresh_config(
- self,
- id: str,
- doc_id: str,
- *,
- enabled: typing.Optional[bool] = OMIT,
- interval_days: typing.Optional[int] = OMIT,
- auto_remove_enabled: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> RefreshConfig:
- """
- Update the per-document auto-refresh state. Only meaningful
- for url-sourced documents; file and text rows reject the
- request.
-
- 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.
-
- Returns
- -------
- RefreshConfig
- The updated refresh config.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.update_refresh_config(
- id="id",
- doc_id="docId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/refresh-config",
- method="PATCH",
- json={
- "enabled": enabled,
- "interval_days": interval_days,
- "auto_remove_enabled": auto_remove_enabled,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- RefreshConfig,
- parse_obj_as(
- type_=RefreshConfig, # 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_refresh_history(
- self, id: str, doc_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListRefreshHistoryResponse:
- """
- List recent auto-refresh attempts for a document.
-
- Parameters
- ----------
- id : str
-
- doc_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListRefreshHistoryResponse
- Recent refresh attempts for the document.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.list_refresh_history(
- id="id",
- doc_id="docId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/documents/{jsonable_encoder(doc_id)}/refresh-history",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListRefreshHistoryResponse,
- parse_obj_as(
- type_=ListRefreshHistoryResponse, # 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_folders(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[KnowledgeBaseFolder]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[KnowledgeBaseFolder]
- Folders in the knowledge base.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.knowledge_bases.list_folders(
- 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/knowledge-bases/{jsonable_encoder(id)}/folders",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListKnowledgeBaseFoldersResponse,
- parse_obj_as(
- type_=ListKnowledgeBaseFoldersResponse, # 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_folders(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.folders
- return AsyncPager(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(),
- ),
- )
- )
- 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_folder(
- self,
- id: str,
- *,
- name: str,
- parent_folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseFolder:
- """
- Create a folder inside a knowledge base.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseFolder
- The created folder.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.create_folder(
- id="id",
- name="name",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders",
- method="POST",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseFolder,
- parse_obj_as(
- type_=KnowledgeBaseFolder, # 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 delete_folder(
- self,
- id: str,
- folder_id: str,
- *,
- force: typing.Optional[bool] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> None:
- """
- Delete a folder. Documents inside the folder are moved to root
- (not deleted). Sub-folders are detached likewise.
-
- 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.
-
- Returns
- -------
- None
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.delete_folder(
- id="id",
- folder_id="folderId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders/{jsonable_encoder(folder_id)}",
- method="DELETE",
- params={
- "force": force,
- },
- 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_folder(
- self,
- id: str,
- folder_id: str,
- *,
- name: typing.Optional[str] = OMIT,
- parent_folder_id: typing.Optional[str] = OMIT,
- clear_parent_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> KnowledgeBaseFolder:
- """
- Update a folder. Pass `parent_folder_id: null` to move to
- root; omit the field to leave it unchanged.
-
- 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.
-
- Returns
- -------
- KnowledgeBaseFolder
- The updated folder.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.update_folder(
- id="id",
- folder_id="folderId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/knowledge-bases/{jsonable_encoder(id)}/folders/{jsonable_encoder(folder_id)}",
- method="PATCH",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- "clear_parent_folder_id": clear_parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- KnowledgeBaseFolder,
- parse_obj_as(
- type_=KnowledgeBaseFolder, # 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 search(
- self,
- *,
- query: str,
- kb_ids: typing.Sequence[str],
- top_k: typing.Optional[int] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SearchKnowledgeBasesResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SearchKnowledgeBasesResponse
- Ranked search hits across the selected knowledge bases.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.knowledge_bases.search(
- query="query",
- kb_ids=["kb_ids"],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/knowledge-bases/search",
- method="POST",
- json={
- "query": query,
- "kb_ids": kb_ids,
- "top_k": top_k,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SearchKnowledgeBasesResponse,
- parse_obj_as(
- type_=SearchKnowledgeBasesResponse, # 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)
diff --git a/src/speechify/agent/memories/__init__.py b/src/speechify/agent/memories/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/memories/__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/memories/client.py b/src/speechify/agent/memories/client.py
deleted file mode 100644
index b81cfe6..0000000
--- a/src/speechify/agent/memories/client.py
+++ /dev/null
@@ -1,148 +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 ...core.jsonable_encoder import jsonable_encoder
-from ...errors.unauthorized_error import UnauthorizedError
-from ...core.pydantic_utilities import parse_obj_as
-from ...errors.not_found_error import NotFoundError
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
-from ...core.client_wrapper import AsyncClientWrapper
-
-
-class MemoriesClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def delete(self, memory_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Soft-delete one memory row.
-
- Parameters
- ----------
- memory_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.memories.delete(
- memory_id="memoryId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/memories/{jsonable_encoder(memory_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)
-
-
-class AsyncMemoriesClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def delete(self, memory_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Soft-delete one memory row.
-
- Parameters
- ----------
- memory_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.memories.delete(
- memory_id="memoryId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/memories/{jsonable_encoder(memory_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)
diff --git a/src/speechify/agent/outbound_calls/__init__.py b/src/speechify/agent/outbound_calls/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/outbound_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/outbound_calls/client.py b/src/speechify/agent/outbound_calls/client.py
deleted file mode 100644
index 443ef9e..0000000
--- a/src/speechify/agent/outbound_calls/client.py
+++ /dev/null
@@ -1,330 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from ...core.client_wrapper import SyncClientWrapper
-from ...types.amd_config import AmdConfig
-from ...core.request_options import RequestOptions
-from ...types.create_outbound_call_response import CreateOutboundCallResponse
-from ...core.serialization import convert_and_respect_annotation_metadata
-from ...core.pydantic_utilities import parse_obj_as
-from ...errors.bad_request_error import BadRequestError
-from ...errors.unauthorized_error import UnauthorizedError
-from ...errors.not_found_error import NotFoundError
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
-from ...core.client_wrapper import AsyncClientWrapper
-
-# this is used as the default value for optional parameters
-OMIT = typing.cast(typing.Any, ...)
-
-
-class OutboundCallsClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def create(
- self,
- *,
- agent_id: str,
- to: str,
- caller_id_number: typing.Optional[str] = OMIT,
- dtmf_prefix: typing.Optional[str] = OMIT,
- dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
- ringing_timeout_ms: typing.Optional[int] = OMIT,
- amd: typing.Optional[AmdConfig] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> CreateOutboundCallResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- CreateOutboundCallResponse
- The outbound call was accepted by LiveKit.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.outbound_calls.create(
- agent_id="agent_01HS...",
- to="+41791234567",
- caller_id_number="+12025551234",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/outbound-calls",
- method="POST",
- json={
- "agent_id": agent_id,
- "to": to,
- "caller_id_number": caller_id_number,
- "dtmf_prefix": dtmf_prefix,
- "dynamic_variables": dynamic_variables,
- "ringing_timeout_ms": ringing_timeout_ms,
- "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- CreateOutboundCallResponse,
- parse_obj_as(
- type_=CreateOutboundCallResponse, # 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)
-
-
-class AsyncOutboundCallsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def create(
- self,
- *,
- agent_id: str,
- to: str,
- caller_id_number: typing.Optional[str] = OMIT,
- dtmf_prefix: typing.Optional[str] = OMIT,
- dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
- ringing_timeout_ms: typing.Optional[int] = OMIT,
- amd: typing.Optional[AmdConfig] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> CreateOutboundCallResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- CreateOutboundCallResponse
- The outbound call was accepted by LiveKit.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.outbound_calls.create(
- agent_id="agent_01HS...",
- to="+41791234567",
- caller_id_number="+12025551234",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/outbound-calls",
- method="POST",
- json={
- "agent_id": agent_id,
- "to": to,
- "caller_id_number": caller_id_number,
- "dtmf_prefix": dtmf_prefix,
- "dynamic_variables": dynamic_variables,
- "ringing_timeout_ms": ringing_timeout_ms,
- "amd": convert_and_respect_annotation_metadata(object_=amd, annotation=AmdConfig, direction="write"),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- CreateOutboundCallResponse,
- parse_obj_as(
- type_=CreateOutboundCallResponse, # 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)
diff --git a/src/speechify/agent/phone_numbers/__init__.py b/src/speechify/agent/phone_numbers/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/phone_numbers/__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/phone_numbers/client.py b/src/speechify/agent/phone_numbers/client.py
deleted file mode 100644
index bf124ba..0000000
--- a/src/speechify/agent/phone_numbers/client.py
+++ /dev/null
@@ -1,1392 +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_phone_numbers_response import ListPhoneNumbersResponse
-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.phone_number_source import PhoneNumberSource
-from ...types.twilio_import_spec import TwilioImportSpec
-from ...types.phone_number import PhoneNumber
-from ...core.serialization import convert_and_respect_annotation_metadata
-from ...errors.bad_request_error import BadRequestError
-from ...errors.payment_required_error import PaymentRequiredError
-from ...types.error import Error
-from ...types.search_available_phone_numbers_response import SearchAvailablePhoneNumbersResponse
-from ...errors.service_unavailable_error import ServiceUnavailableError
-from ...errors.unprocessable_entity_error import UnprocessableEntityError
-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 PhoneNumbersClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListPhoneNumbersResponse:
- """
- List all phone numbers in the caller's workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListPhoneNumbersResponse
- The phone numbers for the workspace.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.list()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListPhoneNumbersResponse,
- parse_obj_as(
- type_=ListPhoneNumbersResponse, # 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 import_(
- self,
- *,
- e164: str,
- source: PhoneNumberSource,
- label: typing.Optional[str] = OMIT,
- trunk_id: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- twilio: typing.Optional[TwilioImportSpec] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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.
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The imported phone number.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.import_(
- e164="+12025551234",
- source="livekit",
- label="Trial inbound",
- agent_id="agent_01HS...",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers",
- method="POST",
- json={
- "e164": e164,
- "source": source,
- "label": label,
- "trunk_id": trunk_id,
- "agent_id": agent_id,
- "twilio": convert_and_respect_annotation_metadata(
- object_=twilio, annotation=TwilioImportSpec, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 == 402:
- raise PaymentRequiredError(
- 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 search_available(
- self,
- *,
- country: typing.Optional[str] = None,
- area_code: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SearchAvailablePhoneNumbersResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SearchAvailablePhoneNumbersResponse
- Available numbers (may be empty if no inventory matches).
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.search_available()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers/available",
- method="GET",
- params={
- "country": country,
- "area_code": area_code,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SearchAvailablePhoneNumbersResponse,
- parse_obj_as(
- type_=SearchAvailablePhoneNumbersResponse, # 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 == 503:
- raise ServiceUnavailableError(
- 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 purchase(
- self,
- *,
- e164: str,
- label: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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).
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The purchased phone number.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.purchase(
- e164="+14155552671",
- label="Sales line",
- agent_id="agent_01HS...",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers/purchase",
- method="POST",
- json={
- "e164": e164,
- "label": label,
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 == 402:
- raise PaymentRequiredError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 422:
- raise UnprocessableEntityError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 503:
- raise ServiceUnavailableError(
- 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 get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> PhoneNumber:
- """
- Retrieve a phone number by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- PhoneNumber
- The requested phone number.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.get(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 phone number from the workspace. For Twilio and LiveKit
- numbers this also deprovisions the backing SIP trunk and dispatch
- rule on LiveKit Cloud.
-
- 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.phone_numbers.delete(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{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,
- *,
- label: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- clear_agent_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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.
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The updated phone number.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.phone_numbers.update(
- id="id",
- label="After-hours line",
- agent_id="agent_01HS4X9VBCDEF1234567890AB",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "label": label,
- "agent_id": agent_id,
- "clear_agent_id": clear_agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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)
-
-
-class AsyncPhoneNumbersClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListPhoneNumbersResponse:
- """
- List all phone numbers in the caller's workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListPhoneNumbersResponse
- The phone numbers for the workspace.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.list()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListPhoneNumbersResponse,
- parse_obj_as(
- type_=ListPhoneNumbersResponse, # 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 import_(
- self,
- *,
- e164: str,
- source: PhoneNumberSource,
- label: typing.Optional[str] = OMIT,
- trunk_id: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- twilio: typing.Optional[TwilioImportSpec] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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.
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The imported phone number.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.import_(
- e164="+12025551234",
- source="livekit",
- label="Trial inbound",
- agent_id="agent_01HS...",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers",
- method="POST",
- json={
- "e164": e164,
- "source": source,
- "label": label,
- "trunk_id": trunk_id,
- "agent_id": agent_id,
- "twilio": convert_and_respect_annotation_metadata(
- object_=twilio, annotation=TwilioImportSpec, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 == 402:
- raise PaymentRequiredError(
- 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 search_available(
- self,
- *,
- country: typing.Optional[str] = None,
- area_code: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SearchAvailablePhoneNumbersResponse:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SearchAvailablePhoneNumbersResponse
- Available numbers (may be empty if no inventory matches).
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.search_available()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers/available",
- method="GET",
- params={
- "country": country,
- "area_code": area_code,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SearchAvailablePhoneNumbersResponse,
- parse_obj_as(
- type_=SearchAvailablePhoneNumbersResponse, # 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 == 503:
- raise ServiceUnavailableError(
- 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 purchase(
- self,
- *,
- e164: str,
- label: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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).
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The purchased phone number.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.purchase(
- e164="+14155552671",
- label="Sales line",
- agent_id="agent_01HS...",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/phone-numbers/purchase",
- method="POST",
- json={
- "e164": e164,
- "label": label,
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 == 402:
- raise PaymentRequiredError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 422:
- raise UnprocessableEntityError(
- typing.cast(
- Error,
- parse_obj_as(
- type_=Error, # type: ignore
- object_=_response.json(),
- ),
- )
- )
- if _response.status_code == 503:
- raise ServiceUnavailableError(
- 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 get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> PhoneNumber:
- """
- Retrieve a phone number by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- PhoneNumber
- The requested phone number.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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 phone number from the workspace. For Twilio and LiveKit
- numbers this also deprovisions the backing SIP trunk and dispatch
- rule on LiveKit Cloud.
-
- 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.phone_numbers.delete(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{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,
- *,
- label: typing.Optional[str] = OMIT,
- agent_id: typing.Optional[str] = OMIT,
- clear_agent_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> PhoneNumber:
- """
- 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.
-
- 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.
-
- Returns
- -------
- PhoneNumber
- The updated phone number.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.phone_numbers.update(
- id="id",
- label="After-hours line",
- agent_id="agent_01HS4X9VBCDEF1234567890AB",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/phone-numbers/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "label": label,
- "agent_id": agent_id,
- "clear_agent_id": clear_agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- PhoneNumber,
- parse_obj_as(
- type_=PhoneNumber, # 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)
diff --git a/src/speechify/agent/sip_trunks/__init__.py b/src/speechify/agent/sip_trunks/__init__.py
deleted file mode 100644
index f3ea265..0000000
--- a/src/speechify/agent/sip_trunks/__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/sip_trunks/client.py b/src/speechify/agent/sip_trunks/client.py
deleted file mode 100644
index 62ebdc5..0000000
--- a/src/speechify/agent/sip_trunks/client.py
+++ /dev/null
@@ -1,718 +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_sip_trunks_response import ListSipTrunksResponse
-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.sip_trunk_kind import SipTrunkKind
-from ...types.sip_trunk_direction import SipTrunkDirection
-from ...types.sip_transport import SipTransport
-from ...types.sip_media_encryption import SipMediaEncryption
-from ...types.sip_trunk import SipTrunk
-from ...errors.bad_request_error import BadRequestError
-from ...errors.payment_required_error import PaymentRequiredError
-from ...types.error import Error
-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 SipTrunksClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListSipTrunksResponse:
- """
- List all SIP trunks in the caller's workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListSipTrunksResponse
- The SIP trunks for the workspace.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.sip_trunks.list()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/sip-trunks",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListSipTrunksResponse,
- parse_obj_as(
- type_=ListSipTrunksResponse, # 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,
- kind: SipTrunkKind,
- direction: SipTrunkDirection,
- sip_address: typing.Optional[str] = OMIT,
- auth_username: typing.Optional[str] = OMIT,
- auth_password: typing.Optional[str] = OMIT,
- allowed_addresses: typing.Optional[typing.Sequence[str]] = OMIT,
- destination_country: typing.Optional[str] = OMIT,
- transport: typing.Optional[SipTransport] = OMIT,
- media_encryption: typing.Optional[SipMediaEncryption] = OMIT,
- credentials: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SipTrunk:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SipTrunk
- The created SIP trunk.
-
- Examples
- --------
- 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",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/sip-trunks",
- method="POST",
- json={
- "name": name,
- "kind": kind,
- "direction": direction,
- "sip_address": sip_address,
- "auth_username": auth_username,
- "auth_password": auth_password,
- "allowed_addresses": allowed_addresses,
- "destination_country": destination_country,
- "transport": transport,
- "media_encryption": media_encryption,
- "credentials": credentials,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SipTrunk,
- parse_obj_as(
- type_=SipTrunk, # 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 == 402:
- raise PaymentRequiredError(
- 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 get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SipTrunk:
- """
- Retrieve a SIP trunk by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- SipTrunk
- The requested SIP trunk.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.sip_trunks.get(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/sip-trunks/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SipTrunk,
- parse_obj_as(
- type_=SipTrunk, # 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 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.
-
- 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.sip_trunks.delete(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/sip-trunks/{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)
-
-
-class AsyncSipTrunksClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> ListSipTrunksResponse:
- """
- List all SIP trunks in the caller's workspace.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListSipTrunksResponse
- The SIP trunks for the workspace.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.sip_trunks.list()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/sip-trunks",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListSipTrunksResponse,
- parse_obj_as(
- type_=ListSipTrunksResponse, # 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,
- kind: SipTrunkKind,
- direction: SipTrunkDirection,
- sip_address: typing.Optional[str] = OMIT,
- auth_username: typing.Optional[str] = OMIT,
- auth_password: typing.Optional[str] = OMIT,
- allowed_addresses: typing.Optional[typing.Sequence[str]] = OMIT,
- destination_country: typing.Optional[str] = OMIT,
- transport: typing.Optional[SipTransport] = OMIT,
- media_encryption: typing.Optional[SipMediaEncryption] = OMIT,
- credentials: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SipTrunk:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SipTrunk
- The created SIP trunk.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await 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",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/sip-trunks",
- method="POST",
- json={
- "name": name,
- "kind": kind,
- "direction": direction,
- "sip_address": sip_address,
- "auth_username": auth_username,
- "auth_password": auth_password,
- "allowed_addresses": allowed_addresses,
- "destination_country": destination_country,
- "transport": transport,
- "media_encryption": media_encryption,
- "credentials": credentials,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SipTrunk,
- parse_obj_as(
- type_=SipTrunk, # 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 == 402:
- raise PaymentRequiredError(
- 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 get(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> SipTrunk:
- """
- Retrieve a SIP trunk by ID.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- SipTrunk
- The requested SIP trunk.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.sip_trunks.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/sip-trunks/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- SipTrunk,
- parse_obj_as(
- type_=SipTrunk, # 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 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.
-
- 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.sip_trunks.delete(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/sip-trunks/{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)
diff --git a/src/speechify/agent/tests/__init__.py b/src/speechify/agent/tests/__init__.py
deleted file mode 100644
index 3bd662a..0000000
--- a/src/speechify/agent/tests/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .types import UpdateAgentTestRequestConfig
-
-__all__ = ["UpdateAgentTestRequestConfig"]
diff --git a/src/speechify/agent/tests/client.py b/src/speechify/agent/tests/client.py
deleted file mode 100644
index 248902d..0000000
--- a/src/speechify/agent/tests/client.py
+++ /dev/null
@@ -1,3242 +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.agent_test import AgentTest
-from ...core.jsonable_encoder import jsonable_encoder
-from ...core.pydantic_utilities import parse_obj_as
-from ...errors.unauthorized_error import UnauthorizedError
-from ...errors.not_found_error import NotFoundError
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
-from .types.update_agent_test_request_config import UpdateAgentTestRequestConfig
-from ...types.tool_mock_config import ToolMockConfig
-from ...core.serialization import convert_and_respect_annotation_metadata
-from ...errors.bad_request_error import BadRequestError
-from ...core.pagination import SyncPager
-from ...types.agent_test_run import AgentTestRun
-from ...types.list_agent_test_runs_response import ListAgentTestRunsResponse
-from ...types.agent_test_suite_run import AgentTestSuiteRun
-from ...types.list_suite_runs_response import ListSuiteRunsResponse
-from ...types.agent_test_suite_run_with_runs import AgentTestSuiteRunWithRuns
-from ...types.run_agent_tests_response import RunAgentTestsResponse
-from ...types.agent_test_with_last_run import AgentTestWithLastRun
-from ...types.list_tests_response import ListTestsResponse
-from ...types.test_stats import TestStats
-from ...types.batch_run_entry import BatchRunEntry
-from ...types.run_batch_response import RunBatchResponse
-from ...types.list_agent_test_attachments_response import ListAgentTestAttachmentsResponse
-from ...types.list_agent_test_folders_response import ListAgentTestFoldersResponse
-from ...types.agent_test_folder import AgentTestFolder
-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 TestsClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- def get_test(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentTest:
- """
- Retrieve a test by ID.
-
- Parameters
- ----------
- id : str
- Test ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTest
- The requested test.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.get_test(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- 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 == 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_test(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a test and all its run history.
-
- Parameters
- ----------
- id : str
- Test ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.delete_test(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{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_test(
- self,
- id: str,
- *,
- name: typing.Optional[str] = OMIT,
- description: typing.Optional[str] = OMIT,
- config: typing.Optional[UpdateAgentTestRequestConfig] = OMIT,
- tool_mock_config: typing.Optional[ToolMockConfig] = OMIT,
- folder_id: typing.Optional[str] = OMIT,
- clear_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTest:
- """
- Update a test. Only fields present on the request body are changed.
-
- 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.
-
- Returns
- -------
- AgentTest
- The updated test.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.update_test(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=UpdateAgentTestRequestConfig, direction="write"
- ),
- "tool_mock_config": convert_and_respect_annotation_metadata(
- object_=tool_mock_config, annotation=ToolMockConfig, direction="write"
- ),
- "folder_id": folder_id,
- "clear_folder_id": clear_folder_id,
- },
- 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 list_test_runs(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[AgentTestRun]:
- """
- List one page of run history for a test, newest first.
- Paginate by passing `cursor` from the previous response.
-
- 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.
-
- Returns
- -------
- SyncPager[AgentTestRun]
- Run history for the test.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/runs",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListAgentTestRunsResponse,
- parse_obj_as(
- type_=ListAgentTestRunsResponse, # 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_test_runs(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.runs
- 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 run_test(
- self, id: str, *, agent_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> AgentTestRun:
- """
- 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`).
-
- 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.
-
- Returns
- -------
- AgentTestRun
- The queued run.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.run_test(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/runs",
- method="POST",
- json={
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestRun,
- parse_obj_as(
- type_=AgentTestRun, # 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_test_run(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentTestRun:
- """
- 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.
-
- Parameters
- ----------
- id : str
- Test run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTestRun
- The test run.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.get_test_run(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/runs/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestRun,
- parse_obj_as(
- type_=AgentTestRun, # 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_suite_runs(
- self,
- *,
- agent_id: typing.Optional[str] = None,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[AgentTestSuiteRun]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[AgentTestSuiteRun]
- One page of suite runs.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests/suite-runs",
- method="GET",
- params={
- "agent_id": agent_id,
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListSuiteRunsResponse,
- parse_obj_as(
- type_=ListSuiteRunsResponse, # 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_suite_runs(
- agent_id=agent_id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.suite_runs
- 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_suite_run(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> AgentTestSuiteRunWithRuns:
- """
- Retrieve a suite run by ID with its child runs and the derived
- aggregate status and pass/fail/error counts.
-
- Parameters
- ----------
- id : str
- Suite run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTestSuiteRunWithRuns
- The suite run with its child runs.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.get_suite_run(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/suite-runs/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestSuiteRunWithRuns,
- parse_obj_as(
- type_=AgentTestSuiteRunWithRuns, # 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 resubmit_suite_run(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> RunAgentTestsResponse:
- """
- 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.
-
- Parameters
- ----------
- id : str
- Suite run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- RunAgentTestsResponse
- The new suite run and its queued child runs.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.resubmit_suite_run(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/suite-runs/{jsonable_encoder(id)}/resubmit",
- method="POST",
- request_options=request_options,
- )
- 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 list_all_tests(
- self,
- *,
- agent_id: typing.Optional[str] = None,
- type: typing.Optional[str] = None,
- status: typing.Optional[str] = None,
- folder_id: typing.Optional[str] = None,
- updated_after: typing.Optional[str] = None,
- q: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- cursor: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> SyncPager[AgentTestWithLastRun]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[AgentTestWithLastRun]
- Paginated list.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests",
- method="GET",
- params={
- "agent_id": agent_id,
- "type": type,
- "status": status,
- "folder_id": folder_id,
- "updated_after": updated_after,
- "q": q,
- "limit": limit,
- "cursor": cursor,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListTestsResponse,
- parse_obj_as(
- type_=ListTestsResponse, # 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_all_tests(
- agent_id=agent_id,
- type=type,
- status=status,
- folder_id=folder_id,
- updated_after=updated_after,
- q=q,
- limit=limit,
- cursor=_parsed_next,
- request_options=request_options,
- )
- _items = _parsed_response.tests
- 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 get_test_stats(
- self, *, window_days: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> TestStats:
- """
- 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.
-
- Parameters
- ----------
- window_days : typing.Optional[int]
- Trailing window in days (default 30, max 90).
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- TestStats
- Stats payload.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.get_test_stats()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests/stats",
- method="GET",
- params={
- "window_days": window_days,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- TestStats,
- parse_obj_as(
- type_=TestStats, # 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 run_tests_batch(
- self, *, entries: typing.Sequence[BatchRunEntry], request_options: typing.Optional[RequestOptions] = None
- ) -> RunBatchResponse:
- """
- 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.
-
- Parameters
- ----------
- entries : typing.Sequence[BatchRunEntry]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- RunBatchResponse
- Runs queued.
-
- Examples
- --------
- from speechify import BatchRunEntry, Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.run_tests_batch(
- entries=[
- BatchRunEntry(
- test_id="test_01ky612y9cb7dbaj638x46msxv",
- )
- ],
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests/runs/batch",
- method="POST",
- json={
- "entries": convert_and_respect_annotation_metadata(
- object_=entries, annotation=typing.Sequence[BatchRunEntry], direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- RunBatchResponse,
- parse_obj_as(
- type_=RunBatchResponse, # 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_test_attachments(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListAgentTestAttachmentsResponse:
- """
- List every agent a test is attached to.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListAgentTestAttachmentsResponse
- Attachment list.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.list_test_attachments(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListAgentTestAttachmentsResponse,
- parse_obj_as(
- type_=ListAgentTestAttachmentsResponse, # 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_test(self, id: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- agent_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.attach_test(
- id="id",
- agent_id="agentId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments/{jsonable_encoder(agent_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_test(self, id: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Detach a test from an agent. The owner agent (the agent the test
- was authored against) cannot be detached; delete the test
- instead.
-
- Parameters
- ----------
- id : str
-
- agent_id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- None
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.detach_test(
- id="id",
- agent_id="agentId",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments/{jsonable_encoder(agent_id)}",
- method="DELETE",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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_test_folders(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListAgentTestFoldersResponse:
- """
- List every test folder the caller owns. Flat list; build the tree client-side.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListAgentTestFoldersResponse
- Folder list.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.list_test_folders()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests/folders",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListAgentTestFoldersResponse,
- parse_obj_as(
- type_=ListAgentTestFoldersResponse, # 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_test_folder(
- self,
- *,
- name: str,
- parent_folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTestFolder:
- """
- Create a test folder. Max depth is 3.
-
- 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.
-
- Returns
- -------
- AgentTestFolder
- Created folder.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.create_test_folder(
- name="name",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tests/folders",
- method="POST",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestFolder,
- parse_obj_as(
- type_=AgentTestFolder, # 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 delete_test_folder(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Soft-delete a folder. Child tests drop back to root.
-
- 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.tests.delete_test_folder(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/folders/{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_test_folder(
- self,
- id: str,
- *,
- name: typing.Optional[str] = OMIT,
- parent_folder_id: typing.Optional[str] = OMIT,
- clear_parent_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTestFolder:
- """
- Rename or reparent a test folder. Cycles are rejected.
-
- 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.
-
- Returns
- -------
- AgentTestFolder
- Updated folder.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tests.update_test_folder(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/folders/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- "clear_parent_folder_id": clear_parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestFolder,
- parse_obj_as(
- type_=AgentTestFolder, # 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)
-
-
-class AsyncTestsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def get_test(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentTest:
- """
- Retrieve a test by ID.
-
- Parameters
- ----------
- id : str
- Test ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTest
- The requested test.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.get_test(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- 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 == 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_test(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Delete a test and all its run history.
-
- Parameters
- ----------
- id : str
- Test 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.tests.delete_test(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{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_test(
- self,
- id: str,
- *,
- name: typing.Optional[str] = OMIT,
- description: typing.Optional[str] = OMIT,
- config: typing.Optional[UpdateAgentTestRequestConfig] = OMIT,
- tool_mock_config: typing.Optional[ToolMockConfig] = OMIT,
- folder_id: typing.Optional[str] = OMIT,
- clear_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTest:
- """
- Update a test. Only fields present on the request body are changed.
-
- 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.
-
- Returns
- -------
- AgentTest
- The updated test.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.update_test(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=UpdateAgentTestRequestConfig, direction="write"
- ),
- "tool_mock_config": convert_and_respect_annotation_metadata(
- object_=tool_mock_config, annotation=ToolMockConfig, direction="write"
- ),
- "folder_id": folder_id,
- "clear_folder_id": clear_folder_id,
- },
- 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 list_test_runs(
- self,
- id: str,
- *,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[AgentTestRun]:
- """
- List one page of run history for a test, newest first.
- Paginate by passing `cursor` from the previous response.
-
- 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.
-
- Returns
- -------
- AsyncPager[AgentTestRun]
- Run history for the test.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.tests.list_test_runs(
- 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/tests/{jsonable_encoder(id)}/runs",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListAgentTestRunsResponse,
- parse_obj_as(
- type_=ListAgentTestRunsResponse, # 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_test_runs(
- id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.runs
- 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(),
- ),
- )
- )
- 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_test(
- self, id: str, *, agent_id: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None
- ) -> AgentTestRun:
- """
- 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`).
-
- 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.
-
- Returns
- -------
- AgentTestRun
- The queued run.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.run_test(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/runs",
- method="POST",
- json={
- "agent_id": agent_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestRun,
- parse_obj_as(
- type_=AgentTestRun, # 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_test_run(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentTestRun:
- """
- 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.
-
- Parameters
- ----------
- id : str
- Test run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTestRun
- The test run.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.get_test_run(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/runs/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestRun,
- parse_obj_as(
- type_=AgentTestRun, # 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_suite_runs(
- self,
- *,
- agent_id: typing.Optional[str] = None,
- cursor: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[AgentTestSuiteRun]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[AgentTestSuiteRun]
- One page of suite runs.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.tests.list_suite_runs()
- 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/tests/suite-runs",
- method="GET",
- params={
- "agent_id": agent_id,
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListSuiteRunsResponse,
- parse_obj_as(
- type_=ListSuiteRunsResponse, # 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_suite_runs(
- agent_id=agent_id,
- cursor=_parsed_next,
- limit=limit,
- request_options=request_options,
- )
- _items = _parsed_response.suite_runs
- 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(),
- ),
- )
- )
- 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_suite_run(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> AgentTestSuiteRunWithRuns:
- """
- Retrieve a suite run by ID with its child runs and the derived
- aggregate status and pass/fail/error counts.
-
- Parameters
- ----------
- id : str
- Suite run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AgentTestSuiteRunWithRuns
- The suite run with its child runs.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.get_suite_run(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/suite-runs/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestSuiteRunWithRuns,
- parse_obj_as(
- type_=AgentTestSuiteRunWithRuns, # 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 resubmit_suite_run(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> RunAgentTestsResponse:
- """
- 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.
-
- Parameters
- ----------
- id : str
- Suite run ID.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- RunAgentTestsResponse
- The new suite run and its queued child runs.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.resubmit_suite_run(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/suite-runs/{jsonable_encoder(id)}/resubmit",
- method="POST",
- request_options=request_options,
- )
- 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 list_all_tests(
- self,
- *,
- agent_id: typing.Optional[str] = None,
- type: typing.Optional[str] = None,
- status: typing.Optional[str] = None,
- folder_id: typing.Optional[str] = None,
- updated_after: typing.Optional[str] = None,
- q: typing.Optional[str] = None,
- limit: typing.Optional[int] = None,
- cursor: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncPager[AgentTestWithLastRun]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[AgentTestWithLastRun]
- Paginated list.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.tests.list_all_tests()
- 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/tests",
- method="GET",
- params={
- "agent_id": agent_id,
- "type": type,
- "status": status,
- "folder_id": folder_id,
- "updated_after": updated_after,
- "q": q,
- "limit": limit,
- "cursor": cursor,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListTestsResponse,
- parse_obj_as(
- type_=ListTestsResponse, # 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_all_tests(
- agent_id=agent_id,
- type=type,
- status=status,
- folder_id=folder_id,
- updated_after=updated_after,
- q=q,
- limit=limit,
- cursor=_parsed_next,
- request_options=request_options,
- )
- _items = _parsed_response.tests
- return AsyncPager(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)
-
- async def get_test_stats(
- self, *, window_days: typing.Optional[int] = None, request_options: typing.Optional[RequestOptions] = None
- ) -> TestStats:
- """
- 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.
-
- Parameters
- ----------
- window_days : typing.Optional[int]
- Trailing window in days (default 30, max 90).
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- TestStats
- Stats payload.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.get_test_stats()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tests/stats",
- method="GET",
- params={
- "window_days": window_days,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- TestStats,
- parse_obj_as(
- type_=TestStats, # 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 run_tests_batch(
- self, *, entries: typing.Sequence[BatchRunEntry], request_options: typing.Optional[RequestOptions] = None
- ) -> RunBatchResponse:
- """
- 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.
-
- Parameters
- ----------
- entries : typing.Sequence[BatchRunEntry]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- RunBatchResponse
- Runs queued.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, BatchRunEntry
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.run_tests_batch(
- entries=[
- BatchRunEntry(
- test_id="test_01ky612y9cb7dbaj638x46msxv",
- )
- ],
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tests/runs/batch",
- method="POST",
- json={
- "entries": convert_and_respect_annotation_metadata(
- object_=entries, annotation=typing.Sequence[BatchRunEntry], direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- RunBatchResponse,
- parse_obj_as(
- type_=RunBatchResponse, # 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_test_attachments(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListAgentTestAttachmentsResponse:
- """
- List every agent a test is attached to.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListAgentTestAttachmentsResponse
- Attachment list.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.list_test_attachments(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListAgentTestAttachmentsResponse,
- parse_obj_as(
- type_=ListAgentTestAttachmentsResponse, # 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_test(
- self, id: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- agent_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.tests.attach_test(
- id="id",
- agent_id="agentId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments/{jsonable_encoder(agent_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_test(
- self, id: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> None:
- """
- Detach a test from an agent. The owner agent (the agent the test
- was authored against) cannot be detached; delete the test
- instead.
-
- Parameters
- ----------
- id : str
-
- agent_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.tests.detach_test(
- id="id",
- agent_id="agentId",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/{jsonable_encoder(id)}/attachments/{jsonable_encoder(agent_id)}",
- method="DELETE",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return
- 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_test_folders(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListAgentTestFoldersResponse:
- """
- List every test folder the caller owns. Flat list; build the tree client-side.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListAgentTestFoldersResponse
- Folder list.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.list_test_folders()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tests/folders",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListAgentTestFoldersResponse,
- parse_obj_as(
- type_=ListAgentTestFoldersResponse, # 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_test_folder(
- self,
- *,
- name: str,
- parent_folder_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTestFolder:
- """
- Create a test folder. Max depth is 3.
-
- 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.
-
- Returns
- -------
- AgentTestFolder
- Created folder.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.create_test_folder(
- name="name",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tests/folders",
- method="POST",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestFolder,
- parse_obj_as(
- type_=AgentTestFolder, # 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 delete_test_folder(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
- """
- Soft-delete a folder. Child tests drop back to root.
-
- 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.tests.delete_test_folder(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/folders/{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_test_folder(
- self,
- id: str,
- *,
- name: typing.Optional[str] = OMIT,
- parent_folder_id: typing.Optional[str] = OMIT,
- clear_parent_folder_id: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AgentTestFolder:
- """
- Rename or reparent a test folder. Cycles are rejected.
-
- 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.
-
- Returns
- -------
- AgentTestFolder
- Updated folder.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tests.update_test_folder(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tests/folders/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "parent_folder_id": parent_folder_id,
- "clear_parent_folder_id": clear_parent_folder_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- AgentTestFolder,
- parse_obj_as(
- type_=AgentTestFolder, # 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)
diff --git a/src/speechify/agent/tests/types/__init__.py b/src/speechify/agent/tests/types/__init__.py
deleted file mode 100644
index ef18feb..0000000
--- a/src/speechify/agent/tests/types/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .update_agent_test_request_config import UpdateAgentTestRequestConfig
-
-__all__ = ["UpdateAgentTestRequestConfig"]
diff --git a/src/speechify/agent/tests/types/update_agent_test_request_config.py b/src/speechify/agent/tests/types/update_agent_test_request_config.py
deleted file mode 100644
index 67ebadb..0000000
--- a/src/speechify/agent/tests/types/update_agent_test_request_config.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from ....types.reply_config import ReplyConfig
-from ....types.tool_call_config import ToolCallConfig
-from ....types.simulation_config import SimulationConfig
-
-UpdateAgentTestRequestConfig = typing.Union[ReplyConfig, ToolCallConfig, SimulationConfig]
diff --git a/src/speechify/agent/tools/__init__.py b/src/speechify/agent/tools/__init__.py
deleted file mode 100644
index 3d29f5d..0000000
--- a/src/speechify/agent/tools/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .types import CreateToolRequestConfig, UpdateToolRequestConfig
-
-__all__ = ["CreateToolRequestConfig", "UpdateToolRequestConfig"]
diff --git a/src/speechify/agent/tools/client.py b/src/speechify/agent/tools/client.py
deleted file mode 100644
index 0dd91d9..0000000
--- a/src/speechify/agent/tools/client.py
+++ /dev/null
@@ -1,1808 +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.tool import Tool
-from ...types.list_tools_response import ListToolsResponse
-from ...core.pydantic_utilities import parse_obj_as
-from ...errors.bad_request_error import BadRequestError
-from ...errors.unauthorized_error import UnauthorizedError
-from json.decoder import JSONDecodeError
-from ...core.api_error import ApiError
-from ...types.tool_kind import ToolKind
-from .types.create_tool_request_config import CreateToolRequestConfig
-from ...core.serialization import convert_and_respect_annotation_metadata
-from ...core.jsonable_encoder import jsonable_encoder
-from ...errors.not_found_error import NotFoundError
-from .types.update_tool_request_config import UpdateToolRequestConfig
-from ...types.list_tool_attached_agents_response import ListToolAttachedAgentsResponse
-from ...types.list_system_builtins_response import ListSystemBuiltinsResponse
-from ...types.mcp_tool_config import McpToolConfig
-from ...types.mcp_probe_result import McpProbeResult
-from ...types.webhook_tool_config import WebhookToolConfig
-from ...types.webhook_probe_result import WebhookProbeResult
-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 ToolsClient:
- 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[Tool]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- SyncPager[Tool]
- A list of tools.
-
- Examples
- --------
- 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
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tools",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListToolsResponse,
- parse_obj_as(
- type_=ListToolsResponse, # 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.tools
- 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 create(
- self,
- *,
- name: str,
- description: str,
- kind: ToolKind,
- config: CreateToolRequestConfig,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> Tool:
- """
- Create a tool. For webhook tools, the response includes the HMAC
- `webhook_secret` exactly once — store it immediately; subsequent
- reads return a masked placeholder.
-
- Parameters
- ----------
- name : str
-
- description : str
-
- kind : ToolKind
-
- config : CreateToolRequestConfig
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The created tool.
-
- Examples
- --------
- from speechify import Speechify, ToolParam, WebhookToolConfig
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.create(
- name="lookup_order",
- description="Fetch order details by order ID.",
- kind="webhook",
- config=WebhookToolConfig(
- url="https://api.your-app.com/webhooks/lookup-order",
- method="POST",
- timeout_ms=5000,
- headers={"X-Org-ID": "acme"},
- params=[
- ToolParam(
- name="order_id",
- type="string",
- description="Order ID",
- required=True,
- )
- ],
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tools",
- method="POST",
- json={
- "name": name,
- "description": description,
- "kind": kind,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=CreateToolRequestConfig, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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) -> Tool:
- """
- Retrieve a tool by ID. Webhook secrets are always masked here.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The requested tool.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.get(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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 tool. Agents that had it attached get a soft-detach.
-
- 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.tools.delete(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{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,
- description: typing.Optional[str] = OMIT,
- config: typing.Optional[UpdateToolRequestConfig] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> Tool:
- """
- Update a tool. Tool kind is immutable — create a new tool to change it.
-
- Parameters
- ----------
- id : str
-
- name : typing.Optional[str]
-
- description : typing.Optional[str]
-
- config : typing.Optional[UpdateToolRequestConfig]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The updated tool.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.update(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=UpdateToolRequestConfig, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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_attached_agents(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListToolAttachedAgentsResponse:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListToolAttachedAgentsResponse
- Agents in the caller's workspace attached to the tool.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.list_attached_agents(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}/attached-agents",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListToolAttachedAgentsResponse,
- parse_obj_as(
- type_=ListToolAttachedAgentsResponse, # 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 rotate_secret(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Tool:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The tool with its newly-rotated webhook_secret.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.rotate_secret(
- id="id",
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}/rotate-secret",
- method="POST",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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_system_builtins(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListSystemBuiltinsResponse:
- """
- 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.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListSystemBuiltinsResponse
- The catalogue of registered system builtins.
-
- Examples
- --------
- from speechify import Speechify
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.list_system_builtins()
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tools/system-builtins",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListSystemBuiltinsResponse,
- parse_obj_as(
- type_=ListSystemBuiltinsResponse, # 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 test_mcp_connection(
- self,
- *,
- config: McpToolConfig,
- tool_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> McpProbeResult:
- """
- 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.
-
- 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.
-
- Returns
- -------
- McpProbeResult
- Probe result. The 200 envelope is used for both success and
- structured failure — inspect `error` to disambiguate. Network
- and validation failures never bubble up as non-2xx so the
- console can render them inline next to the form.
-
- Examples
- --------
- 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(),
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tools/test-mcp-connection",
- method="POST",
- json={
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=McpToolConfig, direction="write"
- ),
- "tool_id": tool_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- McpProbeResult,
- parse_obj_as(
- type_=McpProbeResult, # 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 test_webhook_connection(
- self,
- *,
- config: WebhookToolConfig,
- tool_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> WebhookProbeResult:
- """
- 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.
-
- 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.
-
- Returns
- -------
- WebhookProbeResult
- Probe result. The 200 envelope is used for both success and
- structured failure — inspect `error` to disambiguate. A
- non-2xx response from the endpoint is NOT an `error`: it
- populates `status_code` / `response_body` with `ok=false`.
- Transport and validation failures never bubble up as non-2xx
- so the console can render them inline next to the form.
-
- Examples
- --------
- from speechify import Speechify, WebhookToolConfig
-
- client = Speechify(
- token="YOUR_TOKEN",
- )
- client.agent.tools.test_webhook_connection(
- config=WebhookToolConfig(
- url="url",
- ),
- )
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/agents/tools/test-webhook-connection",
- method="POST",
- json={
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=WebhookToolConfig, direction="write"
- ),
- "tool_id": tool_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- WebhookProbeResult,
- parse_obj_as(
- type_=WebhookProbeResult, # 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)
-
-
-class AsyncToolsClient:
- 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[Tool]:
- """
- 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.
-
- 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.
-
- Returns
- -------
- AsyncPager[Tool]
- A list of tools.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- response = await client.agent.tools.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/tools",
- method="GET",
- params={
- "cursor": cursor,
- "limit": limit,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _parsed_response = typing.cast(
- ListToolsResponse,
- parse_obj_as(
- type_=ListToolsResponse, # 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.tools
- 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(),
- ),
- )
- )
- 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,
- description: str,
- kind: ToolKind,
- config: CreateToolRequestConfig,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> Tool:
- """
- Create a tool. For webhook tools, the response includes the HMAC
- `webhook_secret` exactly once — store it immediately; subsequent
- reads return a masked placeholder.
-
- Parameters
- ----------
- name : str
-
- description : str
-
- kind : ToolKind
-
- config : CreateToolRequestConfig
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The created tool.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, ToolParam, WebhookToolConfig
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.create(
- name="lookup_order",
- description="Fetch order details by order ID.",
- kind="webhook",
- config=WebhookToolConfig(
- url="https://api.your-app.com/webhooks/lookup-order",
- method="POST",
- timeout_ms=5000,
- headers={"X-Org-ID": "acme"},
- params=[
- ToolParam(
- name="order_id",
- type="string",
- description="Order ID",
- required=True,
- )
- ],
- ),
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tools",
- method="POST",
- json={
- "name": name,
- "description": description,
- "kind": kind,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=CreateToolRequestConfig, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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) -> Tool:
- """
- Retrieve a tool by ID. Webhook secrets are always masked here.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The requested tool.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.get(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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 tool. Agents that had it attached get a soft-detach.
-
- 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.tools.delete(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{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,
- description: typing.Optional[str] = OMIT,
- config: typing.Optional[UpdateToolRequestConfig] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> Tool:
- """
- Update a tool. Tool kind is immutable — create a new tool to change it.
-
- Parameters
- ----------
- id : str
-
- name : typing.Optional[str]
-
- description : typing.Optional[str]
-
- config : typing.Optional[UpdateToolRequestConfig]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The updated tool.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.update(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}",
- method="PATCH",
- json={
- "name": name,
- "description": description,
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=UpdateToolRequestConfig, direction="write"
- ),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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_attached_agents(
- self, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListToolAttachedAgentsResponse:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListToolAttachedAgentsResponse
- Agents in the caller's workspace attached to the tool.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.list_attached_agents(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}/attached-agents",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListToolAttachedAgentsResponse,
- parse_obj_as(
- type_=ListToolAttachedAgentsResponse, # 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 rotate_secret(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> Tool:
- """
- 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.
-
- Parameters
- ----------
- id : str
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- Tool
- The tool with its newly-rotated webhook_secret.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.rotate_secret(
- id="id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/agents/tools/{jsonable_encoder(id)}/rotate-secret",
- method="POST",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- Tool,
- parse_obj_as(
- type_=Tool, # 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_system_builtins(
- self, *, request_options: typing.Optional[RequestOptions] = None
- ) -> ListSystemBuiltinsResponse:
- """
- 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.
-
- Parameters
- ----------
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ListSystemBuiltinsResponse
- The catalogue of registered system builtins.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.list_system_builtins()
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tools/system-builtins",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- ListSystemBuiltinsResponse,
- parse_obj_as(
- type_=ListSystemBuiltinsResponse, # 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 test_mcp_connection(
- self,
- *,
- config: McpToolConfig,
- tool_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> McpProbeResult:
- """
- 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.
-
- 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.
-
- Returns
- -------
- McpProbeResult
- Probe result. The 200 envelope is used for both success and
- structured failure — inspect `error` to disambiguate. Network
- and validation failures never bubble up as non-2xx so the
- console can render them inline next to the form.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, McpAuth_None, McpToolConfig
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.test_mcp_connection(
- config=McpToolConfig(
- endpoint="endpoint",
- auth=McpAuth_None(),
- ),
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tools/test-mcp-connection",
- method="POST",
- json={
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=McpToolConfig, direction="write"
- ),
- "tool_id": tool_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- McpProbeResult,
- parse_obj_as(
- type_=McpProbeResult, # 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 test_webhook_connection(
- self,
- *,
- config: WebhookToolConfig,
- tool_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> WebhookProbeResult:
- """
- 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.
-
- 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.
-
- Returns
- -------
- WebhookProbeResult
- Probe result. The 200 envelope is used for both success and
- structured failure — inspect `error` to disambiguate. A
- non-2xx response from the endpoint is NOT an `error`: it
- populates `status_code` / `response_body` with `ok=false`.
- Transport and validation failures never bubble up as non-2xx
- so the console can render them inline next to the form.
-
- Examples
- --------
- import asyncio
-
- from speechify import AsyncSpeechify, WebhookToolConfig
-
- client = AsyncSpeechify(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.agent.tools.test_webhook_connection(
- config=WebhookToolConfig(
- url="url",
- ),
- )
-
-
- asyncio.run(main())
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/agents/tools/test-webhook-connection",
- method="POST",
- json={
- "config": convert_and_respect_annotation_metadata(
- object_=config, annotation=WebhookToolConfig, direction="write"
- ),
- "tool_id": tool_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- return typing.cast(
- WebhookProbeResult,
- parse_obj_as(
- type_=WebhookProbeResult, # 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)
diff --git a/src/speechify/agent/tools/types/__init__.py b/src/speechify/agent/tools/types/__init__.py
deleted file mode 100644
index 5bc7f9e..0000000
--- a/src/speechify/agent/tools/types/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .create_tool_request_config import CreateToolRequestConfig
-from .update_tool_request_config import UpdateToolRequestConfig
-
-__all__ = ["CreateToolRequestConfig", "UpdateToolRequestConfig"]
diff --git a/src/speechify/agent/tools/types/create_tool_request_config.py b/src/speechify/agent/tools/types/create_tool_request_config.py
deleted file mode 100644
index bf5f33b..0000000
--- a/src/speechify/agent/tools/types/create_tool_request_config.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from ....types.system_tool_config import SystemToolConfig
-from ....types.webhook_tool_config import WebhookToolConfig
-from ....types.client_tool_config import ClientToolConfig
-from ....types.mcp_tool_config import McpToolConfig
-
-CreateToolRequestConfig = typing.Union[SystemToolConfig, WebhookToolConfig, ClientToolConfig, McpToolConfig]
diff --git a/src/speechify/agent/tools/types/update_tool_request_config.py b/src/speechify/agent/tools/types/update_tool_request_config.py
deleted file mode 100644
index 3890252..0000000
--- a/src/speechify/agent/tools/types/update_tool_request_config.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from ....types.system_tool_config import SystemToolConfig
-from ....types.webhook_tool_config import WebhookToolConfig
-from ....types.client_tool_config import ClientToolConfig
-from ....types.mcp_tool_config import McpToolConfig
-
-UpdateToolRequestConfig = typing.Union[SystemToolConfig, WebhookToolConfig, ClientToolConfig, McpToolConfig]
diff --git a/src/speechify/agent/types/__init__.py b/src/speechify/agent/types/__init__.py
deleted file mode 100644
index 97a2ec4..0000000
--- a/src/speechify/agent/types/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .create_agent_request_background_noise_preset import CreateAgentRequestBackgroundNoisePreset
-from .create_agent_request_llm_provider import CreateAgentRequestLlmProvider
-from .create_agent_request_stt_override import CreateAgentRequestSttOverride
-from .create_agent_test_request_config import CreateAgentTestRequestConfig
-from .update_agent_request_background_noise_preset import UpdateAgentRequestBackgroundNoisePreset
-from .update_agent_request_llm_provider import UpdateAgentRequestLlmProvider
-from .update_agent_request_stt_override import UpdateAgentRequestSttOverride
-
-__all__ = [
- "CreateAgentRequestBackgroundNoisePreset",
- "CreateAgentRequestLlmProvider",
- "CreateAgentRequestSttOverride",
- "CreateAgentTestRequestConfig",
- "UpdateAgentRequestBackgroundNoisePreset",
- "UpdateAgentRequestLlmProvider",
- "UpdateAgentRequestSttOverride",
-]
diff --git a/src/speechify/agent/types/create_agent_request_background_noise_preset.py b/src/speechify/agent/types/create_agent_request_background_noise_preset.py
deleted file mode 100644
index 8e7a47a..0000000
--- a/src/speechify/agent/types/create_agent_request_background_noise_preset.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CreateAgentRequestBackgroundNoisePreset = typing.Union[
- typing.Literal["office", "city", "forest", "crowded_room", "keyboard_typing", "hold_music", ""], typing.Any
-]
diff --git a/src/speechify/agent/types/create_agent_request_llm_provider.py b/src/speechify/agent/types/create_agent_request_llm_provider.py
deleted file mode 100644
index 624c513..0000000
--- a/src/speechify/agent/types/create_agent_request_llm_provider.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CreateAgentRequestLlmProvider = typing.Union[typing.Literal["openai", "speechify", "custom", ""], typing.Any]
diff --git a/src/speechify/agent/types/create_agent_request_stt_override.py b/src/speechify/agent/types/create_agent_request_stt_override.py
deleted file mode 100644
index 4bc36f4..0000000
--- a/src/speechify/agent/types/create_agent_request_stt_override.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CreateAgentRequestSttOverride = typing.Union[typing.Literal["flux", "whisper-v3", "gpt-realtime-whisper"], typing.Any]
diff --git a/src/speechify/agent/types/create_agent_test_request_config.py b/src/speechify/agent/types/create_agent_test_request_config.py
deleted file mode 100644
index f312b1f..0000000
--- a/src/speechify/agent/types/create_agent_test_request_config.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from ...types.reply_config import ReplyConfig
-from ...types.tool_call_config import ToolCallConfig
-from ...types.simulation_config import SimulationConfig
-
-CreateAgentTestRequestConfig = typing.Union[ReplyConfig, ToolCallConfig, SimulationConfig]
diff --git a/src/speechify/agent/types/update_agent_request_background_noise_preset.py b/src/speechify/agent/types/update_agent_request_background_noise_preset.py
deleted file mode 100644
index f14e59d..0000000
--- a/src/speechify/agent/types/update_agent_request_background_noise_preset.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-UpdateAgentRequestBackgroundNoisePreset = typing.Union[
- typing.Literal["office", "city", "forest", "crowded_room", "keyboard_typing", "hold_music", ""], typing.Any
-]
diff --git a/src/speechify/agent/types/update_agent_request_llm_provider.py b/src/speechify/agent/types/update_agent_request_llm_provider.py
deleted file mode 100644
index 13249e4..0000000
--- a/src/speechify/agent/types/update_agent_request_llm_provider.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-UpdateAgentRequestLlmProvider = typing.Union[typing.Literal["openai", "speechify", "custom", ""], typing.Any]
diff --git a/src/speechify/agent/types/update_agent_request_stt_override.py b/src/speechify/agent/types/update_agent_request_stt_override.py
deleted file mode 100644
index d205b37..0000000
--- a/src/speechify/agent/types/update_agent_request_stt_override.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-UpdateAgentRequestSttOverride = typing.Union[
- typing.Literal["flux", "whisper-v3", "gpt-realtime-whisper", ""], typing.Any
-]
diff --git a/src/speechify/client.py b/src/speechify/client.py
index 2c146c4..e356bae 100644
--- a/src/speechify/client.py
+++ b/src/speechify/client.py
@@ -4,11 +4,10 @@
from .environment import SpeechifyEnvironment
import os
import httpx
+from .core.api_error import ApiError
from .core.client_wrapper import SyncClientWrapper
-from .agent.client import AgentClient
from .tts.client import TtsClient
from .core.client_wrapper import AsyncClientWrapper
-from .agent.client import AsyncAgentClient
from .tts.client import AsyncTtsClient
@@ -60,6 +59,10 @@ def __init__(
httpx_client: typing.Optional[httpx.Client] = None,
):
_defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ if token is None:
+ raise ApiError(
+ body="The client must be instantiated be either passing in token or setting SPEECHIFY_API_KEY"
+ )
self._client_wrapper = SyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
@@ -70,7 +73,6 @@ def __init__(
else httpx.Client(timeout=_defaulted_timeout),
timeout=_defaulted_timeout,
)
- self.agent = AgentClient(client_wrapper=self._client_wrapper)
self.tts = TtsClient(client_wrapper=self._client_wrapper)
@@ -122,6 +124,10 @@ def __init__(
httpx_client: typing.Optional[httpx.AsyncClient] = None,
):
_defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ if token is None:
+ raise ApiError(
+ body="The client must be instantiated be either passing in token or setting SPEECHIFY_API_KEY"
+ )
self._client_wrapper = AsyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
@@ -132,7 +138,6 @@ def __init__(
else httpx.AsyncClient(timeout=_defaulted_timeout),
timeout=_defaulted_timeout,
)
- self.agent = AsyncAgentClient(client_wrapper=self._client_wrapper)
self.tts = AsyncTtsClient(client_wrapper=self._client_wrapper)
diff --git a/src/speechify/core/__init__.py b/src/speechify/core/__init__.py
index 42031ad..f03aecb 100644
--- a/src/speechify/core/__init__.py
+++ b/src/speechify/core/__init__.py
@@ -6,7 +6,6 @@
from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
from .http_client import AsyncHttpClient, HttpClient
from .jsonable_encoder import jsonable_encoder
-from .pagination import AsyncPager, SyncPager
from .pydantic_utilities import (
IS_PYDANTIC_V2,
UniversalBaseModel,
@@ -25,7 +24,6 @@
"ApiError",
"AsyncClientWrapper",
"AsyncHttpClient",
- "AsyncPager",
"BaseClientWrapper",
"FieldMetadata",
"File",
@@ -33,7 +31,6 @@
"IS_PYDANTIC_V2",
"RequestOptions",
"SyncClientWrapper",
- "SyncPager",
"UniversalBaseModel",
"UniversalRootModel",
"convert_and_respect_annotation_metadata",
diff --git a/src/speechify/core/pagination.py b/src/speechify/core/pagination.py
deleted file mode 100644
index 74f8ae6..0000000
--- a/src/speechify/core/pagination.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-from typing_extensions import Self
-
-import pydantic
-
-# Generic to represent the underlying type of the results within a page
-T = typing.TypeVar("T")
-
-
-# SDKs implement a Page ABC per-pagination request, the endpoint then returns a pager that wraps this type
-# for example, an endpoint will return SyncPager[UserPage] where UserPage implements the Page ABC. ex:
-#
-# SyncPager(
-# has_next=response.list_metadata.after is not None,
-# items=response.data,
-# # This should be the outer function that returns the SyncPager again
-# get_next=lambda: list(..., cursor: response.cursor) (or list(..., offset: offset + 1))
-# )
-class BasePage(pydantic.BaseModel, typing.Generic[T]):
- has_next: bool
- items: typing.Optional[typing.List[T]]
-
-
-class SyncPage(BasePage[T], typing.Generic[T]):
- get_next: typing.Optional[typing.Callable[[], typing.Optional[Self]]]
-
-
-class AsyncPage(BasePage[T], typing.Generic[T]):
- get_next: typing.Optional[typing.Callable[[], typing.Awaitable[typing.Optional[Self]]]]
-
-
-# ----------------------------
-
-
-class SyncPager(SyncPage[T], typing.Generic[T]):
- # Here we type ignore the iterator to avoid a mypy error
- # caused by the type conflict with Pydanitc's __iter__ method
- # brought in by extending the base model
- def __iter__(self) -> typing.Iterator[T]: # type: ignore
- for page in self.iter_pages():
- if page.items is not None:
- for item in page.items:
- yield item
-
- def iter_pages(self) -> typing.Iterator[SyncPage[T]]:
- page: typing.Union[SyncPager[T], None] = self
- while True:
- if page is not None:
- yield page
- if page.has_next and page.get_next is not None:
- page = page.get_next()
- if page is None or page.items is None or len(page.items) == 0:
- return
- else:
- return
- else:
- return
-
- def next_page(self) -> typing.Optional[SyncPage[T]]:
- return self.get_next() if self.get_next is not None else None
-
-
-class AsyncPager(AsyncPage[T], typing.Generic[T]):
- async def __aiter__(self) -> typing.AsyncIterator[T]: # type: ignore
- async for page in self.iter_pages():
- if page.items is not None:
- for item in page.items:
- yield item
-
- async def iter_pages(self) -> typing.AsyncIterator[AsyncPage[T]]:
- page: typing.Union[AsyncPager[T], None] = self
- while True:
- if page is not None:
- yield page
- if page is not None and page.has_next and page.get_next is not None:
- page = await page.get_next()
- if page is None or page.items is None or len(page.items) == 0:
- return
- else:
- return
- else:
- return
-
- async def next_page(self) -> typing.Optional[AsyncPage[T]]:
- return await self.get_next() if self.get_next is not None else None
diff --git a/src/speechify/errors/__init__.py b/src/speechify/errors/__init__.py
index 683ab53..7b4bd00 100644
--- a/src/speechify/errors/__init__.py
+++ b/src/speechify/errors/__init__.py
@@ -2,8 +2,6 @@
from .bad_gateway_error import BadGatewayError
from .bad_request_error import BadRequestError
-from .conflict_error import ConflictError
-from .content_too_large_error import ContentTooLargeError
from .forbidden_error import ForbiddenError
from .internal_server_error import InternalServerError
from .not_found_error import NotFoundError
@@ -16,8 +14,6 @@
__all__ = [
"BadGatewayError",
"BadRequestError",
- "ConflictError",
- "ContentTooLargeError",
"ForbiddenError",
"InternalServerError",
"NotFoundError",
diff --git a/src/speechify/errors/conflict_error.py b/src/speechify/errors/conflict_error.py
deleted file mode 100644
index 89fa6aa..0000000
--- a/src/speechify/errors/conflict_error.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.api_error import ApiError
-from ..types.error import Error
-
-
-class ConflictError(ApiError):
- def __init__(self, body: Error):
- super().__init__(status_code=409, body=body)
diff --git a/src/speechify/errors/content_too_large_error.py b/src/speechify/errors/content_too_large_error.py
deleted file mode 100644
index a9b7bc7..0000000
--- a/src/speechify/errors/content_too_large_error.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.api_error import ApiError
-from ..types.error import Error
-
-
-class ContentTooLargeError(ApiError):
- def __init__(self, body: Error):
- super().__init__(status_code=413, body=body)
diff --git a/src/speechify/types/__init__.py b/src/speechify/types/__init__.py
index d53926d..4736402 100644
--- a/src/speechify/types/__init__.py
+++ b/src/speechify/types/__init__.py
@@ -1,112 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
-from .access_token import AccessToken
-from .access_token_scope import AccessTokenScope
-from .access_token_token_type import AccessTokenTokenType
-from .agent import Agent
-from .agent_background_noise_preset import AgentBackgroundNoisePreset
-from .agent_builtin import AgentBuiltin
-from .agent_llm_provider import AgentLlmProvider
-from .agent_snapshot import AgentSnapshot
-from .agent_snapshot_background_noise_preset import AgentSnapshotBackgroundNoisePreset
-from .agent_stt_override import AgentSttOverride
-from .agent_test import AgentTest
-from .agent_test_attachment import AgentTestAttachment
-from .agent_test_config import AgentTestConfig
-from .agent_test_folder import AgentTestFolder
-from .agent_test_run import AgentTestRun
-from .agent_test_suite_run import AgentTestSuiteRun
-from .agent_test_suite_run_with_runs import AgentTestSuiteRunWithRuns
-from .agent_test_with_last_run import AgentTestWithLastRun
-from .agent_voice import AgentVoice
-from .agent_voice_gender import AgentVoiceGender
-from .agent_voice_language import AgentVoiceLanguage
-from .agent_voice_model import AgentVoiceModel
-from .agent_voice_model_name import AgentVoiceModelName
-from .agent_voice_type import AgentVoiceType
-from .amd_config import AmdConfig
-from .amd_config_on_ivr import AmdConfigOnIvr
-from .amd_config_on_ivr_action import AmdConfigOnIvrAction
-from .amd_config_on_unavailable import AmdConfigOnUnavailable
-from .amd_config_on_unavailable_action import AmdConfigOnUnavailableAction
-from .amd_config_on_voicemail import AmdConfigOnVoicemail
-from .amd_config_on_voicemail_action import AmdConfigOnVoicemailAction
-from .amd_config_tuning import AmdConfigTuning
-from .api_key import ApiKey
-from .attached_knowledge_bases_response import AttachedKnowledgeBasesResponse
-from .attached_tools_response import AttachedToolsResponse
-from .audio_asset import AudioAsset
-from .available_phone_number import AvailablePhoneNumber
-from .basic_auth_config import BasicAuthConfig
-from .batch_call import BatchCall
-from .batch_call_status import BatchCallStatus
-from .batch_recipient import BatchRecipient
-from .batch_recipient_request import BatchRecipientRequest
-from .batch_recipient_status import BatchRecipientStatus
-from .batch_run_entry import BatchRunEntry
-from .bearer_auth_config import BearerAuthConfig
-from .billing_entitlements import BillingEntitlements
-from .caller import Caller
-from .caller_memory_item import CallerMemoryItem
-from .client_tool_config import ClientToolConfig
-from .conversation import Conversation
-from .conversation_end_reason import ConversationEndReason
-from .conversation_ivr_surrender_reason import ConversationIvrSurrenderReason
-from .conversation_stats import ConversationStats
-from .conversation_status import ConversationStatus
-from .conversation_transport import ConversationTransport
-from .create_access_token_request import CreateAccessTokenRequest
-from .create_access_token_request_grant_type import CreateAccessTokenRequestGrantType
-from .create_access_token_request_scope import CreateAccessTokenRequestScope
-from .create_api_key_request import CreateApiKeyRequest
-from .create_batch_call_response import CreateBatchCallResponse
-from .create_conversation_response import CreateConversationResponse
-from .create_credential_request import CreateCredentialRequest
-from .create_flow_template_request import CreateFlowTemplateRequest
-from .create_invite_request import CreateInviteRequest
-from .create_outbound_call_response import CreateOutboundCallResponse
from .create_voice_language import CreateVoiceLanguage
from .create_voice_model import CreateVoiceModel
from .create_voice_model_name import CreateVoiceModelName
-from .create_workspace_request import CreateWorkspaceRequest
from .created_voice import CreatedVoice
from .created_voice_gender import CreatedVoiceGender
from .created_voice_type import CreatedVoiceType
-from .credential import Credential
-from .credential_config import CredentialConfig
-from .credential_kind import CredentialKind
-from .criterion_status import CriterionStatus
-from .custom_headers_config import CustomHeadersConfig
-from .data_assertion import DataAssertion
-from .data_assertion_mode import DataAssertionMode
-from .data_assertion_result import DataAssertionResult
-from .data_assertion_result_mode import DataAssertionResultMode
-from .data_collection_field import DataCollectionField
-from .data_collection_field_type import DataCollectionFieldType
-from .delete_caller_response import DeleteCallerResponse
-from .delete_memories_by_caller_response import DeleteMemoriesByCallerResponse
-from .dependent_agent import DependentAgent
-from .dynamic_variable import DynamicVariable
-from .dynamic_variable_type import DynamicVariableType
-from .entitlements_response import EntitlementsResponse
from .error import Error
from .error_code import ErrorCode
from .error_detail import ErrorDetail
-from .evaluation import Evaluation
-from .evaluation_config import EvaluationConfig
-from .evaluation_criterion import EvaluationCriterion
-from .evaluation_kind import EvaluationKind
-from .evaluation_status import EvaluationStatus
-from .flow_graph import FlowGraph
-from .flow_graph_input import FlowGraphInput
-from .flow_template import FlowTemplate
-from .flow_validation_error import FlowValidationError
-from .flow_validation_issue import FlowValidationIssue
-from .flow_version import FlowVersion
-from .get_batch_call_response import GetBatchCallResponse
-from .get_caller_response import GetCallerResponse
-from .get_flow_response import GetFlowResponse
-from .get_flow_version_response import GetFlowVersionResponse
from .get_speech_options_request import GetSpeechOptionsRequest
from .get_speech_response import GetSpeechResponse
from .get_speech_response_audio_format import GetSpeechResponseAudioFormat
@@ -117,272 +19,19 @@
from .get_voice_type import GetVoiceType
from .get_voices_model import GetVoicesModel
from .get_voices_model_name import GetVoicesModelName
-from .import_job import ImportJob
-from .import_job_kind import ImportJobKind
-from .import_job_response import ImportJobResponse
-from .import_job_status import ImportJobStatus
-from .invite import Invite
-from .invite_preview import InvitePreview
-from .invites_list_response import InvitesListResponse
-from .ivr_menu import IvrMenu
-from .ivr_menu_list_entry import IvrMenuListEntry
-from .knowledge_base import KnowledgeBase
-from .knowledge_base_chunk import KnowledgeBaseChunk
-from .knowledge_base_document import KnowledgeBaseDocument
-from .knowledge_base_document_detail import KnowledgeBaseDocumentDetail
-from .knowledge_base_document_source_kind import KnowledgeBaseDocumentSourceKind
-from .knowledge_base_document_status import KnowledgeBaseDocumentStatus
-from .knowledge_base_folder import KnowledgeBaseFolder
-from .knowledge_base_search_hit import KnowledgeBaseSearchHit
-from .list_agent_builtins_response import ListAgentBuiltinsResponse
-from .list_agent_test_attachments_response import ListAgentTestAttachmentsResponse
-from .list_agent_test_folders_response import ListAgentTestFoldersResponse
-from .list_agent_test_runs_response import ListAgentTestRunsResponse
-from .list_agent_tests_response import ListAgentTestsResponse
-from .list_agents_response import ListAgentsResponse
-from .list_audio_assets_response import ListAudioAssetsResponse
-from .list_batch_calls_response import ListBatchCallsResponse
-from .list_caller_conversations_response import ListCallerConversationsResponse
-from .list_caller_memories_response import ListCallerMemoriesResponse
-from .list_callers_response import ListCallersResponse
-from .list_conversations_response import ListConversationsResponse
-from .list_credentials_response import ListCredentialsResponse
-from .list_dynamic_variables_response import ListDynamicVariablesResponse
-from .list_evaluations_response import ListEvaluationsResponse
-from .list_flow_templates_response import ListFlowTemplatesResponse
-from .list_flow_versions_response import ListFlowVersionsResponse
-from .list_import_jobs_response import ListImportJobsResponse
-from .list_ivr_menus_response import ListIvrMenusResponse
-from .list_knowledge_base_chunks_response import ListKnowledgeBaseChunksResponse
-from .list_knowledge_base_documents_response import ListKnowledgeBaseDocumentsResponse
-from .list_knowledge_base_folders_response import ListKnowledgeBaseFoldersResponse
-from .list_knowledge_bases_response import ListKnowledgeBasesResponse
-from .list_memories_response import ListMemoriesResponse
-from .list_messages_response import ListMessagesResponse
-from .list_phone_numbers_response import ListPhoneNumbersResponse
-from .list_recent_callees_response import ListRecentCalleesResponse
-from .list_refresh_history_response import ListRefreshHistoryResponse
-from .list_retrieval_logs_response import ListRetrievalLogsResponse
-from .list_sip_trunks_response import ListSipTrunksResponse
-from .list_suite_runs_response import ListSuiteRunsResponse
-from .list_system_builtins_response import ListSystemBuiltinsResponse
-from .list_tests_response import ListTestsResponse
-from .list_tool_attached_agents_response import ListToolAttachedAgentsResponse
-from .list_tools_response import ListToolsResponse
-from .list_webhook_deliveries_response import ListWebhookDeliveriesResponse
-from .llm_provider import LlmProvider
-from .mcp_auth import McpAuth, McpAuth_Bearer, McpAuth_None, McpAuth_Oauth2ClientCredentials
-from .mcp_auth_bearer import McpAuthBearer
-from .mcp_auth_none import McpAuthNone
-from .mcp_auth_o_auth2 import McpAuthOAuth2
-from .mcp_auth_type import McpAuthType
-from .mcp_probe_error_details import McpProbeErrorDetails
-from .mcp_probe_error_details_stage import McpProbeErrorDetailsStage
-from .mcp_probe_result import McpProbeResult
-from .mcp_probe_tool import McpProbeTool
-from .mcp_tool_config import McpToolConfig
-from .mcp_transport import McpTransport
-from .member import Member
-from .member_role import MemberRole
-from .members_list_response import MembersListResponse
-from .memory import Memory
-from .message import Message
-from .message_role import MessageRole
-from .mocking_strategy import MockingStrategy
from .nested_chunk import NestedChunk
-from .no_match_behavior import NoMatchBehavior
-from .o_auth2client_credentials_config import OAuth2ClientCredentialsConfig
-from .o_auth2jwt_config import OAuth2JwtConfig
-from .o_auth_error import OAuthError
-from .o_auth_error_error import OAuthErrorError
-from .pagination_meta import PaginationMeta
-from .parameter_check import ParameterCheck
-from .parameter_check_mode import ParameterCheckMode
-from .parameter_check_result import ParameterCheckResult
-from .phone_number import PhoneNumber
-from .phone_number_capability import PhoneNumberCapability
-from .phone_number_source import PhoneNumberSource
-from .recent_callee import RecentCallee
-from .refresh_config import RefreshConfig
-from .refresh_history_entry import RefreshHistoryEntry
-from .refresh_history_entry_status import RefreshHistoryEntryStatus
-from .reply_config import ReplyConfig
-from .reply_result import ReplyResult
-from .retrieval_log_entry import RetrievalLogEntry
-from .retrieval_log_result import RetrievalLogResult
-from .run_agent_tests_response import RunAgentTestsResponse
-from .run_batch_response import RunBatchResponse
-from .search_available_phone_numbers_response import SearchAvailablePhoneNumbersResponse
-from .search_knowledge_bases_response import SearchKnowledgeBasesResponse
-from .shadow_conversation_response import ShadowConversationResponse
-from .simulation_config import SimulationConfig
-from .simulation_criterion_result import SimulationCriterionResult
-from .simulation_criterion_result_status import SimulationCriterionResultStatus
-from .simulation_message import SimulationMessage
-from .simulation_message_role import SimulationMessageRole
-from .simulation_result import SimulationResult
-from .simulation_result_sentiment import SimulationResultSentiment
-from .simulation_tool_call import SimulationToolCall
-from .sip_media_encryption import SipMediaEncryption
-from .sip_transport import SipTransport
-from .sip_trunk import SipTrunk
-from .sip_trunk_direction import SipTrunkDirection
-from .sip_trunk_kind import SipTrunkKind
from .speech_marks import SpeechMarks
-from .suite_child_run import SuiteChildRun
-from .suite_run_trigger import SuiteRunTrigger
-from .system_builtin import SystemBuiltin
-from .system_builtin_info import SystemBuiltinInfo
-from .system_tool_config import SystemToolConfig
-from .system_variable_doc import SystemVariableDoc
-from .tenant import Tenant
-from .tenants_list_response import TenantsListResponse
-from .test_run_config_override import TestRunConfigOverride
-from .test_run_result import TestRunResult
-from .test_run_status import TestRunStatus
-from .test_stats import TestStats
-from .test_stats_bucket import TestStatsBucket
-from .test_type import TestType
-from .tool import Tool
-from .tool_attached_agent import ToolAttachedAgent
-from .tool_call_config import ToolCallConfig
-from .tool_call_result import ToolCallResult
-from .tool_config import ToolConfig
-from .tool_kind import ToolKind
-from .tool_mock import ToolMock
-from .tool_mock_config import ToolMockConfig
-from .tool_param import ToolParam
-from .tool_param_type import ToolParamType
-from .transfer_ownership_request import TransferOwnershipRequest
-from .twilio_import_spec import TwilioImportSpec
-from .update_billing_contact_email_request import UpdateBillingContactEmailRequest
-from .update_billing_contact_name_request import UpdateBillingContactNameRequest
-from .update_member_role_request import UpdateMemberRoleRequest
-from .update_sip_trunk_request import UpdateSipTrunkRequest
-from .update_workspace_request import UpdateWorkspaceRequest
-from .upload_audio_asset_response import UploadAudioAssetResponse
-from .webhook_delivery import WebhookDelivery
-from .webhook_delivery_status import WebhookDeliveryStatus
-from .webhook_probe_result import WebhookProbeResult
-from .webhook_tool_config import WebhookToolConfig
-from .webhook_tool_config_method import WebhookToolConfigMethod
-from .widget_config import WidgetConfig
-from .widget_config_avatar import WidgetConfigAvatar
-from .widget_config_avatar_type import WidgetConfigAvatarType
-from .widget_config_style import WidgetConfigStyle
-from .widget_config_terms import WidgetConfigTerms
-from .widget_config_text import WidgetConfigText
-from .widget_config_theme import WidgetConfigTheme
-from .widget_config_transcript import WidgetConfigTranscript
__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",
- "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",
@@ -393,164 +42,6 @@
"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",
]
diff --git a/src/speechify/types/access_token.py b/src/speechify/types/access_token.py
deleted file mode 100644
index 6eea82a..0000000
--- a/src/speechify/types/access_token.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from .access_token_scope import AccessTokenScope
-from .access_token_token_type import AccessTokenTokenType
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AccessToken(UniversalBaseModel):
- access_token: typing.Optional[str] = None
- expires_in: typing.Optional[int] = pydantic.Field(default=None)
- """
- Expiration time, in seconds from the issue time
- """
-
- scope: typing.Optional[AccessTokenScope] = pydantic.Field(default=None)
- """
- The scope, or a space-delimited list of scopes the token is issued for
- """
-
- token_type: typing.Optional[AccessTokenTokenType] = pydantic.Field(default=None)
- """
- Token type
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/access_token_scope.py b/src/speechify/types/access_token_scope.py
deleted file mode 100644
index 73cae3b..0000000
--- a/src/speechify/types/access_token_scope.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AccessTokenScope = typing.Union[
- typing.Literal[
- "audio:speech", "audio:stream", "audio:all", "voices:read", "voices:create", "voices:delete", "voices:all"
- ],
- typing.Any,
-]
diff --git a/src/speechify/types/access_token_token_type.py b/src/speechify/types/access_token_token_type.py
deleted file mode 100644
index 065f512..0000000
--- a/src/speechify/types/access_token_token_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AccessTokenTokenType = typing.Union[typing.Literal["bearer"], typing.Any]
diff --git a/src/speechify/types/agent.py b/src/speechify/types/agent.py
deleted file mode 100644
index 60722d1..0000000
--- a/src/speechify/types/agent.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .agent_llm_provider import AgentLlmProvider
-from .widget_config import WidgetConfig
-from .amd_config import AmdConfig
-from .agent_background_noise_preset import AgentBackgroundNoisePreset
-from .agent_stt_override import AgentSttOverride
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Agent(UniversalBaseModel):
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`).
- This is the sole customer-facing
- identifier. URL paths accept only this prefixed form; legacy
- UUID path parameters are rejected with 404.
- """
-
- name: str
- slug: str
- prompt: str
- first_message: str = pydantic.Field()
- """
- Spoken verbatim at session start when present in the customer's flow graph.
- """
-
- language: str = pydantic.Field()
- """
- ISO 639-1 code, e.g. 'en'.
- """
-
- llm_provider: typing.Optional[AgentLlmProvider] = pydantic.Field(default=None)
- """
- LLM backend the worker constructs for this agent. Null
- means "use the platform default" (resolved server-side at
- dispatch; today: Speechify Kimi K2.6). `openai` and
- `speechify` pair with a model from the allowed (provider,
- model) table. `custom` points the worker at any OpenAI /
- vLLM-compatible endpoint - see `llm_base_url`,
- `llm_api_key`, `llm_extra_body`.
- """
-
- llm_model: typing.Optional[str] = pydantic.Field(default=None)
- """
- Chat model slug. Null means "use the platform default"
- (resolved server-side at dispatch; today: Speechify Kimi
- K2.6). For `openai` / `speechify` it must be a slug from
- the allowed table; for `custom` it is free-form (the
- customer's endpoint owns the namespace).
- """
-
- llm_base_url: typing.Optional[str] = pydantic.Field(default=None)
- """
- Custom OpenAI/vLLM-compatible endpoint base URL. Non-null
- only when `llm_provider` is `custom`.
- """
-
- llm_api_key_set: typing.Optional[bool] = pydantic.Field(default=None)
- """
- Whether a bearer key is stored for the custom endpoint.
- The key itself is write-only and never returned.
- """
-
- llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- JSON object forwarded verbatim to the custom endpoint as
- the chat.completions `extra_body` (reasoning / sampling
- knobs). Non-null only when `llm_provider` is `custom`.
- """
-
- voice_id: str = pydantic.Field()
- """
- Speechify voice slug.
- """
-
- temperature: float
- widget_config: typing.Optional[WidgetConfig] = None
- is_public: bool = pydantic.Field()
- """
- When true, the `` web component can start a
- session against this agent without an API key, subject to
- the `allowed_origins` allowlist. When false (default), only
- authenticated callers can start sessions.
- """
-
- allowed_origins: typing.List[str] = pydantic.Field()
- """
- Exact `Origin` header values (e.g. `https://example.com`)
- that are allowed to start public sessions. Empty array
- with `is_public = true` means any origin is accepted —
- intended for open demos. No subdomain wildcards.
- """
-
- hostname_allowlist: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- Optional per-agent hostname allowlist enforced at
- session-creation time. When set and non-empty, the
- `Origin` header's hostname must be an exact member.
- Bare hostnames only — no scheme, port, or path. Up to
- 10 entries. Omit (null) or leave empty for no
- enforcement (public agents accept any hostname).
- """
-
- memory_enabled: bool = pydantic.Field()
- """
- When true, the post-call extractor writes durable facts about
- each caller; at conversation-start the retriever injects the
- top matches into the system prompt via the `{{memory}}`
- template variable. Defaults to false.
- """
-
- memory_retention_days: int = pydantic.Field()
- """
- Maximum age (in days) of memories kept and surfaced to the
- retriever. 0 disables the cap. Defaults to 90.
- """
-
- webhook_url: typing.Optional[str] = pydantic.Field(default=None)
- """
- Customer-facing post-call webhook target. When non-empty,
- the control plane POSTs a signed payload (transcript +
- evals + extractors + recording URL) once the conversation
- completes. Empty disables the fire path.
- """
-
- webhook_secret_set: typing.Optional[bool] = pydantic.Field(default=None)
- """
- True when an HMAC-SHA256 webhook secret is configured. The
- secret itself is write-only — supplied on PATCH and never
- echoed back on reads.
- """
-
- amd: AmdConfig
- save_audio_recording: bool = pydantic.Field()
- """
- When true, every conversation produces a room-composite
- OGG egress uploaded to the recordings bucket. Defaults
- FALSE for new agents (privacy by default).
- """
-
- navigator_mode: bool = pydantic.Field()
- """
- Tunes worker turn handling for autonomous outbound IVR
- navigation - longer endpointing and no barge-in. The goal
- itself lives in the agent's prompt; this flag is the
- behaviour switch only. Defaults FALSE.
- """
-
- ivr_memory_enabled: bool = pydantic.Field()
- """
- Per-agent kill switch for the IVR-memory cache lookup
- performed at AMD time. Defaults TRUE so existing navigator
- agents keep their always-on behaviour. Set to false to skip
- the cache and force every outbound dial on this agent to
- start cold (LLM-driven navigation only).
- """
-
- tts_speaking_rate: typing.Optional[float] = pydantic.Field(default=None)
- """
- Per-agent override for the voice's default speaking rate
- (0.5 = half speed, 2.0 = double, 1.0 = neutral). Null
- means "use the voice's default rate".
- """
-
- tts_playback_rate: typing.Optional[float] = pydantic.Field(default=None)
- """
- Per-agent post-process pitch-preserving time-stretch applied
- to the synthesized audio in the worker before publishing.
- Distinct from tts_speaking_rate: speaking_rate biases the
- model's generation prosody (clipped syllables, pauses
- preserved); playback_rate uniformly stretches the rendered
- waveform (every sample, every pause, every breath). Range
- 0.5..3.0; null means no post-process.
- """
-
- response_delay_seconds: typing.Optional[float] = pydantic.Field(default=None)
- """
- How long the agent waits after the caller stops talking
- before generating a reply (the worker's endpointing
- min_delay on the VAD path). Range 0.0..5.0. Null means
- "use the stack default" — Deepgram VAD: 0.5s, or 0.75s
- when `navigator_mode=true`. Ignored on Flux + Whisper
- STT, which use semantic turn detection instead.
- """
-
- inactivity_timeout_seconds: typing.Optional[int] = pydantic.Field(default=None)
- """
- Optional override for the per-agent silence-tolerance
- before the worker tears the call down. Null means use
- the platform default.
- """
-
- background_noise_preset: typing.Optional[AgentBackgroundNoisePreset] = pydantic.Field(default=None)
- """
- Optional pre-mixed ambient bed. Null disables background
- noise.
- """
-
- background_noise_volume: typing.Optional[float] = pydantic.Field(default=None)
- """
- Volume of the background-noise bed. Null disables.
- """
-
- stt_override: typing.Optional[AgentSttOverride] = pydantic.Field(default=None)
- """
- Optional override for the streaming-STT stack this agent
- dispatches with. Null means use the worker's default
- stack (today: whisper-v3, Baseten Whisper Large V3). Pick
- `whisper-v3` to pin Whisper Large V3 explicitly, `flux` to
- opt into Deepgram Flux's semantic end-of-turn detection, or
- `gpt-realtime-whisper` for OpenAI's streaming Whisper-class
- STT.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_background_noise_preset.py b/src/speechify/types/agent_background_noise_preset.py
deleted file mode 100644
index 959191f..0000000
--- a/src/speechify/types/agent_background_noise_preset.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentBackgroundNoisePreset = typing.Union[
- typing.Literal["office", "city", "forest", "crowded_room", "keyboard_typing", "hold_music"], typing.Any
-]
diff --git a/src/speechify/types/agent_builtin.py b/src/speechify/types/agent_builtin.py
deleted file mode 100644
index 86a3337..0000000
--- a/src/speechify/types/agent_builtin.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .system_builtin import SystemBuiltin
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentBuiltin(UniversalBaseModel):
- """
- One instance of a system builtin bound to a specific agent.
- Storage lives in the `agent_builtins` table (migration 00061);
- wire format intentionally matches the legacy `kind="system"`
- Tool shape so the worker is untouched by the split.
- """
-
- id: str = pydantic.Field()
- """
- Opaque builtin instance ID.
- """
-
- tenant_id: str = pydantic.Field()
- """
- The workspace owning this instance.
- """
-
- agent_id: str = pydantic.Field()
- """
- The agent this instance is bound to.
- """
-
- builtin: SystemBuiltin
- name: str = pydantic.Field()
- """
- LLM-facing tool name. Unique within the agent's builtin set.
- """
-
- description: str = pydantic.Field()
- """
- LLM-facing one-line description of when to call the tool.
- """
-
- config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Per-instance configuration shape. The schema depends on
- `builtin` — see the per-builtin contracts under
- `/contracts/tools/system_*.schema.json`. Null when the
- builtin takes no instance-level config.
- """
-
- params: typing.Optional[typing.List[typing.Dict[str, typing.Optional[typing.Any]]]] = pydantic.Field(default=None)
- """
- Per-call parameter schema fragment merged into the model's
- tool spec. Each entry is one parameter descriptor (the
- per-builtin contract pins the exact shape). Null when the
- builtin takes no caller arguments.
- """
-
- enabled: bool = pydantic.Field()
- """
- When false, the instance is persisted but skipped at dispatch.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_llm_provider.py b/src/speechify/types/agent_llm_provider.py
deleted file mode 100644
index 6921608..0000000
--- a/src/speechify/types/agent_llm_provider.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentLlmProvider = typing.Union[typing.Literal["openai", "speechify", "custom"], typing.Any]
diff --git a/src/speechify/types/agent_snapshot.py b/src/speechify/types/agent_snapshot.py
deleted file mode 100644
index 7b6af65..0000000
--- a/src/speechify/types/agent_snapshot.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import datetime as dt
-import pydantic
-from .amd_config import AmdConfig
-from .agent_snapshot_background_noise_preset import AgentSnapshotBackgroundNoisePreset
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentSnapshot(UniversalBaseModel):
- """
- Frozen copy of the agent's behavioral configuration captured at
- conversation-create time so the detail view can
- render historical calls accurately even after the live agent
- has been edited. Carries its own `schema_version` because the
- snapshot shape evolves independently of the live Agent shape.
-
- Field-presence contract: new snapshots emit every field
- (explicit null when unset). A key that is ABSENT from a stored
- snapshot means the snapshot pre-dates that field's capture;
- readers hide the value instead of guessing a default.
- """
-
- schema_version: typing.Optional[int] = None
- captured_at: typing.Optional[dt.datetime] = None
- name: typing.Optional[str] = None
- prompt: typing.Optional[str] = None
- first_message: typing.Optional[str] = None
- language: typing.Optional[str] = None
- llm_provider: typing.Optional[str] = pydantic.Field(default=None)
- """
- Resolved provider that actually ran (a "Platform default"
- agent freezes the concrete platform pair at call time).
- """
-
- llm_model: typing.Optional[str] = None
- llm_base_url: typing.Optional[str] = pydantic.Field(default=None)
- """
- Custom-provider endpoint base URL; null for managed providers. The bearer key is never captured.
- """
-
- llm_extra_body: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Extra chat.completions body forwarded verbatim for custom-provider agents; null otherwise.
- """
-
- voice_id: typing.Optional[str] = None
- temperature: typing.Optional[float] = None
- memory_enabled: typing.Optional[bool] = None
- memory_retention_days: typing.Optional[int] = None
- tts_speaking_rate: typing.Optional[float] = pydantic.Field(default=None)
- """
- Per-agent speaking-rate override at call time; null = the resolved voice's default rate.
- """
-
- tts_playback_rate: typing.Optional[float] = pydantic.Field(default=None)
- """
- Post-process time-stretch at call time; null = no time-stretch (1x).
- """
-
- response_delay_seconds: typing.Optional[float] = pydantic.Field(default=None)
- """
- Silence-wait override at call time; null = stack default endpointing.
- """
-
- stt_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Streaming-STT stack the call dispatched with; null = the worker's platform default.
- """
-
- amd: typing.Optional[AmdConfig] = None
- save_audio_recording: typing.Optional[bool] = None
- navigator_mode: typing.Optional[bool] = None
- ivr_memory_enabled: typing.Optional[bool] = None
- inactivity_timeout_seconds: typing.Optional[int] = pydantic.Field(default=None)
- """
- Silence-tolerance override at call time; null = platform default.
- """
-
- background_noise_preset: typing.Optional[AgentSnapshotBackgroundNoisePreset] = pydantic.Field(default=None)
- """
- Ambient-bed preset at call time; null = no background noise.
- """
-
- background_noise_volume: typing.Optional[float] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_snapshot_background_noise_preset.py b/src/speechify/types/agent_snapshot_background_noise_preset.py
deleted file mode 100644
index b96fdbb..0000000
--- a/src/speechify/types/agent_snapshot_background_noise_preset.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentSnapshotBackgroundNoisePreset = typing.Union[
- typing.Literal["office", "city", "forest", "crowded_room", "keyboard_typing", "hold_music"], typing.Any
-]
diff --git a/src/speechify/types/agent_stt_override.py b/src/speechify/types/agent_stt_override.py
deleted file mode 100644
index 917cdee..0000000
--- a/src/speechify/types/agent_stt_override.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentSttOverride = typing.Union[typing.Literal["flux", "whisper-v3", "gpt-realtime-whisper"], typing.Any]
diff --git a/src/speechify/types/agent_test.py b/src/speechify/types/agent_test.py
deleted file mode 100644
index 0724a19..0000000
--- a/src/speechify/types/agent_test.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .test_type import TestType
-from .agent_test_config import AgentTestConfig
-import typing
-from .tool_mock_config import ToolMockConfig
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentTest(UniversalBaseModel):
- """
- A configured test against a voice agent. `config` is a
- type-specific document - see `ReplyConfig`, `ToolCallConfig`,
- and `SimulationConfig` for the per-type shapes (discriminated by `type`).
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`test_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the owning agent.
- """
-
- name: str
- description: str
- type: TestType
- config: AgentTestConfig = pydantic.Field()
- """
- Type-specific configuration document.
- """
-
- tool_mock_config: typing.Optional[ToolMockConfig] = pydantic.Field(default=None)
- """
- Optional tool-mocking config applied during runs of this test.
- """
-
- variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Per-test dynamic-variable overrides. Keys substitute `{{key}}`
- placeholders inside the test config at run-start. Unknown keys
- render as empty string, matching session dispatch behaviour.
- """
-
- folder_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- When set, prefixed wire identifier
- (`folder_<26 char Crockford base32>`) of the containing folder.
- Null means root (unfiled).
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_attachment.py b/src/speechify/types/agent_test_attachment.py
deleted file mode 100644
index 536ce98..0000000
--- a/src/speechify/types/agent_test_attachment.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class AgentTestAttachment(UniversalBaseModel):
- """
- One (test, agent) pair. Poll the `attached_agent_ids` field on `AgentTestWithLastRun` or hit `/v1/agents/tests/{id}/attachments` for the authoritative set.
- """
-
- test_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`test_<26 char Crockford base32>`)
- of the attached test.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the attached agent.
- """
-
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_config.py b/src/speechify/types/agent_test_config.py
deleted file mode 100644
index 01bca82..0000000
--- a/src/speechify/types/agent_test_config.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from .reply_config import ReplyConfig
-from .tool_call_config import ToolCallConfig
-from .simulation_config import SimulationConfig
-
-AgentTestConfig = typing.Union[ReplyConfig, ToolCallConfig, SimulationConfig]
diff --git a/src/speechify/types/agent_test_folder.py b/src/speechify/types/agent_test_folder.py
deleted file mode 100644
index 26fae29..0000000
--- a/src/speechify/types/agent_test_folder.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentTestFolder(UniversalBaseModel):
- """
- One organisational node in the per-owner tests tree.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`folder_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- parent_folder_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- When set, prefixed wire identifier
- (`folder_<26 char Crockford base32>`) of the parent folder.
- Null means root.
- """
-
- name: str
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_run.py b/src/speechify/types/agent_test_run.py
deleted file mode 100644
index dc3173c..0000000
--- a/src/speechify/types/agent_test_run.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .test_run_status import TestRunStatus
-import typing
-import datetime as dt
-from .test_run_result import TestRunResult
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentTestRun(UniversalBaseModel):
- """
- One execution of a test. `result` is populated when `status`
- reaches a terminal state (`passed`, `failed`, or `error`).
- See `TestRunResult` for the shape.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`run_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- test_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`test_<26 char Crockford base32>`)
- of the parent test.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the agent this run executed against.
- """
-
- status: TestRunStatus
- started_at: typing.Optional[dt.datetime] = None
- completed_at: typing.Optional[dt.datetime] = None
- result: typing.Optional[TestRunResult] = pydantic.Field(default=None)
- """
- Populated on terminal status only.
- """
-
- error: typing.Optional[str] = pydantic.Field(default=None)
- """
- Human-readable error message when status is `error`.
- """
-
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_suite_run.py b/src/speechify/types/agent_test_suite_run.py
deleted file mode 100644
index c675493..0000000
--- a/src/speechify/types/agent_test_suite_run.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .suite_run_trigger import SuiteRunTrigger
-from .test_run_status import TestRunStatus
-import datetime as dt
-from .test_run_config_override import TestRunConfigOverride
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentTestSuiteRun(UniversalBaseModel):
- """
- A suite run (test invocation): the grouping object over every
- test run dispatched by one Run All, batch, or resubmit call.
- `status` and the count fields are derived from the child runs.
- `status` is `running` while any child run is still queued or
- running, then `passed` (all passed), `failed` (at least one
- failed), or `error` (at least one errored, none failed).
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`srun_<26 char Crockford base32>`).
- """
-
- agent_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Prefixed `agent_` id of the agent whose suite
- was run. Set for the `run_all` trigger; null for `batch`,
- which can span many agents.
- """
-
- agent_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Display name of `agent_id`'s agent, resolved at read time.
- Null whenever `agent_id` is null, and on the suite run
- embedded in run/resubmit creation responses.
- """
-
- trigger: SuiteRunTrigger
- parent_suite_run_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Set on a `resubmit`: the prefixed `srun_` id of
- the suite run whose failed/errored tests this one re-ran.
- Null for `run_all` and `batch`.
- """
-
- status: TestRunStatus
- total_runs: int = pydantic.Field()
- """
- Number of child runs in the suite.
- """
-
- passed_count: int
- failed_count: int
- errored_count: int
- pending_count: int = pydantic.Field()
- """
- Child runs still queued or running.
- """
-
- created_at: dt.datetime
- completed_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- Newest child-run completion; null until every child run is terminal.
- """
-
- config_override: typing.Optional[TestRunConfigOverride] = pydantic.Field(default=None)
- """
- The run-level config override this suite was run
- with, or null for an ordinary Run All / batch.
- """
-
- flow_version_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- The flow version (`agent_versions` row) this suite targeted,
- or null for the agent's active / synthesized flow.
- """
-
- flow_version_number: typing.Optional[int] = pydantic.Field(default=None)
- """
- Human-facing version number of `flow_version_id`; null when no version was targeted.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_suite_run_with_runs.py b/src/speechify/types/agent_test_suite_run_with_runs.py
deleted file mode 100644
index 6f5aa3a..0000000
--- a/src/speechify/types/agent_test_suite_run_with_runs.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .agent_test_suite_run import AgentTestSuiteRun
-import typing
-from .suite_child_run import SuiteChildRun
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class AgentTestSuiteRunWithRuns(AgentTestSuiteRun):
- """
- A suite run plus every child run, for the grouped detail view.
- """
-
- runs: typing.List[SuiteChildRun]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_test_with_last_run.py b/src/speechify/types/agent_test_with_last_run.py
deleted file mode 100644
index e4005ce..0000000
--- a/src/speechify/types/agent_test_with_last_run.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .agent_test import AgentTest
-import typing
-from .agent_test_run import AgentTestRun
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentTestWithLastRun(AgentTest):
- """
- List-view projection of a test that includes the most recent run
- so the console can display pass/fail badges without an extra
- round-trip. On the global `/v1/agents/tests` surface, also carries
- `attached_agent_ids` so the row can render agent chips without a
- follow-up request.
- """
-
- last_run: typing.Optional[AgentTestRun] = pydantic.Field(default=None)
- """
- The most recent run, or null if the test has never been run.
- """
-
- attached_agent_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- Every agent this test runs against. Always includes the owner agent.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_voice.py b/src/speechify/types/agent_voice.py
deleted file mode 100644
index 998d808..0000000
--- a/src/speechify/types/agent_voice.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .agent_voice_type import AgentVoiceType
-import typing
-from .agent_voice_model import AgentVoiceModel
-from .agent_voice_gender import AgentVoiceGender
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentVoice(UniversalBaseModel):
- """
- One row in the curated voice catalogue returned by
- `GET /v1/agents/voices`. Matches the slug set accepted by
- agent create/update.
- """
-
- id: str = pydantic.Field()
- """
- Voice slug. Passed verbatim as `voice_id` on agent writes.
- """
-
- type: AgentVoiceType
- display_name: str
- models: typing.List[AgentVoiceModel]
- gender: AgentVoiceGender
- locale: str = pydantic.Field()
- """
- Default locale for the voice (BCP-47-ish, e.g. `en-US`).
- """
-
- preview_audio: typing.Optional[str] = pydantic.Field(default=None)
- """
- Preferred preview clip URL, locale-matched when possible.
- """
-
- avatar_image: typing.Optional[str] = pydantic.Field(default=None)
- """
- Avatar URL for the picker UI. Null when no avatar is
- configured; the wire is intentionally `null` rather than
- `""` so the picker doesn't render a broken ` `.
- """
-
- tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- VMS-defined tags (e.g. `narrator`, `young`).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_voice_gender.py b/src/speechify/types/agent_voice_gender.py
deleted file mode 100644
index a5169ae..0000000
--- a/src/speechify/types/agent_voice_gender.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentVoiceGender = typing.Union[typing.Literal["male", "female", "notSpecified"], typing.Any]
diff --git a/src/speechify/types/agent_voice_language.py b/src/speechify/types/agent_voice_language.py
deleted file mode 100644
index ae1cda9..0000000
--- a/src/speechify/types/agent_voice_language.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AgentVoiceLanguage(UniversalBaseModel):
- locale: str = pydantic.Field()
- """
- BCP-47-ish locale tag (e.g. `en-US`, `de-DE`).
- """
-
- preview_audio: typing.Optional[str] = pydantic.Field(default=None)
- """
- URL to a short audio preview for this locale, or null if
- no preview is available.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_voice_model.py b/src/speechify/types/agent_voice_model.py
deleted file mode 100644
index 60e2849..0000000
--- a/src/speechify/types/agent_voice_model.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .agent_voice_model_name import AgentVoiceModelName
-import typing
-from .agent_voice_language import AgentVoiceLanguage
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class AgentVoiceModel(UniversalBaseModel):
- """
- One TTS engine the voice can be synthesised through. Each
- agent voice exposes a multilingual model, plus an
- english-specific model for voices whose locale starts with
- `en`.
- """
-
- name: AgentVoiceModelName
- languages: typing.List[AgentVoiceLanguage]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/agent_voice_model_name.py b/src/speechify/types/agent_voice_model_name.py
deleted file mode 100644
index 73d73dc..0000000
--- a/src/speechify/types/agent_voice_model_name.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentVoiceModelName = typing.Union[typing.Literal["simba-english", "simba-multilingual"], typing.Any]
diff --git a/src/speechify/types/agent_voice_type.py b/src/speechify/types/agent_voice_type.py
deleted file mode 100644
index e0b4281..0000000
--- a/src/speechify/types/agent_voice_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AgentVoiceType = typing.Union[typing.Literal["shared"], typing.Any]
diff --git a/src/speechify/types/amd_config.py b/src/speechify/types/amd_config.py
deleted file mode 100644
index cb38c56..0000000
--- a/src/speechify/types/amd_config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .amd_config_on_voicemail import AmdConfigOnVoicemail
-from .amd_config_on_ivr import AmdConfigOnIvr
-from .amd_config_on_unavailable import AmdConfigOnUnavailable
-import typing
-from .amd_config_tuning import AmdConfigTuning
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AmdConfig(UniversalBaseModel):
- """
- Answering Machine Detection routing config for outbound voice
- agents. AMD classifies the called party's first ~3-15 seconds of
- audio into one of LiveKit's categories (human, uncertain,
- machine-vm, machine-ivr, machine-unavailable) and dispatches per
- category to the configured action. Stored on the agent row;
- flowed onto outbound dispatch metadata under the `amd` key.
- """
-
- enabled: bool = pydantic.Field()
- """
- When false, the worker skips AMD entirely. When true, the
- worker runs AMD on the called party's greeting before
- delivering the agent's first message and dispatches per
- result.category. The per-route fields below are still
- required by the schema regardless of `enabled` state so a
- customer flipping `enabled: false → true` ships coherent
- route configuration immediately.
- """
-
- on_voicemail: AmdConfigOnVoicemail = pydantic.Field()
- """
- Action when AMD returns category=machine-vm.
- """
-
- on_ivr: AmdConfigOnIvr = pydantic.Field()
- """
- Action when AMD returns category=machine-ivr.
- """
-
- on_unavailable: AmdConfigOnUnavailable = pydantic.Field()
- """
- Action when AMD returns category=machine-unavailable (mailbox full or disconnected).
- """
-
- tuning: typing.Optional[AmdConfigTuning] = pydantic.Field(default=None)
- """
- Optional overrides for LiveKit's detection thresholds and
- timeouts. Cross-field rule (enforced at the application
- validator): `timeout_seconds` must be greater than or equal
- to `no_speech_threshold_seconds` when both are set.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/amd_config_on_ivr.py b/src/speechify/types/amd_config_on_ivr.py
deleted file mode 100644
index ae8d85c..0000000
--- a/src/speechify/types/amd_config_on_ivr.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .amd_config_on_ivr_action import AmdConfigOnIvrAction
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class AmdConfigOnIvr(UniversalBaseModel):
- """
- Action when AMD returns category=machine-ivr.
- """
-
- action: AmdConfigOnIvrAction = pydantic.Field()
- """
- proceed: hand control to the agent's flow as if the
- called party were human. hangup: terminate immediately.
- navigate: hand control to the IVR Navigator subagent
- with menu-memoization-aware session config (cache hit
- seeds the agent context; cache miss triggers cold
- discovery and the post-call pipeline extracts the
- menu for future calls).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/amd_config_on_ivr_action.py b/src/speechify/types/amd_config_on_ivr_action.py
deleted file mode 100644
index bf117b5..0000000
--- a/src/speechify/types/amd_config_on_ivr_action.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AmdConfigOnIvrAction = typing.Union[typing.Literal["proceed", "hangup", "navigate"], typing.Any]
diff --git a/src/speechify/types/amd_config_on_unavailable.py b/src/speechify/types/amd_config_on_unavailable.py
deleted file mode 100644
index d3d0669..0000000
--- a/src/speechify/types/amd_config_on_unavailable.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .amd_config_on_unavailable_action import AmdConfigOnUnavailableAction
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class AmdConfigOnUnavailable(UniversalBaseModel):
- """
- Action when AMD returns category=machine-unavailable (mailbox full or disconnected).
- """
-
- action: AmdConfigOnUnavailableAction
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/amd_config_on_unavailable_action.py b/src/speechify/types/amd_config_on_unavailable_action.py
deleted file mode 100644
index 40800bf..0000000
--- a/src/speechify/types/amd_config_on_unavailable_action.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AmdConfigOnUnavailableAction = typing.Union[typing.Literal["hangup"], typing.Any]
diff --git a/src/speechify/types/amd_config_on_voicemail.py b/src/speechify/types/amd_config_on_voicemail.py
deleted file mode 100644
index c3f6a79..0000000
--- a/src/speechify/types/amd_config_on_voicemail.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .amd_config_on_voicemail_action import AmdConfigOnVoicemailAction
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AmdConfigOnVoicemail(UniversalBaseModel):
- """
- Action when AMD returns category=machine-vm.
- """
-
- action: AmdConfigOnVoicemailAction
- message: typing.Optional[str] = pydantic.Field(default=None)
- """
- Spoken before terminating when action=leave_message.
- Supports {{variable}} substitution. Required (non-empty)
- when action=leave_message; rejected by the validator
- otherwise.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/amd_config_on_voicemail_action.py b/src/speechify/types/amd_config_on_voicemail_action.py
deleted file mode 100644
index 7d297bc..0000000
--- a/src/speechify/types/amd_config_on_voicemail_action.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-AmdConfigOnVoicemailAction = typing.Union[typing.Literal["hangup", "leave_message"], typing.Any]
diff --git a/src/speechify/types/amd_config_tuning.py b/src/speechify/types/amd_config_tuning.py
deleted file mode 100644
index 33ffe7e..0000000
--- a/src/speechify/types/amd_config_tuning.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class AmdConfigTuning(UniversalBaseModel):
- """
- Optional overrides for LiveKit's detection thresholds and
- timeouts. Cross-field rule (enforced at the application
- validator): `timeout_seconds` must be greater than or equal
- to `no_speech_threshold_seconds` when both are set.
- """
-
- human_speech_threshold_seconds: typing.Optional[float] = None
- no_speech_threshold_seconds: typing.Optional[float] = None
- timeout_seconds: typing.Optional[float] = None
- classification_prompt: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/api_key.py b/src/speechify/types/api_key.py
deleted file mode 100644
index de8bb22..0000000
--- a/src/speechify/types/api_key.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class ApiKey(UniversalBaseModel):
- api_key: str = pydantic.Field()
- """
- Plaintext API key (`sk_<43-char Crockford base32>`) returned
- EXACTLY ONCE on creation. Hashed at rest and never re-emitted
- on list / get responses.
- """
-
- created_at: int = pydantic.Field()
- """
- Creation time of the key
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`key_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404. Distinct from `api_key` (the once-only
- plaintext `sk_<...>` secret returned on create).
- """
-
- name: str = pydantic.Field()
- """
- Name of the key
- """
-
- updated_at: int = pydantic.Field()
- """
- Last updated time of the key
- """
-
- user_id: str = pydantic.Field()
- """
- User ID to whom the key belongs
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/attached_knowledge_bases_response.py b/src/speechify/types/attached_knowledge_bases_response.py
deleted file mode 100644
index ccfbfc2..0000000
--- a/src/speechify/types/attached_knowledge_bases_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .knowledge_base import KnowledgeBase
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class AttachedKnowledgeBasesResponse(UniversalBaseModel):
- """
- Bare list of the knowledge bases attached to an agent. Not
- paginated — an agent's KB attachment count is naturally
- bounded (configuration, not data scale).
- """
-
- knowledge_bases: typing.List[KnowledgeBase]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/attached_tools_response.py b/src/speechify/types/attached_tools_response.py
deleted file mode 100644
index dcc78a3..0000000
--- a/src/speechify/types/attached_tools_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .tool import Tool
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class AttachedToolsResponse(UniversalBaseModel):
- """
- Bare list of the tools attached to an agent. Not paginated —
- an agent's tool attachment count is bounded by configuration,
- not by data scale.
- """
-
- tools: typing.List[Tool]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/audio_asset.py b/src/speechify/types/audio_asset.py
deleted file mode 100644
index 8b1ca29..0000000
--- a/src/speechify/types/audio_asset.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class AudioAsset(UniversalBaseModel):
- """
- Metadata for a pre-recorded WAV clip stored in the workspace's
- audio-asset bucket. Bytes are immutable once uploaded — to
- replace a clip, upload a new asset and update any references.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`audio_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- original_filename: str = pydantic.Field()
- """
- The filename supplied at upload time, kept for display.
- """
-
- content_type: str = pydantic.Field()
- """
- Always `audio/wav`. Pinned server-side after WAV validation
- rather than trusting the upload's multipart Content-Type
- header.
- """
-
- size_bytes: int = pydantic.Field()
- """
- Stored byte length. Capped at 4 MiB at upload time.
- """
-
- duration_ms: int = pydantic.Field()
- """
- Clip duration in milliseconds. Capped at 30000 (30s) at upload time.
- """
-
- sample_rate_hz: int = pydantic.Field()
- """
- WAV sample rate. Always 48000 (matches the LiveKit room rate).
- """
-
- channels: int = pydantic.Field()
- """
- Channel count. Always 1 (mono).
- """
-
- bit_depth: int = pydantic.Field()
- """
- PCM sample bit depth. Always 16.
- """
-
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/available_phone_number.py b/src/speechify/types/available_phone_number.py
deleted file mode 100644
index a88ad98..0000000
--- a/src/speechify/types/available_phone_number.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class AvailablePhoneNumber(UniversalBaseModel):
- """
- One hit from `GET /v1/agents/phone-numbers/available`. The number is
- not held: a concurrent buy by another customer may take it
- between this response and a subsequent purchase request.
- """
-
- e164: str = pydantic.Field()
- """
- The phone number in E.164 format.
- """
-
- friendly_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Carrier-formatted display variant, e.g. "(415) 555-2671".
- """
-
- locality: typing.Optional[str] = pydantic.Field(default=None)
- """
- City the number is associated with, when known.
- """
-
- region: typing.Optional[str] = pydantic.Field(default=None)
- """
- Two-letter state code for US numbers.
- """
-
- iso_country: str = pydantic.Field()
- """
- ISO-3166 alpha-2 country code.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/basic_auth_config.py b/src/speechify/types/basic_auth_config.py
deleted file mode 100644
index 90e68cd..0000000
--- a/src/speechify/types/basic_auth_config.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class BasicAuthConfig(UniversalBaseModel):
- """
- HTTP Basic auth — username + password.
- """
-
- username: str
- password: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/batch_call.py b/src/speechify/types/batch_call.py
deleted file mode 100644
index 35987a0..0000000
--- a/src/speechify/types/batch_call.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .batch_call_status import BatchCallStatus
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class BatchCall(UniversalBaseModel):
- """
- A batch of outbound calls dispatched to a list of recipients.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`batch_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the agent that will run the batch.
- """
-
- phone_number_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Caller-ID override. When set, prefixed wire identifier
- (`phone_<26 char Crockford base32>`) of the phone number to
- use; falls back to the agent's bound number when null. ADR
- 0015 FK consistency.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable batch name.
- """
-
- status: BatchCallStatus
- total: int = pydantic.Field()
- """
- Total number of recipients.
- """
-
- completed: int = pydantic.Field()
- """
- Recipients successfully dialed.
- """
-
- failed: int = pydantic.Field()
- """
- Recipients that failed.
- """
-
- error: typing.Optional[str] = pydantic.Field(default=None)
- """
- Populated when the batch itself fails.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
- started_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- When the dispatcher started dialing.
- """
-
- finished_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- When the last recipient was resolved.
- """
-
- scheduled_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- If set, the batch waits until this time before dialing.
- """
-
- ringing_timeout_ms: typing.Optional[int] = pydantic.Field(default=None)
- """
- Per-call ringing timeout in milliseconds applied to every
- recipient in the batch. Null when the batch uses the 30s
- default.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/batch_call_status.py b/src/speechify/types/batch_call_status.py
deleted file mode 100644
index c99dcd3..0000000
--- a/src/speechify/types/batch_call_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-BatchCallStatus = typing.Union[
- typing.Literal["pending", "scheduled", "running", "completed", "failed", "cancelled"], typing.Any
-]
diff --git a/src/speechify/types/batch_recipient.py b/src/speechify/types/batch_recipient.py
deleted file mode 100644
index 58f6b40..0000000
--- a/src/speechify/types/batch_recipient.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .batch_recipient_status import BatchRecipientStatus
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class BatchRecipient(UniversalBaseModel):
- """
- One recipient row in a batch call.
- """
-
- id: str
- batch_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`batch_<26 char Crockford base32>`)
- of the parent batch.
- """
-
- phone: str = pydantic.Field()
- """
- Recipient phone number in E.164 format.
- """
-
- dynamic_vars: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Per-recipient variable overrides injected into the agent prompt.
- """
-
- status: BatchRecipientStatus
- conversation_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Set once the call is placed. Prefixed wire identifier
- (`conv_<26 char Crockford base32>`).
- """
-
- error: typing.Optional[str] = pydantic.Field(default=None)
- """
- Populated when this recipient fails.
- """
-
- attempted_at: typing.Optional[dt.datetime] = None
- completed_at: typing.Optional[dt.datetime] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/batch_recipient_request.py b/src/speechify/types/batch_recipient_request.py
deleted file mode 100644
index 11a7af7..0000000
--- a/src/speechify/types/batch_recipient_request.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class BatchRecipientRequest(UniversalBaseModel):
- """
- One entry in a batch-call request.
- """
-
- phone: str = pydantic.Field()
- """
- Recipient phone number in E.164 format.
- """
-
- dynamic_vars: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None)
- """
- Per-recipient variable overrides injected into the agent prompt.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/batch_recipient_status.py b/src/speechify/types/batch_recipient_status.py
deleted file mode 100644
index 0c020b5..0000000
--- a/src/speechify/types/batch_recipient_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-BatchRecipientStatus = typing.Union[typing.Literal["pending", "dialing", "completed", "failed"], typing.Any]
diff --git a/src/speechify/types/batch_run_entry.py b/src/speechify/types/batch_run_entry.py
deleted file mode 100644
index b99e37f..0000000
--- a/src/speechify/types/batch_run_entry.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class BatchRunEntry(UniversalBaseModel):
- """
- One entry in a batch-run request. Omit `agent_id` to fan out to
- every agent the test is attached to.
- """
-
- test_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`test_<26 char Crockford base32>`)
- of the test to run.
- """
-
- agent_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the agent to run the test against. Omit to fan out to
- every agent the test is attached to.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/bearer_auth_config.py b/src/speechify/types/bearer_auth_config.py
deleted file mode 100644
index b178b15..0000000
--- a/src/speechify/types/bearer_auth_config.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class BearerAuthConfig(UniversalBaseModel):
- """
- A static bearer token sent as `Authorization: Bearer …`. For
- rotating tokens prefer one of the oauth2 kinds.
- """
-
- token: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/billing_entitlements.py b/src/speechify/types/billing_entitlements.py
deleted file mode 100644
index 487e6d3..0000000
--- a/src/speechify/types/billing_entitlements.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class BillingEntitlements(UniversalBaseModel):
- """
- Customer-facing per-tier limits + feature flags. The server-internal
- HTTP rate/concurrency guards are deliberately omitted. Numeric fields are
- caps; booleans gate features.
- """
-
- phone_number_quota: int = pydantic.Field()
- """
- Speechify-managed (purchased) phone numbers allowed.
- """
-
- concurrent_call_cap: int = pydantic.Field()
- """
- Simultaneously-active voice calls allowed.
- """
-
- max_members: int = pydantic.Field()
- """
- Members allowed in a single workspace (owner + invitees).
- """
-
- max_call_duration_seconds: int = pydantic.Field()
- """
- Per-call wall-clock ceiling, in seconds.
- """
-
- can_create_workspaces: bool = pydantic.Field()
- """
- Whether the workspace may create ADDITIONAL workspaces.
- """
-
- topup_allowed: bool = pydantic.Field()
- """
- Whether prepaid funds may be added beyond the monthly grant.
- """
-
- voice_cloning: bool = pydantic.Field()
- """
- Whether voice cloning is available.
- """
-
- batch_calls: bool = pydantic.Field()
- """
- Whether batch outbound calls are available.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/caller.py b/src/speechify/types/caller.py
deleted file mode 100644
index f1a0929..0000000
--- a/src/speechify/types/caller.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Caller(UniversalBaseModel):
- """
- First-class Caller entity. Identified by
- the (tenant, agent, identity) triple. Memories and conversations
- FK at it via `caller_id`.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`caller_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- tenant_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`ws_<26 char Crockford base32>`) of
- the owning workspace.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the agent the caller is scoped under.
- """
-
- identity: str = pydantic.Field()
- """
- The raw identifier the caller arrived with (E.164 phone for SIP, LiveKit
- participant id for web). Stable for the life of the caller row.
- """
-
- display_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Operator-editable display name, nullable.
- """
-
- external_ref: typing.Optional[str] = pydantic.Field(default=None)
- """
- Optional handle into the customer's own CRM, nullable.
- """
-
- metadata: typing.Dict[str, typing.Optional[typing.Any]] = pydantic.Field()
- """
- Customer-supplied JSON metadata blob.
- """
-
- first_seen_at: dt.datetime = pydantic.Field()
- """
- Timestamp of the earliest observed conversation / memory for this caller.
- """
-
- last_seen_at: dt.datetime = pydantic.Field()
- """
- Timestamp of the most recent observation. Drives the default list ordering.
- """
-
- conversation_count: int = pydantic.Field()
- """
- Number of conversation rows currently pointing at this caller.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/caller_memory_item.py b/src/speechify/types/caller_memory_item.py
deleted file mode 100644
index 1406b5e..0000000
--- a/src/speechify/types/caller_memory_item.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class CallerMemoryItem(UniversalBaseModel):
- """
- Memory projection returned by the per-caller memories list. Mirrors
- the legacy `/v1/agents/{id}/memories` shape so console code can
- re-use existing renderers.
- """
-
- id: str
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the owning agent.
- """
-
- caller_identity: str
- fact: str
- source_conversation_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- When set, the prefixed wire identifier
- (`conv_<26 char Crockford base32>`) of the conversation this
- memory was extracted from.
- """
-
- confidence: float
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/client_tool_config.py b/src/speechify/types/client_tool_config.py
deleted file mode 100644
index 8564c09..0000000
--- a/src/speechify/types/client_tool_config.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .tool_param import ToolParam
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ClientToolConfig(UniversalBaseModel):
- """
- Config shape for `kind=client`. Execution happens in the caller's browser / SDK.
- """
-
- params: typing.Optional[typing.List[ToolParam]] = None
- timeout_ms: typing.Optional[int] = pydantic.Field(default=None)
- """
- Per-call timeout in milliseconds. Defaults to 10000 server-side when omitted.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/conversation.py b/src/speechify/types/conversation.py
deleted file mode 100644
index 87a25af..0000000
--- a/src/speechify/types/conversation.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .conversation_status import ConversationStatus
-from .conversation_transport import ConversationTransport
-import datetime as dt
-from .conversation_end_reason import ConversationEndReason
-from .agent_snapshot import AgentSnapshot
-from .conversation_ivr_surrender_reason import ConversationIvrSurrenderReason
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Conversation(UniversalBaseModel):
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`conv_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- for the agent that answers this conversation.
- """
-
- room_name: str = pydantic.Field()
- """
- LiveKit room name. Equals the conversation `id` for `web`
- and `sip_outbound` transports; `sip_inbound` rooms use a
- `sip__` name assigned by the SIP dispatch rule.
- """
-
- room_sid: typing.Optional[str] = None
- status: ConversationStatus
- transport: ConversationTransport
- created_at: dt.datetime = pydantic.Field()
- """
- When the conversation row was created (the call was
- initiated). Always present, including for conversations
- that never started — unlike `started_at` — so it is the
- timestamp to display and sort pending calls by.
- """
-
- started_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- Set when the first user participant joins the realtime
- voice session. Null between CreateConversation and the
- participant-joined event, and stays null if no user ever
- joins.
- """
-
- ended_at: typing.Optional[dt.datetime] = None
- duration_ms: typing.Optional[int] = None
- cost_cents: typing.Optional[int] = None
- recording_url: typing.Optional[str] = None
- recording_started_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- When the recording file actually began capturing audio
- (LiveKit egress file started_at). Anchor transcript message
- offsets on this — not `started_at` — when seeking the
- recording: the file's first frame trails the participant
- join by the egress recorder's spin-up (~1-2s). Null when
- there is no recording or the row pre-dates the field.
- """
-
- end_reason: typing.Optional[ConversationEndReason] = pydantic.Field(default=None)
- """
- Coarse termination category. Worker-stamped reasons arrive
- before `terminate_call` fires; `caller_hangup` has two
- emit sites (worker-observed SIP disconnect, plus a
- server-side post-call catch-all).
- * `voicemail_message_left` — AMD machine-vm + we spoke the configured drop-message.
- * `voicemail_hangup` — AMD machine-vm + we terminated silently (action=hangup or empty-message bypass).
- * `ivr_hangup` — AMD machine-ivr + action=hangup.
- * `unavailable_hangup` — AMD machine-unavailable (mailbox full / disconnected).
- * `agent_ended` — LLM-driven end_call builtin.
- * `inactivity_timeout` — worker's inactivity handler fired terminate after the configured silence window.
- * `loop_detected` — worker's runtime loop guard force-ended the call after N consecutive near-identical user turns (typically an IVR replaying its menu while the LLM kept reacting instead of calling end_call).
- * `max_duration_reached` - worker's max-call-duration watchdog force-ended the call at the platform ceiling (a safety bound on runaway calls).
- * `over_capacity` — inbound call refused because the workspace was over its active-call concurrency cap; the busy message played and the call hung up. Stamped server-side and excluded from billing.
- * `caller_hangup` — caller's leg went away. Precise when the worker observed the SIP `participant_disconnected` event (stamped immediately); otherwise stamped server-side ~10s after `room_finished` as a catch-all (web tab close, network blip, worker crash, etc.).
- * `null` — pre-rollout calls only (anything that landed after the rollout completes without a stamp gets `caller_hangup` from the post-call goroutine).
- """
-
- metadata: typing.Dict[str, typing.Optional[typing.Any]]
- caller_identity: typing.Optional[str] = pydantic.Field(default=None)
- """
- Stable caller key (LiveKit participant identity) persisted
- at session start so the post-call memory extractor can
- pivot memories by `(agent_id, caller_identity)`. Empty
- string for anonymous widget sessions.
- """
-
- from_number: typing.Optional[str] = pydantic.Field(default=None)
- """
- E.164 of the phone number that placed the call. For
- `sip_outbound` this is the workspace number used as the
- caller ID; for `sip_inbound` it is the external caller's
- number. Null for `web` conversations and for older
- outbound rows, where the dialing caller id was not recorded
- before this field existed.
- """
-
- to_number: typing.Optional[str] = pydantic.Field(default=None)
- """
- E.164 of the phone number that received the call. For
- `sip_outbound` this is the external callee; for
- `sip_inbound` it is the workspace number the caller
- dialed. Null for `web` conversations and for legacy
- inbound rows whose room name did not embed the dialed
- number.
- """
-
- agent_snapshot: typing.Optional[AgentSnapshot] = pydantic.Field(default=None)
- """
- Frozen snapshot of the agent's configuration at create
- time. Populated only on detail responses; list responses
- intentionally skip the column to keep the row small.
- """
-
- dynamic_variables: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Customer-facing dynamic variables this call ran with: the
- agent's stored variable defaults overlaid with the
- per-session `dynamic_variables` overrides, resolved to
- their values. Reserved `system__*` keys are excluded —
- they are runtime-derived and not part of the audit
- snapshot. Omitted for SIP inbound calls (which take no
- per-session variables) and for any pre-rollout
- conversation. Populated only on detail responses; the
- list endpoint skips it, mirroring `agent_snapshot`.
- """
-
- message_count: int = pydantic.Field()
- """
- Populated only on the list endpoint via a correlated
- subquery. Zero on single-row reads where the join cost
- isn't paid.
- """
-
- ivr_menu_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Audit pointer at the cached IVR menu the
- navigator consulted on this call. NULL when the navigator
- never engaged OR after the referenced menu was
- invalidated (FK is ON DELETE SET NULL).
- """
-
- ivr_path_taken: typing.Optional[typing.List[typing.Dict[str, typing.Optional[typing.Any]]]] = pydantic.Field(
- default=None
- )
- """
- Ordered log of the navigator's per-call presses:
- `[{fingerprint, dtmf, label}, ...]`. Empty array means
- "navigator engaged but pressed nothing" (distinct from
- NULL = "navigator never engaged").
- """
-
- ivr_surrender_reason: typing.Optional[ConversationIvrSurrenderReason] = pydantic.Field(default=None)
- """
- Canonical code the worker emits when the IVR
- navigator gave up. NULL when the navigator completed
- cleanly OR never started a plan.
- * `no_goal` - the goal extractor returned empty.
- * `no_cached_menu` - AMD-time cache miss for the root fingerprint.
- * `below_threshold` - cached menu loaded but confidence < threshold.
- * `fingerprint_mismatch` - in-call prompt diverged from the cached menu fingerprint.
- * `goal_ambiguous` - cached options matched the goal more than once or not at all.
- * `child_cache_miss` - sub-menu fingerprint had no cached row.
- * `dtmf_send_failure` - DTMF press could not be delivered.
- * `matched_option_missing_dtmf` - defensive shape guard.
- * `disabled` - per-agent toggle off OR operator kill switch on.
- * `repeated_prompt_max_retries` - bounded press-retry on the same fingerprint hit its cap of 1.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/conversation_end_reason.py b/src/speechify/types/conversation_end_reason.py
deleted file mode 100644
index 8b3f86c..0000000
--- a/src/speechify/types/conversation_end_reason.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ConversationEndReason = typing.Union[
- typing.Literal[
- "voicemail_message_left",
- "voicemail_hangup",
- "ivr_hangup",
- "unavailable_hangup",
- "agent_ended",
- "caller_hangup",
- "inactivity_timeout",
- "loop_detected",
- "max_duration_reached",
- "over_capacity",
- ],
- typing.Any,
-]
diff --git a/src/speechify/types/conversation_ivr_surrender_reason.py b/src/speechify/types/conversation_ivr_surrender_reason.py
deleted file mode 100644
index a5aa2e0..0000000
--- a/src/speechify/types/conversation_ivr_surrender_reason.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ConversationIvrSurrenderReason = typing.Union[
- typing.Literal[
- "no_goal",
- "no_cached_menu",
- "below_threshold",
- "fingerprint_mismatch",
- "goal_ambiguous",
- "child_cache_miss",
- "dtmf_send_failure",
- "matched_option_missing_dtmf",
- "disabled",
- "repeated_prompt_max_retries",
- ],
- typing.Any,
-]
diff --git a/src/speechify/types/conversation_stats.py b/src/speechify/types/conversation_stats.py
deleted file mode 100644
index eba7d03..0000000
--- a/src/speechify/types/conversation_stats.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ConversationStats(UniversalBaseModel):
- """
- Counts + averages over the caller's conversations matching the supplied filters. AVG fields are null when no rows match the FILTER predicate.
- """
-
- total: int
- completed: int
- failed: int
- active: int
- pending: int
- avg_duration_ms: typing.Optional[float] = None
- avg_cost_cents: typing.Optional[float] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/conversation_status.py b/src/speechify/types/conversation_status.py
deleted file mode 100644
index 7b121bf..0000000
--- a/src/speechify/types/conversation_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ConversationStatus = typing.Union[typing.Literal["pending", "active", "completed", "failed"], typing.Any]
diff --git a/src/speechify/types/conversation_transport.py b/src/speechify/types/conversation_transport.py
deleted file mode 100644
index 5deba94..0000000
--- a/src/speechify/types/conversation_transport.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ConversationTransport = typing.Union[
- typing.Literal["web", "phone", "whatsapp", "sip_inbound", "sip_outbound"], typing.Any
-]
diff --git a/src/speechify/types/create_access_token_request.py b/src/speechify/types/create_access_token_request.py
deleted file mode 100644
index ad3098a..0000000
--- a/src/speechify/types/create_access_token_request.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .create_access_token_request_grant_type import CreateAccessTokenRequestGrantType
-import typing
-from .create_access_token_request_scope import CreateAccessTokenRequestScope
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class CreateAccessTokenRequest(UniversalBaseModel):
- grant_type: CreateAccessTokenRequestGrantType
- scope: typing.Optional[CreateAccessTokenRequestScope] = pydantic.Field(default=None)
- """
- The scope, or a space-delimited list of scopes the token is requested for
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_access_token_request_grant_type.py b/src/speechify/types/create_access_token_request_grant_type.py
deleted file mode 100644
index 9d7c254..0000000
--- a/src/speechify/types/create_access_token_request_grant_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CreateAccessTokenRequestGrantType = typing.Union[typing.Literal["client_credentials"], typing.Any]
diff --git a/src/speechify/types/create_access_token_request_scope.py b/src/speechify/types/create_access_token_request_scope.py
deleted file mode 100644
index 6c7c11c..0000000
--- a/src/speechify/types/create_access_token_request_scope.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CreateAccessTokenRequestScope = typing.Union[
- typing.Literal[
- "audio:speech", "audio:stream", "audio:all", "voices:read", "voices:create", "voices:delete", "voices:all"
- ],
- typing.Any,
-]
diff --git a/src/speechify/types/create_api_key_request.py b/src/speechify/types/create_api_key_request.py
deleted file mode 100644
index 9bd76d6..0000000
--- a/src/speechify/types/create_api_key_request.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class CreateApiKeyRequest(UniversalBaseModel):
- """
- Body for `POST /v1/api-keys` and `PATCH /v1/api-keys/{id}` — both endpoints accept the same shape.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable label for the key.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_batch_call_response.py b/src/speechify/types/create_batch_call_response.py
deleted file mode 100644
index 2a7339b..0000000
--- a/src/speechify/types/create_batch_call_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .batch_call import BatchCall
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class CreateBatchCallResponse(UniversalBaseModel):
- batch: BatchCall
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_conversation_response.py b/src/speechify/types/create_conversation_response.py
deleted file mode 100644
index 4395fd9..0000000
--- a/src/speechify/types/create_conversation_response.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .conversation import Conversation
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class CreateConversationResponse(UniversalBaseModel):
- """
- Returned when a conversation is created. The `token` + `url`
- let the caller connect its browser/SDK directly to the
- realtime voice session — the agent that answers is dispatched
- server-side.
- """
-
- conversation: Conversation
- room: str
- token: str = pydantic.Field()
- """
- Short-lived realtime session access token (JWT).
- """
-
- url: str = pydantic.Field()
- """
- Realtime session wss:// URL to connect to.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_credential_request.py b/src/speechify/types/create_credential_request.py
deleted file mode 100644
index 1e125ad..0000000
--- a/src/speechify/types/create_credential_request.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .credential_kind import CredentialKind
-from .credential_config import CredentialConfig
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class CreateCredentialRequest(UniversalBaseModel):
- """
- Body for `POST /v1/credentials`.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable label, unique per workspace.
- """
-
- kind: CredentialKind
- config: CredentialConfig
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_flow_template_request.py b/src/speechify/types/create_flow_template_request.py
deleted file mode 100644
index 37134fd..0000000
--- a/src/speechify/types/create_flow_template_request.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from .flow_graph_input import FlowGraphInput
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class CreateFlowTemplateRequest(UniversalBaseModel):
- """
- Request body for creating (POST) or replacing (PATCH) a flow
- template. PATCH replaces the whole template, it is not a
- field-by-field patch.
- """
-
- key: str
- name: str
- description: typing.Optional[str] = None
- category: typing.Optional[str] = pydantic.Field(default=None)
- """
- Defaults to "custom" when omitted.
- """
-
- graph: FlowGraphInput
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_invite_request.py b/src/speechify/types/create_invite_request.py
deleted file mode 100644
index c40aed5..0000000
--- a/src/speechify/types/create_invite_request.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .member_role import MemberRole
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class CreateInviteRequest(UniversalBaseModel):
- email: str = pydantic.Field()
- """
- Email of the person to invite. Validated as an RFC 5322 address.
- """
-
- role: typing.Optional[MemberRole] = pydantic.Field(default=None)
- """
- Workspace role the invitee joins with when they accept the
- invite. Optional; defaults to `member` when omitted. An
- admin caller may invite at `admin` or `member` but not
- `owner`. Only an owner can invite a new owner.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_outbound_call_response.py b/src/speechify/types/create_outbound_call_response.py
deleted file mode 100644
index 699643e..0000000
--- a/src/speechify/types/create_outbound_call_response.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class CreateOutboundCallResponse(UniversalBaseModel):
- """
- Returned synchronously when LiveKit accepts the SIP INVITE. Poll
- `GET /v1/agents/conversations/{conversation_id}` for status transitions:
- `pending` (ringing) → `active` (answered) → `completed`.
- """
-
- conversation_id: str = pydantic.Field()
- """
- ID of the conversation created for this call. Use to poll status.
- """
-
- room: str = pydantic.Field()
- """
- LiveKit room name the answered call joins.
- """
-
- sip_participant_id: str = pydantic.Field()
- """
- LiveKit participant ID for the outbound SIP call leg.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/create_workspace_request.py b/src/speechify/types/create_workspace_request.py
deleted file mode 100644
index 5ca5831..0000000
--- a/src/speechify/types/create_workspace_request.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class CreateWorkspaceRequest(UniversalBaseModel):
- """
- Body for POST /v1/workspaces. The `name` field is optional; omitting it falls back to "Workspace".
- """
-
- name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Display name for the new workspace. Trimmed; must be 120 characters or fewer.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/credential.py b/src/speechify/types/credential.py
deleted file mode 100644
index b84aa1b..0000000
--- a/src/speechify/types/credential.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .credential_kind import CredentialKind
-from .credential_config import CredentialConfig
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class Credential(UniversalBaseModel):
- """
- A workspace-shared secret in the credentials vault. Tools (and
- future MCP servers) reference a credential by id rather than
- inlining a secret per row, so one OAuth / Basic / Bearer /
- headers blob is reused across many tools and rotated centrally.
- """
-
- id: str = pydantic.Field()
- """
- Workspace-scoped credential identifier.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable label, unique per workspace among active
- credentials.
- """
-
- kind: CredentialKind
- config: CredentialConfig
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/credential_config.py b/src/speechify/types/credential_config.py
deleted file mode 100644
index 2621f8c..0000000
--- a/src/speechify/types/credential_config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing_extensions
-import typing
-from .o_auth2client_credentials_config import OAuth2ClientCredentialsConfig
-from ..core.serialization import FieldMetadata
-from .o_auth2jwt_config import OAuth2JwtConfig
-from .basic_auth_config import BasicAuthConfig
-from .bearer_auth_config import BearerAuthConfig
-from .custom_headers_config import CustomHeadersConfig
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class CredentialConfig(UniversalBaseModel):
- """
- Kind-specific credential payload. Exactly one block is
- populated — the one named by the credential's `kind`. The
- block IS the secret; it is echoed back decrypted on reads.
- """
-
- oauth2client_credentials: typing_extensions.Annotated[
- typing.Optional[OAuth2ClientCredentialsConfig], FieldMetadata(alias="oauth2_client_credentials")
- ] = None
- oauth2jwt: typing_extensions.Annotated[typing.Optional[OAuth2JwtConfig], FieldMetadata(alias="oauth2_jwt")] = None
- basic: typing.Optional[BasicAuthConfig] = None
- bearer: typing.Optional[BearerAuthConfig] = None
- custom_headers: typing.Optional[CustomHeadersConfig] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/credential_kind.py b/src/speechify/types/credential_kind.py
deleted file mode 100644
index 686fa55..0000000
--- a/src/speechify/types/credential_kind.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CredentialKind = typing.Union[
- typing.Literal["oauth2_client_credentials", "oauth2_jwt", "basic", "bearer", "custom_headers"], typing.Any
-]
diff --git a/src/speechify/types/criterion_status.py b/src/speechify/types/criterion_status.py
deleted file mode 100644
index a43bff7..0000000
--- a/src/speechify/types/criterion_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-CriterionStatus = typing.Union[typing.Literal["success", "failure", "unknown"], typing.Any]
diff --git a/src/speechify/types/custom_headers_config.py b/src/speechify/types/custom_headers_config.py
deleted file mode 100644
index c082774..0000000
--- a/src/speechify/types/custom_headers_config.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class CustomHeadersConfig(UniversalBaseModel):
- """
- An arbitrary set of headers sent on every outbound tool
- request. Useful for vendor signature schemes that don't fit
- Basic / Bearer.
- """
-
- headers: typing.Dict[str, str]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/data_assertion.py b/src/speechify/types/data_assertion.py
deleted file mode 100644
index 2486eab..0000000
--- a/src/speechify/types/data_assertion.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .data_assertion_mode import DataAssertionMode
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class DataAssertion(UniversalBaseModel):
- """
- Asserts on one entry in the LLM-extracted data-collection map
- produced by the unified evaluator. `key` matches a
- data-collection field configured on the agent; the assertion
- runs against the value the judge wrote under that key. Same
- exact / regex / llm modes as `ParameterCheck` so the tool-call
- and data-collection assertion surfaces are uniform.
- """
-
- key: str = pydantic.Field()
- """
- Name of the data-collection field on the agent's evaluation config. The assertion fails when this key is missing from the extracted data.
- """
-
- mode: DataAssertionMode = pydantic.Field()
- """
- How the assertion validates the extracted value.
- """
-
- expected: typing.Optional[str] = pydantic.Field(default=None)
- """
- Expected value string for `exact` and `regex` modes.
- """
-
- criteria: typing.Optional[str] = pydantic.Field(default=None)
- """
- Natural-language criteria for `llm` mode.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/data_assertion_mode.py b/src/speechify/types/data_assertion_mode.py
deleted file mode 100644
index a50fbd0..0000000
--- a/src/speechify/types/data_assertion_mode.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-DataAssertionMode = typing.Union[typing.Literal["exact", "regex", "llm"], typing.Any]
diff --git a/src/speechify/types/data_assertion_result.py b/src/speechify/types/data_assertion_result.py
deleted file mode 100644
index 2c937bf..0000000
--- a/src/speechify/types/data_assertion_result.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .data_assertion_result_mode import DataAssertionResultMode
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class DataAssertionResult(UniversalBaseModel):
- """
- Outcome of one `data_assertions` entry: did the value the
- evaluator extracted under `key` pass the configured exact /
- regex / llm check.
- """
-
- key: str
- mode: DataAssertionResultMode
- actual_json: str = pydantic.Field()
- """
- The extracted value rendered as JSON (`null` when the key was missing from the data map).
- """
-
- passed: bool
- rationale: typing.Optional[str] = pydantic.Field(default=None)
- """
- Empty on pass; reason for failure otherwise.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/data_assertion_result_mode.py b/src/speechify/types/data_assertion_result_mode.py
deleted file mode 100644
index f99c522..0000000
--- a/src/speechify/types/data_assertion_result_mode.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-DataAssertionResultMode = typing.Union[typing.Literal["exact", "regex", "llm"], typing.Any]
diff --git a/src/speechify/types/data_collection_field.py b/src/speechify/types/data_collection_field.py
deleted file mode 100644
index 6002dab..0000000
--- a/src/speechify/types/data_collection_field.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .data_collection_field_type import DataCollectionFieldType
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class DataCollectionField(UniversalBaseModel):
- """
- A structured value the post-call evaluator should extract from the
- transcript. `int` is distinct from `number` so downstream consumers
- receive whole integers without a synthetic decimal.
- """
-
- key: str
- description: str
- type: DataCollectionFieldType
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/data_collection_field_type.py b/src/speechify/types/data_collection_field_type.py
deleted file mode 100644
index b9a1a96..0000000
--- a/src/speechify/types/data_collection_field_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-DataCollectionFieldType = typing.Union[typing.Literal["string", "int", "number", "boolean"], typing.Any]
diff --git a/src/speechify/types/delete_caller_response.py b/src/speechify/types/delete_caller_response.py
deleted file mode 100644
index e590c69..0000000
--- a/src/speechify/types/delete_caller_response.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class DeleteCallerResponse(UniversalBaseModel):
- """
- Audit envelope returned by DELETE /v1/agents/callers/{id}. Surfaces
- the cascade row counts so a privacy operator has direct evidence
- of the purge without re-querying.
- """
-
- caller_purged: int = pydantic.Field()
- """
- 1 on the first delete; 0 on idempotent re-delete.
- """
-
- memories_purged: int = pydantic.Field()
- """
- Number of user_memories rows cascade-soft-deleted under this caller.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/delete_memories_by_caller_response.py b/src/speechify/types/delete_memories_by_caller_response.py
deleted file mode 100644
index 05acf4e..0000000
--- a/src/speechify/types/delete_memories_by_caller_response.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class DeleteMemoriesByCallerResponse(UniversalBaseModel):
- deleted: int = pydantic.Field()
- """
- Number of memories soft-deleted.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/dependent_agent.py b/src/speechify/types/dependent_agent.py
deleted file mode 100644
index 150739c..0000000
--- a/src/speechify/types/dependent_agent.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class DependentAgent(UniversalBaseModel):
- """
- Minimal agent pointer (id + name) used by the document
- detail view to render a clickable link to each agent that
- has the document's KB attached.
- """
-
- id: str
- name: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/dynamic_variable.py b/src/speechify/types/dynamic_variable.py
deleted file mode 100644
index d82fa83..0000000
--- a/src/speechify/types/dynamic_variable.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .dynamic_variable_type import DynamicVariableType
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class DynamicVariable(UniversalBaseModel):
- """
- One customer-scope variable definition on an agent. Referenced in
- prompts, first messages, and webhook tool configs via `{{key}}` or
- `{{key|json}}`. Missing variables render as empty string at dispatch
- time - a typo never breaks a session.
- """
-
- key: str = pydantic.Field()
- """
- Variable name. Must match `[a-zA-Z0-9_]+`. The `system__` prefix
- is reserved for platform-populated variables and will be rejected.
- """
-
- type: DynamicVariableType
- default: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
- """
- Optional default value used when no per-session override is
- supplied. Must conform to the declared `type`.
- """
-
- description: typing.Optional[str] = pydantic.Field(default=None)
- """
- Human-readable note shown in the console variable editor.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/dynamic_variable_type.py b/src/speechify/types/dynamic_variable_type.py
deleted file mode 100644
index d12f3f8..0000000
--- a/src/speechify/types/dynamic_variable_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-DynamicVariableType = typing.Union[typing.Literal["string", "number", "boolean", "json"], typing.Any]
diff --git a/src/speechify/types/entitlements_response.py b/src/speechify/types/entitlements_response.py
deleted file mode 100644
index 69840b1..0000000
--- a/src/speechify/types/entitlements_response.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .billing_entitlements import BillingEntitlements
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class EntitlementsResponse(UniversalBaseModel):
- """
- `catalog` is every sellable tier's FLOOR entitlements, keyed by tier
- (`free`/`starter`/`pro`/`scale`/`enterprise`) for the upgrade cards.
- `current` is the caller's workspace RESOLVED entitlements (tier floor
- composed with its per-tenant override), so a custom/Enterprise customer
- sees their actual caps - not just the tier floor.
- """
-
- catalog: typing.Dict[str, BillingEntitlements] = pydantic.Field()
- """
- Per-tier floor entitlements, keyed by tier string.
- """
-
- current: BillingEntitlements
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/evaluation.py b/src/speechify/types/evaluation.py
deleted file mode 100644
index 2170972..0000000
--- a/src/speechify/types/evaluation.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .evaluation_kind import EvaluationKind
-import typing
-from .evaluation_status import EvaluationStatus
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Evaluation(UniversalBaseModel):
- """
- Three flavours coexist, discriminated by `kind`:
- - `criterion` rows carry `status` + `passed` + `score` + `rationale` for one criterion
- - `summary` row carries overall sentiment + rationale in `rationale`
- - `data` row carries the structured data-collection payload in `data`
-
- `status` is the canonical three-state result. `passed` is a
- derived boolean kept for backwards compatibility with earlier
- webhook consumers: success→true, failure→false, unknown→null.
- """
-
- id: str
- conversation_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`conv_<26 char Crockford base32>`)
- of the conversation this evaluation is attached to.
- """
-
- kind: EvaluationKind
- criterion_id: typing.Optional[str] = None
- name: str
- status: typing.Optional[EvaluationStatus] = pydantic.Field(default=None)
- """
- Three-state criterion result. `unknown` means the criterion did not apply to this call.
- """
-
- passed: typing.Optional[bool] = None
- score: typing.Optional[float] = None
- rationale: str
- data: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
- """
- Structured data-collection payload (present only on `kind=data` rows).
- """
-
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/evaluation_config.py b/src/speechify/types/evaluation_config.py
deleted file mode 100644
index 4bafd9e..0000000
--- a/src/speechify/types/evaluation_config.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .evaluation_criterion import EvaluationCriterion
-from .data_collection_field import DataCollectionField
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class EvaluationConfig(UniversalBaseModel):
- criteria: typing.List[EvaluationCriterion]
- data_collection: typing.List[DataCollectionField]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/evaluation_criterion.py b/src/speechify/types/evaluation_criterion.py
deleted file mode 100644
index 8f065e7..0000000
--- a/src/speechify/types/evaluation_criterion.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class EvaluationCriterion(UniversalBaseModel):
- """
- One LLM-scored assertion about the call ("Did the agent confirm the customer's name?").
- """
-
- id: str
- name: str
- description: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/evaluation_kind.py b/src/speechify/types/evaluation_kind.py
deleted file mode 100644
index 8c1feac..0000000
--- a/src/speechify/types/evaluation_kind.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-EvaluationKind = typing.Union[typing.Literal["criterion", "summary", "data"], typing.Any]
diff --git a/src/speechify/types/evaluation_status.py b/src/speechify/types/evaluation_status.py
deleted file mode 100644
index 9af14a4..0000000
--- a/src/speechify/types/evaluation_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-EvaluationStatus = typing.Union[typing.Literal["success", "failure", "unknown"], typing.Any]
diff --git a/src/speechify/types/flow_graph.py b/src/speechify/types/flow_graph.py
deleted file mode 100644
index 8e5f3d7..0000000
--- a/src/speechify/types/flow_graph.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .flow_version import FlowVersion
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class FlowGraph(UniversalBaseModel):
- """
- A flow graph: an ordered set of typed nodes connected by edges,
- plus flow variables. The node, edge, and variable shapes are
- governed by the live JSON Schema at GET /v1/agents/flow/schema
- and are intentionally opaque here so this spec cannot drift
- from that authoritative definition.
- """
-
- version: FlowVersion
- nodes: typing.List[typing.Dict[str, typing.Optional[typing.Any]]]
- edges: typing.List[typing.Dict[str, typing.Optional[typing.Any]]]
- variables: typing.Optional[typing.List[typing.Dict[str, typing.Optional[typing.Any]]]] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/flow_graph_input.py b/src/speechify/types/flow_graph_input.py
deleted file mode 100644
index 1d43ae4..0000000
--- a/src/speechify/types/flow_graph_input.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class FlowGraphInput(UniversalBaseModel):
- """
- Request-side flow graph: nodes, edges, and variables only.
- Unlike the response-side FlowGraph it carries no `version`
- block - the server owns version metadata.
- """
-
- nodes: typing.List[typing.Dict[str, typing.Optional[typing.Any]]]
- edges: typing.List[typing.Dict[str, typing.Optional[typing.Any]]]
- variables: typing.Optional[typing.List[typing.Dict[str, typing.Optional[typing.Any]]]] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/flow_template.py b/src/speechify/types/flow_template.py
deleted file mode 100644
index b4cf928..0000000
--- a/src/speechify/types/flow_template.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .flow_graph import FlowGraph
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class FlowTemplate(UniversalBaseModel):
- """
- A reusable flow graph that can be cloned onto an agent as a new draft.
- """
-
- id: str = pydantic.Field()
- """
- Flow template id. A raw UUID, not a prefixed external id.
- """
-
- key: str = pydantic.Field()
- """
- Stable unique key for the template.
- """
-
- name: str
- description: typing.Optional[str] = None
- category: str
- graph: FlowGraph
- is_seed: bool = pydantic.Field()
- """
- True for platform-provided templates.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/flow_validation_error.py b/src/speechify/types/flow_validation_error.py
deleted file mode 100644
index ea98cef..0000000
--- a/src/speechify/types/flow_validation_error.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .error_detail import ErrorDetail
-import typing
-from .flow_validation_issue import FlowValidationIssue
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class FlowValidationError(UniversalBaseModel):
- """
- 400 body for flow save / publish / template operations. The standard
- `Error` envelope (so clients read `error.code` = `validation_failed`
- and `request_id`) plus the per-issue `issues` array the flow editor
- uses for node highlighting and the Validator-tab list. `issues` is
- absent on a plain bad request (e.g. an undecodable body, code
- `bad_request`).
- """
-
- error: ErrorDetail
- request_id: typing.Optional[str] = None
- issues: typing.Optional[typing.List[FlowValidationIssue]] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/flow_validation_issue.py b/src/speechify/types/flow_validation_issue.py
deleted file mode 100644
index f7d81e3..0000000
--- a/src/speechify/types/flow_validation_issue.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class FlowValidationIssue(UniversalBaseModel):
- """
- One flow-graph validation problem, located by node/edge/field path.
- """
-
- path: str = pydantic.Field()
- """
- Node / edge / field path the issue applies to; drives editor highlighting.
- """
-
- code: str = pydantic.Field()
- """
- Stable per-issue code, e.g. `tool_call.tool_id.invalid`.
- """
-
- message: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/flow_version.py b/src/speechify/types/flow_version.py
deleted file mode 100644
index a757c14..0000000
--- a/src/speechify/types/flow_version.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class FlowVersion(UniversalBaseModel):
- """
- One published or draft revision of an agent's flow graph.
- """
-
- id: str = pydantic.Field()
- """
- Flow version id. A raw UUID, not a prefixed external id.
- """
-
- agent_id: str
- version: int = pydantic.Field()
- """
- Monotonic revision number within the agent.
- """
-
- parent_version_id: typing.Optional[str] = None
- is_active: bool
- is_draft: bool
- name: typing.Optional[str] = None
- notes: typing.Optional[str] = None
- published_by: typing.Optional[str] = None
- published_at: typing.Optional[dt.datetime] = None
- updated_at: typing.Optional[dt.datetime] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/get_batch_call_response.py b/src/speechify/types/get_batch_call_response.py
deleted file mode 100644
index 53b2eeb..0000000
--- a/src/speechify/types/get_batch_call_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .batch_call import BatchCall
-import typing
-from .batch_recipient import BatchRecipient
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class GetBatchCallResponse(UniversalBaseModel):
- """
- Batch row plus all recipients for the detail view.
- """
-
- batch: BatchCall
- recipients: typing.List[BatchRecipient]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/get_caller_response.py b/src/speechify/types/get_caller_response.py
deleted file mode 100644
index 90d8374..0000000
--- a/src/speechify/types/get_caller_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .caller import Caller
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class GetCallerResponse(UniversalBaseModel):
- """
- Single-resource envelope used by GET / PATCH /v1/agents/callers/{id}.
- """
-
- caller: Caller
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/get_flow_response.py b/src/speechify/types/get_flow_response.py
deleted file mode 100644
index 173377e..0000000
--- a/src/speechify/types/get_flow_response.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .flow_graph import FlowGraph
-from .flow_version import FlowVersion
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class GetFlowResponse(UniversalBaseModel):
- """
- Response for GET /v1/agents/{id}/flow.
- """
-
- draft: typing.Optional[FlowGraph] = None
- active: typing.Optional[FlowGraph] = None
- history: typing.List[FlowVersion]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/get_flow_version_response.py b/src/speechify/types/get_flow_version_response.py
deleted file mode 100644
index 901a76c..0000000
--- a/src/speechify/types/get_flow_version_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .flow_graph import FlowGraph
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class GetFlowVersionResponse(UniversalBaseModel):
- graph: FlowGraph
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/import_job.py b/src/speechify/types/import_job.py
deleted file mode 100644
index 156919a..0000000
--- a/src/speechify/types/import_job.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .import_job_kind import ImportJobKind
-from .import_job_status import ImportJobStatus
-import typing
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ImportJob(UniversalBaseModel):
- """
- Async URL import job (sitemap, crawl, plus
- the auto-refresh path). The console polls
- `GET /v1/agents/knowledge-bases/{id}/imports` while the job is
- non-terminal.
- """
-
- id: str
- kb_id: str
- kind: ImportJobKind
- status: ImportJobStatus
- requested_count: int
- completed_count: int
- failed_count: int
- params: typing.Dict[str, typing.Optional[typing.Any]] = pydantic.Field()
- """
- JSON blob whose shape depends on `kind` — typically `url`,
- `max_pages`, `max_depth`. The console reads it for display
- only.
- """
-
- error: typing.Optional[str] = None
- upstream_job_id: typing.Optional[str] = None
- created_by_uid: str
- created_at: dt.datetime
- updated_at: dt.datetime
- started_at: typing.Optional[dt.datetime] = None
- finished_at: typing.Optional[dt.datetime] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/import_job_kind.py b/src/speechify/types/import_job_kind.py
deleted file mode 100644
index e6230b2..0000000
--- a/src/speechify/types/import_job_kind.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ImportJobKind = typing.Union[typing.Literal["sitemap", "crawl", "refresh", "urls"], typing.Any]
diff --git a/src/speechify/types/import_job_response.py b/src/speechify/types/import_job_response.py
deleted file mode 100644
index 1ce6085..0000000
--- a/src/speechify/types/import_job_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .import_job import ImportJob
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class ImportJobResponse(UniversalBaseModel):
- """
- Wrapper returned by the async import endpoints (sitemap, crawl, multi-URL).
- """
-
- job: ImportJob
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/import_job_status.py b/src/speechify/types/import_job_status.py
deleted file mode 100644
index 970a329..0000000
--- a/src/speechify/types/import_job_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ImportJobStatus = typing.Union[typing.Literal["pending", "running", "completed", "failed", "cancelled"], typing.Any]
diff --git a/src/speechify/types/invite.py b/src/speechify/types/invite.py
deleted file mode 100644
index cd19260..0000000
--- a/src/speechify/types/invite.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .member_role import MemberRole
-import datetime as dt
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Invite(UniversalBaseModel):
- """
- A pending or historical workspace invite.
- """
-
- id: str = pydantic.Field()
- """
- Opaque invite ID.
- """
-
- email: str = pydantic.Field()
- """
- Invitee email.
- """
-
- invited_by: str = pydantic.Field()
- """
- Firebase UID of the member who created the invite.
- """
-
- role: MemberRole = pydantic.Field()
- """
- Workspace role the invitee joins with when they accept.
- """
-
- created_at: dt.datetime
- expires_at: dt.datetime
- accepted_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- Populated once the invite has been accepted.
- """
-
- revoked_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
- """
- Populated once the invite has been revoked.
- """
-
- token: typing.Optional[str] = pydantic.Field(default=None)
- """
- Invite token. Returned ONLY on the create-invite response;
- subsequent list calls redact it. Use the token to build the
- `/join/{token}` join URL.
- """
-
- email_sent: bool = pydantic.Field()
- """
- True when the server delivered the invite email. The
- console uses this on the create-invite response to choose
- between an "email sent" confirmation and the copy-link
- fallback. Always present on the wire; on list responses
- it reflects the most recent send attempt.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/invite_preview.py b/src/speechify/types/invite_preview.py
deleted file mode 100644
index 431b627..0000000
--- a/src/speechify/types/invite_preview.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class InvitePreview(UniversalBaseModel):
- """
- Unauthenticated preview of a workspace invite. Surfaces only what
- the recipient needs to decide whether to accept (workspace name,
- invited address, inviter, expiry). Billing, plan, data region,
- and invite token are deliberately omitted.
- """
-
- tenant_id: str = pydantic.Field()
- """
- Opaque workspace id. Safe to echo back on the accept call.
- """
-
- tenant_name: str = pydantic.Field()
- """
- Workspace display name.
- """
-
- invited_email: str = pydantic.Field()
- """
- The email address the inviter typed when creating the invite.
- """
-
- invited_by_email: typing.Optional[str] = pydantic.Field(default=None)
- """
- Firebase email of the member who created the invite. May be
- absent if the Firebase profile lookup failed transiently —
- clients should still render the preview in that case.
- """
-
- invited_by_display_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Firebase display name of the member who created the invite.
- """
-
- expires_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/invites_list_response.py b/src/speechify/types/invites_list_response.py
deleted file mode 100644
index 3fc713b..0000000
--- a/src/speechify/types/invites_list_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .invite import Invite
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class InvitesListResponse(UniversalBaseModel):
- invites: typing.List[Invite]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/ivr_menu.py b/src/speechify/types/ivr_menu.py
deleted file mode 100644
index 9b9f90e..0000000
--- a/src/speechify/types/ivr_menu.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class IvrMenu(UniversalBaseModel):
- """
- One memorized IVR menu level. Identified by the
- SHA-256 fingerprint of the normalized greeting transcript;
- scoped to the caller's workspace (foreign-tenant menus are
- never returned).
-
- `menu_tree` is the validated JSONB blob the worker consumes:
- prompt text plus the options offered (label + DTMF). Sub-menus
- reached by pressing an option are their own rows, looked up at
- descent time by a fresh fingerprint - the tree structure is the
- implicit graph of fingerprint -> fingerprint transitions.
-
- `confidence_score` is `succeeded_traversals / total_traversals`.
- The worker's plan-then-execute fast path only activates at or
- above 0.5.
-
- `invalidated_at` is non-null on a soft-deleted row; the API
- filters these out of list / lookup / get responses so this field
- is informational only.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`menu_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- fingerprint_id: str
- tenant_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Null on the cross-tenant promoted slot.
- """
-
- schema_version: int
- menu_tree: typing.Dict[str, typing.Optional[typing.Any]] = pydantic.Field()
- """
- Validated menu_tree per contracts/agents/ivr_menu.schema.json. Opaque to consumers other than the worker.
- """
-
- confidence_score: float
- succeeded_traversals: int
- total_traversals: int
- last_validated_at: dt.datetime
- invalidated_at: typing.Optional[dt.datetime] = None
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/ivr_menu_list_entry.py b/src/speechify/types/ivr_menu_list_entry.py
deleted file mode 100644
index 6c7f17d..0000000
--- a/src/speechify/types/ivr_menu_list_entry.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class IvrMenuListEntry(UniversalBaseModel):
- """
- One row in the list-IVR-menus response. Carries the fingerprint
- hash + sample transcript so the console can render the IVR
- identity without a second round-trip. `last_observed_at` and
- `occurrence_count` are projected from `ivr_fingerprints` for
- the "when did we last see this IVR" signal.
- """
-
- menu_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`menu_<26 char Crockford base32>`).
- """
-
- fingerprint_id: str
- fingerprint_hash: str
- transcript_sample: str
- schema_version: int
- menu_tree: typing.Dict[str, typing.Optional[typing.Any]]
- confidence_score: float
- succeeded_traversals: int
- total_traversals: int
- last_validated_at: dt.datetime
- last_observed_at: dt.datetime
- occurrence_count: int
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base.py b/src/speechify/types/knowledge_base.py
deleted file mode 100644
index 94aaed3..0000000
--- a/src/speechify/types/knowledge_base.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class KnowledgeBase(UniversalBaseModel):
- """
- A bundle of documents that can be attached to one or more voice
- agents. Chunks across every document in the knowledge base are
- embedded and searched together.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`kb_<26 char Crockford base32>`).
- """
-
- name: str = pydantic.Field()
- """
- Human-readable label, shown in the console.
- """
-
- description: str = pydantic.Field()
- """
- Optional description.
- """
-
- document_count: int = pydantic.Field()
- """
- Number of ingested documents.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base_chunk.py b/src/speechify/types/knowledge_base_chunk.py
deleted file mode 100644
index 235bd89..0000000
--- a/src/speechify/types/knowledge_base_chunk.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class KnowledgeBaseChunk(UniversalBaseModel):
- id: str
- document_id: str
- kb_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`kb_<26 char Crockford base32>`) of
- the knowledge base the chunk belongs to.
- """
-
- chunk_index: int
- content: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base_document.py b/src/speechify/types/knowledge_base_document.py
deleted file mode 100644
index 4a61125..0000000
--- a/src/speechify/types/knowledge_base_document.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .knowledge_base_document_source_kind import KnowledgeBaseDocumentSourceKind
-import typing
-from .knowledge_base_document_status import KnowledgeBaseDocumentStatus
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class KnowledgeBaseDocument(UniversalBaseModel):
- id: str
- kb_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`kb_<26 char Crockford base32>`) of
- the knowledge base the document belongs to.
- """
-
- source_kind: KnowledgeBaseDocumentSourceKind
- source_url: typing.Optional[str] = pydantic.Field(default=None)
- """
- Source URL for url-sourced documents (and the sitemap /
- crawl imports that produce them). Empty string for file
- and text rows.
- """
-
- folder_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- Folder this document lives in. Null for root-level
- (unfiled) documents. Mutated via the move endpoint.
- """
-
- filename: str
- content_type: str
- byte_size: int
- char_count: int
- chunk_count: int
- status: KnowledgeBaseDocumentStatus
- error: typing.Optional[str] = pydantic.Field(default=None)
- """
- Populated when status is failed.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base_document_detail.py b/src/speechify/types/knowledge_base_document_detail.py
deleted file mode 100644
index 418d7d9..0000000
--- a/src/speechify/types/knowledge_base_document_detail.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .knowledge_base_document import KnowledgeBaseDocument
-import typing
-from .dependent_agent import DependentAgent
-from .refresh_config import RefreshConfig
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class KnowledgeBaseDocumentDetail(KnowledgeBaseDocument):
- """
- Payload of GET /v1/knowledge-bases/documents/{docId}. Extends
- the list-view document with a bounded content preview, the
- list of dependent agents, and (for url-sourced docs) the
- auto-refresh state.
- """
-
- content_preview: str
- preview_truncated: bool
- dependent_agents: typing.List[DependentAgent]
- refresh: typing.Optional[RefreshConfig] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base_document_source_kind.py b/src/speechify/types/knowledge_base_document_source_kind.py
deleted file mode 100644
index ca12d85..0000000
--- a/src/speechify/types/knowledge_base_document_source_kind.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-KnowledgeBaseDocumentSourceKind = typing.Union[typing.Literal["file", "url", "text"], typing.Any]
diff --git a/src/speechify/types/knowledge_base_document_status.py b/src/speechify/types/knowledge_base_document_status.py
deleted file mode 100644
index 7d843d5..0000000
--- a/src/speechify/types/knowledge_base_document_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-KnowledgeBaseDocumentStatus = typing.Union[typing.Literal["fetching", "embedding", "ready", "failed"], typing.Any]
diff --git a/src/speechify/types/knowledge_base_folder.py b/src/speechify/types/knowledge_base_folder.py
deleted file mode 100644
index e9f64c2..0000000
--- a/src/speechify/types/knowledge_base_folder.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class KnowledgeBaseFolder(UniversalBaseModel):
- """
- Folder inside a knowledge base. Root-level folders have
- `parent_folder_id: null`. `document_count` is populated only
- on the list endpoint.
- """
-
- id: str
- kb_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`kb_<26 char Crockford base32>`) of
- the owning knowledge base.
- """
-
- parent_folder_id: typing.Optional[str] = None
- name: str
- document_count: int
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/knowledge_base_search_hit.py b/src/speechify/types/knowledge_base_search_hit.py
deleted file mode 100644
index e1f0f49..0000000
--- a/src/speechify/types/knowledge_base_search_hit.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class KnowledgeBaseSearchHit(UniversalBaseModel):
- chunk_id: str
- document_id: str
- kb_id: str
- filename: str
- chunk_index: int
- content: str
- score: float = pydantic.Field()
- """
- Cosine similarity (higher = more relevant).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agent_builtins_response.py b/src/speechify/types/list_agent_builtins_response.py
deleted file mode 100644
index fe5fb1c..0000000
--- a/src/speechify/types/list_agent_builtins_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_builtin import AgentBuiltin
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentBuiltinsResponse(UniversalBaseModel):
- builtins: typing.List[AgentBuiltin]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agent_test_attachments_response.py b/src/speechify/types/list_agent_test_attachments_response.py
deleted file mode 100644
index b16a64f..0000000
--- a/src/speechify/types/list_agent_test_attachments_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_test_attachment import AgentTestAttachment
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentTestAttachmentsResponse(UniversalBaseModel):
- attachments: typing.List[AgentTestAttachment]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agent_test_folders_response.py b/src/speechify/types/list_agent_test_folders_response.py
deleted file mode 100644
index 4e4f906..0000000
--- a/src/speechify/types/list_agent_test_folders_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_test_folder import AgentTestFolder
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentTestFoldersResponse(UniversalBaseModel):
- folders: typing.List[AgentTestFolder]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agent_test_runs_response.py b/src/speechify/types/list_agent_test_runs_response.py
deleted file mode 100644
index d56686c..0000000
--- a/src/speechify/types/list_agent_test_runs_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .agent_test_run import AgentTestRun
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentTestRunsResponse(PaginationMeta):
- runs: typing.List[AgentTestRun]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agent_tests_response.py b/src/speechify/types/list_agent_tests_response.py
deleted file mode 100644
index 4cec350..0000000
--- a/src/speechify/types/list_agent_tests_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_test_with_last_run import AgentTestWithLastRun
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentTestsResponse(UniversalBaseModel):
- tests: typing.List[AgentTestWithLastRun]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_agents_response.py b/src/speechify/types/list_agents_response.py
deleted file mode 100644
index 97f781c..0000000
--- a/src/speechify/types/list_agents_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent import Agent
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAgentsResponse(UniversalBaseModel):
- agents: typing.List[Agent]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_audio_assets_response.py b/src/speechify/types/list_audio_assets_response.py
deleted file mode 100644
index 59ed0e1..0000000
--- a/src/speechify/types/list_audio_assets_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .audio_asset import AudioAsset
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListAudioAssetsResponse(UniversalBaseModel):
- assets: typing.List[AudioAsset]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_batch_calls_response.py b/src/speechify/types/list_batch_calls_response.py
deleted file mode 100644
index b12b6d9..0000000
--- a/src/speechify/types/list_batch_calls_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .batch_call import BatchCall
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListBatchCallsResponse(PaginationMeta):
- batches: typing.List[BatchCall]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_caller_conversations_response.py b/src/speechify/types/list_caller_conversations_response.py
deleted file mode 100644
index faa1f1c..0000000
--- a/src/speechify/types/list_caller_conversations_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .conversation import Conversation
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListCallerConversationsResponse(PaginationMeta):
- """
- Payload for GET /v1/agents/callers/{id}/conversations.
- """
-
- conversations: typing.List[Conversation]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_caller_memories_response.py b/src/speechify/types/list_caller_memories_response.py
deleted file mode 100644
index 52a7b30..0000000
--- a/src/speechify/types/list_caller_memories_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .caller_memory_item import CallerMemoryItem
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListCallerMemoriesResponse(PaginationMeta):
- """
- Payload for GET /v1/agents/callers/{id}/memories.
- """
-
- memories: typing.List[CallerMemoryItem]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_callers_response.py b/src/speechify/types/list_callers_response.py
deleted file mode 100644
index ee47a9c..0000000
--- a/src/speechify/types/list_callers_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .caller import Caller
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListCallersResponse(PaginationMeta):
- """
- Payload for GET /v1/agents/callers.
- """
-
- callers: typing.List[Caller]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_conversations_response.py b/src/speechify/types/list_conversations_response.py
deleted file mode 100644
index fac47a3..0000000
--- a/src/speechify/types/list_conversations_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .conversation import Conversation
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListConversationsResponse(PaginationMeta):
- conversations: typing.List[Conversation]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_credentials_response.py b/src/speechify/types/list_credentials_response.py
deleted file mode 100644
index e066f8d..0000000
--- a/src/speechify/types/list_credentials_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .credential import Credential
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListCredentialsResponse(UniversalBaseModel):
- credentials: typing.List[Credential]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_dynamic_variables_response.py b/src/speechify/types/list_dynamic_variables_response.py
deleted file mode 100644
index 27af7dc..0000000
--- a/src/speechify/types/list_dynamic_variables_response.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .dynamic_variable import DynamicVariable
-import pydantic
-from .system_variable_doc import SystemVariableDoc
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ListDynamicVariablesResponse(UniversalBaseModel):
- """
- Response for `GET /v1/agents/{id}/variables`. Returns both the
- customer-scope variable catalogue and the read-only `system__*`
- catalogue so the editor UI has a single source of truth.
- """
-
- variables: typing.List[DynamicVariable] = pydantic.Field()
- """
- Customer-defined variables for this agent.
- """
-
- system_variables: typing.List[SystemVariableDoc] = pydantic.Field()
- """
- Platform-populated `system__*` variables, provided for
- reference. This list is the same for every agent.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_evaluations_response.py b/src/speechify/types/list_evaluations_response.py
deleted file mode 100644
index fd0bcdc..0000000
--- a/src/speechify/types/list_evaluations_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .evaluation import Evaluation
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListEvaluationsResponse(UniversalBaseModel):
- evaluations: typing.List[Evaluation]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_flow_templates_response.py b/src/speechify/types/list_flow_templates_response.py
deleted file mode 100644
index d09e1cf..0000000
--- a/src/speechify/types/list_flow_templates_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .flow_template import FlowTemplate
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListFlowTemplatesResponse(UniversalBaseModel):
- templates: typing.List[FlowTemplate]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_flow_versions_response.py b/src/speechify/types/list_flow_versions_response.py
deleted file mode 100644
index 3c26923..0000000
--- a/src/speechify/types/list_flow_versions_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .flow_version import FlowVersion
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListFlowVersionsResponse(UniversalBaseModel):
- versions: typing.List[FlowVersion]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_import_jobs_response.py b/src/speechify/types/list_import_jobs_response.py
deleted file mode 100644
index 1da701b..0000000
--- a/src/speechify/types/list_import_jobs_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .import_job import ImportJob
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListImportJobsResponse(UniversalBaseModel):
- jobs: typing.List[ImportJob]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_ivr_menus_response.py b/src/speechify/types/list_ivr_menus_response.py
deleted file mode 100644
index e834745..0000000
--- a/src/speechify/types/list_ivr_menus_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .ivr_menu_list_entry import IvrMenuListEntry
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListIvrMenusResponse(UniversalBaseModel):
- menus: typing.List[IvrMenuListEntry]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_knowledge_base_chunks_response.py b/src/speechify/types/list_knowledge_base_chunks_response.py
deleted file mode 100644
index e7fba46..0000000
--- a/src/speechify/types/list_knowledge_base_chunks_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .knowledge_base_chunk import KnowledgeBaseChunk
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListKnowledgeBaseChunksResponse(PaginationMeta):
- chunks: typing.List[KnowledgeBaseChunk]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_knowledge_base_documents_response.py b/src/speechify/types/list_knowledge_base_documents_response.py
deleted file mode 100644
index 41529ff..0000000
--- a/src/speechify/types/list_knowledge_base_documents_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .knowledge_base_document import KnowledgeBaseDocument
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListKnowledgeBaseDocumentsResponse(PaginationMeta):
- documents: typing.List[KnowledgeBaseDocument]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_knowledge_base_folders_response.py b/src/speechify/types/list_knowledge_base_folders_response.py
deleted file mode 100644
index 7ffdb28..0000000
--- a/src/speechify/types/list_knowledge_base_folders_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .knowledge_base_folder import KnowledgeBaseFolder
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListKnowledgeBaseFoldersResponse(PaginationMeta):
- """
- Flat list of folders for a knowledge base. The console builds
- the folder tree from `parent_folder_id` references, so callers
- should walk every page before rendering.
- """
-
- folders: typing.List[KnowledgeBaseFolder]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_knowledge_bases_response.py b/src/speechify/types/list_knowledge_bases_response.py
deleted file mode 100644
index 9d02cd7..0000000
--- a/src/speechify/types/list_knowledge_bases_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .knowledge_base import KnowledgeBase
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListKnowledgeBasesResponse(PaginationMeta):
- knowledge_bases: typing.List[KnowledgeBase]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_memories_response.py b/src/speechify/types/list_memories_response.py
deleted file mode 100644
index 2b4a689..0000000
--- a/src/speechify/types/list_memories_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .memory import Memory
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListMemoriesResponse(UniversalBaseModel):
- memories: typing.List[Memory]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_messages_response.py b/src/speechify/types/list_messages_response.py
deleted file mode 100644
index 1b424b3..0000000
--- a/src/speechify/types/list_messages_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .message import Message
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListMessagesResponse(PaginationMeta):
- messages: typing.List[Message]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_phone_numbers_response.py b/src/speechify/types/list_phone_numbers_response.py
deleted file mode 100644
index 375c57c..0000000
--- a/src/speechify/types/list_phone_numbers_response.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .phone_number import PhoneNumber
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ListPhoneNumbersResponse(UniversalBaseModel):
- """
- Response for `GET /v1/agents/phone-numbers`.
- """
-
- numbers: typing.List[PhoneNumber] = pydantic.Field()
- """
- Phone numbers in the workspace (up to 100).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_recent_callees_response.py b/src/speechify/types/list_recent_callees_response.py
deleted file mode 100644
index b2a4240..0000000
--- a/src/speechify/types/list_recent_callees_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .recent_callee import RecentCallee
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListRecentCalleesResponse(PaginationMeta):
- """
- Payload for GET /v1/agents/conversations/recent-callees.
- """
-
- callees: typing.List[RecentCallee]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_refresh_history_response.py b/src/speechify/types/list_refresh_history_response.py
deleted file mode 100644
index 00eb50c..0000000
--- a/src/speechify/types/list_refresh_history_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .refresh_history_entry import RefreshHistoryEntry
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListRefreshHistoryResponse(UniversalBaseModel):
- entries: typing.List[RefreshHistoryEntry]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_retrieval_logs_response.py b/src/speechify/types/list_retrieval_logs_response.py
deleted file mode 100644
index 90e3465..0000000
--- a/src/speechify/types/list_retrieval_logs_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .retrieval_log_entry import RetrievalLogEntry
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListRetrievalLogsResponse(PaginationMeta):
- """
- Payload for `GET /v1/agents/conversations/{id}/retrieval-log`.
- """
-
- entries: typing.List[RetrievalLogEntry]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_sip_trunks_response.py b/src/speechify/types/list_sip_trunks_response.py
deleted file mode 100644
index 0be1c32..0000000
--- a/src/speechify/types/list_sip_trunks_response.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .sip_trunk import SipTrunk
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ListSipTrunksResponse(UniversalBaseModel):
- """
- Response for `GET /v1/agents/sip-trunks`.
- """
-
- trunks: typing.List[SipTrunk] = pydantic.Field()
- """
- SIP trunks in the workspace (up to 20).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_suite_runs_response.py b/src/speechify/types/list_suite_runs_response.py
deleted file mode 100644
index 0513e0c..0000000
--- a/src/speechify/types/list_suite_runs_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .agent_test_suite_run import AgentTestSuiteRun
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListSuiteRunsResponse(PaginationMeta):
- """
- One page of suite runs, newest first. Walk pages while
- `has_more` is true; pass `next_cursor` back as the request
- `cursor` parameter.
- """
-
- suite_runs: typing.List[AgentTestSuiteRun]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_system_builtins_response.py b/src/speechify/types/list_system_builtins_response.py
deleted file mode 100644
index f2ecc2c..0000000
--- a/src/speechify/types/list_system_builtins_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .system_builtin_info import SystemBuiltinInfo
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListSystemBuiltinsResponse(UniversalBaseModel):
- builtins: typing.List[SystemBuiltinInfo]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_tests_response.py b/src/speechify/types/list_tests_response.py
deleted file mode 100644
index a8d3842..0000000
--- a/src/speechify/types/list_tests_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .agent_test_with_last_run import AgentTestWithLastRun
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListTestsResponse(PaginationMeta):
- """
- Workspace-wide paginated list of tests. Walk pages while
- `has_more` is true; pass `next_cursor` back as the request
- `cursor` parameter.
- """
-
- tests: typing.List[AgentTestWithLastRun]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_tool_attached_agents_response.py b/src/speechify/types/list_tool_attached_agents_response.py
deleted file mode 100644
index 1e2e633..0000000
--- a/src/speechify/types/list_tool_attached_agents_response.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .tool_attached_agent import ToolAttachedAgent
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListToolAttachedAgentsResponse(UniversalBaseModel):
- """
- Response shape for GET /v1/agents/tools/{id}/attached-agents.
- Agents are tenant-scoped and ordered by name ASC.
- """
-
- agents: typing.List[ToolAttachedAgent]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_tools_response.py b/src/speechify/types/list_tools_response.py
deleted file mode 100644
index 6231b64..0000000
--- a/src/speechify/types/list_tools_response.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .tool import Tool
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListToolsResponse(PaginationMeta):
- """
- Payload for `GET /v1/agents/tools` — the workspace-level tool
- catalog. Cursor-paginated; the per-agent attached-tools endpoint
- uses a different (bare) shape — see AttachedToolsResponse.
- """
-
- tools: typing.List[Tool]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/list_webhook_deliveries_response.py b/src/speechify/types/list_webhook_deliveries_response.py
deleted file mode 100644
index 6b52a98..0000000
--- a/src/speechify/types/list_webhook_deliveries_response.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .pagination_meta import PaginationMeta
-import typing
-from .webhook_delivery import WebhookDelivery
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ListWebhookDeliveriesResponse(PaginationMeta):
- """
- Payload for `GET /v1/agents/conversations/{id}/webhook-deliveries`.
- """
-
- deliveries: typing.List[WebhookDelivery]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/llm_provider.py b/src/speechify/types/llm_provider.py
deleted file mode 100644
index 69136a9..0000000
--- a/src/speechify/types/llm_provider.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-LlmProvider = typing.Union[typing.Literal["openai", "speechify"], typing.Any]
diff --git a/src/speechify/types/mcp_auth.py b/src/speechify/types/mcp_auth.py
deleted file mode 100644
index b59e531..0000000
--- a/src/speechify/types/mcp_auth.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from __future__ import annotations
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class McpAuth_None(UniversalBaseModel):
- """
- Discriminated union over `type`.
- """
-
- type: typing.Literal["none"] = "none"
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
-
-
-class McpAuth_Bearer(UniversalBaseModel):
- """
- Discriminated union over `type`.
- """
-
- type: typing.Literal["bearer"] = "bearer"
- token: typing.Optional[str] = None
- token_set: typing.Optional[bool] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
-
-
-class McpAuth_Oauth2ClientCredentials(UniversalBaseModel):
- """
- Discriminated union over `type`.
- """
-
- type: typing.Literal["oauth2_client_credentials"] = "oauth2_client_credentials"
- token_url: str
- client_id: str
- client_secret: typing.Optional[str] = None
- client_secret_set: typing.Optional[bool] = None
- scope: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
-
-
-McpAuth = typing.Union[McpAuth_None, McpAuth_Bearer, McpAuth_Oauth2ClientCredentials]
diff --git a/src/speechify/types/mcp_auth_bearer.py b/src/speechify/types/mcp_auth_bearer.py
deleted file mode 100644
index 00951f6..0000000
--- a/src/speechify/types/mcp_auth_bearer.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class McpAuthBearer(UniversalBaseModel):
- token: typing.Optional[str] = pydantic.Field(default=None)
- """
- Bearer token. Write-only — never echoed back on reads.
- """
-
- token_set: typing.Optional[bool] = pydantic.Field(default=None)
- """
- True when a bearer token is configured. Read-only.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_auth_none.py b/src/speechify/types/mcp_auth_none.py
deleted file mode 100644
index bb2ef1d..0000000
--- a/src/speechify/types/mcp_auth_none.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class McpAuthNone(UniversalBaseModel):
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_auth_o_auth2.py b/src/speechify/types/mcp_auth_o_auth2.py
deleted file mode 100644
index 1ba8653..0000000
--- a/src/speechify/types/mcp_auth_o_auth2.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class McpAuthOAuth2(UniversalBaseModel):
- token_url: str
- client_id: str
- client_secret: typing.Optional[str] = pydantic.Field(default=None)
- """
- OAuth2 client_secret. Write-only — never echoed back on reads.
- """
-
- client_secret_set: typing.Optional[bool] = pydantic.Field(default=None)
- """
- True when a client_secret is configured. Read-only.
- """
-
- scope: typing.Optional[str] = pydantic.Field(default=None)
- """
- Optional scope claim sent on the token request.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_auth_type.py b/src/speechify/types/mcp_auth_type.py
deleted file mode 100644
index 02572a9..0000000
--- a/src/speechify/types/mcp_auth_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-McpAuthType = typing.Union[typing.Literal["none", "bearer", "oauth2_client_credentials"], typing.Any]
diff --git a/src/speechify/types/mcp_probe_error_details.py b/src/speechify/types/mcp_probe_error_details.py
deleted file mode 100644
index 57cbd10..0000000
--- a/src/speechify/types/mcp_probe_error_details.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .mcp_probe_error_details_stage import McpProbeErrorDetailsStage
-import typing_extensions
-from ..core.serialization import FieldMetadata
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class McpProbeErrorDetails(UniversalBaseModel):
- """
- Structured upstream signal for an MCP probe failure. All fields
- are optional; the console renders what's present. `stage` names
- the phase the probe was in (`validation`, `oauth2_token`,
- `mcp_connect`, `mcp_initialize`, `mcp_notify`, `mcp_list_tools`).
- `oauth2_error` / `oauth2_error_description` mirror RFC 6749 §5.2
- when the customer's auth server returned the standard error
- shape. `http_status` is the upstream status code for transport
- failures. `upstream_body` is a truncated prefix (max ~1 KiB) of
- the upstream response body when the failure isn't structured.
- `field_hint` names a form field (`endpoint`, `transport`,
- `token`, `token_url`, `client_id`, `client_secret`, `scope`)
- the console should highlight so the customer knows what to fix.
- """
-
- stage: typing.Optional[McpProbeErrorDetailsStage] = None
- http_status: typing.Optional[int] = None
- oauth2error: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="oauth2_error")] = None
- oauth2error_description: typing_extensions.Annotated[
- typing.Optional[str], FieldMetadata(alias="oauth2_error_description")
- ] = None
- upstream_body: typing.Optional[str] = None
- field_hint: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_probe_error_details_stage.py b/src/speechify/types/mcp_probe_error_details_stage.py
deleted file mode 100644
index 4922392..0000000
--- a/src/speechify/types/mcp_probe_error_details_stage.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-McpProbeErrorDetailsStage = typing.Union[
- typing.Literal["validation", "oauth2_token", "mcp_connect", "mcp_initialize", "mcp_notify", "mcp_list_tools"],
- typing.Any,
-]
diff --git a/src/speechify/types/mcp_probe_result.py b/src/speechify/types/mcp_probe_result.py
deleted file mode 100644
index 0327440..0000000
--- a/src/speechify/types/mcp_probe_result.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .mcp_probe_tool import McpProbeTool
-from .mcp_probe_error_details import McpProbeErrorDetails
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class McpProbeResult(UniversalBaseModel):
- """
- Result of an MCP probe. On success, `tools` is the discovered
- catalogue and `error` is absent. On failure, `tools` is `null`
- and `error` carries a human-readable reason the console renders
- inline next to the form. `details` is optional structured
- signal from the upstream (OAuth2 RFC 6749 fields, HTTP status,
- truncated upstream body, form field hint) the console uses to
- expand the inline banner and highlight the offending input.
- Older consoles ignore `details` and fall back to `error`. Both
- validation and network failures land in `error` rather than
- non-2xx responses, so consumers must check `error` before
- reading `tools`.
- """
-
- tools: typing.Optional[typing.List[McpProbeTool]] = None
- error: typing.Optional[str] = None
- details: typing.Optional[McpProbeErrorDetails] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_probe_tool.py b/src/speechify/types/mcp_probe_tool.py
deleted file mode 100644
index 38e176b..0000000
--- a/src/speechify/types/mcp_probe_tool.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class McpProbeTool(UniversalBaseModel):
- """
- One discovered tool in a probe result.
- """
-
- name: str
- description: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_tool_config.py b/src/speechify/types/mcp_tool_config.py
deleted file mode 100644
index 7eb4c0c..0000000
--- a/src/speechify/types/mcp_tool_config.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .mcp_transport import McpTransport
-from .mcp_auth import McpAuth
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class McpToolConfig(UniversalBaseModel):
- """
- Config shape for `kind=mcp`. The worker opens the
- configured transport at session start, runs `initialize` +
- `list_tools`, and registers each discovered remote tool as a
- livekit-agents function_tool proxying through the long-lived
- ClientSession.
- """
-
- endpoint: str
- transport: typing.Optional[McpTransport] = None
- auth: McpAuth
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/mcp_transport.py b/src/speechify/types/mcp_transport.py
deleted file mode 100644
index 9759bb2..0000000
--- a/src/speechify/types/mcp_transport.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-McpTransport = typing.Union[typing.Literal["http_streamable", "sse"], typing.Any]
diff --git a/src/speechify/types/member.py b/src/speechify/types/member.py
deleted file mode 100644
index 35a8c06..0000000
--- a/src/speechify/types/member.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .member_role import MemberRole
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Member(UniversalBaseModel):
- """
- A member of a workspace (joined from `tenant_users` + Firebase profile).
- """
-
- user_uid: str = pydantic.Field()
- """
- Firebase user ID.
- """
-
- email: typing.Optional[str] = pydantic.Field(default=None)
- """
- Member's email from Firebase. Empty when the account has been deleted.
- """
-
- display_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Member's display name from Firebase.
- """
-
- role: MemberRole
- created_at: dt.datetime = pydantic.Field()
- """
- When the user joined the workspace.
- """
-
- is_self: bool = pydantic.Field()
- """
- True when this row is the authenticated caller.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/member_role.py b/src/speechify/types/member_role.py
deleted file mode 100644
index 13def0f..0000000
--- a/src/speechify/types/member_role.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-MemberRole = typing.Union[typing.Literal["owner", "admin", "member"], typing.Any]
diff --git a/src/speechify/types/members_list_response.py b/src/speechify/types/members_list_response.py
deleted file mode 100644
index 4d70fd4..0000000
--- a/src/speechify/types/members_list_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .member import Member
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class MembersListResponse(UniversalBaseModel):
- members: typing.List[Member]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/memory.py b/src/speechify/types/memory.py
deleted file mode 100644
index ef4da9a..0000000
--- a/src/speechify/types/memory.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Memory(UniversalBaseModel):
- """
- One salient fact extracted post-call about a specific caller on
- a specific agent. Retrieved at the next conversation-start for
- the same caller and injected into the agent's system prompt via
- the `{{memory}}` template variable.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`memory_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the owning agent.
- """
-
- caller_identity: str = pydantic.Field()
- """
- Stable caller key (LiveKit participant identity) the memory is scoped to.
- """
-
- fact: str = pydantic.Field()
- """
- Short third-person statement about the caller.
- """
-
- source_conversation_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- When set, the prefixed wire identifier
- (`conv_<26 char Crockford base32>`) of the conversation this
- memory was extracted from. May be null if the source was
- deleted.
- """
-
- confidence: float = pydantic.Field()
- """
- LLM self-reported 0-1 confidence in the fact's durability and relevance.
- """
-
- score: typing.Optional[float] = pydantic.Field(default=None)
- """
- Populated only on retrieval hits — recency-weighted cosine similarity.
- """
-
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/message.py b/src/speechify/types/message.py
deleted file mode 100644
index e770540..0000000
--- a/src/speechify/types/message.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .message_role import MessageRole
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Message(UniversalBaseModel):
- id: str
- conversation_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`conv_<26 char Crockford base32>`)
- of the parent conversation.
- """
-
- role: MessageRole
- content: str
- tool_name: typing.Optional[str] = None
- tool_args: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = None
- tool_result: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
- """
- Arbitrary JSON value returned by the tool (object, array, string, or primitive).
- """
-
- started_at: dt.datetime
- ended_at: typing.Optional[dt.datetime] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/message_role.py b/src/speechify/types/message_role.py
deleted file mode 100644
index decda98..0000000
--- a/src/speechify/types/message_role.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-MessageRole = typing.Union[typing.Literal["user", "assistant", "system", "tool"], typing.Any]
diff --git a/src/speechify/types/mocking_strategy.py b/src/speechify/types/mocking_strategy.py
deleted file mode 100644
index 344c9be..0000000
--- a/src/speechify/types/mocking_strategy.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-MockingStrategy = typing.Union[typing.Literal["none", "all", "selected"], typing.Any]
diff --git a/src/speechify/types/no_match_behavior.py b/src/speechify/types/no_match_behavior.py
deleted file mode 100644
index 29c5374..0000000
--- a/src/speechify/types/no_match_behavior.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-NoMatchBehavior = typing.Union[typing.Literal["call_real_tool", "finish_with_error", "skip"], typing.Any]
diff --git a/src/speechify/types/o_auth2client_credentials_config.py b/src/speechify/types/o_auth2client_credentials_config.py
deleted file mode 100644
index 1591f99..0000000
--- a/src/speechify/types/o_auth2client_credentials_config.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class OAuth2ClientCredentialsConfig(UniversalBaseModel):
- """
- Static client_id + client_secret pair for the OAuth2
- client-credentials flow. The tool runtime mints an access token
- at request time and caches it per credential id.
- """
-
- token_url: str
- client_id: str
- client_secret: str
- scopes: typing.Optional[typing.List[str]] = None
- audience: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/o_auth2jwt_config.py b/src/speechify/types/o_auth2jwt_config.py
deleted file mode 100644
index fe1fc66..0000000
--- a/src/speechify/types/o_auth2jwt_config.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class OAuth2JwtConfig(UniversalBaseModel):
- """
- Issuer, audience, and signing key for the JWT-bearer flow
- (RFC 7523) — e.g. Google service accounts that exchange a
- signed JWT for an access token.
- """
-
- token_url: str
- issuer: str
- subject: typing.Optional[str] = None
- audience: str
- scopes: typing.Optional[typing.List[str]] = None
- private_key: str
- key_id: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/o_auth_error.py b/src/speechify/types/o_auth_error.py
deleted file mode 100644
index f3e3ef5..0000000
--- a/src/speechify/types/o_auth_error.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .o_auth_error_error import OAuthErrorError
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class OAuthError(UniversalBaseModel):
- error: typing.Optional[OAuthErrorError] = None
- error_description: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/o_auth_error_error.py b/src/speechify/types/o_auth_error_error.py
deleted file mode 100644
index 3dcbfaf..0000000
--- a/src/speechify/types/o_auth_error_error.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-OAuthErrorError = typing.Union[
- typing.Literal[
- "invalid_client", "unauthorized_client", "invalid_request", "unsupported_grant_type", "invalid_scope"
- ],
- typing.Any,
-]
diff --git a/src/speechify/types/pagination_meta.py b/src/speechify/types/pagination_meta.py
deleted file mode 100644
index 431833d..0000000
--- a/src/speechify/types/pagination_meta.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class PaginationMeta(UniversalBaseModel):
- """
- Shared pagination metadata composed into every cursor-paginated
- list response via `allOf`. Ships `has_more` alongside `next_cursor`
- as two equivalent end-of-pages signals (defense-in-depth).
- """
-
- next_cursor: typing.Optional[str] = pydantic.Field(default=None)
- """
- Opaque keyset cursor for the next page. Pass back as the
- `cursor` request parameter. `null` when the caller has
- reached the end of the list (`has_more` is also `false`
- in that case).
- """
-
- has_more: bool = pydantic.Field()
- """
- True when more rows exist beyond this page.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/parameter_check.py b/src/speechify/types/parameter_check.py
deleted file mode 100644
index afb3a0e..0000000
--- a/src/speechify/types/parameter_check.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .parameter_check_mode import ParameterCheckMode
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ParameterCheck(UniversalBaseModel):
- """
- Validates one argument of an expected tool call. `path` is a
- dotted JSON path (e.g. `customer.email`); use zero-indexed
- notation for arrays (`items.0.sku`). An empty path checks the
- whole args object.
- """
-
- path: str = pydantic.Field()
- """
- Dotted JSON path to the argument being checked. Empty means the whole args object.
- """
-
- mode: ParameterCheckMode
- expected: typing.Optional[str] = pydantic.Field(default=None)
- """
- Expected value string for `exact` and `regex` modes.
- """
-
- criteria: typing.Optional[str] = pydantic.Field(default=None)
- """
- Natural-language criteria for `llm` mode (e.g. "is a valid email address").
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/parameter_check_mode.py b/src/speechify/types/parameter_check_mode.py
deleted file mode 100644
index 27c6567..0000000
--- a/src/speechify/types/parameter_check_mode.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ParameterCheckMode = typing.Union[typing.Literal["exact", "regex", "llm"], typing.Any]
diff --git a/src/speechify/types/parameter_check_result.py b/src/speechify/types/parameter_check_result.py
deleted file mode 100644
index f23cd89..0000000
--- a/src/speechify/types/parameter_check_result.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .parameter_check_mode import ParameterCheckMode
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ParameterCheckResult(UniversalBaseModel):
- """
- Result of one `ParameterCheck` within a tool-call test run.
- """
-
- path: str
- mode: ParameterCheckMode
- actual_json: str = pydantic.Field()
- """
- JSON-serialised actual value at `path`.
- """
-
- passed: bool
- rationale: typing.Optional[str] = pydantic.Field(default=None)
- """
- LLM rationale (populated for `llm` mode checks).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/phone_number.py b/src/speechify/types/phone_number.py
deleted file mode 100644
index 3921cb1..0000000
--- a/src/speechify/types/phone_number.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .phone_number_source import PhoneNumberSource
-import typing
-from .phone_number_capability import PhoneNumberCapability
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class PhoneNumber(UniversalBaseModel):
- """
- A phone number in the workspace inventory. Bound to an agent via
- `agent_id`; unbound numbers are valid but non-functional until
- assigned.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`phone_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- e164: str = pydantic.Field()
- """
- The phone number in E.164 format (e.g. `+12025551234`).
- """
-
- source: PhoneNumberSource
- label: typing.Optional[str] = pydantic.Field(default=None)
- """
- Optional human-readable label set by the customer.
- """
-
- trunk_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- ID of the SIP trunk backing this number, if applicable.
- """
-
- agent_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- ID of the agent that answers calls to this number. Null when unbound.
- """
-
- capabilities: typing.List[PhoneNumberCapability] = pydantic.Field()
- """
- What this number can do.
- """
-
- livekit_phone_number_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- LiveKit's own phone number ID (populated for `source=livekit` only).
- """
-
- created_at: dt.datetime = pydantic.Field()
- """
- When the number was imported.
- """
-
- updated_at: dt.datetime = pydantic.Field()
- """
- When the number was last modified.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/phone_number_capability.py b/src/speechify/types/phone_number_capability.py
deleted file mode 100644
index ab368a9..0000000
--- a/src/speechify/types/phone_number_capability.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-PhoneNumberCapability = typing.Union[typing.Literal["inbound", "outbound"], typing.Any]
diff --git a/src/speechify/types/phone_number_source.py b/src/speechify/types/phone_number_source.py
deleted file mode 100644
index 870a8ff..0000000
--- a/src/speechify/types/phone_number_source.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-PhoneNumberSource = typing.Union[
- typing.Literal["livekit", "twilio", "byoc", "twilio_purchased", "verified_caller_id"], typing.Any
-]
diff --git a/src/speechify/types/recent_callee.py b/src/speechify/types/recent_callee.py
deleted file mode 100644
index 9986498..0000000
--- a/src/speechify/types/recent_callee.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class RecentCallee(UniversalBaseModel):
- """
- One distinct phone number this workspace has dialled, with the timestamp of the most recent outbound call to it.
- """
-
- phone: str = pydantic.Field()
- """
- E.164 phone number that was dialled.
- """
-
- last_called_at: dt.datetime = pydantic.Field()
- """
- Timestamp of the most recent outbound call to this number.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/refresh_config.py b/src/speechify/types/refresh_config.py
deleted file mode 100644
index 2d714f9..0000000
--- a/src/speechify/types/refresh_config.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class RefreshConfig(UniversalBaseModel):
- """
- Per-document auto-refresh state. Only populated
- for url-sourced documents; file and text rows omit this and
- the console's auto-refresh panel hides accordingly.
- """
-
- enabled: bool
- interval_days: int
- auto_remove_enabled: bool
- last_refreshed_at: typing.Optional[dt.datetime] = None
- consecutive_fetch_failures: int
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/refresh_history_entry.py b/src/speechify/types/refresh_history_entry.py
deleted file mode 100644
index a128645..0000000
--- a/src/speechify/types/refresh_history_entry.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import datetime as dt
-import typing
-from .refresh_history_entry_status import RefreshHistoryEntryStatus
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class RefreshHistoryEntry(UniversalBaseModel):
- """
- One auto-refresh attempt. `running` only appears mid-tick;
- terminal values are the ones the drawer renders.
- """
-
- id: str
- document_id: str
- started_at: dt.datetime
- finished_at: typing.Optional[dt.datetime] = None
- status: RefreshHistoryEntryStatus
- error: typing.Optional[str] = None
- previous_hash: typing.Optional[str] = None
- new_hash: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/refresh_history_entry_status.py b/src/speechify/types/refresh_history_entry_status.py
deleted file mode 100644
index 80646a4..0000000
--- a/src/speechify/types/refresh_history_entry_status.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-RefreshHistoryEntryStatus = typing.Union[
- typing.Literal["running", "changed", "unchanged", "failed", "removed"], typing.Any
-]
diff --git a/src/speechify/types/reply_config.py b/src/speechify/types/reply_config.py
deleted file mode 100644
index 4182c75..0000000
--- a/src/speechify/types/reply_config.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from .simulation_message import SimulationMessage
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ReplyConfig(UniversalBaseModel):
- """
- Configuration for a `reply` test. The runner sends `context` as
- a user message and asks an LLM judge to evaluate the agent response
- against `success_criteria`. Optional few-shot examples sharpen the
- judge's calibration. Use `initial_chat_history` to prepend prior
- turns before `context`; when the history already ends with a user
- message, `context` may be omitted and the agent is evaluated on
- its reply to that last history turn.
- """
-
- context: typing.Optional[str] = pydantic.Field(default=None)
- """
- User message sent to the agent to trigger the behaviour under test. Optional when `initial_chat_history` already ends with a user message.
- """
-
- success_criteria: str = pydantic.Field()
- """
- Natural-language description of what a passing agent response looks like.
- """
-
- success_examples: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- Concrete examples of passing responses (few-shot for the judge).
- """
-
- failure_examples: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- Concrete examples of failing responses (few-shot for the judge).
- """
-
- initial_chat_history: typing.Optional[typing.List[SimulationMessage]] = pydantic.Field(default=None)
- """
- Optional seed conversation prepended before `context`. Lets you test the agent's reply mid-conversation rather than on a cold single-turn prompt.
- """
-
- system_prompt_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`, which applies a proposed
- prompt to every test in the run without editing each one.
- Still honoured; the run-level override wins when both are set.
- Replaces the agent's system prompt for this run only.
- """
-
- first_message_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Replaces the agent's first message for this run only.
- """
-
- model_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`. Still honoured; the
- run-level override wins when both are set. Overrides the LLM
- model used by the agent for this run only.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/reply_result.py b/src/speechify/types/reply_result.py
deleted file mode 100644
index 982dd63..0000000
--- a/src/speechify/types/reply_result.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class ReplyResult(UniversalBaseModel):
- """
- Result details for a `reply` test run.
- """
-
- agent_response: str = pydantic.Field()
- """
- The raw text response the agent produced.
- """
-
- passed: bool
- rationale: str = pydantic.Field()
- """
- LLM judge's explanation of the verdict.
- """
-
- score: float = pydantic.Field()
- """
- 0-1 judge confidence score.
- """
-
- duration_ms: int = pydantic.Field()
- """
- Wall-clock time for the run in milliseconds.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/retrieval_log_entry.py b/src/speechify/types/retrieval_log_entry.py
deleted file mode 100644
index 01e165b..0000000
--- a/src/speechify/types/retrieval_log_entry.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .retrieval_log_result import RetrievalLogResult
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class RetrievalLogEntry(UniversalBaseModel):
- """
- One `search_knowledge` invocation recorded against a
- conversation. Powers the Retrieval panel on the conversation
- detail view.
- """
-
- id: str
- conversation_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`conv_<26 char Crockford base32>`)
- of the conversation.
- """
-
- query: str
- results: typing.List[RetrievalLogResult]
- top_k: int
- hit_count: int
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/retrieval_log_result.py b/src/speechify/types/retrieval_log_result.py
deleted file mode 100644
index 0e07914..0000000
--- a/src/speechify/types/retrieval_log_result.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class RetrievalLogResult(UniversalBaseModel):
- """
- One ranked chunk inside a retrieval log row. Mirrors
- `RetrievalLogResult` in apps/server/internal/kb/types.go —
- denormalised so deleting a chunk or document after the call
- doesn't render historical logs unreadable.
- """
-
- chunk_id: str
- document_id: str
- kb_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`kb_<26 char Crockford base32>`)
- of the knowledge base the matched chunk lives in.
- """
-
- filename: str
- chunk_index: int
- content: str
- score: float
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/run_agent_tests_response.py b/src/speechify/types/run_agent_tests_response.py
deleted file mode 100644
index 98f8675..0000000
--- a/src/speechify/types/run_agent_tests_response.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_test_run import AgentTestRun
-from .agent_test_suite_run import AgentTestSuiteRun
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class RunAgentTestsResponse(UniversalBaseModel):
- """
- Response from `POST /v1/agents/{id}/tests/runs` and the suite-run
- resubmit endpoint. Contains every newly-queued run so the client
- can poll each for completion, plus the `suite_run` that groups
- them. `suite_run` is null only when a Run All found no tests.
- """
-
- runs: typing.List[AgentTestRun]
- suite_run: typing.Optional[AgentTestSuiteRun] = pydantic.Field(default=None)
- """
- The suite run grouping the queued runs.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/run_batch_response.py b/src/speechify/types/run_batch_response.py
deleted file mode 100644
index af544ec..0000000
--- a/src/speechify/types/run_batch_response.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .agent_test_run import AgentTestRun
-from .agent_test_suite_run import AgentTestSuiteRun
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class RunBatchResponse(UniversalBaseModel):
- runs: typing.List[AgentTestRun]
- suite_run: typing.Optional[AgentTestSuiteRun] = pydantic.Field(default=None)
- """
- The suite run grouping the queued runs.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/search_available_phone_numbers_response.py b/src/speechify/types/search_available_phone_numbers_response.py
deleted file mode 100644
index 65cf423..0000000
--- a/src/speechify/types/search_available_phone_numbers_response.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .available_phone_number import AvailablePhoneNumber
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SearchAvailablePhoneNumbersResponse(UniversalBaseModel):
- """
- Response for `GET /v1/agents/phone-numbers/available`.
- """
-
- numbers: typing.List[AvailablePhoneNumber] = pydantic.Field()
- """
- Available numbers (may be empty if no inventory matches).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/search_knowledge_bases_response.py b/src/speechify/types/search_knowledge_bases_response.py
deleted file mode 100644
index 5b6336f..0000000
--- a/src/speechify/types/search_knowledge_bases_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .knowledge_base_search_hit import KnowledgeBaseSearchHit
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class SearchKnowledgeBasesResponse(UniversalBaseModel):
- hits: typing.List[KnowledgeBaseSearchHit]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/shadow_conversation_response.py b/src/speechify/types/shadow_conversation_response.py
deleted file mode 100644
index 2261a29..0000000
--- a/src/speechify/types/shadow_conversation_response.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class ShadowConversationResponse(UniversalBaseModel):
- """
- Connection details for an authorized observer (workspace owner or
- admin) joining an active conversation as a hidden, listen-only
- participant. The livekit-client SDK consumes `livekit_url` +
- `token` to attach to the live room and play the agent + caller
- audio tracks.
- """
-
- conversation_id: str
- room_name: str
- livekit_url: str = pydantic.Field()
- """
- wss://… signaling URL for the LiveKit project hosting the room.
- """
-
- token: str = pydantic.Field()
- """
- Short-lived LiveKit access token. Grant has CanPublish=false,
- CanPublishData=false, CanSubscribe=true, Hidden=true so the
- observer can listen but cannot speak and is invisible to the
- caller and the agent.
- """
-
- identity: str = pydantic.Field()
- """
- Opaque participant identity tag (e.g. shadow_). Visible only to admin tooling.
- """
-
- expires_at: dt.datetime = pydantic.Field()
- """
- When the token stops being accepted by LiveKit. The console should re-mint past this point.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/simulation_config.py b/src/speechify/types/simulation_config.py
deleted file mode 100644
index 049fb9a..0000000
--- a/src/speechify/types/simulation_config.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .simulation_message import SimulationMessage
-from .data_assertion import DataAssertion
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SimulationConfig(UniversalBaseModel):
- """
- Configuration for a `simulation` test. An AI caller drives a
- multi-turn conversation with the agent according to `scenario`.
- After `max_turns` exchanges (or when the agent ends the call),
- the unified post-call evaluator scores the synthetic transcript
- against the agent's configured evaluation criteria + data
- collection fields. A test passes when no configured criterion
- fails and every `data_assertions` entry passes.
- """
-
- scenario: str = pydantic.Field()
- """
- Instructions for the AI caller describing who they are and what they want.
- """
-
- max_turns: typing.Optional[int] = pydantic.Field(default=None)
- """
- Maximum agent turns before the simulation is cut off and judged.
- """
-
- initial_chat_history: typing.Optional[typing.List[SimulationMessage]] = pydantic.Field(default=None)
- """
- Optional seed conversation that precedes the AI caller's first generated message.
- """
-
- data_assertions: typing.Optional[typing.List[DataAssertion]] = pydantic.Field(default=None)
- """
- Optional assertions on the LLM-extracted data-collection
- map. Each entry references a key from the agent's
- data_collection config and validates the extracted value.
- The test fails if any assertion fails.
- """
-
- system_prompt_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`. Still honoured; the
- run-level override wins when both are set. Replaces the
- agent's system prompt for this run only.
- """
-
- model_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`. Still honoured; the
- run-level override wins when both are set. Overrides the LLM
- model used by the agent for this run only.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/simulation_criterion_result.py b/src/speechify/types/simulation_criterion_result.py
deleted file mode 100644
index 5aa85b9..0000000
--- a/src/speechify/types/simulation_criterion_result.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .simulation_criterion_result_status import SimulationCriterionResultStatus
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SimulationCriterionResult(UniversalBaseModel):
- """
- One scored entry of an agent's configured evaluation criterion
- against a simulation transcript. Mirrors the per-criterion row
- the post-call evaluator persists, so test runs and live
- conversations carry identical per-criterion shapes.
- """
-
- criterion_id: str
- name: str
- status: SimulationCriterionResultStatus = pydantic.Field()
- """
- Three-state outcome. `unknown` means the criterion did not
- apply on this run (the topic never came up); `failure`
- means it did apply and the agent did not satisfy it.
- """
-
- score: typing.Optional[float] = pydantic.Field(default=None)
- """
- 0.0..1.0 continuous estimate of how well the criterion was met.
- """
-
- rationale: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/simulation_criterion_result_status.py b/src/speechify/types/simulation_criterion_result_status.py
deleted file mode 100644
index bf95a30..0000000
--- a/src/speechify/types/simulation_criterion_result_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SimulationCriterionResultStatus = typing.Union[typing.Literal["success", "failure", "unknown"], typing.Any]
diff --git a/src/speechify/types/simulation_message.py b/src/speechify/types/simulation_message.py
deleted file mode 100644
index d6fc1ac..0000000
--- a/src/speechify/types/simulation_message.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .simulation_message_role import SimulationMessageRole
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class SimulationMessage(UniversalBaseModel):
- """
- One turn in a simulation conversation. `role` is `user` (the AI caller) or `assistant` (the agent).
- """
-
- role: SimulationMessageRole
- content: str
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/simulation_message_role.py b/src/speechify/types/simulation_message_role.py
deleted file mode 100644
index 106ec8f..0000000
--- a/src/speechify/types/simulation_message_role.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SimulationMessageRole = typing.Union[typing.Literal["user", "assistant"], typing.Any]
diff --git a/src/speechify/types/simulation_result.py b/src/speechify/types/simulation_result.py
deleted file mode 100644
index d08382e..0000000
--- a/src/speechify/types/simulation_result.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .simulation_message import SimulationMessage
-import pydantic
-from .simulation_tool_call import SimulationToolCall
-from .simulation_result_sentiment import SimulationResultSentiment
-from .simulation_criterion_result import SimulationCriterionResult
-from .data_assertion_result import DataAssertionResult
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SimulationResult(UniversalBaseModel):
- """
- Result details for a `simulation` test run. Scoring is unified
- with the post-call evaluator: the synthetic transcript
- is scored against the agent's configured evaluation criteria
- and data-collection fields, then per-test `data_assertions`
- check the extracted values. The top-level `passed` is derived
- — every criterion must resolve to `success` or `unknown` and
- every assertion must pass.
- """
-
- transcript: typing.List[SimulationMessage] = pydantic.Field()
- """
- Full synthetic conversation in order.
- """
-
- tool_calls: typing.Optional[typing.List[SimulationToolCall]] = pydantic.Field(default=None)
- """
- Every tool invocation across all turns.
- """
-
- turns_used: int = pydantic.Field()
- """
- Number of agent turns that ran before the simulation ended.
- """
-
- passed: bool
- rationale: str = pydantic.Field()
- """
- Top-level verdict explanation (run summary on pass; first failing criterion or assertion on fail).
- """
-
- duration_ms: int
- summary: typing.Optional[str] = pydantic.Field(default=None)
- """
- One-sentence narrative summary of what happened in the conversation.
- """
-
- sentiment: typing.Optional[SimulationResultSentiment] = pydantic.Field(default=None)
- """
- Overall sentiment classification.
- """
-
- criteria: typing.Optional[typing.List[SimulationCriterionResult]] = pydantic.Field(default=None)
- """
- One result row per configured EvaluationCriterion on the
- agent. Same shape as the per-criterion rows persisted on
- the post-call evaluations table.
- """
-
- data: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- LLM-extracted values for the agent's configured
- data-collection fields. Keys mirror the agent's
- data_collection field keys; values are typed per the
- declared field type.
- """
-
- data_assertions: typing.Optional[typing.List[DataAssertionResult]] = pydantic.Field(default=None)
- """
- One result row per `data_assertions` entry on the simulation config.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/simulation_result_sentiment.py b/src/speechify/types/simulation_result_sentiment.py
deleted file mode 100644
index cef3f6a..0000000
--- a/src/speechify/types/simulation_result_sentiment.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SimulationResultSentiment = typing.Union[typing.Literal["positive", "neutral", "negative"], typing.Any]
diff --git a/src/speechify/types/simulation_tool_call.py b/src/speechify/types/simulation_tool_call.py
deleted file mode 100644
index c2ecb51..0000000
--- a/src/speechify/types/simulation_tool_call.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SimulationToolCall(UniversalBaseModel):
- """
- One tool invocation that occurred during a simulation run.
- `mocked` is true when the call was intercepted by the run's
- mock config; false when the real tool was called or when the
- tool is a system tool.
- """
-
- turn_index: int = pydantic.Field()
- """
- Zero-based index of the conversation turn in which this call occurred.
- """
-
- tool_name: str
- args: typing.Optional[typing.Any] = None
- response: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
- """
- Response returned to the agent (absent for system tools that end the call).
- """
-
- mocked: bool
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/sip_media_encryption.py b/src/speechify/types/sip_media_encryption.py
deleted file mode 100644
index 8f1edc0..0000000
--- a/src/speechify/types/sip_media_encryption.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SipMediaEncryption = typing.Union[typing.Literal["disable", "allow", "require"], typing.Any]
diff --git a/src/speechify/types/sip_transport.py b/src/speechify/types/sip_transport.py
deleted file mode 100644
index 20e6a2e..0000000
--- a/src/speechify/types/sip_transport.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SipTransport = typing.Union[typing.Literal["auto", "udp", "tcp", "tls"], typing.Any]
diff --git a/src/speechify/types/sip_trunk.py b/src/speechify/types/sip_trunk.py
deleted file mode 100644
index 4ebda05..0000000
--- a/src/speechify/types/sip_trunk.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .sip_trunk_kind import SipTrunkKind
-from .sip_trunk_direction import SipTrunkDirection
-import typing
-from .sip_transport import SipTransport
-from .sip_media_encryption import SipMediaEncryption
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SipTrunk(UniversalBaseModel):
- """
- A SIP trunk in the workspace. Trunks back one or more phone numbers
- and hold the carrier credentials LiveKit uses to route calls.
- `auth_password` is never echoed - `auth_password_set` indicates
- whether one is configured.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`trunk_<26 char Crockford base32>`).
- URL paths accept only this
- prefixed form; legacy UUID path parameters are rejected with
- 404.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable name.
- """
-
- kind: SipTrunkKind
- direction: SipTrunkDirection
- livekit_inbound_trunk_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- LiveKit's inbound trunk ID (present when direction is `inbound` or `both`).
- """
-
- livekit_outbound_trunk_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- LiveKit's outbound trunk ID (present when direction is `outbound` or `both`).
- """
-
- livekit_dispatch_rule_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- LiveKit dispatch rule ID that routes inbound calls into rooms.
- """
-
- sip_address: typing.Optional[str] = pydantic.Field(default=None)
- """
- SIP endpoint hostname (e.g. `sip.telnyx.com`). Required for `kind=byoc`.
- """
-
- auth_username: typing.Optional[str] = pydantic.Field(default=None)
- """
- SIP digest auth username.
- """
-
- auth_password_set: typing.Optional[bool] = pydantic.Field(default=None)
- """
- Whether a SIP digest auth password is configured. The value is never returned.
- """
-
- allowed_addresses: typing.List[str] = pydantic.Field()
- """
- IP address / CIDR allowlist for inbound SIP connections.
- """
-
- destination_country: typing.Optional[str] = pydantic.Field(default=None)
- """
- ISO 3166-1 alpha-2 country code for the outbound dial plan
- (e.g. `US`, `DE`). Required for international outbound on
- some carriers.
- """
-
- transport: SipTransport
- media_encryption: SipMediaEncryption
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/sip_trunk_direction.py b/src/speechify/types/sip_trunk_direction.py
deleted file mode 100644
index 98d203e..0000000
--- a/src/speechify/types/sip_trunk_direction.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SipTrunkDirection = typing.Union[typing.Literal["inbound", "outbound", "both"], typing.Any]
diff --git a/src/speechify/types/sip_trunk_kind.py b/src/speechify/types/sip_trunk_kind.py
deleted file mode 100644
index 9389e68..0000000
--- a/src/speechify/types/sip_trunk_kind.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SipTrunkKind = typing.Union[typing.Literal["livekit", "twilio", "byoc"], typing.Any]
diff --git a/src/speechify/types/suite_child_run.py b/src/speechify/types/suite_child_run.py
deleted file mode 100644
index a97fa1d..0000000
--- a/src/speechify/types/suite_child_run.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from .agent_test_run import AgentTestRun
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class SuiteChildRun(AgentTestRun):
- """
- One child run inside a suite run, carrying the parent test's
- name and the target agent's name so the grouped result view can
- label each row. The agent name disambiguates results when the
- suite spans multiple agents.
- """
-
- test_name: str = pydantic.Field()
- """
- Name of the test this run executed.
- """
-
- agent_name: str = pydantic.Field()
- """
- Display name of the agent this run executed against.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/suite_run_trigger.py b/src/speechify/types/suite_run_trigger.py
deleted file mode 100644
index 8b6baa5..0000000
--- a/src/speechify/types/suite_run_trigger.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-SuiteRunTrigger = typing.Union[typing.Literal["run_all", "batch", "resubmit"], typing.Any]
diff --git a/src/speechify/types/system_builtin.py b/src/speechify/types/system_builtin.py
deleted file mode 100644
index 0be9570..0000000
--- a/src/speechify/types/system_builtin.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-SystemBuiltin = str
diff --git a/src/speechify/types/system_builtin_info.py b/src/speechify/types/system_builtin_info.py
deleted file mode 100644
index f7c17dc..0000000
--- a/src/speechify/types/system_builtin_info.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .system_builtin import SystemBuiltin
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class SystemBuiltinInfo(UniversalBaseModel):
- """
- One entry in the system-builtin catalogue.
- """
-
- name: SystemBuiltin
- label: str = pydantic.Field()
- """
- Console-facing display label for the builtin.
- """
-
- description: str = pydantic.Field()
- """
- Console-facing one-line summary of what the builtin does.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/system_tool_config.py b/src/speechify/types/system_tool_config.py
deleted file mode 100644
index 94898bd..0000000
--- a/src/speechify/types/system_tool_config.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .system_builtin import SystemBuiltin
-import typing
-from .tool_param import ToolParam
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class SystemToolConfig(UniversalBaseModel):
- """
- Config shape for `kind=system`. The `builtin` value names the
- worker-resident capability; the catalogue served by
- `GET /v1/agents/tools/system-builtins` is the runtime source of truth
- for valid names plus their console-facing labels.
- """
-
- builtin: SystemBuiltin
- params: typing.Optional[typing.List[ToolParam]] = None
- builtin_config: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Per-builtin extras (e.g. allowed_numbers for transfer_to_number).
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/system_variable_doc.py b/src/speechify/types/system_variable_doc.py
deleted file mode 100644
index 2af658e..0000000
--- a/src/speechify/types/system_variable_doc.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class SystemVariableDoc(UniversalBaseModel):
- """
- Documents one reserved `system__*` variable that the platform
- auto-populates at session start. Customers cannot define or
- override these keys.
- """
-
- key: str = pydantic.Field()
- """
- The reserved variable key (always starts with `system__`).
- """
-
- description: str = pydantic.Field()
- """
- What the variable contains and when it is populated.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tenant.py b/src/speechify/types/tenant.py
deleted file mode 100644
index 037b1ac..0000000
--- a/src/speechify/types/tenant.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-import datetime as dt
-from .member_role import MemberRole
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Tenant(UniversalBaseModel):
- """
- A workspace the caller belongs to.
-
- Billing fields (`orb_customer_id`, `billing_contact_email`,
- `billing_contact_name`) are exposed because every authenticated
- caller is already a member of the workspace — `cus_…` is an
- opaque support handle, and the billing email is the same
- category of signal as the member emails surfaced on
- `GET /v1/workspaces/current/members`.
- """
-
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`ws_<26 char Crockford base32>`).
- URL paths and the X-Tenant-ID
- header accept only this form. The underlying UUIDv7
- primary key is never disclosed on the API surface.
- """
-
- name: str = pydantic.Field()
- """
- Display name set by the workspace owner.
- """
-
- orb_customer_id: typing.Optional[str] = pydantic.Field(default=None)
- """
- The Orb customer handle (`cus_…`). Empty for the small
- cohort of legacy tenants that were never linked
- (their owner had no Firebase email at the cutover); the
- billing-contact-email endpoint promotes them on first
- edit. Populated for every newly-provisioned tenant.
- """
-
- billing_contact_email: typing.Optional[str] = pydantic.Field(default=None)
- """
- Email synced to Orb's `customer.email`. Defaults to the
- workspace creator's Firebase email at provision time;
- editable via `PUT /v1/workspaces/current/billing-contact-email`.
- """
-
- billing_contact_name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Billing-contact name override that appears on Orb
- invoices. `null` means "inherit the workspace name".
- Editable via `PUT /v1/workspaces/current/billing-contact-name`.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
- my_role: MemberRole = pydantic.Field()
- """
- The caller's role in this workspace. Surfaced so the console
- can gate role-restricted UI on first paint without fetching
- the full members list. The caller is asking about themselves,
- so this is no broader a disclosure than the existing
- `is_self` flag on `GET /v1/workspaces/current/members`.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tenants_list_response.py b/src/speechify/types/tenants_list_response.py
deleted file mode 100644
index 06e0901..0000000
--- a/src/speechify/types/tenants_list_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .tenant import Tenant
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class TenantsListResponse(UniversalBaseModel):
- tenants: typing.List[Tenant]
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/test_run_config_override.py b/src/speechify/types/test_run_config_override.py
deleted file mode 100644
index d2f4d9f..0000000
--- a/src/speechify/types/test_run_config_override.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class TestRunConfigOverride(UniversalBaseModel):
- """
- A run-level config override applied to every test in a Run All.
- Layered on top of the agent's stored config for the duration of
- the suite run, so the whole suite can be validated against a
- proposed prompt / model / toolbelt without editing any test. An
- absent field leaves the agent's value untouched; a run-level
- override wins over a deprecated per-test `system_prompt_override`
- / `model_override`.
- """
-
- prompt: typing.Optional[str] = pydantic.Field(default=None)
- """
- Replaces the agent's system prompt for every test in the run.
- """
-
- model: typing.Optional[str] = pydantic.Field(default=None)
- """
- Overrides the LLM model for every test in the run. The model
- id rides on the agent's configured provider — a
- cross-provider switch is not supported.
- """
-
- tool_ids: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
- """
- Replaces the agent's attached external tools for the run with
- exactly this set. Each entry is a prefixed `tool_`
- id; `builtin_` ids are rejected. An empty array runs with no
- tools; omit the field to keep the agent's attachments.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/test_run_result.py b/src/speechify/types/test_run_result.py
deleted file mode 100644
index f395761..0000000
--- a/src/speechify/types/test_run_result.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .test_type import TestType
-import pydantic
-import typing
-from .reply_result import ReplyResult
-from .tool_call_result import ToolCallResult
-from .simulation_result import SimulationResult
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class TestRunResult(UniversalBaseModel):
- """
- Union-like result of a completed test run. Exactly one of
- `reply`, `tool_call`, or `simulation` is populated, matching
- the `test_type`.
- """
-
- test_type: TestType
- passed: bool
- rationale: str = pydantic.Field()
- """
- Top-level verdict explanation duplicated from the inner result for quick rendering.
- """
-
- duration_ms: int
- reply: typing.Optional[ReplyResult] = None
- tool_call: typing.Optional[ToolCallResult] = None
- simulation: typing.Optional[SimulationResult] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/test_run_status.py b/src/speechify/types/test_run_status.py
deleted file mode 100644
index f9924f7..0000000
--- a/src/speechify/types/test_run_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-TestRunStatus = typing.Union[typing.Literal["queued", "running", "passed", "failed", "error"], typing.Any]
diff --git a/src/speechify/types/test_stats.py b/src/speechify/types/test_stats.py
deleted file mode 100644
index fdf4b1c..0000000
--- a/src/speechify/types/test_stats.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .test_stats_bucket import TestStatsBucket
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class TestStats(UniversalBaseModel):
- """
- Aggregate run metrics over the requested window. `buckets` is
- dense - one entry per day in the window, zero-filled, so a chart
- never has gaps. `by_type` counts runs per test type across the
- whole window.
- """
-
- window_days: int
- buckets: typing.List[TestStatsBucket]
- total_runs: int
- passed_runs: int
- failed_runs: int
- errored_runs: int
- avg_duration_ms: int
- by_type: typing.Optional[typing.Dict[str, int]] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/test_stats_bucket.py b/src/speechify/types/test_stats_bucket.py
deleted file mode 100644
index 360fc17..0000000
--- a/src/speechify/types/test_stats_bucket.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class TestStatsBucket(UniversalBaseModel):
- """
- One daily point on the aggregate pass-rate chart.
- """
-
- day: str = pydantic.Field()
- """
- ISO date (YYYY-MM-DD).
- """
-
- passed: int
- failed: int
- errored: int
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/test_type.py b/src/speechify/types/test_type.py
deleted file mode 100644
index 3d5dbfb..0000000
--- a/src/speechify/types/test_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-TestType = typing.Union[typing.Literal["reply", "tool", "simulation"], typing.Any]
diff --git a/src/speechify/types/tool.py b/src/speechify/types/tool.py
deleted file mode 100644
index 3ce0cb2..0000000
--- a/src/speechify/types/tool.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .tool_kind import ToolKind
-from .tool_config import ToolConfig
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class Tool(UniversalBaseModel):
- id: str = pydantic.Field()
- """
- Prefixed wire identifier (`tool_<26 char Crockford base32>`).
- """
-
- name: str
- description: str
- kind: ToolKind
- config: ToolConfig = pydantic.Field()
- """
- One of `SystemToolConfig`, `WebhookToolConfig`, `ClientToolConfig`, or `MCPToolConfig` depending on `kind`.
- """
-
- webhook_secret: typing.Optional[str] = pydantic.Field(default=None)
- """
- HMAC signing secret for `kind=webhook`. Returned in full **only** on the create
- response; all subsequent reads return a masked placeholder. Store it on first
- create — there is no way to retrieve it later.
- """
-
- created_at: dt.datetime
- updated_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_attached_agent.py b/src/speechify/types/tool_attached_agent.py
deleted file mode 100644
index 66c6d54..0000000
--- a/src/speechify/types/tool_attached_agent.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class ToolAttachedAgent(UniversalBaseModel):
- """
- Minimal agent identity returned alongside a tool so the console
- can render "this tool is attached to: X, Y" copy before a
- destructive action runs.
- """
-
- id: str = pydantic.Field()
- """
- Opaque agent ID.
- """
-
- name: str = pydantic.Field()
- """
- Human-readable agent name.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_call_config.py b/src/speechify/types/tool_call_config.py
deleted file mode 100644
index 365e1e1..0000000
--- a/src/speechify/types/tool_call_config.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from .parameter_check import ParameterCheck
-from .simulation_message import SimulationMessage
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ToolCallConfig(UniversalBaseModel):
- """
- Configuration for a `tool` test. The runner sends `context` as a
- user message and asserts that the agent calls `expected_tool` with
- arguments matching all `parameter_checks`. Use
- `initial_chat_history` to test tool invocations that only make
- sense mid-conversation.
- """
-
- context: typing.Optional[str] = pydantic.Field(default=None)
- """
- User message that should cause the agent to invoke the expected tool. Optional when `initial_chat_history` already ends with a user message.
- """
-
- expected_tool: str = pydantic.Field()
- """
- Name of the tool the agent is expected to call. Leave empty to
- invert the assertion: the test passes only when the agent calls
- no tool at all.
- """
-
- parameter_checks: typing.Optional[typing.List[ParameterCheck]] = pydantic.Field(default=None)
- """
- Assertions on specific arguments of the tool call.
- """
-
- initial_chat_history: typing.Optional[typing.List[SimulationMessage]] = pydantic.Field(default=None)
- """
- Optional seed conversation prepended before `context`.
- """
-
- system_prompt_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`. Still honoured; the
- run-level override wins when both are set. Replaces the
- agent's system prompt for this run only.
- """
-
- model_override: typing.Optional[str] = pydantic.Field(default=None)
- """
- Deprecated. Prefer the run-level `config_override`
- on `POST /v1/agents/{id}/tests/runs`. Still honoured; the
- run-level override wins when both are set. Overrides the LLM
- model used by the agent for this run only.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_call_result.py b/src/speechify/types/tool_call_result.py
deleted file mode 100644
index 59eeaf2..0000000
--- a/src/speechify/types/tool_call_result.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from .parameter_check_result import ParameterCheckResult
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ToolCallResult(UniversalBaseModel):
- """
- Result details for a `tool` test run.
- """
-
- tool_called: str = pydantic.Field()
- """
- Name of the tool the agent actually called (may differ from `expected_tool`).
- """
-
- tool_args: typing.Optional[typing.Optional[typing.Any]] = pydantic.Field(default=None)
- """
- Arguments the agent passed to the tool, as a JSON object.
- """
-
- expected_tool: str = pydantic.Field()
- """
- Name of the tool the test expected the agent to call.
- """
-
- tool_matched: bool = pydantic.Field()
- """
- True when `tool_called` equals `expected_tool`.
- """
-
- parameter_results: typing.List[ParameterCheckResult]
- passed: bool
- rationale: str = pydantic.Field()
- """
- Explanation of the overall verdict.
- """
-
- duration_ms: int
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_config.py b/src/speechify/types/tool_config.py
deleted file mode 100644
index bc91d84..0000000
--- a/src/speechify/types/tool_config.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-from .system_tool_config import SystemToolConfig
-from .webhook_tool_config import WebhookToolConfig
-from .client_tool_config import ClientToolConfig
-from .mcp_tool_config import McpToolConfig
-
-ToolConfig = typing.Union[SystemToolConfig, WebhookToolConfig, ClientToolConfig, McpToolConfig]
diff --git a/src/speechify/types/tool_kind.py b/src/speechify/types/tool_kind.py
deleted file mode 100644
index 5a58c49..0000000
--- a/src/speechify/types/tool_kind.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ToolKind = typing.Union[typing.Literal["system", "webhook", "client", "mcp"], typing.Any]
diff --git a/src/speechify/types/tool_mock.py b/src/speechify/types/tool_mock.py
deleted file mode 100644
index 0545167..0000000
--- a/src/speechify/types/tool_mock.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ToolMock(UniversalBaseModel):
- """
- A canned response returned when the agent calls `tool_name`. If
- `args_match` is set the mock only triggers when the call arguments
- deep-contain it (a structured subset match). A mock without
- `args_match` always matches for its tool.
- """
-
- tool_name: str = pydantic.Field()
- """
- Name of the tool to intercept.
- """
-
- args_match: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = pydantic.Field(default=None)
- """
- Optional structured argument matcher. When set, the mock fires
- only if the tool call's arguments deep-contain every key/value
- in this object: nested objects match recursively as subsets,
- arrays and scalar leaves match by deep equality. An empty
- object matches unconditionally. When absent the mock matches
- unconditionally for this tool.
- """
-
- response: typing.Optional[typing.Any] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_mock_config.py b/src/speechify/types/tool_mock_config.py
deleted file mode 100644
index 33ac0dd..0000000
--- a/src/speechify/types/tool_mock_config.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .mocking_strategy import MockingStrategy
-import typing
-from .tool_mock import ToolMock
-import pydantic
-from .no_match_behavior import NoMatchBehavior
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class ToolMockConfig(UniversalBaseModel):
- """
- Controls tool-call interception during a test run.
- """
-
- strategy: MockingStrategy
- mocks: typing.Optional[typing.List[ToolMock]] = pydantic.Field(default=None)
- """
- Canned responses for specific tools (order matters - first match wins).
- """
-
- no_match_behavior: NoMatchBehavior
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_param.py b/src/speechify/types/tool_param.py
deleted file mode 100644
index 9f2a343..0000000
--- a/src/speechify/types/tool_param.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .tool_param_type import ToolParamType
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class ToolParam(UniversalBaseModel):
- """
- One argument the LLM can pass when calling the tool. Mirrors the JSON-Schema subset standard function-calling schemas support.
- """
-
- name: str
- type: ToolParamType
- description: str
- required: bool
- enum: typing.Optional[typing.List[str]] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/tool_param_type.py b/src/speechify/types/tool_param_type.py
deleted file mode 100644
index 9dc5af6..0000000
--- a/src/speechify/types/tool_param_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-ToolParamType = typing.Union[typing.Literal["string", "number", "integer", "boolean"], typing.Any]
diff --git a/src/speechify/types/transfer_ownership_request.py b/src/speechify/types/transfer_ownership_request.py
deleted file mode 100644
index b5e97b9..0000000
--- a/src/speechify/types/transfer_ownership_request.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class TransferOwnershipRequest(UniversalBaseModel):
- """
- Body for POST /v1/workspaces/current/transfer-owner. The target
- must already be a member of the current workspace — promote via
- invite + accept first for external users.
- """
-
- user_uid: str = pydantic.Field()
- """
- Firebase UID of the member who will become the new owner.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/twilio_import_spec.py b/src/speechify/types/twilio_import_spec.py
deleted file mode 100644
index dc6a2c4..0000000
--- a/src/speechify/types/twilio_import_spec.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class TwilioImportSpec(UniversalBaseModel):
- """
- Twilio credentials for the one-click import flow. Used only when
- `source=twilio`. The Account SID and Auth Token are used to
- provision an Elastic SIP Trunk on the customer's Twilio account
- pointing at LiveKit's SIP endpoint, then stored for future trunk
- management operations.
- """
-
- account_sid: str = pydantic.Field()
- """
- Twilio Account SID (starts with `AC`).
- """
-
- auth_token: str = pydantic.Field()
- """
- Twilio Auth Token. Write-only - never echoed back.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/update_billing_contact_email_request.py b/src/speechify/types/update_billing_contact_email_request.py
deleted file mode 100644
index e90502c..0000000
--- a/src/speechify/types/update_billing_contact_email_request.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class UpdateBillingContactEmailRequest(UniversalBaseModel):
- """
- Body for PUT /v1/workspaces/current/billing-contact-email.
- """
-
- email: str = pydantic.Field()
- """
- New billing contact email. Validated as an RFC 5322 address
- (display-name forms are rejected); must be 254 characters
- or fewer. Domain portion is lowercased for storage.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/update_billing_contact_name_request.py b/src/speechify/types/update_billing_contact_name_request.py
deleted file mode 100644
index fb42d94..0000000
--- a/src/speechify/types/update_billing_contact_name_request.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class UpdateBillingContactNameRequest(UniversalBaseModel):
- """
- Body for PUT /v1/workspaces/current/billing-contact-name. Pass
- `{"name": null}` to clear the override and revert to inheriting
- the workspace name on invoices.
- """
-
- name: typing.Optional[str] = pydantic.Field(default=None)
- """
- Billing-contact name override. When non-null, must be
- non-empty after trimming and 256 characters or fewer.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/update_member_role_request.py b/src/speechify/types/update_member_role_request.py
deleted file mode 100644
index c57bc19..0000000
--- a/src/speechify/types/update_member_role_request.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .member_role import MemberRole
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class UpdateMemberRoleRequest(UniversalBaseModel):
- role: MemberRole
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/update_sip_trunk_request.py b/src/speechify/types/update_sip_trunk_request.py
deleted file mode 100644
index 9ec9391..0000000
--- a/src/speechify/types/update_sip_trunk_request.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from .sip_transport import SipTransport
-from .sip_media_encryption import SipMediaEncryption
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class UpdateSipTrunkRequest(UniversalBaseModel):
- """
- PATCH body for `PATCH /v1/agents/sip-trunks/{id}`. All fields optional;
- omitted fields are left unchanged.
- """
-
- name: typing.Optional[str] = None
- auth_username: typing.Optional[str] = None
- auth_password: typing.Optional[str] = pydantic.Field(default=None)
- """
- Rotating this replaces the stored password.
- """
-
- allowed_addresses: typing.Optional[typing.List[str]] = None
- destination_country: typing.Optional[str] = None
- transport: typing.Optional[SipTransport] = None
- media_encryption: typing.Optional[SipMediaEncryption] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/update_workspace_request.py b/src/speechify/types/update_workspace_request.py
deleted file mode 100644
index 4beec5e..0000000
--- a/src/speechify/types/update_workspace_request.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-
-
-class UpdateWorkspaceRequest(UniversalBaseModel):
- """
- Body for PATCH /v1/workspaces/current. Renames the workspace's
- display name; the wire id (`ws_…`) is immutable.
- """
-
- name: str = pydantic.Field()
- """
- New display name. Must be non-empty (after trimming) and 120 characters or fewer.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/upload_audio_asset_response.py b/src/speechify/types/upload_audio_asset_response.py
deleted file mode 100644
index db9bcb4..0000000
--- a/src/speechify/types/upload_audio_asset_response.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-from .audio_asset import AudioAsset
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import typing
-import pydantic
-
-
-class UploadAudioAssetResponse(UniversalBaseModel):
- asset: AudioAsset
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/webhook_delivery.py b/src/speechify/types/webhook_delivery.py
deleted file mode 100644
index 2c17f23..0000000
--- a/src/speechify/types/webhook_delivery.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import pydantic
-from .webhook_delivery_status import WebhookDeliveryStatus
-import typing
-import datetime as dt
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class WebhookDelivery(UniversalBaseModel):
- """
- Post-call webhook delivery log row. One row per
- `(conversation, webhook-url)`; updated in place across retry
- attempts.
- """
-
- id: str
- conversation_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`conv_<26 char Crockford base32>`)
- of the conversation that triggered this delivery.
- """
-
- agent_id: str = pydantic.Field()
- """
- Prefixed wire identifier (`agent_<26 char Crockford base32>`)
- of the agent.
- """
-
- url: str
- event: str
- status: WebhookDeliveryStatus
- attempt_count: int
- last_attempt_at: typing.Optional[dt.datetime] = None
- last_status_code: typing.Optional[int] = None
- last_error: typing.Optional[str] = None
- created_at: dt.datetime
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/webhook_delivery_status.py b/src/speechify/types/webhook_delivery_status.py
deleted file mode 100644
index c4d1bc5..0000000
--- a/src/speechify/types/webhook_delivery_status.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-WebhookDeliveryStatus = typing.Union[typing.Literal["pending", "delivered", "failed"], typing.Any]
diff --git a/src/speechify/types/webhook_probe_result.py b/src/speechify/types/webhook_probe_result.py
deleted file mode 100644
index 83a114b..0000000
--- a/src/speechify/types/webhook_probe_result.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-import pydantic
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class WebhookProbeResult(UniversalBaseModel):
- """
- Result of a webhook probe. `ok` is true only when the endpoint
- returned a 2xx. A non-2xx response still populates `status_code`
- and `response_body` with `ok=false` — the request reached the
- endpoint, the endpoint just declined it. `error` is set only for
- transport-level failures (DNS, connect, TLS, timeout, blocked
- address range) where no response was received; `status_code` is
- absent in that case. `signed` reports whether the probe carried
- an `X-Speechify-Signature` header — false on the create-form
- flow, which has no stored secret yet. Both success and failure
- use the 200 envelope so the console renders them inline.
- """
-
- ok: bool
- status_code: typing.Optional[int] = pydantic.Field(default=None)
- """
- HTTP status the endpoint returned. Absent on a transport failure.
- """
-
- latency_ms: typing.Optional[int] = pydantic.Field(default=None)
- """
- Wall-clock round-trip time in milliseconds.
- """
-
- response_body: typing.Optional[str] = pydantic.Field(default=None)
- """
- Truncated prefix (max ~2 KiB) of the endpoint's response body.
- """
-
- signed: bool = pydantic.Field()
- """
- Whether the probe request carried an HMAC signature header.
- """
-
- error: typing.Optional[str] = pydantic.Field(default=None)
- """
- Human-readable transport-level failure reason. Absent when any response was received.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/webhook_tool_config.py b/src/speechify/types/webhook_tool_config.py
deleted file mode 100644
index 28d8eb9..0000000
--- a/src/speechify/types/webhook_tool_config.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .webhook_tool_config_method import WebhookToolConfigMethod
-import pydantic
-from .tool_param import ToolParam
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-
-
-class WebhookToolConfig(UniversalBaseModel):
- """
- Config shape for `kind=webhook`.
- """
-
- url: str
- method: typing.Optional[WebhookToolConfigMethod] = None
- headers: typing.Optional[typing.Dict[str, str]] = pydantic.Field(default=None)
- """
- Static headers sent with every call. `Authorization` and `X-Speechify-Signature` are reserved.
- """
-
- timeout_ms: typing.Optional[int] = pydantic.Field(default=None)
- """
- Per-call timeout in milliseconds. Defaults to 10000 server-side when omitted.
- """
-
- params: typing.Optional[typing.List[ToolParam]] = None
- fire_and_forget: typing.Optional[bool] = pydantic.Field(default=None)
- """
- When true the worker dispatches the HTTP request and returns
- immediately to the LLM with a synthetic "queued" result
- instead of waiting for the response body. The customer's
- endpoint is expected to enqueue the work and return any
- non-error status quickly; errors raised after dispatch are
- logged but never surfaced to the LLM. Use for long-running
- customer-side work (job triggers, async ticket creation,
- etc.) where blocking the call on the response would hurt
- the conversation. Defaults to false.
- """
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/webhook_tool_config_method.py b/src/speechify/types/webhook_tool_config_method.py
deleted file mode 100644
index f8968f7..0000000
--- a/src/speechify/types/webhook_tool_config_method.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-WebhookToolConfigMethod = typing.Union[typing.Literal["POST", "GET"], typing.Any]
diff --git a/src/speechify/types/widget_config.py b/src/speechify/types/widget_config.py
deleted file mode 100644
index e36b94f..0000000
--- a/src/speechify/types/widget_config.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .widget_config_style import WidgetConfigStyle
-from .widget_config_theme import WidgetConfigTheme
-from .widget_config_avatar import WidgetConfigAvatar
-from .widget_config_text import WidgetConfigText
-from .widget_config_terms import WidgetConfigTerms
-from .widget_config_transcript import WidgetConfigTranscript
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class WidgetConfig(UniversalBaseModel):
- """
- Customer-editable appearance + behaviour payload for the
- embedded `` pill: button text, avatar style,
- orb colours, terms-and-conditions markdown, transcript display.
- Every field is optional - empty fields fall back to the
- widget's compile-time defaults.
- """
-
- version: typing.Optional[int] = None
- style: typing.Optional[WidgetConfigStyle] = None
- theme: typing.Optional[WidgetConfigTheme] = None
- avatar: typing.Optional[WidgetConfigAvatar] = None
- text: typing.Optional[WidgetConfigText] = None
- terms: typing.Optional[WidgetConfigTerms] = None
- transcript: typing.Optional[WidgetConfigTranscript] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/widget_config_avatar.py b/src/speechify/types/widget_config_avatar.py
deleted file mode 100644
index c9ebbd2..0000000
--- a/src/speechify/types/widget_config_avatar.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from .widget_config_avatar_type import WidgetConfigAvatarType
-import typing_extensions
-from ..core.serialization import FieldMetadata
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class WidgetConfigAvatar(UniversalBaseModel):
- type: typing.Optional[WidgetConfigAvatarType] = None
- image_url: typing.Optional[str] = None
- orb_color1: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="orb_color_1")] = None
- orb_color2: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="orb_color_2")] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/widget_config_avatar_type.py b/src/speechify/types/widget_config_avatar_type.py
deleted file mode 100644
index b654b1f..0000000
--- a/src/speechify/types/widget_config_avatar_type.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-WidgetConfigAvatarType = typing.Union[typing.Literal["orb", "image"], typing.Any]
diff --git a/src/speechify/types/widget_config_style.py b/src/speechify/types/widget_config_style.py
deleted file mode 100644
index 0ba7be1..0000000
--- a/src/speechify/types/widget_config_style.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-WidgetConfigStyle = typing.Union[typing.Literal["pill", "fab"], typing.Any]
diff --git a/src/speechify/types/widget_config_terms.py b/src/speechify/types/widget_config_terms.py
deleted file mode 100644
index 51be2f9..0000000
--- a/src/speechify/types/widget_config_terms.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class WidgetConfigTerms(UniversalBaseModel):
- enabled: typing.Optional[bool] = None
- content: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/widget_config_text.py b/src/speechify/types/widget_config_text.py
deleted file mode 100644
index 9b19fe6..0000000
--- a/src/speechify/types/widget_config_text.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class WidgetConfigText(UniversalBaseModel):
- start_call: typing.Optional[str] = None
- end_call: typing.Optional[str] = None
- listening: typing.Optional[str] = None
- thinking: typing.Optional[str] = None
- speaking: typing.Optional[str] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
diff --git a/src/speechify/types/widget_config_theme.py b/src/speechify/types/widget_config_theme.py
deleted file mode 100644
index 38fa82c..0000000
--- a/src/speechify/types/widget_config_theme.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-WidgetConfigTheme = typing.Union[typing.Literal["dark", "light", "auto"], typing.Any]
diff --git a/src/speechify/types/widget_config_transcript.py b/src/speechify/types/widget_config_transcript.py
deleted file mode 100644
index 93980b3..0000000
--- a/src/speechify/types/widget_config_transcript.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-from ..core.pydantic_utilities import UniversalBaseModel
-import typing
-from ..core.pydantic_utilities import IS_PYDANTIC_V2
-import pydantic
-
-
-class WidgetConfigTranscript(UniversalBaseModel):
- enabled: typing.Optional[bool] = None
-
- if IS_PYDANTIC_V2:
- model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
- else:
-
- class Config:
- frozen = True
- smart_union = True
- extra = pydantic.Extra.allow
From d54d3864c47b8e34a934a520869fad096e555618 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:10 +0000
Subject: [PATCH 2/2] [fern-replay] Applied customizations
Patches applied (1):
- patch-3ae14425: fix(packaging): make the SDK installable from source [DRG-31]
Patches with unresolved conflicts (1):
- patch-698be8b4: chore(packaging): require python >=3.9 (drop EOL 3.8) for livekit/realtime [DRG-31]
Run `fern-replay resolve` to apply these customizations.
Patches absorbed by generator (1):
- patch-011172da: fix(packaging): make the SDK installable from source [DRG-31]
The generator now produces these customizations natively.
---
.fern/replay.lock | 146 ++++++++++++++++++++++++++++++++++++++++++++--
pyproject.toml | 8 +--
2 files changed, 143 insertions(+), 11 deletions(-)
diff --git a/.fern/replay.lock b/.fern/replay.lock
index 6c2700b..4d2d70c 100644
--- a/.fern/replay.lock
+++ b/.fern/replay.lock
@@ -12,19 +12,25 @@ generations:
cli_version: unknown
generator_versions:
fernapi/fern-python-sdk: 4.3.19
-current_generation: 92df9bc3e13b50c59afbac896a5ef5b7093e0741
+ - commit_sha: 9a6aad9348122ef915de73a17d2662d500e11bb4
+ tree_hash: 89d651fab2a5958930e6c245da1ca9aa726477b7
+ timestamp: 2026-06-17T17:42:08.017Z
+ cli_version: unknown
+ generator_versions:
+ fernapi/fern-python-sdk: 4.3.19
+current_generation: 9a6aad9348122ef915de73a17d2662d500e11bb4
patches:
- id: patch-3ae14425
- content_hash: sha256:f60544299d0e84b69fb0be022b955a9cbd7a6950b59574db65cc8068e40acb11
+ content_hash: sha256:487941b7f72636b37d1b50f7f08c21aeeb8932d2e80a6e33326c158844eab3fb
original_commit: 3ae1442513e6b91d566d7eab5b54d24fe0701a43
original_message: "fix(packaging): make the SDK installable from source [DRG-31]"
original_author: lspeechify <289678208+lspeechify@users.noreply.github.com>
- base_generation: 92df9bc3e13b50c59afbac896a5ef5b7093e0741
+ base_generation: 9a6aad9348122ef915de73a17d2662d500e11bb4
files:
- pyproject.toml
patch_content: |
diff --git a/pyproject.toml b/pyproject.toml
- index 5f9dc3c..9246d68 100644
+ index 2615901..7b358f3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,3 @@
@@ -42,7 +48,7 @@ patches:
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
- @@ -39,7 +35,7 @@ packages = [
+ @@ -39,13 +35,13 @@ packages = [
{ include = "speechify", from = "src"}
]
@@ -51,6 +57,135 @@ patches:
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.8"
+ +python = ">=3.9"
+ httpx = ">=0.21.2"
+ pydantic = ">= 1.9.2"
+ pydantic-core = "^2.18.2"
+ theirs_snapshot:
+ pyproject.toml: |
+ [tool.poetry]
+ name = "speechify-api"
+ version = "1.2.4"
+ description = "Official Speechify API SDK"
+ readme = "README.md"
+ authors = [
+ "Speechify "
+ ]
+ keywords = [
+ "speechify",
+ "ai",
+ "api",
+ "sdk",
+ "text-to-speech",
+ "tts"
+ ]
+
+ classifiers = [
+ "Intended Audience :: Developers",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Operating System :: OS Independent",
+ "Operating System :: POSIX",
+ "Operating System :: MacOS",
+ "Operating System :: POSIX :: Linux",
+ "Operating System :: Microsoft :: Windows",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Typing :: Typed"
+ ]
+ packages = [
+ { include = "speechify", from = "src"}
+ ]
+
+ [tool.poetry.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"
+ httpx = ">=0.21.2"
+ pydantic = ">= 1.9.2"
+ pydantic-core = "^2.18.2"
+ typing_extensions = ">= 4.0.0"
+
+ [tool.poetry.dev-dependencies]
+ mypy = "1.0.1"
+ pytest = "^7.4.0"
+ pytest-asyncio = "^0.23.5"
+ python-dateutil = "^2.9.0"
+ types-python-dateutil = "^2.9.0.20240316"
+ ruff = "^0.5.6"
+
+ [tool.pytest.ini_options]
+ testpaths = [ "tests" ]
+ asyncio_mode = "auto"
+
+ [tool.mypy]
+ plugins = ["pydantic.mypy"]
+
+ [tool.ruff]
+ line-length = 120
+
+
+ [build-system]
+ requires = ["poetry-core"]
+ build-backend = "poetry.core.masonry.api"
+ - id: patch-698be8b4
+ content_hash: sha256:8919a4e60253edecb7c8ccfa7b7380d73d142ea5818fcec057abebeb55b19fdd
+ original_commit: 698be8b43fe28a36979809f2f71170d0d0324101
+ original_message: "chore(packaging): require python >=3.9 (drop EOL 3.8) for livekit/realtime [DRG-31]"
+ original_author: lspeechify <289678208+lspeechify@users.noreply.github.com>
+ base_generation: 003ddd4f7a52ea9c36e137952e291b2a8e0bedc3
+ files:
+ - pyproject.toml
+ patch_content: |+
+ From 698be8b43fe28a36979809f2f71170d0d0324101 Mon Sep 17 00:00:00 2001
+ From: lspeechify <289678208+lspeechify@users.noreply.github.com>
+ Date: Wed, 17 Jun 2026 10:38:57 +0100
+ Subject: [PATCH] chore(packaging): require python >=3.9 (drop EOL 3.8) for
+ livekit/realtime [DRG-31]
+
+ Matches the generator's pyproject_python_version=>=3.9 (api PR): SDK floor
+ becomes >=3.9 and livekit is a plain dependency (no marker). 3.8 is EOL and
+ the realtime layer needs 3.9+. Keeps the source-install fix (no [project] table).
+ ---
+ pyproject.toml | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+ diff --git a/pyproject.toml b/pyproject.toml
+ index 3ca5a90..9246d68 100644
+ --- a/pyproject.toml
+ +++ b/pyproject.toml
+ @@ -19,7 +19,6 @@ 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",
+ @@ -42,9 +41,9 @@ Homepage = 'https://docs.speechify.ai'
+ Repository = 'https://github.com/speechifyinc/speechify-api-sdk-python'
+
+ [tool.poetry.dependencies]
+ -python = "^3.8"
+ +python = ">=3.9"
+ httpx = ">=0.21.2"
+ -livekit = { version = ">=1.1,<2", python = ">=3.9"}
+ +livekit = ">=1.1,<2"
+ pydantic = ">= 1.9.2"
+ pydantic-core = "^2.18.2"
+ typing_extensions = ">= 4.0.0"
+ --
+ 2.52.0
+
theirs_snapshot:
pyproject.toml: |
[tool.poetry]
@@ -125,3 +260,4 @@ patches:
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
+ status: unresolved
diff --git a/pyproject.toml b/pyproject.toml
index 2615901..7b358f3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,3 @@
-[project]
-name = "speechify-api"
-
[tool.poetry]
name = "speechify-api"
version = "1.2.4"
@@ -22,7 +19,6 @@ 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",
@@ -39,13 +35,13 @@ packages = [
{ include = "speechify", from = "src"}
]
-[project.urls]
+[tool.poetry.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.8"
+python = ">=3.9"
httpx = ">=0.21.2"
pydantic = ">= 1.9.2"
pydantic-core = "^2.18.2"