chainlit 1.1.300__py3-none-any.whl → 1.1.300rc0__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 (47) hide show
  1. chainlit/__init__.py +1 -3
  2. chainlit/cli/__init__.py +6 -53
  3. chainlit/cli/utils.py +24 -0
  4. chainlit/config.py +0 -4
  5. chainlit/context.py +0 -9
  6. chainlit/copilot/dist/index.js +204 -204
  7. chainlit/data/__init__.py +3 -6
  8. chainlit/data/sql_alchemy.py +3 -3
  9. chainlit/element.py +9 -33
  10. chainlit/emitter.py +7 -8
  11. chainlit/frontend/dist/assets/{DailyMotion-578b63e6.js → DailyMotion-e54bf0dc.js} +1 -1
  12. chainlit/frontend/dist/assets/{Facebook-b825e5bb.js → Facebook-a767c817.js} +1 -1
  13. chainlit/frontend/dist/assets/{FilePlayer-bcba3b4e.js → FilePlayer-5d19f3d1.js} +1 -1
  14. chainlit/frontend/dist/assets/{Kaltura-fc1c9497.js → Kaltura-93bef413.js} +1 -1
  15. chainlit/frontend/dist/assets/{Mixcloud-4cfb2724.js → Mixcloud-d5d27c2a.js} +1 -1
  16. chainlit/frontend/dist/assets/{Mux-aa92055c.js → Mux-ad063035.js} +1 -1
  17. chainlit/frontend/dist/assets/{Preview-9f55905a.js → Preview-a9a0e47e.js} +1 -1
  18. chainlit/frontend/dist/assets/{SoundCloud-f991fe03.js → SoundCloud-1698c4da.js} +1 -1
  19. chainlit/frontend/dist/assets/{Streamable-53128f49.js → Streamable-e5832da9.js} +1 -1
  20. chainlit/frontend/dist/assets/{Twitch-fce8b9f5.js → Twitch-cd321ef4.js} +1 -1
  21. chainlit/frontend/dist/assets/{Vidyard-e35c6102.js → Vidyard-8646c638.js} +1 -1
  22. chainlit/frontend/dist/assets/{Vimeo-fff35f8e.js → Vimeo-0e590e3a.js} +1 -1
  23. chainlit/frontend/dist/assets/{Wistia-ec07dc64.js → Wistia-76f0c9b0.js} +1 -1
  24. chainlit/frontend/dist/assets/{YouTube-ad068e2a.js → YouTube-a94756f4.js} +1 -1
  25. chainlit/frontend/dist/assets/index-51fef15f.js +727 -0
  26. chainlit/frontend/dist/assets/{index-aaf974a9.css → index-53c62926.css} +1 -1
  27. chainlit/frontend/dist/assets/{react-plotly-b2c6442b.js → react-plotly-d9ffbf69.js} +1 -1
  28. chainlit/frontend/dist/index.html +3 -2
  29. chainlit/message.py +8 -13
  30. chainlit/oauth_providers.py +0 -118
  31. chainlit/server.py +57 -182
  32. chainlit/slack/app.py +2 -2
  33. chainlit/socket.py +20 -26
  34. chainlit/step.py +9 -24
  35. chainlit/translations/en-US.json +1 -1
  36. chainlit/types.py +17 -7
  37. chainlit/user.py +1 -9
  38. chainlit/utils.py +0 -43
  39. {chainlit-1.1.300.dist-info → chainlit-1.1.300rc0.dist-info}/METADATA +9 -18
  40. chainlit-1.1.300rc0.dist-info/RECORD +77 -0
  41. chainlit/data/dynamodb.py +0 -586
  42. chainlit/frontend/dist/assets/index-d40d41cc.js +0 -727
  43. chainlit/teams/__init__.py +0 -6
  44. chainlit/teams/app.py +0 -332
  45. chainlit-1.1.300.dist-info/RECORD +0 -79
  46. {chainlit-1.1.300.dist-info → chainlit-1.1.300rc0.dist-info}/WHEEL +0 -0
  47. {chainlit-1.1.300.dist-info → chainlit-1.1.300rc0.dist-info}/entry_points.txt +0 -0
