langwatch-scenario 0.4.0__py3-none-any.whl → 0.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. {langwatch_scenario-0.4.0.dist-info → langwatch_scenario-0.7.1.dist-info}/METADATA +210 -86
  2. langwatch_scenario-0.7.1.dist-info/RECORD +237 -0
  3. scenario/__init__.py +12 -118
  4. scenario/_events/__init__.py +64 -0
  5. scenario/_events/event_bus.py +185 -0
  6. scenario/_events/event_reporter.py +83 -0
  7. scenario/_events/events.py +162 -0
  8. scenario/_events/messages.py +58 -0
  9. scenario/_events/utils.py +97 -0
  10. scenario/_generated/langwatch_api_client/README.md +139 -0
  11. scenario/_generated/langwatch_api_client/lang_watch_api_client/__init__.py +13 -0
  12. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/__init__.py +1 -0
  13. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/__init__.py +1 -0
  14. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/delete_api_annotations_id.py +155 -0
  15. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/delete_api_prompts_by_id.py +218 -0
  16. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/delete_api_scenario_events.py +183 -0
  17. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_annotations.py +136 -0
  18. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_annotations_id.py +155 -0
  19. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_annotations_trace_id.py +160 -0
  20. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_dataset_by_slug_or_id.py +229 -0
  21. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_prompts.py +188 -0
  22. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_prompts_by_id.py +218 -0
  23. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_prompts_by_id_versions.py +218 -0
  24. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/get_api_trace_id.py +155 -0
  25. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/patch_api_annotations_id.py +178 -0
  26. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_annotations_trace_id.py +178 -0
  27. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_dataset_by_slug_entries.py +108 -0
  28. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_prompts.py +187 -0
  29. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_prompts_by_id_versions.py +241 -0
  30. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_scenario_events.py +229 -0
  31. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_trace_id_share.py +155 -0
  32. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/post_api_trace_id_unshare.py +155 -0
  33. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/default/put_api_prompts_by_id.py +241 -0
  34. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/traces/__init__.py +1 -0
  35. scenario/_generated/langwatch_api_client/lang_watch_api_client/api/traces/post_api_trace_search.py +168 -0
  36. scenario/_generated/langwatch_api_client/lang_watch_api_client/client.py +268 -0
  37. scenario/_generated/langwatch_api_client/lang_watch_api_client/errors.py +16 -0
  38. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/__init__.py +455 -0
  39. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/annotation.py +131 -0
  40. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/dataset_post_entries.py +74 -0
  41. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/dataset_post_entries_entries_item.py +44 -0
  42. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_annotations_id_response_200.py +68 -0
  43. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_200.py +59 -0
  44. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_400.py +61 -0
  45. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_400_error.py +8 -0
  46. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_401.py +61 -0
  47. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_401_error.py +8 -0
  48. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_404.py +59 -0
  49. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_prompts_by_id_response_500.py +59 -0
  50. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_scenario_events_response_200.py +81 -0
  51. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_scenario_events_response_400.py +59 -0
  52. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_scenario_events_response_401.py +59 -0
  53. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/delete_api_scenario_events_response_500.py +59 -0
  54. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/error.py +67 -0
  55. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/evaluation.py +164 -0
  56. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/evaluation_timestamps.py +68 -0
  57. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_200.py +75 -0
  58. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_200_data_item.py +109 -0
  59. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_200_data_item_entry.py +44 -0
  60. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_400.py +78 -0
  61. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_401.py +78 -0
  62. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_404.py +78 -0
  63. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_422.py +67 -0
  64. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_dataset_by_slug_or_id_response_500.py +78 -0
  65. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200.py +172 -0
  66. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_messages_item.py +69 -0
  67. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_messages_item_role.py +10 -0
  68. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_response_format_type_0.py +81 -0
  69. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_response_format_type_0_json_schema.py +77 -0
  70. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_response_format_type_0_json_schema_schema.py +44 -0
  71. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_200_response_format_type_0_type.py +8 -0
  72. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_400.py +61 -0
  73. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_400_error.py +8 -0
  74. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_401.py +61 -0
  75. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_401_error.py +8 -0
  76. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_404.py +59 -0
  77. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_response_500.py +59 -0
  78. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200.py +155 -0
  79. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data.py +204 -0
  80. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_demonstrations.py +101 -0
  81. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_demonstrations_columns_item.py +79 -0
  82. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_demonstrations_columns_item_type.py +18 -0
  83. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_demonstrations_rows_item.py +59 -0
  84. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_inputs_item.py +71 -0
  85. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_inputs_item_type.py +16 -0
  86. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_messages_item.py +71 -0
  87. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_messages_item_role.py +10 -0
  88. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_outputs_item.py +98 -0
  89. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_outputs_item_json_schema.py +59 -0
  90. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_outputs_item_type.py +11 -0
  91. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_200_config_data_prompting_technique.py +59 -0
  92. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_400.py +61 -0
  93. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_400_error.py +8 -0
  94. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_401.py +61 -0
  95. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_401_error.py +8 -0
  96. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_404.py +59 -0
  97. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_by_id_versions_response_500.py +59 -0
  98. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item.py +172 -0
  99. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_messages_item.py +69 -0
  100. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_messages_item_role.py +10 -0
  101. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_response_format_type_0.py +81 -0
  102. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_response_format_type_0_json_schema.py +77 -0
  103. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_response_format_type_0_json_schema_schema.py +44 -0
  104. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_200_item_response_format_type_0_type.py +8 -0
  105. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_400.py +61 -0
  106. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_400_error.py +8 -0
  107. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_401.py +61 -0
  108. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_401_error.py +8 -0
  109. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_prompts_response_500.py +59 -0
  110. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200.py +249 -0
  111. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_error_type_0.py +79 -0
  112. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_evaluations_item.py +152 -0
  113. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_evaluations_item_error.py +79 -0
  114. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_evaluations_item_timestamps.py +68 -0
  115. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_input.py +59 -0
  116. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_metadata.py +68 -0
  117. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_metrics.py +95 -0
  118. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_output.py +59 -0
  119. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item.py +271 -0
  120. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_error_type_0.py +79 -0
  121. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_input.py +90 -0
  122. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_input_value_item.py +69 -0
  123. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_metrics.py +77 -0
  124. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_output.py +89 -0
  125. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_output_value_item.py +68 -0
  126. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_params.py +68 -0
  127. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_spans_item_timestamps.py +95 -0
  128. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/get_api_trace_id_response_200_timestamps.py +77 -0
  129. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/input_.py +68 -0
  130. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/metadata.py +68 -0
  131. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/metrics.py +115 -0
  132. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/output.py +59 -0
  133. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/pagination.py +68 -0
  134. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/patch_api_annotations_id_body.py +77 -0
  135. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/patch_api_annotations_id_response_200.py +68 -0
  136. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_annotations_trace_id_body.py +77 -0
  137. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_body.py +59 -0
  138. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body.py +147 -0
  139. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data.py +207 -0
  140. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_demonstrations.py +106 -0
  141. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_demonstrations_columns_item.py +79 -0
  142. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_demonstrations_columns_item_type.py +18 -0
  143. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_demonstrations_rows_item.py +59 -0
  144. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_inputs_item.py +71 -0
  145. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_inputs_item_type.py +16 -0
  146. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_messages_item.py +71 -0
  147. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_messages_item_role.py +10 -0
  148. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_outputs_item.py +98 -0
  149. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_outputs_item_json_schema.py +59 -0
  150. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_outputs_item_type.py +11 -0
  151. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_body_config_data_prompting_technique.py +59 -0
  152. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200.py +155 -0
  153. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data.py +206 -0
  154. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_demonstrations.py +101 -0
  155. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_demonstrations_columns_item.py +79 -0
  156. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_demonstrations_columns_item_type.py +18 -0
  157. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_demonstrations_rows_item.py +59 -0
  158. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_inputs_item.py +71 -0
  159. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_inputs_item_type.py +16 -0
  160. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_messages_item.py +71 -0
  161. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_messages_item_role.py +10 -0
  162. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_outputs_item.py +98 -0
  163. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_outputs_item_json_schema.py +59 -0
  164. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_outputs_item_type.py +11 -0
  165. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_200_config_data_prompting_technique.py +59 -0
  166. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_400.py +61 -0
  167. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_400_error.py +8 -0
  168. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_401.py +61 -0
  169. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_401_error.py +8 -0
  170. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_404.py +59 -0
  171. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_by_id_versions_response_500.py +59 -0
  172. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200.py +172 -0
  173. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_messages_item.py +69 -0
  174. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_messages_item_role.py +10 -0
  175. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_response_format_type_0.py +81 -0
  176. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_response_format_type_0_json_schema.py +77 -0
  177. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_response_format_type_0_json_schema_schema.py +44 -0
  178. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_200_response_format_type_0_type.py +8 -0
  179. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_400.py +61 -0
  180. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_400_error.py +8 -0
  181. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_401.py +61 -0
  182. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_401_error.py +8 -0
  183. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_prompts_response_500.py +59 -0
  184. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_0.py +127 -0
  185. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_0_metadata.py +68 -0
  186. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_1.py +164 -0
  187. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_1_results_type_0.py +98 -0
  188. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_1_results_type_0_verdict.py +10 -0
  189. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_1_status.py +13 -0
  190. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2.py +245 -0
  191. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_0.py +88 -0
  192. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_1.py +88 -0
  193. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_2.py +120 -0
  194. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_2_tool_calls_item.py +87 -0
  195. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_2_tool_calls_item_function.py +67 -0
  196. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_3.py +88 -0
  197. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_body_type_2_messages_item_type_4.py +85 -0
  198. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_response_201.py +81 -0
  199. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_response_400.py +59 -0
  200. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_response_401.py +59 -0
  201. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_scenario_events_response_500.py +59 -0
  202. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_trace_id_share_response_200.py +59 -0
  203. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/post_api_trace_id_unshare_response_200.py +59 -0
  204. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_body.py +59 -0
  205. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_200.py +75 -0
  206. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_400.py +61 -0
  207. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_400_error.py +8 -0
  208. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_401.py +61 -0
  209. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_401_error.py +8 -0
  210. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_404.py +59 -0
  211. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/put_api_prompts_by_id_response_500.py +59 -0
  212. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/search_request.py +133 -0
  213. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/search_request_filters.py +51 -0
  214. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/search_response.py +93 -0
  215. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/timestamps.py +77 -0
  216. scenario/_generated/langwatch_api_client/lang_watch_api_client/models/trace.py +225 -0
  217. scenario/_generated/langwatch_api_client/lang_watch_api_client/py.typed +1 -0
  218. scenario/_generated/langwatch_api_client/lang_watch_api_client/types.py +46 -0
  219. scenario/_generated/langwatch_api_client/pyproject.toml +27 -0
  220. scenario/_utils/__init__.py +32 -0
  221. scenario/_utils/ids.py +58 -0
  222. scenario/_utils/message_conversion.py +103 -0
  223. scenario/{utils.py → _utils/utils.py} +21 -110
  224. scenario/agent_adapter.py +8 -4
  225. scenario/cache.py +4 -3
  226. scenario/config.py +7 -5
  227. scenario/judge_agent.py +13 -29
  228. scenario/pytest_plugin.py +6 -51
  229. scenario/scenario_executor.py +372 -215
  230. scenario/scenario_state.py +6 -6
  231. scenario/script.py +9 -9
  232. scenario/types.py +15 -8
  233. scenario/user_simulator_agent.py +4 -11
  234. langwatch_scenario-0.4.0.dist-info/RECORD +0 -18
  235. {langwatch_scenario-0.4.0.dist-info → langwatch_scenario-0.7.1.dist-info}/WHEEL +0 -0
  236. {langwatch_scenario-0.4.0.dist-info → langwatch_scenario-0.7.1.dist-info}/entry_points.txt +0 -0
  237. {langwatch_scenario-0.4.0.dist-info → langwatch_scenario-0.7.1.dist-info}/top_level.txt +0 -0
  238. /scenario/{error_messages.py → _error_messages.py} +0 -0
