clawops 0.1.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.
- clawops-0.1.0/.claude/settings.local.json +16 -0
- clawops-0.1.0/.gitignore +10 -0
- clawops-0.1.0/PKG-INFO +244 -0
- clawops-0.1.0/README.md +213 -0
- clawops-0.1.0/docs/plans/2026-03-06-clawops-agent-design.md +468 -0
- clawops-0.1.0/docs/plans/2026-03-06-clawops-python-sdk-design.md +326 -0
- clawops-0.1.0/docs/plans/2026-03-06-clawops-python-sdk-implementation.md +4717 -0
- clawops-0.1.0/pyproject.toml +60 -0
- clawops-0.1.0/src/clawops/__init__.py +62 -0
- clawops-0.1.0/src/clawops/_base_client.py +342 -0
- clawops-0.1.0/src/clawops/_client.py +171 -0
- clawops-0.1.0/src/clawops/_constants.py +13 -0
- clawops-0.1.0/src/clawops/_exceptions.py +147 -0
- clawops-0.1.0/src/clawops/_models.py +21 -0
- clawops-0.1.0/src/clawops/_resource.py +36 -0
- clawops-0.1.0/src/clawops/_utils.py +27 -0
- clawops-0.1.0/src/clawops/_version.py +1 -0
- clawops-0.1.0/src/clawops/pagination.py +104 -0
- clawops-0.1.0/src/clawops/py.typed +0 -0
- clawops-0.1.0/src/clawops/resources/__init__.py +10 -0
- clawops-0.1.0/src/clawops/resources/accounts.py +57 -0
- clawops-0.1.0/src/clawops/resources/calls.py +219 -0
- clawops-0.1.0/src/clawops/resources/numbers.py +157 -0
- clawops-0.1.0/src/clawops/resources/sip/__init__.py +22 -0
- clawops-0.1.0/src/clawops/resources/sip/credentials.py +134 -0
- clawops-0.1.0/src/clawops/types/__init__.py +24 -0
- clawops-0.1.0/src/clawops/types/call.py +46 -0
- clawops-0.1.0/src/clawops/types/call_params.py +46 -0
- clawops-0.1.0/src/clawops/types/number.py +50 -0
- clawops-0.1.0/src/clawops/types/number_params.py +30 -0
- clawops-0.1.0/src/clawops/types/shared.py +17 -0
- clawops-0.1.0/src/clawops/types/sip/__init__.py +3 -0
- clawops-0.1.0/src/clawops/types/sip/credential.py +48 -0
- clawops-0.1.0/src/clawops/types/sip/credential_params.py +14 -0
- clawops-0.1.0/src/clawops/webhooks.py +61 -0
- clawops-0.1.0/tests/__init__.py +0 -0
- clawops-0.1.0/tests/conftest.py +16 -0
- clawops-0.1.0/tests/test_base_client.py +157 -0
- clawops-0.1.0/tests/test_calls.py +85 -0
- clawops-0.1.0/tests/test_client.py +82 -0
- clawops-0.1.0/tests/test_exceptions.py +78 -0
- clawops-0.1.0/tests/test_integration.py +135 -0
- clawops-0.1.0/tests/test_models.py +45 -0
- clawops-0.1.0/tests/test_numbers.py +69 -0
- clawops-0.1.0/tests/test_pagination.py +50 -0
- clawops-0.1.0/tests/test_params.py +33 -0
- clawops-0.1.0/tests/test_sip_credentials.py +64 -0
- clawops-0.1.0/tests/test_types.py +97 -0
- clawops-0.1.0/tests/test_utils.py +31 -0
- clawops-0.1.0/tests/test_webhooks.py +47 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Read(//Users/ghyeok/Developments/clawops/**)",
|
|
5
|
+
"WebSearch",
|
|
6
|
+
"mcp__plugin_context7_context7__resolve-library-id",
|
|
7
|
+
"mcp__plugin_context7_context7__query-docs",
|
|
8
|
+
"Bash(git:*)",
|
|
9
|
+
"Bash(pip install:*)",
|
|
10
|
+
"Bash(pytest:*)",
|
|
11
|
+
"Bash(python:*)",
|
|
12
|
+
"Bash(mypy:*)",
|
|
13
|
+
"Bash(ruff check:*)"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
clawops-0.1.0/.gitignore
ADDED
clawops-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clawops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The official Python library for the ClawOps Voice API
|
|
5
|
+
Project-URL: Homepage, https://github.com/learners-superpumped/clawops-python
|
|
6
|
+
Project-URL: Documentation, https://docs.claw-ops.com
|
|
7
|
+
Project-URL: Repository, https://github.com/learners-superpumped/clawops-python
|
|
8
|
+
Author-email: ClawOps <support@claw-ops.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx<1,>=0.23.0
|
|
22
|
+
Requires-Dist: pydantic<3,>=2.0.0
|
|
23
|
+
Requires-Dist: typing-extensions>=4.7.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: respx>=0.20; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# ClawOps Python SDK
|
|
33
|
+
|
|
34
|
+
[ClawOps Voice API](https://api.claw-ops.com/docs)의 공식 Python 라이브러리입니다.
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/clawops/)
|
|
37
|
+
[](https://pypi.org/project/clawops/)
|
|
38
|
+
|
|
39
|
+
## 설치
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install clawops
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 사용법
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from clawops import ClawOps
|
|
49
|
+
|
|
50
|
+
client = ClawOps(
|
|
51
|
+
api_key="sk_...", # 또는 CLAWOPS_API_KEY 환경변수 사용
|
|
52
|
+
account_id="AC1a2b3c4d", # 또는 CLAWOPS_ACCOUNT_ID 환경변수 사용
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 통화 (Calls)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# 발신 전화 생성
|
|
60
|
+
call = client.calls.create(
|
|
61
|
+
to="01012345678",
|
|
62
|
+
from_="07052358010",
|
|
63
|
+
url="https://my-app.com/twiml",
|
|
64
|
+
status_callback="https://my-app.com/status",
|
|
65
|
+
status_callback_event="initiated ringing answered completed",
|
|
66
|
+
)
|
|
67
|
+
print(call.call_id)
|
|
68
|
+
|
|
69
|
+
# 통화 목록 조회 (페이지네이션)
|
|
70
|
+
page = client.calls.list(status="completed", page=0, page_size=20)
|
|
71
|
+
for call in page:
|
|
72
|
+
print(call.call_id, call.status)
|
|
73
|
+
|
|
74
|
+
# 모든 통화를 자동으로 순회
|
|
75
|
+
for call in client.calls.list().auto_paging_iter():
|
|
76
|
+
print(call.call_id)
|
|
77
|
+
|
|
78
|
+
# 특정 통화 조회
|
|
79
|
+
call = client.calls.get("CAabcdef1234567890")
|
|
80
|
+
|
|
81
|
+
# 통화 종료
|
|
82
|
+
call = client.calls.update("CAabcdef1234567890", status="completed")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 전화번호 (Numbers)
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# 번호 구매
|
|
89
|
+
number = client.numbers.create(source="pool")
|
|
90
|
+
print(number.phone_number)
|
|
91
|
+
|
|
92
|
+
# 번호 목록 조회
|
|
93
|
+
numbers = client.numbers.list()
|
|
94
|
+
|
|
95
|
+
# 웹훅 URL 변경
|
|
96
|
+
number = client.numbers.update("07012340001", webhook_url="https://my-app.com/webhook")
|
|
97
|
+
|
|
98
|
+
# 번호 해제
|
|
99
|
+
client.numbers.delete("07012340001")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### SIP 자격증명 (SIP Credentials)
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# SIP 자격증명 생성
|
|
106
|
+
cred = client.sip.credentials.create(display_name="Office Phone")
|
|
107
|
+
print(cred.credential_id, cred.sip_username)
|
|
108
|
+
|
|
109
|
+
# 자격증명 목록 조회
|
|
110
|
+
creds = client.sip.credentials.list()
|
|
111
|
+
|
|
112
|
+
# 특정 자격증명 조회
|
|
113
|
+
cred = client.sip.credentials.get("clu1abc2def3ghi")
|
|
114
|
+
|
|
115
|
+
# 자격증명 삭제
|
|
116
|
+
client.sip.credentials.delete("clu1abc2def3ghi")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 멀티 계정 접근
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# 다른 계정의 리소스에 접근
|
|
123
|
+
other = client.accounts("AC_other_account_id")
|
|
124
|
+
other.calls.list()
|
|
125
|
+
other.numbers.list()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 비동기 사용법
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from clawops import AsyncClawOps
|
|
132
|
+
|
|
133
|
+
# async context manager 사용
|
|
134
|
+
async with AsyncClawOps(api_key="sk_...", account_id="AC1a2b3c4d") as client:
|
|
135
|
+
call = await client.calls.create(
|
|
136
|
+
to="01012345678",
|
|
137
|
+
from_="07052358010",
|
|
138
|
+
url="https://my-app.com/twiml",
|
|
139
|
+
)
|
|
140
|
+
print(call.call_id)
|
|
141
|
+
|
|
142
|
+
# 모든 리소스 메서드는 비동기 버전을 제공합니다
|
|
143
|
+
page = await client.calls.list(status="completed")
|
|
144
|
+
async for call in page.auto_paging_iter():
|
|
145
|
+
print(call.call_id)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## 웹훅 서명 검증
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
client.webhooks.verify(
|
|
152
|
+
url="https://my-app.com/webhook",
|
|
153
|
+
params={"CallId": "CA...", "CallStatus": "completed"},
|
|
154
|
+
signature=request.headers["X-Signature"],
|
|
155
|
+
signing_key="your_account_signing_key",
|
|
156
|
+
)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
서명이 유효하지 않으면 `WebhookVerificationError`가 발생합니다.
|
|
160
|
+
|
|
161
|
+
## 에러 처리
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from clawops import ClawOps, BadRequestError, AuthenticationError, NotFoundError
|
|
165
|
+
|
|
166
|
+
client = ClawOps()
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
call = client.calls.create(to="01012345678", from_="07052358010", url="https://...")
|
|
170
|
+
except BadRequestError as e:
|
|
171
|
+
print(f"잘못된 요청: {e.status_code} - {e.body}")
|
|
172
|
+
except AuthenticationError as e:
|
|
173
|
+
print(f"유효하지 않은 API 키: {e.status_code}")
|
|
174
|
+
except NotFoundError as e:
|
|
175
|
+
print(f"리소스를 찾을 수 없음: {e.status_code}")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `status_code`, `response`, `body`, `request` 속성을 제공합니다.
|
|
179
|
+
|
|
180
|
+
| 에러 | 상태 코드 |
|
|
181
|
+
| -------------------------- | --------- |
|
|
182
|
+
| `BadRequestError` | 400 |
|
|
183
|
+
| `AuthenticationError` | 401 |
|
|
184
|
+
| `PermissionDeniedError` | 403 |
|
|
185
|
+
| `NotFoundError` | 404 |
|
|
186
|
+
| `ConflictError` | 409 |
|
|
187
|
+
| `UnprocessableEntityError` | 422 |
|
|
188
|
+
| `InternalServerError` | 500+ |
|
|
189
|
+
| `ServiceUnavailableError` | 503 |
|
|
190
|
+
|
|
191
|
+
## 설정
|
|
192
|
+
|
|
193
|
+
### 재시도
|
|
194
|
+
|
|
195
|
+
기본적으로 `408`, `409`, `429`, `500+` 에러 시 지수 백오프로 최대 2회 재시도합니다.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
client = ClawOps(max_retries=5)
|
|
199
|
+
|
|
200
|
+
# 재시도 비활성화
|
|
201
|
+
client = ClawOps(max_retries=0)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 타임아웃
|
|
205
|
+
|
|
206
|
+
기본 타임아웃은 600초 (연결 타임아웃 5초)입니다. 클라이언트 또는 요청 단위로 변경할 수 있습니다:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
# 클라이언트 단위
|
|
210
|
+
client = ClawOps(timeout=30.0)
|
|
211
|
+
|
|
212
|
+
# 요청 단위
|
|
213
|
+
call = client.calls.create(..., timeout=10.0)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 커스텀 HTTP 클라이언트
|
|
217
|
+
|
|
218
|
+
프록시, 커스텀 인증서 등 고급 설정이 필요한 경우 `httpx.Client`를 직접 주입할 수 있습니다:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
import httpx
|
|
222
|
+
|
|
223
|
+
client = ClawOps(
|
|
224
|
+
http_client=httpx.Client(proxies="http://proxy.example.com:8080"),
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## 환경변수
|
|
229
|
+
|
|
230
|
+
| 변수 | 설명 | 필수 여부 |
|
|
231
|
+
| -------------------- | ---------------------- | ------------------------------------------- |
|
|
232
|
+
| `CLAWOPS_API_KEY` | API 키 (`sk_...`) | 예 (생성자에 전달하지 않은 경우) |
|
|
233
|
+
| `CLAWOPS_ACCOUNT_ID` | 기본 계정 ID (`AC...`) | 예 (생성자에 전달하지 않은 경우) |
|
|
234
|
+
| `CLAWOPS_BASE_URL` | API 기본 URL | 아니오 (기본값: `https://api.claw-ops.com`) |
|
|
235
|
+
|
|
236
|
+
## 요구사항
|
|
237
|
+
|
|
238
|
+
- Python 3.9+
|
|
239
|
+
- `httpx` >= 0.23.0
|
|
240
|
+
- `pydantic` >= 2.0.0
|
|
241
|
+
|
|
242
|
+
## 라이선스
|
|
243
|
+
|
|
244
|
+
Apache-2.0
|
clawops-0.1.0/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# ClawOps Python SDK
|
|
2
|
+
|
|
3
|
+
[ClawOps Voice API](https://api.claw-ops.com/docs)의 공식 Python 라이브러리입니다.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/clawops/)
|
|
6
|
+
[](https://pypi.org/project/clawops/)
|
|
7
|
+
|
|
8
|
+
## 설치
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install clawops
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 사용법
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from clawops import ClawOps
|
|
18
|
+
|
|
19
|
+
client = ClawOps(
|
|
20
|
+
api_key="sk_...", # 또는 CLAWOPS_API_KEY 환경변수 사용
|
|
21
|
+
account_id="AC1a2b3c4d", # 또는 CLAWOPS_ACCOUNT_ID 환경변수 사용
|
|
22
|
+
)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 통화 (Calls)
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# 발신 전화 생성
|
|
29
|
+
call = client.calls.create(
|
|
30
|
+
to="01012345678",
|
|
31
|
+
from_="07052358010",
|
|
32
|
+
url="https://my-app.com/twiml",
|
|
33
|
+
status_callback="https://my-app.com/status",
|
|
34
|
+
status_callback_event="initiated ringing answered completed",
|
|
35
|
+
)
|
|
36
|
+
print(call.call_id)
|
|
37
|
+
|
|
38
|
+
# 통화 목록 조회 (페이지네이션)
|
|
39
|
+
page = client.calls.list(status="completed", page=0, page_size=20)
|
|
40
|
+
for call in page:
|
|
41
|
+
print(call.call_id, call.status)
|
|
42
|
+
|
|
43
|
+
# 모든 통화를 자동으로 순회
|
|
44
|
+
for call in client.calls.list().auto_paging_iter():
|
|
45
|
+
print(call.call_id)
|
|
46
|
+
|
|
47
|
+
# 특정 통화 조회
|
|
48
|
+
call = client.calls.get("CAabcdef1234567890")
|
|
49
|
+
|
|
50
|
+
# 통화 종료
|
|
51
|
+
call = client.calls.update("CAabcdef1234567890", status="completed")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 전화번호 (Numbers)
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
# 번호 구매
|
|
58
|
+
number = client.numbers.create(source="pool")
|
|
59
|
+
print(number.phone_number)
|
|
60
|
+
|
|
61
|
+
# 번호 목록 조회
|
|
62
|
+
numbers = client.numbers.list()
|
|
63
|
+
|
|
64
|
+
# 웹훅 URL 변경
|
|
65
|
+
number = client.numbers.update("07012340001", webhook_url="https://my-app.com/webhook")
|
|
66
|
+
|
|
67
|
+
# 번호 해제
|
|
68
|
+
client.numbers.delete("07012340001")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### SIP 자격증명 (SIP Credentials)
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
# SIP 자격증명 생성
|
|
75
|
+
cred = client.sip.credentials.create(display_name="Office Phone")
|
|
76
|
+
print(cred.credential_id, cred.sip_username)
|
|
77
|
+
|
|
78
|
+
# 자격증명 목록 조회
|
|
79
|
+
creds = client.sip.credentials.list()
|
|
80
|
+
|
|
81
|
+
# 특정 자격증명 조회
|
|
82
|
+
cred = client.sip.credentials.get("clu1abc2def3ghi")
|
|
83
|
+
|
|
84
|
+
# 자격증명 삭제
|
|
85
|
+
client.sip.credentials.delete("clu1abc2def3ghi")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 멀티 계정 접근
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# 다른 계정의 리소스에 접근
|
|
92
|
+
other = client.accounts("AC_other_account_id")
|
|
93
|
+
other.calls.list()
|
|
94
|
+
other.numbers.list()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 비동기 사용법
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from clawops import AsyncClawOps
|
|
101
|
+
|
|
102
|
+
# async context manager 사용
|
|
103
|
+
async with AsyncClawOps(api_key="sk_...", account_id="AC1a2b3c4d") as client:
|
|
104
|
+
call = await client.calls.create(
|
|
105
|
+
to="01012345678",
|
|
106
|
+
from_="07052358010",
|
|
107
|
+
url="https://my-app.com/twiml",
|
|
108
|
+
)
|
|
109
|
+
print(call.call_id)
|
|
110
|
+
|
|
111
|
+
# 모든 리소스 메서드는 비동기 버전을 제공합니다
|
|
112
|
+
page = await client.calls.list(status="completed")
|
|
113
|
+
async for call in page.auto_paging_iter():
|
|
114
|
+
print(call.call_id)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 웹훅 서명 검증
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
client.webhooks.verify(
|
|
121
|
+
url="https://my-app.com/webhook",
|
|
122
|
+
params={"CallId": "CA...", "CallStatus": "completed"},
|
|
123
|
+
signature=request.headers["X-Signature"],
|
|
124
|
+
signing_key="your_account_signing_key",
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
서명이 유효하지 않으면 `WebhookVerificationError`가 발생합니다.
|
|
129
|
+
|
|
130
|
+
## 에러 처리
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from clawops import ClawOps, BadRequestError, AuthenticationError, NotFoundError
|
|
134
|
+
|
|
135
|
+
client = ClawOps()
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
call = client.calls.create(to="01012345678", from_="07052358010", url="https://...")
|
|
139
|
+
except BadRequestError as e:
|
|
140
|
+
print(f"잘못된 요청: {e.status_code} - {e.body}")
|
|
141
|
+
except AuthenticationError as e:
|
|
142
|
+
print(f"유효하지 않은 API 키: {e.status_code}")
|
|
143
|
+
except NotFoundError as e:
|
|
144
|
+
print(f"리소스를 찾을 수 없음: {e.status_code}")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `status_code`, `response`, `body`, `request` 속성을 제공합니다.
|
|
148
|
+
|
|
149
|
+
| 에러 | 상태 코드 |
|
|
150
|
+
| -------------------------- | --------- |
|
|
151
|
+
| `BadRequestError` | 400 |
|
|
152
|
+
| `AuthenticationError` | 401 |
|
|
153
|
+
| `PermissionDeniedError` | 403 |
|
|
154
|
+
| `NotFoundError` | 404 |
|
|
155
|
+
| `ConflictError` | 409 |
|
|
156
|
+
| `UnprocessableEntityError` | 422 |
|
|
157
|
+
| `InternalServerError` | 500+ |
|
|
158
|
+
| `ServiceUnavailableError` | 503 |
|
|
159
|
+
|
|
160
|
+
## 설정
|
|
161
|
+
|
|
162
|
+
### 재시도
|
|
163
|
+
|
|
164
|
+
기본적으로 `408`, `409`, `429`, `500+` 에러 시 지수 백오프로 최대 2회 재시도합니다.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
client = ClawOps(max_retries=5)
|
|
168
|
+
|
|
169
|
+
# 재시도 비활성화
|
|
170
|
+
client = ClawOps(max_retries=0)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 타임아웃
|
|
174
|
+
|
|
175
|
+
기본 타임아웃은 600초 (연결 타임아웃 5초)입니다. 클라이언트 또는 요청 단위로 변경할 수 있습니다:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# 클라이언트 단위
|
|
179
|
+
client = ClawOps(timeout=30.0)
|
|
180
|
+
|
|
181
|
+
# 요청 단위
|
|
182
|
+
call = client.calls.create(..., timeout=10.0)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 커스텀 HTTP 클라이언트
|
|
186
|
+
|
|
187
|
+
프록시, 커스텀 인증서 등 고급 설정이 필요한 경우 `httpx.Client`를 직접 주입할 수 있습니다:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
import httpx
|
|
191
|
+
|
|
192
|
+
client = ClawOps(
|
|
193
|
+
http_client=httpx.Client(proxies="http://proxy.example.com:8080"),
|
|
194
|
+
)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 환경변수
|
|
198
|
+
|
|
199
|
+
| 변수 | 설명 | 필수 여부 |
|
|
200
|
+
| -------------------- | ---------------------- | ------------------------------------------- |
|
|
201
|
+
| `CLAWOPS_API_KEY` | API 키 (`sk_...`) | 예 (생성자에 전달하지 않은 경우) |
|
|
202
|
+
| `CLAWOPS_ACCOUNT_ID` | 기본 계정 ID (`AC...`) | 예 (생성자에 전달하지 않은 경우) |
|
|
203
|
+
| `CLAWOPS_BASE_URL` | API 기본 URL | 아니오 (기본값: `https://api.claw-ops.com`) |
|
|
204
|
+
|
|
205
|
+
## 요구사항
|
|
206
|
+
|
|
207
|
+
- Python 3.9+
|
|
208
|
+
- `httpx` >= 0.23.0
|
|
209
|
+
- `pydantic` >= 2.0.0
|
|
210
|
+
|
|
211
|
+
## 라이선스
|
|
212
|
+
|
|
213
|
+
Apache-2.0
|