waken-sdk 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.
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: waken-sdk
3
+ Version: 0.1.0
4
+ Summary: Waken SDK: persistent AI agents hosted on the cloud, from Python
5
+ License: MIT
6
+ Project-URL: Homepage, https://waken.sh
7
+ Project-URL: Documentation, https://waken.sh/docs/api
8
+ Project-URL: Source, https://github.com/medhychabour/waken
9
+ Keywords: ai,agents,waken,claude-code,codex,sdk
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+
15
+ # waken-sdk
16
+
17
+ Persistent AI agents hosted on the cloud, from Python. Installed as `waken-sdk`, imported as `waken`. A thin client over the [Waken HTTP API](https://waken.sh/docs/api), no dependencies, Python 3.9+.
18
+
19
+ ```bash
20
+ pip install waken-sdk
21
+ ```
22
+
23
+ ```python
24
+ import os
25
+ from waken import Waken
26
+
27
+ waken = Waken(api_key=os.environ["WAKEN_KEY"])
28
+
29
+ agent = waken.agents.create(
30
+ name="bookkeeper",
31
+ model={"provider": "anthropic", "api_key": os.environ["ANTHROPIC_API_KEY"]},
32
+ spend_cap_usd=10,
33
+ )
34
+
35
+ reply = waken.agents.message(agent["id"], "Sort my March receipts by vendor.")
36
+ print(reply["text"])
37
+
38
+ cp = waken.checkpoints.take(agent["id"]) # a point you can rewind to
39
+ waken.checkpoints.restore(agent["id"], cp["id"]) # rewind: files, memory, conversation
40
+ ```
41
+
42
+ Everything the API does is here: `agents` (create, list, get, delete, message, sleep, wake, restart, usage, resize, set_model, set_harness, logs, exec), `checkpoints` (take, list, restore), `files` (list, read, read_text, write, mkdir, move, delete, upload_tar), `env` (list, set), `triggers` (schedules and the agent's incoming webhook), `webhooks` (events on all your agents), `harnesses()`. Any other route: `waken.request(method, path, body)`.
43
+
44
+ Errors raise `WakenError` with `.status` and the API message.
45
+
46
+ Keys are created in the dashboard, Developers. An agent runs on your own model key, passed at creation and never stored by Waken.
@@ -0,0 +1,32 @@
1
+ # waken-sdk
2
+
3
+ Persistent AI agents hosted on the cloud, from Python. Installed as `waken-sdk`, imported as `waken`. A thin client over the [Waken HTTP API](https://waken.sh/docs/api), no dependencies, Python 3.9+.
4
+
5
+ ```bash
6
+ pip install waken-sdk
7
+ ```
8
+
9
+ ```python
10
+ import os
11
+ from waken import Waken
12
+
13
+ waken = Waken(api_key=os.environ["WAKEN_KEY"])
14
+
15
+ agent = waken.agents.create(
16
+ name="bookkeeper",
17
+ model={"provider": "anthropic", "api_key": os.environ["ANTHROPIC_API_KEY"]},
18
+ spend_cap_usd=10,
19
+ )
20
+
21
+ reply = waken.agents.message(agent["id"], "Sort my March receipts by vendor.")
22
+ print(reply["text"])
23
+
24
+ cp = waken.checkpoints.take(agent["id"]) # a point you can rewind to
25
+ waken.checkpoints.restore(agent["id"], cp["id"]) # rewind: files, memory, conversation
26
+ ```
27
+
28
+ Everything the API does is here: `agents` (create, list, get, delete, message, sleep, wake, restart, usage, resize, set_model, set_harness, logs, exec), `checkpoints` (take, list, restore), `files` (list, read, read_text, write, mkdir, move, delete, upload_tar), `env` (list, set), `triggers` (schedules and the agent's incoming webhook), `webhooks` (events on all your agents), `harnesses()`. Any other route: `waken.request(method, path, body)`.
29
+
30
+ Errors raise `WakenError` with `.status` and the API message.
31
+
32
+ Keys are created in the dashboard, Developers. An agent runs on your own model key, passed at creation and never stored by Waken.
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "waken-sdk"
7
+ version = "0.1.0"
8
+ description = "Waken SDK: persistent AI agents hosted on the cloud, from Python"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.9"
12
+ keywords = ["ai", "agents", "waken", "claude-code", "codex", "sdk"]
13
+ classifiers = ["Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License"]
14
+
15
+ [project.urls]
16
+ Homepage = "https://waken.sh"
17
+ Documentation = "https://waken.sh/docs/api"
18
+ Source = "https://github.com/medhychabour/waken"
19
+
20
+ [tool.setuptools]
21
+ packages = ["waken"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,227 @@
1
+ """Waken SDK for Python. A thin, dependency-free client over the HTTP API (https://waken.sh/docs/api).
2
+
3
+ from waken import Waken
4
+ waken = Waken(api_key=os.environ["WAKEN_KEY"])
5
+ agent = waken.agents.create(name="bookkeeper", model={"provider": "anthropic", "api_key": "sk-ant-..."})
6
+ print(waken.agents.message(agent["id"], "Sort my March receipts by vendor.")["text"])
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import urllib.error
12
+ import urllib.parse
13
+ import urllib.request
14
+ from typing import Any, Optional
15
+
16
+ __all__ = ["Waken", "WakenError"]
17
+ __version__ = "0.1.0"
18
+
19
+
20
+ class WakenError(Exception):
21
+ def __init__(self, status: int, message: str, body: Any = None):
22
+ super().__init__(message)
23
+ self.status, self.body = status, body
24
+
25
+
26
+ class Waken:
27
+ def __init__(self, api_key: str, base_url: str = "https://api.waken.sh", timeout: float = 60.0):
28
+ if not api_key:
29
+ raise ValueError("api_key is required: create one in the dashboard, Developers")
30
+ self._key, self._base, self._timeout = api_key, base_url.rstrip("/"), timeout
31
+ self.agents = _Agents(self)
32
+ self.checkpoints = _Checkpoints(self)
33
+ self.files = _Files(self)
34
+ self.env = _Env(self)
35
+ self.triggers = _Triggers(self)
36
+ self.webhooks = _Webhooks(self)
37
+
38
+ # Low level: any route. body may be a dict (sent as JSON), str or bytes (sent as is), or None.
39
+ def request(self, method: str, path: str, body: Any = None, timeout: Optional[float] = None, raw: bool = False, content_type: Optional[str] = None) -> Any:
40
+ headers = {"Authorization": f"Bearer {self._key}"}
41
+ data = None
42
+ if body is not None:
43
+ if isinstance(body, (str, bytes)):
44
+ data = body.encode() if isinstance(body, str) else body
45
+ headers["Content-Type"] = content_type or "application/octet-stream"
46
+ else:
47
+ data = json.dumps(body).encode()
48
+ headers["Content-Type"] = "application/json"
49
+ req = urllib.request.Request(self._base + path, data=data, method=method, headers=headers)
50
+ try:
51
+ with urllib.request.urlopen(req, timeout=timeout or self._timeout) as r:
52
+ payload = r.read()
53
+ except urllib.error.HTTPError as e:
54
+ text = e.read().decode(errors="replace")
55
+ try:
56
+ j = json.loads(text)
57
+ msg = j.get("error") if isinstance(j, dict) else None
58
+ except ValueError:
59
+ j, msg = text, None
60
+ raise WakenError(e.code, msg or f"{method} {path}: HTTP {e.code}", j) from None
61
+ if raw:
62
+ return payload
63
+ if not payload:
64
+ return None
65
+ try:
66
+ return json.loads(payload)
67
+ except ValueError:
68
+ return {"raw": payload.decode(errors="replace")}
69
+
70
+ def harnesses(self) -> list:
71
+ return self.request("GET", "/harnesses")
72
+
73
+
74
+ class _Agents:
75
+ def __init__(self, c: Waken):
76
+ self._c = c
77
+
78
+ def create(self, **agent: Any) -> dict:
79
+ """name, harness, model={provider, name, api_key}, env, spend_cap_usd, idle_s, external_id, mem_mib, disk_gib,
80
+ desktop, image, command, port, registry_auth, repo, repo_ref, repo_token."""
81
+ return self._c.request("POST", "/agents", agent, timeout=180)
82
+
83
+ def list(self, external_id: Optional[str] = None) -> list:
84
+ q = f"?external_id={urllib.parse.quote(external_id)}" if external_id else ""
85
+ return self._c.request("GET", "/agents" + q)
86
+
87
+ def get(self, id: str) -> dict:
88
+ return self._c.request("GET", f"/agents/{id}")
89
+
90
+ def delete(self, id: str) -> dict:
91
+ return self._c.request("DELETE", f"/agents/{id}")
92
+
93
+ def message(self, id: str, text: str, timeout: float = 600) -> dict:
94
+ """Talk to the agent. Wakes it if needed; the call stays open until it answers."""
95
+ return self._c.request("POST", f"/agents/{id}/message", {"text": text}, timeout=timeout)
96
+
97
+ def sleep(self, id: str) -> dict:
98
+ return self._c.request("POST", f"/agents/{id}/sleep", timeout=120)
99
+
100
+ def wake(self, id: str) -> dict:
101
+ return self._c.request("POST", f"/agents/{id}/wake", timeout=120)
102
+
103
+ def restart(self, id: str) -> dict:
104
+ return self._c.request("POST", f"/agents/{id}/restart")
105
+
106
+ def usage(self, id: str) -> dict:
107
+ return self._c.request("GET", f"/agents/{id}/usage")
108
+
109
+ def resize(self, id: str, mem_mib: Optional[int] = None, disk_gib: Optional[int] = None) -> dict:
110
+ body = {k: v for k, v in (("mem_mib", mem_mib), ("disk_gib", disk_gib)) if v}
111
+ return self._c.request("PUT", f"/agents/{id}/size", body, timeout=180)
112
+
113
+ def set_model(self, id: str, model: dict) -> dict:
114
+ return self._c.request("PUT", f"/agents/{id}/model", {"model": model})
115
+
116
+ def set_harness(self, id: str, harness: str, model: dict) -> dict:
117
+ return self._c.request("PUT", f"/agents/{id}/harness", {"harness": harness, "model": model}, timeout=180)
118
+
119
+ def logs(self, id: str, lines: int = 100) -> dict:
120
+ return self._c.request("GET", f"/agents/{id}/logs?lines={lines}")
121
+
122
+ def exec(self, id: str, command: str, timeout_s: int = 60) -> dict:
123
+ return self._c.request("POST", f"/agents/{id}/exec", {"command": command, "timeout_s": timeout_s}, timeout=timeout_s + 30)
124
+
125
+
126
+ class _Checkpoints:
127
+ def __init__(self, c: Waken):
128
+ self._c = c
129
+
130
+ def take(self, id: str) -> dict:
131
+ return self._c.request("POST", f"/agents/{id}/snapshot", timeout=180)
132
+
133
+ def list(self, id: str) -> list:
134
+ return self._c.request("GET", f"/agents/{id}/snapshots")
135
+
136
+ def restore(self, id: str, snapshot_id: Optional[str] = None) -> dict:
137
+ """Rewind to a checkpoint, or to the latest one when snapshot_id is omitted."""
138
+ return self._c.request("POST", f"/agents/{id}/restore", {"snapshot_id": snapshot_id} if snapshot_id else {}, timeout=180)
139
+
140
+
141
+ class _Files:
142
+ """Paths are relative to the agent's working folder."""
143
+
144
+ def __init__(self, c: Waken):
145
+ self._c = c
146
+
147
+ def list(self, id: str, path: str = "") -> Any:
148
+ return self._c.request("GET", f"/agents/{id}/files/list?path={urllib.parse.quote(path)}")
149
+
150
+ def read(self, id: str, path: str) -> bytes:
151
+ return self._c.request("GET", f"/agents/{id}/files/download?path={urllib.parse.quote(path)}", raw=True)
152
+
153
+ def read_text(self, id: str, path: str) -> str:
154
+ return self.read(id, path).decode()
155
+
156
+ def write(self, id: str, path: str, content: Any) -> Any:
157
+ return self._c.request("PUT", f"/agents/{id}/files/write?path={urllib.parse.quote(path)}", content)
158
+
159
+ def mkdir(self, id: str, path: str) -> Any:
160
+ return self._c.request("POST", f"/agents/{id}/files/mkdir", {"path": path})
161
+
162
+ def move(self, id: str, src: str, dst: str) -> Any:
163
+ return self._c.request("POST", f"/agents/{id}/files/move", {"from": src, "to": dst})
164
+
165
+ def delete(self, id: str, path: str) -> Any:
166
+ return self._c.request("DELETE", f"/agents/{id}/files/delete?path={urllib.parse.quote(path)}")
167
+
168
+ def upload_tar(self, id: str, tar_gz: bytes) -> dict:
169
+ """Upload a whole folder as a gzipped tarball."""
170
+ return self._c.request("POST", f"/agents/{id}/files", tar_gz, timeout=300, content_type="application/gzip")
171
+
172
+
173
+ class _Env:
174
+ """Environment variables of an agent. Values are never returned."""
175
+
176
+ def __init__(self, c: Waken):
177
+ self._c = c
178
+
179
+ def list(self, id: str) -> dict:
180
+ return self._c.request("GET", f"/agents/{id}/env")
181
+
182
+ def set(self, id: str, env: dict, unset: Optional[list] = None, reload: bool = False) -> Any:
183
+ return self._c.request("PUT", f"/agents/{id}/env", {"env": env, "unset": unset or [], "reload": reload})
184
+
185
+
186
+ class _Triggers:
187
+ """Schedules, and the incoming webhook of an agent."""
188
+
189
+ def __init__(self, c: Waken):
190
+ self._c = c
191
+
192
+ def list(self, id: str) -> list:
193
+ return self._c.request("GET", f"/agents/{id}/triggers")
194
+
195
+ def create(self, id: str, cron: str, message: str) -> dict:
196
+ return self._c.request("POST", f"/agents/{id}/triggers", {"cron": cron, "message": message})
197
+
198
+ def delete(self, id: str, tid: str) -> Any:
199
+ return self._c.request("DELETE", f"/agents/{id}/triggers/{tid}")
200
+
201
+ def run(self, id: str, tid: str) -> Any:
202
+ return self._c.request("POST", f"/agents/{id}/triggers/{tid}/run", timeout=600)
203
+
204
+ def webhook(self, id: str) -> dict:
205
+ return self._c.request("GET", f"/agents/{id}/webhook")
206
+
207
+ def rotate_webhook(self, id: str) -> dict:
208
+ return self._c.request("POST", f"/agents/{id}/webhook/rotate")
209
+
210
+
211
+ class _Webhooks:
212
+ """Outgoing webhooks: events on all your agents."""
213
+
214
+ def __init__(self, c: Waken):
215
+ self._c = c
216
+
217
+ def list(self) -> list:
218
+ return self._c.request("GET", "/webhooks")
219
+
220
+ def create(self, url: str, events: Optional[list] = None) -> dict:
221
+ body: dict = {"url": url}
222
+ if events:
223
+ body["events"] = events
224
+ return self._c.request("POST", "/webhooks", body)
225
+
226
+ def delete(self, wid: str) -> Any:
227
+ return self._c.request("DELETE", f"/webhooks/{wid}")
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: waken-sdk
3
+ Version: 0.1.0
4
+ Summary: Waken SDK: persistent AI agents hosted on the cloud, from Python
5
+ License: MIT
6
+ Project-URL: Homepage, https://waken.sh
7
+ Project-URL: Documentation, https://waken.sh/docs/api
8
+ Project-URL: Source, https://github.com/medhychabour/waken
9
+ Keywords: ai,agents,waken,claude-code,codex,sdk
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+
15
+ # waken-sdk
16
+
17
+ Persistent AI agents hosted on the cloud, from Python. Installed as `waken-sdk`, imported as `waken`. A thin client over the [Waken HTTP API](https://waken.sh/docs/api), no dependencies, Python 3.9+.
18
+
19
+ ```bash
20
+ pip install waken-sdk
21
+ ```
22
+
23
+ ```python
24
+ import os
25
+ from waken import Waken
26
+
27
+ waken = Waken(api_key=os.environ["WAKEN_KEY"])
28
+
29
+ agent = waken.agents.create(
30
+ name="bookkeeper",
31
+ model={"provider": "anthropic", "api_key": os.environ["ANTHROPIC_API_KEY"]},
32
+ spend_cap_usd=10,
33
+ )
34
+
35
+ reply = waken.agents.message(agent["id"], "Sort my March receipts by vendor.")
36
+ print(reply["text"])
37
+
38
+ cp = waken.checkpoints.take(agent["id"]) # a point you can rewind to
39
+ waken.checkpoints.restore(agent["id"], cp["id"]) # rewind: files, memory, conversation
40
+ ```
41
+
42
+ Everything the API does is here: `agents` (create, list, get, delete, message, sleep, wake, restart, usage, resize, set_model, set_harness, logs, exec), `checkpoints` (take, list, restore), `files` (list, read, read_text, write, mkdir, move, delete, upload_tar), `env` (list, set), `triggers` (schedules and the agent's incoming webhook), `webhooks` (events on all your agents), `harnesses()`. Any other route: `waken.request(method, path, body)`.
43
+
44
+ Errors raise `WakenError` with `.status` and the API message.
45
+
46
+ Keys are created in the dashboard, Developers. An agent runs on your own model key, passed at creation and never stored by Waken.
@@ -0,0 +1,7 @@
1
+ README.md
2
+ pyproject.toml
3
+ waken/__init__.py
4
+ waken_sdk.egg-info/PKG-INFO
5
+ waken_sdk.egg-info/SOURCES.txt
6
+ waken_sdk.egg-info/dependency_links.txt
7
+ waken_sdk.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ waken