chainlit 1.1.202__py3-none-any.whl → 1.1.300__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 (60) hide show
  1. chainlit/__init__.py +22 -4
  2. chainlit/cli/__init__.py +53 -6
  3. chainlit/config.py +25 -18
  4. chainlit/context.py +9 -0
  5. chainlit/copilot/dist/index.js +443 -410
  6. chainlit/data/__init__.py +19 -5
  7. chainlit/data/dynamodb.py +586 -0
  8. chainlit/data/sql_alchemy.py +47 -28
  9. chainlit/discord/app.py +4 -2
  10. chainlit/element.py +36 -20
  11. chainlit/emitter.py +8 -7
  12. chainlit/frontend/dist/assets/{DailyMotion-53376209.js → DailyMotion-578b63e6.js} +1 -1
  13. chainlit/frontend/dist/assets/{Facebook-aee41f5b.js → Facebook-b825e5bb.js} +1 -1
  14. chainlit/frontend/dist/assets/{FilePlayer-b2cdb30f.js → FilePlayer-bcba3b4e.js} +1 -1
  15. chainlit/frontend/dist/assets/{Kaltura-51db0377.js → Kaltura-fc1c9497.js} +1 -1
  16. chainlit/frontend/dist/assets/{Mixcloud-cb900886.js → Mixcloud-4cfb2724.js} +1 -1
  17. chainlit/frontend/dist/assets/{Mux-79ac59e6.js → Mux-aa92055c.js} +1 -1
  18. chainlit/frontend/dist/assets/{Preview-cfe7584c.js → Preview-9f55905a.js} +1 -1
  19. chainlit/frontend/dist/assets/{SoundCloud-a985707c.js → SoundCloud-f991fe03.js} +1 -1
  20. chainlit/frontend/dist/assets/{Streamable-3d89aab5.js → Streamable-53128f49.js} +1 -1
  21. chainlit/frontend/dist/assets/{Twitch-bf016588.js → Twitch-fce8b9f5.js} +1 -1
  22. chainlit/frontend/dist/assets/{Vidyard-1891ecd7.js → Vidyard-e35c6102.js} +1 -1
  23. chainlit/frontend/dist/assets/{Vimeo-0645662c.js → Vimeo-fff35f8e.js} +1 -1
  24. chainlit/frontend/dist/assets/{Wistia-3b449fe2.js → Wistia-ec07dc64.js} +1 -1
  25. chainlit/frontend/dist/assets/{YouTube-5ea2381e.js → YouTube-ad068e2a.js} +1 -1
  26. chainlit/frontend/dist/assets/index-aaf974a9.css +1 -0
  27. chainlit/frontend/dist/assets/index-d40d41cc.js +727 -0
  28. chainlit/frontend/dist/assets/{react-plotly-2ff19c9f.js → react-plotly-b2c6442b.js} +1 -1
  29. chainlit/frontend/dist/index.html +2 -3
  30. chainlit/langchain/callbacks.py +4 -2
  31. chainlit/llama_index/callbacks.py +2 -2
  32. chainlit/message.py +30 -25
  33. chainlit/oauth_providers.py +118 -0
  34. chainlit/server.py +208 -83
  35. chainlit/slack/app.py +2 -3
  36. chainlit/socket.py +27 -23
  37. chainlit/step.py +44 -30
  38. chainlit/teams/__init__.py +6 -0
  39. chainlit/teams/app.py +332 -0
  40. chainlit/translations/en-US.json +2 -4
  41. chainlit/types.py +17 -17
  42. chainlit/user.py +9 -1
  43. chainlit/utils.py +47 -3
  44. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/METADATA +22 -14
  45. chainlit-1.1.300.dist-info/RECORD +79 -0
  46. chainlit/cli/utils.py +0 -24
  47. chainlit/frontend/dist/assets/index-a0c5a67e.js +0 -698
  48. chainlit/frontend/dist/assets/index-d088547c.css +0 -1
  49. chainlit/playground/__init__.py +0 -2
  50. chainlit/playground/config.py +0 -36
  51. chainlit/playground/provider.py +0 -108
  52. chainlit/playground/providers/__init__.py +0 -11
  53. chainlit/playground/providers/anthropic.py +0 -118
  54. chainlit/playground/providers/huggingface.py +0 -75
  55. chainlit/playground/providers/langchain.py +0 -89
  56. chainlit/playground/providers/openai.py +0 -386
  57. chainlit/playground/providers/vertexai.py +0 -171
  58. chainlit-1.1.202.dist-info/RECORD +0 -86
  59. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/WHEEL +0 -0
  60. {chainlit-1.1.202.dist-info → chainlit-1.1.300.dist-info}/entry_points.txt +0 -0
