cycls 0.0.2.71__py3-none-any.whl → 0.0.2.73__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 CHANGED
@@ -1,2 +1,15 @@
1
- from .sdk import Agent, function
2
- from .runtime import Runtime
1
+ from .sdk import function, agent
2
+ from .runtime import Runtime
3
+
4
+ def __getattr__(name):
5
+ from . import sdk
6
+ if name in ("api_key", "base_url"):
7
+ return getattr(sdk, name)
8
+ raise AttributeError(f"module 'cycls' has no attribute '{name}'")
9
+
10
+ def __setattr__(name, value):
11
+ from . import sdk
12
+ if name in ("api_key", "base_url"):
13
+ setattr(sdk, name, value)
14
+ return
15
+ raise AttributeError(f"module 'cycls' has no attribute '{name}'")
cycls/runtime.py CHANGED
@@ -178,9 +178,11 @@ class Runtime:
178
178
 
179
179
  def _generate_dockerfile(self, port=None) -> str:
180
180
  """Generates a multi-stage Dockerfile string."""
181
- # Only install extra packages not in base image
181
+ using_base = self.base_image == BASE_IMAGE
182
+
183
+ # Only install extra packages not in base image (use uv if available in base)
182
184
  run_pip_install = (
183
- f"RUN pip install --no-cache-dir {' '.join(self.pip_packages)}"
185
+ f"RUN uv pip install --system --no-cache {' '.join(self.pip_packages)}"
184
186
  if self.pip_packages else ""
185
187
  )
