chainlit 2.0rc0__tar.gz → 2.0.1__tar.gz

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 (110) hide show
  1. {chainlit-2.0rc0 → chainlit-2.0.1}/PKG-INFO +3 -34
  2. {chainlit-2.0rc0 → chainlit-2.0.1}/README.md +1 -31
  3. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/__init__.py +49 -54
  4. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/action.py +12 -10
  5. chainlit-2.0rc0/chainlit/auth.py → chainlit-2.0.1/chainlit/auth/__init__.py +20 -34
  6. chainlit-2.0.1/chainlit/auth/cookie.py +123 -0
  7. chainlit-2.0.1/chainlit/auth/jwt.py +37 -0
  8. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/callbacks.py +29 -1
  9. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/chat_context.py +2 -2
  10. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/chat_settings.py +3 -1
  11. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/cli/__init__.py +14 -1
  12. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/config.py +21 -59
  13. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/context.py +3 -2
  14. chainlit-2.0.1/chainlit/copilot/dist/index.js +12200 -0
  15. chainlit-2.0.1/chainlit/data/__init__.py +113 -0
  16. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/acl.py +3 -2
  17. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/base.py +1 -1
  18. chainlit-2.0.1/chainlit/data/chainlit_data_layer.py +584 -0
  19. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/dynamodb.py +5 -3
  20. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/literalai.py +4 -6
  21. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/sql_alchemy.py +8 -7
  22. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/azure.py +1 -0
  23. chainlit-2.0.1/chainlit/data/storage_clients/azure_blob.py +80 -0
  24. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/base.py +6 -0
  25. chainlit-2.0.1/chainlit/data/storage_clients/gcs.py +78 -0
  26. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/s3.py +16 -3
  27. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/discord/app.py +2 -1
  28. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/element.py +13 -9
  29. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/emitter.py +17 -21
  30. chainlit-2.0rc0/chainlit/frontend/dist/assets/DailyMotion-CleI-8Dh.js → chainlit-2.0.1/chainlit/frontend/dist/assets/DailyMotion-B8XgmoRm.js +1 -1
  31. chainlit-2.0.1/chainlit/frontend/dist/assets/Dataframe-VU4lXMbv.js +22 -0
  32. chainlit-2.0rc0/chainlit/frontend/dist/assets/Facebook-C4PuTowX.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Facebook-fVIMi9h_.js +1 -1
  33. chainlit-2.0rc0/chainlit/frontend/dist/assets/FilePlayer-D49YToZz.js → chainlit-2.0.1/chainlit/frontend/dist/assets/FilePlayer-DlXvvaZa.js +1 -1
  34. chainlit-2.0rc0/chainlit/frontend/dist/assets/Kaltura-BkZcQEIs.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Kaltura-C48Ui_4V.js +1 -1
  35. chainlit-2.0rc0/chainlit/frontend/dist/assets/Mixcloud-DzvBFYsm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Mixcloud-Dmjz7RrS.js +1 -1
  36. chainlit-2.0rc0/chainlit/frontend/dist/assets/Mux-UXPyWWYv.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Mux-Bqaa3ZzG.js +1 -1
  37. chainlit-2.0rc0/chainlit/frontend/dist/assets/Preview-0YXzpiVm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Preview-B2d1Ugq4.js +1 -1
  38. chainlit-2.0rc0/chainlit/frontend/dist/assets/SoundCloud-CS54COex.js → chainlit-2.0.1/chainlit/frontend/dist/assets/SoundCloud-BGuk87T3.js +1 -1
  39. chainlit-2.0rc0/chainlit/frontend/dist/assets/Streamable-DYYShO6Q.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Streamable-DOe4rXrG.js +1 -1
  40. chainlit-2.0rc0/chainlit/frontend/dist/assets/Twitch-DG7403Hm.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Twitch-TA7I2UEi.js +1 -1
  41. chainlit-2.0rc0/chainlit/frontend/dist/assets/Vidyard-C5JbOHIQ.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Vidyard-B5F6Dk_y.js +1 -1
  42. chainlit-2.0rc0/chainlit/frontend/dist/assets/Vimeo-dFLZbhqH.js → chainlit-2.0.1/chainlit/frontend/dist/assets/Vimeo-DP_Y98tQ.js +1 -1
  43. chainlit-2.0.1/chainlit/frontend/dist/assets/Wistia-DB26BTg8.js +1 -0
  44. chainlit-2.0rc0/chainlit/frontend/dist/assets/YouTube-Dct4gpfH.js → chainlit-2.0.1/chainlit/frontend/dist/assets/YouTube-CMwwf2TN.js +1 -1
  45. chainlit-2.0.1/chainlit/frontend/dist/assets/index-88S3ZtD5.css +1 -0
  46. chainlit-2.0.1/chainlit/frontend/dist/assets/index-D7lZEN9m.js +8665 -0
  47. chainlit-2.0rc0/chainlit/frontend/dist/assets/react-plotly-CFHBSMgg.js → chainlit-2.0.1/chainlit/frontend/dist/assets/react-plotly-28_xImPF.js +1 -1
  48. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/index.html +2 -2
  49. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/haystack/callbacks.py +5 -4
  50. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/input_widget.py +6 -4
  51. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langchain/callbacks.py +56 -47
  52. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langflow/__init__.py +1 -0
  53. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/llama_index/callbacks.py +7 -7
  54. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/message.py +6 -7
  55. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/mistralai/__init__.py +3 -2
  56. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/oauth_providers.py +70 -3
  57. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/openai/__init__.py +3 -2
  58. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/secret.py +1 -1
  59. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/server.py +483 -199
  60. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/session.py +7 -5
  61. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/slack/app.py +3 -2
  62. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/socket.py +79 -106
  63. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/step.py +11 -11
  64. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/sync.py +2 -1
  65. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/teams/app.py +1 -0
  66. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/en-US.json +1 -1
  67. chainlit-2.0.1/chainlit/translations/nl-NL.json +229 -0
  68. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/types.py +20 -4
  69. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/user.py +2 -1
  70. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/utils.py +3 -2
  71. {chainlit-2.0rc0 → chainlit-2.0.1}/pyproject.toml +10 -9
  72. chainlit-2.0rc0/chainlit/copilot/dist/index.js +0 -4900
  73. chainlit-2.0rc0/chainlit/data/__init__.py +0 -32
  74. chainlit-2.0rc0/chainlit/frontend/dist/assets/Wistia-143Q9V9c.js +0 -1
  75. chainlit-2.0rc0/chainlit/frontend/dist/assets/index-2yAiK0R5.js +0 -1091
  76. chainlit-2.0rc0/chainlit/frontend/dist/assets/index-CwmincdQ.css +0 -1
  77. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/__main__.py +0 -0
  78. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/_utils.py +0 -0
  79. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/cache.py +0 -0
  80. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/copilot/dist/assets/logo_dark-IkGJ_IwC.svg +0 -0
  81. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/copilot/dist/assets/logo_light-Bb_IPh6r.svg +0 -0
  82. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/storage_clients/__init__.py +0 -0
  83. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/data/utils.py +0 -0
  84. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/discord/__init__.py +0 -0
  85. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/assets/logo_dark-IkGJ_IwC.svg +0 -0
  86. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/assets/logo_light-Bb_IPh6r.svg +0 -0
  87. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/frontend/dist/favicon.svg +0 -0
  88. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/haystack/__init__.py +0 -0
  89. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/hello.py +0 -0
  90. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/langchain/__init__.py +0 -0
  91. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/llama_index/__init__.py +0 -0
  92. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/logger.py +0 -0
  93. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/markdown.py +0 -0
  94. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/py.typed +0 -0
  95. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/slack/__init__.py +0 -0
  96. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/teams/__init__.py +0 -0
  97. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/telemetry.py +0 -0
  98. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/bn.json +0 -0
  99. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/gu.json +0 -0
  100. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/he-IL.json +0 -0
  101. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/hi.json +0 -0
  102. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/kn.json +0 -0
  103. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/ml.json +0 -0
  104. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/mr.json +0 -0
  105. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/ta.json +0 -0
  106. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/te.json +0 -0
  107. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations/zh-CN.json +0 -0
  108. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/translations.py +0 -0
  109. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/user_session.py +0 -0
  110. {chainlit-2.0rc0 → chainlit-2.0.1}/chainlit/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chainlit