@@ -4,7 +4,6 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <!-- TAG INJECTION PLACEHOLDER -->
7
- <link rel="icon" href="/favicon" />
8
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
9
  <!-- FONT START -->
@@ -22,8 +21,8 @@
22
21
  <script>
23
22
  const global = globalThis;
24
23
  </script>
25
- <script type="module" crossorigin src="/assets/index-a0c5a67e.js"></script>
26
- <link rel="stylesheet" href="/assets/index-d088547c.css">
24
+ <script type="module" crossorigin src="/assets/index-d40d41cc.js"></script>
25
+ <link rel="stylesheet" href="/assets/index-aaf974a9.css">
27
26
  </head>
28
27
  <body>
29
28
  <div id="root"></div>
@@ -456,7 +456,7 @@ class LangchainTracer(BaseTracer, GenerationHelper, FinalStreamHelper):
456
456
  elif run.run_type == "llm":
457
457
  step_type = "llm"
458
458
  elif run.run_type == "retriever":
459
- step_type = "retrieval"
459
+ step_type = "tool"
460
460
  elif run.run_type == "tool":
461
461
  step_type = "tool"
462
462
  elif run.run_type == "embedding":
@@ -533,7 +533,9 @@ class LangchainTracer(BaseTracer, GenerationHelper, FinalStreamHelper):
533
533
  break
534
534
 
535
535
  current_step.language = "json"
536
- current_step.output = json.dumps(message_completion, indent=4, ensure_ascii=False)
536
+ current_step.output = json.dumps(
537
+ message_completion, indent=4, ensure_ascii=False
538
+ )
537
539
  else:
538
540
  completion_start = self.completion_generations[str(run.id)]
539
541
  completion = generation.get("text", "")
@@ -73,9 +73,9 @@ class LlamaIndexCallbackHandler(TokenCountingHandler):
73
73
 
74
74
  step_type: StepType = "undefined"
75
75
  if event_type == CBEventType.RETRIEVE:
76
- step_type = "retrieval"
76
+ step_type = "tool"
77
77
  elif event_type == CBEventType.QUERY:
78
- step_type = "retrieval"
78
+ step_type = "tool"
79
79
  elif event_type == CBEventType.LLM:
80
80
  step_type = "llm"
81
81
  else:
chainlit/message.py CHANGED
@@ -7,7 +7,7 @@ from typing import Dict, List, Optional, Union, cast
7
7
 
8
8
  from chainlit.action import Action
9
9
  from chainlit.config import config
10
- from chainlit.context import context
10
+ from chainlit.context import context, local_steps
11
11
  from chainlit.data import get_data_layer
12
12
  from chainlit.element import ElementBased
13
13
  from chainlit.logger import logger
@@ -21,7 +21,6 @@ from chainlit.types import (
21
21
  AskSpec,
22
22
  FileDict,
23
23
  )
24
- from literalai import BaseGeneration
25
24
  from literalai.helper import utc_now
26
25
  from literalai.step import MessageStepType
27
26
 
@@ -38,17 +37,22 @@ class MessageBase(ABC):
38
37
  fail_on_persist_error: bool = False
39
38
  persisted = False
40
39
  is_error = False
40
+ parent_id: Optional[str] = None
41
41
  language: Optional[str] = None
42
42
  metadata: Optional[Dict] = None
43
43
  tags: Optional[List[str]] = None
44
44
  wait_for_answer = False
45
45
  indent: Optional[int] = None
46
- generation: Optional[BaseGeneration] = None
47
46
 
48
47
  def __post_init__(self) -> None:
49
48
  trace_event(f"init {self.__class__.__name__}")
50
49
  self.thread_id = context.session.thread_id
51
50
 
51
+ previous_steps = local_steps.get() or []
52
+ parent_step = previous_steps[-1] if previous_steps else None
53
+ if parent_step:
54
+ self.parent_id = parent_step.id
55
+
52
56
  if not getattr(self, "id", None):
53
57
  self.id = str(uuid.uuid4())
54
58
 
@@ -57,6 +61,7 @@ class MessageBase(ABC):
57
61
  type = _dict.get("type", "assistant_message")
