woise 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- woise-1.0.0/PKG-INFO +169 -0
- woise-1.0.0/README.md +151 -0
- woise-1.0.0/pyproject.toml +37 -0
- woise-1.0.0/setup.cfg +4 -0
- woise-1.0.0/src/woise/__init__.py +61 -0
- woise-1.0.0/src/woise/_core.py +350 -0
- woise-1.0.0/src/woise/agent.py +201 -0
- woise-1.0.0/src/woise/live.py +343 -0
- woise-1.0.0/src/woise/py.typed +0 -0
- woise-1.0.0/src/woise/resources.py +630 -0
- woise-1.0.0/src/woise/signature.py +27 -0
- woise-1.0.0/src/woise/types.py +242 -0
- woise-1.0.0/src/woise.egg-info/PKG-INFO +169 -0
- woise-1.0.0/src/woise.egg-info/SOURCES.txt +17 -0
- woise-1.0.0/src/woise.egg-info/dependency_links.txt +1 -0
- woise-1.0.0/src/woise.egg-info/requires.txt +8 -0
- woise-1.0.0/src/woise.egg-info/top_level.txt +1 -0
- woise-1.0.0/tests/test_live.py +182 -0
- woise-1.0.0/tests/test_sdk.py +600 -0
woise-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: woise
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Woise: voice and chat agents for your systems. Calls, campaigns, chat, live audio and webhooks.
|
|
5
|
+
Author: Woise
|
|
6
|
+
License-Expression: BSD-2-Clause
|
|
7
|
+
Project-URL: Homepage, https://woise.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Typing :: Typed
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.24
|
|
13
|
+
Provides-Extra: live
|
|
14
|
+
Requires-Dist: websockets>=12; extra == "live"
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
17
|
+
Requires-Dist: websockets>=12; extra == "dev"
|
|
18
|
+
|
|
19
|
+
# woise (Python)
|
|
20
|
+
|
|
21
|
+
Voice and chat agents for your systems: your CRM, app or phone system places
|
|
22
|
+
calls, runs campaigns, chats with agents, talks to them live, and gets the
|
|
23
|
+
results back as webhooks.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install woise # live audio: pip install "woise[live]"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Python 3.9+. One dependency (`httpx`). `Woise` is sync, `AsyncWoise` is the same
|
|
30
|
+
API with `await`. The API key picks your region: `sk-woise-us-...` talks to
|
|
31
|
+
`https://us.woise.ai`, `sk-woise-in-...` to `https://in.woise.ai`. Older keys
|
|
32
|
+
without a region need `Woise(key, region="us")`. Local dev or a partner domain:
|
|
33
|
+
`Woise(key, base_url="http://localhost:8000")`.
|
|
34
|
+
|
|
35
|
+
## Build an agent and place a call
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import os
|
|
39
|
+
from woise import Woise, Agent
|
|
40
|
+
|
|
41
|
+
woise = Woise(os.environ["WOISE_API_KEY"])
|
|
42
|
+
|
|
43
|
+
agent = Agent("Smile Dental", prompt="You are Priya, the receptionist at Smile Dental.")
|
|
44
|
+
agent.start("greet", say="Hi, this is Priya from Smile Dental.", prompt="Confirm tomorrow's visit.",
|
|
45
|
+
next={"done": "they confirmed or cancelled"})
|
|
46
|
+
agent.end("done", say="Thanks, bye.")
|
|
47
|
+
agent.after_call(collect={"outcome": "confirmed, cancelled or rescheduled"})
|
|
48
|
+
saved = woise.agents.save(agent, publish=True) # save again later = new draft
|
|
49
|
+
|
|
50
|
+
call = woise.calls.create(agent=saved, to="+14155550123", variables={"first_name": "Ravi"})
|
|
51
|
+
print(call.status, call.id) # queued, enr_...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`next` maps the step to go to, to the condition in plain words.
|
|
55
|
+
`agent.anytime("human", when="asks for a person", transfer="+14155550100")` adds a
|
|
56
|
+
step that can fire from anywhere. `agent.node(id, type, data)` adds any other node.
|
|
57
|
+
|
|
58
|
+
## Run a campaign from a CSV
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# leads.csv: phone_number,first_name,plan (every other column becomes a {{variable}})
|
|
62
|
+
campaign = woise.campaigns.create(agent=saved, contacts="leads.csv", number="+14155550100")
|
|
63
|
+
campaign.launch()
|
|
64
|
+
print(campaign.progress())
|
|
65
|
+
campaign.pause(); campaign.resume()
|
|
66
|
+
campaign.add_contacts([{"phone_number": "+14155550124", "first_name": "Sita"}])
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Get results back: `call.ended` in Flask, with the signature check
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
hook = woise.webhooks.create(url="https://crm.example.com/woise", events=["call.ended"])
|
|
73
|
+
print(hook.secret) # shown ONCE: store it as WOISE_WEBHOOK_SECRET
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from flask import Flask, abort, request
|
|
78
|
+
from woise import verify_signature
|
|
79
|
+
|
|
80
|
+
app = Flask(__name__)
|
|
81
|
+
|
|
82
|
+
@app.post("/woise")
|
|
83
|
+
def woise_event():
|
|
84
|
+
if not verify_signature(request.get_data(), request.headers.get("X-Woise-Signature"),
|
|
85
|
+
os.environ["WOISE_WEBHOOK_SECRET"]):
|
|
86
|
+
abort(401)
|
|
87
|
+
event = request.get_json()
|
|
88
|
+
print(event["event"], event["call_id"], event["call_disposition"], event["collected"])
|
|
89
|
+
return "", 204
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Events: `call.started`, `call.ended`, `chat.ended`, `campaign.finished`. Failed
|
|
93
|
+
deliveries are retried with backoff; `woise.webhooks.deliveries(hook)` shows the log.
|
|
94
|
+
|
|
95
|
+
## Chat
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
chat = woise.chats.start(saved, variables={"first_name": "Ravi"})
|
|
99
|
+
print(chat.greeting)
|
|
100
|
+
print(chat.send("Are you open on Sunday?").text)
|
|
101
|
+
chat.end()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Runs: transcripts, outcomes, recordings
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
for run in woise.runs.list(agent=saved, limit=20):
|
|
108
|
+
print(run.id, run.outcome, run.collected)
|
|
109
|
+
print(run.transcript) # "agent: ...\ncaller: ..."
|
|
110
|
+
print(woise.runs.recording_url(run)) # short-lived link
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Live voice: Twilio Media Streams -> Woise in ~20 lines
|
|
114
|
+
|
|
115
|
+
Point a Twilio `<Connect><Stream url="wss://you.example.com/twilio"/></Connect>`
|
|
116
|
+
at this relay. It forwards Twilio's messages to Woise verbatim and Woise answers
|
|
117
|
+
in the same format (media, mark, clear), so barge-in works unchanged.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import asyncio, json, os
|
|
121
|
+
import websockets
|
|
122
|
+
from woise import AsyncWoise
|
|
123
|
+
|
|
124
|
+
woise = AsyncWoise(os.environ["WOISE_API_KEY"])
|
|
125
|
+
AGENT = "wf_..." # your agent id
|
|
126
|
+
|
|
127
|
+
async def relay(twilio):
|
|
128
|
+
async with woise.live.voice(AGENT, format="twilio") as call:
|
|
129
|
+
async def up(): # Twilio -> Woise
|
|
130
|
+
async for message in twilio:
|
|
131
|
+
await call.send_raw(message)
|
|
132
|
+
async def down(): # Woise -> Twilio
|
|
133
|
+
async for event in call:
|
|
134
|
+
await twilio.send(json.dumps(event.data))
|
|
135
|
+
await asyncio.gather(up(), down())
|
|
136
|
+
|
|
137
|
+
async def main():
|
|
138
|
+
async with websockets.serve(relay, "0.0.0.0", 8080):
|
|
139
|
+
await asyncio.Future()
|
|
140
|
+
|
|
141
|
+
asyncio.run(main())
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Raw PCM16 instead (your own media server, 8/16/24 kHz mono):
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
with woise.live.voice(AGENT, sample_rate=16000) as call:
|
|
148
|
+
call.send_audio(pcm16_bytes)
|
|
149
|
+
for event in call:
|
|
150
|
+
if event.type == "audio": speaker.write(event.audio)
|
|
151
|
+
elif event.type == "interrupt": speaker.flush() # the caller barged in
|
|
152
|
+
elif event.type == "transcript": print(event.data["role"], event.text)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`woise.live.chat(agent)` is the same socket for text: `send_text`, then stream
|
|
156
|
+
`agent_text` events.
|
|
157
|
+
|
|
158
|
+
## More
|
|
159
|
+
|
|
160
|
+
- Numbers: `woise.numbers.connections()`, `.carrier_numbers(conn)`, `.import_byo(conn, ["+1..."])`,
|
|
161
|
+
`.list(connection_id=conn)`, `.attach(number, agent, connection_id=conn)`, `.detach(number, connection_id=conn)`
|
|
162
|
+
(managed numbers: `.list()`, `.attach(number, agent)`)
|
|
163
|
+
- `woise.tools.create_http("lookup_patient", url="https://crm.example.com/patients", parameters={"phone": "the caller's number"})`
|
|
164
|
+
- `woise.knowledge.add("faq.pdf")`
|
|
165
|
+
- Errors are `WoiseError` with `.status`, `.code`, `.message`, `.request_id`.
|
|
166
|
+
GET/PUT/DELETE are retried on 429/5xx; `calls.create` never is (pass
|
|
167
|
+
`idempotency_key=` to retry safely).
|
|
168
|
+
|
|
169
|
+
BSD-2-Clause.
|
woise-1.0.0/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# woise (Python)
|
|
2
|
+
|
|
3
|
+
Voice and chat agents for your systems: your CRM, app or phone system places
|
|
4
|
+
calls, runs campaigns, chats with agents, talks to them live, and gets the
|
|
5
|
+
results back as webhooks.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install woise # live audio: pip install "woise[live]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Python 3.9+. One dependency (`httpx`). `Woise` is sync, `AsyncWoise` is the same
|
|
12
|
+
API with `await`. The API key picks your region: `sk-woise-us-...` talks to
|
|
13
|
+
`https://us.woise.ai`, `sk-woise-in-...` to `https://in.woise.ai`. Older keys
|
|
14
|
+
without a region need `Woise(key, region="us")`. Local dev or a partner domain:
|
|
15
|
+
`Woise(key, base_url="http://localhost:8000")`.
|
|
16
|
+
|
|
17
|
+
## Build an agent and place a call
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import os
|
|
21
|
+
from woise import Woise, Agent
|
|
22
|
+
|
|
23
|
+
woise = Woise(os.environ["WOISE_API_KEY"])
|
|
24
|
+
|
|
25
|
+
agent = Agent("Smile Dental", prompt="You are Priya, the receptionist at Smile Dental.")
|
|
26
|
+
agent.start("greet", say="Hi, this is Priya from Smile Dental.", prompt="Confirm tomorrow's visit.",
|
|
27
|
+
next={"done": "they confirmed or cancelled"})
|
|
28
|
+
agent.end("done", say="Thanks, bye.")
|
|
29
|
+
agent.after_call(collect={"outcome": "confirmed, cancelled or rescheduled"})
|
|
30
|
+
saved = woise.agents.save(agent, publish=True) # save again later = new draft
|
|
31
|
+
|
|
32
|
+
call = woise.calls.create(agent=saved, to="+14155550123", variables={"first_name": "Ravi"})
|
|
33
|
+
print(call.status, call.id) # queued, enr_...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`next` maps the step to go to, to the condition in plain words.
|
|
37
|
+
`agent.anytime("human", when="asks for a person", transfer="+14155550100")` adds a
|
|
38
|
+
step that can fire from anywhere. `agent.node(id, type, data)` adds any other node.
|
|
39
|
+
|
|
40
|
+
## Run a campaign from a CSV
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
# leads.csv: phone_number,first_name,plan (every other column becomes a {{variable}})
|
|
44
|
+
campaign = woise.campaigns.create(agent=saved, contacts="leads.csv", number="+14155550100")
|
|
45
|
+
campaign.launch()
|
|
46
|
+
print(campaign.progress())
|
|
47
|
+
campaign.pause(); campaign.resume()
|
|
48
|
+
campaign.add_contacts([{"phone_number": "+14155550124", "first_name": "Sita"}])
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Get results back: `call.ended` in Flask, with the signature check
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
hook = woise.webhooks.create(url="https://crm.example.com/woise", events=["call.ended"])
|
|
55
|
+
print(hook.secret) # shown ONCE: store it as WOISE_WEBHOOK_SECRET
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from flask import Flask, abort, request
|
|
60
|
+
from woise import verify_signature
|
|
61
|
+
|
|
62
|
+
app = Flask(__name__)
|
|
63
|
+
|
|
64
|
+
@app.post("/woise")
|
|
65
|
+
def woise_event():
|
|
66
|
+
if not verify_signature(request.get_data(), request.headers.get("X-Woise-Signature"),
|
|
67
|
+
os.environ["WOISE_WEBHOOK_SECRET"]):
|
|
68
|
+
abort(401)
|
|
69
|
+
event = request.get_json()
|
|
70
|
+
print(event["event"], event["call_id"], event["call_disposition"], event["collected"])
|
|
71
|
+
return "", 204
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Events: `call.started`, `call.ended`, `chat.ended`, `campaign.finished`. Failed
|
|
75
|
+
deliveries are retried with backoff; `woise.webhooks.deliveries(hook)` shows the log.
|
|
76
|
+
|
|
77
|
+
## Chat
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
chat = woise.chats.start(saved, variables={"first_name": "Ravi"})
|
|
81
|
+
print(chat.greeting)
|
|
82
|
+
print(chat.send("Are you open on Sunday?").text)
|
|
83
|
+
chat.end()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Runs: transcripts, outcomes, recordings
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
for run in woise.runs.list(agent=saved, limit=20):
|
|
90
|
+
print(run.id, run.outcome, run.collected)
|
|
91
|
+
print(run.transcript) # "agent: ...\ncaller: ..."
|
|
92
|
+
print(woise.runs.recording_url(run)) # short-lived link
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Live voice: Twilio Media Streams -> Woise in ~20 lines
|
|
96
|
+
|
|
97
|
+
Point a Twilio `<Connect><Stream url="wss://you.example.com/twilio"/></Connect>`
|
|
98
|
+
at this relay. It forwards Twilio's messages to Woise verbatim and Woise answers
|
|
99
|
+
in the same format (media, mark, clear), so barge-in works unchanged.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
import asyncio, json, os
|
|
103
|
+
import websockets
|
|
104
|
+
from woise import AsyncWoise
|
|
105
|
+
|
|
106
|
+
woise = AsyncWoise(os.environ["WOISE_API_KEY"])
|
|
107
|
+
AGENT = "wf_..." # your agent id
|
|
108
|
+
|
|
109
|
+
async def relay(twilio):
|
|
110
|
+
async with woise.live.voice(AGENT, format="twilio") as call:
|
|
111
|
+
async def up(): # Twilio -> Woise
|
|
112
|
+
async for message in twilio:
|
|
113
|
+
await call.send_raw(message)
|
|
114
|
+
async def down(): # Woise -> Twilio
|
|
115
|
+
async for event in call:
|
|
116
|
+
await twilio.send(json.dumps(event.data))
|
|
117
|
+
await asyncio.gather(up(), down())
|
|
118
|
+
|
|
119
|
+
async def main():
|
|
120
|
+
async with websockets.serve(relay, "0.0.0.0", 8080):
|
|
121
|
+
await asyncio.Future()
|
|
122
|
+
|
|
123
|
+
asyncio.run(main())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Raw PCM16 instead (your own media server, 8/16/24 kHz mono):
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
with woise.live.voice(AGENT, sample_rate=16000) as call:
|
|
130
|
+
call.send_audio(pcm16_bytes)
|
|
131
|
+
for event in call:
|
|
132
|
+
if event.type == "audio": speaker.write(event.audio)
|
|
133
|
+
elif event.type == "interrupt": speaker.flush() # the caller barged in
|
|
134
|
+
elif event.type == "transcript": print(event.data["role"], event.text)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`woise.live.chat(agent)` is the same socket for text: `send_text`, then stream
|
|
138
|
+
`agent_text` events.
|
|
139
|
+
|
|
140
|
+
## More
|
|
141
|
+
|
|
142
|
+
- Numbers: `woise.numbers.connections()`, `.carrier_numbers(conn)`, `.import_byo(conn, ["+1..."])`,
|
|
143
|
+
`.list(connection_id=conn)`, `.attach(number, agent, connection_id=conn)`, `.detach(number, connection_id=conn)`
|
|
144
|
+
(managed numbers: `.list()`, `.attach(number, agent)`)
|
|
145
|
+
- `woise.tools.create_http("lookup_patient", url="https://crm.example.com/patients", parameters={"phone": "the caller's number"})`
|
|
146
|
+
- `woise.knowledge.add("faq.pdf")`
|
|
147
|
+
- Errors are `WoiseError` with `.status`, `.code`, `.message`, `.request_id`.
|
|
148
|
+
GET/PUT/DELETE are retried on 429/5xx; `calls.create` never is (pass
|
|
149
|
+
`idempotency_key=` to retry safely).
|
|
150
|
+
|
|
151
|
+
BSD-2-Clause.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "woise"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Woise: voice and chat agents for your systems. Calls, campaigns, chat, live audio and webhooks."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "BSD-2-Clause"
|
|
12
|
+
authors = [{ name = "Woise" }]
|
|
13
|
+
dependencies = ["httpx>=0.24"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Typing :: Typed",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
live = ["websockets>=12"]
|
|
21
|
+
dev = ["pytest>=7", "websockets>=12"]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://woise.ai"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
where = ["src"]
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.package-data]
|
|
30
|
+
woise = ["py.typed"]
|
|
31
|
+
|
|
32
|
+
[tool.pytest.ini_options]
|
|
33
|
+
testpaths = ["tests"]
|
|
34
|
+
|
|
35
|
+
[tool.ruff]
|
|
36
|
+
target-version = "py39"
|
|
37
|
+
line-length = 100
|
woise-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Woise: voice and chat agents for your systems.
|
|
2
|
+
|
|
3
|
+
from woise import Woise, Agent
|
|
4
|
+
woise = Woise("sk-woise-us-...")
|
|
5
|
+
woise.calls.create(agent="wf_...", to="+14155550123")
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from ._core import AsyncTransport, SyncTransport, WoiseError, cell_from_key
|
|
11
|
+
from .agent import Agent
|
|
12
|
+
from .live import LiveEvent
|
|
13
|
+
from .signature import SIGNATURE_HEADER, sign, verify_signature
|
|
14
|
+
from .types import (
|
|
15
|
+
Call,
|
|
16
|
+
Campaign,
|
|
17
|
+
ChatReply,
|
|
18
|
+
Document,
|
|
19
|
+
Number,
|
|
20
|
+
Run,
|
|
21
|
+
SavedAgent,
|
|
22
|
+
Tool,
|
|
23
|
+
Webhook,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__version__ = "1.0.0"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Woise(SyncTransport):
|
|
30
|
+
"""The Woise client. ``Woise(api_key)``; the key picks the region.
|
|
31
|
+
|
|
32
|
+
Options: ``base_url`` (local dev, partner domains), ``region`` ("us"/"in")
|
|
33
|
+
for old keys without a region, ``timeout`` (seconds), ``max_retries``.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AsyncWoise(AsyncTransport):
|
|
38
|
+
"""Same as ``Woise``, every method is ``await``-able."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"SIGNATURE_HEADER",
|
|
43
|
+
"Agent",
|
|
44
|
+
"AsyncWoise",
|
|
45
|
+
"Call",
|
|
46
|
+
"Campaign",
|
|
47
|
+
"ChatReply",
|
|
48
|
+
"Document",
|
|
49
|
+
"LiveEvent",
|
|
50
|
+
"Number",
|
|
51
|
+
"Run",
|
|
52
|
+
"SavedAgent",
|
|
53
|
+
"Tool",
|
|
54
|
+
"Webhook",
|
|
55
|
+
"Woise",
|
|
56
|
+
"WoiseError",
|
|
57
|
+
"__version__",
|
|
58
|
+
"cell_from_key",
|
|
59
|
+
"sign",
|
|
60
|
+
"verify_signature",
|
|
61
|
+
]
|