3
- Version: 2.0rc0
3
+ Version: 2.0.1
4
4
  Summary: Build Conversational AI.
5
5
  Home-page: https://chainlit.io/
6
6
  License: Apache-2.0
@@ -30,12 +30,11 @@ Requires-Dist: httpx (>=0.23.0)
30
30
  Requires-Dist: lazify (>=0.4.0,<0.5.0)
31
31
  Requires-Dist: literalai (==0.0.623)
32
32
  Requires-Dist: nest-asyncio (>=1.6.0,<2.0.0)
33
- Requires-Dist: numpy (>=1.26,<2.0)
34
33
  Requires-Dist: packaging (>=23.1,<24.0)
35
34
  Requires-Dist: pydantic (>=1,<3)
36
35
  Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
37
36
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
38
- Requires-Dist: python-multipart (>=0.0.9,<0.0.10)
37
+ Requires-Dist: python-multipart (>=0.0.18,<0.0.19)
39
38
  Requires-Dist: python-socketio (>=5.11.0,<6.0.0)
40
39
  Requires-Dist: starlette (>=0.41.2,<0.42.0)
41
40
  Requires-Dist: syncer (>=2.0.3,<3.0.0)
@@ -59,22 +58,10 @@ Description-Content-Type: text/markdown
59
58
 