58
62
  message = Message(
59
63
  id=_dict["id"],
64
+ parent_id=_dict.get("parentId"),
60
65
  created_at=_dict["createdAt"],
61
66
  content=_dict["output"],
62
67
  author=_dict.get("name", config.ui.name),
@@ -71,6 +76,7 @@ class MessageBase(ABC):
71
76
  _dict: StepDict = {
72
77
  "id": self.id,
73
78
  "threadId": self.thread_id,
79
+ "parentId": self.parent_id,
74
80
  "createdAt": self.created_at,
75
81
  "start": self.created_at,
76
82
  "end": self.created_at,
@@ -84,7 +90,6 @@ class MessageBase(ABC):
84
90
  "isError": self.is_error,
85
91
  "waitForAnswer": self.wait_for_answer,
86
92
  "indent": self.indent,
87
- "generation": self.generation.to_dict() if self.generation else None,
88
93
  "metadata": self.metadata or {},
89
94
  "tags": self.tags,
90
95
  }
@@ -173,21 +178,21 @@ class MessageBase(ABC):
173
178
  Sends a token to the UI. This is useful for streaming messages.
174
179
  Once all tokens have been streamed, call .send() to end the stream and persist the message if persistence is enabled.
175
180
  """
176
-
177
- if not self.streaming:
178
- self.streaming = True
179
- step_dict = self.to_dict()
180
- await context.emitter.stream_start(step_dict)
181
-
182
181
  if is_sequence:
183
182
  self.content = token
184
183
  else:
185
184
  self.content += token
186
185
 
187
186
  assert self.id
188
- await context.emitter.send_token(
189
- id=self.id, token=token, is_sequence=is_sequence
190
- )
187
+
188
+ if not self.streaming:
189
+ self.streaming = True
190
+ step_dict = self.to_dict()
191
+ await context.emitter.stream_start(step_dict)
192
+ else:
193
+ await context.emitter.send_token(
194
+ id=self.id, token=token, is_sequence=is_sequence
195
+ )
191
196
 
192
197
 
193
198
  class Message(MessageBase):
@@ -196,7 +201,7 @@ class Message(MessageBase):
196
201
 
197
202
  Args:
198
203
  content (Union[str, Dict]): The content of the message.
199
- author (str, optional): The author of the message, this will be used in the UI. Defaults to the chatbot name (see config).
204
+ author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
200
205
  language (str, optional): Language of the code is the content is code. See https://react-code-blocks-rajinwonderland.vercel.app/?path=/story/codeblock--supported-languages for a list of supported languages.
201
206
  actions (List[Action], optional): A list of actions to send with the message.
202
207
  elements (List[ElementBased], optional): A list of elements to send with the message.
@@ -212,15 +217,14 @@ class Message(MessageBase):
212
217
  elements: Optional[List[ElementBased]] = None,
213
218
  disable_feedback: bool = False,
214
219
  type: MessageStepType = "assistant_message",
215
- generation: Optional[BaseGeneration] = None,
216
220
  metadata: Optional[Dict] = None,
217
221
  tags: Optional[List[str]] = None,
218
222
  id: Optional[str] = None,
223
+ parent_id: Optional[str] = None,
219
224
  created_at: Union[str, None] = None,
220
225
  ):
221
226
  time.sleep(0.001)
222
227
  self.language = language
223
- self.generation = generation
224
228
  if isinstance(content, dict):
225
229
  try:
226
230
  self.content = json.dumps(content, indent=4, ensure_ascii=False)
@@ -237,6 +241,9 @@ class Message(MessageBase):
237
241
  if id:
238
242
  self.id = str(id)
239
243
 
244
+ if parent_id:
245
+ self.parent_id = str(parent_id)
246
+
240
247
  if created_at:
241
248
  self.created_at = created_at
242
249
 
@@ -303,9 +310,7 @@ class ErrorMessage(MessageBase):
303
310
 
304
311
  Args:
305
312
  content (str): Text displayed above the upload button.
306
- author (str, optional): The author of the message, this will be used in the UI. Defaults to the chatbot name (see config).
307
- parent_id (str, optional): If provided, the message will be nested inside the parent in the UI.
308
- indent (int, optional): If positive, the message will be nested in the UI.
313
+ author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
309
314
  """
310
315
 
311
316
  def __init__(
@@ -316,7 +321,7 @@ class ErrorMessage(MessageBase):
316
321
  ):
317
322
  self.content = content
318
323
  self.author = author
319
- self.type = "system_message"
324
+ self.type = "assistant_message"
320
325
  self.is_error = True
321
326
  self.fail_on_persist_error = fail_on_persist_error
322
327
 
@@ -346,7 +351,7 @@ class AskUserMessage(AskMessageBase):
346
351
 
347
352
  Args:
348
353
  content (str): The content of the prompt.
349
- author (str, optional): The author of the message, this will be used in the UI. Defaults to the chatbot name (see config).
354
+ author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
350
355
  disable_feedback (bool, optional): Hide the feedback buttons for this specific message
351
356
  timeout (int, optional): The number of seconds to wait for an answer before raising a TimeoutError.
352
357
  raise_on_timeout (bool, optional): Whether to raise a socketio TimeoutError if the user does not answer in time.
@@ -357,7 +362,7 @@ class AskUserMessage(AskMessageBase):
357
362
  content: str,
358
363
  author: str = config.ui.name,
359
364
  type: MessageStepType = "assistant_message",
360
- disable_feedback: bool = False,
365
+ disable_feedback: bool = True,
361
366
  timeout: int = 60,
362
367
  raise_on_timeout: bool = False,
363
368
  ):
