cycls 0.0.2.78__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 +20 -0
- cycls/auth.py +4 -0
- cycls/cli.py +217 -0
- cycls/default-theme/assets/index-B0ZKcm_V.css +1 -0
- cycls/default-theme/assets/index-D5EDcI4J.js +422 -0
- cycls/default-theme/index.html +28 -0
- cycls/dev-theme/index.html +298 -0
- cycls/grpc/__init__.py +3 -0
- cycls/grpc/client.py +71 -0
- cycls/grpc/runtime.proto +18 -0
- cycls/grpc/runtime_pb2.py +40 -0
- cycls/grpc/runtime_pb2_grpc.py +100 -0
- cycls/grpc/server.py +60 -0
- cycls/runtime.py +465 -0
- cycls/sdk.py +181 -0
- cycls/web.py +131 -0
- cycls-0.0.2.78.dist-info/METADATA +274 -0
- cycls-0.0.2.78.dist-info/RECORD +20 -0
- cycls-0.0.2.78.dist-info/WHEEL +4 -0
- cycls-0.0.2.78.dist-info/entry_points.txt +3 -0
cycls/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from types import ModuleType
|
|
3
|
+
from .sdk import function, agent
|
|
4
|
+
from .runtime import Runtime
|
|
5
|
+
|
|
6
|
+
class _Module(ModuleType):
|
|
7
|
+
def __getattr__(self, name):
|
|
8
|
+
from . import sdk
|
|
9
|
+
if name in ("api_key", "base_url"):
|
|
10
|
+
return getattr(sdk, name)
|
|
11
|
+
raise AttributeError(f"module 'cycls' has no attribute '{name}'")
|
|
12
|
+
|
|
13
|
+
def __setattr__(self, name, value):
|
|
14
|
+
from . import sdk
|
|
15
|
+
if name in ("api_key", "base_url"):
|
|
16
|
+
setattr(sdk, name, value)
|
|
17
|
+
return
|
|
18
|
+
super().__setattr__(name, value)
|
|
19
|
+
|
|
20
|
+
sys.modules[__name__].__class__ = _Module
|
cycls/auth.py
ADDED
cycls/cli.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
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()
|
|
@@ -0,0 +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)}
|