186
188
  run_apt_install = (
@@ -191,16 +193,19 @@ class Runtime:
191
193
  copy_lines = "\n".join([f"COPY context_files/{dst} {dst}" for dst in self.copy.values()])
192
194
  expose_line = f"EXPOSE {port}" if port else ""
193
195
 
196
+ # Skip env/mkdir/workdir if using pre-built base (already configured)
197
+ env_lines = "" if using_base else f"""ENV PIP_ROOT_USER_ACTION=ignore \\
198
+ PYTHONUNBUFFERED=1
199
+ RUN mkdir -p {self.io_dir}
200
+ WORKDIR /app"""
201
+
194
202
  return f"""
195
203
  # STAGE 1: Base image with all dependencies
196
204
  FROM {self.base_image} as base
197
- ENV PIP_ROOT_USER_ACTION=ignore
198
- ENV PYTHONUNBUFFERED=1
199
- RUN mkdir -p {self.io_dir}
205
+ {env_lines}
200
206
  {run_apt_install}
201
207
  {run_pip_install}
202
208
  {run_shell_commands}
203
- WORKDIR /app
204
209
  {copy_lines}
205
210
  COPY {self.runner_filename} {self.runner_path}
206
211
  ENTRYPOINT ["python", "{self.runner_path}", "{self.io_dir}"]
cycls/sdk.py CHANGED
@@ -1,30 +1,21 @@
1
- import os, time, inspect, uvicorn
1
+ import os, time, uvicorn
2
2
  from .runtime import Runtime
3
3
  from .web import web, Config
4
4
  from .auth import PK_LIVE, PK_TEST, JWKS_PROD, JWKS_TEST
5
5
  import importlib.resources
6
- from pydantic import BaseModel
7
- from typing import Callable
8
6
 
9
7
  CYCLS_PATH = importlib.resources.files('cycls')
10
8
 
11
- class RegisteredAgent(BaseModel):
12
- func: Callable
13
- name: str
14
- domain: str
15
- config: Config
16
-
17
- def set_prod(config: Config, prod: bool):
18
- config.prod = prod
19
- config.pk = PK_LIVE if prod else PK_TEST
20
- config.jwks = JWKS_PROD if prod else JWKS_TEST
9
+ # Module-level configuration
10
+ api_key = None
11
+ base_url = None
21
12
 
22
13
  themes = {
23
14
  "default": CYCLS_PATH.joinpath('default-theme'),
24
15
  "dev": CYCLS_PATH.joinpath('dev-theme'),
25
16
  }
26
17
 
27
- def resolve_theme(theme):
18
+ def _resolve_theme(theme):
28
19
  """Resolve theme - accepts string name or path"""
29
20
  if isinstance(theme, str):
30
21
  if theme in themes:
@@ -32,77 +23,54 @@ def resolve_theme(theme):
32
23
  raise ValueError(f"Unknown theme: {theme}. Available: {list(themes.keys())}")
33
24
  return theme
34
25
 
35
- def function(python_version=None, pip=None, apt=None, run_commands=None, copy=None, name=None, base_url=None, key=None):
36
- # """
37
- # A decorator factory that transforms a Python function into a containerized,
38
- # remotely executable object.
39
- def decorator(func):
40
- Name = name or func.__name__
41
- copy_dict = {i:i for i in copy or []}
42
- return Runtime(func, Name.replace('_', '-'), python_version, pip, apt, run_commands, copy_dict, base_url, key)
43
- return decorator
26
+ def _set_prod(config: Config, prod: bool):
27
+ config.prod = prod
28
+ config.pk = PK_LIVE if prod else PK_TEST
29
+ config.jwks = JWKS_PROD if prod else JWKS_TEST
30
+
31
+ class AgentRuntime:
32
+ """Wraps an agent function with local/deploy/modal capabilities."""
33
+
34
+ def __init__(self, func, name, theme, pip, apt, copy, copy_public, modal_keys, auth, org, domain, header, intro, title, plan, analytics):
35
+ self.func = func
36
+ self.name = name
37
+ self.theme = _resolve_theme(theme)
38
+ self.pip = pip
39
+ self.apt = apt
40
+ self.copy = copy
41
+ self.copy_public = copy_public
42
+ self.modal_keys = modal_keys
43
+ self.domain = domain or f"{name}.cycls.ai"
44
+
45
+ self.config = Config(
46
+ header=header,
47
+ intro=intro,
48
+ title=title,
49
+ auth=auth,
50
+ plan=plan,
51
+ analytics=analytics,
52
+ org=org,
53
+ )
44
54
 
45
- class Agent:
46
- def __init__(self, theme="default", org=None, api_token=None, pip=[], apt=[], copy=[], copy_public=[], modal_keys=["",""], key=None, base_url=None):
47
- self.org, self.api_token = org, api_token
48
- self.theme = resolve_theme(theme)
49
- self.key, self.modal_keys, self.pip, self.apt, self.copy, self.copy_public = key, modal_keys, pip, apt, copy, copy_public
50
- self.base_url = base_url
51
-
52
- self.registered_functions = []
53
-
54
- def __call__(self, name=None, header="", intro="", title="", domain=None, auth=False, tier="free", analytics=False):
55
- if tier=="cycls_pass":
56
- auth=True
57
- analytics=True
58
- def decorator(f):
59
- agent_name = name or f.__name__.replace('_', '-')
60
- self.registered_functions.append(RegisteredAgent(
61
- func=f,
62
- name=agent_name,
63
- domain=domain or f"{agent_name}.cycls.ai",
64
- config=Config(
65
- header=header,
66
- intro=intro,
67
- title=title,
68
- auth=auth,
69
- tier=tier,
70
- analytics=analytics,
71
- org=self.org,
72
- ),
73
- ))
74
- return f
75
- return decorator
55
+ def __call__(self, *args, **kwargs):
56
+ """Make the runtime callable - delegates to the wrapped function."""
57
+ return self.func(*args, **kwargs)
76
58
 
77
59
  def _local(self, port=8080, watch=True):
78
60
  """Run directly with uvicorn (no Docker)."""
79
- if not self.registered_functions:
80
- print("Error: No @agent decorated function found.")
81
- return
82
-
83
- agent = self.registered_functions[0]
84
- if len(self.registered_functions) > 1:
85
- print(f"⚠️ Warning: Multiple agents found. Running '{agent.name}'.")
86
- print(f"🚀 Starting local server at localhost:{port}")
87
- agent.config.public_path = self.theme
88
- set_prod(agent.config, False)
89
- uvicorn.run(web(agent.func, agent.config), host="0.0.0.0", port=port, reload=watch)
90
- return
61
+ print(f"Starting local server at localhost:{port}")
62
+ self.config.public_path = self.theme
63
+ _set_prod(self.config, False)
64
+ uvicorn.run(web(self.func, self.config), host="0.0.0.0", port=port, reload=watch)
91
65
 
92
66
  def _runtime(self, prod=False):
93
- """Create a Runtime instance for the first registered agent."""
94
- if not self.registered_functions:
95
- print("Error: No @agent decorated function found.")
96
- return None
97
-
98
- agent = self.registered_functions[0]
99
- if len(self.registered_functions) > 1:
100
- print(f"⚠️ Warning: Multiple agents found. Running '{agent.name}'.")
67
+ """Create a Runtime instance for deployment."""
68
+ _set_prod(self.config, prod)
69
+ config_dict = self.config.model_dump()
101
70
 
102
- set_prod(agent.config, prod)
103
- func = agent.func
104
- name = agent.name
105
- config_dict = agent.config.model_dump()
71
+ # Extract to local variables to avoid capturing self in lambda (cloudpickle issue)
72
+ func = self.func
73
+ name = self.name
106
74
 
107
75
  files = {str(self.theme): "theme", str(CYCLS_PATH)+"/web.py": "web.py"}
108
76
  files.update({f: f for f in self.copy})
@@ -114,73 +82,100 @@ class Agent:
114
82
  apt_packages=self.apt,
115
83
  pip_packages=["fastapi[standard]", "pyjwt", "cryptography", "uvicorn", *self.pip],
116
84
  copy=files,
117
- base_url=self.base_url,
118
- api_key=self.key
85
+ base_url=base_url,
86
+ api_key=api_key
119
87
  )
