chainlit 1.0.401__py3-none-any.whl → 2.0.4__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.

Files changed (113) hide show
  1. chainlit/__init__.py +98 -279
  2. chainlit/_utils.py +8 -0
  3. chainlit/action.py +12 -10
  4. chainlit/{auth.py → auth/__init__.py} +28 -36
  5. chainlit/auth/cookie.py +123 -0
  6. chainlit/auth/jwt.py +39 -0
  7. chainlit/cache.py +4 -6
  8. chainlit/callbacks.py +362 -0
  9. chainlit/chat_context.py +64 -0
  10. chainlit/chat_settings.py +3 -1
  11. chainlit/cli/__init__.py +77 -8
  12. chainlit/config.py +191 -102
  13. chainlit/context.py +42 -13
  14. chainlit/copilot/dist/index.js +8750 -903
  15. chainlit/data/__init__.py +101 -416
  16. chainlit/data/acl.py +6 -2
  17. chainlit/data/base.py +107 -0
  18. chainlit/data/chainlit_data_layer.py +614 -0
  19. chainlit/data/dynamodb.py +590 -0
  20. chainlit/data/literalai.py +500 -0
  21. chainlit/data/sql_alchemy.py +721 -0
  22. chainlit/data/storage_clients/__init__.py +0 -0
  23. chainlit/data/storage_clients/azure.py +81 -0
  24. chainlit/data/storage_clients/azure_blob.py +89 -0
  25. chainlit/data/storage_clients/base.py +26 -0
  26. chainlit/data/storage_clients/gcs.py +88 -0
  27. chainlit/data/storage_clients/s3.py +75 -0
  28. chainlit/data/utils.py +29 -0
  29. chainlit/discord/__init__.py +6 -0
  30. chainlit/discord/app.py +354 -0
  31. chainlit/element.py +91 -33
  32. chainlit/emitter.py +81 -29
  33. chainlit/frontend/dist/assets/DailyMotion-Ce9dQoqZ.js +1 -0
  34. chainlit/frontend/dist/assets/Dataframe-C1XonMcV.js +22 -0
  35. chainlit/frontend/dist/assets/Facebook-DVVt6lrr.js +1 -0
  36. chainlit/frontend/dist/assets/FilePlayer-c7stW4vz.js +1 -0
  37. chainlit/frontend/dist/assets/Kaltura-BmMmgorA.js +1 -0
  38. chainlit/frontend/dist/assets/Mixcloud-Cw8hDmiO.js +1 -0
  39. chainlit/frontend/dist/assets/Mux-DiRZfeUf.js +1 -0
  40. chainlit/frontend/dist/assets/Preview-6Jt2mRHx.js +1 -0
  41. chainlit/frontend/dist/assets/SoundCloud-DKwcT58_.js +1 -0
  42. chainlit/frontend/dist/assets/Streamable-BVdxrEeX.js +1 -0
  43. chainlit/frontend/dist/assets/Twitch-DFqZR7Gu.js +1 -0
  44. chainlit/frontend/dist/assets/Vidyard-0BQAAtVk.js +1 -0
  45. chainlit/frontend/dist/assets/Vimeo-CRFSH0Vu.js +1 -0
  46. chainlit/frontend/dist/assets/Wistia-CKrmdQaG.js +1 -0
  47. chainlit/frontend/dist/assets/YouTube-CQpL-rvU.js +1 -0
  48. chainlit/frontend/dist/assets/index-DQmLRKyv.css +1 -0
  49. chainlit/frontend/dist/assets/index-QdmxtIMQ.js +8665 -0
  50. chainlit/frontend/dist/assets/react-plotly-B9hvVpUG.js +3484 -0
  51. chainlit/frontend/dist/index.html +2 -4
  52. chainlit/haystack/callbacks.py +4 -7
  53. chainlit/input_widget.py +8 -4
  54. chainlit/langchain/callbacks.py +103 -68
  55. chainlit/langflow/__init__.py +1 -0
  56. chainlit/llama_index/callbacks.py +65 -40
  57. chainlit/markdown.py +22 -6
  58. chainlit/message.py +54 -56
  59. chainlit/mistralai/__init__.py +50 -0
  60. chainlit/oauth_providers.py +266 -8
  61. chainlit/openai/__init__.py +10 -18
  62. chainlit/secret.py +1 -1
  63. chainlit/server.py +789 -228
  64. chainlit/session.py +108 -90
  65. chainlit/slack/__init__.py +6 -0
  66. chainlit/slack/app.py +397 -0
  67. chainlit/socket.py +199 -116
  68. chainlit/step.py +141 -89
  69. chainlit/sync.py +2 -1
  70. chainlit/teams/__init__.py +6 -0
  71. chainlit/teams/app.py +338 -0
  72. chainlit/translations/bn.json +244 -0
  73. chainlit/translations/en-US.json +122 -8
  74. chainlit/translations/gu.json +244 -0
  75. chainlit/translations/he-IL.json +244 -0
  76. chainlit/translations/hi.json +244 -0
  77. chainlit/translations/ja.json +242 -0
  78. chainlit/translations/kn.json +244 -0
  79. chainlit/translations/ml.json +244 -0
  80. chainlit/translations/mr.json +244 -0
  81. chainlit/translations/nl-NL.json +242 -0
  82. chainlit/translations/ta.json +244 -0
  83. chainlit/translations/te.json +244 -0
  84. chainlit/translations/zh-CN.json +243 -0
  85. chainlit/translations.py +60 -0
  86. chainlit/types.py +133 -28
  87. chainlit/user.py +14 -3
  88. chainlit/user_session.py +6 -3
  89. chainlit/utils.py +52 -5
  90. chainlit/version.py +3 -2
  91. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/METADATA +48 -50
  92. chainlit-2.0.4.dist-info/RECORD +107 -0
  93. chainlit/cli/utils.py +0 -24
  94. chainlit/frontend/dist/assets/index-9711593e.js +0 -723
  95. chainlit/frontend/dist/assets/index-d088547c.css +0 -1
  96. chainlit/frontend/dist/assets/react-plotly-d8762cc2.js +0 -3602
  97. chainlit/playground/__init__.py +0 -2
  98. chainlit/playground/config.py +0 -40
  99. chainlit/playground/provider.py +0 -108
  100. chainlit/playground/providers/__init__.py +0 -13
  101. chainlit/playground/providers/anthropic.py +0 -118
  102. chainlit/playground/providers/huggingface.py +0 -75
  103. chainlit/playground/providers/langchain.py +0 -89
  104. chainlit/playground/providers/openai.py +0 -408
  105. chainlit/playground/providers/vertexai.py +0 -171
  106. chainlit/translations/pt-BR.json +0 -155
  107. chainlit-1.0.401.dist-info/RECORD +0 -66
  108. /chainlit/copilot/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
  109. /chainlit/copilot/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
  110. /chainlit/frontend/dist/assets/{logo_dark-2a3cf740.svg → logo_dark-IkGJ_IwC.svg} +0 -0
  111. /chainlit/frontend/dist/assets/{logo_light-b078e7bc.svg → logo_light-Bb_IPh6r.svg} +0 -0
  112. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/WHEEL +0 -0
  113. {chainlit-1.0.401.dist-info → chainlit-2.0.4.dist-info}/entry_points.txt +0 -0
