timbal 2.2.8__tar.gz → 2.2.9__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 (227) hide show
  1. {timbal-2.2.8 → timbal-2.2.9}/PKG-INFO +1 -1
  2. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/_version.py +2 -2
  3. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/__main__.py +100 -1
  4. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/llm_router.py +2 -1
  5. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/models.py +8 -0
  6. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/cli.py +69 -30
  7. timbal-2.2.9/python/timbal/evals/reporters.py +80 -0
  8. timbal-2.2.9/python/timbal/evals/runner.py +304 -0
  9. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/utils.py +124 -14
  10. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/models.yaml +72 -0
  11. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/__init__.py +32 -0
  12. timbal-2.2.9/python/timbal/tools/aircall.py +512 -0
  13. timbal-2.2.8/python/timbal/evals/runner.py +0 -185
  14. {timbal-2.2.8 → timbal-2.2.9}/.gitignore +0 -0
  15. {timbal-2.2.8 → timbal-2.2.9}/LICENSE +0 -0
  16. {timbal-2.2.8 → timbal-2.2.9}/README.md +0 -0
  17. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/chat-completions.mdx +0 -0
  18. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/create-from-workforce.mdx +0 -0
  19. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/cancel.mdx +0 -0
  20. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/get.mdx +0 -0
  21. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/list.mdx +0 -0
  22. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/retry.mdx +0 -0
  23. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/link.mdx +0 -0
  24. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/list-context-vars.mdx +0 -0
  25. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/list-policies.mdx +0 -0
  26. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/messages.mdx +0 -0
  27. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/responses.mdx +0 -0
  28. {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/unlink.mdx +0 -0
  29. {timbal-2.2.8 → timbal-2.2.9}/pyproject.toml +0 -0
  30. {timbal-2.2.8 → timbal-2.2.9}/pyrightconfig.json +0 -0
  31. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/__init__.py +0 -0
  32. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/__init__.py +0 -0
  33. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/cli_utils.py +0 -0
  34. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/cst_utils.py +0 -0
  35. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/flow.py +0 -0
  36. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/format.py +0 -0
  37. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/model_discovery.py +0 -0
  38. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/test.py +0 -0
  39. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/tool_discovery.py +0 -0
  40. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/__init__.py +0 -0
  41. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_edge.py +0 -0
  42. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_step.py +0 -0
  43. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_tool.py +0 -0
  44. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_edge.py +0 -0
  45. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_step.py +0 -0
  46. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_tool.py +0 -0
  47. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_config.py +0 -0
  48. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_param.py +0 -0
  49. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_position.py +0 -0
  50. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/__init__.py +0 -0
  51. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/base.py +0 -0
  52. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/__init__.py +0 -0
  53. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/anthropic.py +0 -0
  54. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/default.py +0 -0
  55. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/message.py +0 -0
  56. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/openai.py +0 -0
  57. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/string.py +0 -0
  58. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/timbal.py +0 -0
  59. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/registry.py +0 -0
  60. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/__init__.py +0 -0
  61. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/agent.py +0 -0
  62. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/fallback_model.py +0 -0
  63. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/mcp.py +0 -0
  64. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/memory_compaction.py +0 -0
  65. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/runnable.py +0 -0
  66. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/skill.py +0 -0
  67. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/test_model.py +0 -0
  68. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/tool.py +0 -0
  69. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/tool_set.py +0 -0
  70. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/workflow.py +0 -0
  71. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/errors.py +0 -0
  72. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/__init__.py +0 -0
  73. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/display.py +0 -0
  74. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/agent.py +0 -0
  75. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_examples.yaml +0 -0
  76. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_flow_validators.yaml +0 -0
  77. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_negations.yaml +0 -0
  78. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_parallel.yaml +0 -0
  79. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_subagent.yaml +0 -0
  80. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_transforms.yaml +0 -0
  81. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/test_invalid_validator.yaml +0 -0
  82. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/models.py +0 -0
  83. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/__init__.py +0 -0
  84. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/base.py +0 -0
  85. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/comparison_base.py +0 -0
  86. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains.py +0 -0
  87. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains_all.py +0 -0
  88. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains_any.py +0 -0
  89. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/context.py +0 -0
  90. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/email.py +0 -0
  91. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/ends_with.py +0 -0
  92. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/eq.py +0 -0
  93. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/gt.py +0 -0
  94. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/gte.py +0 -0
  95. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/json.py +0 -0
  96. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/language.py +0 -0
  97. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/length.py +0 -0
  98. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/llm_base.py +0 -0
  99. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/lt.py +0 -0
  100. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/lte.py +0 -0
  101. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/max_length.py +0 -0
  102. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/min_length.py +0 -0
  103. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/not_null.py +0 -0
  104. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/parallel.py +0 -0
  105. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/pattern.py +0 -0
  106. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/prompt.py +0 -0
  107. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/semantic.py +0 -0
  108. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/seq.py +0 -0
  109. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/starts_with.py +0 -0
  110. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/type.py +0 -0
  111. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/logs.py +0 -0
  112. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/__init__.py +0 -0
  113. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/integrations.py +0 -0
  114. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/knowledge_bases/__init__.py +0 -0
  115. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/knowledge_bases/query.py +0 -0
  116. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/tool_proxy.py +0 -0
  117. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/types.py +0 -0
  118. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/utils.py +0 -0
  119. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/__init__.py +0 -0
  120. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/__main__.py +0 -0
  121. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/http.py +0 -0
  122. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/jobs.py +0 -0
  123. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/voice.html +0 -0
  124. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/voice.py +0 -0
  125. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/__init__.py +0 -0
  126. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/config.py +0 -0
  127. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/config_loader.py +0 -0
  128. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/context.py +0 -0
  129. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/dependency_analyzer.py +0 -0
  130. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/__init__.py +0 -0
  131. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/exporters/__init__.py +0 -0
  132. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/exporters/otel.py +0 -0
  133. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/__init__.py +0 -0
  134. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/base.py +0 -0
  135. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/in_memory.py +0 -0
  136. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/jsonl.py +0 -0
  137. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/platform.py +0 -0
  138. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/sqlite.py +0 -0
  139. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/span.py +0 -0
  140. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/trace.py +0 -0
  141. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/_creds.py +0 -0
  142. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/asana.py +0 -0
  143. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/bash.py +0 -0
  144. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/cala.py +0 -0
  145. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/cloudflare.py +0 -0
  146. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/dynamics_business_central.py +0 -0
  147. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/dynamics_sales.py +0 -0
  148. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/edit.py +0 -0
  149. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/elasticsearch.py +0 -0
  150. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/elevenlabs.py +0 -0
  151. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/excel.py +0 -0
  152. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/fal.py +0 -0
  153. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/fathom.py +0 -0
  154. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/firecrawl.py +0 -0
  155. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/gemini_images.py +0 -0
  156. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/gmail.py +0 -0
  157. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_analytics.py +0 -0
  158. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_business.py +0 -0
  159. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_calendar.py +0 -0
  160. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_docs.py +0 -0
  161. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_drive.py +0 -0
  162. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_maps.py +0 -0
  163. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_merchant_center.py +0 -0
  164. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_search_console.py +0 -0
  165. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_sheets.py +0 -0
  166. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/happy_scribe.py +0 -0
  167. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/higgsfield.py +0 -0
  168. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/hubspot.py +0 -0
  169. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/interaction.py +0 -0
  170. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/jira.py +0 -0
  171. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/klaviyo.py +0 -0
  172. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/knowledge_base.py +0 -0
  173. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/krea.py +0 -0
  174. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/lancedb.py +0 -0
  175. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/linkedin.py +0 -0
  176. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/mongodb.py +0 -0
  177. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/netsuite.py +0 -0
  178. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/onedrive.py +0 -0
  179. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/outlook.py +0 -0
  180. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/parallel.py +0 -0
  181. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/pinecone.py +0 -0
  182. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/powerbi.py +0 -0
  183. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/quiver_ai.py +0 -0
  184. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/read.py +0 -0
  185. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/replicate.py +0 -0
  186. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/resend.py +0 -0
  187. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/salesforce.py +0 -0
  188. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/scraperapi.py +0 -0
  189. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/sharepoint.py +0 -0
  190. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/shopify.py +0 -0
  191. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/slack.py +0 -0
  192. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/stripe.py +0 -0
  193. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/tavily.py +0 -0
  194. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/web_search.py +0 -0
  195. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/write.py +0 -0
  196. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/xai.py +0 -0
  197. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/zendesk.py +0 -0
  198. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/zoho_crm.py +0 -0
  199. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/__init__.py +0 -0
  200. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/approval.py +0 -0
  201. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/__init__.py +0 -0
  202. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/base.py +0 -0
  203. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/custom.py +0 -0
  204. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/file.py +0 -0
  205. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/text.py +0 -0
  206. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/thinking.py +0 -0
  207. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/tool_result.py +0 -0
  208. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/tool_use.py +0 -0
  209. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/__init__.py +0 -0
  210. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/approval.py +0 -0
  211. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/base.py +0 -0
  212. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/delta.py +0 -0
  213. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/interaction.py +0 -0
  214. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/output.py +0 -0
  215. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/start.py +0 -0
  216. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/file.py +0 -0
  217. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/message.py +0 -0
  218. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/run_status.py +0 -0
  219. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/__init__.py +0 -0
  220. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/import_spec.py +0 -0
  221. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/model.py +0 -0
  222. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/net.py +0 -0
  223. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/schema.py +0 -0
  224. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/serialization.py +0 -0
  225. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/__init__.py +0 -0
  226. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/elevenlabs.py +0 -0
  227. {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/session.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: timbal
3
- Version: 2.2.8
3
+ Version: 2.2.9
4
4
  Summary: Simple, performant, battle-tested framework for building reliable AI applications
5
5
  Project-URL: Source, https://github.com/timbal-ai/timbal
6
6
  Author-email: Timbal <team@timbal.ai>
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.2.8'
22
- __version_tuple__ = version_tuple = (2, 2, 8)
21
+ __version__ = version = '2.2.9'
22
+ __version_tuple__ = version_tuple = (2, 2, 9)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -83,10 +83,42 @@ def main() -> None:
83
83
  "--stream", "-s", action="store_true", help="Print every event instead of only the final output event."
84
84
  )
85
85
 
86
+ # Evals operation
87
+ evals_parser = subparsers.add_parser(
88
+ "evals",
89
+ help="Run evals against the workspace entry point.",
90
+ )
91
+ evals_parser.add_argument(
92
+ "evals_path",
93
+ nargs="?",
94
+ default=None,
95
+ help="Path to an eval file or directory (defaults to the workspace path). "
96
+ "Use ::eval_name to run a single eval.",
97
+ )
98
+ evals_parser.add_argument(
99
+ "--tags",
100
+ default=None,
101
+ help="Comma-separated tag filter; evals matching ANY tag will run.",
102
+ )
103
+ evals_parser.add_argument(
104
+ "--jobs",
105
+ "-j",
106
+ type=int,
107
+ default=1,
108
+ help="Run up to N evals concurrently (default 1). Results are emitted as they complete.",
109
+ )
110
+ evals_parser.add_argument(
111
+ "--format",
112
+ choices=["json", "pretty"],
113
+ default="json",
114
+ help="Output format: 'json' (default) streams one JSON event per line to stdout as each eval "
115
+ "completes; 'pretty' is the rich terminal report.",
116
+ )
117
+
86
118
  # Defer transformer module loading (pulls in libcst + timbal.codegen which
87
119
  # are expensive) — only needed for transformer operations, not for
88
120
  # list-tools, get-flow, or test.
89
- _lightweight_ops = {"get-models", "get-tools", "get-flow", "test"}
121
+ _lightweight_ops = {"get-models", "get-tools", "get-flow", "test", "evals"}
90
122
  if not (_lightweight_ops & set(sys.argv[1:])):
91
123
  from timbal.codegen.transformers import load_modules
92
124
 
@@ -230,6 +262,73 @@ def main() -> None:
230
262
  asyncio.run(run_test(import_spec, params, run_context=run_context, stream=args.stream))
231
263
  return
232
264
 
265
+ if operation == "evals":
266
+ import asyncio
267
+ import os
268
+
269
+ os.environ.setdefault("TIMBAL_SUPPRESS_EVENTS", "tracing_setup")
270
+ os.environ["TIMBAL_LOG_LEVEL"] = "CRITICAL"
271
+
272
+ from ..logs import setup_logging
273
+
274
+ setup_logging()
275
+
276
+ from dotenv import load_dotenv
277
+
278
+ load_dotenv(override=True)
279
+
280
+ from . import parse_fqn
281
+
282
+ # The workspace entry point is the default runnable for all evals;
283
+ # individual evals can still override it with their own 'runnable' key.
284
+ try:
285
+ runnable = parse_fqn(workspace_path).load()
286
+ except (FileNotFoundError, ValueError) as e:
287
+ print(f"error: {e}", file=sys.stderr)
288
+ sys.exit(1)
289
+ except Exception as e:
290
+ print(f"error: failed to load entry point: {e}", file=sys.stderr)
291
+ sys.exit(1)
292
+
293
+ from timbal.evals.utils import collect_evals
294
+
295
+ evals_path_arg = args.evals_path if args.evals_path is not None else str(workspace_path)
296
+ eval_name = None
297
+ if "::" in evals_path_arg:
298
+ evals_path_arg, eval_name = evals_path_arg.rsplit("::", 1)
299
+ tags = {t.strip() for t in args.tags.split(",")} if args.tags else None
300
+
301
+ # Resolve relative eval paths against the workspace (--path), not the
302
+ # process cwd, so running codegen from outside the workspace works.
303
+ evals_path = Path(evals_path_arg)
304
+ if not evals_path.is_absolute():
305
+ evals_path = workspace_path / evals_path
306
+
307
+ try:
308
+ evals = collect_evals(evals_path, runnable, eval_name, tags)
309
+ except ValueError as e:
310
+ print(f"error: {e}", file=sys.stderr)
311
+ sys.exit(1)
312
+
313
+ if not evals:
314
+ # Warn but keep going, matching the evals CLI: an empty run must
315
+ # still emit the start/summary events consumers expect.
316
+ print(f"warning: no evals found in {evals_path}", file=sys.stderr)
317
+
318
+ from timbal.evals.runner import run_evals
319
+
320
+ if args.format == "pretty":
321
+ from timbal.evals.reporters import PrettyReporter
322
+
323
+ reporter = PrettyReporter()
324
+ else:
325
+ from timbal.evals.reporters import JsonReporter
326
+
327
+ reporter = JsonReporter()
328
+
329
+ summary = asyncio.run(run_evals(evals, reporter=reporter, max_concurrency=args.jobs))
330
+ sys.exit(0 if summary.failed == 0 else 1)
331
+
233
332
  # Transformer operations — heavy imports already loaded above.
234
333
  from timbal.codegen import parse_fqn
235
334
  from timbal.codegen.transformers import apply_operation
@@ -416,8 +416,9 @@ async def _llm_router(
416
416
  # Per-request headers: change every call, so passed via extra_headers on each .create().
417
417
  request_headers: dict[str, str] = {
418
418
  "x-timbal-run-id": run_context.id,
419
- "x-timbal-call-id": call_id,
420
419
  }
420
+ if call_id:
421
+ request_headers["x-timbal-call-id"] = call_id
421
422
  if run_context.platform_config and run_context.platform_config.subject:
422
423
  if run_context.platform_config.subject.app_id:
423
424
  request_headers["x-timbal-app-id"] = run_context.platform_config.subject.app_id
@@ -54,6 +54,9 @@ Model = Literal[
54
54
  "anthropic/claude-sonnet-4-5",
55
55
  "anthropic/claude-haiku-4-5",
56
56
  "openai/gpt-5.5",
57
+ "openai/gpt-5.6-sol",
58
+ "openai/gpt-5.6-terra",
59
+ "openai/gpt-5.6-luna",
57
60
  "openai/gpt-5.4",
58
61
  "openai/gpt-5.4-mini",
59
62
  "openai/gpt-5.4-nano",
@@ -108,6 +111,7 @@ Model = Literal[
108
111
  "google/gemini-2.5-flash-lite",
109
112
  "google/gemini-2.5-flash-image",
110
113
  "google/gemini-2.5-flash-preview-tts",
114
+ "xai/grok-4.5",
111
115
  "xai/grok-4",
112
116
  "xai/grok-4-fast-reasoning",
113
117
  "xai/grok-4-fast-non-reasoning",
@@ -120,13 +124,17 @@ Model = Literal[
120
124
  "groq/openai/gpt-oss-120b",
121
125
  "groq/openai/gpt-oss-20b",
122
126
  "fireworks/accounts/fireworks/models/deepseek-v4-pro",
127
+ "fireworks/accounts/fireworks/models/deepseek-v4-flash",
123
128
  "fireworks/accounts/fireworks/models/qwen3p6-plus",
129
+ "fireworks/accounts/fireworks/models/qwen3p7-plus",
124
130
  "fireworks/accounts/fireworks/models/kimi-k2p6",
125
131
  "fireworks/accounts/fireworks/models/kimi-k2p5",
126
132
  "fireworks/accounts/fireworks/models/minimax-m2p5",
133
+ "fireworks/accounts/fireworks/models/minimax-m2p7",
127
134
  "fireworks/accounts/fireworks/models/gpt-oss-120b",
128
135
  "fireworks/accounts/fireworks/models/gpt-oss-20b",
129
136
  "fireworks/accounts/fireworks/models/glm-5p1",
137
+ "fireworks/accounts/fireworks/models/glm-5p2",
130
138
  "xiaomi/mimo-v2-pro",
131
139
  "xiaomi/mimo-v2-omni",
132
140
  "xiaomi/mimo-v2-flash",
@@ -20,7 +20,7 @@ from .. import __version__
20
20
  from ..logs import setup_logging
21
21
  from ..utils import ImportSpec
22
22
  from .runner import run_evals
23
- from .utils import discover_config, discover_eval_files, parse_eval_file
23
+ from .utils import collect_evals, discover_config, dump_summary
24
24
 
25
25
  console = Console()
26
26
 
@@ -79,6 +79,29 @@ if __name__ == "__main__":
79
79
  help="Filter evals by tags. Comma-separated list (e.g., 'smoke,fast'). "
80
80
  "Evals matching ANY of the tags will run.",
81
81
  )
82
+ parser.add_argument(
83
+ "-o",
84
+ "--output",
85
+ type=str,
86
+ default=None,
87
+ help="Write results as JSON to the given file. Use '-' to print JSON to stdout.",
88
+ )
89
+ parser.add_argument(
90
+ "-f",
91
+ "--format",
92
+ type=str,
93
+ choices=["pretty", "json"],
94
+ default="pretty",
95
+ help="Output format: 'pretty' (default) is the rich terminal report; "
96
+ "'json' streams one JSON event per line (JSONL) to stdout as each eval completes.",
97
+ )
98
+ parser.add_argument(
99
+ "-j",
100
+ "--jobs",
101
+ type=int,
102
+ default=1,
103
+ help="Run up to N evals concurrently (default 1). Results are reported as they complete.",
104
+ )
82
105
  parser.add_argument(
83
106
  "-V",
84
107
  "--version",
@@ -87,6 +110,19 @@ if __name__ == "__main__":
87
110
  )
88
111
  args = parser.parse_args()
89
112
 
113
+ if args.format == "json" and args.output == "-":
114
+ console.print("[red]Error:[/red] --format json already streams JSON to stdout; use -o <file> instead of '-'")
115
+ sys.exit(1)
116
+
117
+ if args.output == "-" or args.format == "json":
118
+ # Reserve stdout for JSON; route all human-readable output (headers,
119
+ # eval trees, failures, summary, warnings) to stderr so pipelines can
120
+ # parse stdout reliably.
121
+ from . import display
122
+
123
+ console.file = sys.stderr
124
+ display.console.file = sys.stderr
125
+
90
126
  if args.version:
91
127
  console.print(f"timbal.eval {__version__}")
92
128
  sys.exit(0)
@@ -125,47 +161,50 @@ if __name__ == "__main__":
125
161
  console.print(f"[red]Error:[/red] Failed to load runnable: {e}")
126
162
  sys.exit(1)
127
163
 
128
- eval_files = discover_eval_files(path)
129
- if not eval_files:
130
- console.print(f"[yellow]Warning:[/yellow] No eval files found in {path}")
131
- sys.exit(0)
164
+ tag_filters = {t.strip() for t in args.tags.split(",")} if args.tags else None
165
+
166
+ try:
167
+ evals = collect_evals(path, runnable, eval_name_filter, tag_filters)
168
+ except ValueError as e:
169
+ console.print(f"[red]Error:[/red] {e}")
170
+ sys.exit(1)
132
171
 
133
- evals = [eval for eval_file in eval_files for eval in parse_eval_file(eval_file, runnable)]
134
172
  if not evals:
135
- console.print(f"[yellow]Warning:[/yellow] No evals found in {len(eval_files)} file(s)")
136
- sys.exit(0)
173
+ # Warn but keep going: an empty run must still produce the JSON
174
+ # events/document that -o and --format json consumers expect.
175
+ suffix = f" matching tags: {', '.join(sorted(tag_filters))}" if tag_filters else ""
176
+ console.print(f"[yellow]Warning:[/yellow] No evals found in {path}{suffix}")
137
177
 
138
- # Check for duplicate eval names
139
- seen_names: dict[str, Path] = {}
140
- for e in evals:
141
- if e.name in seen_names:
142
- console.print(
143
- f"[red]Error:[/red] Duplicate eval name '{e.name}' found in:\n - {seen_names[e.name]}\n - {e.path}"
144
- )
145
- sys.exit(1)
146
- seen_names[e.name] = e.path
178
+ if args.format == "json":
179
+ from .reporters import JsonReporter
147
180
 
148
- # Filter by eval name if specified
149
- if eval_name_filter:
150
- evals = [e for e in evals if e.name == eval_name_filter]
151
- if not evals:
152
- console.print(f"[red]Error:[/red] No eval found with name '{eval_name_filter}'")
153
- sys.exit(1)
181
+ reporter = JsonReporter()
182
+ else:
183
+ from .reporters import PrettyReporter
154
184
 
155
- # Filter by tags if specified
156
- if args.tags:
157
- tag_filters = {t.strip() for t in args.tags.split(",")}
158
- evals = [e for e in evals if tag_filters & set(e.tags)]
159
- if not evals:
160
- console.print(f"[yellow]Warning:[/yellow] No evals found matching tags: {', '.join(sorted(tag_filters))}")
161
- sys.exit(0)
185
+ reporter = PrettyReporter()
162
186
 
163
187
  summary = asyncio.run(
164
188
  run_evals(
165
189
  evals,
166
190
  capture=not args.no_capture,
191
+ reporter=reporter,
192
+ max_concurrency=args.jobs,
167
193
  )
168
194
  )
169
195
 
196
+ if args.output:
197
+ import json
198
+
199
+ summary_dict = asyncio.run(dump_summary(summary))
200
+ summary_json = json.dumps(summary_dict, indent=2, default=str)
201
+ if args.output == "-":
202
+ sys.stdout.write(summary_json + "\n")
203
+ else:
204
+ output_path = Path(args.output).expanduser()
205
+ output_path.parent.mkdir(parents=True, exist_ok=True)
206
+ output_path.write_text(summary_json)
207
+ console.print(f"[dim]Results written to {output_path}[/dim]")
208
+
170
209
  # Exit with error code if any eval failed
171
210
  sys.exit(0 if summary.failed == 0 else 1)
@@ -0,0 +1,80 @@
1
+ import json
2
+ import sys
3
+ from typing import Any, TextIO
4
+
5
+ from .models import Eval, EvalResult, EvalSummary
6
+ from .utils import dump_result
7
+
8
+
9
+ class Reporter:
10
+ """Receives eval lifecycle callbacks.
11
+
12
+ `result()` is called as each eval completes — in file order for sequential
13
+ runs, in completion order for parallel runs.
14
+ """
15
+
16
+ def start(self, evals: list[Eval]) -> None:
17
+ pass
18
+
19
+ async def result(self, result: EvalResult) -> None:
20
+ pass
21
+
22
+ def finish(self, summary: EvalSummary) -> None:
23
+ pass
24
+
25
+
26
+ class PrettyReporter(Reporter):
27
+ """Human-readable Rich output (the default CLI experience)."""
28
+
29
+ def __init__(self) -> None:
30
+ from . import display # deferred: pulls in rich
31
+
32
+ self._display = display
33
+
34
+ def start(self, evals: list[Eval]) -> None:
35
+ self._display.print_header(evals)
36
+
37
+ async def result(self, result: EvalResult) -> None:
38
+ self._display.print_eval_result(result)
39
+
40
+ def finish(self, summary: EvalSummary) -> None:
41
+ self._display.print_failures(summary.results)
42
+ self._display.print_summary(summary)
43
+
44
+
45
+ class JsonReporter(Reporter):
46
+ """Streams one JSON object per line (JSONL) as evals complete.
47
+
48
+ Events:
49
+ {"event": "start", "total": N, "evals": [{"name", "path"}, ...]}
50
+ {"event": "result", ...} # one per eval, in completion order
51
+ {"event": "summary", "total", "passed", "failed", "total_duration"}
52
+ """
53
+
54
+ def __init__(self, stream: TextIO | None = None) -> None:
55
+ # Grab the stream reference eagerly: output capture swaps sys.stdout
56
+ # globally while evals run, and events must reach the real stream.
57
+ self._stream = stream if stream is not None else sys.stdout
58
+
59
+ def _emit(self, obj: dict[str, Any]) -> None:
60
+ self._stream.write(json.dumps(obj, default=str) + "\n")
61
+ self._stream.flush()
62
+
63
+ def start(self, evals: list[Eval]) -> None:
64
+ self._emit({
65
+ "event": "start",
66
+ "total": len(evals),
67
+ "evals": [{"name": e.name, "path": str(e.path)} for e in evals],
68
+ })
69
+
70
+ async def result(self, result: EvalResult) -> None:
71
+ self._emit({"event": "result", **await dump_result(result)})
72
+
73
+ def finish(self, summary: EvalSummary) -> None:
74
+ self._emit({
75
+ "event": "summary",
76
+ "total": summary.total,
77
+ "passed": summary.passed,
78
+ "failed": summary.failed,
79
+ "total_duration": summary.total_duration,
80
+ })