langfun 0.1.2.dev202511200805__tar.gz → 0.1.2.dev202512150805__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.

Files changed (224) hide show
  1. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/PKG-INFO +1 -1
  2. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/agentic/action.py +0 -1
  3. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/gemini.py +2 -0
  4. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/gemini_test.py +36 -0
  5. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/__init__.py +2 -0
  6. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/checkpointing.py +86 -42
  7. langfun-0.1.2.dev202512150805/langfun/core/eval/v2/config_saver.py +37 -0
  8. langfun-0.1.2.dev202512150805/langfun/core/eval/v2/config_saver_test.py +36 -0
  9. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/evaluation.py +10 -2
  10. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/experiment.py +21 -12
  11. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/progress.py +1 -0
  12. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/progress_tracking.py +1 -2
  13. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/reporting.py +2 -4
  14. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/base.py +14 -38
  15. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/beam.py +13 -0
  16. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/beam_test.py +25 -3
  17. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/ckpt_monitor.py +62 -6
  18. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/ckpt_monitor_test.py +51 -0
  19. langfun-0.1.2.dev202512150805/langfun/core/eval/v2/runners/parallel.py +243 -0
  20. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/parallel_test.py +91 -4
  21. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/sequential_test.py +1 -4
  22. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/language_model.py +30 -12
  23. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/language_model_test.py +33 -2
  24. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/__init__.py +3 -0
  25. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/gemini.py +41 -3
  26. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/gemini_test.py +26 -0
  27. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/google_genai.py +18 -0
  28. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/openai.py +27 -0
  29. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/vertexai.py +20 -0
  30. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/image.py +54 -2
  31. langfun-0.1.2.dev202512150805/langfun/core/modalities/image_test.py +224 -0
  32. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/mime.py +14 -1
  33. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/mime_test.py +48 -0
  34. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun.egg-info/PKG-INFO +1 -1
  35. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun.egg-info/SOURCES.txt +2 -0
  36. langfun-0.1.2.dev202511200805/langfun/core/eval/v2/runners/parallel.py +0 -100
  37. langfun-0.1.2.dev202511200805/langfun/core/modalities/image_test.py +0 -108
  38. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/LICENSE +0 -0
  39. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/README.md +0 -0
  40. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/__init__.py +0 -0
  41. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/__init__.py +0 -0
  42. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/bounding_box_parser.py +0 -0
  43. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/bounding_box_parser_test.py +0 -0
  44. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/drawing.py +0 -0
  45. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/drawing_test.py +0 -0
  46. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/location.py +0 -0
  47. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/assistant/capabilities/gui/location_test.py +0 -0
  48. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/__init__.py +0 -0
  49. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/agentic/__init__.py +0 -0
  50. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/agentic/action_eval.py +0 -0
  51. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/agentic/action_eval_test.py +0 -0
  52. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/agentic/action_test.py +0 -0
  53. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/async_support.py +0 -0
  54. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/async_support_test.py +0 -0
  55. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/__init__.py +0 -0
  56. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/__init__.py +0 -0
  57. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/correction.py +0 -0
  58. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/correction_test.py +0 -0
  59. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/execution.py +0 -0
  60. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/execution_test.py +0 -0
  61. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/generation.py +0 -0
  62. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/generation_test.py +0 -0
  63. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/parsing.py +0 -0
  64. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/parsing_test.py +0 -0
  65. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/sandboxing.py +0 -0
  66. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/coding/python/sandboxing_test.py +0 -0
  67. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/component.py +0 -0
  68. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/component_test.py +0 -0
  69. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/concurrent.py +0 -0
  70. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/concurrent_test.py +0 -0
  71. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/console.py +0 -0
  72. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/console_test.py +0 -0
  73. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/__init__.py +0 -0
  74. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/__init__.py +0 -0
  75. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/anthropic.py +0 -0
  76. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/anthropic_test.py +0 -0
  77. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/openai.py +0 -0
  78. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/data/conversion/openai_test.py +0 -0
  79. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/__init__.py +0 -0
  80. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/base.py +0 -0
  81. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/base_test.py +0 -0
  82. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/matching.py +0 -0
  83. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/matching_test.py +0 -0
  84. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/patching.py +0 -0
  85. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/patching_test.py +0 -0
  86. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/scoring.py +0 -0
  87. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/scoring_test.py +0 -0
  88. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/checkpointing_test.py +0 -0
  89. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/eval_test_helper.py +0 -0
  90. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/evaluation_test.py +0 -0
  91. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/example.py +0 -0
  92. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/example_test.py +0 -0
  93. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/experiment_test.py +0 -0
  94. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/metric_values.py +0 -0
  95. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/metric_values_test.py +0 -0
  96. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/metrics.py +0 -0
  97. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/metrics_test.py +0 -0
  98. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/progress_test.py +0 -0
  99. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/progress_tracking_test.py +0 -0
  100. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/reporting_test.py +0 -0
  101. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/__init__.py +0 -0
  102. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/debug.py +0 -0
  103. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/debug_test.py +0 -0
  104. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/eval/v2/runners/sequential.py +0 -0
  105. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/langfunc.py +0 -0
  106. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/langfunc_test.py +0 -0
  107. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/anthropic.py +0 -0
  108. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/anthropic_test.py +0 -0
  109. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/azure_openai.py +0 -0
  110. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/azure_openai_test.py +0 -0
  111. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/cache/__init__.py +0 -0
  112. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/cache/base.py +0 -0
  113. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/cache/in_memory.py +0 -0
  114. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/cache/in_memory_test.py +0 -0
  115. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/compositional.py +0 -0
  116. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/compositional_test.py +0 -0
  117. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/deepseek.py +0 -0
  118. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/deepseek_test.py +0 -0
  119. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/fake.py +0 -0
  120. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/fake_test.py +0 -0
  121. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/google_genai_test.py +0 -0
  122. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/groq.py +0 -0
  123. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/groq_test.py +0 -0
  124. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/llama_cpp.py +0 -0
  125. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/llama_cpp_test.py +0 -0
  126. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/openai_compatible.py +0 -0
  127. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/openai_compatible_test.py +0 -0
  128. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/openai_test.py +0 -0
  129. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/rest.py +0 -0
  130. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/rest_test.py +0 -0
  131. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/llms/vertexai_test.py +0 -0
  132. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/logging.py +0 -0
  133. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/logging_test.py +0 -0
  134. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/__init__.py +0 -0
  135. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/client.py +0 -0
  136. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/client_test.py +0 -0
  137. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/session.py +0 -0
  138. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/session_test.py +0 -0
  139. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/testing/simple_mcp_client.py +0 -0
  140. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/testing/simple_mcp_server.py +0 -0
  141. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/tool.py +0 -0
  142. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/mcp/tool_test.py +0 -0
  143. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/memories/__init__.py +0 -0
  144. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/memories/conversation_history.py +0 -0
  145. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/memories/conversation_history_test.py +0 -0
  146. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/memory.py +0 -0
  147. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/message.py +0 -0
  148. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/message_test.py +0 -0
  149. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/__init__.py +0 -0
  150. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/audio.py +0 -0
  151. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/audio_test.py +0 -0
  152. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/pdf.py +0 -0
  153. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/pdf_test.py +0 -0
  154. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/video.py +0 -0
  155. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modalities/video_test.py +0 -0
  156. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modality.py +0 -0
  157. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/modality_test.py +0 -0
  158. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/natural_language.py +0 -0
  159. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/natural_language_test.py +0 -0
  160. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/sampling.py +0 -0
  161. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/sampling_test.py +0 -0
  162. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/__init__.py +0 -0
  163. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/completion.py +0 -0
  164. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/completion_test.py +0 -0
  165. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/description.py +0 -0
  166. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/description_test.py +0 -0
  167. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/function_generation.py +0 -0
  168. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/function_generation_test.py +0 -0
  169. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/mapping.py +0 -0
  170. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/mapping_test.py +0 -0
  171. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/parsing.py +0 -0
  172. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/parsing_test.py +0 -0
  173. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/querying.py +0 -0
  174. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/querying_test.py +0 -0
  175. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/__init__.py +0 -0
  176. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/base.py +0 -0
  177. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/base_test.py +0 -0
  178. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/json.py +0 -0
  179. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/json_test.py +0 -0
  180. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/python.py +0 -0
  181. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema/python_test.py +0 -0
  182. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema_generation.py +0 -0
  183. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/schema_generation_test.py +0 -0
  184. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/scoring.py +0 -0
  185. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/scoring_test.py +0 -0
  186. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/tokenization.py +0 -0
  187. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/structured/tokenization_test.py +0 -0
  188. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/subscription.py +0 -0
  189. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/subscription_test.py +0 -0
  190. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/template.py +0 -0
  191. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/template_test.py +0 -0
  192. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/__init__.py +0 -0
  193. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/completion.py +0 -0
  194. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/completion_test.py +0 -0
  195. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/conversation.py +0 -0
  196. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/conversation_test.py +0 -0
  197. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/demonstration.py +0 -0
  198. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/demonstration_test.py +0 -0
  199. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/selfplay.py +0 -0
  200. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/core/templates/selfplay_test.py +0 -0
  201. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/__init__.py +0 -0
  202. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_environment.py +0 -0
  203. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_environment_test.py +0 -0
  204. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_feature.py +0 -0
  205. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_feature_test.py +0 -0
  206. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_sandbox.py +0 -0
  207. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/base_sandbox_test.py +0 -0
  208. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/__init__.py +0 -0
  209. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/chain.py +0 -0
  210. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/chain_test.py +0 -0
  211. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/event_logger.py +0 -0
  212. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/event_logger_test.py +0 -0
  213. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/metric_writer.py +0 -0
  214. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/event_handlers/metric_writer_test.py +0 -0
  215. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/interface.py +0 -0
  216. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/interface_test.py +0 -0
  217. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/load_balancers.py +0 -0
  218. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/load_balancers_test.py +0 -0
  219. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun/env/test_utils.py +0 -0
  220. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun.egg-info/dependency_links.txt +0 -0
  221. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun.egg-info/requires.txt +0 -0
  222. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/langfun.egg-info/top_level.txt +0 -0
  223. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/setup.cfg +0 -0
  224. {langfun-0.1.2.dev202511200805 → langfun-0.1.2.dev202512150805}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202511200805
