langfun 0.1.2.dev202503190804__tar.gz → 0.1.2.dev202503210804__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.
Files changed (160) hide show
  1. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/PKG-INFO +3 -2
  2. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/agentic/__init__.py +2 -0
  3. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/agentic/action.py +212 -49
  4. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/agentic/action_test.py +29 -7
  5. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/rest.py +14 -4
  6. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/rest_test.py +51 -0
  7. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun.egg-info/PKG-INFO +3 -2
  8. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/LICENSE +0 -0
  9. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/README.md +0 -0
  10. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/__init__.py +0 -0
  11. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/__init__.py +0 -0
  12. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/agentic/action_eval.py +0 -0
  13. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/agentic/action_eval_test.py +0 -0
  14. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/__init__.py +0 -0
  15. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/__init__.py +0 -0
  16. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/correction.py +0 -0
  17. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/correction_test.py +0 -0
  18. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/execution.py +0 -0
  19. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/execution_test.py +0 -0
  20. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/generation.py +0 -0
  21. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/generation_test.py +0 -0
  22. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/parsing.py +0 -0
  23. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/parsing_test.py +0 -0
  24. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/sandboxing.py +0 -0
  25. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/coding/python/sandboxing_test.py +0 -0
  26. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/component.py +0 -0
  27. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/component_test.py +0 -0
  28. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/concurrent.py +0 -0
  29. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/concurrent_test.py +0 -0
  30. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/console.py +0 -0
  31. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/console_test.py +0 -0
  32. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/__init__.py +0 -0
  33. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/base.py +0 -0
  34. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/base_test.py +0 -0
  35. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/matching.py +0 -0
  36. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/matching_test.py +0 -0
  37. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/patching.py +0 -0
  38. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/patching_test.py +0 -0
  39. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/scoring.py +0 -0
  40. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/scoring_test.py +0 -0
  41. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/__init__.py +0 -0
  42. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/checkpointing.py +0 -0
  43. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/checkpointing_test.py +0 -0
  44. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/eval_test_helper.py +0 -0
  45. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/evaluation.py +0 -0
  46. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/evaluation_test.py +0 -0
  47. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/example.py +0 -0
  48. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/example_test.py +0 -0
  49. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/experiment.py +0 -0
  50. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/experiment_test.py +0 -0
  51. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/metric_values.py +0 -0
  52. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/metric_values_test.py +0 -0
  53. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/metrics.py +0 -0
  54. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/metrics_test.py +0 -0
  55. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/progress.py +0 -0
  56. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/progress_test.py +0 -0
  57. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/progress_tracking.py +0 -0
  58. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/progress_tracking_test.py +0 -0
  59. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/reporting.py +0 -0
  60. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/reporting_test.py +0 -0
  61. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/runners.py +0 -0
  62. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/eval/v2/runners_test.py +0 -0
  63. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/langfunc.py +0 -0
  64. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/langfunc_test.py +0 -0
  65. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/language_model.py +0 -0
  66. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/language_model_test.py +0 -0
  67. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/__init__.py +0 -0
  68. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/anthropic.py +0 -0
  69. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/anthropic_test.py +0 -0
  70. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/azure_openai.py +0 -0
  71. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/azure_openai_test.py +0 -0
  72. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/cache/__init__.py +0 -0
  73. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/cache/base.py +0 -0
  74. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/cache/in_memory.py +0 -0
  75. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/cache/in_memory_test.py +0 -0
  76. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/compositional.py +0 -0
  77. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/compositional_test.py +0 -0
  78. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/deepseek.py +0 -0
  79. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/deepseek_test.py +0 -0
  80. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/fake.py +0 -0
  81. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/fake_test.py +0 -0
  82. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/gemini.py +0 -0
  83. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/gemini_test.py +0 -0
  84. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/google_genai.py +0 -0
  85. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/google_genai_test.py +0 -0
  86. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/groq.py +0 -0
  87. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/groq_test.py +0 -0
  88. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/llama_cpp.py +0 -0
  89. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/llama_cpp_test.py +0 -0
  90. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/openai.py +0 -0
  91. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/openai_compatible.py +0 -0
  92. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/openai_compatible_test.py +0 -0
  93. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/openai_test.py +0 -0
  94. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/vertexai.py +0 -0
  95. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/llms/vertexai_test.py +0 -0
  96. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/logging.py +0 -0
  97. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/logging_test.py +0 -0
  98. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/memories/__init__.py +0 -0
  99. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/memories/conversation_history.py +0 -0
  100. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/memories/conversation_history_test.py +0 -0
  101. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/memory.py +0 -0
  102. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/message.py +0 -0
  103. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/message_test.py +0 -0
  104. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/__init__.py +0 -0
  105. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/audio.py +0 -0
  106. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/audio_test.py +0 -0
  107. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/image.py +0 -0
  108. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/image_test.py +0 -0
  109. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/mime.py +0 -0
  110. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/mime_test.py +0 -0
  111. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/pdf.py +0 -0
  112. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/pdf_test.py +0 -0
  113. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/video.py +0 -0
  114. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modalities/video_test.py +0 -0
  115. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modality.py +0 -0
  116. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/modality_test.py +0 -0
  117. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/natural_language.py +0 -0
  118. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/natural_language_test.py +0 -0
  119. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/sampling.py +0 -0
  120. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/sampling_test.py +0 -0
  121. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/__init__.py +0 -0
  122. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/completion.py +0 -0
  123. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/completion_test.py +0 -0
  124. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/description.py +0 -0
  125. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/description_test.py +0 -0
  126. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/function_generation.py +0 -0
  127. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/function_generation_test.py +0 -0
  128. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/mapping.py +0 -0
  129. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/mapping_test.py +0 -0
  130. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/parsing.py +0 -0
  131. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/parsing_test.py +0 -0
  132. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/querying.py +0 -0
  133. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/querying_test.py +0 -0
  134. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/schema.py +0 -0
  135. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/schema_generation.py +0 -0
  136. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/schema_generation_test.py +0 -0
  137. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/schema_test.py +0 -0
  138. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/scoring.py +0 -0
  139. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/scoring_test.py +0 -0
  140. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/tokenization.py +0 -0
  141. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/structured/tokenization_test.py +0 -0
  142. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/subscription.py +0 -0
  143. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/subscription_test.py +0 -0
  144. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/template.py +0 -0
  145. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/template_test.py +0 -0
  146. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/__init__.py +0 -0
  147. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/completion.py +0 -0
  148. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/completion_test.py +0 -0
  149. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/conversation.py +0 -0
  150. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/conversation_test.py +0 -0
  151. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/demonstration.py +0 -0
  152. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/demonstration_test.py +0 -0
  153. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/selfplay.py +0 -0
  154. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun/core/templates/selfplay_test.py +0 -0
  155. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun.egg-info/SOURCES.txt +0 -0
  156. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun.egg-info/dependency_links.txt +0 -0
  157. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun.egg-info/requires.txt +0 -0
  158. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/langfun.egg-info/top_level.txt +0 -0
  159. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/setup.cfg +0 -0
  160. {langfun-0.1.2.dev202503190804 → langfun-0.1.2.dev202503210804}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202503190804