120
88
 
121
89
  def local(self, port=8080, watch=True):
122
90
  """Run locally in Docker with file watching by default."""
123
- # Child process spawned by watcher - run without watch
124
91
  if os.environ.get('_CYCLS_WATCH_CHILD'):
125
92
  watch = False
126
93
  runtime = self._runtime(prod=False)
127
- if runtime:
128
- runtime.watch(port=port) if watch else runtime.run(port=port)
94
+ runtime.watch(port=port) if watch else runtime.run(port=port)
129
95
 
130
96
  def deploy(self, port=8080):
131
97
  """Deploy to production."""
132
- if self.key is None:
133
- print("🛑 Error: Please add your Cycls API key")
98
+ if api_key is None:
99
+ print("Error: Please set cycls.api_key")
134
100
  return
135
101
  runtime = self._runtime(prod=True)
136
- if runtime:
137
- runtime.deploy(port=port)
138
-
102
+ runtime.deploy(port=port)
103
+
139
104
  def modal(self, prod=False):
140
105
  import modal
141
106
  from modal.runner import run_app
142
- self.client = modal.Client.from_credentials(*self.modal_keys)
107
+
108
+ # Extract to local variables to avoid capturing self in lambda
109
+ func = self.func
110
+ name = self.name
111
+ domain = self.domain
112
+
113
+ client = modal.Client.from_credentials(*self.modal_keys)
143
114
  image = (modal.Image.debian_slim()
144
115
  .pip_install("fastapi[standard]", "pyjwt", "cryptography", *self.pip)
145
116
  .apt_install(*self.apt)
146
117
  .add_local_dir(self.theme, "/root/theme")
147
118
  .add_local_file(str(CYCLS_PATH)+"/web.py", "/root/web.py"))
148
-
119
+
149
120
  for item in self.copy:
150
121
  image = image.add_local_file(item, f"/root/{item}") if "." in item else image.add_local_dir(item, f'/root/{item}')
151
-
122
+
152
123
  for item in self.copy_public:
153
124
  image = image.add_local_file(item, f"/root/public/{item}") if "." in item else image.add_local_dir(item, f'/root/public/{item}')
154
125
 
155
- self.app = modal.App("development", image=image)
156
-
157
- if not self.registered_functions:
158
- print("Error: No @agent decorated function found.")
159
- return
126
+ app = modal.App("development", image=image)
127
+
128
+ _set_prod(self.config, prod)
129
+ config_dict = self.config.model_dump()
130
+
131
+ app.function(serialized=True, name=name)(
132
+ modal.asgi_app(label=name, custom_domains=[domain])
133
+ (lambda: __import__("web").web(func, config_dict))
134
+ )
160
135
 
161
- for agent in self.registered_functions:
162
- set_prod(agent.config, prod)
163
- func = agent.func
164
- name = agent.name
165
- domain = agent.domain
166
- config_dict = agent.config.model_dump()
167
- self.app.function(serialized=True, name=name)(
168
- modal.asgi_app(label=name, custom_domains=[domain])
169
- (lambda: __import__("web").web(func, config_dict))
170
- )
171
136
  if prod:
172
- for agent in self.registered_functions:
173
- print(f"✅ Deployed to ⇒ https://{agent.domain}")
174
- self.app.deploy(client=self.client, name=self.registered_functions[0].name)
175
- return
137
+ print(f"Deployed to => https://{domain}")
138
+ app.deploy(client=client, name=name)
176
139
  else:
177
140
  with modal.enable_output():
