cycls 0.0.2.47__tar.gz → 0.0.2.49__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycls
3
- Version: 0.0.2.47
3
+ Version: 0.0.2.49
4
4
  Summary: Cycls SDK
5
5
  Author: Mohammed J. AlRujayi
6
6
  Author-email: mj@cycls.com
@@ -40,15 +40,7 @@ The Distribution SDK for AI Agents.
40
40
 
41
41
  # Cycls 🚲
42
42
 
43
- `cycls` is a zero-config framework for building and publishing AI agents. With a single decorator and one command, you can deploy your code as a web application complete with a front-end UI and an OpenAI-compatible API endpoint.
44
-
45
- ### Design Philosophy
46
- `cycls` is an anti-framework. We treat the boilerplate, config files, and infrastructure that surround modern applications as a bug to be eliminated. A developer's focus is the most valuable resource, and context-switching is its greatest enemy.
47
-
48
- Our zero-config approach makes your Python script the single source of truth for the entire application. When your code is all you need, you stay focused, iterate faster, and ship with confidence.
49
-
50
- This philosophy has a powerful side-effect: it makes development genuinely iterative. The self-contained nature of an agent encourages you to 'build in cycles'—starting simple and adding complexity without penalty. This same simplicity also makes `cycls` an ideal target for code generation. Because the entire application can be expressed in one file, LLMs can write, modify, and reason about `cycls` agents far more effectively than with traditional frameworks. It's a seamless interface for both human and machine.
51
-
43
+ `cycls` is an open-source SDK for building and publishing AI agents. With a single decorator and one command, you can deploy your code as a web application complete with a front-end UI and an OpenAI-compatible API endpoint.
52
44
 
53
45
  ## Key Features
54
46
 
@@ -67,6 +59,8 @@ This philosophy has a powerful side-effect: it makes development genuinely itera
67
59
  pip install cycls
68
60
  ```
69
61
 
62
+ **Note:** You must have [Docker](https://www.docker.com/get-started) installed and running on your machine.
63
+
70
64
  ## How to Use
71
65
  ### 1. Local Development: "Hello, World!"
72
66
 
@@ -81,9 +75,9 @@ agent = cycls.Agent()
81
75
  # Decorate your function to register it as an agent
82
76
  @agent()
83
77
  async def hello(context):
84
- yield "hi"
78
+ yield "Hello, World!"
85
79
 
86
- agent.local()
80
+ agent.deploy(prod=False)
87
81
  ```
88
82
 
89
83
  Run it from your terminal:
@@ -103,12 +97,12 @@ import cycls
103
97
  # Initialize the agent with dependencies and API keys
104
98
  agent = cycls.Agent(
105
99
  pip=["openai"],
106
- keys=["ak-<token_id>", "as-<token_secret>"]
100
+ key=["YOUR_CYCLS_KEY"] # Get yours from cycls.com
107
101
  )
108
102
 
109
103
  # A helper function to call the LLM
110
104
  async def llm(messages):
111
- # Import inside the function: 'openai' is only needed at runtime in the container.
105
+ # Import inside the function: 'openai' is needed at runtime in the container.
112
106
  import openai
113
107
  client = openai.AsyncOpenAI(api_key="sk-...") # Your OpenAI key
114
108
  model = "gpt-4o"
@@ -18,15 +18,7 @@ The Distribution SDK for AI Agents.
18
18
 
19
19
  # Cycls 🚲
20
20
 
21
- `cycls` is a zero-config framework for building and publishing AI agents. With a single decorator and one command, you can deploy your code as a web application complete with a front-end UI and an OpenAI-compatible API endpoint.
22
-
23
- ### Design Philosophy
24
- `cycls` is an anti-framework. We treat the boilerplate, config files, and infrastructure that surround modern applications as a bug to be eliminated. A developer's focus is the most valuable resource, and context-switching is its greatest enemy.
25
-
26
- Our zero-config approach makes your Python script the single source of truth for the entire application. When your code is all you need, you stay focused, iterate faster, and ship with confidence.
27
-
28
- This philosophy has a powerful side-effect: it makes development genuinely iterative. The self-contained nature of an agent encourages you to 'build in cycles'—starting simple and adding complexity without penalty. This same simplicity also makes `cycls` an ideal target for code generation. Because the entire application can be expressed in one file, LLMs can write, modify, and reason about `cycls` agents far more effectively than with traditional frameworks. It's a seamless interface for both human and machine.
29
-
21
+ `cycls` is an open-source SDK for building and publishing AI agents. With a single decorator and one command, you can deploy your code as a web application complete with a front-end UI and an OpenAI-compatible API endpoint.
30
22
 