3
+ Version: 0.1.2.dev202512150805
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -1907,7 +1907,6 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
1907
1907
 
1908
1908
  def _on_bound(self):
1909
1909
  super()._on_bound()
1910
- self._event_handler = None
1911
1910
  self._tls = threading.local()
1912
1911
  self._current_action = self.root
1913
1912
  self._current_execution = self.root.execution
@@ -138,6 +138,8 @@ class GeminiMessageConverter(lf.MessageConverter):
138
138
  self._safe_read(data, 'mimeType')
139
139
  ).from_uri(self._safe_read(data, 'fileUri'))
140
140
  )
141
+ elif 'functionCall' in part or 'functionResponse' in part:
142
+ pass
141
143
  else:
142
144
  raise ValueError(f'Unsupported content part: {part!r}.')
143
145
  message = message_cls.from_chunks(chunks)
@@ -242,6 +242,42 @@ class GeminiConversionTest(unittest.TestCase):
242
242
  'https://www.youtube.com/watch?v=abcd'
243
243
  )
244
244
 
245
+ def test_from_value_with_function_call(self):
246
+ message = lf.Message.from_value(
247
+ {
248
+ 'role': 'model',
249
+ 'parts': [
250
+ {'text': 'Let me search for that.'},
251
+ {
252
+ 'functionCall': {
253
+ 'name': 'search',
254
+ 'args': {'query': 'test'},
255
+ }
256
+ },
257
+ ],
258
+ },
259
+ format='gemini',
260
+ )
261
+ self.assertEqual(message.text, 'Let me search for that.')
262
+
263
+ def test_from_value_with_function_response(self):
264
+ message = lf.Message.from_value(
265
+ {
266
+ 'role': 'user',
267
+ 'parts': [
268
+ {
269
+ 'functionResponse': {
270
+ 'name': 'search',
271
+ 'response': {'results': ['a', 'b']},
272
+ }
273
+ },
274
+ {'text': 'Here are the results.'},
275
+ ],
276
+ },
277
+ format='gemini',
278
+ )
279
+ self.assertEqual(message.text, 'Here are the results.')
280
+
245
281
 