178
- run_app(app=self.app, client=self.client)
179
- print(" Modal development server is running. Press Ctrl+C to stop.")
180
- with modal.enable_output(), run_app(app=self.app, client=self.client):
141
+ run_app(app=app, client=client)
142
+ print("Modal development server is running. Press Ctrl+C to stop.")
143
+ with modal.enable_output(), run_app(app=app, client=client):
181
144
  while True: time.sleep(10)
182
145
 
183
- # docker system prune -af
184
- # poetry config pypi-token.pypi <your-token>
185
- # poetry run python cake.py
186
- # poetry publish --build
146
+
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):
148
+ """Decorator that transforms a function into a deployable agent."""
149
+ if plan == "cycls_pass":
150
+ auth = True
151
+ analytics = True
152
+
153
+ def decorator(func):
154
+ agent_name = name or func.__name__.replace('_', '-')
155
+ return AgentRuntime(
156
+ func=func,
157
+ name=agent_name,
158
+ theme=theme,
159
+ pip=pip,
160
+ apt=apt,
161
+ copy=copy,
162
+ copy_public=copy_public,
163
+ modal_keys=modal_keys,
164
+ auth=auth,
165
+ org=org,
166
+ domain=domain,
167
+ header=header,
168
+ intro=intro,
169
+ title=title,
170
+ plan=plan,
171
+ analytics=analytics,
172
+ )
173
+ return decorator
174
+
175
+ def function(python_version=None, pip=None, apt=None, run_commands=None, copy=None, name=None):
176
+ """Decorator that transforms a Python function into a containerized, remotely executable object."""
177
+ def decorator(func):
178
+ func_name = name or func.__name__
179
+ copy_dict = {i: i for i in copy or []}
180
+ return Runtime(func, func_name.replace('_', '-'), python_version, pip, apt, run_commands, copy_dict, base_url, api_key)
181
+ return decorator
cycls/web.py CHANGED
@@ -10,7 +10,7 @@ class Config(BaseModel):
10
10
  title: str = ""
11
11
  prod: bool = False
12
12
  auth: bool = False
13
- tier: str = "free"
13
+ plan: str = "free"
14
14
  analytics: bool = False
15
15
  org: Optional[str] = None
16
16
  pk: str = ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycls
3
- Version: 0.0.2.71
3
+ Version: 0.0.2.73
4
4
  Summary: Distribute Intelligence
5
5
  Author: Mohammed J. AlRujayi
6
6
  Author-email: mj@cycls.com
@@ -32,6 +32,7 @@ Distribute Intelligence
32
32
 
33
33
  <h4 align="center">
34
34
  <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>
35
+ <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>
35
36
  <a href="https://blog.cycls.com"><img src="https://img.shields.io/badge/newsletter-blueviolet.svg?logo=substack&label=cycls" alt="Cycls newsletter" /></a>
36
37
  <a href="https://x.com/cyclsai">
37
38
  <img src="https://img.shields.io/twitter/follow/CyclsAI" alt="Cycls Twitter" />
@@ -53,24 +54,27 @@ Write a function. Deploy it as an API, a web interface, or both. Add authenticat
53
54
  ```python
54
55
  import cycls
55
56
 
56
- agent = cycls.Agent(pip=["openai"])
57
+ cycls.api_key = "YOUR_CYCLS_API_KEY"
57
58
 
58
- @agent("my-agent", auth=True, analytics=True)
59
- async def chat(context):
59
+ @cycls.agent(pip=["openai"])
60
+ async def agent(context):
60
61
  from openai import AsyncOpenAI
61
62
  client = AsyncOpenAI()
62
63
 
63
- response = await client.chat.completions.create(
64
- model="gpt-4o",
65
- messages=context.messages,
66
- stream=True
64
+ stream = await client.responses.create(
65
+ model="o3-mini",
66
+ input=context.messages,
67
+ stream=True,
68
+ reasoning={"effort": "medium", "summary": "auto"},
67
69
  )
68
70
 
69
- async for chunk in response:
70
- if chunk.choices[0].delta.content:
71
- yield chunk.choices[0].delta.content
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
72
76
 
73
- agent.deploy() # Live at https://my-agent.cycls.ai
77
+ agent.deploy() # Live at https://agent.cycls.ai
74
78
  ```
75
79
 
76
80
  ## Installation
@@ -87,7 +91,7 @@ Requires Docker.
87
91
  - **Web Interface** - Chat UI served automatically
88
92
  - **Authentication** - `auth=True` enables JWT-based access control
89
93
  - **Analytics** - `analytics=True` tracks usage
