langfun 0.1.2.dev202510240805__tar.gz → 0.1.2.dev202510250803__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 langfun might be problematic. Click here for more details.
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/PKG-INFO +1 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/concurrent_test.py +1 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/conversion/anthropic_test.py +8 -6
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/conversion/gemini_test.py +12 -9
- langfun-0.1.2.dev202510250803/langfun/core/data/conversion/openai.py +235 -0
- langfun-0.1.2.dev202510250803/langfun/core/data/conversion/openai_test.py +320 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/progress_tracking_test.py +3 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/langfunc_test.py +4 -2
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/language_model.py +6 -6
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/language_model_test.py +9 -3
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/__init__.py +2 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/cache/base.py +3 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/cache/in_memory_test.py +14 -4
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/deepseek.py +1 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/groq.py +1 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/llama_cpp.py +1 -1
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/openai.py +7 -2
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/openai_compatible.py +134 -27
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/openai_compatible_test.py +207 -20
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/openai_test.py +0 -2
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/vertexai.py +2 -2
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/message.py +78 -44
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/message_test.py +56 -81
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/__init__.py +8 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/mime.py +9 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modality.py +104 -27
- langfun-0.1.2.dev202510250803/langfun/core/modality_test.py +117 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/sampling_test.py +20 -4
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/completion.py +2 -7
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/completion_test.py +23 -43
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/mapping.py +4 -13
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/querying.py +13 -11
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/querying_test.py +65 -29
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/template.py +39 -13
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/template_test.py +83 -17
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/metric_writer_test.py +3 -3
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/load_balancers_test.py +2 -2
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun.egg-info/PKG-INFO +1 -1
- langfun-0.1.2.dev202510240805/langfun/core/data/conversion/openai.py +0 -131
- langfun-0.1.2.dev202510240805/langfun/core/data/conversion/openai_test.py +0 -176
- langfun-0.1.2.dev202510240805/langfun/core/modality_test.py +0 -87
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/LICENSE +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/README.md +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/bounding_box_parser.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/bounding_box_parser_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/drawing.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/drawing_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/location.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/assistant/capabilities/gui/location_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/agentic/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/agentic/action.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/agentic/action_eval.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/agentic/action_eval_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/agentic/action_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/async_support.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/async_support_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/correction.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/correction_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/execution.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/execution_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/generation.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/generation_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/parsing.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/parsing_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/sandboxing.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/coding/python/sandboxing_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/component.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/component_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/concurrent.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/console.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/console_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/conversion/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/conversion/anthropic.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/data/conversion/gemini.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/base.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/base_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/matching.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/matching_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/patching.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/patching_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/scoring.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/scoring_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/checkpointing.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/checkpointing_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/eval_test_helper.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/evaluation.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/evaluation_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/example.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/example_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/experiment.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/experiment_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/metric_values.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/metric_values_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/metrics.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/metrics_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/progress.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/progress_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/progress_tracking.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/reporting.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/reporting_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/runners.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/eval/v2/runners_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/langfunc.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/anthropic.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/anthropic_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/azure_openai.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/azure_openai_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/cache/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/cache/in_memory.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/compositional.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/compositional_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/deepseek_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/fake.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/fake_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/gemini.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/gemini_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/google_genai.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/google_genai_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/groq_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/llama_cpp_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/rest.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/rest_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/llms/vertexai_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/logging.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/logging_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/client.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/client_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/session.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/testing/simple_mcp_client.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/testing/simple_mcp_server.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/mcp/tool.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/memories/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/memories/conversation_history.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/memories/conversation_history_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/memory.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/audio.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/audio_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/image.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/image_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/mime_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/pdf.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/pdf_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/video.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/modalities/video_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/natural_language.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/natural_language_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/sampling.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/description.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/description_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/function_generation.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/function_generation_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/mapping_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/parsing.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/parsing_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/schema.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/schema_generation.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/schema_generation_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/schema_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/scoring.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/scoring_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/tokenization.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/structured/tokenization_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/subscription.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/subscription_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/completion.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/completion_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/conversation.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/conversation_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/demonstration.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/demonstration_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/selfplay.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/templates/selfplay_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/base_environment.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/base_feature.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/base_sandbox.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/base_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/__init__.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/base.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/event_logger.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/event_logger_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/event_handlers/metric_writer.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/interface.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/interface_test.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/load_balancers.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/env/test_utils.py +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun.egg-info/SOURCES.txt +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun.egg-info/dependency_links.txt +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun.egg-info/requires.txt +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun.egg-info/top_level.txt +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/setup.cfg +0 -0
- {langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/setup.py +0 -0
|
@@ -253,14 +253,16 @@ class AnthropicConversionTest(unittest.TestCase):
|
|
|
253
253
|
)
|
|
254
254
|
self.assertEqual(
|
|
255
255
|
m.text,
|
|
256
|
-
'What are the common words from <<[[
|
|
256
|
+
'What are the common words from <<[[image:dc6e1e43]]>> and'
|
|
257
|
+
' <<[[pdf:5daf5f31]]>> ?'
|
|
257
258
|
)
|
|
258
|
-
|
|
259
|
-
self.
|
|
260
|
-
self.assertEqual(
|
|
259
|
+
modalities = m.modalities()
|
|
260
|
+
self.assertIsInstance(modalities[0], lf_modalities.Image)
|
|
261
|
+
self.assertEqual(modalities[0].mime_type, 'image/png')
|
|
262
|
+
self.assertEqual(modalities[0].content, image_content)
|
|
261
263
|
|
|
262
|
-
self.assertIsInstance(
|
|
263
|
-
self.assertEqual(
|
|
264
|
+
self.assertIsInstance(modalities[1], lf_modalities.PDF)
|
|
265
|
+
self.assertEqual(modalities[1].content, pdf_content)
|
|
264
266
|
|
|
265
267
|
|
|
266
268
|
if __name__ == '__main__':
|
|
@@ -225,19 +225,22 @@ class GeminiConversionTest(unittest.TestCase):
|
|
|
225
225
|
self.assertEqual(
|
|
226
226
|
m.text,
|
|
227
227
|
(
|
|
228
|
-
'What are the common words from <<[[
|
|
229
|
-
'and <<[[
|
|
228
|
+
'What are the common words from <<[[image:dc6e1e43]]>> , '
|
|
229
|
+
'<<[[pdf:4dc12e93]]>> and <<[[video:7e169565]]>> ?'
|
|
230
230
|
)
|
|
231
231
|
)
|
|
232
|
-
self.assertIsInstance(m.
|
|
233
|
-
self.assertEqual(m.
|
|
234
|
-
self.assertEqual(m.
|
|
232
|
+
self.assertIsInstance(m.modalities()[0], lf_modalities.Image)
|
|
233
|
+
self.assertEqual(m.modalities()[0].mime_type, 'image/png')
|
|
234
|
+
self.assertEqual(m.modalities()[0].to_bytes(), image_content)
|
|
235
235
|
|
|
236
|
-
self.assertIsInstance(m.
|
|
237
|
-
self.assertEqual(m.
|
|
236
|
+
self.assertIsInstance(m.modalities()[1], lf_modalities.PDF)
|
|
237
|
+
self.assertEqual(m.modalities()[1].uri, 'https://my.pdf')
|
|
238
238
|
|
|
239
|
-
self.assertIsInstance(m.
|
|
240
|
-
self.assertEqual(
|
|
239
|
+
self.assertIsInstance(m.modalities()[2], lf_modalities.Video)
|
|
240
|
+
self.assertEqual(
|
|
241
|
+
m.modalities()[2].uri,
|
|
242
|
+
'https://www.youtube.com/watch?v=abcd'
|
|
243
|
+
)
|
|
241
244
|
|
|
242
245
|
|
|
243
246
|
if __name__ == '__main__':
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Copyright 2025 The Langfun Authors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""OpenAI API message conversion."""
|
|
15
|
+
|
|
16
|
+
from typing import Annotated, Any, Callable
|
|
17
|
+
|
|
18
|
+
import langfun.core as lf
|
|
19
|
+
from langfun.core import modalities as lf_modalities
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OpenAIChatCompletionAPIMessageConverter(lf.MessageConverter):
|
|
23
|
+
"""Converter to OpenAI ChatCompletion API.
|
|
24
|
+
|
|
25
|
+
See https://platform.openai.com/docs/api-reference/chat
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
FORMAT_ID = 'openai_chat_completion_api'
|
|
29
|
+
|
|
30
|
+
chunk_preprocessor: Annotated[
|
|
31
|
+
Callable[[str | lf.Modality], Any] | None,
|
|
32
|
+
(
|
|
33
|
+
'Chunk preprocessor for Langfun chunk to OpenAI chunk conversion. '
|
|
34
|
+
'It will be applied before each Langfun chunk is converted. '
|
|
35
|
+
'If returns None, the chunk will be skipped.'
|
|
36
|
+
)
|
|
37
|
+
] = None
|
|
38
|
+
|
|
39
|
+
def to_value(self, message: lf.Message) -> dict[str, Any]:
|
|
40
|
+
"""Converts a Langfun message to OpenAI API."""
|
|
41
|
+
parts = []
|
|
42
|
+
for chunk in message.chunk():
|
|
43
|
+
if self.chunk_preprocessor is not None:
|
|
44
|
+
chunk = self.chunk_preprocessor(chunk)
|
|
45
|
+
if chunk is None:
|
|
46
|
+
continue
|
|
47
|
+
parts.append(self.chunk_to_json(type(message), chunk))
|
|
48
|
+
return dict(
|
|
49
|
+
role=self.get_role(message),
|
|
50
|
+
content=parts,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def chunk_to_json(
|
|
54
|
+
self,
|
|
55
|
+
message_cls: type[lf.Message],
|
|
56
|
+
chunk: str | lf.Modality
|
|
57
|
+
) -> dict[str, Any]:
|
|
58
|
+
"""Converts a Langfun chunk to OpenAI chunk."""
|
|
59
|
+
del message_cls
|
|
60
|
+
if isinstance(chunk, str):
|
|
61
|
+
return dict(type='text', text=chunk)
|
|
62
|
+
elif isinstance(chunk, lf_modalities.Image):
|
|
63
|
+
return dict(
|
|
64
|
+
type='image_url', image_url=dict(url=chunk.embeddable_uri)
|
|
65
|
+
)
|
|
66
|
+
# TODO(daiyip): Support audio_input.
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f'Unsupported content type: {chunk!r}.')
|
|
69
|
+
|
|
70
|
+
def get_role(self, message: lf.Message) -> str:
|
|
71
|
+
"""Returns the role of the message."""
|
|
72
|
+
if isinstance(message, lf.SystemMessage):
|
|
73
|
+
return 'system'
|
|
74
|
+
elif isinstance(message, lf.UserMessage):
|
|
75
|
+
return 'user'
|
|
76
|
+
elif isinstance(message, lf.AIMessage):
|
|
77
|
+
return 'assistant'
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError(f'Unsupported message type: {message!r}.')
|
|
80
|
+
|
|
81
|
+
def get_message_cls(self, role: str) -> type[lf.Message]:
|
|
82
|
+
"""Returns the message class of the message."""
|
|
83
|
+
match role:
|
|
84
|
+
case 'system':
|
|
85
|
+
return lf.SystemMessage
|
|
86
|
+
case 'user':
|
|
87
|
+
return lf.UserMessage
|
|
88
|
+
case 'assistant':
|
|
89
|
+
return lf.AIMessage
|
|
90
|
+
case _:
|
|
91
|
+
raise ValueError(f'Unsupported role: {role!r}.')
|
|
92
|
+
|
|
93
|
+
def from_value(self, value: dict[str, Any]) -> lf.Message:
|
|
94
|
+
"""Returns a Langfun message from OpenAI message."""
|
|
95
|
+
message_cls = self.get_message_cls(
|
|
96
|
+
self._safe_read(value, 'role', default='assistant')
|
|
97
|
+
)
|
|
98
|
+
content = self._safe_read(value, 'content')
|
|
99
|
+
if isinstance(content, str):
|
|
100
|
+
return message_cls(content)
|
|
101
|
+
|
|
102
|
+
assert isinstance(content, list)
|
|
103
|
+
chunks = []
|
|
104
|
+
for item in content:
|
|
105
|
+
chunks.append(self.json_to_chunk(item))
|
|
106
|
+
return message_cls.from_chunks(chunks)
|
|
107
|
+
|
|
108
|
+
def json_to_chunk(self, json: dict[str, Any]) -> str | lf.Modality:
|
|
109
|
+
"""Returns a Langfun chunk from OpenAI chunk JSON."""
|
|
110
|
+
t = self._safe_read(json, 'type')
|
|
111
|
+
if t == 'text':
|
|
112
|
+
return self._safe_read(json, 'text')
|
|
113
|
+
elif t == 'image_url':
|
|
114
|
+
return lf_modalities.Image.from_uri(
|
|
115
|
+
self._safe_read(self._safe_read(json, 'image_url'), 'url')
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
raise ValueError(f'Unsupported content type: {json!r}.')
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _as_openai_chat_completion_api_format(
|
|
122
|
+
self,
|
|
123
|
+
chunk_preprocessor: Callable[[str | lf.Modality], Any] | None = None,
|
|
124
|
+
**kwargs
|
|
125
|
+
) -> dict[str, Any]:
|
|
126
|
+
"""Returns an OpenAI format message."""
|
|
127
|
+
return OpenAIChatCompletionAPIMessageConverter(
|
|
128
|
+
chunk_preprocessor=chunk_preprocessor, **kwargs
|
|
129
|
+
).to_value(self)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def _from_openai_chat_completion_api_format(
|
|
134
|
+
cls,
|
|
135
|
+
openai_message: dict[str, Any],
|
|
136
|
+
**kwargs
|
|
137
|
+
) -> lf.Message:
|
|
138
|
+
"""Creates a Langfun message from the OpenAI format message."""
|
|
139
|
+
del cls
|
|
140
|
+
return OpenAIChatCompletionAPIMessageConverter(
|
|
141
|
+
**kwargs
|
|
142
|
+
).from_value(openai_message)
|
|
143
|
+
|
|
144
|
+
# Set shortcut methods in lf.Message.
|
|
145
|
+
lf.Message.as_openai_chat_completion_api_format = (
|
|
146
|
+
_as_openai_chat_completion_api_format
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
lf.Message.from_openai_chat_completion_api_format = (
|
|
150
|
+
_from_openai_chat_completion_api_format
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
#
|
|
155
|
+
# OpenAI Responses API message converter.
|
|
156
|
+
#
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class OpenAIResponsesAPIMessageConverter(
|
|
160
|
+
OpenAIChatCompletionAPIMessageConverter
|
|
161
|
+
):
|
|
162
|
+
"""Converter to OpenAI Responses API.
|
|
163
|
+
|
|
164
|
+
See https://platform.openai.com/docs/api-reference/responses/create
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
FORMAT_ID = 'openai_responses_api'
|
|
168
|
+
|
|
169
|
+
def to_value(self, message: lf.Message) -> dict[str, Any]:
|
|
170
|
+
"""Converts a Langfun message to OpenAI API."""
|
|
171
|
+
message_json = super().to_value(message)
|
|
172
|
+
message_json['type'] = 'message'
|
|
173
|
+
return message_json
|
|
174
|
+
|
|
175
|
+
def chunk_to_json(
|
|
176
|
+
self,
|
|
177
|
+
message_cls: type[lf.Message],
|
|
178
|
+
chunk: str | lf.Modality
|
|
179
|
+
) -> dict[str, Any]:
|
|
180
|
+
"""Converts a Langfun chunk to OpenAI chunk."""
|
|
181
|
+
source = 'output' if issubclass(message_cls, lf.AIMessage) else 'input'
|
|
182
|
+
|
|
183
|
+
if isinstance(chunk, str):
|
|
184
|
+
return dict(type=f'{source}_text', text=chunk)
|
|
185
|
+
elif isinstance(chunk, lf_modalities.Image):
|
|
186
|
+
return dict(
|
|
187
|
+
type=f'{source}_image', image_url=chunk.embeddable_uri
|
|
188
|
+
)
|
|
189
|
+
# TODO(daiyip): Support audio_input.
|
|
190
|
+
else:
|
|
191
|
+
raise ValueError(f'Unsupported content type: {chunk!r}.')
|
|
192
|
+
|
|
193
|
+
def json_to_chunk(self, json: dict[str, Any]) -> str | lf.Modality:
|
|
194
|
+
"""Returns a Langfun chunk from OpenAI chunk JSON."""
|
|
195
|
+
t = self._safe_read(json, 'type')
|
|
196
|
+
if t in ('input_text', 'output_text'):
|
|
197
|
+
return self._safe_read(json, 'text')
|
|
198
|
+
elif t in ('input_image', 'output_image'):
|
|
199
|
+
return lf_modalities.Image.from_uri(self._safe_read(json, 'image_url'))
|
|
200
|
+
else:
|
|
201
|
+
raise ValueError(f'Unsupported content type: {json!r}.')
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _as_openai_responses_api_format(
|
|
205
|
+
self,
|
|
206
|
+
chunk_preprocessor: Callable[[str | lf.Modality], Any] | None = None,
|
|
207
|
+
**kwargs
|
|
208
|
+
) -> dict[str, Any]:
|
|
209
|
+
"""Returns an OpenAI format message."""
|
|
210
|
+
return OpenAIResponsesAPIMessageConverter(
|
|
211
|
+
chunk_preprocessor=chunk_preprocessor, **kwargs
|
|
212
|
+
).to_value(self)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@classmethod
|
|
216
|
+
def _from_openai_responses_api_format(
|
|
217
|
+
cls,
|
|
218
|
+
openai_message: dict[str, Any],
|
|
219
|
+
**kwargs
|
|
220
|
+
) -> lf.Message:
|
|
221
|
+
"""Creates a Langfun message from the OpenAI format message."""
|
|
222
|
+
del cls
|
|
223
|
+
return OpenAIResponsesAPIMessageConverter(
|
|
224
|
+
**kwargs
|
|
225
|
+
).from_value(openai_message)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
# Set shortcut methods in lf.Message.
|
|
229
|
+
lf.Message.as_openai_responses_api_format = (
|
|
230
|
+
_as_openai_responses_api_format
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
lf.Message.from_openai_responses_api_format = (
|
|
234
|
+
_from_openai_responses_api_format
|
|
235
|
+
)
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Copyright 2025 The Langfun Authors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import base64
|
|
15
|
+
import unittest
|
|
16
|
+
import langfun.core as lf
|
|
17
|
+
from langfun.core import modalities as lf_modalities
|
|
18
|
+
from langfun.core.data.conversion import openai # pylint: disable=unused-import
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
image_content = (
|
|
22
|
+
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x04'
|
|
23
|
+
b'\x03\x00\x00\x00\x12Y \xcb\x00\x00\x00\x18PLTE\x00\x00'
|
|
24
|
+
b'\x00fff_chaag_cg_ch^ci_ciC\xedb\x94\x00\x00\x00\x08tRNS'
|
|
25
|
+
b'\x00\n\x9f*\xd4\xff_\xf4\xe4\x8b\xf3a\x00\x00\x00>IDATx'
|
|
26
|
+
b'\x01c \x05\x08)"\xd8\xcc\xae!\x06pNz\x88k\x19\\Q\xa8"\x10'
|
|
27
|
+
b'\xc1\x14\x95\x01%\xc1\n\xa143Ta\xa8"D-\x84\x03QM\x98\xc3'
|
|
28
|
+
b'\x1a\x1a\x1a@5\x0e\x04\xa0q\x88\x05\x00\x07\xf8\x18\xf9'
|
|
29
|
+
b'\xdao\xd0|\x00\x00\x00\x00IEND\xaeB`\x82'
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class OpenAIChatCompletionAPIConverterTest(unittest.TestCase):
|
|
34
|
+
|
|
35
|
+
def test_as_format_with_role(self):
|
|
36
|
+
self.assertEqual(
|
|
37
|
+
lf.UserMessage('hi').as_format('openai_chat_completion_api'),
|
|
38
|
+
{
|
|
39
|
+
'role': 'user',
|
|
40
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
self.assertEqual(
|
|
44
|
+
lf.AIMessage('hi').as_format('openai_chat_completion_api'),
|
|
45
|
+
{
|
|
46
|
+
'role': 'assistant',
|
|
47
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
self.assertEqual(
|
|
51
|
+
lf.SystemMessage('hi').as_format('openai_chat_completion_api'),
|
|
52
|
+
{
|
|
53
|
+
'role': 'system',
|
|
54
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def test_as_format_with_image(self):
|
|
59
|
+
self.assertEqual(
|
|
60
|
+
lf.Template(
|
|
61
|
+
'What is this {{image}}?',
|
|
62
|
+
image=lf_modalities.Image.from_bytes(image_content)
|
|
63
|
+
).render().as_format('openai_chat_completion_api'),
|
|
64
|
+
{
|
|
65
|
+
'role': 'user',
|
|
66
|
+
'content': [
|
|
67
|
+
{
|
|
68
|
+
'type': 'text',
|
|
69
|
+
'text': 'What is this'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
'type': 'image_url',
|
|
73
|
+
'image_url': {
|
|
74
|
+
'url': (
|
|
75
|
+
'data:image/png;base64,'
|
|
76
|
+
+ base64.b64encode(image_content).decode('utf-8')
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
'type': 'text',
|
|
82
|
+
'text': '?'
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def test_as_format_with_chunk_preprocessor(self):
|
|
89
|
+
self.assertEqual(
|
|
90
|
+
lf.Template(
|
|
91
|
+
'What is this {{image}}?',
|
|
92
|
+
image=lf_modalities.Image.from_bytes(image_content)
|
|
93
|
+
).render().as_openai_chat_completion_api_format(
|
|
94
|
+
chunk_preprocessor=lambda x: x if isinstance(x, str) else None
|
|
95
|
+
),
|
|
96
|
+
{
|
|
97
|
+
'role': 'user',
|
|
98
|
+
'content': [
|
|
99
|
+
{
|
|
100
|
+
'type': 'text',
|
|
101
|
+
'text': 'What is this'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
'type': 'text',
|
|
105
|
+
'text': '?'
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def test_from_value_with_simple_text(self):
|
|
112
|
+
self.assertEqual(
|
|
113
|
+
lf.Message.from_value(
|
|
114
|
+
{
|
|
115
|
+
'content': 'this is a text',
|
|
116
|
+
},
|
|
117
|
+
format='openai_chat_completion_api',
|
|
118
|
+
),
|
|
119
|
+
lf.AIMessage('this is a text'),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def test_from_value_with_role(self):
|
|
123
|
+
self.assertEqual(
|
|
124
|
+
lf.Message.from_value(
|
|
125
|
+
{
|
|
126
|
+
'role': 'user',
|
|
127
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
128
|
+
},
|
|
129
|
+
format='openai_chat_completion_api',
|
|
130
|
+
),
|
|
131
|
+
lf.UserMessage('hi'),
|
|
132
|
+
)
|
|
133
|
+
self.assertEqual(
|
|
134
|
+
lf.Message.from_value(
|
|
135
|
+
{
|
|
136
|
+
'role': 'assistant',
|
|
137
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
138
|
+
},
|
|
139
|
+
format='openai_chat_completion_api',
|
|
140
|
+
),
|
|
141
|
+
lf.AIMessage('hi'),
|
|
142
|
+
)
|
|
143
|
+
self.assertEqual(
|
|
144
|
+
lf.Message.from_value(
|
|
145
|
+
{
|
|
146
|
+
'role': 'system',
|
|
147
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
148
|
+
},
|
|
149
|
+
format='openai_chat_completion_api',
|
|
150
|
+
),
|
|
151
|
+
lf.SystemMessage('hi'),
|
|
152
|
+
)
|
|
153
|
+
with self.assertRaisesRegex(ValueError, 'Unsupported role: .*'):
|
|
154
|
+
lf.Message.from_value(
|
|
155
|
+
{
|
|
156
|
+
'role': 'function',
|
|
157
|
+
'content': [{'type': 'text', 'text': 'hi'}],
|
|
158
|
+
},
|
|
159
|
+
format='openai_chat_completion_api',
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def test_from_value_with_image(self):
|
|
163
|
+
image = lf_modalities.Image.from_bytes(image_content)
|
|
164
|
+
m = lf.Message.from_openai_chat_completion_api_format(
|
|
165
|
+
lf.Template(
|
|
166
|
+
'What is this {{image}}?',
|
|
167
|
+
image=image
|
|
168
|
+
).render().as_format('openai_chat_completion_api'),
|
|
169
|
+
)
|
|
170
|
+
self.assertEqual(m.text, f'What is this <<[[{image.id}]]>> ?')
|
|
171
|
+
self.assertIsInstance(m.images[0], lf_modalities.Image)
|
|
172
|
+
self.assertEqual(m.images[0].mime_type, 'image/png')
|
|
173
|
+
self.assertEqual(m.images[0].to_bytes(), image_content)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class OpenAIResponsesAPIMessageConverterTest(unittest.TestCase):
|
|
177
|
+
|
|
178
|
+
def test_as_format_with_role(self):
|
|
179
|
+
self.assertEqual(
|
|
180
|
+
lf.UserMessage('hi').as_format('openai_responses_api'),
|
|
181
|
+
{
|
|
182
|
+
'type': 'message',
|
|
183
|
+
'role': 'user',
|
|
184
|
+
'content': [{'type': 'input_text', 'text': 'hi'}],
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
self.assertEqual(
|
|
188
|
+
lf.AIMessage('hi').as_format('openai_responses_api'),
|
|
189
|
+
{
|
|
190
|
+
'type': 'message',
|
|
191
|
+
'role': 'assistant',
|
|
192
|
+
'content': [{'type': 'output_text', 'text': 'hi'}],
|
|
193
|
+
},
|
|
194
|
+
)
|
|
195
|
+
self.assertEqual(
|
|
196
|
+
lf.SystemMessage('hi').as_format('openai_responses_api'),
|
|
197
|
+
{
|
|
198
|
+
'type': 'message',
|
|
199
|
+
'role': 'system',
|
|
200
|
+
'content': [{'type': 'input_text', 'text': 'hi'}],
|
|
201
|
+
},
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def test_as_format_with_image(self):
|
|
205
|
+
self.assertEqual(
|
|
206
|
+
lf.Template(
|
|
207
|
+
'What is this {{image}}?',
|
|
208
|
+
image=lf_modalities.Image.from_bytes(image_content)
|
|
209
|
+
).render().as_format('openai_responses_api'),
|
|
210
|
+
{
|
|
211
|
+
'type': 'message',
|
|
212
|
+
'role': 'user',
|
|
213
|
+
'content': [
|
|
214
|
+
{
|
|
215
|
+
'type': 'input_text',
|
|
216
|
+
'text': 'What is this'
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
'type': 'input_image',
|
|
220
|
+
'image_url': (
|
|
221
|
+
'data:image/png;base64,'
|
|
222
|
+
+ base64.b64encode(image_content).decode('utf-8')
|
|
223
|
+
)
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
'type': 'input_text',
|
|
227
|
+
'text': '?'
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def test_as_format_with_chunk_preprocessor(self):
|
|
234
|
+
self.assertEqual(
|
|
235
|
+
lf.Template(
|
|
236
|
+
'What is this {{image}}?',
|
|
237
|
+
image=lf_modalities.Image.from_bytes(image_content)
|
|
238
|
+
).render().as_openai_responses_api_format(
|
|
239
|
+
chunk_preprocessor=lambda x: x if isinstance(x, str) else None
|
|
240
|
+
),
|
|
241
|
+
{
|
|
242
|
+
'type': 'message',
|
|
243
|
+
'role': 'user',
|
|
244
|
+
'content': [
|
|
245
|
+
{
|
|
246
|
+
'type': 'input_text',
|
|
247
|
+
'text': 'What is this'
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
'type': 'input_text',
|
|
251
|
+
'text': '?'
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
def test_from_value_with_simple_text(self):
|
|
258
|
+
self.assertEqual(
|
|
259
|
+
lf.Message.from_value(
|
|
260
|
+
{
|
|
261
|
+
'content': 'this is a text',
|
|
262
|
+
},
|
|
263
|
+
format='openai_responses_api',
|
|
264
|
+
),
|
|
265
|
+
lf.AIMessage('this is a text'),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def test_from_value_with_role(self):
|
|
269
|
+
self.assertEqual(
|
|
270
|
+
lf.Message.from_value(
|
|
271
|
+
{
|
|
272
|
+
'role': 'user',
|
|
273
|
+
'content': [{'type': 'input_text', 'text': 'hi'}],
|
|
274
|
+
},
|
|
275
|
+
format='openai_responses_api',
|
|
276
|
+
),
|
|
277
|
+
lf.UserMessage('hi'),
|
|
278
|
+
)
|
|
279
|
+
self.assertEqual(
|
|
280
|
+
lf.Message.from_value(
|
|
281
|
+
{
|
|
282
|
+
'role': 'assistant',
|
|
283
|
+
'content': [{'type': 'output_text', 'text': 'hi'}],
|
|
284
|
+
},
|
|
285
|
+
format='openai_responses_api',
|
|
286
|
+
),
|
|
287
|
+
lf.AIMessage('hi'),
|
|
288
|
+
)
|
|
289
|
+
self.assertEqual(
|
|
290
|
+
lf.Message.from_value(
|
|
291
|
+
{
|
|
292
|
+
'role': 'system',
|
|
293
|
+
'content': [{'type': 'input_text', 'text': 'hi'}],
|
|
294
|
+
},
|
|
295
|
+
format='openai_responses_api',
|
|
296
|
+
),
|
|
297
|
+
lf.SystemMessage('hi'),
|
|
298
|
+
)
|
|
299
|
+
with self.assertRaisesRegex(ValueError, 'Unsupported role: .*'):
|
|
300
|
+
lf.Message.from_value(
|
|
301
|
+
{
|
|
302
|
+
'role': 'function',
|
|
303
|
+
'content': [{'type': 'input_text', 'text': 'hi'}],
|
|
304
|
+
},
|
|
305
|
+
format='openai_responses_api',
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
def test_from_value_with_image(self):
|
|
309
|
+
image = lf_modalities.Image.from_bytes(image_content)
|
|
310
|
+
m = lf.Message.from_openai_responses_api_format(
|
|
311
|
+
lf.Template(
|
|
312
|
+
'What is this {{image}}?', image=image
|
|
313
|
+
).render().as_format('openai_responses_api'),
|
|
314
|
+
)
|
|
315
|
+
self.assertEqual(m.text, f'What is this <<[[{image.id}]]>> ?')
|
|
316
|
+
self.assertIsInstance(m.modalities()[0], lf_modalities.Image)
|
|
317
|
+
self.assertEqual(m.modalities()[0].content, image_content)
|
|
318
|
+
|
|
319
|
+
if __name__ == '__main__':
|
|
320
|
+
unittest.main()
|
|
@@ -18,6 +18,7 @@ import sys
|
|
|
18
18
|
import tempfile
|
|
19
19
|
import unittest
|
|
20
20
|
|
|
21
|
+
from langfun.core import concurrent as lf_concurrent
|
|
21
22
|
from langfun.core import console as lf_console
|
|
22
23
|
from langfun.core.eval.v2 import eval_test_helper
|
|
23
24
|
from langfun.core.eval.v2 import progress_tracking # pylint: disable=unused-import
|
|
@@ -51,6 +52,7 @@ class TqdmProgressTrackerTest(unittest.TestCase):
|
|
|
51
52
|
with contextlib.redirect_stderr(string_io):
|
|
52
53
|
_ = experiment.run(root_dir, 'new', plugins=[])
|
|
53
54
|
sys.stderr.flush()
|
|
55
|
+
lf_concurrent.ProgressBar.refresh()
|
|
54
56
|
self.assertIn('All: 100%', string_io.getvalue())
|
|
55
57
|
|
|
56
58
|
def test_with_example_ids(self):
|
|
@@ -62,6 +64,7 @@ class TqdmProgressTrackerTest(unittest.TestCase):
|
|
|
62
64
|
with contextlib.redirect_stderr(string_io):
|
|
63
65
|
_ = experiment.run(root_dir, 'new', example_ids=[1], plugins=[])
|
|
64
66
|
sys.stderr.flush()
|
|
67
|
+
lf_concurrent.ProgressBar.refresh()
|
|
65
68
|
self.assertIn('All: 100%', string_io.getvalue())
|
|
66
69
|
|
|
67
70
|
|
{langfun-0.1.2.dev202510240805 → langfun-0.1.2.dev202510250803}/langfun/core/langfunc_test.py
RENAMED
|
@@ -82,7 +82,7 @@ class LangFuncCallTest(unittest.TestCase):
|
|
|
82
82
|
|
|
83
83
|
i = l.render()
|
|
84
84
|
self.assertEqual(i, 'Hello')
|
|
85
|
-
self.assertEqual(i, message.UserMessage('Hello'))
|
|
85
|
+
self.assertEqual(i, message.UserMessage('Hello', __template_input__={}))
|
|
86
86
|
self.assertEqual(i.tags, ['rendered'])
|
|
87
87
|
|
|
88
88
|
r = l()
|
|
@@ -96,7 +96,9 @@ class LangFuncCallTest(unittest.TestCase):
|
|
|
96
96
|
self.assertEqual(r.tags, ['lm-response', 'lm-output'])
|
|
97
97
|
self.assertEqual(
|
|
98
98
|
r.source,
|
|
99
|
-
message.UserMessage(
|
|
99
|
+
message.UserMessage(
|
|
100
|
+
'Hello', metadata=dict(cache_seed=0, __template_input__={})
|
|
101
|
+
)
|
|
100
102
|
)
|
|
101
103
|
self.assertEqual(r.source.tags, ['rendered', 'lm-input'])
|
|
102
104
|
|