voiceml 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -13
- data/lib/voiceml/client.rb +53 -13
- data/lib/voiceml/errors.rb +15 -2
- data/lib/voiceml/models/accounts.rb +47 -3
- data/lib/voiceml/models/applications.rb +6 -0
- data/lib/voiceml/models/assistants_v1.rb +40 -0
- data/lib/voiceml/models/calls.rb +4 -0
- data/lib/voiceml/models/common.rb +35 -4
- data/lib/voiceml/models/conferences.rb +8 -0
- data/lib/voiceml/models/conversations_v1.rb +131 -29
- data/lib/voiceml/models/diagnostics.rb +33 -12
- data/lib/voiceml/models/exports.rb +58 -0
- data/lib/voiceml/models/incoming_phone_numbers.rb +4 -0
- data/lib/voiceml/models/media.rb +4 -0
- data/lib/voiceml/models/messages.rb +29 -0
- data/lib/voiceml/models/messaging_v1.rb +35 -2
- data/lib/voiceml/models/monitor_v1.rb +54 -0
- data/lib/voiceml/models/notifications.rb +2 -0
- data/lib/voiceml/models/outgoing_caller_ids.rb +6 -0
- data/lib/voiceml/models/payments.rb +2 -0
- data/lib/voiceml/models/pricing.rb +38 -4
- data/lib/voiceml/models/queues.rb +8 -0
- data/lib/voiceml/models/recordings.rb +5 -1
- data/lib/voiceml/models/routes_v2.rb +6 -2
- data/lib/voiceml/models/sip.rb +34 -6
- data/lib/voiceml/models/sip_registrations.rb +49 -0
- data/lib/voiceml/models/siprec.rb +5 -17
- data/lib/voiceml/models/streams.rb +4 -16
- data/lib/voiceml/models/transcriptions.rb +35 -4
- data/lib/voiceml/models/usage_records.rb +48 -0
- data/lib/voiceml/models/user_defined_messages.rb +2 -0
- data/lib/voiceml/models/voice_v1.rb +29 -19
- data/lib/voiceml/request_validator.rb +125 -0
- data/lib/voiceml/resources/accounts.rb +75 -0
- data/lib/voiceml/resources/applications.rb +3 -1
- data/lib/voiceml/resources/assistants_v1.rb +53 -77
- data/lib/voiceml/resources/base.rb +138 -16
- data/lib/voiceml/resources/calls.rb +34 -49
- data/lib/voiceml/resources/conferences.rb +26 -5
- data/lib/voiceml/resources/conversations_v1.rb +147 -172
- data/lib/voiceml/resources/diagnostics.rb +20 -35
- data/lib/voiceml/resources/exports.rb +36 -0
- data/lib/voiceml/resources/incoming_phone_numbers.rb +53 -32
- data/lib/voiceml/resources/messages.rb +79 -15
- data/lib/voiceml/resources/messaging_v1.rb +47 -13
- data/lib/voiceml/resources/monitor_v1.rb +68 -0
- data/lib/voiceml/resources/notifications.rb +1 -1
- data/lib/voiceml/resources/outgoing_caller_ids.rb +77 -0
- data/lib/voiceml/resources/pricing.rb +13 -5
- data/lib/voiceml/resources/queues.rb +6 -5
- data/lib/voiceml/resources/recordings.rb +39 -5
- data/lib/voiceml/resources/routes_v2.rb +10 -4
- data/lib/voiceml/resources/sip.rb +30 -11
- data/lib/voiceml/resources/transcriptions.rb +40 -0
- data/lib/voiceml/resources/usage_records.rb +51 -0
- data/lib/voiceml/resources/voice_v1.rb +31 -38
- data/lib/voiceml/transport.rb +277 -230
- data/lib/voiceml/version.rb +1 -1
- data/lib/voiceml.rb +14 -15
- metadata +18 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 758b40e32d36539e838ab6418d8a978b089ebfebc7754847049e47fb281e4336
|
|
4
|
+
data.tar.gz: 057dc821a03507d3883edc839e9e5e2ead794e162cef2ff76ea6bf1d6f9787d6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d88a3dc916f95b965f0899f910a0fee987d85b9d81ee33dc2dec8ce9b3d71178209e7c07999fb599d76cf172ad620b84d144459e2d3cb9ecde7e9a87e2a60dc1
|
|
7
|
+
data.tar.gz: 9aa62aaa635a1e2021ded627867cc6954eb389c16732c67ab9470fad749a6acbe64f448b7bd92dae412798196d024022d83c33ce0203f6718d0158330da8f5d5
|
data/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
The official Ruby client for the [VoiceML REST API](https://voicetel.com/docs/api/v0.9/voiceml/) — Twilio-compatible outbound voice and answering-machine-detection from VoiceTel, with idiomatic snake_case kwargs, structured errors, and a Twilio-compatible wire format.
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
7
|

|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
|
|
11
11
|
## 📚 Table of Contents
|
|
@@ -44,9 +44,11 @@ The official Ruby client for the [VoiceML REST API](https://voicetel.com/docs/ap
|
|
|
44
44
|
- **Queues** — create, list, update, delete, peek, dequeue (front or specific member).
|
|
45
45
|
- **Applications** — CRUD on stored TwiML + callback bundles.
|
|
46
46
|
- **Recordings** — account-wide list, metadata fetch, audio fetch (follows S3 redirect), delete.
|
|
47
|
-
- **Messages** — create, fetch, list (To/From/DateSent filters + pagination), update (Body redaction; Status=canceled), delete.
|
|
47
|
+
- **Messages** — create, fetch, list (To/From/DateSent filters + pagination), update (Body redaction; Status=canceled), delete, delivery feedback (`create_feedback`).
|
|
48
48
|
- **IncomingPhoneNumbers** — list, fetch, update.
|
|
49
49
|
- **Notifications** — fetch, list.
|
|
50
|
+
- **Monitor Alerts** — `client.monitor_alerts` list (severity + date-window filters) and fetch over the `/v1` `meta` envelope.
|
|
51
|
+
- **Accounts** — `client.accounts.fetch` / `update` / `fetch_balance` / `rotate_key` (key rotation returns the new key on `AccountWithKey#api_key`).
|
|
50
52
|
- **SIP** — SIP Trunking: Domains (CRUD), CredentialLists + Credentials (CRUD), IpAccessControlLists + IpAddresses (CRUD), Domain↔ACL/CredentialList mappings (historical, Auth/Calls, Auth/Registrations namespaces).
|
|
51
53
|
- **Routes V2** — Twilio Inbound Processing Region API: `client.routes_v2.sip_domains.fetch(name)` / `update(name, voice_region:, friendly_name:)`.
|
|
52
54
|
- **Messaging Service** — `client.messaging_v1.services` CRUD (`MG...` services), routed automatically at the `messaging.voicetel.com` product host.
|
|
@@ -57,7 +59,7 @@ The official Ruby client for the [VoiceML REST API](https://voicetel.com/docs/ap
|
|
|
57
59
|
VoiceML mirrors Twilio's product-per-subdomain model. The whole `conversations_v1` group is routed to `conversations.voicetel.com` and `messaging_v1` to `messaging.voicetel.com`, while everything else stays on the default `voiceml.voicetel.com`. These hosts are derived automatically from `base_url`; a non-`voicetel.com` base (e.g. a self-hosted instance) keeps every product on that single host. Override per product with `messaging_base_url:` / `conversations_base_url:` on the client constructor.
|
|
58
60
|
|
|
59
61
|
### 🧪 Tested
|
|
60
|
-
- **
|
|
62
|
+
- **227 examples** with mocked HTTP layer (`webmock`) covering every resource and pagination edge cases — spec drift gets caught at parse time.
|
|
61
63
|
- Integration smoke spec gated by env vars — safe for CI.
|
|
62
64
|
|
|
63
65
|
### 📦 Clean Distribution
|
|
@@ -77,7 +79,7 @@ Or in your `Gemfile`:
|
|
|
77
79
|
gem 'voiceml', '~> 0.7'
|
|
78
80
|
```
|
|
79
81
|
|
|
80
|
-
Requires Ruby 3.
|
|
82
|
+
Requires Ruby 3.1 or later.
|
|
81
83
|
|
|
82
84
|
## 🏁 Quickstart
|
|
83
85
|
|
|
@@ -90,8 +92,8 @@ client = VoiceML::Client.new(
|
|
|
90
92
|
)
|
|
91
93
|
|
|
92
94
|
call = client.calls.create(
|
|
93
|
-
to: '+
|
|
94
|
-
from: '+
|
|
95
|
+
to: '+14155550100',
|
|
96
|
+
from: '+14155550101',
|
|
95
97
|
url: 'https://example.com/twiml',
|
|
96
98
|
machine_detection: 'DetectMessageEnd'
|
|
97
99
|
)
|
|
@@ -105,7 +107,7 @@ end
|
|
|
105
107
|
|
|
106
108
|
## 🔑 Authentication
|
|
107
109
|
|
|
108
|
-
Every endpoint uses **HTTP Basic** with your `AccountSid` as the username and your per-tenant API key as the password —
|
|
110
|
+
Every endpoint uses **HTTP Basic** with your `AccountSid` as the username and your per-tenant API key as the password — the same positions Twilio SDKs use, so existing credential-passing code migrates unchanged. VoiceML issues its own credentials; Twilio-issued credentials do not work here.
|
|
109
111
|
|
|
110
112
|
- **Username** = your `AccountSid` (Twilio-format `AC` + 32 hex chars).
|
|
111
113
|
- **Password** = your per-tenant API key (pass as `api_key:` or, for migration-compatible drop-in, `auth_token:`).
|
|
@@ -126,9 +128,11 @@ client.diagnostics.health # uses your AccountSid + key on every call
|
|
|
126
128
|
| `client.queues` | create, list, update, delete | peek, dequeue (front or specific member) |
|
|
127
129
|
| `client.applications` | CRUD on TwiML + callback bundles | |
|
|
128
130
|
| `client.recordings` | account-wide list, metadata, audio fetch, delete | follows S3 redirect for audio |
|
|
129
|
-
| `client.messages` | create, fetch, list, update, delete | To/From/DateSent filters; Body redaction; Status=canceled |
|
|
131
|
+
| `client.messages` | create, fetch, list, update, delete, create_feedback | To/From/DateSent filters; Body redaction; Status=canceled; delivery feedback |
|
|
130
132
|
| `client.incoming_phone_numbers` | list, fetch, update | |
|
|
131
133
|
| `client.notifications` | fetch, list | |
|
|
134
|
+
| `client.monitor_alerts` | list, fetch | Monitor v1 Alerts (`/v1` `meta` envelope); severity + date-window filters |
|
|
135
|
+
| `client.accounts` | fetch, update, fetch_balance, rotate_key | rotate_key returns the new API key on `AccountWithKey#api_key` |
|
|
132
136
|
| `client.messaging_v1.services` | create, list, fetch, update, delete | Messaging Service (`MG...`); routed at `messaging.voicetel.com` |
|
|
133
137
|
| `client.pricing.v1` / `.v2` | countries.list / fetch, numbers.fetch | Voice, Messaging, PhoneNumbers, Trunking (read-only, default host) |
|
|
134
138
|
| `client.diagnostics` | `/health`, OpenAPI spec | |
|
|
@@ -139,8 +143,8 @@ Methods accept idiomatic snake_case keyword arguments — they're translated to
|
|
|
139
143
|
client = VoiceML::Client.new(account_sid: 'AC...', api_key: '...')
|
|
140
144
|
|
|
141
145
|
call = client.calls.create(
|
|
142
|
-
to: '+
|
|
143
|
-
from: '+
|
|
146
|
+
to: '+14155550100',
|
|
147
|
+
from: '+14155550101',
|
|
144
148
|
url: 'https://example.com/twiml'
|
|
145
149
|
)
|
|
146
150
|
|
|
@@ -195,7 +199,7 @@ client.calls.each(status: 'completed', page_size: 200) do |call|
|
|
|
195
199
|
end
|
|
196
200
|
|
|
197
201
|
# Enumerator form — chain with Enumerable methods
|
|
198
|
-
recent = client.messages.each(from: '+
|
|
202
|
+
recent = client.messages.each(from: '+14155550101', page_size: 200).first(50)
|
|
199
203
|
|
|
200
204
|
client.queues.each do |q|
|
|
201
205
|
archive(q) if q.current_size.zero?
|
data/lib/voiceml/client.rb
CHANGED
|
@@ -18,43 +18,66 @@ require_relative 'resources/conversations_v1'
|
|
|
18
18
|
require_relative 'resources/assistants_v1'
|
|
19
19
|
require_relative 'resources/messaging_v1'
|
|
20
20
|
require_relative 'resources/pricing'
|
|
21
|
+
require_relative 'resources/accounts'
|
|
22
|
+
require_relative 'resources/outgoing_caller_ids'
|
|
23
|
+
require_relative 'resources/exports'
|
|
24
|
+
require_relative 'resources/usage_records'
|
|
25
|
+
require_relative 'resources/transcriptions'
|
|
26
|
+
require_relative 'resources/monitor_v1'
|
|
21
27
|
|
|
22
28
|
module VoiceML
|
|
23
29
|
# Synchronous client for the VoiceML REST API.
|
|
24
30
|
#
|
|
25
31
|
# VoiceML uses HTTP Basic auth: the `account_sid` (Twilio-format `AC` + 32 hex) is the
|
|
26
|
-
# username and `api_key` is the password
|
|
27
|
-
#
|
|
32
|
+
# username and `api_key` is the password, in the same HTTP Basic positions twilio-ruby
|
|
33
|
+
# uses. VoiceML issues its own credentials — the AccountSid plus a VoiceML API key;
|
|
34
|
+
# Twilio-issued credentials do not work here.
|
|
35
|
+
#
|
|
36
|
+
# A client without an `api_key:` is a credential-less diagnostics client: only
|
|
37
|
+
# {VoiceML::DiagnosticsResource} calls work (the spec marks them `security: []`);
|
|
38
|
+
# anything authenticated raises {VoiceML::ConfigurationError}.
|
|
39
|
+
#
|
|
40
|
+
# The client is thread-safe: requests may be issued from any number of threads,
|
|
41
|
+
# each holding its own connection per host.
|
|
28
42
|
#
|
|
29
43
|
# @example
|
|
30
44
|
# client = VoiceML::Client.new(account_sid: 'AC...', api_key: '...')
|
|
31
45
|
# call = client.calls.create(
|
|
32
|
-
# to: '+
|
|
33
|
-
# from: '+
|
|
34
|
-
# url: 'https://example.com/
|
|
46
|
+
# to: '+14155550100',
|
|
47
|
+
# from: '+14155550101',
|
|
48
|
+
# url: 'https://example.com/handler'
|
|
35
49
|
# )
|
|
36
50
|
# puts call.sid, call.status
|
|
37
51
|
class Client
|
|
38
52
|
attr_reader :calls, :conferences, :queues, :applications, :recordings,
|
|
39
53
|
:incoming_phone_numbers, :notifications, :diagnostics, :messages,
|
|
40
54
|
:sip, :routes_v2, :voice_v1, :conversations_v1, :assistants_v1,
|
|
41
|
-
:messaging_v1, :pricing
|
|
55
|
+
:messaging_v1, :pricing, :accounts, :outgoing_caller_ids, :exports,
|
|
56
|
+
:usage_records, :transcriptions, :monitor_alerts
|
|
42
57
|
|
|
43
58
|
# @param account_sid [String] Twilio-format AccountSid (`AC` + 32 hex).
|
|
44
|
-
# @param api_key [String, nil] per-tenant API key. Pass either `api_key:` or
|
|
45
|
-
# Twilio-compatible alias `auth_token:` (not both — `ArgumentError` if you do).
|
|
46
|
-
#
|
|
47
|
-
#
|
|
59
|
+
# @param api_key [String, nil] per-tenant VoiceML API key. Pass either `api_key:` or
|
|
60
|
+
# the Twilio-compatible alias `auth_token:` (not both — `ArgumentError` if you do).
|
|
61
|
+
# Omit both for a credential-less diagnostics-only client.
|
|
62
|
+
# @param auth_token [String, nil] Twilio-compatible alias for `api_key`. Lets
|
|
63
|
+
# credential-passing code written for twilio-ruby keep its call shape; the key
|
|
64
|
+
# itself must be a VoiceML API key.
|
|
48
65
|
# @param base_url [String] server base URL. Defaults to `https://voiceml.voicetel.com`.
|
|
49
|
-
# @param timeout [Numeric] per-request timeout in seconds. Defaults to 30.
|
|
50
|
-
# @param max_retries [Integer] retry attempts
|
|
66
|
+
# @param timeout [Numeric] per-request connect/read/write timeout in seconds. Defaults to 30.
|
|
67
|
+
# @param max_retries [Integer] retry attempts. Idempotent requests (GET/HEAD/PUT/DELETE)
|
|
68
|
+
# retry on 429/5xx and transport errors; POST/PATCH retry only on 429 and
|
|
69
|
+
# connect-phase failures. Defaults to 2.
|
|
51
70
|
# @param user_agent [String, nil] override the `User-Agent` header. Defaults to
|
|
52
71
|
# `"voiceml-ruby/#{VERSION}"`.
|
|
72
|
+
# @param http_client [Net::HTTP, #call, nil] a `Net::HTTP` used for its own host, or a
|
|
73
|
+
# factory `->(uri) { Net::HTTP.new(uri.host, uri.port) }` supplying every
|
|
74
|
+
# connection. Caller-supplied connections are never finished by the SDK; hosts the
|
|
75
|
+
# object/factory does not cover fall back to SDK-managed connections.
|
|
53
76
|
# @param messaging_base_url [String, nil] override the host for `messaging_v1`. Defaults to
|
|
54
77
|
# the `messaging.*.voicetel.com` subdomain derived from `base_url` (else `base_url` itself).
|
|
55
78
|
# @param conversations_base_url [String, nil] override the host for `conversations_v1`. Defaults
|
|
56
79
|
# to the `conversations.*.voicetel.com` subdomain derived from `base_url` (else `base_url`).
|
|
57
|
-
def initialize(account_sid
|
|
80
|
+
def initialize(account_sid: nil, api_key: nil, auth_token: nil,
|
|
58
81
|
base_url: Transport::DEFAULT_BASE_URL,
|
|
59
82
|
timeout: Transport::DEFAULT_TIMEOUT,
|
|
60
83
|
max_retries: Transport::DEFAULT_MAX_RETRIES,
|
|
@@ -102,6 +125,12 @@ module VoiceML
|
|
|
102
125
|
@assistants_v1 = AssistantsV1Resource.new(@transport)
|
|
103
126
|
@messaging_v1 = MessagingV1Resource.new(messaging_transport)
|
|
104
127
|
@pricing = PricingResource.new(@transport)
|
|
128
|
+
@accounts = AccountsResource.new(@transport)
|
|
129
|
+
@outgoing_caller_ids = OutgoingCallerIdsResource.new(@transport)
|
|
130
|
+
@exports = ExportsResource.new(@transport)
|
|
131
|
+
@usage_records = UsageRecordsResource.new(@transport)
|
|
132
|
+
@transcriptions = TranscriptionsResource.new(@transport)
|
|
133
|
+
@monitor_alerts = MonitorAlertsResource.new(@transport)
|
|
105
134
|
end
|
|
106
135
|
|
|
107
136
|
def account_sid
|
|
@@ -111,5 +140,16 @@ module VoiceML
|
|
|
111
140
|
def base_url
|
|
112
141
|
@transport.base_url
|
|
113
142
|
end
|
|
143
|
+
|
|
144
|
+
# Close SDK-managed idle connections. The client remains usable.
|
|
145
|
+
def close
|
|
146
|
+
@transport.close
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# A redacted dump: never includes the API key.
|
|
150
|
+
def inspect
|
|
151
|
+
"#<#{self.class.name} account_sid=#{account_sid} base_url=#{base_url}>"
|
|
152
|
+
end
|
|
153
|
+
alias to_s inspect
|
|
114
154
|
end
|
|
115
155
|
end
|
data/lib/voiceml/errors.rb
CHANGED
|
@@ -43,12 +43,25 @@ module VoiceML
|
|
|
43
43
|
# HTTP 410 — recording audio is no longer available (no local file, no S3 key).
|
|
44
44
|
class GoneError < ApiError; end
|
|
45
45
|
|
|
46
|
-
# HTTP 429 — per-account rate limit exceeded.
|
|
47
|
-
|
|
46
|
+
# HTTP 429 — per-account rate limit exceeded. When the server sends a
|
|
47
|
+
# `Retry-After` header, the parsed delay in seconds is exposed on
|
|
48
|
+
# `#retry_after`.
|
|
49
|
+
class RateLimitError < ApiError
|
|
50
|
+
attr_reader :retry_after
|
|
51
|
+
|
|
52
|
+
def retry_after=(seconds)
|
|
53
|
+
@retry_after = seconds
|
|
54
|
+
end
|
|
55
|
+
end
|
|
48
56
|
|
|
49
57
|
# HTTP 501 — endpoint is mounted as a stub (e.g. UserDefinedMessages).
|
|
50
58
|
class NotImplementedAPIError < ApiError; end
|
|
51
59
|
|
|
60
|
+
# The request could not be delivered: connection failures, TLS errors,
|
|
61
|
+
# timeouts, malformed or refused redirects. The original exception is
|
|
62
|
+
# preserved as `#cause`.
|
|
63
|
+
class ConnectionError < ApiError; end
|
|
64
|
+
|
|
52
65
|
# HTTP 5xx — the server hit an error processing the request.
|
|
53
66
|
class ServerError < ApiError; end
|
|
54
67
|
|
|
@@ -6,17 +6,18 @@ module VoiceML
|
|
|
6
6
|
# Twilio-compatible Account resource. The voiceml SDK is single-account
|
|
7
7
|
# (the credential's account is implicit on every call), so this model
|
|
8
8
|
# exists primarily to decode `GET/POST /Accounts/{Sid}.json` responses
|
|
9
|
-
#
|
|
10
|
-
# echoes the account record back to the caller.
|
|
9
|
+
# in the Twilio-compatible wire format — useful for migration tooling
|
|
10
|
+
# that echoes the account record back to the caller.
|
|
11
11
|
class Account
|
|
12
12
|
ATTRIBUTES = %w[
|
|
13
|
-
sid friendly_name status type
|
|
13
|
+
sid friendly_name status type owner_account_sid
|
|
14
14
|
date_created date_updated subresource_uris uri
|
|
15
15
|
].freeze
|
|
16
16
|
|
|
17
17
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
18
18
|
|
|
19
19
|
def initialize(attrs = {})
|
|
20
|
+
@raw_attributes = attrs
|
|
20
21
|
ATTRIBUTES.each do |field|
|
|
21
22
|
value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
|
|
22
23
|
instance_variable_set("@#{field}", value)
|
|
@@ -34,11 +35,13 @@ module VoiceML
|
|
|
34
35
|
# the account's settlement currency. No `sid` field on the wire (the
|
|
35
36
|
# balance is account-scoped, not its own resource).
|
|
36
37
|
class Balance
|
|
38
|
+
include RawAttributes
|
|
37
39
|
ATTRIBUTES = %w[account_sid balance currency].freeze
|
|
38
40
|
|
|
39
41
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
40
42
|
|
|
41
43
|
def initialize(attrs = {})
|
|
44
|
+
@raw_attributes = attrs
|
|
42
45
|
ATTRIBUTES.each do |field|
|
|
43
46
|
value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
|
|
44
47
|
instance_variable_set("@#{field}", value)
|
|
@@ -51,4 +54,45 @@ module VoiceML
|
|
|
51
54
|
new(hash)
|
|
52
55
|
end
|
|
53
56
|
end
|
|
57
|
+
|
|
58
|
+
# `POST /Accounts/{Sid}/RotateKey` response — the account configuration
|
|
59
|
+
# view plus the freshly generated `api_key`. No read endpoint returns the
|
|
60
|
+
# key, so store it right away; requests signed with the previous key fail
|
|
61
|
+
# with 401 from that point on. The key is secret material and never
|
|
62
|
+
# appears in `inspect` / `to_s` output.
|
|
63
|
+
class AccountWithKey
|
|
64
|
+
include RawAttributes
|
|
65
|
+
ATTRIBUTES = %w[
|
|
66
|
+
sid api_key sip_username name phone_regions allow_cidr disabled
|
|
67
|
+
stt_fs_vendor stt_http_url stt_http_token_set tts_http_url
|
|
68
|
+
tts_http_token_set tts_engine_name tts_default_voice tts_default_language
|
|
69
|
+
stripe_secret_key_set pay_enabled sms_provider sms_allowed_providers
|
|
70
|
+
stt_allowed_providers stt_provider voice_url voice_method
|
|
71
|
+
voice_fallback_url voice_fallback_method aws_bucket aws_region
|
|
72
|
+
aws_prefix aws_access_key_id aws_secret_access_key_set aws_kms_key_id
|
|
73
|
+
created_at updated_at
|
|
74
|
+
].freeze
|
|
75
|
+
|
|
76
|
+
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
77
|
+
|
|
78
|
+
def initialize(attrs = {})
|
|
79
|
+
@raw_attributes = attrs
|
|
80
|
+
ATTRIBUTES.each do |field|
|
|
81
|
+
value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
|
|
82
|
+
instance_variable_set("@#{field}", value)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.from_hash(hash)
|
|
87
|
+
return nil if hash.nil?
|
|
88
|
+
|
|
89
|
+
new(hash)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# A redacted dump: never includes the api_key.
|
|
93
|
+
def inspect
|
|
94
|
+
"#<#{self.class.name} sid=#{@sid}>"
|
|
95
|
+
end
|
|
96
|
+
alias to_s inspect
|
|
97
|
+
end
|
|
54
98
|
end
|
|
@@ -5,16 +5,20 @@ require_relative 'common'
|
|
|
5
5
|
module VoiceML
|
|
6
6
|
# Persistent TwiML+callback bundle dispatched by `<Dial><Application>`.
|
|
7
7
|
class Application
|
|
8
|
+
include RawAttributes
|
|
8
9
|
ATTRIBUTES = %w[
|
|
9
10
|
sid account_sid friendly_name api_version voice_url voice_method
|
|
10
11
|
voice_fallback_url voice_fallback_method voice_caller_id_lookup
|
|
11
12
|
status_callback status_callback_method status_callback_event
|
|
13
|
+
message_status_callback sms_status_callback
|
|
14
|
+
sms_url sms_method sms_fallback_url sms_fallback_method
|
|
12
15
|
date_created date_updated uri
|
|
13
16
|
].freeze
|
|
14
17
|
|
|
15
18
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
16
19
|
|
|
17
20
|
def initialize(attrs = {})
|
|
21
|
+
@raw_attributes = attrs
|
|
18
22
|
ATTRIBUTES.each do |field|
|
|
19
23
|
value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
|
|
20
24
|
instance_variable_set("@#{field}", value)
|
|
@@ -30,11 +34,13 @@ module VoiceML
|
|
|
30
34
|
|
|
31
35
|
# Paginated `GET /Applications` response.
|
|
32
36
|
class ApplicationList
|
|
37
|
+
include RawAttributes
|
|
33
38
|
include Pageable
|
|
34
39
|
|
|
35
40
|
attr_reader :applications
|
|
36
41
|
|
|
37
42
|
def initialize(hash = {})
|
|
43
|
+
@raw_attributes = hash
|
|
38
44
|
assign_page_fields(hash)
|
|
39
45
|
@applications = (hash['applications'] || []).map { |a| Application.from_hash(a) }
|
|
40
46
|
end
|
|
@@ -18,21 +18,25 @@ module VoiceML
|
|
|
18
18
|
|
|
19
19
|
# AssistantsV1Assistant — `aia_asst_...`. Used by list/create/update/delete responses.
|
|
20
20
|
class AssistantsV1Assistant
|
|
21
|
+
include RawAttributes
|
|
21
22
|
ATTRIBUTES = %w[
|
|
22
23
|
account_sid customer_ai id model name owner url personality_prompt
|
|
23
24
|
date_created date_updated
|
|
24
25
|
].freeze
|
|
25
26
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
26
27
|
def initialize(attrs = {})
|
|
28
|
+
@raw_attributes = attrs
|
|
27
29
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
28
30
|
end
|
|
29
31
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
class AssistantsV1AssistantList
|
|
35
|
+
include RawAttributes
|
|
33
36
|
include V1Pageable
|
|
34
37
|
attr_reader :assistants
|
|
35
38
|
def initialize(hash = {})
|
|
39
|
+
@raw_attributes = hash
|
|
36
40
|
assign_meta_fields(hash)
|
|
37
41
|
@assistants = (hash['assistants'] || []).map { |h| AssistantsV1Assistant.from_hash(h) }
|
|
38
42
|
end
|
|
@@ -41,12 +45,14 @@ module VoiceML
|
|
|
41
45
|
# AssistantsV1AssistantWithToolsAndKnowledge — fetch-one shape that includes the
|
|
42
46
|
# attached tools and knowledge arrays inline.
|
|
43
47
|
class AssistantsV1AssistantWithToolsAndKnowledge
|
|
48
|
+
include RawAttributes
|
|
44
49
|
ATTRIBUTES = %w[
|
|
45
50
|
account_sid customer_ai id model name owner url personality_prompt
|
|
46
51
|
date_created date_updated tools knowledge
|
|
47
52
|
].freeze
|
|
48
53
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
49
54
|
def initialize(attrs = {})
|
|
55
|
+
@raw_attributes = attrs
|
|
50
56
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
51
57
|
end
|
|
52
58
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
@@ -54,21 +60,25 @@ module VoiceML
|
|
|
54
60
|
|
|
55
61
|
# AssistantsV1Tool — `aia_tool_...`.
|
|
56
62
|
class AssistantsV1Tool
|
|
63
|
+
include RawAttributes
|
|
57
64
|
ATTRIBUTES = %w[
|
|
58
65
|
account_sid description enabled id meta name requires_auth type url
|
|
59
66
|
date_created date_updated
|
|
60
67
|
].freeze
|
|
61
68
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
62
69
|
def initialize(attrs = {})
|
|
70
|
+
@raw_attributes = attrs
|
|
63
71
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
64
72
|
end
|
|
65
73
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
66
74
|
end
|
|
67
75
|
|
|
68
76
|
class AssistantsV1ToolList
|
|
77
|
+
include RawAttributes
|
|
69
78
|
include V1Pageable
|
|
70
79
|
attr_reader :tools
|
|
71
80
|
def initialize(hash = {})
|
|
81
|
+
@raw_attributes = hash
|
|
72
82
|
assign_meta_fields(hash)
|
|
73
83
|
@tools = (hash['tools'] || []).map { |h| AssistantsV1Tool.from_hash(h) }
|
|
74
84
|
end
|
|
@@ -76,12 +86,14 @@ module VoiceML
|
|
|
76
86
|
|
|
77
87
|
# AssistantsV1ToolWithPolicies — fetch-one shape that includes the policies array inline.
|
|
78
88
|
class AssistantsV1ToolWithPolicies
|
|
89
|
+
include RawAttributes
|
|
79
90
|
ATTRIBUTES = %w[
|
|
80
91
|
account_sid description enabled id meta name requires_auth type url
|
|
81
92
|
date_created date_updated policies
|
|
82
93
|
].freeze
|
|
83
94
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
84
95
|
def initialize(attrs = {})
|
|
96
|
+
@raw_attributes = attrs
|
|
85
97
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
86
98
|
end
|
|
87
99
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
@@ -89,21 +101,25 @@ module VoiceML
|
|
|
89
101
|
|
|
90
102
|
# AssistantsV1Knowledge — `aia_know_...`.
|
|
91
103
|
class AssistantsV1Knowledge
|
|
104
|
+
include RawAttributes
|
|
92
105
|
ATTRIBUTES = %w[
|
|
93
106
|
account_sid description id knowledge_source_details name status type url
|
|
94
107
|
embedding_model date_created date_updated
|
|
95
108
|
].freeze
|
|
96
109
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
97
110
|
def initialize(attrs = {})
|
|
111
|
+
@raw_attributes = attrs
|
|
98
112
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
99
113
|
end
|
|
100
114
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
101
115
|
end
|
|
102
116
|
|
|
103
117
|
class AssistantsV1KnowledgeList
|
|
118
|
+
include RawAttributes
|
|
104
119
|
include V1Pageable
|
|
105
120
|
attr_reader :knowledge
|
|
106
121
|
def initialize(hash = {})
|
|
122
|
+
@raw_attributes = hash
|
|
107
123
|
assign_meta_fields(hash)
|
|
108
124
|
@knowledge = (hash['knowledge'] || []).map { |h| AssistantsV1Knowledge.from_hash(h) }
|
|
109
125
|
end
|
|
@@ -111,9 +127,11 @@ module VoiceML
|
|
|
111
127
|
|
|
112
128
|
# AssistantsV1KnowledgeStatus — read-only ingestion status snapshot.
|
|
113
129
|
class AssistantsV1KnowledgeStatus
|
|
130
|
+
include RawAttributes
|
|
114
131
|
ATTRIBUTES = %w[account_sid status last_status date_updated].freeze
|
|
115
132
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
116
133
|
def initialize(attrs = {})
|
|
134
|
+
@raw_attributes = attrs
|
|
117
135
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
118
136
|
end
|
|
119
137
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
@@ -121,18 +139,22 @@ module VoiceML
|
|
|
121
139
|
|
|
122
140
|
# AssistantsV1KnowledgeChunk — single retrieved chunk of indexed Knowledge content.
|
|
123
141
|
class AssistantsV1KnowledgeChunk
|
|
142
|
+
include RawAttributes
|
|
124
143
|
ATTRIBUTES = %w[account_sid content metadata date_created date_updated].freeze
|
|
125
144
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
126
145
|
def initialize(attrs = {})
|
|
146
|
+
@raw_attributes = attrs
|
|
127
147
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
128
148
|
end
|
|
129
149
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
130
150
|
end
|
|
131
151
|
|
|
132
152
|
class AssistantsV1KnowledgeChunkList
|
|
153
|
+
include RawAttributes
|
|
133
154
|
include V1Pageable
|
|
134
155
|
attr_reader :chunks
|
|
135
156
|
def initialize(hash = {})
|
|
157
|
+
@raw_attributes = hash
|
|
136
158
|
assign_meta_fields(hash)
|
|
137
159
|
@chunks = (hash['chunks'] || []).map { |h| AssistantsV1KnowledgeChunk.from_hash(h) }
|
|
138
160
|
end
|
|
@@ -140,20 +162,24 @@ module VoiceML
|
|
|
140
162
|
|
|
141
163
|
# AssistantsV1Session — a chat session between an identity and an Assistant.
|
|
142
164
|
class AssistantsV1Session
|
|
165
|
+
include RawAttributes
|
|
143
166
|
ATTRIBUTES = %w[
|
|
144
167
|
id account_sid assistant_id verified identity date_created date_updated
|
|
145
168
|
].freeze
|
|
146
169
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
147
170
|
def initialize(attrs = {})
|
|
171
|
+
@raw_attributes = attrs
|
|
148
172
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
149
173
|
end
|
|
150
174
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
151
175
|
end
|
|
152
176
|
|
|
153
177
|
class AssistantsV1SessionList
|
|
178
|
+
include RawAttributes
|
|
154
179
|
include V1Pageable
|
|
155
180
|
attr_reader :sessions
|
|
156
181
|
def initialize(hash = {})
|
|
182
|
+
@raw_attributes = hash
|
|
157
183
|
assign_meta_fields(hash)
|
|
158
184
|
@sessions = (hash['sessions'] || []).map { |h| AssistantsV1Session.from_hash(h) }
|
|
159
185
|
end
|
|
@@ -161,21 +187,25 @@ module VoiceML
|
|
|
161
187
|
|
|
162
188
|
# AssistantsV1Message — `aia_msg_...`. One message in an Assistant session.
|
|
163
189
|
class AssistantsV1Message
|
|
190
|
+
include RawAttributes
|
|
164
191
|
ATTRIBUTES = %w[
|
|
165
192
|
id account_sid assistant_id session_id identity role content meta
|
|
166
193
|
date_created date_updated
|
|
167
194
|
].freeze
|
|
168
195
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
169
196
|
def initialize(attrs = {})
|
|
197
|
+
@raw_attributes = attrs
|
|
170
198
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
171
199
|
end
|
|
172
200
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
173
201
|
end
|
|
174
202
|
|
|
175
203
|
class AssistantsV1MessageList
|
|
204
|
+
include RawAttributes
|
|
176
205
|
include V1Pageable
|
|
177
206
|
attr_reader :messages
|
|
178
207
|
def initialize(hash = {})
|
|
208
|
+
@raw_attributes = hash
|
|
179
209
|
assign_meta_fields(hash)
|
|
180
210
|
@messages = (hash['messages'] || []).map { |h| AssistantsV1Message.from_hash(h) }
|
|
181
211
|
end
|
|
@@ -184,9 +214,11 @@ module VoiceML
|
|
|
184
214
|
# AssistantsV1SendMessageResponse — POST /v1/Assistants/{id}/Messages return shape.
|
|
185
215
|
# Distinct from AssistantsV1Message: carries the model's reply body + flag/abort signals.
|
|
186
216
|
class AssistantsV1SendMessageResponse
|
|
217
|
+
include RawAttributes
|
|
187
218
|
ATTRIBUTES = %w[status flagged aborted session_id account_sid body error].freeze
|
|
188
219
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
189
220
|
def initialize(attrs = {})
|
|
221
|
+
@raw_attributes = attrs
|
|
190
222
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
191
223
|
end
|
|
192
224
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
@@ -194,21 +226,25 @@ module VoiceML
|
|
|
194
226
|
|
|
195
227
|
# AssistantsV1Feedback — `aia_fdbk_...`. Numeric score + text feedback on a message.
|
|
196
228
|
class AssistantsV1Feedback
|
|
229
|
+
include RawAttributes
|
|
197
230
|
ATTRIBUTES = %w[
|
|
198
231
|
assistant_id id account_sid user_sid message_id score session_id text
|
|
199
232
|
date_created date_updated
|
|
200
233
|
].freeze
|
|
201
234
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
202
235
|
def initialize(attrs = {})
|
|
236
|
+
@raw_attributes = attrs
|
|
203
237
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
204
238
|
end
|
|
205
239
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
206
240
|
end
|
|
207
241
|
|
|
208
242
|
class AssistantsV1FeedbackList
|
|
243
|
+
include RawAttributes
|
|
209
244
|
include V1Pageable
|
|
210
245
|
attr_reader :feedbacks
|
|
211
246
|
def initialize(hash = {})
|
|
247
|
+
@raw_attributes = hash
|
|
212
248
|
assign_meta_fields(hash)
|
|
213
249
|
@feedbacks = (hash['feedbacks'] || []).map { |h| AssistantsV1Feedback.from_hash(h) }
|
|
214
250
|
end
|
|
@@ -217,21 +253,25 @@ module VoiceML
|
|
|
217
253
|
# AssistantsV1Policy — `aia_plcy_...`. Read-only — listed under /v1/Policies (filterable
|
|
218
254
|
# by ToolId/KnowledgeId) and embedded inline on Tool fetch responses.
|
|
219
255
|
class AssistantsV1Policy
|
|
256
|
+
include RawAttributes
|
|
220
257
|
ATTRIBUTES = %w[
|
|
221
258
|
id name description account_sid user_sid type policy_details
|
|
222
259
|
date_created date_updated
|
|
223
260
|
].freeze
|
|
224
261
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
225
262
|
def initialize(attrs = {})
|
|
263
|
+
@raw_attributes = attrs
|
|
226
264
|
ATTRIBUTES.each { |f| instance_variable_set("@#{f}", attrs.key?(f) ? attrs[f] : attrs[f.to_sym]) }
|
|
227
265
|
end
|
|
228
266
|
def self.from_hash(h); h.nil? ? nil : new(h); end
|
|
229
267
|
end
|
|
230
268
|
|
|
231
269
|
class AssistantsV1PolicyList
|
|
270
|
+
include RawAttributes
|
|
232
271
|
include V1Pageable
|
|
233
272
|
attr_reader :policies
|
|
234
273
|
def initialize(hash = {})
|
|
274
|
+
@raw_attributes = hash
|
|
235
275
|
assign_meta_fields(hash)
|
|
236
276
|
@policies = (hash['policies'] || []).map { |h| AssistantsV1Policy.from_hash(h) }
|
|
237
277
|
end
|
data/lib/voiceml/models/calls.rb
CHANGED
|
@@ -6,6 +6,7 @@ module VoiceML
|
|
|
6
6
|
# A Twilio-compatible Call resource. Returned by `client.calls.create`, `client.calls.get`,
|
|
7
7
|
# `client.calls.update`, and listed in `CallList#calls`.
|
|
8
8
|
class Call
|
|
9
|
+
include RawAttributes
|
|
9
10
|
ATTRIBUTES = %w[
|
|
10
11
|
sid account_sid api_version to to_formatted from from_formatted
|
|
11
12
|
parent_call_sid caller_name forwarded_from status direction
|
|
@@ -17,6 +18,7 @@ module VoiceML
|
|
|
17
18
|
attr_reader(*ATTRIBUTES.map(&:to_sym))
|
|
18
19
|
|
|
19
20
|
def initialize(attrs = {})
|
|
21
|
+
@raw_attributes = attrs
|
|
20
22
|
ATTRIBUTES.each do |field|
|
|
21
23
|
value = attrs.key?(field) ? attrs[field] : attrs[field.to_sym]
|
|
22
24
|
instance_variable_set("@#{field}", value)
|
|
@@ -32,11 +34,13 @@ module VoiceML
|
|
|
32
34
|
|
|
33
35
|
# Paginated `GET /Calls` response.
|
|
34
36
|
class CallList
|
|
37
|
+
include RawAttributes
|
|
35
38
|
include Pageable
|
|
36
39
|
|
|
37
40
|
attr_reader :calls
|
|
38
41
|
|
|
39
42
|
def initialize(hash = {})
|
|
43
|
+
@raw_attributes = hash
|
|
40
44
|
assign_page_fields(hash)
|
|
41
45
|
@calls = (hash['calls'] || []).map { |c| Call.from_hash(c) }
|
|
42
46
|
end
|