shinychat 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shinychat/__init__.py +9 -1
- shinychat/__version.py +16 -3
- shinychat/_chat.py +87 -106
- shinychat/_chat_normalize.py +252 -287
- shinychat/_chat_normalize_chatlas.py +449 -0
- shinychat/_chat_provider_types.py +11 -3
- shinychat/_chat_types.py +9 -2
- shinychat/_markdown_stream.py +9 -5
- shinychat/playwright/_chat.py +42 -3
- shinychat/types/__init__.py +6 -1
- shinychat/www/GIT_VERSION +1 -1
- shinychat/www/chat/chat.css +1 -1
- shinychat/www/chat/chat.css.map +2 -2
- shinychat/www/chat/chat.js +101 -22
- shinychat/www/chat/chat.js.map +4 -4
- shinychat/www/markdown-stream/markdown-stream.js +125 -46
- shinychat/www/markdown-stream/markdown-stream.js.map +4 -4
- {shinychat-0.1.0.dist-info → shinychat-0.2.0.dist-info}/METADATA +9 -8
- shinychat-0.2.0.dist-info/RECORD +31 -0
- shinychat-0.1.0.dist-info/RECORD +0 -30
- {shinychat-0.1.0.dist-info → shinychat-0.2.0.dist-info}/WHEEL +0 -0
- {shinychat-0.1.0.dist-info → shinychat-0.2.0.dist-info}/licenses/LICENSE +0 -0
shinychat/__init__.py
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
from ._chat import Chat, chat_ui
|
2
|
+
from ._chat_normalize import message_content, message_content_chunk
|
2
3
|
from ._markdown_stream import MarkdownStream, output_markdown_stream
|
3
4
|
|
4
|
-
__all__ = [
|
5
|
+
__all__ = [
|
6
|
+
"Chat",
|
7
|
+
"chat_ui",
|
8
|
+
"MarkdownStream",
|
9
|
+
"output_markdown_stream",
|
10
|
+
"message_content",
|
11
|
+
"message_content_chunk",
|
12
|
+
]
|
shinychat/__version.py
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
# file generated by setuptools-scm
|
2
2
|
# don't change, don't track in version control
|
3
3
|
|
4
|
-
__all__ = [
|
4
|
+
__all__ = [
|
5
|
+
"__version__",
|
6
|
+
"__version_tuple__",
|
7
|
+
"version",
|
8
|
+
"version_tuple",
|
9
|
+
"__commit_id__",
|
10
|
+
"commit_id",
|
11
|
+
]
|
5
12
|
|
6
13
|
TYPE_CHECKING = False
|
7
14
|
if TYPE_CHECKING:
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
9
16
|
from typing import Union
|
10
17
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
19
|
+
COMMIT_ID = Union[str, None]
|
12
20
|
else:
|
13
21
|
VERSION_TUPLE = object
|
22
|
+
COMMIT_ID = object
|
14
23
|
|
15
24
|
version: str
|
16
25
|
__version__: str
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
18
27
|
version_tuple: VERSION_TUPLE
|
28
|
+
commit_id: COMMIT_ID
|
29
|
+
__commit_id__: COMMIT_ID
|
19
30
|
|
20
|
-
__version__ = version = '0.
|
21
|
-
__version_tuple__ = version_tuple = (0,
|
31
|
+
__version__ = version = '0.2.0'
|
32
|
+
__version_tuple__ = version_tuple = (0, 2, 0)
|
33
|
+
|
34
|
+
__commit_id__ = commit_id = None
|
shinychat/_chat.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import inspect
|
4
|
+
import warnings
|
4
5
|
from contextlib import asynccontextmanager
|
5
6
|
from typing import (
|
6
7
|
TYPE_CHECKING,
|
@@ -52,9 +53,10 @@ from ._chat_bookmark import (
|
|
52
53
|
is_chatlas_chat_client,
|
53
54
|
set_chatlas_state,
|
54
55
|
)
|
55
|
-
from ._chat_normalize import
|
56
|
+
from ._chat_normalize import message_content, message_content_chunk
|
57
|
+
from ._chat_normalize_chatlas import hide_corresponding_request, is_tool_result
|
56
58
|
from ._chat_provider_types import (
|
57
|
-
AnthropicMessage,
|
59
|
+
AnthropicMessage, # pyright: ignore[reportAttributeAccessIssue]
|
58
60
|
GoogleMessage,
|
59
61
|
LangChainMessage,
|
60
62
|
OllamaMessage,
|
@@ -182,21 +184,7 @@ class Chat:
|
|
182
184
|
A unique identifier for the chat session. In Shiny Core, make sure this id
|
183
185
|
matches a corresponding :func:`~shiny.ui.chat_ui` call in the UI.
|
184
186
|
messages
|
185
|
-
|
186
|
-
following:
|
187
|
-
|
188
|
-
* A string, which is interpreted as markdown and rendered to HTML on the client.
|
189
|
-
* To prevent interpreting as markdown, mark the string as
|
190
|
-
:class:`~shiny.ui.HTML`.
|
191
|
-
* A UI element (specifically, a :class:`~shiny.ui.TagChild`).
|
192
|
-
* This includes :class:`~shiny.ui.TagList`, which take UI elements
|
193
|
-
(including strings) as children. In this case, strings are still
|
194
|
-
interpreted as markdown as long as they're not inside HTML.
|
195
|
-
* A dictionary with `content` and `role` keys. The `content` key can contain a
|
196
|
-
content as described above, and the `role` key can be "assistant" or "user".
|
197
|
-
|
198
|
-
**NOTE:** content may include specially formatted **input suggestion** links
|
199
|
-
(see `.append_message()` for more information).
|
187
|
+
Deprecated. Use `chat.ui(messages=...)` instead.
|
200
188
|
on_error
|
201
189
|
How to handle errors that occur in response to user input. When `"unhandled"`,
|
202
190
|
the app will stop running when an error occurs. Otherwise, a notification
|
@@ -208,11 +196,8 @@ class Chat:
|
|
208
196
|
* `"sanitize"`: Sanitize the error message before displaying it to the user.
|
209
197
|
* `"unhandled"`: Do not display any error message to the user.
|
210
198
|
tokenizer
|
211
|
-
|
212
|
-
|
213
|
-
is attempted to be loaded from the tokenizers library. A specific tokenizer
|
214
|
-
may also be provided by following the `TokenEncoding` (tiktoken or tozenizers)
|
215
|
-
protocol (e.g., `tiktoken.encoding_for_model("gpt-4o")`).
|
199
|
+
Deprecated. Token counting and message trimming features will be removed in a
|
200
|
+
future version.
|
216
201
|
"""
|
217
202
|
|
218
203
|
def __init__(
|
@@ -226,6 +211,17 @@ class Chat:
|
|
226
211
|
if not isinstance(id, str):
|
227
212
|
raise TypeError("`id` must be a string.")
|
228
213
|
|
214
|
+
if messages:
|
215
|
+
warn_deprecated(
|
216
|
+
"`Chat(messages=...)` is deprecated. Use `.ui(messages=...)` instead."
|
217
|
+
)
|
218
|
+
|
219
|
+
if tokenizer is not None:
|
220
|
+
warn_deprecated(
|
221
|
+
"`Chat(tokenizer=...)` is deprecated. "
|
222
|
+
"This is only relevant for `.messages(token_limits=...)` which is also now deprecated."
|
223
|
+
)
|
224
|
+
|
229
225
|
self.id = resolve_id(id)
|
230
226
|
self.user_input_id = ResolvedId(f"{self.id}_user_input")
|
231
227
|
self._transform_user: TransformUserInputAsync | None = None
|
@@ -381,7 +377,9 @@ class Chat:
|
|
381
377
|
"A on_user_submit function should not take more than 1 argument"
|
382
378
|
)
|
383
379
|
elif len(fn_params) == 1:
|
384
|
-
|
380
|
+
with warnings.catch_warnings():
|
381
|
+
warnings.simplefilter("ignore")
|
382
|
+
input = self.user_input(transform=True)
|
385
383
|
# The line immediately below handles the possibility of input
|
386
384
|
# being transformed to None. Technically, input should never be
|
387
385
|
# None at this point (since the handler should be suspended).
|
@@ -486,48 +484,22 @@ class Chat:
|
|
486
484
|
"""
|
487
485
|
Reactively read chat messages
|
488
486
|
|
489
|
-
Obtain chat messages within a reactive context.
|
490
|
-
intended for passing messages along to a model for response generation where
|
491
|
-
you typically want to:
|
492
|
-
|
493
|
-
1. Cap the number of tokens sent in a single request (i.e., `token_limits`).
|
494
|
-
2. Apply user input transformations (i.e., `transform_user`), if any.
|
495
|
-
3. Not apply assistant response transformations (i.e., `transform_assistant`)
|
496
|
-
since these are predominantly for display purposes (i.e., the model shouldn't
|
497
|
-
concern itself with how the responses are displayed).
|
487
|
+
Obtain chat messages within a reactive context.
|
498
488
|
|
499
489
|
Parameters
|
500
490
|
----------
|
501
491
|
format
|
502
|
-
|
503
|
-
|
504
|
-
with `content` and `role` keys). Other supported formats include:
|
505
|
-
|
506
|
-
* `"anthropic"`: Anthropic message format.
|
507
|
-
* `"google"`: Google message (aka content) format.
|
508
|
-
* `"langchain"`: LangChain message format.
|
509
|
-
* `"openai"`: OpenAI message format.
|
510
|
-
* `"ollama"`: Ollama message format.
|
492
|
+
Deprecated. Provider-specific message formatting will be removed in a future
|
493
|
+
version.
|
511
494
|
token_limits
|
512
|
-
|
513
|
-
|
514
|
-
is useful for avoiding "exceeded token limit" errors when sending messages
|
515
|
-
to the relevant model, while still providing the most recent context available.
|
516
|
-
A specified value must be a tuple of two integers. The first integer is the
|
517
|
-
maximum number of tokens that can be sent to the model in a single request.
|
518
|
-
The second integer is the amount of tokens to reserve for the model's response.
|
519
|
-
Note that token counts based on the `tokenizer` provided to the `Chat`
|
520
|
-
constructor.
|
495
|
+
Deprecated. Token counting and message trimming features will be removed in
|
496
|
+
a future version.
|
521
497
|
transform_user
|
522
|
-
|
523
|
-
|
524
|
-
The default value of `"all"` means all user input messages are transformed.
|
525
|
-
The value of `"last"` means only the last user input message is transformed.
|
526
|
-
The value of `"none"` means no user input messages are transformed.
|
498
|
+
Deprecated. Message transformation features will be removed in a future
|
499
|
+
version.
|
527
500
|
transform_assistant
|
528
|
-
|
529
|
-
|
530
|
-
constructor.
|
501
|
+
Deprecated. Message transformation features will be removed in a future
|
502
|
+
version.
|
531
503
|
|
532
504
|
Note
|
533
505
|
----
|
@@ -541,6 +513,34 @@ class Chat:
|
|
541
513
|
A tuple of chat messages.
|
542
514
|
"""
|
543
515
|
|
516
|
+
if not isinstance(format, MISSING_TYPE):
|
517
|
+
warn_deprecated(
|
518
|
+
"`.messages(format=...)` is deprecated. "
|
519
|
+
"Provider-specific message formatting will be removed in a future version. "
|
520
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
521
|
+
)
|
522
|
+
|
523
|
+
if token_limits is not None:
|
524
|
+
warn_deprecated(
|
525
|
+
"`.messages(token_limits=...)` is deprecated. "
|
526
|
+
"Token counting and message trimming features will be removed in a future version. "
|
527
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
528
|
+
)
|
529
|
+
|
530
|
+
if transform_user != "all":
|
531
|
+
warn_deprecated(
|
532
|
+
"`.messages(transform_user=...)` is deprecated. "
|
533
|
+
"Message transformation features will be removed in a future version. "
|
534
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
535
|
+
)
|
536
|
+
|
537
|
+
if transform_assistant:
|
538
|
+
warn_deprecated(
|
539
|
+
"`.messages(transform_assistant=...)` is deprecated. "
|
540
|
+
"Message transformation features will be removed in a future version. "
|
541
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
542
|
+
)
|
543
|
+
|
544
544
|
messages = self._messages()
|
545
545
|
|
546
546
|
# Anthropic requires a user message first and no system messages
|
@@ -636,7 +636,7 @@ class Chat:
|
|
636
636
|
self._pending_messages.append((message, False, "append", None))
|
637
637
|
return
|
638
638
|
|
639
|
-
msg =
|
639
|
+
msg = message_content(message)
|
640
640
|
msg = await self._transform_message(msg)
|
641
641
|
if msg is None:
|
642
642
|
return
|
@@ -753,7 +753,10 @@ class Chat:
|
|
753
753
|
self._current_stream_id = stream_id
|
754
754
|
|
755
755
|
# Normalize various message types into a ChatMessage()
|
756
|
-
msg =
|
756
|
+
msg = message_content_chunk(message)
|
757
|
+
|
758
|
+
if is_tool_result(message):
|
759
|
+
await hide_corresponding_request(message)
|
757
760
|
|
758
761
|
if operation == "replace":
|
759
762
|
self._current_stream_message = (
|
@@ -1020,25 +1023,15 @@ class Chat:
|
|
1020
1023
|
self, fn: TransformUserInput | TransformUserInputAsync | None = None
|
1021
1024
|
) -> None | Callable[[TransformUserInput | TransformUserInputAsync], None]:
|
1022
1025
|
"""
|
1023
|
-
|
1024
|
-
|
1025
|
-
Use this method as a decorator on a function (`fn`) that transforms user input
|
1026
|
-
before storing it in the chat messages returned by `.messages()`. This is
|
1027
|
-
useful for implementing RAG workflows, like taking a URL and scraping it for
|
1028
|
-
text before sending it to the model.
|
1029
|
-
|
1030
|
-
Parameters
|
1031
|
-
----------
|
1032
|
-
fn
|
1033
|
-
A function to transform user input before storing it in the chat
|
1034
|
-
`.messages()`. If `fn` returns `None`, the user input is effectively
|
1035
|
-
ignored, and `.on_user_submit()` callbacks are suspended until more input is
|
1036
|
-
submitted. This behavior is often useful to catch and handle errors that
|
1037
|
-
occur during transformation. In this case, the transform function should
|
1038
|
-
append an error message to the chat (via `.append_message()`) to inform the
|
1039
|
-
user of the error.
|
1026
|
+
Deprecated. User input transformation features will be removed in a future version.
|
1040
1027
|
"""
|
1041
1028
|
|
1029
|
+
warn_deprecated(
|
1030
|
+
"The `.transform_user_input` decorator is deprecated. "
|
1031
|
+
"User input transformation features will be removed in a future version. "
|
1032
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
1033
|
+
)
|
1034
|
+
|
1042
1035
|
def _set_transform(fn: TransformUserInput | TransformUserInputAsync):
|
1043
1036
|
self._transform_user = _utils.wrap_async(fn)
|
1044
1037
|
|
@@ -1062,31 +1055,15 @@ class Chat:
|
|
1062
1055
|
fn: TransformAssistantResponseFunction | None = None,
|
1063
1056
|
) -> None | Callable[[TransformAssistantResponseFunction], None]:
|
1064
1057
|
"""
|
1065
|
-
|
1066
|
-
|
1067
|
-
Use this method as a decorator on a function (`fn`) that transforms assistant
|
1068
|
-
responses before displaying them in the chat. This is useful for post-processing
|
1069
|
-
model responses before displaying them to the user.
|
1070
|
-
|
1071
|
-
Parameters
|
1072
|
-
----------
|
1073
|
-
fn
|
1074
|
-
A function that takes a string and returns either a string,
|
1075
|
-
:class:`shiny.ui.HTML`, or `None`. If `fn` returns a string, it gets
|
1076
|
-
interpreted and parsed as a markdown on the client (and the resulting HTML
|
1077
|
-
is then sanitized). If `fn` returns :class:`shiny.ui.HTML`, it will be
|
1078
|
-
displayed as-is. If `fn` returns `None`, the response is effectively ignored.
|
1079
|
-
|
1080
|
-
Note
|
1081
|
-
----
|
1082
|
-
When doing an `.append_message_stream()`, `fn` gets called on every chunk of the
|
1083
|
-
response (thus, it should be performant), and can optionally access more
|
1084
|
-
information (i.e., arguments) about the stream. The 1st argument (required)
|
1085
|
-
contains the accumulated content, the 2nd argument (optional) contains the
|
1086
|
-
current chunk, and the 3rd argument (optional) is a boolean indicating whether
|
1087
|
-
this chunk is the last one in the stream.
|
1058
|
+
Deprecated. Assistant response transformation features will be removed in a future version.
|
1088
1059
|
"""
|
1089
1060
|
|
1061
|
+
warn_deprecated(
|
1062
|
+
"The `.transform_assistant_response` decorator is deprecated. "
|
1063
|
+
"Assistant response transformation features will be removed in a future version. "
|
1064
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
1065
|
+
)
|
1066
|
+
|
1090
1067
|
def _set_transform(
|
1091
1068
|
fn: TransformAssistantResponseFunction,
|
1092
1069
|
):
|
@@ -1303,6 +1280,14 @@ class Chat:
|
|
1303
1280
|
2. Maintaining message state separately from `.messages()`.
|
1304
1281
|
|
1305
1282
|
"""
|
1283
|
+
|
1284
|
+
if transform:
|
1285
|
+
warn_deprecated(
|
1286
|
+
"`.user_input(transform=...)` is deprecated. "
|
1287
|
+
"User input transformation features will be removed in a future version. "
|
1288
|
+
"See here for more details: https://github.com/posit-dev/shinychat/pull/91"
|
1289
|
+
)
|
1290
|
+
|
1306
1291
|
msg = self._latest_user_input()
|
1307
1292
|
if msg is None:
|
1308
1293
|
return None
|
@@ -1791,17 +1776,13 @@ def chat_ui(
|
|
1791
1776
|
else:
|
1792
1777
|
ui = TagList(content).render()
|
1793
1778
|
|
1794
|
-
if role == "user":
|
1795
|
-
tag_name = "shiny-user-message"
|
1796
|
-
else:
|
1797
|
-
tag_name = "shiny-chat-message"
|
1798
|
-
|
1799
1779
|
message_tags.append(
|
1800
1780
|
Tag(
|
1801
|
-
|
1781
|
+
"shiny-chat-message",
|
1802
1782
|
ui["dependencies"],
|
1803
1783
|
content=ui["html"],
|
1804
1784
|
icon=icon_attr,
|
1785
|
+
data_role=role,
|
1805
1786
|
)
|
1806
1787
|
)
|
1807
1788
|
|