3
+ Version: 0.1.2.dev202503210804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -53,6 +53,7 @@ Dynamic: description-content-type
53
53
  Dynamic: home-page
54
54
  Dynamic: keywords
55
55
  Dynamic: license
56
+ Dynamic: license-file
56
57
  Dynamic: provides-extra
57
58
  Dynamic: requires-dist
58
59
  Dynamic: summary
@@ -19,6 +19,8 @@
19
19
 
20
20
  from langfun.core.agentic.action import Action
21
21
  from langfun.core.agentic.action import ActionInvocation
22
+ from langfun.core.agentic.action import ExecutionTrace
23
+ from langfun.core.agentic.action import ParallelExecutions
22
24
  from langfun.core.agentic.action import Session
23
25
 
24
26
  from langfun.core.agentic.action_eval import ActionEval
@@ -16,10 +16,10 @@
16
16
  import abc
17
17
  import contextlib
18
18
  import datetime
19
+ import threading
19
20
  import time
20
-
21
21
  import typing
22
- from typing import Annotated, Any, ContextManager, Iterable, Iterator, Optional, Type, Union
22
+ from typing import Annotated, Any, Callable, Iterable, Iterator, Optional, Type, Union
23
23
  import langfun.core as lf
24
24
  from langfun.core import structured as lf_structured