chainlit/server.py CHANGED
@@ -18,7 +18,6 @@ import webbrowser
18
18
  from contextlib import asynccontextmanager
19
19
  from pathlib import Path
20
20
 
21
- import socketio
22
21
  from chainlit.auth import create_jwt, get_configuration, get_current_user
23
22
  from chainlit.config import (
24
23
  APP_ROOT,
@@ -34,19 +33,19 @@ from chainlit.data import get_data_layer
34
33
  from chainlit.data.acl import is_thread_author
35
34
  from chainlit.logger import logger
36
35
  from chainlit.markdown import get_markdown_str
36
+ from chainlit.telemetry import trace_event
37
37
  from chainlit.types import (
38
38
  DeleteFeedbackRequest,
39
39
  DeleteThreadRequest,
40
+ GenerationRequest,
40
41
  GetThreadsRequest,
41
42
  Theme,
42
43
  UpdateFeedbackRequest,
43
44
  )
44
45
  from chainlit.user import PersistedUser, User
45
46
  from fastapi import (
46
- APIRouter,
47
47
  Depends,
48
48
  FastAPI,
49
- Form,
50
49
  HTTPException,
51
50
  Query,
52
51
  Request,
@@ -57,14 +56,12 @@ from fastapi import (
57
56
  from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, RedirectResponse
58
57
  from fastapi.security import OAuth2PasswordRequestForm
59
58
  from fastapi.staticfiles import StaticFiles
59
+ from fastapi_socketio import SocketManager
60
60
  from starlette.datastructures import URL
61
61
  from starlette.middleware.cors import CORSMiddleware
62
62
  from typing_extensions import Annotated
63
63
  from watchfiles import awatch
64
64
 
65
- ROOT_PATH = os.environ.get("CHAINLIT_ROOT_PATH", "")
66
- IS_SUBMOUNT = os.environ.get("CHAINLIT_SUBMOUNT", "") == "true"
67
-
68
65
 
69
66
  @asynccontextmanager
70
67
  async def lifespan(app: FastAPI):
@@ -72,9 +69,9 @@ async def lifespan(app: FastAPI):
72
69
  port = config.run.port
73
70
 
74
71
  if host == DEFAULT_HOST:
75
- url = f"http://localhost:{port}{ROOT_PATH}"
72
+ url = f"http://localhost:{port}"
76
73
  else:
77
- url = f"http://{host}:{port}{ROOT_PATH}"
74
+ url = f"http://{host}:{port}"
78
75
 
79
76
  logger.info(f"Your app is available at {url}")
80
77
 
@@ -115,7 +112,7 @@ async def lifespan(app: FastAPI):
115
112
  logger.error(f"Error reloading module: {e}")
116
113
 
117
114
  await asyncio.sleep(1)
118
- await sio.emit("reload", {})
115
+ await socket.emit("reload", {})
119
116
 
120
117
  break
121
118
 
@@ -169,36 +166,12 @@ def get_build_dir(local_target: str, packaged_target: str):
169
166
  build_dir = get_build_dir("frontend", "frontend")
170
167
  copilot_build_dir = get_build_dir(os.path.join("libs", "copilot"), "copilot")
171
168
 
172
- app = FastAPI(lifespan=lifespan)
173
-
174
- sio = socketio.AsyncServer(
175
- cors_allowed_origins=[] if IS_SUBMOUNT else "*", async_mode="asgi"
176
- )
177
-
178
- combined_asgi_app = socketio.ASGIApp(
179
- sio,
180
- app,
181
- socketio_path=f"{ROOT_PATH}/ws/socket.io" if ROOT_PATH else "/ws/socket.io",
182
- )
183
-
184
- app.add_middleware(
185
- CORSMiddleware,
186
- allow_origins=config.project.allow_origins,
187
- allow_credentials=True,
188
- allow_methods=["*"],
189
- allow_headers=["*"],
190
- )
191
-
192
- router = APIRouter(prefix=ROOT_PATH)
193
169
 
194
- app.mount(
195
- f"{ROOT_PATH}/public",
196
- StaticFiles(directory="public", check_dir=False),
197
- name="public",
198
- )
170
+ app = FastAPI(lifespan=lifespan)
199
171
 
172
+ app.mount("/public", StaticFiles(directory="public", check_dir=False), name="public")
200
173
  app.mount(
201
- f"{ROOT_PATH}/assets",
174
+ "/assets",
202
175
  StaticFiles(
203
176
  packages=[("chainlit", os.path.join(build_dir, "assets"))],
204
177
  follow_symlink=config.project.follow_symlink,
@@ -207,7 +180,7 @@ app.mount(
207
180
  )
208
181
 
209
182
  app.mount(
210
- f"{ROOT_PATH}/copilot",
183
+ "/copilot",
211
184
  StaticFiles(
212
185
  packages=[("chainlit", copilot_build_dir)],
213
186
  follow_symlink=config.project.follow_symlink,
@@ -216,6 +189,22 @@ app.mount(
216
189
  )
217
190
 
218
191
 
192
+ app.add_middleware(
193
+ CORSMiddleware,
194
+ allow_origins=config.project.allow_origins,
195
+ allow_credentials=True,
196
+ allow_methods=["*"],
197
+ allow_headers=["*"],
198
+ )
199
+
200
+ socket = SocketManager(
201
+ app,
202
+ cors_allowed_origins=[],
203
+ async_mode="asgi",
204
+ socketio_path="/ws/socket.io",
205
+ )
206
+
207
+
219
208
  # -------------------------------------------------------------------------------
220
209
  # SLACK HANDLER
221
210
  # -------------------------------------------------------------------------------
@@ -223,28 +212,11 @@ app.mount(
223
212
  if os.environ.get("SLACK_BOT_TOKEN") and os.environ.get("SLACK_SIGNING_SECRET"):
224
213
  from chainlit.slack.app import slack_app_handler
225
214
 
226
- @router.post("/slack/events")
227
- async def slack_endpoint(req: Request):
215
+ @app.post("/slack/events")
216
+ async def endpoint(req: Request):
228
217
  return await slack_app_handler.handle(req)
229
218
 
230
219
 
231
- # -------------------------------------------------------------------------------
232
- # TEAMS HANDLER
233
- # -------------------------------------------------------------------------------
234
-
235
- if os.environ.get("TEAMS_APP_ID") and os.environ.get("TEAMS_APP_PASSWORD"):
236
- from botbuilder.schema import Activity
237
- from chainlit.teams.app import adapter, bot
238
-
239
- @router.post("/teams/events")
240
- async def teams_endpoint(req: Request):
241
- body = await req.json()
242
- activity = Activity().deserialize(body)
243
- auth_header = req.headers.get("Authorization", "")
244
- response = await adapter.process_activity(activity, auth_header, bot.on_turn)
245
- return response
246
-
247
-
248
220
  # -------------------------------------------------------------------------------
249
221
  # HTTP HANDLERS
250
222
  # -------------------------------------------------------------------------------
@@ -266,17 +238,14 @@ def get_html_template():
266
238
  )
267
239
  url = config.ui.github or default_url
268
240
  meta_image_url = config.ui.custom_meta_image_url or default_meta_image_url
269
- favicon_path = ROOT_PATH + "/favicon" if ROOT_PATH else "/favicon"
270
241
 
271
242
  tags = f"""<title>{config.ui.name}</title>
272
- <link rel="icon" href="{favicon_path}" />
273
243
  <meta name="description" content="{config.ui.description}">
274
244
  <meta property="og:type" content="website">
275
245
  <meta property="og:title" content="{config.ui.name}">
276
246
  <meta property="og:description" content="{config.ui.description}">
277
247
  <meta property="og:image" content="{meta_image_url}">
278
- <meta property="og:url" content="{url}">
279
- <meta property="og:root_path" content="{ROOT_PATH}">"""
248
+ <meta property="og:url" content="{url}">"""
280
249
 
281
250
  js = f"""<script>{f"window.theme = {json.dumps(config.ui.theme.to_dict())}; " if config.ui.theme else ""}</script>"""
282
251
 
@@ -306,9 +275,6 @@ def get_html_template():
306
275
  content = replace_between_tags(
307
276
  content, "<!-- FONT START -->", "<!-- FONT END -->", font
308
277
  )
309
- if ROOT_PATH:
310
- content = content.replace('href="/', f'href="{ROOT_PATH}/')
311
- content = content.replace('src="/', f'src="{ROOT_PATH}/')
312
278
  return content
313
279
 
314
280
 
@@ -318,7 +284,6 @@ def get_user_facing_url(url: URL):
318
284
  Handles deployment with proxies (like cloud run).
319
285
  """
320
286
 
321
- ROOT_PATH = os.environ.get("CHAINLIT_ROOT_PATH", "")
322
287
  chainlit_url = os.environ.get("CHAINLIT_URL")
323
288
 
324
289
  # No config, we keep the URL as is
@@ -334,26 +299,15 @@ def get_user_facing_url(url: URL):
334
299
  if config_url.path.endswith("/"):
335
300
  config_url = config_url.replace(path=config_url.path[:-1])
336
301
 
337
- # Add ROOT_PATH to the final URL if it exists
338
- if ROOT_PATH:
339
- # Ensure ROOT_PATH starts with a slash
340
- if not ROOT_PATH.startswith("/"):
341
- ROOT_PATH = "/" + ROOT_PATH
342
- # Ensure ROOT_PATH does not end with a slash
343
- if ROOT_PATH.endswith("/"):
344
- ROOT_PATH = ROOT_PATH[:-1]
345
-
346
- return config_url.__str__() + ROOT_PATH + url.path
347
-
348
302
  return config_url.__str__() + url.path
349
303
 
350
304
 
351
- @router.get("/auth/config")
305
+ @app.get("/auth/config")
352
306
  async def auth(request: Request):
353
307
  return get_configuration()
354
308
 
355
309
 
356
- @router.post("/login")
310
+ @app.post("/login")
357
311
  async def login(form_data: OAuth2PasswordRequestForm = Depends()):
358
312
  if not config.code.password_auth_callback:
359
313
  raise HTTPException(
@@ -382,14 +336,14 @@ async def login(form_data: OAuth2PasswordRequestForm = Depends()):
382
336
  }
383
337
 
384
338
 
385
- @router.post("/logout")
339
+ @app.post("/logout")
386
340
  async def logout(request: Request, response: Response):
387
341
  if config.code.on_logout:
388
342
  return await config.code.on_logout(request, response)
389
343
  return {"success": True}
390
344
 
391
345
 
392
- @router.post("/auth/header")
346
+ @app.post("/auth/header")
393
347
  async def header_auth(request: Request):
394
348
  if not config.code.header_auth_callback:
395
349
  raise HTTPException(
@@ -418,7 +372,7 @@ async def header_auth(request: Request):
418
372
  }
419
373
 
420
374
 
421
- @router.get("/auth/oauth/{provider_id}")
375
+ @app.get("/auth/oauth/{provider_id}")
422
376
  async def oauth_login(provider_id: str, request: Request):
423
377
  if config.code.oauth_callback is None:
424
378
  raise HTTPException(
@@ -459,7 +413,7 @@ async def oauth_login(provider_id: str, request: Request):
459
413
  return response
460
414
 
461
415
 
462
- @router.get("/auth/oauth/{provider_id}/callback")
416
+ @app.get("/auth/oauth/{provider_id}/callback")
463
417
  async def oauth_callback(
464
418
  provider_id: str,
465
419
  request: Request,
@@ -543,85 +497,7 @@ async def oauth_callback(
543
497
  return response
544
498
 
545
499
 
546
- # specific route for azure ad hybrid flow
547
- @router.post("/auth/oauth/azure-ad-hybrid/callback")
548
- async def oauth_azure_hf_callback(
549
- request: Request,
550
- error: Optional[str] = None,
551
- code: Annotated[Optional[str], Form()] = None,
552
- id_token: Annotated[Optional[str], Form()] = None,
553
- ):
554
- provider_id = "azure-ad-hybrid"
555
- if config.code.oauth_callback is None:
556
- raise HTTPException(
557
- status_code=status.HTTP_400_BAD_REQUEST,
558
- detail="No oauth_callback defined",
559
- )
560
-
561
- provider = get_oauth_provider(provider_id)
562
- if not provider:
563
- raise HTTPException(
564
- status_code=status.HTTP_404_NOT_FOUND,
565
- detail=f"Provider {provider_id} not found",
566
- )
567
-
568
- if error:
569
- params = urllib.parse.urlencode(
570
- {
571
- "error": error,
572
- }
573
- )
574
- response = RedirectResponse(
575
- # FIXME: redirect to the right frontend base url to improve the dev environment
576
- url=f"/login?{params}",
577
- )
578
- return response
579
-
580
- if not code:
581
- raise HTTPException(
582
- status_code=status.HTTP_400_BAD_REQUEST,
583
- detail="Missing code",
584
- )
585
-
586
- url = get_user_facing_url(request.url)
587
- token = await provider.get_token(code, url)
588
-
589
- (raw_user_data, default_user) = await provider.get_user_info(token)
590
-
591
- user = await config.code.oauth_callback(
592
- provider_id, token, raw_user_data, default_user, id_token
593
- )
594
-
595
- if not user:
596
- raise HTTPException(
597
- status_code=status.HTTP_401_UNAUTHORIZED,
598
- detail="Unauthorized",
599
- )
600
-
601
- access_token = create_jwt(user)
602
-
603
- if data_layer := get_data_layer():
604
- try:
605
- await data_layer.create_user(user)
606
- except Exception as e:
607
- logger.error(f"Error creating user: {e}")
608
-
609
- params = urllib.parse.urlencode(
610
- {
611
- "access_token": access_token,
612
- "token_type": "bearer",
613
- }
614
- )
615
- response = RedirectResponse(
616
- # FIXME: redirect to the right frontend base url to improve the dev environment
617
- url=f"/login/callback?{params}",
618
- status_code=302,
619
- )
620
- response.delete_cookie("oauth_state")
621
- return response
622
-
623
-
624
- @router.get("/project/translations")
500
+ @app.get("/project/translations")
625
501
  async def project_translations(
626
502
  language: str = Query(default="en-US", description="Language code"),
627
503
  ):
@@ -637,7 +513,7 @@ async def project_translations(
637
513
  )
638
514
 
639
515
 
640
- @router.get("/project/settings")
516
+ @app.get("/project/settings")
641
517
  async def project_settings(
642
518
  current_user: Annotated[Union[User, PersistedUser], Depends(get_current_user)],
643
519
  language: str = Query(default="en-US", description="Language code"),
@@ -683,7 +559,7 @@ async def project_settings(
683
559
  )
684
560
 
685
561
 
686
- @router.put("/feedback")
562
+ @app.put("/feedback")
687
563
  async def update_feedback(
688
564
  request: Request,
689
565
  update: UpdateFeedbackRequest,
@@ -702,7 +578,7 @@ async def update_feedback(
702
578
  return JSONResponse(content={"success": True, "feedbackId": feedback_id})
703
579
 
704
580
 
705
- @router.delete("/feedback")
581
+ @app.delete("/feedback")
706
582
  async def delete_feedback(
707
583
  request: Request,
708
584
  payload: DeleteFeedbackRequest,
@@ -721,7 +597,7 @@ async def delete_feedback(
721
597
  return JSONResponse(content={"success": True})
722
598
 
723
599
 
724
- @router.post("/project/threads")
600
+ @app.post("/project/threads")
725
601
  async def get_user_threads(
726
602
  request: Request,
727
603
  payload: GetThreadsRequest,
@@ -746,7 +622,7 @@ async def get_user_threads(
746
622
  return JSONResponse(content=res.to_dict())
747
623
 
748
624
 
749
- @router.get("/project/thread/{thread_id}")
625
+ @app.get("/project/thread/{thread_id}")
750
626
  async def get_thread(
751
627
  request: Request,
752
628
  thread_id: str,
@@ -764,7 +640,7 @@ async def get_thread(
764
640
  return JSONResponse(content=res)
765
641
 
766
642
 
767
- @router.get("/project/thread/{thread_id}/element/{element_id}")
643
+ @app.get("/project/thread/{thread_id}/element/{element_id}")
768
644
  async def get_thread_element(
769
645
  request: Request,
770
646
  thread_id: str,
@@ -783,7 +659,7 @@ async def get_thread_element(
783
659
  return JSONResponse(content=res)
784
660
 
785
661
 
786
- @router.delete("/project/thread")
662
+ @app.delete("/project/thread")
787
663
  async def delete_thread(
788
664
  request: Request,
789
665
  payload: DeleteThreadRequest,
@@ -804,7 +680,7 @@ async def delete_thread(
804
680
  return JSONResponse(content={"success": True})
805
681
 
806
682
 
807
- @router.post("/project/file")
683
+ @app.post("/project/file")
808
684
  async def upload_file(
809
685
  session_id: str,
810
686
  file: UploadFile,
@@ -840,7 +716,7 @@ async def upload_file(
840
716
  return JSONResponse(file_response)
841
717
 
842
718
 
843
- @router.get("/project/file/{file_id}")
719
+ @app.get("/project/file/{file_id}")
844
720
  async def get_file(
845
721
  file_id: str,
846
722
  session_id: Optional[str] = None,
@@ -862,7 +738,7 @@ async def get_file(
862
738
  raise HTTPException(status_code=404, detail="File not found")
863
739
 
864
740
 
865
- @router.get("/files/{filename:path}")
741
+ @app.get("/files/{filename:path}")
866
742
  async def serve_file(
867
743
  filename: str,
868
744
  current_user: Annotated[Union[User, PersistedUser], Depends(get_current_user)],
@@ -880,7 +756,7 @@ async def serve_file(
880
756
  raise HTTPException(status_code=404, detail="File not found")
881
757
 
882
758
 
883
- @router.get("/favicon")
759
+ @app.get("/favicon")
884
760
  async def get_favicon():
885
761
  custom_favicon_path = os.path.join(APP_ROOT, "public", "favicon.*")
886
762
  files = glob.glob(custom_favicon_path)
@@ -895,7 +771,7 @@ async def get_favicon():
895
771
  return FileResponse(favicon_path, media_type=media_type)
896
772
 
897
773
 
898
- @router.get("/logo")
774
+ @app.get("/logo")
899
775
  async def get_logo(theme: Optional[Theme] = Query(Theme.light)):
900
776
  theme_value = theme.value if theme else Theme.light.value
901
777
  logo_path = None
@@ -917,7 +793,7 @@ async def get_logo(theme: Optional[Theme] = Query(Theme.light)):
917
793
  return FileResponse(logo_path, media_type=media_type)
918
794
 
919
795
 
920
- @router.get("/avatars/{avatar_id}")
796
+ @app.get("/avatars/{avatar_id}")
921
797
  async def get_avatar(avatar_id: str):
922
798
  if avatar_id == "default":
923
799
  avatar_id = config.ui.name
@@ -936,20 +812,19 @@ async def get_avatar(avatar_id: str):
936
812
  return await get_favicon()
937
813
 
938
814
 
939
- @router.head("/")
815
+ @app.head("/")
940
816
  def status_check():
941
817
  return {"message": "Site is operational"}
942
818
 
943
819
 
944
- @router.get("/{full_path:path}")
945
- async def serve():
946
- html_template = get_html_template()
947
- """Serve the UI files."""
948
- response = HTMLResponse(content=html_template, status_code=200)
949
-
950
- return response
820
+ def register_wildcard_route_handler():
821
+ @app.get("/{path:path}")
822
+ async def serve(request: Request, path: str):
823
+ html_template = get_html_template()
824
+ """Serve the UI files."""
825
+ response = HTMLResponse(content=html_template, status_code=200)
951
826
 
827
+ return response
952
828
 
953
- app.include_router(router)
954
829
 
955
830
  import chainlit.socket # noqa
chainlit/slack/app.py CHANGED
@@ -176,8 +176,8 @@ async def get_user(slack_user_id: str):
176
176
  slack_user = await slack_app.client.users_info(user=slack_user_id)
177
177
  slack_user_profile = slack_user["user"]["profile"]
178
178
 
179
- user_identifier = slack_user_profile.get("email") or slack_user_id
180
- user = User(identifier=USER_PREFIX + user_identifier, metadata=slack_user_profile)
179
+ user_email = slack_user_profile.get("email")
180
+ user = User(identifier=USER_PREFIX + user_email, metadata=slack_user_profile)
181
181
 
182
182
  users_by_slack_id[slack_user_id] = user
183
183
 
chainlit/socket.py CHANGED
@@ -3,7 +3,6 @@ import json
3
3
  import time
4
4
  import uuid
5
5
  from typing import Any, Dict, Literal
6
- from urllib.parse import unquote
7
6
 
8
7
  from chainlit.action import Action
9
8
  from chainlit.auth import get_current_user, require_login
@@ -13,15 +12,14 @@ from chainlit.data import get_data_layer
13
12
  from chainlit.element import Element
14
13
  from chainlit.logger import logger
15
14
  from chainlit.message import ErrorMessage, Message
16
- from chainlit.server import sio
15
+ from chainlit.server import socket
17
16
  from chainlit.session import WebsocketSession
18
17
  from chainlit.telemetry import trace_event
19
18
  from chainlit.types import (
20
19
  AudioChunk,
21
20
  AudioChunkPayload,
22
21
  AudioEndPayload,
23
- MessagePayload,
24
- SystemMessagePayload,
22
+ UIMessagePayload,
25
23
  )
26
24
  from chainlit.user_session import user_sessions
27
25
 
@@ -54,7 +52,7 @@ async def resume_thread(session: WebsocketSession):
54
52
  user_is_author = author == session.user.identifier
55
53
 
56
54
  if user_is_author:
57
- metadata = thread.get("metadata") or {}
55
+ metadata = thread.get("metadata", {})
58
56
  user_sessions[session.id] = metadata.copy()
59
57
  if chat_profile := metadata.get("chat_profile"):
60
58
  session.chat_profile = chat_profile
@@ -99,8 +97,8 @@ def build_anon_user_identifier(environ):
99
97
  return str(uuid.uuid5(uuid.NAMESPACE_DNS, ip))
100
98
 
101
99
 
102
- @sio.on("connect")
103
- async def connect(sid, environ):
100
+ @socket.on("connect")
101
+ async def connect(sid, environ, auth):
104
102
  if (
105
103
  not config.code.on_chat_start
106
104
  and not config.code.on_message
@@ -125,11 +123,11 @@ async def connect(sid, environ):
125
123
 
126
124
  # Session scoped function to emit to the client
127
125
  def emit_fn(event, data):
128
- return sio.emit(event, data, to=sid)
126
+ return socket.emit(event, data, to=sid)
129
127
 
130
128
  # Session scoped function to emit to the client and wait for a response
131
129
  def emit_call_fn(event: Literal["ask", "call_fn"], data, timeout):
132
- return sio.call(event, data, timeout=timeout, to=sid)
130
+ return socket.call(event, data, timeout=timeout, to=sid)
133
131
 
134
132
  session_id = environ.get("HTTP_X_CHAINLIT_SESSION_ID")
135
133
  if restore_existing_session(sid, session_id, emit_fn, emit_call_fn):
@@ -140,10 +138,6 @@ async def connect(sid, environ):
140
138
 
141
139
  client_type = environ.get("HTTP_X_CHAINLIT_CLIENT_TYPE")
142
140
  http_referer = environ.get("HTTP_REFERER")
143
- url_encoded_chat_profile = environ.get("HTTP_X_CHAINLIT_CHAT_PROFILE")
144
- chat_profile = (
145
- unquote(url_encoded_chat_profile) if url_encoded_chat_profile else None
146
- )
147
141
 
148
142
  ws_session = WebsocketSession(
149
143
  id=session_id,
@@ -154,7 +148,7 @@ async def connect(sid, environ):
154
148
  user_env=user_env,
155
149
  user=user,
156
150
  token=token,
157
- chat_profile=chat_profile,
151
+ chat_profile=environ.get("HTTP_X_CHAINLIT_CHAT_PROFILE"),
158
152
  thread_id=environ.get("HTTP_X_CHAINLIT_THREAD_ID"),
159
153
  languages=environ.get("HTTP_ACCEPT_LANGUAGE"),
160
154
  http_referer=http_referer,
@@ -164,7 +158,7 @@ async def connect(sid, environ):
164
158
  return True
165
159
 
166
160
 
167
- @sio.on("connection_successful")
161
+ @socket.on("connection_successful")
168
162
  async def connection_successful(sid):
169
163
  context = init_ws_context(sid)
170
164
 
@@ -192,14 +186,14 @@ async def connection_successful(sid):
192
186
  context.session.current_task = task
193
187
 
194
188
 
195
- @sio.on("clear_session")
189
+ @socket.on("clear_session")
196
190
  async def clean_session(sid):
197
191
  session = WebsocketSession.get(sid)
198
192
  if session:
199
193
  session.to_clear = True
200
194
 
201
195
 
202
- @sio.on("disconnect")
196
+ @socket.on("disconnect")
203
197
  async def disconnect(sid):
204
198
  session = WebsocketSession.get(sid)
205
199
 
@@ -233,7 +227,7 @@ async def disconnect(sid):
233
227
  asyncio.ensure_future(clear_on_timeout(sid))
234
228
 
235
229
 
236
- @sio.on("stop")
230
+ @socket.on("stop")
237
231
  async def stop(sid):
238
232
  if session := WebsocketSession.get(sid):
239
233
  trace_event("stop_task")
@@ -248,12 +242,12 @@ async def stop(sid):
248
242
  await config.code.on_stop()
249
243
 
250
244
 
251
- async def process_message(session: WebsocketSession, payload: MessagePayload):
245
+ async def process_message(session: WebsocketSession, payload: UIMessagePayload):
252
246
  """Process a message from the user."""
253
247
  try:
254
248
  context = init_ws_context(session)
255
249
  await context.emitter.task_start()
256
- message = await context.emitter.process_message(payload)
250
+ message = await context.emitter.process_user_message(payload)
257
251
 
258
252
  if config.code.on_message:
259
253
  # Sleep 1ms to make sure any children step starts after the message step start
@@ -270,8 +264,8 @@ async def process_message(session: WebsocketSession, payload: MessagePayload):
270
264
  await context.emitter.task_end()
271
265
 
272
266
 
273
- @sio.on("client_message")
274
- async def message(sid, payload: MessagePayload):
267
+ @socket.on("ui_message")
268
+ async def message(sid, payload: UIMessagePayload):
275
269
  """Handle a message sent by the User."""
276
270
  session = WebsocketSession.require(sid)
277
271
 
@@ -279,7 +273,7 @@ async def message(sid, payload: MessagePayload):
279
273
  session.current_task = task
280
274
 
281
275
 
282
- @sio.on("audio_chunk")
276
+ @socket.on("audio_chunk")
283
277
  async def audio_chunk(sid, payload: AudioChunkPayload):
284
278
  """Handle an audio chunk sent by the user."""
285
279
  session = WebsocketSession.require(sid)
@@ -290,7 +284,7 @@ async def audio_chunk(sid, payload: AudioChunkPayload):
290
284
  asyncio.create_task(config.code.on_audio_chunk(AudioChunk(**payload)))
291
285
 
292
286
 
293
- @sio.on("audio_end")
287
+ @socket.on("audio_end")
294
288
  async def audio_end(sid, payload: AudioEndPayload):
295
289
  """Handle the end of the audio stream."""
296
290
  session = WebsocketSession.require(sid)
@@ -334,7 +328,7 @@ async def process_action(action: Action):
334
328
  logger.warning("No callback found for action %s", action.name)
335
329
 
336
330
 
337
- @sio.on("action_call")
331
+ @socket.on("action_call")
338
332
  async def call_action(sid, action):
339
333
  """Handle an action call from the UI."""
340
334
  context = init_ws_context(sid)
@@ -361,7 +355,7 @@ async def call_action(sid, action):
361
355
  )
362
356
 
363
357
 
364
- @sio.on("chat_settings_change")
358
+ @socket.on("chat_settings_change")
365
359
  async def change_settings(sid, settings: Dict[str, Any]):
366
360
  """Handle change settings submit from the UI."""
367
361
  context = init_ws_context(sid)