31
23
  ## Key Features
32
24
 
@@ -45,6 +37,8 @@ This philosophy has a powerful side-effect: it makes development genuinely itera
45
37
  pip install cycls
46
38
  ```
47
39
 
40
+ **Note:** You must have [Docker](https://www.docker.com/get-started) installed and running on your machine.
41
+
48
42
  ## How to Use
49
43
  ### 1. Local Development: "Hello, World!"
50
44
 
@@ -59,9 +53,9 @@ agent = cycls.Agent()
59
53
  # Decorate your function to register it as an agent
60
54
  @agent()
61
55
  async def hello(context):
62
- yield "hi"
56
+ yield "Hello, World!"
63
57
 
64
- agent.local()
58
+ agent.deploy(prod=False)
65
59
  ```
66
60
 
67
61
  Run it from your terminal:
@@ -81,12 +75,12 @@ import cycls
81
75
  # Initialize the agent with dependencies and API keys
82
76
  agent = cycls.Agent(
83
77
  pip=["openai"],
84
- keys=["ak-<token_id>", "as-<token_secret>"]
78
+ key=["YOUR_CYCLS_KEY"] # Get yours from cycls.com
85
79
  )
86
80
 
87
81
  # A helper function to call the LLM
88
82
  async def llm(messages):
89
- # Import inside the function: 'openai' is only needed at runtime in the container.
83
+ # Import inside the function: 'openai' is needed at runtime in the container.
90
84
  import openai
91
85
  client = openai.AsyncOpenAI(api_key="sk-...") # Your OpenAI key
92
86
  model = "gpt-4o"
@@ -4,25 +4,24 @@ from modal.runner import run_app
4
4
  from .web import web
5
5
  import importlib.resources
6
6
 
7
- theme_path = importlib.resources.files('cycls').joinpath('theme')
8
- cycls_path = importlib.resources.files('cycls')
7
+ CYCLS_PATH = importlib.resources.files('cycls')
9
8
 
10
- def function(python_version=None, pip=None, apt=None, run_commands=None, copy=None, name=None, base_url=None, api_key=None):
9
+ def function(python_version=None, pip=None, apt=None, run_commands=None, copy=None, name=None, base_url=None, key=None):
11
10
  # """
12
11
  # A decorator factory that transforms a Python function into a containerized,
13
12
  # remotely executable object.
14
13
  def decorator(func):
15
14
  Name = name or func.__name__
16
15
  copy_dict = {i:i for i in copy or []}
17
- return Runtime(func, Name.replace('_', '-'), python_version, pip, apt, run_commands, copy_dict, base_url, api_key)
16
+ return Runtime(func, Name.replace('_', '-'), python_version, pip, apt, run_commands, copy_dict, base_url, key)
18
17
  return decorator
19
18
 
20
19
  class Agent:
21
- def __init__(self, theme=theme_path, org=None, api_token=None, pip=[], apt=[], copy=[], copy_public=[], keys=["",""], api_key=None):
20
+ def __init__(self, theme=CYCLS_PATH.joinpath('theme'), org=None, api_token=None, pip=[], apt=[], copy=[], copy_public=[], modal_keys=["",""], key=None, base_url=None):
22
21
  self.org, self.api_token = org, api_token
23
22
  self.theme = theme
24
- self.keys, self.pip, self.apt, self.copy, self.copy_public = keys, pip, apt, copy, copy_public
25
- self.api_key = api_key
23
+ self.key, self.modal_keys, self.pip, self.apt, self.copy, self.copy_public = key, modal_keys, pip, apt, copy, copy_public
24
+ self.base_url = base_url
26
25
 
27
26
  self.registered_functions = []
28
27
 
@@ -30,7 +29,7 @@ class Agent:
30
29
  def decorator(f):