chainlit/step.py CHANGED
@@ -3,19 +3,44 @@ import inspect
3
3
  import json
4
4
  import time
5
5
  import uuid
6
+ from copy import deepcopy
6
7
  from functools import wraps
7
8
  from typing import Callable, Dict, List, Optional, TypedDict, Union
8
9
 
10
+ from literalai import BaseGeneration
11
+ from literalai.helper import utc_now
12
+ from literalai.observability.step import StepType, TrueStepType
13
+
9
14
  from chainlit.config import config
10
- from chainlit.context import context, local_steps
15
+ from chainlit.context import CL_RUN_NAMES, context, local_steps
11
16
  from chainlit.data import get_data_layer
12
17
  from chainlit.element import Element
13
18
  from chainlit.logger import logger
14
19
  from chainlit.telemetry import trace_event
15
20
  from chainlit.types import FeedbackDict
16
- from literalai import BaseGeneration
17
- from literalai.helper import utc_now
18
- from literalai.step import StepType, TrueStepType
21
+
22
+
23
+ def check_add_step_in_cot(step: "Step"):
24
+ is_message = step.type in [
25
+ "user_message",
26
+ "assistant_message",
27
+ ]
28
+ is_cl_run = step.name in CL_RUN_NAMES and step.type == "run"
29
+ if config.ui.cot == "hidden" and not is_message and not is_cl_run:
30
+ return False
31
+ return True
32
+
33
+
34
+ def stub_step(step: "Step") -> "StepDict":
35
+ return {
36
+ "type": step.type,
37
+ "name": step.name,
38
+ "id": step.id,
39
+ "parentId": step.parent_id,
40
+ "threadId": step.thread_id,
41
+ "input": "",
42
+ "output": "",
43
+ }
19
44
 