246
282
  if __name__ == '__main__':
247
283
  unittest.main()
@@ -35,11 +35,13 @@ from langfun.core.eval.v2.experiment import Runner
35
35
  from langfun.core.eval.v2 import runners
36
36
 
37
37
  # Plugins
38
+ from langfun.core.eval.v2.config_saver import RunConfigSaver
38
39
  from langfun.core.eval.v2.checkpointing import BulkCheckpointer
39
40
  from langfun.core.eval.v2.checkpointing import PerExampleCheckpointer
40
41
  from langfun.core.eval.v2.reporting import HtmlReporter
41
42
  from langfun.core.eval.v2.reporting import ExampleHtmlGenerator
42
43
 
44
+ # Google-internal imports.
43
45
 
44
46
  # pylint: enable=g-bad-import-order
45
47
  # pylint: enable=g-importing-member
@@ -14,6 +14,7 @@
14
14
  """Checkpointing evaluation runs."""
15
15
  import abc
16
16
  import datetime
17
+ import os
17
18
  import re
18
19
  import threading
19
20
  import traceback
@@ -37,7 +38,7 @@ class Checkpointer(experiment_lib.Plugin):
37
38
  later. When an experiment starts, the checkpointer loads any previously saved
38
39
  examples from an earlier run (or a warm-start run) into `experiment.state`,