25
25
  import pyglove as pg
@@ -90,6 +90,7 @@ TracedItem = Union[
90
90
  lf_structured.QueryInvocation,
91
91
  'ActionInvocation',
92
92
  'ExecutionTrace',
93
+ 'ParallelExecutions',
93
94
  # NOTE(daiyip): Consider remove log entry once we migrate existing agents.
94
95
  lf.logging.LogEntry,
95
96
  ]
@@ -206,6 +207,9 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
206
207
  child_items.append(item)
207
208
  elif isinstance(item, ExecutionTrace):
208
209
  child_items.extend(item._child_items(item_cls)) # pylint: disable=protected-access
210
+ elif isinstance(item, ParallelExecutions):
211
+ for branch in item.branches:
212
+ child_items.extend(branch._child_items(item_cls)) # pylint: disable=protected-access
209
213
  return child_items
210
214
 
211
215
  def _all_child_items(self, item_cls: Type[Any]) -> list[Any]:
@@ -217,6 +221,9 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
217
221
  child_items.extend(item.execution._all_child_items(item_cls)) # pylint: disable=protected-access
218
222
  elif isinstance(item, ExecutionTrace):
219
223
  child_items.extend(item._all_child_items(item_cls)) # pylint: disable=protected-access
224
+ elif isinstance(item, ParallelExecutions):
225
+ for branch in item.branches:
226
+ child_items.extend(branch._all_child_items(item_cls)) # pylint: disable=protected-access
220
227
  return child_items
221
228
 
222
229
  def append(self, item: TracedItem) -> None:
@@ -334,6 +341,8 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
334
341
  css_class = 'log'
335
342
  elif isinstance(item, ExecutionTrace):
336
343
  css_class = 'phase'
344
+ elif isinstance(item, ParallelExecutions):
345
+ css_class = 'parallel'
337
346
  else:
338
347
  raise ValueError(f'Unsupported item type: {type(item)}')
339
348
 
@@ -383,6 +392,11 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
383
392
  item.name or 'Phase',
384
393
  tooltip=f'Execution phase {item.name!r}.'
385
394
  )
395
+ elif isinstance(item, ParallelExecutions):
396
+ return pg.views.html.controls.Label(
397
+ item.name or 'Parallel',
398
+ tooltip='Parallel executions.'
399
+ )
386
400
  else:
387
401
  raise ValueError(f'Unsupported item type: {type(item)}')
388
402
 
@@ -401,6 +415,12 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
401
415
  color: purple;
402
416
  padding: 10px;
403
417
  }
418
+ .tab-button.parallel > ::before {
419
+ content: "||";
420
+ font-weight: bold;
421
+ color: blue;
422
+ padding: 10px;
423
+ }
404
424
  .tab-button.query > ::before {
405
425
  content: "Q";
406
426
  font-weight: bold;
@@ -439,6 +459,79 @@ class ExecutionTrace(pg.Object, pg.views.html.HtmlTreeView.Extension):
439
459
  ]
440
460
 
441
461
 