20
45
 
21
46
  class StepDict(TypedDict, total=False):
@@ -24,11 +49,11 @@ class StepDict(TypedDict, total=False):
24
49
  id: str
25
50
  threadId: str
26
51
  parentId: Optional[str]
27
- disableFeedback: bool
28
52
  streaming: bool
29
53
  waitForAnswer: Optional[bool]
30
54
  isError: Optional[bool]
31
55
  metadata: Dict
56
+ tags: Optional[List[str]]
32
57
  input: str
33
58
  output: str
34
59
  createdAt: Optional[str]
@@ -37,20 +62,26 @@ class StepDict(TypedDict, total=False):
37
62
  generation: Optional[Dict]
38
63
  showInput: Optional[Union[bool, str]]
39
64
  language: Optional[str]
40
- indent: Optional[int]
41
65
  feedback: Optional[FeedbackDict]
42
66
 
43
67
 
68
+ def flatten_args_kwargs(func, args, kwargs):
69
+ signature = inspect.signature(func)
70
+ bound_arguments = signature.bind(*args, **kwargs)
71
+ bound_arguments.apply_defaults()
72
+ return {k: deepcopy(v) for k, v in bound_arguments.arguments.items()}
73
+
74
+
44
75
  def step(
45
76
  original_function: Optional[Callable] = None,
46
77
  *,
47
78
  name: Optional[str] = "",
48
79
  type: TrueStepType = "undefined",
49
80
  id: Optional[str] = None,
50
- disable_feedback: bool = True,
51
- root: bool = False,
81
+ parent_id: Optional[str] = None,
82
+ tags: Optional[List[str]] = None,
52
83
  language: Optional[str] = None,
53
- show_input: Union[bool, str] = False,
84
+ show_input: Union[bool, str] = "json",
54
85
  ):
55
86
  """Step decorator for async and sync functions."""
56
87
 
@@ -69,21 +100,22 @@ def step(
69
100
  type=type,
70
101
  name=name,
71
102
  id=id,
72
- disable_feedback=disable_feedback,
73
- root=root,
103
+ parent_id=parent_id,
104
+ tags=tags,
74
105
  language=language,
75
106
  show_input=show_input,
76
107
  ) as step:
77
108
  try:
78
- step.input = {"args": args, "kwargs": kwargs}
79
- except:
80
- pass
109
+ step.input = flatten_args_kwargs(func, args, kwargs)
110
+ except Exception as e:
111
+ logger.exception(e)
81
112
  result = await func(*args, **kwargs)
82
113
  try:
83
114
  if result and not step.output:
84
115
  step.output = result
85
- except:
86
- pass
116
+ except Exception as e:
117
+ step.is_error = True
118
+ step.output = str(e)
87
119
  return result
88
120
 
89
121
  return async_wrapper
@@ -95,21 +127,22 @@ def step(
95
127
  type=type,
96
128
  name=name,
97
129
  id=id,
98
- disable_feedback=disable_feedback,
99
- root=root,
130
+ parent_id=parent_id,
131
+ tags=tags,
100
132
  language=language,
101
133
  show_input=show_input,
102
134
  ) as step:
103
135
  try:
104
- step.input = {"args": args, "kwargs": kwargs}
105
- except:
106
- pass
136
+ step.input = flatten_args_kwargs(func, args, kwargs)
137
+ except Exception as e:
138
+ logger.exception(e)
107
139
  result = func(*args, **kwargs)