39
40
  so the runner can skip processing them again.
40
- Subclasses should implement `_list_checkpoint_filenames` to identify
41
+ Subclasses should implement `_list_checkpoint_files` to identify
41
42
  checkpoint files to load, and `_save_example` to save a newly processed
42
43
  example.
43
44
  """
@@ -130,7 +131,7 @@ class Checkpointer(experiment_lib.Plugin):
130
131
  experiment: Experiment,
131
132
  ) -> None:
132
133
  """Creates the checkpoint file."""
133
- ckpt_files = self._list_checkpoint_filenames(runner, experiment)
134
+ ckpt_files = self._list_checkpoint_files(runner, experiment)
134
135
  experiment.info(f'Found {len(ckpt_files)} checkpoint files to load.')
135
136
 
136
137
  # Load the checkpoint files in parallel.
@@ -140,18 +141,18 @@ class Checkpointer(experiment_lib.Plugin):
140
141
  experiment
141
142
  )
142
143
  context = dict(counter=0, counter_lock=threading.Lock())
143
- copy_ckpt = current_run.input_root != current_run.output_root
144
144
 
145
145
  def _load_state(ckpt_file):
146
146
  error = None
147
147
  with pg.timeit() as t:
148
148
  try:
149
- experiment.load_state(
150
- current_run.input_path_for(experiment, ckpt_file),
149
+ loaded_examples = experiment.load_state(
150
+ ckpt_file,
151
151
  filter=lambda x: x.id in examples_to_load,
152
152
  load_example_metadata=lambda x: x.id in examples_to_load_metadata,
153
153
  )
154
154
  except BaseException as e: # pylint: disable=broad-except
155
+ loaded_examples = []
155
156
  error = e
156
157
  finally:
157
158
  with context['counter_lock']:
@@ -169,22 +170,18 @@ class Checkpointer(experiment_lib.Plugin):
169
170
  f'Skipping the file. ({progress_str})'
170
171
  )
171
172
 
172
- if not copy_ckpt:
173
- return
174
-
175
- # Copy the checkpoint records to the output directory.
176
- try:
177
- with pg.io.open_sequence(
178
- current_run.output_path_for(experiment, ckpt_file), 'w'
179
- ) as o, pg.io.open_sequence(
180
- current_run.input_path_for(experiment, ckpt_file), 'r'
181
- ) as i:
182
- for x in i:
183
- o.add(x)
184
- except BaseException as e: # pylint: disable=broad-except
185
- experiment.warning(
186
- f'Failed to copy checkpoint {ckpt_file!r}: {e}.'
187
- )
173
+ output_ckpt_file = current_run.output_path_for(
174
+ experiment, os.path.basename(ckpt_file)
175
+ )
176
+ if ckpt_file != output_ckpt_file and any(
177
+ e for e in loaded_examples if not e.has_error
178
+ ):
179
+ # Write the error-free warm-start examples to the output checkpoint
180
+ # file.
181
+ with SequenceWriter(output_ckpt_file) as writer:
182
+ for example in loaded_examples:
183
+ if not example.has_error:
184
+ writer.add(example)
188
185
 
189
186
  _ = list(
190
187
  lf.concurrent_map(
@@ -196,10 +193,10 @@ class Checkpointer(experiment_lib.Plugin):
196
193
  )
197
194
 
198
195
  @abc.abstractmethod
199
- def _list_checkpoint_filenames(
196
+ def _list_checkpoint_files(
200
197
  self, runner: Runner, experiment: Experiment
201
198
  ) -> list[str]:
202
- """Lists the checkpoint filenames to restore."""
199
+ """Lists the checkpoint file paths to restore."""
203
200
 
204
201
  @abc.abstractmethod
205
202
  def _save_example(
@@ -225,22 +222,41 @@ class PerExampleCheckpointer(Checkpointer):
225
222
  self._checkpoint_file_prefix = prefix
226
223
  self._checkpoint_file_ext = ext
227
224
 
228
- def _list_checkpoint_filenames(
225
+ def _list_checkpoint_files(
229
226
  self, runner: Runner, experiment: Experiment
230
227
  ) -> list[str]:
231
- experiment_dir = runner.current_run.input_dir(experiment)
232
- filenames = []
228
+
229
+ def _list_checkpoints_from(ckpt_dir: str, examples_to_load: set[int]):
230
+ ckpt_files = []
231
+ if pg.io.path_exists(ckpt_dir):
232
+ regex = re.compile(
233
+ f'{self._checkpoint_file_prefix}_(\\d+){self._checkpoint_file_ext}'
234
+ .replace('.', '\\.')
235
+ )
236
+ for filename in pg.io.listdir(ckpt_dir):
237
+ match = regex.match(filename)
238
+ if match and int(match.group(1)) in examples_to_load:
239
+ examples_to_load.remove(int(match.group(1)))
240
+ ckpt_files.append(os.path.join(ckpt_dir, filename))
241
+ return ckpt_files
242
+
233
243
  examples_to_load = runner.current_run.examples_to_load(experiment)
234
- if pg.io.path_exists(experiment_dir):
235
- regex = re.compile(
236
- f'{self._checkpoint_file_prefix}_(\\d+){self._checkpoint_file_ext}'
237
- .replace('.', '\\.')
244
+
245
+ # Take output directory as the first priority to checkpoints processed in
246
+ # this run.
247
+ ckpt_files = _list_checkpoints_from(
248
+ runner.current_run.output_dir(experiment), examples_to_load
249
+ )
250
+ # If the input and output directories are different, also load from the
251
+ # input directory.
252
+ if (examples_to_load
253
+ and runner.current_run.input_root != runner.current_run.output_root):
254
+ ckpt_files.extend(
255
+ _list_checkpoints_from(
256
+ runner.current_run.input_dir(experiment), examples_to_load
257
+ )
238
258
  )
239
- for filename in pg.io.listdir(experiment_dir):
240
- match = regex.match(filename)
241
- if match and int(match.group(1)) in examples_to_load:
242
- filenames.append(filename)
243
- return filenames
259
+ return ckpt_files
244
260
 
245
261
  def _save_example(
246
262
  self,
@@ -340,13 +356,24 @@ class BulkCheckpointer(Checkpointer):
340
356
  if self._sequence_writer is not None:
341
357
  self._sequence_writer[experiment.id] = sequence_writer
342
358
 
343
- def _list_checkpoint_filenames(
359
+ def _list_checkpoint_files(
344
360
  self, runner: Runner, experiment: Experiment
345
361
  ) -> list[str]:
346
- if pg.io.path_exists(
347
- runner.current_run.input_path_for(experiment, self.checkpoint_filename)
348
- ):
349
- return [self.checkpoint_filename]
362
+ # Always honor the output directory if it's present, as it contains both
363
+ # the warm-started examples and newly processed examples.
364
+ output_ckpt_file = runner.current_run.output_path_for(
365
+ experiment, self.checkpoint_filename
366
+ )
367
+ if pg.io.path_exists(output_ckpt_file):
368
+ return [output_ckpt_file]
369
+
370
+ if runner.current_run.input_root != runner.current_run.output_root:
371
+ input_ckpt_file = runner.current_run.input_path_for(
372
+ experiment, self.checkpoint_filename
373
+ )
374
+ if pg.io.path_exists(input_ckpt_file):
375
+ return [input_ckpt_file]
376
+ print('CCC', experiment.hash, [])
350
377
  return []
351
378
 
352
379
  def on_experiment_complete(
@@ -394,17 +421,26 @@ class BulkCheckpointer(Checkpointer):
394
421
 
395
422
 
396
423
  class SequenceWriter:
397
- """A thread-safe writer for sequence files (e.g., Bagz).
424
+ """A thread-safe writer for sequence files (e.g., Bagz) with atomic write.
398
425
 
399
426
  `SequenceWriter` wraps a `pg.io.SequenceWriter` to provide thread-safe
400
427
  `add` and `close` operations, ensuring that examples can be written
401
428
  concurrently from multiple threads without corrupting the sequence file.
429
+ It writes to a temporary file and renames it to target path on `close` to
430
+ achieve atomic write. If the target path exists, new examples are appended
431
+ to existing content.
402
432
  """