@@ -0,0 +1,185 @@
1
+ from rx.core.observable.observable import Observable
2
+ from typing import Optional, Any
3
+ from .events import ScenarioEvent
4
+ from .event_reporter import EventReporter
5
+
6
+ import asyncio
7
+ import queue
8
+ import threading
9
+ import logging
10
+
11
+ class ScenarioEventBus:
12
+ """
13
+ Subscribes to scenario event streams and handles HTTP posting using a dedicated worker thread.
14
+
15
+ The EventBus acts as an observer of scenario events, automatically
16
+ posting them to external APIs. It uses a queue-based threading model
17
+ where events are processed by a dedicated worker thread.
18
+
19
+ Key design principles:
20
+ - Single worker thread handles all HTTP posting (simplifies concurrency)
21
+ - Thread created lazily when first event arrives
22
+ - Thread terminates when queue empty and stream completed
23
+ - Non-daemon thread ensures all events posted before program exit
24
+
25
+ Attributes:
26
+ _event_reporter: EventReporter instance for HTTP posting of events
27
+ _max_retries: Maximum number of retry attempts for failed event processing
28
+ _event_queue: Thread-safe queue for passing events to worker thread
29
+ _completed: Whether the event stream has completed
30
+ _subscription: RxPY subscription to the event stream
31
+ _worker_thread: Dedicated thread for processing events
32
+ """
33
+
34
+ def __init__(
35
+ self, event_reporter: Optional[EventReporter] = None, max_retries: int = 3
36
+ ):
37
+ """
38
+ Initialize the event bus with optional event reporter and retry configuration.
39
+
40
+ Args:
41
+ event_reporter: Optional EventReporter for HTTP posting of events.
42
+ If not provided, a default EventReporter will be created.
43
+ max_retries: Maximum number of retry attempts for failed event processing.
44
+ Defaults to 3 attempts with exponential backoff.
45
+ """
46
+ self._event_reporter: EventReporter = event_reporter or EventReporter()
47
+ self._max_retries = max_retries
48
+
49
+ # Custom logger for this class
50
+ self.logger = logging.getLogger(__name__)
51
+
52
+ # Threading infrastructure
53
+ self._event_queue: queue.Queue[ScenarioEvent] = queue.Queue()
54
+ self._completed = False
55
+ self._subscription: Optional[Any] = None
56
+ self._worker_thread: Optional[threading.Thread] = None
57
+ self._shutdown_event = threading.Event() # Signal worker to shutdown
58
+
59
+ def _get_or_create_worker(self) -> None:
60
+ """Lazily create worker thread when first event arrives"""
61
+ if self._worker_thread is None or not self._worker_thread.is_alive():
62
+ self.logger.debug("Creating new worker thread")
63
+ self._worker_thread = threading.Thread(
64
+ target=self._worker_loop,
65
+ daemon=False,
66
+ name="ScenarioEventBus-Worker"
67
+ )
68
+ self._worker_thread.start()
69
+ self.logger.debug("Worker thread started")
70
+
71
+ def _worker_loop(self) -> None:
72
+ """Main worker thread loop - processes events from queue until shutdown"""
73
+ self.logger.debug("Worker thread loop started")
74
+ while True:
75
+ try:
76
+ if self._shutdown_event.wait(timeout=0.1):
77
+ self.logger.debug("Worker thread received shutdown signal")
78
+ break
79
+
80
+ try:
81
+ event = self._event_queue.get(timeout=0.1)
82
+ self.logger.debug(f"Worker picked up event: {event.type_} ({event.scenario_run_id})")
83
+ self._process_event_sync(event)
84
+ self._event_queue.task_done()
85
+ except queue.Empty:
86
+ # Exit if stream completed and no more events
87
+ if self._completed:
88
+ self.logger.debug("Stream completed and no more events, worker thread exiting")
89
+ break
90
+ continue
91
+
92
+ except Exception as e:
93
+ self.logger.error(f"Worker thread error: {e}")
94
+
95
+ self.logger.debug("Worker thread loop ended")
96
+
97
+ def _process_event_sync(self, event: ScenarioEvent) -> None:
98
+ """
99
+ Process event synchronously in worker thread with retry logic.
100
+ """
101
+ self.logger.debug(f"Processing HTTP post for {event.type_} ({event.scenario_run_id})")
102
+
103
+ try:
104
+ # Convert async to sync using asyncio.run - this blocks until HTTP completes
105
+ success = asyncio.run(self._process_event_with_retry(event))
106
+ if not success:
107
+ self.logger.warning(f"Failed to process event {event.type_} after {self._max_retries} attempts")
108
+ else:
109
+ self.logger.debug(f"Successfully posted {event.type_} ({event.scenario_run_id})")
110
+ except Exception as e:
111
+ self.logger.error(f"Error processing event {event.type_}: {e}")
112
+
113
+ async def _process_event_with_retry(self, event: ScenarioEvent, attempt: int = 1) -> bool:
114
+ """
115
+ Process a single event with retry logic (now runs in worker thread context).
116
+ """
117
+ try:
118
+ if self._event_reporter:
119
+ await self._event_reporter.post_event(event)
120
+ return True
121
+ except Exception as e:
122
+ if attempt >= self._max_retries:
123
+ return False
124
+ print(f"Error processing event (attempt {attempt}/{self._max_retries}): {e}")
125
+ await asyncio.sleep(0.1 * (2 ** (attempt - 1))) # Exponential backoff
126
+ return await self._process_event_with_retry(event, attempt + 1)
127
+
128
+ def subscribe_to_events(self, event_stream: Observable) -> None:
129
+ """
130
+ Subscribe to any observable stream of scenario events.
131
+ Events are queued for processing by the dedicated worker thread.
132
+ """
133
+ if self._subscription is not None:
134
+ self.logger.debug("Already subscribed to event stream")
135
+ return
136
+
137
+ def handle_event(event: ScenarioEvent) -> None:
138
+ self.logger.debug(f"Event received, queuing: {event.type_} ({event.scenario_run_id})")
139
+ self._get_or_create_worker()
140
+ self._event_queue.put(event)
141
+ self.logger.debug(f"Event queued: {event.type_} ({event.scenario_run_id})")
142
+
143
+ self.logger.info("Subscribing to event stream")
144
+ self._subscription = event_stream.subscribe(
145
+ handle_event,
146
+ lambda e: self.logger.error(f"Error in event stream: {e}"),
147
+ lambda: self._set_completed()
148
+ )
149
+
150
+ def _set_completed(self):
151
+ """Helper to set completed state with logging"""
152
+ self.logger.debug("Event stream completed")
153
+ self._completed = True
154
+
155
+ def drain(self) -> None:
156
+ """
157
+ Waits for all queued events to complete processing.
158
+
159
+ This method blocks until all events in the queue have been processed.
160
+ Since _process_event_sync() uses asyncio.run(), HTTP requests complete
161
+ before task_done() is called, so join() ensures everything is finished.
162
+ """
163
+ self.logger.debug("Drain started - waiting for queue to empty")
164
+
165
+ # Wait for all events to be processed - this is sufficient!
166
+ self._event_queue.join()
167
+ self.logger.debug("Event queue drained")
168
+
169
+ # Signal worker to shutdown and wait for it
170
+ self._shutdown_event.set()
171
+ if self._worker_thread and self._worker_thread.is_alive():
172
+ self.logger.debug("Waiting for worker thread to shutdown...")
173
+ self._worker_thread.join(timeout=5.0)
174
+ if self._worker_thread.is_alive():
175
+ self.logger.warning("Worker thread did not shutdown within timeout")
176
+ else:
177
+ self.logger.debug("Worker thread shutdown complete")
178
+
179
+ self.logger.info("Drain completed")
180
+
181
+ def is_completed(self) -> bool:
182
+ """
183
+ Returns whether all events have been processed.
184
+ """
185
+ return self._completed and self._event_queue.empty()
@@ -0,0 +1,83 @@
1
+ import logging
2
+ import os
3
+ import httpx
4
+ from typing import Optional
5
+ from .events import ScenarioEvent
6
+
7
+
8
+ class EventReporter:
9
+ """
10
+ Handles HTTP posting of scenario events to external endpoints.
11
+
12
+ Single responsibility: Send events via HTTP to configured endpoints
13
+ with proper authentication and error handling.
14
+
15
+ Args:
16
+ endpoint (str, optional): The base URL to post events to. Defaults to LANGWATCH_ENDPOINT env var.
17
+ api_key (str, optional): The API key for authentication. Defaults to LANGWATCH_API_KEY env var.
18
+
19
+ Example:
20
+ event = {
21
+ "type": "SCENARIO_RUN_STARTED",
22
+ "batch_run_id": "batch-1",
23
+ "scenario_id": "scenario-1",
24
+ "scenario_run_id": "run-1",
25
+ "metadata": {
26
+ "name": "test",
27
+ "description": "test scenario"
28
+ }
29
+ }
30
+
31
+ reporter = EventReporter(endpoint="https://api.langwatch.ai", api_key="test-api-key")
32
+ await reporter.post_event(event)
33
+ """
34
+
35
+ def __init__(self, endpoint: Optional[str] = None, api_key: Optional[str] = None):
36
+ self.endpoint = endpoint or os.getenv("LANGWATCH_ENDPOINT")
37
+ self.api_key = api_key or os.getenv("LANGWATCH_API_KEY", "")
38
+ self.logger = logging.getLogger(__name__)
39
+
40
+ async def post_event(self, event: ScenarioEvent):
41
+ """
42
+ Posts an event to the configured endpoint.
43
+
44
+ Args:
45
+ event: A dictionary containing the event data
46
+
47
+ Returns:
48
+ None - logs success/failure internally
49
+ """
50
+ event_type = event.type_
51
+ self.logger.info(f"[{event_type}] Publishing event ({event.scenario_run_id})")
52
+
53
+ if not self.endpoint:
54
+ self.logger.warning(
55
+ "No LANGWATCH_ENDPOINT configured, skipping event posting"
56
+ )
57
+ return
58
+
59
+ try:
60
+ async with httpx.AsyncClient() as client:
61
+ response = await client.post(
62
+ f"{self.endpoint}/api/scenario-events",
63
+ json=event.to_dict(),
64
+ headers={
65
+ "Content-Type": "application/json",
66
+ "X-Auth-Token": self.api_key,
67
+ },
68
+ )
69
+ self.logger.info(f"[{event_type}] POST response status: {response.status_code} ({event.scenario_run_id})")
70
+
71
+ if response.is_success:
72
+ data = response.json()
73
+ self.logger.info(f"[{event_type}] POST response: {data} ({event.scenario_run_id})")
74
+ else:
75
+ error_text = response.text
76
+ self.logger.error(
77
+ f"[{event_type}] Event POST failed: status={response.status_code}, "
78
+ f"reason={response.reason_phrase}, error={error_text}, "
79
+ f"event={event}"
80
+ )
81
+ except Exception as error:
82
+ self.logger.error(
83
+ f"[{event_type}] Event POST error: {error}, event={event}, endpoint={self.endpoint}")
@@ -0,0 +1,162 @@
1
+ """
2
+ Exports scenario event models from the generated LangWatch API client,
3
+ renaming the auto-generated types to clean, meaningful names.
4
+
5
+ This ensures all event types are always in sync with the OpenAPI spec and
6
+ the backend, and provides a single import location for event models.
7
+
8
+ If you need to add custom logic or helpers, you can extend or wrap these models here.
9
+ """
10
+
11
+ from typing import Union, Any, Optional, TypeAlias
12
+ from scenario._generated.langwatch_api_client.lang_watch_api_client.models import (
13
+ PostApiScenarioEventsBodyType0,
14
+ PostApiScenarioEventsBodyType0Metadata,
15
+ PostApiScenarioEventsBodyType1,
16
+ PostApiScenarioEventsBodyType1ResultsType0,
17
+ PostApiScenarioEventsBodyType1ResultsType0Verdict,
18
+ PostApiScenarioEventsBodyType1Status,
19
+ PostApiScenarioEventsBodyType2,
20
+ )
21
+ from .messages import MessageType
22
+
23
+ # Create alias for cleaner naming
24
+ ScenarioRunStartedEventMetadata: TypeAlias = PostApiScenarioEventsBodyType0Metadata
25
+ ScenarioRunFinishedEventResults: TypeAlias = PostApiScenarioEventsBodyType1ResultsType0
26
+ ScenarioRunFinishedEventVerdict: TypeAlias = PostApiScenarioEventsBodyType1ResultsType0Verdict
27
+ ScenarioRunFinishedEventStatus: TypeAlias = PostApiScenarioEventsBodyType1Status
28
+
29
+
30
+ class ScenarioRunStartedEvent(PostApiScenarioEventsBodyType0):
31
+ """
32
+ Event published when a scenario run begins execution.
33
+
34
+ Automatically sets type_ to "SCENARIO_RUN_STARTED" and includes metadata
35
+ about the scenario (name, description, etc.).
36
+
37
+ Args:
38
+ batch_run_id (str): Unique identifier for the batch of scenario runs
39
+ scenario_id (str): Unique identifier for the scenario definition
40
+ scenario_run_id (str): Unique identifier for this specific run
41
+ metadata (ScenarioRunStartedEventMetadata): Scenario details like name and description
42
+ timestamp (Optional[int], optional): Unix timestamp in milliseconds, auto-generated if not provided
43
+ raw_event (Optional[Any], optional): Raw event data
44
+ scenario_set_id (Optional[str], optional): Set identifier, defaults to "default"
45
+ """
46
+ def __init__(
47
+ self,
48
+ batch_run_id: str,
49
+ scenario_id: str,
50
+ scenario_run_id: str,
51
+ metadata: ScenarioRunStartedEventMetadata,
52
+ timestamp: int,
53
+ raw_event: Optional[Any] = None,
54
+ scenario_set_id: Optional[str] = "default"
55
+ ):
56
+ super().__init__(
57
+ type_="SCENARIO_RUN_STARTED",
58
+ batch_run_id=batch_run_id,
59
+ scenario_id=scenario_id,
60
+ scenario_run_id=scenario_run_id,
61
+ metadata=metadata,
62
+ timestamp=timestamp,
63
+ raw_event=raw_event,
64
+ scenario_set_id=scenario_set_id or "default"
65
+ )
66
+
67
+ class ScenarioRunFinishedEvent(PostApiScenarioEventsBodyType1):
68
+ """
69
+ Event published when a scenario run completes execution.
70
+
71
+ Automatically sets type_ to "SCENARIO_RUN_FINISHED" and includes results
72
+ with verdict (PASS/FAIL/SUCCESS) and reasoning.
73
+
74
+ Args:
75
+ batch_run_id (str): Unique identifier for the batch of scenario runs
76
+ scenario_id (str): Unique identifier for the scenario definition
77
+ scenario_run_id (str): Unique identifier for this specific run
78
+ status (ScenarioRunFinishedEventStatus): Overall execution status
79
+ timestamp (Optional[int], optional): Unix timestamp in milliseconds, auto-generated if not provided
80
+ raw_event (Optional[Any], optional): Raw event data
81
+ scenario_set_id (Optional[str], optional): Set identifier, defaults to "default"
82
+ results (Optional[ScenarioRunFinishedEventResults], optional): Verdict and reasoning for the outcome
83
+ """
84
+ def __init__(
85
+ self,
86
+ batch_run_id: str,
87
+ scenario_id: str,
88
+ scenario_run_id: str,
89
+ status: ScenarioRunFinishedEventStatus,
90
+ timestamp: int,
91
+ results: Optional[ScenarioRunFinishedEventResults] = None,
92
+ raw_event: Optional[Any] = None,
93
+ scenario_set_id: Optional[str] = "default",
94
+ ):
95
+ super().__init__(
96
+ type_="SCENARIO_RUN_FINISHED",
97
+ batch_run_id=batch_run_id,
98
+ scenario_id=scenario_id,
99
+ scenario_run_id=scenario_run_id,
100
+ status=status,
101
+ timestamp=timestamp,
102
+ raw_event=raw_event,
103
+ scenario_set_id=scenario_set_id or "default",
104
+ results=results
105
+ )
106
+
107
+ class ScenarioMessageSnapshotEvent(PostApiScenarioEventsBodyType2):
108
+ """
109
+ Event published to capture intermediate state during scenario execution.
110
+
111
+ Automatically sets type_ to "SCENARIO_MESSAGE_SNAPSHOT" and allows tracking
112
+ of messages, context, or other runtime data during scenario processing.
113
+
114
+ Args:
115
+ batch_run_id (str): Unique identifier for the batch of scenario runs
116
+ scenario_id (str): Unique identifier for the scenario definition
117
+ scenario_run_id (str): Unique identifier for this specific run
118
+ messages (list[MessageType]): List of message objects in the conversation
119
+ timestamp (Optional[int], optional): Unix timestamp in milliseconds, auto-generated if not provided
120
+ raw_event (Optional[Any], optional): Raw event data
121
+ scenario_set_id (Optional[str], optional): Set identifier, defaults to "default"
122
+ """
123
+ def __init__(
124
+ self,
125
+ batch_run_id: str,
126
+ scenario_id: str,
127
+ scenario_run_id: str,
128
+ messages: list[MessageType],
129
+ timestamp: int,
130
+ raw_event: Optional[Any] = None,
131
+ scenario_set_id: Optional[str] = "default"
132
+ ):
133
+ super().__init__(
134
+ type_="SCENARIO_MESSAGE_SNAPSHOT",
135
+ batch_run_id=batch_run_id,
136
+ scenario_id=scenario_id,
137
+ scenario_run_id=scenario_run_id,
138
+ messages=messages,
139
+ timestamp=timestamp,
140
+ raw_event=raw_event,
141
+ scenario_set_id=scenario_set_id or "default"
142
+ )
143
+
144
+ # Union type for all supported event types
145
+ ScenarioEvent = Union[
146
+ ScenarioRunStartedEvent,
147
+ ScenarioRunFinishedEvent,
148
+ ScenarioMessageSnapshotEvent
149
+ ]
150
+
151
+
152
+ __all__ = [
153
+ "ScenarioEvent",
154
+ "ScenarioRunStartedEvent",
155
+ "ScenarioRunStartedEventMetadata",
156
+ "ScenarioRunFinishedEvent",
157
+ "ScenarioRunFinishedEventResults",
158
+ "ScenarioRunFinishedEventVerdict",
159
+ "ScenarioRunFinishedEventStatus",
160
+ "ScenarioMessageSnapshotEvent",
161
+ "MessageType",
162
+ ]
@@ -0,0 +1,58 @@
1
+ """
2
+ Exports message models from the generated LangWatch API client,
3
+ renaming the auto-generated types to clean, meaningful names.
4
+
5
+ This ensures all message types are always in sync with the OpenAPI spec and
6
+ the backend, and provides a single import location for message models.
7
+
8
+ If you need to add custom logic or helpers, you can extend or wrap these models here.
9
+ """
10
+
11
+ from typing import Union, TypeAlias
12
+ from scenario._generated.langwatch_api_client.lang_watch_api_client.models import (
13
+ PostApiScenarioEventsBodyType2MessagesItemType0,
14
+ PostApiScenarioEventsBodyType2MessagesItemType1,
15
+ PostApiScenarioEventsBodyType2MessagesItemType2,
16
+ PostApiScenarioEventsBodyType2MessagesItemType3,
17
+ PostApiScenarioEventsBodyType2MessagesItemType4,
18
+ PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItem,
19
+ PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItemFunction,
20
+ )
21
+
22
+ # Create aliases for cleaner naming
23
+ DeveloperMessage: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType0
24
+ SystemMessage: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType1
25
+ AssistantMessage: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType2
26
+ UserMessage: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType3
27
+ ToolMessage: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType4
28
+ ToolCall: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItem
29
+ FunctionCall: TypeAlias = PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItemFunction
30
+
31
+ # Union type for all supported message types
32
+ MessageType = Union[
33
+ DeveloperMessage,
34
+ SystemMessage,
35
+ AssistantMessage,
36
+ UserMessage,
37
+ ToolMessage,
38
+ ]
39
+
40
+ __all__ = [
41
+ "MessageType",
42
+ "DeveloperMessage",
43
+ "SystemMessage",
44
+ "AssistantMessage",
45
+ "UserMessage",
46
+ "ToolMessage",
47
+ "ToolCall",
48
+ "FunctionCall",
49
+
50
+ # API client models -- Required for PDocs
51
+ "PostApiScenarioEventsBodyType2MessagesItemType0",
52
+ "PostApiScenarioEventsBodyType2MessagesItemType1",
53
+ "PostApiScenarioEventsBodyType2MessagesItemType2",
54
+ "PostApiScenarioEventsBodyType2MessagesItemType3",
55
+ "PostApiScenarioEventsBodyType2MessagesItemType4",
56
+ "PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItem",
57
+ "PostApiScenarioEventsBodyType2MessagesItemType2ToolCallsItemFunction",
58
+ ]
@@ -0,0 +1,97 @@
1
+ import warnings
2
+ from openai.types.chat.chat_completion_message_param import ChatCompletionMessageParam
3
+ from .events import MessageType
4
+ from .messages import (
5
+ SystemMessage,
6
+ AssistantMessage,
7
+ UserMessage,
8
+ ToolMessage,
9
+ ToolCall,
10
+ FunctionCall,
11
+ )
12
+ from typing import List
13
+ import uuid
14
+
15
+ def convert_messages_to_api_client_messages(messages: list[ChatCompletionMessageParam]) -> list[MessageType]:
16
+ """
17
+ Converts OpenAI ChatCompletionMessageParam messages to API client Message format.
18
+
19
+ This function transforms messages from OpenAI's format to the API client format
20
+ that matches the expected schema for ScenarioMessageSnapshotEvent.
21
+
22
+ Args:
23
+ messages: List of OpenAI ChatCompletionMessageParam messages
24
+
25
+ Returns:
26
+ List of API client Message objects
27
+
28
+ Raises:
29
+ ValueError: If message role is not supported or message format is invalid
30
+ """
31
+
32
+ converted_messages: list[MessageType] = []
33
+
34
+ for i, message in enumerate(messages):
35
+ # Generate unique ID for each message
36
+ message_id = message.get("id") or str(uuid.uuid4())
37
+
38
+ role = message.get("role")
39
+ content = message.get("content")
40
+
41
+ if role == "user":
42
+ if not content:
43
+ raise ValueError(f"User message at index {i} missing required content")
44
+ converted_messages.append(UserMessage(
45
+ id=message_id,
46
+ role="user",
47
+ content=str(content)
48
+ ))
49
+ elif role == "assistant":
50
+ # Handle tool calls if present
51
+ tool_calls = message.get("tool_calls")
52
+ api_tool_calls: List[ToolCall] = []
53
+
54
+ if tool_calls:
55
+ for tool_call in tool_calls:
56
+ api_tool_calls.append(ToolCall(
57
+ id=tool_call.get("id", str(uuid.uuid4())),
58
+ type_="function",
59
+ function=FunctionCall(
60
+ name=tool_call["function"].get("name", "unknown"),
61
+ arguments=tool_call["function"].get("arguments", "{}")
62
+ )
63
+ ))
64
+
65
+ converted_messages.append(AssistantMessage(
66
+ id=message_id,
67
+ role="assistant",
68
+ content=str(content),
69
+ tool_calls=api_tool_calls
70
+ ))
71
+ elif role == "system":
72
+ if not content:
73
+ raise ValueError(f"System message at index {i} missing required content")
74
+ converted_messages.append(SystemMessage(
75
+ id=message_id,
76
+ role="system",
77
+ content=str(content)
78
+ ))
79
+ elif role == "tool":
80
+ tool_call_id = message.get("tool_call_id")
81
+ if not tool_call_id:
82
+ warnings.warn(f"Tool message at index {i} missing required tool_call_id, skipping tool message")
83
+ continue
84
+ if not content:
85
+ warnings.warn(f"Tool message at index {i} missing required content, skipping tool message")
86
+ continue
87
+
88
+ converted_messages.append(ToolMessage(
89
+ id=message_id,
90
+ role="tool",
91
+ content=str(content),
92
+ tool_call_id=tool_call_id
93
+ ))
94
+ else:
95
+ raise ValueError(f"Unsupported message role '{role}' at index {i}")
96
+
97
+ return converted_messages