chainlit 0.2.111__py3-none-any.whl → 0.3.0__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.
Potentially problematic release.
This version of chainlit might be problematic. Click here for more details.
- chainlit/__init__.py +48 -32
- chainlit/action.py +12 -12
- chainlit/cache.py +20 -0
- chainlit/cli/__init__.py +43 -62
- chainlit/cli/mock.py +48 -0
- chainlit/client.py +111 -89
- chainlit/config.py +22 -3
- chainlit/element.py +95 -124
- chainlit/{sdk.py → emitter.py} +55 -64
- chainlit/frontend/dist/assets/index-0b7e367e.js +717 -0
- chainlit/frontend/dist/assets/index-0cc9e355.css +1 -0
- chainlit/frontend/dist/index.html +3 -3
- chainlit/hello.py +3 -3
- chainlit/lc/__init__.py +11 -0
- chainlit/lc/agent.py +32 -0
- chainlit/lc/callbacks.py +411 -0
- chainlit/message.py +72 -96
- chainlit/server.py +280 -195
- chainlit/session.py +4 -2
- chainlit/sync.py +37 -0
- chainlit/types.py +18 -1
- chainlit/user_session.py +16 -16
- {chainlit-0.2.111.dist-info → chainlit-0.3.0.dist-info}/METADATA +15 -14
- chainlit-0.3.0.dist-info/RECORD +37 -0
- chainlit/frontend/dist/assets/index-4d8f8873.js +0 -713
- chainlit/frontend/dist/assets/index-bdffdaa0.css +0 -1
- chainlit/lc/chainlit_handler.py +0 -271
- chainlit/lc/monkey.py +0 -28
- chainlit/lc/new_monkey.py +0 -167
- chainlit/lc/old_monkey.py +0 -119
- chainlit/lc/utils.py +0 -38
- chainlit/watch.py +0 -54
- chainlit-0.2.111.dist-info/RECORD +0 -38
- {chainlit-0.2.111.dist-info → chainlit-0.3.0.dist-info}/WHEEL +0 -0
- {chainlit-0.2.111.dist-info → chainlit-0.3.0.dist-info}/entry_points.txt +0 -0
chainlit/{sdk.py → emitter.py}
RENAMED
|
@@ -6,22 +6,25 @@ from socketio.exceptions import TimeoutError
|
|
|
6
6
|
import inspect
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ChainlitEmitter:
|
|
10
10
|
"""
|
|
11
|
-
Chainlit
|
|
12
|
-
Instead, the developer interacts with the
|
|
11
|
+
Chainlit Emitter class. The Emitter is not directly exposed to the developer.
|
|
12
|
+
Instead, the developer interacts with the Emitter through the methods and classes exposed in the __init__ file.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
session: Session
|
|
16
16
|
|
|
17
17
|
def __init__(self, session: Session) -> None:
|
|
18
|
-
"""Initialize
|
|
18
|
+
"""Initialize with the user session."""
|
|
19
19
|
self.session = session
|
|
20
20
|
|
|
21
|
-
def _get_session_property(self, property_name: str):
|
|
21
|
+
def _get_session_property(self, property_name: str, raise_error=True):
|
|
22
22
|
"""Helper method to get a property from the session."""
|
|
23
23
|
if not hasattr(self, "session") or property_name not in self.session:
|
|
24
|
-
|
|
24
|
+
if raise_error:
|
|
25
|
+
raise ValueError(f"Session does not have property '{property_name}'")
|
|
26
|
+
else:
|
|
27
|
+
return None
|
|
25
28
|
return self.session[property_name]
|
|
26
29
|
|
|
27
30
|
@property
|
|
@@ -37,50 +40,47 @@ class Chainlit:
|
|
|
37
40
|
@property
|
|
38
41
|
def client(self) -> Union[BaseClient, None]:
|
|
39
42
|
"""Get the 'client' property from the session."""
|
|
40
|
-
return self._get_session_property("client")
|
|
43
|
+
return self._get_session_property("client", raise_error=False)
|
|
41
44
|
|
|
42
45
|
def send_message(self, msg_dict: Dict):
|
|
43
46
|
"""Send a message to the UI."""
|
|
44
|
-
if not self.emit:
|
|
45
|
-
return
|
|
46
47
|
|
|
47
|
-
self.emit("
|
|
48
|
+
return self.emit("new_message", msg_dict)
|
|
48
49
|
|
|
49
50
|
def update_message(self, msg_dict: Dict):
|
|
50
51
|
"""Update a message in the UI."""
|
|
51
|
-
if not self.emit:
|
|
52
|
-
return
|
|
53
52
|
|
|
54
|
-
self.emit("update_message", msg_dict)
|
|
53
|
+
return self.emit("update_message", msg_dict)
|
|
55
54
|
|
|
56
|
-
def delete_message(self,
|
|
55
|
+
def delete_message(self, msg_dict):
|
|
57
56
|
"""Delete a message in the UI."""
|
|
58
|
-
if not self.emit:
|
|
59
|
-
return
|
|
60
57
|
|
|
61
|
-
self.emit("delete_message",
|
|
58
|
+
return self.emit("delete_message", msg_dict)
|
|
62
59
|
|
|
63
60
|
def send_ask_timeout(self):
|
|
64
61
|
"""Send a prompt timeout message to the UI."""
|
|
65
62
|
|
|
66
|
-
|
|
67
|
-
self.emit("ask_timeout", {})
|
|
63
|
+
return self.emit("ask_timeout", {})
|
|
68
64
|
|
|
69
65
|
def clear_ask(self):
|
|
70
66
|
"""Clear the prompt from the UI."""
|
|
71
|
-
if self.emit:
|
|
72
|
-
self.emit("clear_ask", {})
|
|
73
67
|
|
|
74
|
-
|
|
68
|
+
return self.emit("clear_ask", {})
|
|
69
|
+
|
|
70
|
+
async def send_ask_user(
|
|
71
|
+
self, msg_dict: Dict, spec: AskSpec, raise_on_timeout=False
|
|
72
|
+
):
|
|
75
73
|
"""Send a prompt to the UI and wait for a response."""
|
|
76
|
-
if not self.ask_user:
|
|
77
|
-
return
|
|
78
74
|
|
|
79
75
|
try:
|
|
80
|
-
# End the task temporarily so that the User can answer the prompt
|
|
81
|
-
self.task_end()
|
|
82
76
|
# Send the prompt to the UI
|
|
83
|
-
res = self.ask_user(
|
|
77
|
+
res = await self.ask_user(
|
|
78
|
+
{"msg": msg_dict, "spec": spec.to_dict()}, spec.timeout
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# End the task temporarily so that the User can answer the prompt
|
|
82
|
+
await self.task_end()
|
|
83
|
+
|
|
84
84
|
if self.client and res:
|
|
85
85
|
# If cloud is enabled, store the response in the database/S3
|
|
86
86
|
if spec.type == "text":
|
|
@@ -89,80 +89,71 @@ class Chainlit:
|
|
|
89
89
|
"authorIsUser": True,
|
|
90
90
|
"content": res["content"],
|
|
91
91
|
}
|
|
92
|
-
self.client.create_message(res_msg)
|
|
92
|
+
await self.client.create_message(res_msg)
|
|
93
93
|
elif spec.type == "file":
|
|
94
94
|
# TODO: upload file to S3
|
|
95
95
|
pass
|
|
96
96
|
|
|
97
|
-
self.clear_ask()
|
|
97
|
+
await self.clear_ask()
|
|
98
98
|
return res
|
|
99
99
|
except TimeoutError as e:
|
|
100
|
-
self.send_ask_timeout()
|
|
100
|
+
await self.send_ask_timeout()
|
|
101
101
|
|
|
102
102
|
if raise_on_timeout:
|
|
103
103
|
raise e
|
|
104
104
|
finally:
|
|
105
|
-
self.task_start()
|
|
105
|
+
await self.task_start()
|
|
106
106
|
|
|
107
107
|
def update_token_count(self, count: int):
|
|
108
108
|
"""Update the token count for the UI."""
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self.emit("token_usage", count)
|
|
109
|
+
|
|
110
|
+
return self.emit("token_usage", count)
|
|
112
111
|
|
|
113
112
|
def task_start(self):
|
|
114
113
|
"""
|
|
115
114
|
Send a task start signal to the UI.
|
|
116
115
|
"""
|
|
117
|
-
|
|
118
|
-
self.emit("task_start", {})
|
|
116
|
+
return self.emit("task_start", {})
|
|
119
117
|
|
|
120
118
|
def task_end(self):
|
|
121
119
|
"""Send a task end signal to the UI."""
|
|
122
|
-
|
|
123
|
-
self.emit("task_end", {})
|
|
120
|
+
return self.emit("task_end", {})
|
|
124
121
|
|
|
125
122
|
def stream_start(self, msg_dict: Dict):
|
|
126
123
|
"""Send a stream start signal to the UI."""
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
124
|
+
return self.emit(
|
|
125
|
+
"stream_start",
|
|
126
|
+
msg_dict,
|
|
127
|
+
)
|
|
132
128
|
|
|
133
|
-
def send_token(self, token: str):
|
|
129
|
+
def send_token(self, id: Union[str, int], token: str):
|
|
134
130
|
"""Send a message token to the UI."""
|
|
135
|
-
|
|
136
|
-
self.emit("stream_token", token)
|
|
131
|
+
return self.emit("stream_token", {"id": id, "token": token})
|
|
137
132
|
|
|
138
|
-
def stream_end(self, msg):
|
|
139
|
-
"""Send a stream end signal to the UI."""
|
|
140
|
-
if self.emit:
|
|
141
|
-
self.emit("stream_end", msg)
|
|
142
133
|
|
|
143
|
-
|
|
144
|
-
def get_sdk() -> Union[Chainlit, None]:
|
|
134
|
+
def get_emitter() -> Union[ChainlitEmitter, None]:
|
|
145
135
|
"""
|
|
146
|
-
Get the Chainlit
|
|
136
|
+
Get the Chainlit Emitter instance from the current call stack.
|
|
147
137
|
This unusual approach is necessary because:
|
|
148
|
-
- we need to get the right
|
|
149
|
-
- to preserve a lean developer experience, we do not pass the
|
|
138
|
+
- we need to get the right Emitter instance with the right websocket connection
|
|
139
|
+
- to preserve a lean developer experience, we do not pass the Emitter instance to every function call
|
|
150
140
|
|
|
151
|
-
What happens is that we set
|
|
141
|
+
What happens is that we set __chainlit_emitter__ in the local variables when we receive a websocket message.
|
|
152
142
|
Then we can retrieve it from the call stack when we need it, even if the developer's code has no idea about it.
|
|
153
143
|
"""
|
|
154
|
-
attr = "
|
|
144
|
+
attr = "__chainlit_emitter__"
|
|
155
145
|
candidates = [i[0].f_locals.get(attr) for i in inspect.stack()]
|
|
156
|
-
|
|
146
|
+
emitter = None
|
|
157
147
|
for candidate in candidates:
|
|
158
148
|
if candidate:
|
|
159
|
-
|
|
149
|
+
emitter = candidate
|
|
160
150
|
break
|
|
161
|
-
|
|
151
|
+
|
|
152
|
+
return emitter
|
|
162
153
|
|
|
163
154
|
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
if
|
|
167
|
-
return
|
|
155
|
+
def get_emit_fn():
|
|
156
|
+
emitter = get_emitter()
|
|
157
|
+
if emitter:
|
|
158
|
+
return emitter.emit
|
|
168
159
|
return None
|