403
433
 
404
434
  def __init__(self, path: str):
405
435
  self._lock = threading.Lock()
406
436
  self._path = path
407
- self._sequence_writer = pg.io.open_sequence(path, 'a')
437
+ basename = os.path.basename(path)
438
+ self._tmp_path = os.path.join(
439
+ os.path.dirname(path), f'tmp.{basename}'
440
+ )
441
+ if pg.io.path_exists(self._path):
442
+ pg.io.copy(self._path, self._tmp_path)
443
+ self._sequence_writer = pg.io.open_sequence(self._tmp_path, 'a')
408
444
 
409
445
  @property
410
446
  def path(self) -> str:
@@ -429,6 +465,14 @@ class SequenceWriter:
429
465
  return
430
466
  self._sequence_writer.close()
431
467
  self._sequence_writer = None
468
+ pg.io.rename(self._tmp_path, self._path)
469
+
470
+ def __enter__(self):
471
+ return self
472
+
473
+ def __exit__(self, *args, **kwargs):
474
+ del args, kwargs
475
+ self.close()
432
476
 
433
477
  def __del__(self):
434
478
  self.close()
@@ -0,0 +1,37 @@
1
+ # Copyright 2024 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
+ """Config saver plugins."""
15
+
16
+ import os
17
+ from langfun.core.eval.v2 import experiment as experiment_lib
18
+
19
+
20
+ class RunConfigSaver(experiment_lib.Plugin):
21
+ """Saves the current run."""
22
+
23
+ def on_run_start(
24
+ self,
25
+ runner: experiment_lib.Runner,
26
+ root: experiment_lib.Experiment
27
+ ) -> None:
28
+ del root # Unused.
29
+ self._save_run_config(runner)
30
+
31
+ def _save_run_config(self, runner: experiment_lib.Runner) -> None:
32
+ def _save():
33
+ runner.current_run.save(
34
+ os.path.join(runner.current_run.output_root, 'run.json'),
35
+ hide_default_values=True,
36
+ )
37
+ runner.background_run(_save)
@@ -0,0 +1,36 @@
1
+ # Copyright 2024 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
+ """Config saver test."""
15
+
16
+ import os
17
+ import tempfile
18
+ import unittest
19
+ from langfun.core.eval.v2 import config_saver
20
+ from langfun.core.eval.v2 import eval_test_helper
21
+ from langfun.core.eval.v2.runners import parallel # pylint: disable=unused-import
22
+
23
+
24
+ class RunConfigSaverTest(unittest.TestCase):
25
+
26
+ def test_save_run_config(self):
27
+ root_dir = os.path.join(tempfile.mkdtemp(), 'test_run_config_saver')
28
+ experiment = eval_test_helper.test_evaluation()
29
+ run = experiment.run(
30
+ root_dir, 'new', plugins=[config_saver.RunConfigSaver()]
31
+ )
32
+ self.assertTrue(os.path.exists(os.path.join(run.output_root, 'run.json')))
33
+
34
+
35
+ if __name__ == '__main__':
36
+ unittest.main()
@@ -114,6 +114,13 @@ class Evaluation(experiment_lib.Experiment):
114
114
  self._log_entries = []