108
140
  try:
109
141
  if result and not step.output:
110
142
  step.output = result
111
- except:
112
- pass
143
+ except Exception as e:
144
+ step.is_error = True
145
+ step.output = str(e)
113
146
  return result
114
147
 
115
148
  return sync_wrapper
@@ -127,16 +160,15 @@ class Step:
127
160
  type: TrueStepType
128
161
  id: str
129
162
  parent_id: Optional[str]
130
- disable_feedback: bool
131
163
 
132
164
  streaming: bool
133
165
  persisted: bool
134
166
 
135
- root: bool
136
167
  show_input: Union[bool, str]
137
168
 
138
169
  is_error: Optional[bool]
139
170
  metadata: Dict
171
+ tags: Optional[List[str]]
140
172
  thread_id: str
141
173
  created_at: Union[str, None]
142
174
  start: Union[str, None]
@@ -153,25 +185,25 @@ class Step:
153
185
  id: Optional[str] = None,
154
186
  parent_id: Optional[str] = None,
155
187
  elements: Optional[List[Element]] = None,
156
- disable_feedback: bool = True,
157
- root: bool = False,
188
+ metadata: Optional[Dict] = None,
189
+ tags: Optional[List[str]] = None,
158
190
  language: Optional[str] = None,
159
- show_input: Union[bool, str] = False,
191
+ show_input: Union[bool, str] = "json",
192
+ thread_id: Optional[str] = None,
160
193
  ):
161
194
  trace_event(f"init {self.__class__.__name__} {type}")
162
195
  time.sleep(0.001)
163
196
  self._input = ""
164
197
  self._output = ""
165
- self.thread_id = context.session.thread_id
198
+ self.thread_id = thread_id or context.session.thread_id
166
199
  self.name = name or ""
167
200
  self.type = type
168
201
  self.id = id or str(uuid.uuid4())
169
- self.disable_feedback = disable_feedback
170
- self.metadata = {}
202
+ self.metadata = metadata or {}
203
+ self.tags = tags
171
204
  self.is_error = False
172
205
  self.show_input = show_input
173
206
  self.parent_id = parent_id
174
- self.root = root
175
207
 
176
208
  self.language = language
177
209
  self.generation = None
@@ -185,22 +217,46 @@ class Step:
185
217
  self.persisted = False
186
218
  self.fail_on_persist_error = False
187
219
 
220
+ def _clean_content(self, content):
221
+ """
222
+ Recursively checks and converts bytes objects in content.
223
+ """
224
+
225
+ def handle_bytes(item):
226
+ if isinstance(item, bytes):
227
+ return "STRIPPED_BINARY_DATA"
228
+ elif isinstance(item, dict):
229
+ return {k: handle_bytes(v) for k, v in item.items()}
230
+ elif isinstance(item, list):
231
+ return [handle_bytes(i) for i in item]
232
+ elif isinstance(item, tuple):
233
+ return tuple(handle_bytes(i) for i in item)
234
+ return item
235
+
236
+ return handle_bytes(content)
237
+
188
238
  def _process_content(self, content, set_language=False):
189
239
  if content is None:
190
240
  return ""
191
- if isinstance(content, dict):
241
+ content = self._clean_content(content)
242
+
243
+ if (
244
+ isinstance(content, dict)
245
+ or isinstance(content, list)
246
+ or isinstance(content, tuple)
247
+ ):
192
248
  try:
193
249
  processed_content = json.dumps(content, indent=4, ensure_ascii=False)
194
250
  if set_language:
195
251
  self.language = "json"
196
252
  except TypeError:
197
- processed_content = str(content)
253
+ processed_content = str(content).replace("\\n", "\n")
198
254
  if set_language:
199
255
  self.language = "text"
200
256
  elif isinstance(content, str):
201
257
  processed_content = content
202
258
  else:
203
- processed_content = str(content)
259
+ processed_content = str(content).replace("\\n", "\n")
204
260
  if set_language:
205
261
  self.language = "text"
206
262
  return processed_content
@@ -228,9 +284,9 @@ class Step:
228
284
  "id": self.id,