462
+ class ParallelExecutions(pg.Object, pg.views.html.HtmlTreeView.Extension):
463
+ """A class for encapsulating parallel execution traces."""
464
+
465
+ name: Annotated[
466
+ str | None,
467
+ 'The name of the parallel execution.'
468
+ ] = None
469
+
470
+ branches: Annotated[
471
+ list[ExecutionTrace],
472
+ 'The branches of the parallel execution.'
473
+ ] = []
474
+
475
+ def __getitem__(self, key: int) -> ExecutionTrace:
476
+ return self.branches[key]
477
+
478
+ def __len__(self) -> int:
479
+ return len(self.branches)
480
+
481
+ def _on_bound(self):
482
+ super()._on_bound()
483
+ self._tab_control = None
484
+ self._lock = threading.Lock()
485
+
486
+ def add(self) -> ExecutionTrace:
487
+ """Appends a branch to the parallel execution."""
488
+ with self._lock, pg.notify_on_change(False):
489
+ branch = ExecutionTrace(name=f'[{len(self)}]')
490
+ self.branches.append(branch)
491
+ if self._tab_control is not None:
492
+ self._tab_control.append(self._branch_tab(branch))
493
+ return branch
494
+
495
+ #
496
+ # HTML views.
497
+ #
498
+
499
+ def _html_tree_view_summary(
500
+ self,
501
+ *,
502
+ name: str | None = None,
503
+ extra_flags: dict[str, Any] | None = None,
504
+ view: pg.views.html.HtmlTreeView, **kwargs
505
+ ):
506
+ return None
507
+
508
+ def _html_tree_view_content(
509
+ self,
510
+ *,
511
+ extra_flags: dict[str, Any] | None = None,
512
+ **kwargs
513
+ ):
514
+ del kwargs
515
+ extra_flags = extra_flags or {}
516
+ interactive = extra_flags.get('interactive', True)
517
+ if interactive or self.branches:
518
+ self._tab_control = pg.views.html.controls.TabControl(
519
+ [self._branch_tab(branch) for branch in self.branches],
520
+ tab_position='left'
521
+ )
522
+ return self._tab_control.to_html()
523
+ return '(no tracked parallel executions)'
524
+
525
+ def _branch_tab(self, branch: ExecutionTrace) -> pg.views.html.controls.Tab:
526
+ return pg.views.html.controls.Tab(
527
+ label=pg.views.html.controls.Label(
528
+ branch.name,
529
+ tooltip=f'Execution thread {branch.name!r}.'
530
+ ),
531
+ content=pg.view(branch),
532
+ )
533
+
534
+
442
535
  class ActionInvocation(pg.Object, pg.views.html.HtmlTreeView.Extension):
443
536
  """A class for capturing the invocation of an action."""
444
537
  action: Action
@@ -463,28 +556,8 @@ class ActionInvocation(pg.Object, pg.views.html.HtmlTreeView.Extension):
463
556
 
464
557
  def _on_bound(self):
465
558
  super()._on_bound()
466
- self._current_phase = self.execution
467
559
  self._tab_control = None
468
560
 
469
- @property
470
- def current_phase(self) -> ExecutionTrace:
471
- """Returns the current execution phase."""
472
- return self._current_phase
473
-
474
- @contextlib.contextmanager
475
- def phase(self, name: str) -> Iterator[ExecutionTrace]:
476
- """Context manager for starting a new execution phase."""
477
- phase = ExecutionTrace(name=name)
478
- phase.start()
479
- parent_phase = self._current_phase
480
- self._current_phase.append(phase)
481
- self._current_phase = phase
482
- try:
483
- yield phase
484
- finally:
485
- phase.stop()
486
- self._current_phase = parent_phase
487
-
488
561
  @property
489
562
  def logs(self) -> list[lf.logging.LogEntry]:
490
563
  """Returns immediate child logs from execution sequence."""
@@ -679,52 +752,80 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
679
752
  'An optional identifier for the sessin, which will be used for logging.'
680
753
  ] = None
681
754
 
682
- def _on_bound(self):
683
- super()._on_bound()
684
- self._current_action = self.root
755
+ # NOTE(daiyip): Action execution may involve multi-threading, hence current
756
+ # action and execution are thread-local.
685
757
 