115
115
  self._log_lock = threading.Lock()
116
116
 
117
+ def _identity(self) -> str:
118
+ """Returns the definition of the evaluation."""
119
+ return self.format(
120
+ compact=True, hide_default_values=True, use_inferred=True,
121
+ exclude_keys=('plugins', 'progress', 'usage_summary')
122
+ )
123
+
117
124
  #
118
125
  # Handling evaluation hierarchy (materialized vs. hyper evaluations).
119
126
  #
@@ -379,10 +386,10 @@ class Evaluation(experiment_lib.Experiment):
379
386
  load_example_metadata: bool = True,
380
387
  filter: Callable[[example_lib.Example], bool] | None = None, # pylint: disable=redefined-builtin
381
388
  raise_if_not_exist: bool = False
382
- ) -> None:
389
+ ) -> list[example_lib.Example]:
383
390
  """Loads saved state from a sequence IO file."""
384
391
  if pg.io.path_exists(state_file):
385
- self._state.load(
392
+ return self._state.load(
386
393
  state_file,
387
394
  example_input_by_id=self.example_input_by_id,
388
395
  load_example_metadata=load_example_metadata,
@@ -390,6 +397,7 @@ class Evaluation(experiment_lib.Experiment):
390
397
  )
391
398
  elif raise_if_not_exist:
392
399
  raise ValueError(f'State file {state_file} does not exist.')
400
+ return []
393
401
 
394
402
  def _reset(self) -> None:
395
403
  """Resets the state of the evaluation."""
@@ -268,11 +268,11 @@ class Experiment(lf.Component, pg.views.HtmlTreeView.Extension):
268
268
  @functools.cached_property
269
269
  def hash(self) -> str:
270
270
  """A 8-byte MD5 hash computed from experiment identity."""
271
- identity = self.format(
272
- compact=True, hide_default_values=True, use_inferred=True,
273
- exclude_keys=('plugins', 'progress', 'usage_summary')
274
- )
275
- return hashlib.md5(identity.encode()).hexdigest()[:8]
271
+ return hashlib.md5(self._identity().encode()).hexdigest()[:8]
272
+
273
+ @abc.abstractmethod
274
+ def _identity(self) -> str:
275
+ """Returns the identity of the experiment."""
276
276
 
277
277
  @classmethod
278
278
  def link(cls, path: str) -> str:
@@ -691,6 +691,12 @@ class Suite(Experiment):
691
691
  """Returns whether the task is a leaf."""
692
692
  return False
693
693
 
694
+ def _identity(self) -> str:
695
+ """Returns the definition of the evaluation."""
696
+ return '[' + ', '.join(
697
+ [child._identity() for child in self.children] # pylint: disable=protected-access
698
+ ) + ']'
699
+
694
700
 
695
701
  class RunId(pg.Object):
696
702
  """Structured repreesentation a experiment run ID."""
@@ -848,10 +854,10 @@ class Run(pg.Object, pg.views.html.HtmlTreeView.Extension):
848
854
  ] = None
