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.
- {timbal-2.2.8 → timbal-2.2.9}/PKG-INFO +1 -1
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/_version.py +2 -2
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/__main__.py +100 -1
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/llm_router.py +2 -1
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/models.py +8 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/cli.py +69 -30
- timbal-2.2.9/python/timbal/evals/reporters.py +80 -0
- timbal-2.2.9/python/timbal/evals/runner.py +304 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/utils.py +124 -14
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/models.yaml +72 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/__init__.py +32 -0
- timbal-2.2.9/python/timbal/tools/aircall.py +512 -0
- timbal-2.2.8/python/timbal/evals/runner.py +0 -185
- {timbal-2.2.8 → timbal-2.2.9}/.gitignore +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/LICENSE +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/README.md +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/chat-completions.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/create-from-workforce.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/cancel.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/get.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/list.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/jobs/retry.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/link.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/list-context-vars.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/list-policies.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/messages.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/responses.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/docs/api-reference/ace/unlink.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/pyproject.toml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/pyrightconfig.json +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/cli_utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/cst_utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/flow.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/format.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/model_discovery.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/test.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/tool_discovery.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_edge.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_step.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/add_tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_edge.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_step.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/remove_tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_config.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_param.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/codegen/transformers/set_position.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/anthropic.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/default.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/message.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/openai.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/string.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/impl/timbal.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/collectors/registry.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/agent.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/fallback_model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/mcp.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/memory_compaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/runnable.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/skill.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/test_model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/tool_set.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/core/workflow.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/errors.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/display.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/agent.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_examples.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_flow_validators.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_negations.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_parallel.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_subagent.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/eval_transforms.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/fixtures/test_invalid_validator.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/models.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/comparison_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains_all.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/contains_any.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/context.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/email.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/ends_with.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/eq.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/gt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/gte.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/json.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/language.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/llm_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/lt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/lte.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/max_length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/min_length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/not_null.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/parallel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/pattern.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/prompt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/semantic.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/seq.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/starts_with.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/evals/validators/type.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/logs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/integrations.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/knowledge_bases/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/knowledge_bases/query.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/tool_proxy.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/types.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/platform/utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/__main__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/http.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/jobs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/voice.html +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/server/voice.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/config.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/config_loader.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/context.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/dependency_analyzer.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/exporters/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/exporters/otel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/in_memory.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/jsonl.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/platform.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/providers/sqlite.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/span.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/state/tracing/trace.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/_creds.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/asana.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/bash.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/cala.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/cloudflare.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/dynamics_business_central.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/dynamics_sales.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/edit.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/elasticsearch.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/elevenlabs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/excel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/fal.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/fathom.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/firecrawl.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/gemini_images.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/gmail.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_analytics.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_business.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_calendar.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_docs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_drive.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_maps.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_merchant_center.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_search_console.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/google_sheets.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/happy_scribe.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/higgsfield.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/hubspot.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/interaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/jira.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/klaviyo.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/knowledge_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/krea.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/lancedb.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/linkedin.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/mongodb.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/netsuite.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/onedrive.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/outlook.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/parallel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/pinecone.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/powerbi.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/quiver_ai.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/read.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/replicate.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/resend.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/salesforce.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/scraperapi.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/sharepoint.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/shopify.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/slack.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/stripe.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/tavily.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/web_search.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/write.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/xai.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/zendesk.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/tools/zoho_crm.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/approval.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/custom.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/file.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/text.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/thinking.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/tool_result.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/content/tool_use.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/approval.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/delta.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/interaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/output.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/events/start.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/file.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/message.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/types/run_status.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/import_spec.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/net.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/schema.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/utils/serialization.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/elevenlabs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.9}/python/timbal/voice/session.py +0 -0
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 2,
|
|
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
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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
|
+
})
|