cycls 0.0.2.79__py3-none-any.whl → 0.0.2.81__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.
@@ -1 +1 @@
1
- :root{--bg-primary: #ffffff;--bg-secondary: #f9fafb;--bg-tertiary: #f3f4f6;--bg-sidebar: rgba(255, 255, 255, .8);--bg-hover: rgba(0, 0, 0, .05);--bg-active: rgba(0, 0, 0, .07);--bg-overlay: rgba(0, 0, 0, .25);--text-primary: #0d0d0d;--text-secondary: #374151;--text-tertiary: #6b6b6b;--text-muted: #9ca3af;--border-primary: rgba(0, 0, 0, .1);--border-secondary: rgba(0, 0, 0, .06);--accent-primary: #10a37f;--accent-hover: #0d8a6c;--scrollbar-thumb: #d1d1d1;--scrollbar-thumb-hover: #b1b1b1;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--code-bg: #f3f4f6;--code-text: #1f2937;--msg-user-bg: #f3f4f6;--msg-assistant-bg: transparent;--input-bg: #ffffff;--input-border: #e5e7eb;--input-focus-border: #10a37f;--btn-primary-bg: #0d0d0d;--btn-primary-text: #ffffff;--btn-secondary-bg: transparent;--btn-secondary-text: #0d0d0d}.dark,[data-theme=dark]{--bg-primary: #212121;--bg-secondary: #171717;--bg-tertiary: #2f2f2f;--bg-sidebar: rgba(23, 23, 23, .95);--bg-hover: rgba(255, 255, 255, .08);--bg-active: rgba(255, 255, 255, .12);--bg-overlay: rgba(0, 0, 0, .5);--text-primary: #ececec;--text-secondary: #c5c5c5;--text-tertiary: #8e8e8e;--text-muted: #6b6b6b;--border-primary: rgba(255, 255, 255, .1);--border-secondary: rgba(255, 255, 255, .06);--accent-primary: #10a37f;--accent-hover: #1abc94;--scrollbar-thumb: #4a4a4a;--scrollbar-thumb-hover: #5a5a5a;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .4), 0 2px 4px -1px rgba(0, 0, 0, .3);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4), 0 4px 6px -2px rgba(0, 0, 0, .3);--code-bg: #2f2f2f;--code-text: #e5e7eb;--msg-user-bg: #2f2f2f;--msg-assistant-bg: transparent;--input-bg: #2f2f2f;--input-border: #424242;--input-focus-border: #10a37f;--btn-primary-bg: #ececec;--btn-primary-text: #0d0d0d;--btn-secondary-bg: transparent;--btn-secondary-text: #ececec}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]){--bg-primary: #212121;--bg-secondary: #171717;--bg-tertiary: #2f2f2f;--bg-sidebar: rgba(23, 23, 23, .95);--bg-hover: rgba(255, 255, 255, .08);--bg-active: rgba(255, 255, 255, .12);--bg-overlay: rgba(0, 0, 0, .5);--text-primary: #ececec;--text-secondary: #c5c5c5;--text-tertiary: #8e8e8e;--text-muted: #6b6b6b;--border-primary: rgba(255, 255, 255, .1);--border-secondary: rgba(255, 255, 255, .06);--accent-primary: #10a37f;--accent-hover: #1abc94;--scrollbar-thumb: #4a4a4a;--scrollbar-thumb-hover: #5a5a5a;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .4), 0 2px 4px -1px rgba(0, 0, 0, .3);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4), 0 4px 6px -2px rgba(0, 0, 0, .3);--code-bg: #2f2f2f;--code-text: #e5e7eb;--msg-user-bg: #2f2f2f;--msg-assistant-bg: transparent;--input-bg: #2f2f2f;--input-border: #424242;--input-focus-border: #10a37f;--btn-primary-bg: #ececec;--btn-primary-text: #0d0d0d;--btn-secondary-bg: transparent;--btn-secondary-text: #ececec}}body{background-color:var(--bg-primary);color:var(--text-primary);transition:background-color .2s ease,color .2s ease}.cl-internal-p8bmz4{box-shadow:none!important;border:1px solid var(--border-primary);box-shadow:var(--shadow-sm)}.cl-drawerRoot{z-index:99!important}.cl-pricingTableCardFooterButton{padding:10px}.cl-pricingTableCardFee{font-size:2rem}.cl-pricingTableCardTitleContainer{margin-bottom:10px}.scrollbar-thin{scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) transparent}.scrollbar-thin::-webkit-scrollbar{width:6px}.scrollbar-thin::-webkit-scrollbar-track{background:transparent}.scrollbar-thin::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);border-radius:3px}.scrollbar-thin::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.scrollbar-thin::-webkit-scrollbar-thumb{background-color:transparent}.scrollbar-thin:hover::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}.sidebar-transition{transition:transform .3s ease-in-out,width .3s ease-in-out}.sidebar-overlay{z-index:40}.sidebar-panel{z-index:50}@keyframes slideDown{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.dropdown-menu{animation:slideDown .15s ease-out}.sidebar-item:focus-visible{outline:2px solid var(--text-primary);outline-offset:-2px;border-radius:8px}.user-profile-item:hover .user-avatar{transform:scale(1.02)}.chat-title-fade{mask-image:linear-gradient(to right,black 85%,transparent 100%);-webkit-mask-image:linear-gradient(to right,black 85%,transparent 100%)}.theme-toggle-icon{transition:transform .3s ease,opacity .2s ease}.theme-toggle:hover .theme-toggle-icon{transform:rotate(15deg)}.theme-transition{transition:background-color .2s ease,color .2s ease,border-color .2s ease,box-shadow .2s ease}.dark .prose,[data-theme=dark] .prose{--tw-prose-body: var(--text-primary);--tw-prose-headings: var(--text-primary);--tw-prose-lead: var(--text-secondary);--tw-prose-links: var(--accent-primary);--tw-prose-bold: var(--text-primary);--tw-prose-counters: var(--text-tertiary);--tw-prose-bullets: var(--text-tertiary);--tw-prose-hr: var(--border-primary);--tw-prose-quotes: var(--text-secondary);--tw-prose-quote-borders: var(--border-primary);--tw-prose-captions: var(--text-tertiary);--tw-prose-code: var(--text-primary);--tw-prose-pre-code: var(--code-text);--tw-prose-pre-bg: var(--code-bg);--tw-prose-th-borders: var(--border-primary);--tw-prose-td-borders: var(--border-secondary)}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]) .prose{--tw-prose-body: var(--text-primary);--tw-prose-headings: var(--text-primary);--tw-prose-lead: var(--text-secondary);--tw-prose-links: var(--accent-primary);--tw-prose-bold: var(--text-primary);--tw-prose-counters: var(--text-tertiary);--tw-prose-bullets: var(--text-tertiary);--tw-prose-hr: var(--border-primary);--tw-prose-quotes: var(--text-secondary);--tw-prose-quote-borders: var(--border-primary);--tw-prose-captions: var(--text-tertiary);--tw-prose-code: var(--text-primary);--tw-prose-pre-code: var(--code-text);--tw-prose-pre-bg: var(--code-bg);--tw-prose-th-borders: var(--border-primary);--tw-prose-td-borders: var(--border-secondary)}}.dark pre code.hljs,[data-theme=dark] pre code.hljs{background:var(--code-bg)!important}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]) pre code.hljs{background:var(--code-bg)!important}}.group button:hover{transform:scale(1.05)}
1
+ :root{--bg-primary: #ffffff;--bg-secondary: #f9fafb;--bg-tertiary: #f3f4f6;--bg-sidebar: rgba(255, 255, 255, .8);--bg-hover: rgba(0, 0, 0, .05);--bg-active: rgba(0, 0, 0, .07);--bg-overlay: rgba(0, 0, 0, .25);--text-primary: #0d0d0d;--text-secondary: #374151;--text-tertiary: #6b6b6b;--text-muted: #9ca3af;--border-primary: rgba(0, 0, 0, .1);--border-secondary: rgba(0, 0, 0, .06);--accent-primary: #10a37f;--accent-hover: #0d8a6c;--scrollbar-thumb: #d1d1d1;--scrollbar-thumb-hover: #b1b1b1;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--code-bg: #f3f4f6;--code-text: #1f2937;--msg-user-bg: #f3f4f6;--msg-assistant-bg: transparent;--input-bg: #ffffff;--input-border: #e5e7eb;--input-focus-border: #10a37f;--btn-primary-bg: #0d0d0d;--btn-primary-text: #ffffff;--btn-secondary-bg: transparent;--btn-secondary-text: #0d0d0d}.dark,[data-theme=dark]{--bg-primary: #212121;--bg-secondary: #171717;--bg-tertiary: #2f2f2f;--bg-sidebar: rgba(23, 23, 23, .95);--bg-hover: rgba(255, 255, 255, .08);--bg-active: rgba(255, 255, 255, .12);--bg-overlay: rgba(0, 0, 0, .5);--text-primary: #ececec;--text-secondary: #c5c5c5;--text-tertiary: #8e8e8e;--text-muted: #6b6b6b;--border-primary: rgba(255, 255, 255, .1);--border-secondary: rgba(255, 255, 255, .06);--accent-primary: #10a37f;--accent-hover: #1abc94;--scrollbar-thumb: #4a4a4a;--scrollbar-thumb-hover: #5a5a5a;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .4), 0 2px 4px -1px rgba(0, 0, 0, .3);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4), 0 4px 6px -2px rgba(0, 0, 0, .3);--code-bg: #2f2f2f;--code-text: #e5e7eb;--msg-user-bg: #2f2f2f;--msg-assistant-bg: transparent;--input-bg: #2f2f2f;--input-border: #424242;--input-focus-border: #10a37f;--btn-primary-bg: #ececec;--btn-primary-text: #0d0d0d;--btn-secondary-bg: transparent;--btn-secondary-text: #ececec}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]){--bg-primary: #212121;--bg-secondary: #171717;--bg-tertiary: #2f2f2f;--bg-sidebar: rgba(23, 23, 23, .95);--bg-hover: rgba(255, 255, 255, .08);--bg-active: rgba(255, 255, 255, .12);--bg-overlay: rgba(0, 0, 0, .5);--text-primary: #ececec;--text-secondary: #c5c5c5;--text-tertiary: #8e8e8e;--text-muted: #6b6b6b;--border-primary: rgba(255, 255, 255, .1);--border-secondary: rgba(255, 255, 255, .06);--accent-primary: #10a37f;--accent-hover: #1abc94;--scrollbar-thumb: #4a4a4a;--scrollbar-thumb-hover: #5a5a5a;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .3);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .4), 0 2px 4px -1px rgba(0, 0, 0, .3);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4), 0 4px 6px -2px rgba(0, 0, 0, .3);--code-bg: #2f2f2f;--code-text: #e5e7eb;--msg-user-bg: #2f2f2f;--msg-assistant-bg: transparent;--input-bg: #2f2f2f;--input-border: #424242;--input-focus-border: #10a37f;--btn-primary-bg: #ececec;--btn-primary-text: #0d0d0d;--btn-secondary-bg: transparent;--btn-secondary-text: #ececec}}body{background-color:var(--bg-primary);color:var(--text-primary);transition:background-color .2s ease,color .2s ease}.cl-internal-p8bmz4{box-shadow:none!important;border:1px solid var(--border-primary);box-shadow:var(--shadow-sm)}.cl-drawerRoot{z-index:99!important}.cl-pricingTableCardFooterButton{padding:10px}.cl-pricingTableCardFee{font-size:2rem}.cl-pricingTableCardTitleContainer{margin-bottom:10px}.scrollbar-thin{scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) transparent}.scrollbar-thin::-webkit-scrollbar{width:6px}.scrollbar-thin::-webkit-scrollbar-track{background:transparent}.scrollbar-thin::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb);border-radius:3px}.scrollbar-thin::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover)}.scrollbar-thin::-webkit-scrollbar-thumb{background-color:transparent}.scrollbar-thin:hover::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb)}.sidebar-transition{transition:transform .3s ease-in-out,width .3s ease-in-out}.sidebar-overlay{z-index:40}.sidebar-panel{z-index:50}@keyframes slideDown{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.dropdown-menu{animation:slideDown .15s ease-out}.sidebar-item:focus-visible{outline:2px solid var(--text-primary);outline-offset:-2px;border-radius:8px}.user-profile-item:hover .user-avatar{transform:scale(1.02)}.chat-title-fade{mask-image:linear-gradient(to right,black 85%,transparent 100%);-webkit-mask-image:linear-gradient(to right,black 85%,transparent 100%)}.theme-toggle-icon{transition:transform .3s ease,opacity .2s ease}.theme-toggle:hover .theme-toggle-icon{transform:rotate(15deg)}.theme-transition{transition:background-color .2s ease,color .2s ease,border-color .2s ease,box-shadow .2s ease}.dark .prose,[data-theme=dark] .prose{--tw-prose-body: var(--text-primary);--tw-prose-headings: var(--text-primary);--tw-prose-lead: var(--text-secondary);--tw-prose-links: var(--accent-primary);--tw-prose-bold: var(--text-primary);--tw-prose-counters: var(--text-tertiary);--tw-prose-bullets: var(--text-tertiary);--tw-prose-hr: var(--border-primary);--tw-prose-quotes: var(--text-secondary);--tw-prose-quote-borders: var(--border-primary);--tw-prose-captions: var(--text-tertiary);--tw-prose-code: var(--text-primary);--tw-prose-pre-code: var(--code-text);--tw-prose-pre-bg: var(--code-bg);--tw-prose-th-borders: var(--border-primary);--tw-prose-td-borders: var(--border-secondary)}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]) .prose{--tw-prose-body: var(--text-primary);--tw-prose-headings: var(--text-primary);--tw-prose-lead: var(--text-secondary);--tw-prose-links: var(--accent-primary);--tw-prose-bold: var(--text-primary);--tw-prose-counters: var(--text-tertiary);--tw-prose-bullets: var(--text-tertiary);--tw-prose-hr: var(--border-primary);--tw-prose-quotes: var(--text-secondary);--tw-prose-quote-borders: var(--border-primary);--tw-prose-captions: var(--text-tertiary);--tw-prose-code: var(--text-primary);--tw-prose-pre-code: var(--code-text);--tw-prose-pre-bg: var(--code-bg);--tw-prose-th-borders: var(--border-primary);--tw-prose-td-borders: var(--border-secondary)}}.dark pre code.hljs,[data-theme=dark] pre code.hljs{background:var(--code-bg)!important}@media (prefers-color-scheme: dark){:root:not(.light):not([data-theme=light]) pre code.hljs{background:var(--code-bg)!important}}
@@ -13,8 +13,8 @@
13
13
  rel="stylesheet"
14
14
  href="https://esm.sh/katex@0.16.8/dist/katex.min.css"
15
15
  />
16
- <script type="module" crossorigin src="/assets/index-D5EDcI4J.js"></script>
17
- <link rel="stylesheet" crossorigin href="/assets/index-B0ZKcm_V.css">
16
+ <script type="module" crossorigin src="/assets/index-C2r4Daz3.js"></script>
17
+ <link rel="stylesheet" crossorigin href="/assets/index-DWGS8zpa.css">
18
18
  </head>
19
19
  <body style="overflow-x: hidden">
20
20
  <div id="root"></div>
cycls/grpc/client.py CHANGED
@@ -32,7 +32,7 @@ class RuntimeClient:
32
32
  for response in stub.Execute(request, timeout=self.timeout):
33
33
  result = cloudpickle.loads(response.data)
34
34
  if response.error:
35
- raise RuntimeError(result)
35
+ raise RuntimeError(f"Function execution failed: {result}")
36
36
  yield result
37
37
 
38
38
  def call(self, func, *args, **kwargs):
cycls/runtime.py CHANGED
@@ -3,6 +3,7 @@ import docker
3
3
  import cloudpickle
4
4
  import tempfile
5
5
  import hashlib
6
+ import json
6
7
  import os
7
8
  import sys
8
9
  import shutil
@@ -228,8 +229,10 @@ CMD ["python", "entrypoint.py"]
228
229
  self._container.reload()
229
230
  if self._container.status == 'running':
230
231
  return self._client
231
- except:
232
- pass
232
+ except docker.errors.NotFound:
233
+ pass # Container was removed externally
234
+ except docker.errors.APIError:
235
+ pass # Docker API issue, will recreate
233
236
  self._cleanup_container()
234
237
 
235
238
  tag = self._ensure_grpc_image()
@@ -259,8 +262,10 @@ CMD ["python", "entrypoint.py"]
259
262
  try:
260
263
  self._container.stop(timeout=3)
261
264
  self._container.remove()
262
- except:
263
- pass
265
+ except docker.errors.NotFound:
266
+ pass # Already removed
267
+ except docker.errors.APIError:
268
+ pass # Best effort cleanup
264
269
  self._container = None
265
270
  self._host_port = None
266
271
 
@@ -320,8 +325,10 @@ CMD ["python", "entrypoint.py"]
320
325
  try:
321
326
  from watchfiles import watch as watchfiles_watch
322
327
  except ImportError:
323
- print("watchfiles not installed. Run: pip install watchfiles")
324
- return
328
+ print("watchfiles not installed (enables auto-reload on file changes).")
329
+ print("Install with: pip install watchfiles")
330
+ print("Running without file watching...")
331
+ return self.run(*args, **kwargs)
325
332
 
326
333
  import inspect
327
334
  import subprocess
@@ -441,7 +448,7 @@ CMD ["python", "entrypoint.py"]
441
448
  print(f"Deploy failed: {e.response.status_code}")
442
449
  try:
443
450
  print(f" {e.response.json()['detail']}")
444
- except:
451
+ except (json.JSONDecodeError, KeyError):
445
452
  print(f" {e.response.text}")
446
453
  return None
447
454
  except requests.exceptions.RequestException as e:
cycls/sdk.py CHANGED
@@ -96,10 +96,9 @@ class AgentRuntime:
96
96
  def deploy(self, port=8080):
97
97
  """Deploy to production."""
98
98
  if api_key is None:
99
- print("Error: Please set cycls.api_key")
100
- return
99
+ raise RuntimeError("Missing API key. Set cycls.api_key before calling deploy().")
101
100
  runtime = self._runtime(prod=True)
102
- runtime.deploy(port=port)
101
+ return runtime.deploy(port=port)
103
102
 
104
103
  def modal(self, prod=False):
105
104
  import modal
@@ -144,8 +143,14 @@ class AgentRuntime:
144
143
  while True: time.sleep(10)
145
144
 
146
145
 
147
- def agent(name=None, pip=[], apt=[], copy=[], copy_public=[], theme="default", modal_keys=["", ""], auth=False, org=None, domain=None, header="", intro="", title="", plan="free", analytics=False):
146
+ def agent(name=None, pip=None, apt=None, copy=None, copy_public=None, theme="default", modal_keys=None, auth=False, org=None, domain=None, header="", intro="", title="", plan="free", analytics=False):
148
147
  """Decorator that transforms a function into a deployable agent."""
148
+ pip = pip or []
149
+ apt = apt or []
150
+ copy = copy or []
151
+ copy_public = copy_public or []
152
+ modal_keys = modal_keys or ["", ""]
153
+
149
154
  if plan == "cycls_pass":
150
155
  auth = True
151
156
  analytics = True
cycls/web.py CHANGED
@@ -94,8 +94,12 @@ def web(func, config):
94
94
  return {"type": "user",
95
95
  "user": {"id": decoded.get("id"), "name": decoded.get("name"), "email": decoded.get("email"), "org": decoded.get("org"),
96
96
  "plans": decoded.get("public", {}).get("plans", [])}}
97
- except:
98
- raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials", headers={"WWW-Authenticate": "Bearer"})
97
+ except jwt.ExpiredSignatureError:
98
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired", headers={"WWW-Authenticate": "Bearer"})
99
+ except jwt.InvalidTokenError as e:
100
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Invalid token: {e}", headers={"WWW-Authenticate": "Bearer"})
101
+ except Exception as e:
102
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Auth error: {e}", headers={"WWW-Authenticate": "Bearer"})
99
103
 
100
104
  @app.post("/")
101
105
  @app.post("/chat/cycls")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycls
3
- Version: 0.0.2.79
3
+ Version: 0.0.2.81
4
4
  Summary: Distribute Intelligence
5
5
  Author: Mohammed J. AlRujayi
6
6
  Author-email: mj@cycls.com
@@ -47,6 +47,8 @@ Distribute Intelligence
47
47
 
48
48
  The open-source SDK for distributing AI agents.
49
49
 
50
+ The function is the unit of abstraction in cycls. Your agent logic lives in a plain Python function — the decorator layers on everything else: containerization, authentication, deployment, analytics. You write the function, the `@` handles the infrastructure.
51
+
50
52
  ## Distribute Intelligence
51
53
 
52
54
  Write a function. Deploy it as an API, a web interface, or both. Add authentication, analytics, and monetization with flags.
@@ -0,0 +1,20 @@
1
+ cycls/__init__.py,sha256=vyI1d_8VP4XW7MliFuUs_P3O9KQxyCwQu-JkxrCyhPQ,597
2
+ cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
3
+ cycls/chat.py,sha256=t-ZN4LD3yMNcIOcZihlcDIXMsO76sdfD-_XVUFTIhNw,4781
4
+ cycls/default-theme/assets/index-C2r4Daz3.js,sha256=OGzjspxo0uUTdtQIzWZNgFMhGUtW4wSVuW33iA7oLFM,1351283
5
+ cycls/default-theme/assets/index-DWGS8zpa.css,sha256=SxylXQV1qgQ0sw9QlMxcu9jwWTu8XPOnWZju8upUpCM,6504
6
+ cycls/default-theme/index.html,sha256=WPUqVzJyh-aO2ulWTbXwOVAfWHaj0yWTGd9e8HOEro4,828
7
+ cycls/dev-theme/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
8
+ cycls/grpc/__init__.py,sha256=sr8UQMgJEHyBreBKV8xz8UCd0zDP5lhjXTnfkOB_yOY,63
9
+ cycls/grpc/client.py,sha256=GJoWlh2gP3YWEQ75-dX-IInyOdr2YSM8Cuw0lI-vD1I,2302
10
+ cycls/grpc/runtime.proto,sha256=B1AqrNIXOtr3Xsyzfc2Z1OCBepa6hsi4DJ4a3Pf33IQ,244
11
+ cycls/grpc/runtime_pb2.py,sha256=vEJo8FGP5aWPSDqzjZldfctduA2ojiyvoody7vpf-1w,1703
12
+ cycls/grpc/runtime_pb2_grpc.py,sha256=KFd8KqGbiNsKm8X39Q9_BPwXjeZUiDl8O_4aTlEys3k,3394
13
+ cycls/grpc/server.py,sha256=pfb4bo06NKDv0OpknqMSMjB9f8HUR41EZau1c6_XU5A,1911
14
+ cycls/runtime.py,sha256=CORCjI-AW-cE6zg_blQsbLHchcM6coJo6b3N4PriuWo,18072
15
+ cycls/sdk.py,sha256=yOLAOx26qaAgddLu7QcAroeaQ2eWqIjCvM7QmCe-OJs,6760
16
+ cycls/web.py,sha256=mRzuOVZPEMW6bLkzEDHI25AWYBREqbtoHsBzgGbUH4g,5038
17
+ cycls-0.0.2.81.dist-info/METADATA,sha256=9-5YcYEGassz9HZmGBX8iDEXxiVBnJQLtu4rgx5JOAQ,8759
18
+ cycls-0.0.2.81.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
19
+ cycls-0.0.2.81.dist-info/entry_points.txt,sha256=0NBXjzFFxdtO57z3vdaQEy68KmYTEgwK9Gvo34AOTb4,41
20
+ cycls-0.0.2.81.dist-info/RECORD,,
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cycls=cycls.chat:main
3
+
cycls/cli.py DELETED
@@ -1,217 +0,0 @@
1
- import sys
2
- import json
3
- import time
4
- import threading
5
- import httpx
6
-
7
- # ANSI codes
8
- DIM = "\033[2m"
9
- BOLD = "\033[1m"
10
- RESET = "\033[0m"
11
- CLEAR_LINE = "\r\033[K"
12
- GREEN = "\033[32m"
13
- YELLOW = "\033[33m"
14
- BLUE = "\033[34m"
15
- RED = "\033[31m"
16
- CYAN = "\033[36m"
17
- MAGENTA = "\033[35m"
18
-
19
- CALLOUT_STYLES = {
20
- "success": ("✓", GREEN),
21
- "warning": ("⚠", YELLOW),
22
- "info": ("ℹ", BLUE),
23
- "error": ("✗", RED),
24
- }
25
-
26
- def format_time(seconds):
27
- if seconds < 60:
28
- return f"{seconds:.1f}s"
29
- return f"{int(seconds // 60)}m {int(seconds % 60)}s"
30
-
31
- def render_table(headers, rows):
32
- if not headers:
33
- return
34
- widths = [len(str(h)) for h in headers]
35
- for row in rows:
36
- for i, cell in enumerate(row):
37
- if i < len(widths):
38
- widths[i] = max(widths[i], len(str(cell)))
39
-
40
- top = "┌" + "┬".join("─" * (w + 2) for w in widths) + "┐"
41
- sep = "├" + "┼".join("─" * (w + 2) for w in widths) + "┤"
42
- bot = "└" + "┴".join("─" * (w + 2) for w in widths) + "┘"
43
-
44
- def fmt_row(cells, bold=False):
45
- parts = []
46
- for i, w in enumerate(widths):
47
- cell = str(cells[i]) if i < len(cells) else ""
48
- if bold:
49
- parts.append(f" {BOLD}{cell.ljust(w)}{RESET} ")
50
- else:
51
- parts.append(f" {cell.ljust(w)} ")
52
- return "│" + "│".join(parts) + "│"
53
-
54
- print(top)
55
- print(fmt_row(headers, bold=True))
56
- print(sep)
57
- for row in rows:
58
- print(fmt_row(row))
59
- print(bot)
60
-
61
- class Spinner:
62
- def __init__(self):
63
- self.active = False
64
- self.thread = None
65
- self.frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
66
-
67
- def start(self):
68
- self.active = True
69
- def spin():
70
- i = 0
71
- while self.active:
72
- if not self.active:
73
- break
74
- print(f"\r{MAGENTA}{self.frames[i % len(self.frames)]}{RESET} ", end="", flush=True)
75
- for _ in range(8): # Check active more frequently
76
- if not self.active:
77
- break
78
- time.sleep(0.01)
79
- i += 1
80
- self.thread = threading.Thread(target=spin, daemon=True)
81
- self.thread.start()
82
-
83
- def stop(self):
84
- self.active = False
85
- if self.thread:
86
- self.thread.join(timeout=0.2)
87
- print(f"{CLEAR_LINE}", end="", flush=True)
88
-
89
- def chat(url):
90
- messages = []
91
- endpoint = f"{url.rstrip('/')}/chat/cycls"
92
-
93
- print(f"\n{MAGENTA}●{RESET} {BOLD}{url}{RESET}\n")
94
-
95
- while True:
96
- try:
97
- user_input = input(f"{CYAN}❯{RESET} ")
98
- if not user_input.strip():
99
- continue
100
-
101
- messages.append({"role": "user", "content": user_input})
102
- print()
103
-
104
- start_time = time.time()
105
- in_thinking = False
106
- table_headers = []
107
- table_rows = []
108
-
109
- with httpx.stream("POST", endpoint, json={"messages": messages}, timeout=None) as r:
110
- for line in r.iter_lines():
111
- if line.startswith("data: ") and line != "data: [DONE]":
112
-
113
- data = json.loads(line[6:])
114
- msg_type = data.get("type")
115
-
116
- # Handle plain string or missing type
117
- if msg_type is None:
118
- # Could be OpenAI format or plain text
119
- if isinstance(data, str):
120
- print(data, end="", flush=True)
121
- continue
122
- elif "choices" in data:
123
- # OpenAI format
124
- content = data.get("choices", [{}])[0].get("delta", {}).get("content", "")
125
- if content:
126
- print(content, end="", flush=True)
127
- continue
128
- elif "text" in data:
129
- print(data.get("text", ""), end="", flush=True)
130
- continue
131
- elif "content" in data:
132
- print(data.get("content", ""), end="", flush=True)
133
- continue
134
- else:
135
- # Debug: print raw data
136
- print(f"[debug: {data}]", end="", flush=True)
137
- continue
138
-
139
- # Close thinking if switching
140
- if msg_type != "thinking" and in_thinking:
141
- print(f"</thinking>{RESET}\n", end="", flush=True)
142
- in_thinking = False
143
-
144
- # Flush table if switching
145
- if msg_type != "table" and table_headers:
146
- render_table(table_headers, table_rows)
147
- table_headers = []
148
- table_rows = []
149
-
150
- if msg_type == "thinking":
151
- if not in_thinking:
152
- print(f"{DIM}<thinking>", end="", flush=True)
153
- in_thinking = True
154
- print(data.get("thinking", ""), end="", flush=True)
155
-
156
- elif msg_type == "text":
157
- print(data.get("text", ""), end="", flush=True)
158
-
159
- elif msg_type == "code":
160
- lang = data.get("language", "")
161
- print(f"\n```{lang}\n{data.get('code', '')}\n```\n", end="", flush=True)
162
-
163
- elif msg_type == "status":
164
- print(f"{DIM}[{data.get('status', '')}]{RESET} ", end="", flush=True)
165
-
166
- elif msg_type == "table":
167
- if "headers" in data:
168
- if table_headers:
169
- render_table(table_headers, table_rows)
170
- table_headers = data["headers"]
171
- table_rows = []
172
- elif "row" in data:
173
- table_rows.append(data["row"])
174
-
175
- elif msg_type == "callout":
176
- style = data.get("style", "info")
177
- icon, color = CALLOUT_STYLES.get(style, ("•", RESET))
178
- title = data.get("title", "")
179
- text = data.get("callout", "")
180
- if title:
181
- print(f"\n{color}{icon} {BOLD}{title}{RESET}")
182
- print(f"{color} {text}{RESET}\n", end="", flush=True)
183
- else:
184
- print(f"\n{color}{icon} {text}{RESET}\n", end="", flush=True)
185
-
186
- elif msg_type == "image":
187
- print(f"{DIM}[image: {data.get('src', '')}]{RESET}", end="", flush=True)
188
-
189
- # Flush remaining
190
- if table_headers:
191
- render_table(table_headers, table_rows)
192
- if in_thinking:
193
- print(f"</thinking>{RESET}", end="", flush=True)
194
-
195
- elapsed = time.time() - start_time
196
- print(f"\n\n{DIM}✦ {format_time(elapsed)}{RESET}\n")
197
-
198
- except KeyboardInterrupt:
199
- continue
200
- except EOFError:
201
- print(f"{RESET}\n👋")
202
- break
203
- except (httpx.ReadError, httpx.ConnectError):
204
- print(f"{RESET}🔄 Reconnecting...", end="", flush=True)
205
- time.sleep(1)
206
- print(CLEAR_LINE, end="")
207
- if messages:
208
- messages.pop()
209
-
210
- def main():
211
- if len(sys.argv) < 3 or sys.argv[1] != "chat":
212
- print("Usage: cycls chat <url>")
213
- sys.exit(1)
214
- chat(sys.argv[2])
215
-
216
- if __name__ == "__main__":
217
- main()
@@ -1,20 +0,0 @@
1
- cycls/__init__.py,sha256=vyI1d_8VP4XW7MliFuUs_P3O9KQxyCwQu-JkxrCyhPQ,597
2
- cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
3
- cycls/cli.py,sha256=AKf0z7ZLau3GvBVR_IhB7agmq4nVaHkcuUafNyvv2_A,7978
4
- cycls/default-theme/assets/index-B0ZKcm_V.css,sha256=wK9-NhEB8xPcN9Zv69zpOcfGTlFbMwyC9WqTmSKUaKw,6546
5
- cycls/default-theme/assets/index-D5EDcI4J.js,sha256=sN4qRcAXa7DBd9JzmVcCoCwH4l8cNCM-U9QGUjBvWSo,1346506
6
- cycls/default-theme/index.html,sha256=bM-yW_g0cGrV40Q5yY3ccY0fM4zI1Wuu5I8EtGFJIxs,828
7
- cycls/dev-theme/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
8
- cycls/grpc/__init__.py,sha256=sr8UQMgJEHyBreBKV8xz8UCd0zDP5lhjXTnfkOB_yOY,63
9
- cycls/grpc/client.py,sha256=zDFIBABXzuv_RUVn5LllppZ38C7k01RyAS8ZURBjudQ,2270
10
- cycls/grpc/runtime.proto,sha256=B1AqrNIXOtr3Xsyzfc2Z1OCBepa6hsi4DJ4a3Pf33IQ,244
11
- cycls/grpc/runtime_pb2.py,sha256=vEJo8FGP5aWPSDqzjZldfctduA2ojiyvoody7vpf-1w,1703
12
- cycls/grpc/runtime_pb2_grpc.py,sha256=KFd8KqGbiNsKm8X39Q9_BPwXjeZUiDl8O_4aTlEys3k,3394
13
- cycls/grpc/server.py,sha256=pfb4bo06NKDv0OpknqMSMjB9f8HUR41EZau1c6_XU5A,1911
14
- cycls/runtime.py,sha256=XME8DnLkAt_51asjt6RODCogWg8G5N-IlH_i3cbknf0,17592
15
- cycls/sdk.py,sha256=B5_ZNGvXqqKcAGAvhk-tyr0YH8kfvCJPKl01rhetvFw,6588
16
- cycls/web.py,sha256=_QNH8K55vTm90Z7tvcRKal5IybjkB1GY7Pf9p3qu3r8,4659
17
- cycls-0.0.2.79.dist-info/METADATA,sha256=GUMQwfbWWGSpRZ1JKXEGAKxhAKsxammGvXm6ZLBHN98,8496
18
- cycls-0.0.2.79.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
19
- cycls-0.0.2.79.dist-info/entry_points.txt,sha256=vEhqUxFhhuzCKWtq02LbMnT3wpUqdfgcM3Yh-jjXom8,40
20
- cycls-0.0.2.79.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- cycls=cycls.cli:main
3
-