686
758
  @property
687
- def final_result(self) -> Any:
688
- """Returns the final result of the session."""
689
- return self.root.result
759
+ def _current_action(self) -> ActionInvocation:
760
+ """Returns the current invocation."""
761
+ return getattr(self._tls, '__current_action__')
762
+
763
+ @_current_action.setter
764
+ def _current_action(self, value: ActionInvocation):
765
+ setattr(self._tls, '__current_action__', value)
690
766
 
691
767
  @property
692
- def current_action(self) -> ActionInvocation:
693
- """Returns the current invocation."""
694
- return self._current_action
768
+ def _current_execution(self) -> ExecutionTrace:
769
+ """Returns the current execution."""
770
+ return getattr(self._tls, '__current_execution__')
695
771
 
696
- def add_metadata(self, **kwargs: Any) -> None:
697
- """Adds metadata to the current invocation."""
698
- with pg.notify_on_change(False):
699
- self._current_action.metadata.update(kwargs)
772
+ @_current_execution.setter
773
+ def _current_execution(self, value: ExecutionTrace):
774
+ setattr(self._tls, '__current_execution__', value)
700
775
 
701
- def phase(self, name: str) -> ContextManager[ExecutionTrace]:
702
- """Context manager for starting a new execution phase."""
703
- return self.current_action.phase(name)
776
+ def _on_bound(self):
777
+ super()._on_bound()
778
+ self._tls = threading.local()
779
+ self._current_action = self.root
780
+ self._current_execution = self.root.execution
781
+
782
+ #
783
+ # Context-manager for information tracking.
784
+ #
704
785
 
705
786
  @contextlib.contextmanager
706
787
  def track_action(self, action: Action) -> Iterator[ActionInvocation]:
707
788
  """Track the execution of an action."""
708
- if not self.root.execution.has_started:
709
- self.root.start()
789
+ if not self._current_execution.has_started:
790
+ self._current_execution.start()
710
791
 
711
792
  invocation = ActionInvocation(pg.maybe_ref(action))
712
793
  parent_action = self._current_action
713
- parent_action.current_phase.append(invocation)
794
+ parent_execution = self._current_execution
795
+ parent_execution.append(invocation)
714
796
 
715
797
  try:
716
798
  self._current_action = invocation
799
+ self._current_execution = invocation.execution
717
800
  # Start the execution of the current action.
718
801
  self._current_action.start()
719
802
  yield invocation
720
803
  finally:
721
804
  # Stop the execution of the current action.
722
- self._current_action.end(action.result, action.metadata)
805
+ invocation.end(action.result, action.metadata)
806
+ self._current_execution = parent_execution
723
807
  self._current_action = parent_action
724
808
  if parent_action is self.root:
725
- parent_action.end(
726
- result=action.result, metadata=action.metadata,
727
- )
809
+ parent_action.end(result=action.result, metadata=action.metadata)
810
+
811
+ @contextlib.contextmanager
812
+ def track_phase(self, name: str | None) -> Iterator[ExecutionTrace]:
813
+ """Context manager for starting a new execution phase."""
814
+ parent_execution = self._current_execution
815
+ if name is None:
816
+ phase = parent_execution
817
+ else:
818
+ phase = ExecutionTrace(name=name)
819
+ phase.start()
820
+ parent_execution.append(phase)
821
+
822
+ try:
823
+ self._current_execution = phase
824
+ yield phase
825
+ finally:
826
+ if phase is not parent_execution:
827
+ phase.stop()
828
+ self._current_execution = parent_execution
728
829
 
729
830
  @contextlib.contextmanager