@@ -411,7 +416,7 @@ class AskFileMessage(AskMessageBase):
411
416
  accept (Union[List[str], Dict[str, List[str]]]): List of mime type to accept like ["text/csv", "application/pdf"] or a dict like {"text/plain": [".txt", ".py"]}.
412
417
  max_size_mb (int, optional): Maximum size per file in MB. Maximum value is 100.
413
418
  max_files (int, optional): Maximum number of files to upload. Maximum value is 10.
414
- author (str, optional): The author of the message, this will be used in the UI. Defaults to the chatbot name (see config).
419
+ author (str, optional): The author of the message, this will be used in the UI. Defaults to the assistant name (see config).
415
420
  disable_feedback (bool, optional): Hide the feedback buttons for this specific message
416
421
  timeout (int, optional): The number of seconds to wait for an answer before raising a TimeoutError.
417
422
  raise_on_timeout (bool, optional): Whether to raise a socketio TimeoutError if the user does not answer in time.
@@ -425,7 +430,7 @@ class AskFileMessage(AskMessageBase):
425
430
  max_files=1,
426
431
  author=config.ui.name,
427
432
  type: MessageStepType = "assistant_message",
428
- disable_feedback: bool = False,
433
+ disable_feedback: bool = True,
429
434
  timeout=90,
430
435
  raise_on_timeout=False,
431
436
  ):
@@ -501,7 +506,7 @@ class AskActionMessage(AskMessageBase):
501
506
  content: str,
502
507
  actions: List[Action],
503
508
  author=config.ui.name,
504
- disable_feedback=False,
509
+ disable_feedback=True,
505
510
  timeout=90,
506
511
  raise_on_timeout=False,
507
512
  ):
@@ -4,6 +4,7 @@ import urllib.parse
4
4
  from typing import Dict, List, Optional, Tuple
5
5
 
6
6
  import httpx
7
+ from chainlit.secret import random_secret
7
8
  from chainlit.user import User
8
9
  from fastapi import HTTPException
9
10
 
@@ -186,6 +187,60 @@ class AzureADOAuthProvider(OAuthProvider):
186
187
  )
187
188
  return token
188
189
 