849
855
 
850
856
  example_ids: Annotated[
851
- list[int] | None,
857
+ list[int] | Callable[[Experiment], list[int]] | None,
852
858
  (
853
- 'The example IDs to run. If None, it will run all examples. '
854
- 'Though '
859
+ 'The example IDs to run. Or a callable for determining the examples '
860
+ 'to run based on the experiment. If None, it will run all examples. '
855
861
  )
856
862
  ] = None
857
863
 
@@ -967,10 +973,13 @@ class Run(pg.Object, pg.views.html.HtmlTreeView.Extension):
967
973
  """Returns the example IDs to evaluate."""
968
974
  if not experiment.is_leaf:
969
975
  return set()
970
- return set(
971
- self.example_ids if self.example_ids else
972
- range(1, experiment.num_examples + 1)
973
- )
976
+ if self.example_ids is None:
977
+ return set(range(1, experiment.num_examples + 1))
978
+ elif isinstance(self.example_ids, Callable):
979
+ return set(self.example_ids(experiment))
980
+ else:
981
+ assert isinstance(self.example_ids, list), self.example_ids
982
+ return set(self.example_ids)
974
983
 
975
984
  def examples_to_reprocess(self, experiment: Experiment) -> set[int]:
976
985
  """Returns the example IDs to reprocess per request."""
@@ -92,6 +92,7 @@ class Progress(pg.Object, pg.views.HtmlTreeView.Extension):
92
92
  stop_time=None,
93
93
  execution_summary=pg.object_utils.TimeIt.StatusSummary(),
94
94
  )
95
+ self._progress_bar = None
95
96
 
96
97
  @property
97
98
  def num_completed(self) -> int:
