cycls 0.0.2.88__py3-none-any.whl → 0.0.2.90__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.
@@ -17,7 +17,7 @@
17
17
  rel="stylesheet"
18
18
  href="https://esm.sh/katex@0.16.8/dist/katex.min.css"
19
19
  />
20
- <script type="module" crossorigin src="/assets/index-DOmNqb-2.js"></script>
20
+ <script type="module" crossorigin src="/assets/index-zAUKbDo6.js"></script>
21
21
  <link rel="stylesheet" crossorigin href="/assets/index-oGkkm3Z8.css">
22
22
  </head>
23
23
  <body style="overflow-x: hidden">
cycls/web.py CHANGED
@@ -16,6 +16,7 @@ class Config(BaseModel):
16
16
  org: Optional[str] = None
17
17
  pk: Optional[str] = None
18
18
  jwks: Optional[str] = None
19
+ debug: bool = False
19
20
 
20
21
  def set_prod(self, prod: bool):
21
22
  self.prod = prod
@@ -36,13 +37,18 @@ def sse(item):
36
37
  if not isinstance(item, dict): item = {"type": "text", "text": item}
37
38
  return f"data: {json.dumps(item)}\n\n"
38
39
 
39
- async def encoder(stream):
40
- if inspect.isasyncgen(stream):
41
- async for item in stream:
42
- if msg := sse(item): yield msg
43
- else:
44
- for item in stream:
45
- if msg := sse(item): yield msg
40
+ async def encoder(stream, debug=False):
41
+ import traceback
42
+ try:
43
+ if inspect.isasyncgen(stream):
44
+ async for item in stream:
45
+ if msg := sse(item): yield msg
46
+ else:
47
+ for item in stream:
48
+ if msg := sse(item): yield msg
49
+ except Exception as e:
50
+ error_msg = traceback.format_exc() if debug else str(e)
51
+ yield sse({"type": "thinking", "thinking": f"⚠️ Error\n```\n{error_msg}```"})
46
52
  yield "data: [DONE]\n\n"
47
53
 
48
54
  class Messages(list):
@@ -117,15 +123,23 @@ def web(func, config):
117
123
  @app.post("/chat/cycls")
118
124
  @app.post("/chat/completions")
119
125
  async def back(request: Request, jwt: Optional[dict] = Depends(validate) if config.auth else None):
126
+ import traceback
120
127
  data = await request.json()
121
128
  messages = data.get("messages")
122
129
  user_data = jwt.get("user") if jwt else None
123
130
  context = Context(messages = Messages(messages), user = User(**user_data) if user_data else None)
124
- stream = await func(context) if inspect.iscoroutinefunction(func) else func(context)
131
+ try:
132
+ stream = await func(context) if inspect.iscoroutinefunction(func) else func(context)
133
+ except Exception as e:
134
+ error_msg = traceback.format_exc() if config.debug else str(e)
135
+ async def error_stream():
136
+ yield sse({"type": "thinking", "thinking": f"⚠️ Error\n```\n{error_msg}```"})
137
+ yield "data: [DONE]\n\n"
138
+ return StreamingResponse(error_stream(), media_type="text/event-stream")
125
139
  if request.url.path == "/chat/completions":
126
140
  stream = openai_encoder(stream)
127
141
  elif request.url.path == "/chat/cycls":
128
- stream = encoder(stream)
142
+ stream = encoder(stream, debug=config.debug)
129
143
  return StreamingResponse(stream, media_type="text/event-stream")
130
144
 
131
145
  @app.get("/config")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycls
3
- Version: 0.0.2.88
3
+ Version: 0.0.2.90
4
4
  Summary: Distribute Intelligence
5
5
  Author-email: "Mohammed J. AlRujayi" <mj@cycls.com>
6
6
  Requires-Python: >=3.9
@@ -19,7 +19,8 @@ Distribute Intelligence
19
19
 
20
20
  <h4 align="center">
21
21
  <a href="https://cycls.com">Website</a> |
22
- <a href="https://docs.cycls.com">Docs</a>
22
+ <a href="https://docs.cycls.com">Docs</a> |
23
+ <a href="docs/tutorial.md">Tutorial</a>
23
24
  </h4>
24
25
 
25
26
  <h4 align="center">
@@ -79,7 +80,7 @@ app.deploy() # Live at https://agent.cycls.ai
79
80
  pip install cycls
80
81
  ```
81
82
 
82
- Requires Docker.
83
+ Requires Docker. See the [full tutorial](docs/tutorial.md) for a comprehensive guide.
83
84
 
84
85
  ## What You Get
85
86
 
@@ -102,6 +103,8 @@ Get an API key at [cycls.com](https://cycls.com).
102
103
 
103
104
  ## Authentication & Analytics
104
105
 
106
+ See the [tutorial](docs/tutorial.md#authentication) for full auth and monetization examples.
107
+
105
108
  ```python
106
109
  @cycls.app(pip=["openai"], auth=True, analytics=True)
107
110
  async def app(context):
@@ -118,7 +121,7 @@ async def app(context):
118
121
 