730
831
  def track_queries(
@@ -741,12 +842,21 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
741
842
  A list of `lf.QueryInvocation` objects, each for a single `lf.query`
742
843
  call.
743
844
  """
744
- with self.phase(phase) if phase else contextlib.nullcontext():
845
+ with self.track_phase(phase) as execution:
745
846
  with lf_structured.track_queries(include_child_scopes=False) as queries:
746
847
  try:
747
848
  yield queries
748
849
  finally:
749
- self._current_action.current_phase.extend(queries)
850
+ execution.extend(queries)
851
+
852
+ #
853
+ # Operations with activity tracking.
854
+ #
855
+
856
+ def add_metadata(self, **kwargs: Any) -> None:
857
+ """Adds metadata to the current invocation."""
858
+ with pg.notify_on_change(False):
859
+ self._current_action.metadata.update(kwargs)
750
860
 
751
861
  def query(
752
862
  self,
@@ -785,7 +895,7 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
785
895
  lm: The language model to use for the query.
786
896
  examples: The examples to use for the query.
787
897
  **kwargs: Additional keyword arguments to pass to `lf.query`.
788
-
898
+
789
899
  Returns:
790
900
  The result of the query.
791
901
  """
@@ -799,6 +909,49 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
799
909
  **kwargs
800
910
  )
801
911
 