60
59
  Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications.
61
60
 
62
- - ✅ ChatGPT-like application
63
- - ✅ Embedded Chatbot & Software Copilot
64
- - ✅ Slack & Discord
65
- - ✅ Custom frontend (build your own agentic experience)
66
- - ✅ API Endpoint
67
-
68
61
  Full documentation is available [here](https://docs.chainlit.io). You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/), an app built using Chainlit!
69
62
 
70
- > [!NOTE]
71
- > Check out [Literal AI](https://literalai.com), our product to monitor and evaluate LLM applications! It works with any Python or TypeScript applications and [seamlessly](https://docs.chainlit.io/data-persistence/overview) with Chainlit by adding a `LITERAL_API_KEY` in your project.
72
- >
73
- > Chainlit is developed and maintained by the Literal AI team, which is currently focused on expanding the capabilities of Literal AI. While we continue to support and maintain Chainlit, we are also committed to enabling the community to contribute, particularly in areas like integrations and data layers.
63
+ https://github.com/user-attachments/assets/b3738aba-55c0-42fa-ac00-6efd1ee0d148
74
64
 
75
- <p align="center">
76
- <img src="https://github.com/Chainlit/chainlit/assets/13104895/0c2cc7a9-766c-41d3-aae2-117a2d0eb8ed" alt="Chainlit user interface" width="80%"></img>
77
- </p>
78
65
 
79
66
  ## Installation
80
67
 
@@ -142,24 +129,6 @@ chainlit run demo.py -w
142
129
 
143
130
  <img src="/images/quick-start.png" alt="Quick Start"></img>
144
131
 
145
- ## 🎉 Key Features and Integrations
146
-
147
- Full documentation is available [here](https://docs.chainlit.io). Key features:
148
-
149
- - [💬 Multi Modal chats](https://docs.chainlit.io/advanced-features/multi-modal)
150
- - [💭 Chain of Thought visualization](https://docs.chainlit.io/concepts/step)
151
- - [💾 Data persistence + human feedback](https://docs.chainlit.io/data-persistence/overview)
152
- - [🐛 Debug Mode](https://docs.chainlit.io/data-persistence/enterprise#debug-mode)
153
- - [👤 Authentication](https://docs.chainlit.io/authentication/overview)
154
-
155
- Chainlit is compatible with all Python programs and libraries. That being said, it comes with integrations for:
156
-
157
- - [LangChain](https://docs.chainlit.io/integrations/langchain)
158
- - [Llama Index](https://docs.chainlit.io/integrations/llama-index)
159
- - [Autogen](https://github.com/Chainlit/cookbook/tree/main/pyautogen)
160
- - [OpenAI Assistant](https://github.com/Chainlit/cookbook/tree/main/openai-assistant)
161
- - [Haystack](https://docs.chainlit.io/integrations/haystack)
162
-
163
132
  ## 📚 More Examples - Cookbook
164
133
 
165
134
  You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more.
@@ -10,22 +10,10 @@
10
10
 
11
11
  Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications.
12
12
 
13
- - ✅ ChatGPT-like application
14
- - ✅ Embedded Chatbot & Software Copilot
15
- - ✅ Slack & Discord
16
- - ✅ Custom frontend (build your own agentic experience)
17
- - ✅ API Endpoint
18
-
19
13
  Full documentation is available [here](https://docs.chainlit.io). You can ask Chainlit related questions to [Chainlit Help](https://help.chainlit.io/), an app built using Chainlit!
20
14
 
21
- > [!NOTE]
22
- > Check out [Literal AI](https://literalai.com), our product to monitor and evaluate LLM applications! It works with any Python or TypeScript applications and [seamlessly](https://docs.chainlit.io/data-persistence/overview) with Chainlit by adding a `LITERAL_API_KEY` in your project.
23
- >
24
- > Chainlit is developed and maintained by the Literal AI team, which is currently focused on expanding the capabilities of Literal AI. While we continue to support and maintain Chainlit, we are also committed to enabling the community to contribute, particularly in areas like integrations and data layers.
15
+ https://github.com/user-attachments/assets/b3738aba-55c0-42fa-ac00-6efd1ee0d148
25
16
 
26
- <p align="center">
27
- <img src="https://github.com/Chainlit/chainlit/assets/13104895/0c2cc7a9-766c-41d3-aae2-117a2d0eb8ed" alt="Chainlit user interface" width="80%"></img>
28
- </p>
29
17
 
30
18
  ## Installation
31
19
 
@@ -93,24 +81,6 @@ chainlit run demo.py -w
93
81
 
94
82
  <img src="/images/quick-start.png" alt="Quick Start"></img>
95
83
 
96
- ## 🎉 Key Features and Integrations
97
-
98
- Full documentation is available [here](https://docs.chainlit.io). Key features:
99
-
100
- - [💬 Multi Modal chats](https://docs.chainlit.io/advanced-features/multi-modal)
101
- - [💭 Chain of Thought visualization](https://docs.chainlit.io/concepts/step)
102
- - [💾 Data persistence + human feedback](https://docs.chainlit.io/data-persistence/overview)
103
- - [🐛 Debug Mode](https://docs.chainlit.io/data-persistence/enterprise#debug-mode)
104
- - [👤 Authentication](https://docs.chainlit.io/authentication/overview)
105
-
106
- Chainlit is compatible with all Python programs and libraries. That being said, it comes with integrations for:
107
-
108
- - [LangChain](https://docs.chainlit.io/integrations/langchain)
109
- - [Llama Index](https://docs.chainlit.io/integrations/llama-index)
110
- - [Autogen](https://github.com/Chainlit/cookbook/tree/main/pyautogen)
111
- - [OpenAI Assistant](https://github.com/Chainlit/cookbook/tree/main/openai-assistant)
112
- - [Haystack](https://docs.chainlit.io/integrations/haystack)
113
-
114
84
  ## 📚 More Examples - Cookbook
115
85
 
116
86
  You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more.
@@ -25,7 +25,7 @@ from chainlit.chat_settings import ChatSettings
25
25
  from chainlit.context import context
26
26
  from chainlit.element import (
27
27
  Audio,
28
- Component,
28
+ CustomElement,
29
29
  Dataframe,
30
30
  File,
31
31
  Image,
@@ -69,7 +69,9 @@ from .callbacks import (
69
69
  on_message,
70
70
  on_settings_update,
71
71
  on_stop,
72
+ on_window_message,
72
73
  password_auth_callback,
74
+ send_window_message,
73
75
  set_chat_profiles,
74
76
  set_starters,
75
77
  )
@@ -115,80 +117,73 @@ __getattr__ = make_module_getattr(
115
117
  )
116
118
 
117
119
  __all__ = [
118
- "__version__",
120
+ "Action",
121
+ "AskActionMessage",
122
+ "AskFileMessage",
123
+ "AskUserMessage",
124
+ "AsyncLangchainCallbackHandler",
125
+ "Audio",
126
+ "ChatGeneration",
119
127
  "ChatProfile",
120
- "Starter",
121
- "user_session",
122
- "chat_context",
128
+ "ChatSettings",
129
+ "CompletionGeneration",
123
130
  "CopilotFunction",
131
+ "CustomElement",
132
+ "Dataframe",
133
+ "ErrorMessage",
134
+ "File",
135
+ "GenerationMessage",
136
+ "HaystackAgentCallbackHandler",
137
+ "Image",
124
138
  "InputAudioChunk",
139
+ "LangchainCallbackHandler",
140
+ "LlamaIndexCallbackHandler",
141
+ "Message",
125
142
  "OutputAudioChunk",
126
- "Action",
127
- "User",
128
- "PersistedUser",
129
- "Audio",
130
143
  "Pdf",
144
+ "PersistedUser",
131
145
  "Plotly",
132
- "Image",
133
- "Text",
134
- "Component",
135
146
  "Pyplot",
136
- "File",
147
+ "Starter",
148
+ "Step",
137
149
  "Task",
138
150
  "TaskList",
139
151
  "TaskStatus",
152
+ "Text",
153
+ "User",
140
154
  "Video",
141
- "ChatSettings",
142
- "input_widget",
143
- "Message",
144
- "ErrorMessage",
145
- "AskUserMessage",
146
- "AskActionMessage",
147
- "AskFileMessage",
148
- "Step",
149
- "step",
150
- "ChatGeneration",
151
- "CompletionGeneration",
152
- "GenerationMessage",
153
- "on_logout",
154
- "on_chat_start",
155
- "on_chat_end",
156
- "on_chat_resume",
157
- "on_stop",
155
+ "__version__",
158
156
  "action_callback",
159
157
  "author_rename",
160
- "on_settings_update",
161
- "password_auth_callback",
162
- "header_auth_callback",
163
- "sleep",
164
- "run_sync",
165
- "make_async",
166
158
  "cache",
159
+ "chat_context",
167
160
  "context",
168
- "LangchainCallbackHandler",
169
- "AsyncLangchainCallbackHandler",
170
- "LlamaIndexCallbackHandler",
171
- "HaystackAgentCallbackHandler",
172
- "instrument_openai",
173
- "instrument_mistralai",
174
- "password_auth_callback",
161
+ "data_layer",
175
162
  "header_auth_callback",
163
+ "input_widget",
164
+ "instrument_mistralai",
165
+ "instrument_openai",
166
+ "make_async",
176
167
  "oauth_callback",
168
+ "on_audio_chunk",
169
+ "on_audio_end",
170
+ "on_audio_start",
171
+ "on_chat_end",
172
+ "on_chat_resume",
173
+ "on_chat_start",
177
174
  "on_logout",
178
175
  "on_message",
179
- "on_chat_start",
180
- "on_chat_resume",
176
+ "on_settings_update",
177
+ "on_stop",
178
+ "on_window_message",
179
+ "password_auth_callback",
180
+ "run_sync",
181
+ "send_window_message",
181
182
  "set_chat_profiles",
182
183
  "set_starters",
183
- "on_chat_end",
184
- "on_audio_start",
185
- "on_audio_chunk",
186
- "on_audio_end",
187
- "author_rename",
188
- "on_stop",
189
- "action_callback",
190
- "on_settings_update",
191
- "data_layer",
184
+ "sleep",
185
+ "step",
186
+ "user_session",
192
187
  ]
193
188
 
194
189
 
@@ -1,28 +1,30 @@
1
1
  import uuid
2
- from typing import Optional
2
+ from typing import Dict, Optional
3
+
4
+ from dataclasses_json import DataClassJsonMixin
5
+ from pydantic import Field
6
+ from pydantic.dataclasses import dataclass
3
7
 
4
8
  from chainlit.context import context
5
9
  from chainlit.telemetry import trace_event
6
- from dataclasses_json import DataClassJsonMixin
7
- from pydantic.dataclasses import Field, dataclass
8
10
 
9
11
 
10
12
  @dataclass
11
13
  class Action(DataClassJsonMixin):
12
14
  # Name of the action, this should be used in the action_callback
13
15
  name: str
14
- # The value associated with the action. This is useful to differentiate between multiple actions with the same name.
15
- value: str
16
- # The label of the action. This is what the user will see. If not provided the name will be used.
16
+ # The parameters to call this action with.
17
+ payload: Dict
18
+ # The label of the action. This is what the user will see.
17
19
  label: str = ""
18
- # The description of the action. This is what the user will see when they hover the action.
19
- description: str = ""
20
+ # The tooltip of the action button. This is what the user will see when they hover the action.
21
+ tooltip: str = ""
22
+ # The lucid icon name for this action.
23
+ icon: Optional[str] = None
20
24
  # This should not be set manually, only used internally.
21
25
  forId: Optional[str] = None
22
26
  # The ID of the action
23
27
  id: str = Field(default_factory=lambda: str(uuid.uuid4()))
24
- # Show the action in a drawer menu
25
- collapsed: bool = False
26
28
 
27
29
  def __post_init__(self) -> None:
28
30
  trace_event(f"init {self.__class__.__name__}")
@@ -1,20 +1,16 @@
1
1
  import os
2
- from datetime import datetime, timedelta
3
- from typing import Any, Dict
4
2
 
5
- import jwt
3
+ from fastapi import Depends, HTTPException
4
+
6
5
  from chainlit.config import config
7
6
  from chainlit.data import get_data_layer
7
+ from chainlit.logger import logger
8
8
  from chainlit.oauth_providers import get_configured_oauth_providers
9
- from chainlit.user import User
10
- from fastapi import Depends, HTTPException
11
- from fastapi.security import OAuth2PasswordBearer
12
-
13
- reuseable_oauth = OAuth2PasswordBearer(tokenUrl="/login", auto_error=False)
14
9
 
10
+ from .cookie import OAuth2PasswordBearerWithCookie
11
+ from .jwt import create_jwt, decode_jwt, get_jwt_secret
15
12
 
16
- def get_jwt_secret():
17
- return os.environ.get("CHAINLIT_AUTH_SECRET")
13
+ reuseable_oauth = OAuth2PasswordBearerWithCookie(tokenUrl="/login", auto_error=False)
18
14
 
19
15
 
20
16
  def ensure_jwt_secret():
@@ -45,49 +41,36 @@ def get_configuration():
45
41
  "oauthProviders": (
46
42
  get_configured_oauth_providers() if is_oauth_enabled() else []
47
43
  ),
44
+ "default_theme": config.ui.default_theme,
48
45
  }
49
46
 
50
47
 
51
- def create_jwt(data: User) -> str:
52
- to_encode: Dict[str, Any] = data.to_dict()
53
- to_encode.update(
54
- {
55
- "exp": datetime.utcnow() + timedelta(
56
- seconds=config.project.user_session_timeout
57
- ),
58
- }
59
- )
60
- encoded_jwt = jwt.encode(to_encode, get_jwt_secret(), algorithm="HS256")
61
- return encoded_jwt
62
-
63
-
64
48
  async def authenticate_user(token: str = Depends(reuseable_oauth)):
65
49
  try:
66
- dict = jwt.decode(
67
- token,
68
- get_jwt_secret(),
69
- algorithms=["HS256"],
70
- options={"verify_signature": True},
71
- )
72
- del dict["exp"]
73
- user = User(**dict)
50
+ user = decode_jwt(token)
74
51
  except Exception as e:
75
52
  raise HTTPException(
76
53
  status_code=401, detail="Invalid authentication token"
77
54
  ) from e
55
+
78
56
  if data_layer := get_data_layer():
57
+ # Get or create persistent user if we've a data layer available.
79
58
  try:
80
59
  persisted_user = await data_layer.get_user(user.identifier)
81
60
  if persisted_user is None:
82
61
  persisted_user = await data_layer.create_user(user)
83
- except Exception:
62
+ assert persisted_user
63
+ except Exception as e:
64
+ logger.exception("Unable to get persisted_user from data layer: %s", e)
84
65
  return user
85
66
 
86
67
  if user and user.display_name:
68
+ # Copy ephemeral display_name from authenticated user to persistent user.
87
69
  persisted_user.display_name = user.display_name
70
+
88
71
  return persisted_user
89
- else:
90
- return user
72
+
73
+ return user
91
74
 
92
75
 
93
76
  async def get_current_user(token: str = Depends(reuseable_oauth)):
@@ -95,3 +78,6 @@ async def get_current_user(token: str = Depends(reuseable_oauth)):
95
78
  return None
96
79
 
97
80
  return await authenticate_user(token)
81
+
82
+
83
+ __all__ = ["create_jwt", "get_configuration", "get_current_user"]
@@ -0,0 +1,123 @@
1
+ import os
2
+ from typing import Literal, Optional, cast
3
+
4
+ from fastapi import Request, Response
5
+ from fastapi.exceptions import HTTPException
6
+ from fastapi.security.base import SecurityBase
7
+ from fastapi.security.utils import get_authorization_scheme_param
8
+ from starlette.status import HTTP_401_UNAUTHORIZED
9
+
10
+ """ Module level cookie settings. """
11
+ _cookie_samesite = cast(
12
+ Literal["lax", "strict", "none"],
13
+ os.environ.get("CHAINLIT_COOKIE_SAMESITE", "lax"),
14
+ )
15
+
16
+ assert (
17
+ _cookie_samesite
18
+ in [
19
+ "lax",
20
+ "strict",
21
+ "none",
22
+ ]
23
+ ), "Invalid value for CHAINLIT_COOKIE_SAMESITE. Must be one of 'lax', 'strict' or 'none'."
24
+ _cookie_secure = _cookie_samesite == "none"
25
+
26
+ _auth_cookie_lifetime = 60 * 60 # 1 hour
27
+ _state_cookie_lifetime = 3 * 60 # 3m
28
+ _auth_cookie_name = "access_token"
29
+ _state_cookie_name = "oauth_state"
30
+
31
+
32
+ class OAuth2PasswordBearerWithCookie(SecurityBase):
33
+ """
34
+ OAuth2 password flow with cookie support with fallback to bearer token.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ tokenUrl: str,
40
+ scheme_name: Optional[str] = None,
41
+ auto_error: bool = True,
42
+ ):
43
+ self.tokenUrl = tokenUrl
44
+ self.scheme_name = scheme_name or self.__class__.__name__
45
+ self.auto_error = auto_error
46
+
47
+ async def __call__(self, request: Request) -> Optional[str]:
48
+ # First try to get the token from the cookie
49
+ token = request.cookies.get(_auth_cookie_name)
50
+
51
+ # If no cookie, try the Authorization header as fallback
52
+ if not token:
53
+ # TODO: Only bother to check if cookie auth is explicitly disabled.
54
+ authorization = request.headers.get("Authorization")
55
+ if authorization:
56
+ scheme, token = get_authorization_scheme_param(authorization)
57
+ if scheme.lower() != "bearer":
58
+ if self.auto_error:
59
+ raise HTTPException(
60
+ status_code=HTTP_401_UNAUTHORIZED,
61
+ detail="Invalid authentication credentials",
62
+ headers={"WWW-Authenticate": "Bearer"},
63
+ )
64
+ else:
65
+ return None
66
+ else:
67
+ if self.auto_error:
68
+ raise HTTPException(
69
+ status_code=HTTP_401_UNAUTHORIZED,
70
+ detail="Not authenticated",
71
+ headers={"WWW-Authenticate": "Bearer"},
72
+ )
73
+ else:
74
+ return None
75
+
76
+ return token
77
+
78
+
79
+ def set_auth_cookie(response: Response, token: str):
80
+ """
81
+ Helper function to set the authentication cookie with secure parameters
82
+ """
83
+
84
+ response.set_cookie(
85
+ key=_auth_cookie_name,
86
+ value=token,
87
+ httponly=True,
88
+ secure=_cookie_secure,
89
+ samesite=_cookie_samesite,
90
+ max_age=_auth_cookie_lifetime,
91
+ )
92
+
93
+
94
+ def clear_auth_cookie(response: Response):
95
+ """
96
+ Helper function to clear the authentication cookie
97
+ """
98
+ response.delete_cookie(key=_auth_cookie_name, path="/")
99
+
100
+
101
+ def set_oauth_state_cookie(response: Response, token: str):
102
+ response.set_cookie(
103
+ _state_cookie_name,
104
+ token,
105
+ httponly=True,
106
+ samesite=_cookie_samesite,
107
+ secure=_cookie_secure,
108
+ max_age=_state_cookie_lifetime,
109
+ )
110
+
111
+
112
+ def validate_oauth_state_cookie(request: Request, state: str):
113
+ """Check the state from the oauth provider against the browser cookie."""
114
+
115
+ oauth_state = request.cookies.get(_state_cookie_name)
116
+
117
+ if oauth_state != state:
118
+ raise Exception("oauth state does not correspond")
119
+
120
+
121
+ def clear_oauth_state_cookie(response: Response):
122
+ """Oauth complete, delete state token."""
123
+ response.delete_cookie(_state_cookie_name) # Do we set path here?
@@ -0,0 +1,37 @@
1
+ import datetime
2
+ import os
3
+ from typing import Any, Dict, Optional
4
+
5
+ import jwt as pyjwt
6
+
7
+ from chainlit.config import config
8
+ from chainlit.user import User
9
+
10
+
11
+ def get_jwt_secret() -> Optional[str]:
12
+ return os.environ.get("CHAINLIT_AUTH_SECRET")
13
+
14
+
15
+ def create_jwt(data: User) -> str:
16
+ to_encode: Dict[str, Any] = data.to_dict()
17
+ to_encode.update(
18
+ {
19
+ "exp": datetime.datetime.utcnow()
20
+ + datetime.timedelta(seconds=config.project.user_session_timeout),
21
+ }
22
+ )
23
+ secret = get_jwt_secret()
24
+ assert secret
25
+ encoded_jwt = pyjwt.encode(to_encode, secret, algorithm="HS256")
26
+ return encoded_jwt
27
+
28
+
29
+ def decode_jwt(token: str) -> User:
30
+ dict = pyjwt.decode(
31
+ token,
32
+ get_jwt_secret(),
33
+ algorithms=["HS256"],
34
+ options={"verify_signature": True},
35
+ )
36
+ del dict["exp"]
37
+ return User(**dict)
@@ -6,6 +6,7 @@ from starlette.datastructures import Headers
6
6
 
7
7
  from chainlit.action import Action
8
8
  from chainlit.config import config
9
+ from chainlit.context import context
9
10
  from chainlit.data.base import BaseDataLayer
10
11
  from chainlit.message import Message
11
12
  from chainlit.oauth_providers import get_configured_oauth_providers
@@ -125,6 +126,33 @@ def on_message(func: Callable) -> Callable:
125
126
  return func
126
127
 
127
128
 
129
+ @trace
130
+ async def send_window_message(data: Any):
131
+ """
132
+ Send custom data to the host window via a window.postMessage event.
133
+
134
+ Args:
135
+ data (Any): The data to send with the event.
136
+ """
137
+ await context.emitter.send_window_message(data)
138
+
139
+
140
+ @trace
141
+ def on_window_message(func: Callable[[str], Any]) -> Callable:
142
+ """
143
+ Hook to react to javascript postMessage events coming from the UI.
144
+
145
+ Args:
146
+ func (Callable[[str], Any]): The function to be called when a window message is received.
147
+ Takes the message content as a string parameter.
148
+
149
+ Returns:
150
+ Callable[[str], Any]: The decorated on_window_message function.
151
+ """
152
+ config.code.on_window_message = wrap_user_function(func)
153
+ return func
154
+
155
+
128
156
  @trace
129
157
  def on_chat_start(func: Callable) -> Callable:
130
158
  """
@@ -297,7 +325,7 @@ def action_callback(name: str) -> Callable:
297
325
  """
298
326
 
299
327
  def decorator(func: Callable[[Action], Any]):
300
- config.code.action_callbacks[name] = wrap_user_function(func, with_task=True)
328
+ config.code.action_callbacks[name] = wrap_user_function(func, with_task=False)
301
329
  return func
302
330
 
303
331
  return decorator
@@ -25,10 +25,10 @@ class ChatContext:
25
25
 
26
26
  if context.session.id not in chat_contexts:
27
27
  chat_contexts[context.session.id] = []
28
-
28
+
29
29
  if message not in chat_contexts[context.session.id]:
30
30
  chat_contexts[context.session.id].append(message)
31
-
31
+
32
32
  return message
33
33
 
34
34
  def remove(self, message: "Message") -> bool:
@@ -1,8 +1,10 @@
1
1
  from typing import List
2
2
 
3
+ from pydantic import Field
4
+ from pydantic.dataclasses import dataclass
5
+
3
6
  from chainlit.context import context
4
7
  from chainlit.input_widget import InputWidget
5
- from pydantic.dataclasses import Field, dataclass
6
8
 
7
9
 
8
10
  @dataclass
@@ -9,6 +9,7 @@ import uvicorn
9
9
  nest_asyncio.apply()
10
10
 
11
11
  # ruff: noqa: E402
12
+ from chainlit.auth import ensure_jwt_secret
12
13
  from chainlit.cache import init_lc_cache
13
14
  from chainlit.config import (
14
15
  BACKEND_ROOT,
@@ -24,7 +25,18 @@ from chainlit.logger import logger
24
25
  from chainlit.markdown import init_markdown
25
26
  from chainlit.secret import random_secret
26
27
  from chainlit.telemetry import trace_event
27
- from chainlit.utils import check_file, ensure_jwt_secret
28
+ from chainlit.utils import check_file
29
+
30
+
31
+ def assert_app():
32
+ if (
33
+ not config.code.on_chat_start
34
+ and not config.code.on_message
35
+ and not config.code.on_audio_chunk
36
+ ):
37
+ raise Exception(
38
+ "You need to configure at least one of on_chat_start, on_message or on_audio_chunk callback"
39
+ )
28
40
 
29
41
 
30
42
  # Create the main command group for Chainlit CLI
@@ -66,6 +78,7 @@ def run_chainlit(target: str):
66
78
  load_module(config.run.module_name)
67
79
 
68
80
  ensure_jwt_secret()
81
+ assert_app()
69
82
 
70
83
  # Create the chainlit.md file if it doesn't exist
71
84
  init_markdown(config.root)