229
285
  "threadId": self.thread_id,
230
286
  "parentId": self.parent_id,
231
- "disableFeedback": self.disable_feedback,
232
287
  "streaming": self.streaming,
233
288
  "metadata": self.metadata,
289
+ "tags": self.tags,
234
290
  "input": self.input,
235
291
  "isError": self.is_error,
236
292
  "output": self.output,
@@ -261,18 +317,15 @@ class Step:
261
317
  except Exception as e:
262
318
  if self.fail_on_persist_error:
263
319
  raise e
264
- logger.error(f"Failed to persist step update: {str(e)}")
320
+ logger.error(f"Failed to persist step update: {e!s}")
265
321
 
266
322
  tasks = [el.send(for_id=self.id) for el in self.elements]
267
323
  await asyncio.gather(*tasks)
268
324
 
269
- if config.ui.hide_cot and self.parent_id:
270
- return
271
-
272
- if not config.features.prompt_playground and "generation" in step_dict:
273
- step_dict.pop("generation", None)
274
-
275
- await context.emitter.update_step(step_dict)
325
+ if not check_add_step_in_cot(self):
326
+ await context.emitter.update_step(stub_step(self))
327
+ else:
328
+ await context.emitter.update_step(step_dict)
276
329
 
277
330
  return True
278
331
 
@@ -291,7 +344,7 @@ class Step:
291
344
  except Exception as e:
292
345
  if self.fail_on_persist_error:
293
346
  raise e
294
- logger.error(f"Failed to persist step deletion: {str(e)}")
347
+ logger.error(f"Failed to persist step deletion: {e!s}")
295
348
 
296
349
  await context.emitter.delete_step(step_dict)
297
350
 
@@ -299,7 +352,7 @@ class Step:
299
352
 
300
353
  async def send(self):
301
354
  if self.persisted:
302
- return
355
+ return self
303
356
 
304
357
  if config.code.author_rename:
305
358
  self.name = await config.code.author_rename(self.name)
@@ -318,45 +371,48 @@ class Step:
318
371
  except Exception as e:
319
372
  if self.fail_on_persist_error:
320
373
  raise e
321
- logger.error(f"Failed to persist step creation: {str(e)}")
374
+ logger.error(f"Failed to persist step creation: {e!s}")
322
375
 
323
376
  tasks = [el.send(for_id=self.id) for el in self.elements]
324
377
  await asyncio.gather(*tasks)
325
378
 
326
- if config.ui.hide_cot and self.parent_id:
327
- return self.id
328
-
329
- if not config.features.prompt_playground and "generation" in step_dict:
330
- step_dict.pop("generation", None)
331
-
332
- await context.emitter.send_step(step_dict)
379
+ if not check_add_step_in_cot(self):
380
+ await context.emitter.send_step(stub_step(self))
381
+ else:
382
+ await context.emitter.send_step(step_dict)
333
383
 
334
- return self.id
384
+ return self
335
385
 
336
- async def stream_token(self, token: str, is_sequence=False):
386
+ async def stream_token(self, token: str, is_sequence=False, is_input=False):
337
387
  """
338
388
  Sends a token to the UI.
339
389
  Once all tokens have been streamed, call .send() to end the stream and persist the step if persistence is enabled.
340
390
  """
341
-
342
- if not self.streaming:
343
- self.streaming = True
344
- step_dict = self.to_dict()
345
- await context.emitter.stream_start(step_dict)
346
-
347
391
  if is_sequence:
348
- self.output = token
392
+ if is_input:
393
+ self.input = token
394
+ else:
395
+ self.output = token
349
396
  else:
350
- self.output += token
397
+ if is_input:
398
+ self.input += token
399
+ else:
400
+ self.output += token
351
401
 
352
402
  assert self.id
353
403
 
354
- if config.ui.hide_cot and self.parent_id:
404
+ if not check_add_step_in_cot(self):
405
+ await context.emitter.send_step(stub_step(self))
355
406
  return
356
407
 