190
+
191
+ class AzureADHybridOAuthProvider(OAuthProvider):
192
+ id = "azure-ad-hybrid"
193
+ env = [
194
+ "OAUTH_AZURE_AD_HYBRID_CLIENT_ID",
195
+ "OAUTH_AZURE_AD_HYBRID_CLIENT_SECRET",
196
+ "OAUTH_AZURE_AD_HYBRID_TENANT_ID",
197
+ ]
198
+ authorize_url = (
199
+ f"https://login.microsoftonline.com/{os.environ.get('OAUTH_AZURE_AD_HYBRID_TENANT_ID', '')}/oauth2/v2.0/authorize"
200
+ if os.environ.get("OAUTH_AZURE_AD_HYBRID_ENABLE_SINGLE_TENANT")
201
+ else "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
202
+ )
203
+ token_url = (
204
+ f"https://login.microsoftonline.com/{os.environ.get('OAUTH_AZURE_AD_HYBRID_TENANT_ID', '')}/oauth2/v2.0/token"
205
+ if os.environ.get("OAUTH_AZURE_AD_HYBRID_ENABLE_SINGLE_TENANT")
206
+ else "https://login.microsoftonline.com/common/oauth2/v2.0/token"
207
+ )
208
+
209
+ def __init__(self):
210
+ self.client_id = os.environ.get("OAUTH_AZURE_AD_HYBRID_CLIENT_ID")
211
+ self.client_secret = os.environ.get("OAUTH_AZURE_AD_HYBRID_CLIENT_SECRET")
212
+ nonce = random_secret(16)
213
+ self.authorize_params = {
214
+ "tenant": os.environ.get("OAUTH_AZURE_AD_HYBRID_TENANT_ID"),
215
+ "response_type": "code id_token",
216
+ "scope": "https://graph.microsoft.com/User.Read https://graph.microsoft.com/openid",
217
+ "response_mode": "form_post",
218
+ "nonce": nonce,
219
+ }
220
+
221
+ async def get_token(self, code: str, url: str):
222
+ payload = {
223
+ "client_id": self.client_id,
224
+ "client_secret": self.client_secret,
225
+ "code": code,
226
+ "grant_type": "authorization_code",
227
+ "redirect_uri": url,
228
+ }
229
+ async with httpx.AsyncClient() as client:
230
+ response = await client.post(
231
+ self.token_url,
232
+ data=payload,
233
+ )
234
+ response.raise_for_status()
235
+ json = response.json()
236
+
237
+ token = json["access_token"]
238
+ if not token:
239
+ raise HTTPException(
240
+ status_code=400, detail="Failed to get the access token"
241
+ )
242
+ return token
243
+
189
244
  async def get_user_info(self, token: str):
190
245
  async with httpx.AsyncClient() as client:
191
246
  response = await client.get(
@@ -475,14 +530,77 @@ class AWSCognitoOAuthProvider(OAuthProvider):
475
530
  return (cognito_user, user)
476
531
 
477
532
 
533
+ class GitlabOAuthProvider(OAuthProvider):
534
+ id = "gitlab"
535
+ env = [
536
+ "OAUTH_GITLAB_CLIENT_ID",
537
+ "OAUTH_GITLAB_CLIENT_SECRET",
538
+ "OAUTH_GITLAB_DOMAIN",
539
+ ]
540
+
541
+ def __init__(self):
542
+ self.client_id = os.environ.get("OAUTH_GITLAB_CLIENT_ID")
543
+ self.client_secret = os.environ.get("OAUTH_GITLAB_CLIENT_SECRET")
544
+ # Ensure that the domain does not have a trailing slash
545
+ self.domain = f"https://{os.environ.get('OAUTH_GITLAB_DOMAIN', '').rstrip('/')}"
546
+
547
+ self.authorize_url = f"{self.domain}/oauth/authorize"
548
+
549
+ self.authorize_params = {
550
+ "scope": "openid profile email",
551
+ "response_type": "code",
552
+ }
553
+
554
+ async def get_token(self, code: str, url: str):
555
+ payload = {
556
+ "client_id": self.client_id,
557
+ "client_secret": self.client_secret,
558
+ "code": code,
559
+ "grant_type": "authorization_code",
560
+ "redirect_uri": url,
561
+ }
562
+ async with httpx.AsyncClient() as client:
563
+ response = await client.post(
564
+ f"{self.domain}/oauth/token",
565
+ data=payload,
566
+ )
567
+ response.raise_for_status()
568
+ json_content = response.json()
569
+ token = json_content.get("access_token")
570
+ if not token:
571
+ raise HTTPException(
572
+ status_code=400, detail="Failed to get the access token"
573
+ )
574
+ return token
575
+
576
+ async def get_user_info(self, token: str):
577
+ async with httpx.AsyncClient() as client:
578
+ response = await client.get(
579
+ f"{self.domain}/oauth/userinfo",
580
+ headers={"Authorization": f"Bearer {token}"},
581
+ )
582
+ response.raise_for_status()
583
+ gitlab_user = response.json()
584
+ user = User(
585
+ identifier=gitlab_user.get("email"),
586
+ metadata={
587
+ "image": gitlab_user.get("picture", ""),
588
+ "provider": "gitlab",
589
+ },
590
+ )
591
+ return (gitlab_user, user)
592
+
593
+
478
594
  providers = [
479
595
  GithubOAuthProvider(),
480
596
  GoogleOAuthProvider(),
481
597
  AzureADOAuthProvider(),
598
+ AzureADHybridOAuthProvider(),
482
599
  OktaOAuthProvider(),
483
600
  Auth0OAuthProvider(),
484
601
  DescopeOAuthProvider(),
485
602
  AWSCognitoOAuthProvider(),
603
+ GitlabOAuthProvider(),
486
604
  ]
487
605
 
488
606