912
+ def concurrent_map(
913
+ self,
914
+ func: Callable[[Any], Any],
915
+ parallel_inputs: Iterable[Any],
916
+ *,
917
+ phase: str | None = None,
918
+ max_workers: int = 32,
919
+ timeout: int | None = None,
920
+ silence_on_errors: Union[
921
+ Type[BaseException], tuple[Type[BaseException], ...], None
922
+ ] = Exception
923
+ ) -> Iterator[Any]:
924
+ """Starts and tracks parallel execution with `lf.concurrent_map`."""
925
+ parallel_inputs = list(parallel_inputs)
926
+ parallel_execution = ParallelExecutions(name=phase)
927
+ self._current_execution.append(parallel_execution)
928
+ parent_action = self._current_action
929
+
930
+ def _map_single(input_value):
931
+ execution = parallel_execution.add()
932
+
933
+ # This happens on a new thread. Therefore, we update the thread-local
934
+ # states from the parent thread.
935
+ self._current_execution = execution
936
+ self._current_action = parent_action
937
+ execution.start()
938
+ try:
939
+ with self.track_queries():
940
+ return func(input_value)
941
+ finally:
942
+ execution.stop()
943
+
944
+ for input_value, result, error in lf.concurrent_map(
945
+ _map_single,
946
+ parallel_inputs,
947
+ max_workers=max_workers,
948
+ timeout=timeout,
949
+ silence_on_errors=silence_on_errors
950
+ ):
951
+ yield input_value, result, error
952
+
953
+ # NOTE(daiyip): Clean up `query_prompt` and `query_output` once TS
954
+ # code migration is done.
802
955
  def query_prompt(
803
956
  self,
804
957
  prompt: Union[str, lf.Template, Any],
@@ -878,7 +1031,7 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
878
1031
  return lf_structured.query_output(response, schema=schema, **kwargs)
879
1032
 
880
1033
  def _log(self, level: lf.logging.LogLevel, message: str, **kwargs):
881
- self._current_action.current_phase.append(
1034
+ self._current_execution.append(
882
1035
  lf.logging.LogEntry(
883
1036
  level=level,
884
1037
  time=datetime.datetime.now(),
@@ -914,6 +1067,16 @@ class Session(pg.Object, pg.views.html.HtmlTreeView.Extension):
914
1067
  result=self.root
915
1068
  )
916
1069
 
1070
+ @property
1071
+ def final_result(self) -> Any:
1072
+ """Returns the final result of the session."""
1073
+ return self.root.result
1074
+
1075
+ @property
1076
+ def current_action(self) -> ActionInvocation:
1077
+ """Returns the current invocation."""
1078
+ return self._current_action
1079
+
917
1080
  #
918
1081
  # HTML views.
919
1082
  #
@@ -41,12 +41,23 @@ class SessionTest(unittest.TestCase):
41
41
 
42
42
  def call(self, session, *, lm, **kwargs):
43
43
  test.assertIs(session.current_action.action, self)
44
- with session.phase('prepare'):
44
+ with session.track_phase('prepare'):
45
45
  session.info('Begin Foo', x=1)
46
46
  session.query('foo', lm=lm)
47
47
  with session.track_queries():
48
48
  self.make_additional_query(lm)
49
49
  session.add_metadata(note='foo')
50
+
51
+ def _sub_task(i):
52
+ session.add_metadata(**{f'subtask_{i}': i})
53
+ return lf_structured.query(f'subtask_{i}', lm=lm)
54
+
55
+ for i, output, error in session.concurrent_map(
56
+ _sub_task, range(3), max_workers=2, silence_on_errors=None,
57
+ ):
58
+ assert isinstance(i, int), i
59
+ assert isinstance(output, str), output
60
+ assert error is None, error
50
61
  return self.x + Bar()(session, lm=lm)
51
62
 
52
63
  def make_additional_query(self, lm):
@@ -73,21 +84,24 @@ class SessionTest(unittest.TestCase):
73
84
  self.assertTrue(root.execution.has_stopped)
74
85
  self.assertGreater(root.execution.elapse, 0)
75
86
  self.assertEqual(root.result, 3)
76
- self.assertEqual(root.metadata, dict(note='foo'))
87
+ self.assertEqual(
88
+ root.metadata,
89
+ dict(note='foo', subtask_0=0, subtask_1=1, subtask_2=2)
90
+ )
77
91
 
78
92
  # The root space should have one action (foo), no queries, and no logs.
79
93
  self.assertEqual(len(list(root.actions)), 1)
80
94
  self.assertEqual(len(list(root.queries)), 0)
81
95
  self.assertEqual(len(list(root.logs)), 0)
82
- # 1 query from Bar and 2 from Foo.
83
- self.assertEqual(len(list(root.all_queries)), 3)
96
+ # 1 query from Bar, 2 from Foo and 3 from parallel executions.
97
+ self.assertEqual(len(list(root.all_queries)), 6)
84
98
  # 1 log from Bar and 1 from Foo.
85
99
  self.assertEqual(len(list(root.all_logs)), 2)
86
- self.assertEqual(root.usage_summary.total.num_requests, 3)
100
+ self.assertEqual(root.usage_summary.total.num_requests, 6)
87
101
 
88
102
  # Inspecting the top-level action (Foo)
89
103
  foo_invocation = root.execution.items[0]
90
- self.assertEqual(len(foo_invocation.execution.items), 3)
104
+ self.assertEqual(len(foo_invocation.execution.items), 4)
91
105
 
92
106
  # Prepare phase.
93
107
  prepare_phase = foo_invocation.execution.items[0]
@@ -104,8 +118,16 @@ class SessionTest(unittest.TestCase):
104
118
  self.assertIsInstance(query_invocation, lf_structured.QueryInvocation)
105
119
  self.assertIs(query_invocation.lm, lm)
106
120
 
121
+ # Tracked parallel executions.
122
+ parallel_executions = foo_invocation.execution.items[2]
123
+ self.assertIsInstance(parallel_executions, action_lib.ParallelExecutions)
124
+ self.assertEqual(len(parallel_executions), 3)
125
+ self.assertEqual(len(parallel_executions[0].queries), 1)
126
+ self.assertEqual(len(parallel_executions[1].queries), 1)
127
+ self.assertEqual(len(parallel_executions[2].queries), 1)
128
+
107
129
  # Invocation to Bar.
108
- bar_invocation = foo_invocation.execution.items[2]
130
+ bar_invocation = foo_invocation.execution.items[3]
109
131
  self.assertIsInstance(bar_invocation, action_lib.ActionInvocation)
110
132
  self.assertIsInstance(bar_invocation.action, Bar)
111
133
  self.assertEqual(bar_invocation.result, 2)
@@ -89,11 +89,21 @@ class REST(lf.LanguageModel):
89
89
  timeout=self.timeout,
90
90
  )
91
91
  )
92
- except (requests.exceptions.ReadTimeout,
93
- requests.exceptions.ConnectTimeout) as e:
92
+ except (
93
+ requests.exceptions.Timeout,
94
+ requests.exceptions.ReadTimeout,
95
+ requests.exceptions.ConnectTimeout,
96
+ TimeoutError,
97
+ ) as e:
94
98
  raise lf.TemporaryLMError(str(e)) from e
95
- except ConnectionError as e:
96
- raise lf.LMError(str(e)) from e
99
+ except (
100
+ requests.exceptions.ConnectionError,
101
+ ConnectionError,
102
+ ) as e:
103
+ error_message = str(e)
104
+ if 'REJECTED_CLIENT_THROTTLED' in error_message:
105
+ raise lf.TemporaryLMError(error_message) from e
106
+ raise lf.LMError(error_message) from e
97
107
 
98
108
  def _error(self, status_code: int, content: str) -> lf.LMError:
99
109
  if status_code == 429:
@@ -38,6 +38,13 @@ def mock_requests_post(url: str, json: dict[str, Any], **kwargs):
38
38
  return response
39
39
 
40
40
 
41
+ def mock_requests_post_exception(error):
42
+ def _mock_requests(url: str, json: dict[str, Any], **kwargs):
43
+ del url, json, kwargs
44
+ raise error
45
+ return _mock_requests
46
+
47
+
41
48
  def mock_requests_post_error(status_code, error_type, error_message):
42
49
  def _mock_requests(url: str, json: dict[str, Any], **kwargs):
43
50
  del url, json, kwargs
@@ -106,6 +113,50 @@ class RestTest(unittest.TestCase):
106
113
  ):
