langfun 0.0.2.dev20240429__py3-none-any.whl → 0.1.2.dev202501140804__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.
- langfun/__init__.py +20 -2
- langfun/core/__init__.py +16 -5
- langfun/core/agentic/__init__.py +30 -0
- langfun/core/agentic/action.py +854 -0
- langfun/core/agentic/action_eval.py +150 -0
- langfun/core/agentic/action_eval_test.py +109 -0
- langfun/core/agentic/action_test.py +136 -0
- langfun/core/coding/python/__init__.py +5 -11
- langfun/core/coding/python/correction.py +37 -21
- langfun/core/coding/python/correction_test.py +29 -3
- langfun/core/coding/python/execution.py +40 -216
- langfun/core/coding/python/execution_test.py +29 -89
- langfun/core/coding/python/generation.py +21 -11
- langfun/core/coding/python/generation_test.py +2 -2
- langfun/core/coding/python/parsing.py +108 -193
- langfun/core/coding/python/parsing_test.py +2 -105
- langfun/core/component.py +63 -2
- langfun/core/component_test.py +53 -0
- langfun/core/concurrent.py +414 -117
- langfun/core/concurrent_test.py +111 -24
- langfun/core/console.py +18 -5
- langfun/core/console_test.py +17 -0
- langfun/core/eval/__init__.py +16 -1
- langfun/core/eval/base.py +622 -174
- langfun/core/eval/base_test.py +200 -54
- langfun/core/eval/matching.py +63 -76
- langfun/core/eval/matching_test.py +17 -8
- langfun/core/eval/patching.py +130 -0
- langfun/core/eval/patching_test.py +170 -0
- langfun/core/eval/scoring.py +26 -26
- langfun/core/eval/scoring_test.py +19 -2
- langfun/core/eval/v2/__init__.py +42 -0
- langfun/core/eval/v2/checkpointing.py +380 -0
- langfun/core/eval/v2/checkpointing_test.py +228 -0
- langfun/core/eval/v2/eval_test_helper.py +136 -0
- langfun/core/eval/v2/evaluation.py +725 -0
- langfun/core/eval/v2/evaluation_test.py +180 -0
- langfun/core/eval/v2/example.py +305 -0
- langfun/core/eval/v2/example_test.py +128 -0
- langfun/core/eval/v2/experiment.py +1048 -0
- langfun/core/eval/v2/experiment_test.py +433 -0
- langfun/core/eval/v2/metric_values.py +156 -0
- langfun/core/eval/v2/metric_values_test.py +80 -0
- langfun/core/eval/v2/metrics.py +357 -0
- langfun/core/eval/v2/metrics_test.py +203 -0
- langfun/core/eval/v2/progress.py +348 -0
- langfun/core/eval/v2/progress_test.py +82 -0
- langfun/core/eval/v2/progress_tracking.py +210 -0
- langfun/core/eval/v2/progress_tracking_test.py +66 -0
- langfun/core/eval/v2/reporting.py +270 -0
- langfun/core/eval/v2/reporting_test.py +158 -0
- langfun/core/eval/v2/runners.py +488 -0
- langfun/core/eval/v2/runners_test.py +334 -0
- langfun/core/langfunc.py +4 -17
- langfun/core/langfunc_test.py +22 -6
- langfun/core/language_model.py +577 -39
- langfun/core/language_model_test.py +470 -56
- langfun/core/llms/__init__.py +87 -16
- langfun/core/llms/anthropic.py +312 -87
- langfun/core/llms/anthropic_test.py +71 -3
- langfun/core/llms/cache/base.py +21 -2
- langfun/core/llms/cache/in_memory.py +13 -0
- langfun/core/llms/cache/in_memory_test.py +53 -2
- langfun/core/llms/compositional.py +101 -0
- langfun/core/llms/compositional_test.py +73 -0
- langfun/core/llms/deepseek.py +117 -0
- langfun/core/llms/deepseek_test.py +61 -0
- langfun/core/llms/fake.py +11 -7
- langfun/core/llms/fake_test.py +14 -0
- langfun/core/llms/gemini.py +507 -0
- langfun/core/llms/gemini_test.py +195 -0
- langfun/core/llms/google_genai.py +62 -218
- langfun/core/llms/google_genai_test.py +9 -202
- langfun/core/llms/groq.py +160 -144
- langfun/core/llms/groq_test.py +31 -137
- langfun/core/llms/llama_cpp.py +15 -42
- langfun/core/llms/llama_cpp_test.py +4 -30
- langfun/core/llms/openai.py +395 -203
- langfun/core/llms/openai_compatible.py +179 -0
- langfun/core/llms/openai_compatible_test.py +495 -0
- langfun/core/llms/openai_test.py +30 -395
- langfun/core/llms/rest.py +113 -0
- langfun/core/llms/rest_test.py +111 -0
- langfun/core/llms/vertexai.py +192 -0
- langfun/core/llms/vertexai_test.py +52 -0
- langfun/core/logging.py +284 -0
- langfun/core/logging_test.py +125 -0
- langfun/core/message.py +319 -9
- langfun/core/message_test.py +190 -13
- langfun/core/modalities/__init__.py +6 -2
- langfun/core/modalities/audio.py +30 -0
- langfun/core/modalities/audio_test.py +63 -0
- langfun/core/modalities/image.py +39 -20
- langfun/core/modalities/image_test.py +52 -9
- langfun/core/modalities/mime.py +206 -29
- langfun/core/modalities/mime_test.py +90 -9
- langfun/core/modalities/ms_office.py +117 -0
- langfun/core/modalities/ms_office_test.py +389 -0
- langfun/core/modalities/pdf.py +22 -0
- langfun/core/modalities/pdf_test.py +57 -0
- langfun/core/modalities/video.py +9 -26
- langfun/core/modalities/video_test.py +3 -3
- langfun/core/modality.py +26 -3
- langfun/core/modality_test.py +2 -2
- langfun/core/sampling.py +11 -11
- langfun/core/structured/__init__.py +12 -16
- langfun/core/structured/completion.py +32 -5
- langfun/core/structured/completion_test.py +7 -6
- langfun/core/structured/description.py +2 -2
- langfun/core/structured/description_test.py +3 -3
- langfun/core/structured/function_generation.py +60 -27
- langfun/core/structured/function_generation_test.py +72 -2
- langfun/core/structured/mapping.py +97 -47
- langfun/core/structured/mapping_test.py +90 -2
- langfun/core/structured/parsing.py +33 -21
- langfun/core/structured/parsing_test.py +53 -9
- langfun/core/structured/querying.py +746 -0
- langfun/core/structured/{prompting_test.py → querying_test.py} +469 -51
- langfun/core/structured/schema.py +204 -97
- langfun/core/structured/schema_generation.py +1 -1
- langfun/core/structured/schema_test.py +130 -29
- langfun/core/structured/scoring.py +125 -19
- langfun/core/structured/scoring_test.py +30 -0
- langfun/core/structured/tokenization.py +64 -0
- langfun/core/structured/tokenization_test.py +48 -0
- langfun/core/template.py +115 -1
- langfun/core/template_test.py +71 -1
- langfun/core/templates/conversation.py +9 -0
- langfun/core/templates/conversation_test.py +4 -3
- langfun/core/templates/selfplay_test.py +10 -2
- langfun-0.1.2.dev202501140804.dist-info/METADATA +225 -0
- langfun-0.1.2.dev202501140804.dist-info/RECORD +153 -0
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/WHEEL +1 -1
- langfun/core/coding/python/errors.py +0 -108
- langfun/core/coding/python/errors_test.py +0 -99
- langfun/core/coding/python/permissions.py +0 -90
- langfun/core/coding/python/permissions_test.py +0 -86
- langfun/core/structured/prompting.py +0 -238
- langfun/core/text_formatting.py +0 -162
- langfun/core/text_formatting_test.py +0 -47
- langfun-0.0.2.dev20240429.dist-info/METADATA +0 -100
- langfun-0.0.2.dev20240429.dist-info/RECORD +0 -108
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/LICENSE +0 -0
- {langfun-0.0.2.dev20240429.dist-info → langfun-0.1.2.dev202501140804.dist-info}/top_level.txt +0 -0
langfun/core/message.py
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
"""Messages that are exchanged between users and agents."""
|
15
15
|
|
16
16
|
import contextlib
|
17
|
+
import functools
|
17
18
|
import io
|
18
19
|
from typing import Annotated, Any, Optional, Union
|
19
20
|
|
@@ -22,7 +23,11 @@ from langfun.core import natural_language
|
|
22
23
|
import pyglove as pg
|
23
24
|
|
24
25
|
|
25
|
-
class Message(
|
26
|
+
class Message(
|
27
|
+
natural_language.NaturalLanguageFormattable,
|
28
|
+
pg.Object,
|
29
|
+
pg.views.HtmlTreeView.Extension
|
30
|
+
):
|
26
31
|
"""Message.
|
27
32
|
|
28
33
|
``Message`` is the protocol for users and the system to interact with
|
@@ -144,7 +149,7 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
144
149
|
def from_value(cls, value: Union[str, 'Message']) -> 'Message':
|
145
150
|
"""Creates a message from a value or return value itself if a Message."""
|
146
151
|
if isinstance(value, modality.Modality):
|
147
|
-
return cls('
|
152
|
+
return cls('<<[[object]]>>', object=value)
|
148
153
|
if isinstance(value, Message):
|
149
154
|
return value
|
150
155
|
return cls(value)
|
@@ -276,6 +281,16 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
276
281
|
# API for supporting modalities.
|
277
282
|
#
|
278
283
|
|
284
|
+
@property
|
285
|
+
def text_with_modality_hash(self) -> str:
|
286
|
+
"""Returns text with modality object placeheld by their 8-byte MD5 hash."""
|
287
|
+
parts = [self.text]
|
288
|
+
for name, modality_obj in self.referred_modalities().items():
|
289
|
+
parts.append(
|
290
|
+
f'<{name}>{modality_obj.hash}</{name}>'
|
291
|
+
)
|
292
|
+
return ''.join(parts)
|
293
|
+
|
279
294
|
def get_modality(
|
280
295
|
self, var_name: str, default: Any = None, from_message_chain: bool = True
|
281
296
|
) -> modality.Modality | None:
|
@@ -304,21 +319,22 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
304
319
|
m.referred_name: m for m in chunks if isinstance(m, modality.Modality)
|
305
320
|
}
|
306
321
|
|
307
|
-
def chunk(self) -> list[str | modality.Modality]:
|
322
|
+
def chunk(self, text: str | None = None) -> list[str | modality.Modality]:
|
308
323
|
"""Chunk a message into a list of str or modality objects."""
|
309
324
|
chunks = []
|
310
325
|
|
311
326
|
def add_text_chunk(text_piece: str) -> None:
|
312
327
|
if text_piece:
|
313
328
|
chunks.append(text_piece)
|
329
|
+
if text is None:
|
330
|
+
text = self.text
|
314
331
|
|
315
|
-
text = self.text
|
316
332
|
chunk_start = 0
|
317
333
|
ref_end = 0
|
318
334
|
while chunk_start < len(text):
|
319
335
|
ref_start = text.find(modality.Modality.REF_START, ref_end)
|
320
336
|
if ref_start == -1:
|
321
|
-
add_text_chunk(text[chunk_start:].strip())
|
337
|
+
add_text_chunk(text[chunk_start:].strip(' '))
|
322
338
|
break
|
323
339
|
|
324
340
|
var_start = ref_start + len(modality.Modality.REF_START)
|
@@ -330,29 +346,31 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
330
346
|
var_name = text[var_start:ref_end].strip()
|
331
347
|
var_value = self.get_modality(var_name)
|
332
348
|
if var_value is not None:
|
333
|
-
add_text_chunk(text[chunk_start:ref_start].strip())
|
349
|
+
add_text_chunk(text[chunk_start:ref_start].strip(' '))
|
334
350
|
chunks.append(var_value)
|
335
351
|
chunk_start = ref_end + len(modality.Modality.REF_END)
|
336
352
|
return chunks
|
337
353
|
|
338
354
|
@classmethod
|
339
355
|
def from_chunks(
|
340
|
-
cls, chunks: list[str | modality.Modality], separator: str = '
|
356
|
+
cls, chunks: list[str | modality.Modality], separator: str = ' '
|
341
357
|
) -> 'Message':
|
342
358
|
"""Assembly a message from a list of string or modality objects."""
|
343
359
|
fused_text = io.StringIO()
|
344
360
|
ref_index = 0
|
345
361
|
metadata = dict()
|
346
|
-
|
362
|
+
last_char = None
|
347
363
|
for i, chunk in enumerate(chunks):
|
348
|
-
if i > 0:
|
364
|
+
if i > 0 and last_char not in ('\t', ' ', '\n'):
|
349
365
|
fused_text.write(separator)
|
350
366
|
if isinstance(chunk, str):
|
351
367
|
fused_text.write(chunk)
|
368
|
+
last_char = chunk[-1]
|
352
369
|
else:
|
353
370
|
assert isinstance(chunk, modality.Modality), chunk
|
354
371
|
var_name = f'obj{ref_index}'
|
355
372
|
fused_text.write(modality.Modality.text_marker(var_name))
|
373
|
+
last_char = modality.Modality.REF_END[-1]
|
356
374
|
# Make a reference if the chunk is already owned by another object
|
357
375
|
# to avoid copy.
|
358
376
|
metadata[var_name] = pg.maybe_ref(chunk)
|
@@ -391,6 +409,11 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
391
409
|
with pg.notify_on_change(False):
|
392
410
|
self.tags.append(tag)
|
393
411
|
|
412
|
+
def has_tag(self, tag: str | tuple[str, ...]) -> bool:
|
413
|
+
if isinstance(tag, str):
|
414
|
+
return tag in self.tags
|
415
|
+
return any(t in self.tags for t in tag)
|
416
|
+
|
394
417
|
#
|
395
418
|
# Message source chain.
|
396
419
|
#
|
@@ -488,6 +511,293 @@ class Message(natural_language.NaturalLanguageFormattable, pg.Object):
|
|
488
511
|
v = self.metadata[key]
|
489
512
|
return v.value if isinstance(v, pg.Ref) else v
|
490
513
|
|
514
|
+
def _html_tree_view_content(
|
515
|
+
self,
|
516
|
+
*,
|
517
|
+
view: pg.views.HtmlTreeView,
|
518
|
+
root_path: pg.KeyPath | None = None,
|
519
|
+
collapse_level: int | None = None,
|
520
|
+
extra_flags: dict[str, Any] | None = None,
|
521
|
+
**kwargs,
|
522
|
+
) -> pg.Html:
|
523
|
+
"""Returns the HTML representation of the message.
|
524
|
+
|
525
|
+
Args:
|
526
|
+
view: The HTML tree view.
|
527
|
+
root_path: The root path of the message.
|
528
|
+
collapse_level: The global collapse level.
|
529
|
+
extra_flags: Extra flags to control the rendering.
|
530
|
+
- source_tag: tags to filter source messages. If None, the entire
|
531
|
+
source chain will be included.
|
532
|
+
- include_message_metadata: Whether to include the metadata of the
|
533
|
+
message.
|
534
|
+
- collapse_modalities_in_text: Whether to collapse the modalities in the
|
535
|
+
message text.
|
536
|
+
- collapse_llm_usage: Whether to collapse the usage in the message.
|
537
|
+
- collapse_message_result_level: The level to collapse the result in the
|
538
|
+
message.
|
539
|
+
- collapse_message_metadata_level: The level to collapse the metadata in
|
540
|
+
the message.
|
541
|
+
- collapse_source_message_level: The level to collapse the source in the
|
542
|
+
message.
|
543
|
+
- collapse_level: The global collapse level.
|
544
|
+
**kwargs: Omitted keyword arguments.
|
545
|
+
|
546
|
+
Returns:
|
547
|
+
The HTML representation of the message content.
|
548
|
+
"""
|
549
|
+
extra_flags = extra_flags if extra_flags is not None else {}
|
550
|
+
|
551
|
+
include_message_metadata: bool = extra_flags.get(
|
552
|
+
'include_message_metadata', True
|
553
|
+
)
|
554
|
+
source_tag: str | tuple[str, ...] | None = extra_flags.get(
|
555
|
+
'source_tag', ('lm-input', 'lm-output')
|
556
|
+
)
|
557
|
+
collapse_modalities_in_text: bool = extra_flags.get(
|
558
|
+
'collapse_modalities_in_text', True
|
559
|
+
)
|
560
|
+
collapse_llm_usage: bool = extra_flags.get(
|
561
|
+
'collapse_llm_usage', False
|
562
|
+
)
|
563
|
+
collapse_message_result_level: int | None = extra_flags.get(
|
564
|
+
'collapse_message_result_level', 1
|
565
|
+
)
|
566
|
+
collapse_message_metadata_level: int | None = extra_flags.get(
|
567
|
+
'collapse_message_metadata_level', 1
|
568
|
+
)
|
569
|
+
collapse_source_message_level: int | None = extra_flags.get(
|
570
|
+
'collapse_source_message_level', 1
|
571
|
+
)
|
572
|
+
passthrough_kwargs = view.get_passthrough_kwargs(**kwargs)
|
573
|
+
def render_tags():
|
574
|
+
return pg.Html.element(
|
575
|
+
'div',
|
576
|
+
[pg.Html.element('span', [tag]) for tag in self.tags],
|
577
|
+
css_classes=['message-tags'],
|
578
|
+
)
|
579
|
+
|
580
|
+
def render_message_text():
|
581
|
+
maybe_reformatted = self.get('formatted_text')
|
582
|
+
referred_chunks = {}
|
583
|
+
s = pg.Html('<div class="message-text">')
|
584
|
+
for chunk in self.chunk(maybe_reformatted):
|
585
|
+
if isinstance(chunk, str):
|
586
|
+
s.write(s.escape(chunk))
|
587
|
+
else:
|
588
|
+
assert isinstance(chunk, modality.Modality), chunk
|
589
|
+
child_path = pg.KeyPath(['metadata', chunk.referred_name], root_path)
|
590
|
+
s.write(
|
591
|
+
pg.Html.element(
|
592
|
+
'div',
|
593
|
+
[
|
594
|
+
view.render(
|
595
|
+
chunk,
|
596
|
+
name=chunk.referred_name,
|
597
|
+
root_path=child_path,
|
598
|
+
collapse_level=(
|
599
|
+
0 if collapse_modalities_in_text else 1
|
600
|
+
),
|
601
|
+
extra_flags=dict(
|
602
|
+
display_modality_when_hover=True,
|
603
|
+
),
|
604
|
+
**passthrough_kwargs,
|
605
|
+
)
|
606
|
+
],
|
607
|
+
css_classes=['modality-in-text'],
|
608
|
+
)
|
609
|
+
)
|
610
|
+
referred_chunks[chunk.referred_name] = chunk
|
611
|
+
s.write('</div>')
|
612
|
+
return s
|
613
|
+
|
614
|
+
def render_result():
|
615
|
+
if 'result' not in self.metadata:
|
616
|
+
return None
|
617
|
+
child_path = pg.KeyPath(['metadata', 'result'], root_path)
|
618
|
+
return pg.Html.element(
|
619
|
+
'div',
|
620
|
+
[
|
621
|
+
view.render(
|
622
|
+
self.result,
|
623
|
+
name='result',
|
624
|
+
root_path=child_path,
|
625
|
+
collapse_level=view.get_collapse_level(
|
626
|
+
(collapse_level, -1),
|
627
|
+
collapse_message_result_level,
|
628
|
+
),
|
629
|
+
extra_flags=extra_flags,
|
630
|
+
**passthrough_kwargs,
|
631
|
+
)
|
632
|
+
],
|
633
|
+
css_classes=['message-result'],
|
634
|
+
)
|
635
|
+
|
636
|
+
def render_usage():
|
637
|
+
if 'usage' not in self.metadata:
|
638
|
+
return None
|
639
|
+
child_path = pg.KeyPath(['metadata', 'usage'], root_path)
|
640
|
+
return pg.Html.element(
|
641
|
+
'div',
|
642
|
+
[
|
643
|
+
view.render(
|
644
|
+
self.usage,
|
645
|
+
name='llm usage',
|
646
|
+
key_style='label',
|
647
|
+
root_path=child_path,
|
648
|
+
collapse_level=view.get_collapse_level(
|
649
|
+
(collapse_level, -1),
|
650
|
+
0 if collapse_llm_usage else 1,
|
651
|
+
),
|
652
|
+
extra_flags=extra_flags,
|
653
|
+
**view.get_passthrough_kwargs(
|
654
|
+
remove=['key_style'], **kwargs
|
655
|
+
),
|
656
|
+
)
|
657
|
+
],
|
658
|
+
css_classes=['message-usage'],
|
659
|
+
)
|
660
|
+
|
661
|
+
def render_source_message():
|
662
|
+
source = self.source
|
663
|
+
while (source is not None
|
664
|
+
and source_tag is not None
|
665
|
+
and not source.has_tag(source_tag)):
|
666
|
+
source = source.source
|
667
|
+
if source is not None:
|
668
|
+
child_path = pg.KeyPath('source', root_path)
|
669
|
+
child_extra_flags = extra_flags.copy()
|
670
|
+
child_extra_flags['collapse_source_message_level'] = (
|
671
|
+
view.get_collapse_level(
|
672
|
+
(collapse_source_message_level, -1), 0,
|
673
|
+
)
|
674
|
+
)
|
675
|
+
return view.render(
|
676
|
+
self.source,
|
677
|
+
name='source',
|
678
|
+
root_path=child_path,
|
679
|
+
collapse_level=view.get_collapse_level(
|
680
|
+
(collapse_level, -1),
|
681
|
+
collapse_source_message_level,
|
682
|
+
),
|
683
|
+
extra_flags=child_extra_flags,
|
684
|
+
**passthrough_kwargs,
|
685
|
+
)
|
686
|
+
return None
|
687
|
+
|
688
|
+
def render_metadata():
|
689
|
+
if not include_message_metadata:
|
690
|
+
return None
|
691
|
+
child_path = pg.KeyPath('metadata', root_path)
|
692
|
+
return pg.Html.element(
|
693
|
+
'div',
|
694
|
+
[
|
695
|
+
view.render(
|
696
|
+
self.metadata,
|
697
|
+
css_classes=['message-metadata'],
|
698
|
+
exclude_keys=['usage', 'result'],
|
699
|
+
name='metadata',
|
700
|
+
root_path=child_path,
|
701
|
+
collapse_level=view.get_collapse_level(
|
702
|
+
(collapse_level, -1),
|
703
|
+
collapse_message_metadata_level,
|
704
|
+
),
|
705
|
+
**view.get_passthrough_kwargs(
|
706
|
+
remove=['exclude_keys'], **kwargs
|
707
|
+
),
|
708
|
+
)
|
709
|
+
],
|
710
|
+
css_classes=['message-metadata'],
|
711
|
+
)
|
712
|
+
|
713
|
+
return pg.Html.element(
|
714
|
+
'div',
|
715
|
+
[
|
716
|
+
render_tags(),
|
717
|
+
render_message_text(),
|
718
|
+
render_result(),
|
719
|
+
render_usage(),
|
720
|
+
render_metadata(),
|
721
|
+
render_source_message(),
|
722
|
+
],
|
723
|
+
css_classes=['complex_value'],
|
724
|
+
)
|
725
|
+
|
726
|
+
@classmethod
|
727
|
+
@functools.cache
|
728
|
+
def _html_tree_view_config(cls) -> dict[str, Any]:
|
729
|
+
return pg.views.HtmlTreeView.get_kwargs(
|
730
|
+
super()._html_tree_view_config(),
|
731
|
+
dict(
|
732
|
+
css_classes=['lf-message'],
|
733
|
+
)
|
734
|
+
)
|
735
|
+
|
736
|
+
@classmethod
|
737
|
+
@functools.cache
|
738
|
+
def _html_tree_view_css_styles(cls) -> list[str]:
|
739
|
+
return super()._html_tree_view_css_styles() + [
|
740
|
+
"""
|
741
|
+
/* Langfun Message styles.*/
|
742
|
+
[class^="message-"] > details {
|
743
|
+
margin: 0px 0px 5px 0px;
|
744
|
+
border: 1px solid #EEE;
|
745
|
+
}
|
746
|
+
.lf-message.summary-title::after {
|
747
|
+
content: ' 💬';
|
748
|
+
}
|
749
|
+
details.pyglove.ai-message {
|
750
|
+
border: 1px solid blue;
|
751
|
+
color: blue;
|
752
|
+
}
|
753
|
+
details.pyglove.user-message {
|
754
|
+
border: 1px solid green;
|
755
|
+
color: green;
|
756
|
+
}
|
757
|
+
.message-tags {
|
758
|
+
margin: 5px 0px 5px 0px;
|
759
|
+
font-size: .8em;
|
760
|
+
}
|
761
|
+
.message-tags > span {
|
762
|
+
border-radius: 5px;
|
763
|
+
background-color: #CCC;
|
764
|
+
padding: 3px;
|
765
|
+
margin: 0px 2px 0px 2px;
|
766
|
+
color: white;
|
767
|
+
}
|
768
|
+
.message-text {
|
769
|
+
padding: 20px;
|
770
|
+
margin: 10px 5px 10px 5px;
|
771
|
+
font-style: italic;
|
772
|
+
white-space: pre-wrap;
|
773
|
+
border: 1px solid #EEE;
|
774
|
+
border-radius: 5px;
|
775
|
+
background-color: #EEE;
|
776
|
+
}
|
777
|
+
.modality-in-text {
|
778
|
+
display: inline-block;
|
779
|
+
}
|
780
|
+
.modality-in-text > details.pyglove {
|
781
|
+
display: inline-block;
|
782
|
+
font-size: 0.8em;
|
783
|
+
border: 0;
|
784
|
+
background-color: #A6F1A6;
|
785
|
+
margin: 0px 5px 0px 5px;
|
786
|
+
}
|
787
|
+
.message-result {
|
788
|
+
color: dodgerblue;
|
789
|
+
}
|
790
|
+
.message-usage {
|
791
|
+
color: orange;
|
792
|
+
}
|
793
|
+
.message-usage .object-key.str {
|
794
|
+
border: 1px solid orange;
|
795
|
+
background-color: orange;
|
796
|
+
color: white;
|
797
|
+
}
|
798
|
+
"""
|
799
|
+
]
|
800
|
+
|
491
801
|
|
492
802
|
#
|
493
803
|
# Messages of different roles.
|