@@ -97,8 +97,7 @@ class _TqdmProgressTracker(experiment_lib.Plugin):
97
97
  self._leaf_progresses = {
98
98
  leaf.id: lf.concurrent.ProgressBar.install(
99
99
  label=f'[#{i + 1} - {leaf.id}]',
100
- total=(len(runner.current_run.example_ids)
101
- if runner.current_run.example_ids else leaf.num_examples),
100
+ total=len(runner.current_run.examples_to_evaluate(leaf)),
102
101
  color='cyan',
103
102
  status=None
104
103
  )
@@ -86,10 +86,8 @@ class ExampleHtmlGenerator(experiment_lib.Plugin):
86
86
  return
87
87
 
88
88
  try:
89
- with pg.timeit() as t, pg.io.open(src_file, 'r') as src:
90
- content = src.read()
91
- with pg.io.open(dest_file, 'w') as dest:
92
- dest.write(content)
89
+ with pg.timeit() as t:
90
+ pg.io.copy(src_file, dest_file)
93
91
  experiment.info(
94
92
  f'\'{example.id}.html\' copied in {t.elapse:.2f} seconds.'
95
93
  )
@@ -22,6 +22,7 @@ from typing import Any, Annotated, Callable, Iterator, Literal
22
22
 
23
23
  from langfun import core as lf
24
24
  from langfun.core.eval.v2 import checkpointing
25
+ from langfun.core.eval.v2 import config_saver
25
26
  from langfun.core.eval.v2 import evaluation as evaluation_lib
26
27
  from langfun.core.eval.v2 import example as example_lib
27
28
  from langfun.core.eval.v2 import experiment as experiment_lib
@@ -37,9 +38,6 @@ Experiment = experiment_lib.Experiment
37
38
  Plugin = experiment_lib.Plugin
38
39
 
39
40
 
40
- _RUN_MANIFEST = 'run.json'
41
-
42
-
43
41
  class RunnerBase(Runner):
44
42
  """Base class for runners with plugin support and IO pooling.
45
43
 
@@ -64,6 +62,7 @@ class RunnerBase(Runner):
64
62
  plugins = [
65
63
  checkpointing.BulkCheckpointer(),
66
64
  reporting.HtmlReporter(),
65
+ config_saver.RunConfigSaver(),
67
66
  ]
68
67
 
69
68
  max_background_threads: Annotated[
@@ -115,24 +114,8 @@ class RunnerBase(Runner):
115
114
  for plugin in experiment.plugins:
116
115
  yield plugin
117
116
 
118
- #
119
- # IO operations for saving running files.
120
- #
121
-
122
- def _save_run_manifest(self) -> None:
123
- def _save():
124
- pg.symbolic.deref(self.current_run.clone(), recursive=True).save(
125
- self.current_run.output_path_for(
126
- self.current_run.experiment, _RUN_MANIFEST
127
- ),
128
- hide_default_values=True
129
- )
130
- self.background_run(_save)
131
-
132
117
  def on_run_start(self) -> None:
133
118
  """Called when a runner is started."""
134
- self._save_run_manifest()
135
-
136
119
  for plugin in self._all_plugins(self.current_run.experiment):
137
120
  plugin.on_run_start(self, self.current_run.experiment)
138
121
 
@@ -152,11 +135,11 @@ class RunnerBase(Runner):
152
135
  num_examples_to_evaluate = 0
153
136
  if experiment.is_leaf:
154
137
  assert isinstance(experiment, Evaluation)
155
- num_examples_to_evaluate = (
156
- len(self.current_run.example_ids)
157
- if self.current_run.example_ids else experiment.num_examples
138
+ num_examples_to_evaluate = len(
139
+ self.current_run.examples_to_evaluate(experiment)
158
140
  )
159
141
  experiment.progress.start(total=num_examples_to_evaluate)
142
+ pg.io.mkdirs(self.current_run.output_dir(experiment))
160
143
  else:
161
144
  experiment.progress.start(total=len(experiment.leaf_nodes))
162
145
 
@@ -207,10 +190,7 @@ class RunnerBase(Runner):
207
190
  self._log_experiment_completion(experiment)
208
191
 
209
192
  def _log_experiment_completion(self, experiment: Experiment):
210
- example_ids = (
211
- self.current_run.example_ids if self.current_run.example_ids else
212
- list(range(1, experiment.num_examples + 1))
213
- )
193
+ example_ids = sorted(self.current_run.examples_to_evaluate(experiment))
214
194
  num_from_checkpoint, num_processed = 0, 0
215
195
  for example_id in example_ids:
216
196
  status = experiment.state.get_status(example_id)
@@ -377,18 +357,14 @@ class RunnerBase(Runner):
377
357
  per_evaluation_settings['cache'] = cache
378
358
 
379
359
  with lf.use_settings(**per_evaluation_settings):
380
- if self.current_run.example_ids is None:
381
- items = (
382
- Example(id=i + 1, input=ex) for i, ex in enumerate(
383
- evaluation.example_inputs)
384
- )
385
- else:
386
- items = (
387
- Example(
388
- id=example_id,
389
- input=evaluation.example_input_by_id(example_id)
390
- ) for example_id in self.current_run.example_ids
391
- )
360
+ items = (
361
+ Example(
362
+ id=example_id,
363
+ input=evaluation.example_input_by_id(example_id)
364
+ ) for example_id in sorted(
365
+ self.current_run.examples_to_evaluate(evaluation)
366
+ )
367
+ )
392
368
  if self.current_run.shuffle_inputs:
393
369
  items = list(items)
394
370
  random.shuffle(items)
@@ -83,6 +83,9 @@ if beam is not None:
83
83
  self._runner = pg.from_json_str(self._runner_str)
84
84
  assert isinstance(self._runner, LeafNodeRunner)
85
85
  self._runner.setup()
86
+ self._input_dir = self._runner.current_run.input_dir(
87
+ self._runner.current_run.experiment
88
+ )
86
89
  self._output_dir = self._runner.current_run.output_dir(
87
90
  self._runner.current_run.experiment
88
91
  )
@@ -106,6 +109,16 @@ if beam is not None:
106
109
  )
107
110
  if pg.io.path_exists(ckpt_file):
108
111
  yield ckpt_file
112
+ return
113
+
114
+ if self._input_dir != self._output_dir:
115
+ warmup_ckpt_file = os.path.join(
116
+ self._input_dir, f'checkpoint_{example_id}.{self._ckpt_format}'
117
+ )
118
+ if pg.io.path_exists(warmup_ckpt_file):
119
+ pg.io.copy(warmup_ckpt_file, ckpt_file)
120
+ yield ckpt_file
121
+ return
109
122
 
110
123
  # Write the in-progress file to indicate that the example is being
111
124
  # processed.