119
122
  ## Native UI Components
120
123
 
121
- Yield structured objects for rich streaming responses:
124
+ Yield structured objects for rich streaming responses. See the [tutorial](docs/tutorial.md#native-ui-components) for all component types and examples.
122
125
 
123
126
  ```python
124
127
  @cycls.app()
@@ -193,7 +196,7 @@ See [docs/streaming-protocol.md](docs/streaming-protocol.md) for frontend integr
193
196
 
194
197
  ## Declarative Infrastructure
195
198
 
196
- Define your entire runtime in the decorator:
199
+ Define your entire runtime in the decorator. See the [tutorial](docs/tutorial.md#declarative-infrastructure) for more details.
197
200
 
198
201
  ```python
199
202
  @cycls.app(
@@ -264,6 +267,13 @@ Access them at `https://your-app.cycls.ai/public/logo.png`.
264
267
 
265
268
  No YAML. No Dockerfiles. No infrastructure repo. The code is the deployment.
266
269
 
270
+ ## Learn More
271
+
272
+ - [Tutorial](docs/tutorial.md) - Comprehensive guide from basics to advanced
273
+ - [Streaming Protocol](docs/streaming-protocol.md) - Frontend integration
274
+ - [Runtime](docs/runtime.md) - Containerization details
275
+ - [Examples](examples/) - Working code samples
276
+
267
277
  ## License
268
278
 
269
279
  MIT
@@ -0,0 +1,14 @@
1
+ cycls/__init__.py,sha256=efbq0vRijGOByKtz9bRF8WQFYmnPSgZV1DH-54s6iwQ,493
2
+ cycls/app.py,sha256=5Uns6lwZCU5qwFD80vOJ_omDlhlEOGP65woK7rg2tn8,3222
3
+ cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
4
+ cycls/cli.py,sha256=cVbIkTDnVofohvByyYUrXF_RYDQZVQECJqo7cPBPJfs,4781
5
+ cycls/function.py,sha256=FP94mCd5hfCASFwsTSYny7KOEsJOh3LME9oZgiVfgzo,14795
6
+ cycls/web.py,sha256=XbSgra1G_L61tr1TshVeqjNERoFtFH_4VIwnQFxH00g,6242
7
+ cycls/themes/default/index.html,sha256=UFVO8M-ZLQegknKHj750ddHVZBRdoDy2lw24-VTHm9Y,1082
8
+ cycls/themes/default/assets/index-oGkkm3Z8.css,sha256=xHhbrJvvz8mIN_Otrl6nawKJcA41L3tCFhVEOstGhVU,6498
9
+ cycls/themes/default/assets/index-zAUKbDo6.js,sha256=22QXtR54l35a5CJhyOxfOTCLBF_uHurfUnL7L2ivG2g,1351998
10
+ cycls/themes/dev/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
11
+ cycls-0.0.2.90.dist-info/METADATA,sha256=SGJ7bWQjLA3eIp6uQXdZTQP6rtb98elI160nkWG8MjI,8761
12
+ cycls-0.0.2.90.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
13
+ cycls-0.0.2.90.dist-info/entry_points.txt,sha256=CktT5eNvW_Qxomf7L_Ez_GdUbL6qAfx_Utm6_HtUJwE,41
14
+ cycls-0.0.2.90.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- cycls/__init__.py,sha256=efbq0vRijGOByKtz9bRF8WQFYmnPSgZV1DH-54s6iwQ,493
2
- cycls/app.py,sha256=cYzHJboFRAKXhImJOkTLdMxpFZFlkVt_oulJrhF14KU,3124
3
- cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
4
- cycls/cli.py,sha256=cVbIkTDnVofohvByyYUrXF_RYDQZVQECJqo7cPBPJfs,4781
5
- cycls/function.py,sha256=dJ7N4kqI5dB1te-LDHrYC7l8S0tanYai1S344T2NqzU,14730
6
- cycls/web.py,sha256=svDytrmrUoeZQtl9lBb9pGLb1JRKtcB8nZmHnErrweA,5540
7
- cycls/themes/default/index.html,sha256=X7RbyJUic2iO1pJO0dX1iJBgUxMgqMZ-xKLTKwAE_Uk,1082
8
- cycls/themes/default/assets/index-DOmNqb-2.js,sha256=QTP1orFISS03SmgaBF2t7D1BlHmt8hXKvhlFZcic16I,1351775
9
- cycls/themes/default/assets/index-oGkkm3Z8.css,sha256=xHhbrJvvz8mIN_Otrl6nawKJcA41L3tCFhVEOstGhVU,6498
10
- cycls/themes/dev/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
11
- cycls-0.0.2.88.dist-info/METADATA,sha256=OwtVn0VmqjOkIz0aANvWulmYlhcB6PZuuYTelHrCHWg,8106
12
- cycls-0.0.2.88.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
13
- cycls-0.0.2.88.dist-info/entry_points.txt,sha256=CktT5eNvW_Qxomf7L_Ez_GdUbL6qAfx_Utm6_HtUJwE,41
14
- cycls-0.0.2.88.dist-info/RECORD,,