357
- await context.emitter.send_token(
358
- id=self.id, token=token, is_sequence=is_sequence
359
- )
408
+ if not self.streaming:
409
+ self.streaming = True
410
+ step_dict = self.to_dict()
411
+ await context.emitter.stream_start(step_dict)
412
+ else:
413
+ await context.emitter.send_token(
414
+ id=self.id, token=token, is_sequence=is_sequence, is_input=is_input
415
+ )
360
416
 
361
417
  # Handle parameter less decorator
362
418
  def __call__(self, func):
@@ -367,7 +423,6 @@ class Step:
367
423
  id=self.id,
368
424
  parent_id=self.parent_id,
369
425
  thread_id=self.thread_id,
370
- disable_feedback=self.disable_feedback,
371
426
  )
372
427
 
373
428
  # Handle Context Manager Protocol
@@ -376,12 +431,9 @@ class Step:
376
431
  previous_steps = local_steps.get() or []
377
432
  parent_step = previous_steps[-1] if previous_steps else None
378
433
 
379
- if not self.parent_id and not self.root:
434
+ if not self.parent_id:
380
435
  if parent_step:
381
436
  self.parent_id = parent_step.id
382
- elif context.session.root_message:
383
- self.parent_id = context.session.root_message.id
384
- context.active_steps.append(self)
385
437
  local_steps.set(previous_steps + [self])
386
438
  await self.send()
387
439
  return self
@@ -389,13 +441,14 @@ class Step:
389
441
  async def __aexit__(self, exc_type, exc_val, exc_tb):
390
442
  self.end = utc_now()
391
443
 
392
- if self in context.active_steps:
393
- context.active_steps.remove(self)
444
+ if exc_type:
445
+ self.output = str(exc_val)
446
+ self.is_error = True
394
447
 
395
- local_active_steps = local_steps.get()
396
- if local_active_steps and self in local_active_steps:
397
- local_active_steps.remove(self)
398
- local_steps.set(local_active_steps)
448
+ current_steps = local_steps.get()
449
+ if current_steps and self in current_steps:
450
+ current_steps.remove(self)
451
+ local_steps.set(current_steps)
399
452
 
400
453
  await self.update()
401
454
 
@@ -405,12 +458,9 @@ class Step:
405
458
  previous_steps = local_steps.get() or []
406
459
  parent_step = previous_steps[-1] if previous_steps else None
407
460
 
408
- if not self.parent_id and not self.root:
461
+ if not self.parent_id:
409
462
  if parent_step:
410
463
  self.parent_id = parent_step.id
411
- elif context.session.root_message:
412
- self.parent_id = context.session.root_message.id
413
- context.active_steps.append(self)
414
464
  local_steps.set(previous_steps + [self])
415
465
 
416
466
  asyncio.create_task(self.send())
@@ -418,12 +468,14 @@ class Step:
418
468
 
419
469
  def __exit__(self, exc_type, exc_val, exc_tb):
420
470
  self.end = utc_now()
421
- if self in context.active_steps:
422
- context.active_steps.remove(self)
423
471
 
424
- local_active_steps = local_steps.get()
425
- if local_active_steps and self in local_active_steps:
426
- local_active_steps.remove(self)
427
- local_steps.set(local_active_steps)
472
+ if exc_type:
473
+ self.output = str(exc_val)
474
+ self.is_error = True
475
+
476
+ current_steps = local_steps.get()
477
+ if current_steps and self in current_steps:
478
+ current_steps.remove(self)
479
+ local_steps.set(current_steps)
428
480
 
429
481
  asyncio.create_task(self.update())
chainlit/sync.py CHANGED
@@ -10,9 +10,10 @@ import asyncio
10
10
  import threading
11
11
 
12
12
  from asyncer import asyncify
13
- from chainlit.context import context_var
14
13
  from syncer import sync
15
14
 
15
+ from chainlit.context import context_var
16
+
16
17
  make_async = asyncify
17
18
 
18
19
  T_Retval = TypeVar("T_Retval")
@@ -0,0 +1,6 @@
1
+ import importlib.util
2
+
3
+ if importlib.util.find_spec("botbuilder") is None:
4
+ raise ValueError(
5
+ "The botbuilder-core package is required to integrate Chainlit with a Slack app. Run `pip install botbuilder-core --upgrade`"
6
+ )