107
114
  self._lm('hello', max_attempts=1)
108
115
 
116
+ for error, expected_lm_error_cls, expected_lm_error_msg in [
117
+ (
118
+ requests.exceptions.Timeout('Timeout.'),
119
+ lf.TemporaryLMError,
120
+ 'Timeout.',
121
+ ),
122
+ (
123
+ requests.exceptions.ReadTimeout('Read timeout.'),
124
+ lf.TemporaryLMError,
125
+ 'Read timeout.',
126
+ ),
127
+ (
128
+ requests.exceptions.ConnectTimeout('Connect timeout.'),
129
+ lf.TemporaryLMError,
130
+ 'Connect timeout.',
131
+ ),
132
+ (
133
+ TimeoutError('Timeout error.'),
134
+ lf.TemporaryLMError,
135
+ 'Timeout error.',
136
+ ),
137
+ (
138
+ requests.exceptions.ConnectionError('REJECTED_CLIENT_THROTTLED'),
139
+ lf.TemporaryLMError,
140
+ 'REJECTED_CLIENT_THROTTLED',
141
+ ),
142
+ (
143
+ requests.exceptions.ConnectionError('Connection error.'),
144
+ lf.LMError,
145
+ 'Connection error.',
146
+ ),
147
+ (
148
+ ConnectionError('Connection error.'),
149
+ lf.LMError,
150
+ 'Connection error.',
151
+ )
152
+ ]:
153
+ with mock.patch('requests.Session.post') as mock_post:
154
+ mock_post.side_effect = mock_requests_post_exception(error)
155
+ with self.assertRaisesRegex(
156
+ expected_lm_error_cls, expected_lm_error_msg
157
+ ):
158
+ self._lm._sample_single(lf.UserMessage('hello'))
159
+
109
160
 
110
161
  if __name__ == '__main__':
111
162
  unittest.main()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202503190804
3
+ Version: 0.1.2.dev202503210804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -53,6 +53,7 @@ Dynamic: description-content-type
53
53
  Dynamic: home-page
54
54
  Dynamic: keywords
55
55
  Dynamic: license
56
+ Dynamic: license-file
56
57
  Dynamic: provides-extra
57
58
  Dynamic: requires-dist
58
59
  Dynamic: summary