90
- - **Monetization** - `tier="cycls_pass"` integrates with [Cycls Pass](https://cycls.ai) subscriptions
94
+ - **Monetization** - `plan="cycls_pass"` integrates with [Cycls Pass](https://cycls.ai) subscriptions
91
95
  - **Native UI Components** - Render thinking bubbles, tables, code blocks in responses
92
96
 
93
97
  ## Running
@@ -95,17 +99,33 @@ Requires Docker.
95
99
  ```python
96
100
  agent.local() # Development with hot-reload (localhost:8080)
97
101
  agent.local(watch=False) # Development without hot-reload
98
- agent.deploy() # Production: https://agent-name.cycls.ai
102
+ agent.deploy() # Production: https://agent.cycls.ai
99
103
  ```
100
104
 
101
105
  Get an API key at [cycls.com](https://cycls.com).
102
106
 
107
+ ## Authentication & Analytics
108
+
109
+ ```python
110
+ @cycls.agent(pip=["openai"], auth=True, analytics=True)
111
+ async def agent(context):
112
+ # context.user available when auth=True
113
+ user = context.user # User(id, email, name, plans)
114
+ yield f"Hello {user.name}!"
115
+ ```
116
+
117
+ | Flag | Description |
118
+ |------|-------------|
119
+ | `auth=True` | Universal user pool via Cycls Pass (Clerk-based). You can also use your own Clerk auth. |
120
+ | `analytics=True` | Rich usage metrics available on the Cycls dashboard. |
121
+ | `plan="cycls_pass"` | Monetization via Cycls Pass subscriptions. Enables both auth and analytics. |
122
+
103
123
  ## Native UI Components
104
124
 
105
125
  Yield structured objects for rich streaming responses:
106
126
 
107
127
  ```python
108
- @agent()
128
+ @cycls.agent()
109
129
  async def demo(context):
110
130
  yield {"type": "thinking", "thinking": "Analyzing the request..."}
111
131
  yield "Here's what I found:\n\n"
@@ -128,32 +148,26 @@ async def demo(context):
128
148
  | `{"type": "callout", "callout": "...", "style": "..."}` | Yes |
129
149
  | `{"type": "image", "src": "..."}` | Yes |
130
150
 
131
- ### Reasoning Models
151
+ ### Thinking Bubbles
132
152
 
133
- ```python
134
- @agent()
135
- async def chat(context):
136
- from openai import AsyncOpenAI
137
- client = AsyncOpenAI()
153
+ 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:
138
154
 
139
- stream = await client.responses.create(
140
- model="o3-mini",
141
- input=context.messages,
142
- stream=True,
143
- reasoning={"effort": "medium", "summary": "auto"},
144
- )
155
+ ```python
156
+ # Multiple yields build one thinking bubble
157
+ yield {"type": "thinking", "thinking": "Let me "}
158
+ yield {"type": "thinking", "thinking": "analyze this..."}
159
+ yield {"type": "thinking", "thinking": " Done thinking."}
145
160
 
146
- async for event in stream:
147
- if event.type == "response.reasoning_summary_text.delta":
148
- yield {"type": "thinking", "thinking": event.delta}
149
- elif event.type == "response.output_text.delta":
150
- yield event.delta
161
+ # Then output the response
162
+ yield "Here's what I found..."
151
163
  ```
152
164
 
165
+ This works seamlessly with OpenAI's reasoning models - just map reasoning summaries to the thinking component.
166
+
153
167
  ## Context Object
154
168
 
155
169
  ```python
156
- @agent()
170
+ @cycls.agent()
157
171
  async def chat(context):
158
172
  context.messages # [{"role": "user", "content": "..."}]
159
173
  context.messages.raw # Full data including UI component parts
@@ -183,16 +197,17 @@ See [docs/streaming-protocol.md](docs/streaming-protocol.md) for frontend integr
183
197
 
184
198
  ## Declarative Infrastructure
185
199
 
186
- Define your entire runtime in Python:
200
+ Define your entire runtime in the decorator:
187
201
 
188
202
  ```python
189
- agent = cycls.Agent(
203
+ @cycls.agent(
190
204
  pip=["openai", "pandas", "numpy"],
191
205
  apt=["ffmpeg", "libmagic1"],
192
- run_commands=["curl -sSL https://example.com/setup.sh | bash"],
193
206
  copy=["./utils.py", "./models/", "/absolute/path/to/config.json"],
194
207
  copy_public=["./assets/logo.png", "./static/"],
195
208
  )
209
+ async def my_agent(context):
210
+ ...
196
211
  ```
197
212
 
198
213
  ### `pip` - Python Packages
@@ -211,17 +226,6 @@ Install system-level dependencies via apt-get. Need ffmpeg for audio processing?
211
226
  apt=["ffmpeg", "imagemagick", "libpq-dev"]
212
227
  ```
213
228
 
214
- ### `run_commands` - Shell Commands
215
-
216
- Run arbitrary shell commands during the container build. Useful for custom setup scripts, downloading assets, or any build-time configuration.
217
-
218
- ```python
219
- run_commands=[
220
- "curl -sSL https://example.com/setup.sh | bash",
221
- "chmod +x /app/scripts/*.sh"
222
- ]
223
- ```
224
-
225
229
  ### `copy` - Bundle Files and Directories
226
230
 
227
231
  Include local files and directories in your container. Works with both relative and absolute paths. Copies files and entire directory trees.
@@ -237,7 +241,7 @@ copy=[
237
241
  Then import them in your function:
238
242
 
239
243
  ```python
240
- @agent()
244
+ @cycls.agent(copy=["./utils.py"])
241
245
  async def chat(context):
242
246
  from utils import helper_function # Your bundled module
243
247
  ...
@@ -1,14 +1,14 @@
1
- cycls/__init__.py,sha256=bVT0dYTXLdSC3ZURgtm-DEOj-VO6RUM6zGsJB0zuj6Y,61
1
+ cycls/__init__.py,sha256=HEpBZpHkC-4YwDUqcKAcnulyPxcvKnplhx91nB2a7IU,464
2
2
  cycls/auth.py,sha256=xkndHZyCfnlertMMEKerCJjf23N3fVcTRVTTSXTTuzg,247
3
3
  cycls/cli.py,sha256=AKf0z7ZLau3GvBVR_IhB7agmq4nVaHkcuUafNyvv2_A,7978
4
4
  cycls/default-theme/assets/index-B0ZKcm_V.css,sha256=wK9-NhEB8xPcN9Zv69zpOcfGTlFbMwyC9WqTmSKUaKw,6546
5
5
  cycls/default-theme/assets/index-D5EDcI4J.js,sha256=sN4qRcAXa7DBd9JzmVcCoCwH4l8cNCM-U9QGUjBvWSo,1346506
6
6
  cycls/default-theme/index.html,sha256=bM-yW_g0cGrV40Q5yY3ccY0fM4zI1Wuu5I8EtGFJIxs,828
7
7
  cycls/dev-theme/index.html,sha256=QJBHkdNuMMiwQU7o8dN8__8YQeQB45D37D-NCXIWB2Q,11585
8
- cycls/runtime.py,sha256=LgOrQ6Arh-GWSJqckfra-CvjeSekTvGvjHOBxu7JTQQ,21408
9
- cycls/sdk.py,sha256=6oRKP44TJN9HKdNw9OYzDlZFDUMUhoCMt8TEwyu26dI,7368
10
- cycls/web.py,sha256=3M3qaWTNY3dpgd7Vq5aXREp-cIFsHrDqBQ1YkGrOaUk,4659
11
- cycls-0.0.2.71.dist-info/METADATA,sha256=MG66f3JLtPXNMLV1rCs29BYkBxk2B3aMIG5_azsD9HI,8008
12
- cycls-0.0.2.71.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
13
- cycls-0.0.2.71.dist-info/entry_points.txt,sha256=vEhqUxFhhuzCKWtq02LbMnT3wpUqdfgcM3Yh-jjXom8,40
14
- cycls-0.0.2.71.dist-info/RECORD,,
8
+ cycls/runtime.py,sha256=lg7XKHd9fLV_bYksHv2LHf3Lq7HPAC3K5Tr8pNgQ7sM,21641
9
+ cycls/sdk.py,sha256=X8-VAVqtksO0VGJIxlg02HLmeFpwtwMHWu9PNksS5kw,6620
10
+ cycls/web.py,sha256=_QNH8K55vTm90Z7tvcRKal5IybjkB1GY7Pf9p3qu3r8,4659
11
+ cycls-0.0.2.73.dist-info/METADATA,sha256=IP8h-NzyerOy701pjRYDbY_Nbvb1WsoU6JTKYE8xQ34,8695
12
+ cycls-0.0.2.73.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
13
+ cycls-0.0.2.73.dist-info/entry_points.txt,sha256=vEhqUxFhhuzCKWtq02LbMnT3wpUqdfgcM3Yh-jjXom8,40
14
+ cycls-0.0.2.73.dist-info/RECORD,,