cycls 0.0.2.93__py3-none-any.whl
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.
- cycls/__init__.py +14 -0
- cycls/app.py +91 -0
- cycls/auth.py +4 -0
- cycls/cli.py +104 -0
- cycls/function.py +407 -0
- cycls/state.py +6 -0
- cycls/themes/default/assets/index-Xh0IeurI.js +435 -0
- cycls/themes/default/assets/index-oGkkm3Z8.css +1 -0
- cycls/themes/default/index.html +32 -0
- cycls/themes/dev/index.html +298 -0
- cycls/web.py +171 -0
- cycls-0.0.2.93.dist-info/METADATA +282 -0
- cycls-0.0.2.93.dist-info/RECORD +15 -0
- cycls-0.0.2.93.dist-info/WHEEL +4 -0
- cycls-0.0.2.93.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cycls
|
|
3
|
+
Version: 0.0.2.93
|
|
4
|
+
Summary: Distribute Intelligence
|
|
5
|
+
Author-email: "Mohammed J. AlRujayi" <mj@cycls.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: cloudpickle>=3.1.1
|
|
8
|
+
Requires-Dist: docker>=7.1.0
|
|
9
|
+
Requires-Dist: email-validator>=2.0.0
|
|
10
|
+
Requires-Dist: fastapi>=0.111.0
|
|
11
|
+
Requires-Dist: httpx>=0.27.0
|
|
12
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
13
|
+
Requires-Dist: uvicorn>=0.30.0
|
|
14
|
+
Requires-Dist: watchfiles>=1.0.0
|
|
15
|
+
Provides-Extra: state
|
|
16
|
+
Requires-Dist: agentfs-sdk==0.4.0; extra == 'state'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
<h3 align="center">
|
|
20
|
+
Distribute Intelligence
|
|
21
|
+
</h3>
|
|
22
|
+
|
|
23
|
+
<h4 align="center">
|
|
24
|
+
<a href="https://cycls.com">Website</a> |
|
|
25
|
+
<a href="https://docs.cycls.com">Docs</a> |
|
|
26
|
+
<a href="docs/tutorial.md">Tutorial</a>
|
|
27
|
+
</h4>
|
|
28
|
+
|
|
29
|
+
<h4 align="center">
|
|
30
|
+
<a href="https://pypi.python.org/pypi/cycls"><img src="https://img.shields.io/pypi/v/cycls.svg?label=cycls+pypi&color=blueviolet" alt="cycls Python package on PyPi" /></a>
|
|
31
|
+
<a href="https://github.com/Cycls/cycls/actions/workflows/tests.yml"><img src="https://github.com/Cycls/cycls/actions/workflows/tests.yml/badge.svg" alt="Tests" /></a>
|
|
32
|
+
<a href="https://blog.cycls.com"><img src="https://img.shields.io/badge/newsletter-blueviolet.svg?logo=substack&label=cycls" alt="Cycls newsletter" /></a>
|
|
33
|
+
<a href="https://x.com/cyclsai">
|
|
34
|
+
<img src="https://img.shields.io/twitter/follow/CyclsAI" alt="Cycls Twitter" />
|
|
35
|
+
</a>
|
|
36
|
+
</h4>
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# Cycls
|
|
41
|
+
|
|
42
|
+
The open-source SDK for distributing AI agents.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Agent extends App (prompts, skills)
|
|
46
|
+
└── App extends Function (web UI)
|
|
47
|
+
└── Function (containerization)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Distribute Intelligence
|
|
51
|
+
|
|
52
|
+
Write a function. Deploy it as an API, a web interface, or both. Add authentication, analytics, and monetization with flags.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import cycls
|
|
56
|
+
|
|
57
|
+
cycls.api_key = "YOUR_CYCLS_API_KEY"
|
|
58
|
+
|
|
59
|
+
@cycls.app(pip=["openai"])
|
|
60
|
+
async def app(context):
|
|
61
|
+
from openai import AsyncOpenAI
|
|
62
|
+
client = AsyncOpenAI()
|
|
63
|
+
|
|
64
|
+
stream = await client.responses.create(
|
|
65
|
+
model="o3-mini",
|
|
66
|
+
input=context.messages,
|
|
67
|
+
stream=True,
|
|
68
|
+
reasoning={"effort": "medium", "summary": "auto"},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
async for event in stream:
|
|
72
|
+
if event.type == "response.reasoning_summary_text.delta":
|
|
73
|
+
yield {"type": "thinking", "thinking": event.delta} # Renders as thinking bubble
|
|
74
|
+
elif event.type == "response.output_text.delta":
|
|
75
|
+
yield event.delta
|
|
76
|
+
|
|
77
|
+
app.deploy() # Live at https://agent.cycls.ai
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Installation
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install cycls
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Requires Docker. See the [full tutorial](docs/tutorial.md) for a comprehensive guide.
|
|
87
|
+
|
|
88
|
+
## What You Get
|
|
89
|
+
|
|
90
|
+
- **Streaming API** - OpenAI-compatible `/chat/completions` endpoint
|
|
91
|
+
- **Web Interface** - Chat UI served automatically
|
|
92
|
+
- **Authentication** - `auth=True` enables JWT-based access control
|
|
93
|
+
- **Analytics** - `analytics=True` tracks usage
|
|
94
|
+
- **Monetization** - `plan="cycls_pass"` integrates with [Cycls Pass](https://cycls.ai) subscriptions
|
|
95
|
+
- **Native UI Components** - Render thinking bubbles, tables, code blocks in responses
|
|
96
|
+
|
|
97
|
+
## Running
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
app.local() # Development with hot-reload (localhost:8080)
|
|
101
|
+
app.local(watch=False) # Development without hot-reload
|
|
102
|
+
app.deploy() # Production: https://agent.cycls.ai
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Get an API key at [cycls.com](https://cycls.com).
|
|
106
|
+
|
|
107
|
+
## Authentication & Analytics
|
|
108
|
+
|
|
109
|
+
See the [tutorial](docs/tutorial.md#authentication) for full auth and monetization examples.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
@cycls.app(pip=["openai"], auth=True, analytics=True)
|
|
113
|
+
async def app(context):
|
|
114
|
+
# context.user available when auth=True
|
|
115
|
+
user = context.user # User(id, email, name, plans)
|
|
116
|
+
yield f"Hello {user.name}!"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Flag | Description |
|
|
120
|
+
|------|-------------|
|
|
121
|
+
| `auth=True` | Universal user pool via Cycls Pass (Clerk-based). You can also use your own Clerk auth. |
|
|
122
|
+
| `analytics=True` | Rich usage metrics available on the Cycls dashboard. |
|
|
123
|
+
| `plan="cycls_pass"` | Monetization via Cycls Pass subscriptions. Enables both auth and analytics. |
|
|
124
|
+
|
|
125
|
+
## Native UI Components
|
|
126
|
+
|
|
127
|
+
Yield structured objects for rich streaming responses. See the [tutorial](docs/tutorial.md#native-ui-components) for all component types and examples.
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
@cycls.app()
|
|
131
|
+
async def demo(context):
|
|
132
|
+
yield {"type": "thinking", "thinking": "Analyzing the request..."}
|
|
133
|
+
yield "Here's what I found:\n\n"
|
|
134
|
+
|
|
135
|
+
yield {"type": "table", "headers": ["Name", "Status"]}
|
|
136
|
+
yield {"type": "table", "row": ["Server 1", "Online"]}
|
|
137
|
+
yield {"type": "table", "row": ["Server 2", "Offline"]}
|
|
138
|
+
|
|
139
|
+
yield {"type": "code", "code": "result = analyze(data)", "language": "python"}
|
|
140
|
+
yield {"type": "callout", "callout": "Analysis complete!", "style": "success"}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Component | Streaming |
|
|
144
|
+
|-----------|-----------|
|
|
145
|
+
| `{"type": "thinking", "thinking": "..."}` | Yes |
|
|
146
|
+
| `{"type": "code", "code": "...", "language": "..."}` | Yes |
|
|
147
|
+
| `{"type": "table", "headers": [...]}` | Yes |
|
|
148
|
+
| `{"type": "table", "row": [...]}` | Yes |
|
|
149
|
+
| `{"type": "status", "status": "..."}` | Yes |
|
|
150
|
+
| `{"type": "callout", "callout": "...", "style": "..."}` | Yes |
|
|
151
|
+
| `{"type": "image", "src": "..."}` | Yes |
|
|
152
|
+
|
|
153
|
+
### Thinking Bubbles
|
|
154
|
+
|
|
155
|
+
The `{"type": "thinking", "thinking": "..."}` component renders as a collapsible thinking bubble in the UI. Each yield appends to the same bubble until a different component type is yielded:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# Multiple yields build one thinking bubble
|
|
159
|
+
yield {"type": "thinking", "thinking": "Let me "}
|
|
160
|
+
yield {"type": "thinking", "thinking": "analyze this..."}
|
|
161
|
+
yield {"type": "thinking", "thinking": " Done thinking."}
|
|
162
|
+
|
|
163
|
+
# Then output the response
|
|
164
|
+
yield "Here's what I found..."
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
This works seamlessly with OpenAI's reasoning models - just map reasoning summaries to the thinking component.
|
|
168
|
+
|
|
169
|
+
## Context Object
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
@cycls.app()
|
|
173
|
+
async def chat(context):
|
|
174
|
+
context.messages # [{"role": "user", "content": "..."}]
|
|
175
|
+
context.messages.raw # Full data including UI component parts
|
|
176
|
+
context.user # User(id, email, name, plans) when auth=True
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## API Endpoints
|
|
180
|
+
|
|
181
|
+
| Endpoint | Format |
|
|
182
|
+
|----------|--------|
|
|
183
|
+
| `POST chat/cycls` | Cycls streaming protocol |
|
|
184
|
+
| `POST chat/completions` | OpenAI-compatible |
|
|
185
|
+
|
|
186
|
+
## Streaming Protocol
|
|
187
|
+
|
|
188
|
+
Cycls streams structured components over SSE:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
data: {"type": "thinking", "thinking": "Let me "}
|
|
192
|
+
data: {"type": "thinking", "thinking": "analyze..."}
|
|
193
|
+
data: {"type": "text", "text": "Here's the answer"}
|
|
194
|
+
data: {"type": "callout", "callout": "Done!", "style": "success"}
|
|
195
|
+
data: [DONE]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
See [docs/streaming-protocol.md](docs/streaming-protocol.md) for frontend integration.
|
|
199
|
+
|
|
200
|
+
## Declarative Infrastructure
|
|
201
|
+
|
|
202
|
+
Define your entire runtime in the decorator. See the [tutorial](docs/tutorial.md#declarative-infrastructure) for more details.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
@cycls.app(
|
|
206
|
+
pip=["openai", "pandas", "numpy"],
|
|
207
|
+
apt=["ffmpeg", "libmagic1"],
|
|
208
|
+
copy=["./utils.py", "./models/", "/absolute/path/to/config.json"],
|
|
209
|
+
copy_public=["./assets/logo.png", "./static/"],
|
|
210
|
+
)
|
|
211
|
+
async def my_app(context):
|
|
212
|
+
...
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `pip` - Python Packages
|
|
216
|
+
|
|
217
|
+
Install any packages from PyPI. These are installed during the container build.
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
pip=["openai", "pandas", "numpy", "transformers"]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `apt` - System Packages
|
|
224
|
+
|
|
225
|
+
Install system-level dependencies via apt-get. Need ffmpeg for audio processing? ImageMagick for images? Just declare it.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
apt=["ffmpeg", "imagemagick", "libpq-dev"]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `copy` - Bundle Files and Directories
|
|
232
|
+
|
|
233
|
+
Include local files and directories in your container. Works with both relative and absolute paths. Copies files and entire directory trees.
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
copy=[
|
|
237
|
+
"./utils.py", # Single file, relative path
|
|
238
|
+
"./models/", # Entire directory
|
|
239
|
+
"/home/user/configs/app.json", # Absolute path
|
|
240
|
+
]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Then import them in your function:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
@cycls.app(copy=["./utils.py"])
|
|
247
|
+
async def chat(context):
|
|
248
|
+
from utils import helper_function # Your bundled module
|
|
249
|
+
...
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### `copy_public` - Static Files
|
|
253
|
+
|
|
254
|
+
Files and directories served at the `/public` endpoint. Perfect for images, downloads, or any static assets your agent needs to reference.
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
copy_public=["./assets/logo.png", "./downloads/"]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Access them at `https://your-app.cycls.ai/public/logo.png`.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### What You Get
|
|
265
|
+
|
|
266
|
+
- **One file** - Code, dependencies, configuration, and infrastructure together
|
|
267
|
+
- **Instant deploys** - Unchanged code deploys in seconds from cache
|
|
268
|
+
- **No drift** - What you see is what runs. Always.
|
|
269
|
+
- **Just works** - Closures, lambdas, dynamic imports - your function runs exactly as written
|
|
270
|
+
|
|
271
|
+
No YAML. No Dockerfiles. No infrastructure repo. The code is the deployment.
|
|
272
|
+
|
|
273
|
+
## Learn More
|
|
274
|
+
|
|
275
|
+
- [Tutorial](docs/tutorial.md) - Comprehensive guide from basics to advanced
|
|
276
|
+
- [Streaming Protocol](docs/streaming-protocol.md) - Frontend integration
|
|
277
|
+
- [Runtime](docs/runtime.md) - Containerization details
|
|
278
|
+
- [Examples](examples/) - Working code samples
|
|
279
|
+
|
|
280
|
+
## License
|
|
281
|
+
|
|
282
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
cycls/__init__.py,sha256=efbq0vRijGOByKtz9bRF8WQFYmnPSgZV1DH-54s6iwQ,493
|
|
2
|
+
cycls/app.py,sha256=_-RoN8JuNE7fWSOHk80GpQ2GyaoXv-vtUWc_W8tDzm0,3243
|
|
3
|
+
cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
|
|
4
|
+
cycls/cli.py,sha256=cVbIkTDnVofohvByyYUrXF_RYDQZVQECJqo7cPBPJfs,4781
|
|
5
|
+
cycls/function.py,sha256=FP94mCd5hfCASFwsTSYny7KOEsJOh3LME9oZgiVfgzo,14795
|
|
6
|
+
cycls/state.py,sha256=3RL_BqcbfiAkJ6byeEo4Q9L99VurYyYKYJJhJhEVmAo,210
|
|
7
|
+
cycls/web.py,sha256=v-hyWL9nlh4SyqAVgRzOkx96YuBntxqw6Q6phpAMDv0,6172
|
|
8
|
+
cycls/themes/default/index.html,sha256=L8tZ4RktYhVlmp48bT3Q-dvpFxz40uMHqQ_MRHoyX0s,1082
|
|
9
|
+
cycls/themes/default/assets/index-Xh0IeurI.js,sha256=P2jy3GnsJfxlD5X06qm2yt4_LYHOcQN4LvYRBkHQSho,1356696
|
|
10
|
+
cycls/themes/default/assets/index-oGkkm3Z8.css,sha256=xHhbrJvvz8mIN_Otrl6nawKJcA41L3tCFhVEOstGhVU,6498
|
|
11
|
+
cycls/themes/dev/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
|
|
12
|
+
cycls-0.0.2.93.dist-info/METADATA,sha256=rl9q236k7yvmSS2tlu1BTm_Z0VZsob1OvU4dC73kc4M,8869
|
|
13
|
+
cycls-0.0.2.93.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
cycls-0.0.2.93.dist-info/entry_points.txt,sha256=CktT5eNvW_Qxomf7L_Ez_GdUbL6qAfx_Utm6_HtUJwE,41
|
|
15
|
+
cycls-0.0.2.93.dist-info/RECORD,,
|