31
30
  self.registered_functions.append({
32
31
  "func": f,
33
- "config": ["public", False, self.org, self.api_token, header, intro, title, auth],
32
+ "config": ["theme", False, self.org, self.api_token, header, intro, title, auth],
34
33
  # "name": name,
35
34
  "name": name or (f.__name__).replace('_', '-'),
36
35
  "domain": domain or f"{name}.cycls.ai",
@@ -55,7 +54,7 @@ class Agent:
55
54
  if not self.registered_functions:
56
55
  print("Error: No @agent decorated function found.")
57
56
  return
58
- if (self.api_key is None) and prod:
57
+ if (self.key is None) and prod:
59
58
  print("🛑 Error: Please add your Cycls API key")
60
59
  return
61
60
 
@@ -65,38 +64,44 @@ class Agent:
65
64
 
66
65
  i["config"][1] = False
67
66
 
68
- copy={str(self.theme):"public", str(cycls_path)+"/web.py":"web.py"}
67
+ copy={str(self.theme):"theme", str(CYCLS_PATH)+"/web.py":"web.py"}
69
68
  copy.update({i:i for i in self.copy})
70
- copy.update({i:f"a/{i}" for i in self.copy_public})
69
+ copy.update({i:f"public/{i}" for i in self.copy_public})
71
70
 
72
- def runner(port):
71
+ def server(port):
73
72
  import uvicorn, logging
74
73
  # This one-liner hides the confusing "0.0.0.0" message
75
74
  logging.getLogger("uvicorn.error").addFilter(type("F",(),{"filter": lambda s,r: "0.0.0.0" not in r.getMessage()})())
76
- print(f"\n🚀 Local Link: http://localhost:{port}\n")
75
+ print(f"\n🔨 Visit {i["name"]} => http://localhost:{port}\n")
77
76
  uvicorn.run(__import__("web").web(i["func"], *i["config"]), host="0.0.0.0", port=port)
78
77
 
79
78
  new = Runtime(
80
79
  # func=lambda port: __import__("uvicorn").run(__import__("web").web(i["func"], *i["config"]), host="0.0.0.0", port=port),
81
- func=runner,
80
+ func=server,
82
81
  name=i["name"],
83
82
  apt_packages=self.apt,
84
83
  pip_packages=["fastapi[standard]", "pyjwt", "cryptography", "uvicorn", *self.pip],
85
84
  copy=copy,
86
- api_key=self.api_key
85
+ base_url=self.base_url,
86
+ api_key=self.key
87
87
  )
88
88
  new.deploy(port=port) if prod else new.run(port=port)
89
89
  return
90
90
 
91
91
  def modal(self, prod=False):
92
- self.client = modal.Client.from_credentials(*self.keys)
92
+ self.client = modal.Client.from_credentials(*self.modal_keys)
93
93
  image = (modal.Image.debian_slim()
94
94
  .pip_install("fastapi[standard]", "pyjwt", "cryptography", *self.pip)
95
95
  .apt_install(*self.apt)
96
- .add_local_dir(self.theme, "/root/public")
97
- .add_local_file(str(cycls_path)+"/web.py", "/root/web.py"))
96
+ .add_local_dir(self.theme, "/root/theme")
97
+ .add_local_file(str(CYCLS_PATH)+"/web.py", "/root/web.py"))
98
+
98
99
  for item in self.copy:
99
100
  image = image.add_local_file(item, f"/root/{item}") if "." in item else image.add_local_dir(item, f'/root/{item}')
101
+
102
+ for item in self.copy_public:
103
+ image = image.add_local_file(item, f"/root/public/{item}") if "." in item else image.add_local_dir(item, f'/root/public/{item}')
104
+
100
105
  self.app = modal.App("development", image=image)
101
106
 
102
107
  if not self.registered_functions:
@@ -119,8 +119,8 @@ def web(func, public_path="", prod=False, org=None, api_token=None, header="", i
119
119
  pk_test="pk_test_c2VsZWN0LXNsb3RoLTU4LmNsZXJrLmFjY291bnRzLmRldiQ"
120
120
  )
121
121
 
122
- if Path("a").is_dir():
123
- app.mount("/a", StaticFiles(directory="a", html=True))
122
+ if Path("public").is_dir():
123
+ app.mount("/public", StaticFiles(directory="public", html=True))
124
124
  app.mount("/", StaticFiles(directory=public_path, html=True))
125
125
 
126
126
  return app
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cycls"
3
- version = "0.0.2.47"
3
+ version = "0.0.2.49"
4
4
 
5
5
  packages = [{ include = "cycls" }]
6
6
  include = ["cycls/theme/**/*"]
File without changes
File without changes