timbal 2.2.8__tar.gz → 2.2.10__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.10}/PKG-INFO +1 -1
- timbal-2.2.10/docs/api-reference/ace/jobs/create.mdx +4 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/_version.py +2 -2
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/__main__.py +100 -1
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/model_discovery.py +12 -11
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/tool_discovery.py +1 -1
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/openai.py +86 -11
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/llm_router.py +27 -3
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/models.py +22 -10
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/runnable.py +15 -5
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/cli.py +69 -30
- timbal-2.2.10/python/timbal/evals/reporters.py +80 -0
- timbal-2.2.10/python/timbal/evals/runner.py +304 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/utils.py +124 -14
- timbal-2.2.10/python/timbal/models.yaml +1094 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/voice.html +96 -5
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/voice.py +29 -2
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/__init__.py +32 -0
- timbal-2.2.10/python/timbal/tools/aircall.py +512 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/base.py +5 -2
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/thinking.py +7 -6
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/message.py +25 -5
- timbal-2.2.10/python/timbal/voice/__init__.py +87 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/voice/elevenlabs.py +10 -0
- timbal-2.2.10/python/timbal/voice/eou.py +130 -0
- timbal-2.2.10/python/timbal/voice/metrics.py +48 -0
- timbal-2.2.10/python/timbal/voice/playback.py +149 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/voice/session.py +580 -237
- timbal-2.2.10/python/timbal/voice/turn_detection.py +658 -0
- timbal-2.2.8/docs/api-reference/ace/messages.mdx +0 -4
- timbal-2.2.8/docs/api-reference/ace/responses.mdx +0 -4
- timbal-2.2.8/python/timbal/evals/runner.py +0 -185
- timbal-2.2.8/python/timbal/models.yaml +0 -1058
- timbal-2.2.8/python/timbal/voice/__init__.py +0 -41
- {timbal-2.2.8 → timbal-2.2.10}/.gitignore +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/LICENSE +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/README.md +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/chat-completions.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/create-from-workforce.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/jobs/cancel.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/jobs/get.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/jobs/list.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/jobs/retry.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/link.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/list-context-vars.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/list-policies.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/docs/api-reference/ace/unlink.mdx +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/pyproject.toml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/pyrightconfig.json +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/cli_utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/cst_utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/flow.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/format.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/test.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/add_edge.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/add_step.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/add_tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/remove_edge.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/remove_step.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/remove_tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/set_config.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/set_param.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/codegen/transformers/set_position.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/anthropic.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/default.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/message.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/string.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/impl/timbal.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/collectors/registry.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/agent.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/fallback_model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/mcp.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/memory_compaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/skill.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/test_model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/tool.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/tool_set.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/core/workflow.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/errors.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/display.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/agent.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_examples.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_flow_validators.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_negations.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_parallel.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_subagent.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/eval_transforms.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/fixtures/test_invalid_validator.yaml +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/models.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/comparison_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/contains.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/contains_all.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/contains_any.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/context.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/email.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/ends_with.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/eq.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/gt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/gte.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/json.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/language.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/llm_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/lt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/lte.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/max_length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/min_length.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/not_null.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/parallel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/pattern.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/prompt.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/semantic.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/seq.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/starts_with.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/evals/validators/type.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/logs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/integrations.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/knowledge_bases/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/knowledge_bases/query.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/tool_proxy.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/types.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/platform/utils.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/__main__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/http.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/server/jobs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/config.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/config_loader.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/context.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/dependency_analyzer.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/exporters/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/exporters/otel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/in_memory.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/jsonl.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/platform.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/providers/sqlite.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/span.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/state/tracing/trace.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/_creds.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/asana.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/bash.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/cala.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/cloudflare.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/dynamics_business_central.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/dynamics_sales.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/edit.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/elasticsearch.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/elevenlabs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/excel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/fal.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/fathom.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/firecrawl.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/gemini_images.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/gmail.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_analytics.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_business.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_calendar.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_docs.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_drive.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_maps.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_merchant_center.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_search_console.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/google_sheets.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/happy_scribe.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/higgsfield.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/hubspot.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/interaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/jira.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/klaviyo.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/knowledge_base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/krea.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/lancedb.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/linkedin.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/mongodb.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/netsuite.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/onedrive.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/outlook.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/parallel.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/pinecone.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/powerbi.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/quiver_ai.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/read.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/replicate.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/resend.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/salesforce.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/scraperapi.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/sharepoint.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/shopify.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/slack.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/stripe.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/tavily.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/web_search.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/write.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/xai.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/zendesk.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/tools/zoho_crm.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/approval.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/custom.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/file.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/text.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/tool_result.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/content/tool_use.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/approval.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/base.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/delta.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/interaction.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/output.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/events/start.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/file.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/types/run_status.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/__init__.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/import_spec.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/model.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/net.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/schema.py +0 -0
- {timbal-2.2.8 → timbal-2.2.10}/python/timbal/utils/serialization.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.10'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 2, 10)
|
|
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
|
|
@@ -5,17 +5,18 @@ import yaml
|
|
|
5
5
|
_MODELS_YAML = Path(__file__).parent.parent / "models.yaml"
|
|
6
6
|
|
|
7
7
|
_PROVIDER_LOGOS = {
|
|
8
|
-
"anthropic": "https://
|
|
9
|
-
"openai": "https://
|
|
10
|
-
"google": "https://
|
|
11
|
-
"togetherai": "https://
|
|
12
|
-
"xai": "https://
|
|
13
|
-
"groq": "https://
|
|
14
|
-
"fireworks": "https://
|
|
15
|
-
"xiaomi": "https://
|
|
16
|
-
"byteplus": "https://
|
|
17
|
-
"cerebras": "https://
|
|
18
|
-
"sambanova": "https://
|
|
8
|
+
"anthropic": "https://timbalusercontent.com/assets/anthropic_favicon.svg",
|
|
9
|
+
"openai": "https://timbalusercontent.com/assets/openai_favicon.svg",
|
|
10
|
+
"google": "https://timbalusercontent.com/assets/google_favicon.svg",
|
|
11
|
+
"togetherai": "https://timbalusercontent.com/assets/togetherai_favicon.svg",
|
|
12
|
+
"xai": "https://timbalusercontent.com/assets/xai_favicon.svg",
|
|
13
|
+
"groq": "https://timbalusercontent.com/assets/groq_favicon.svg",
|
|
14
|
+
"fireworks": "https://timbalusercontent.com/assets/fireworks_favicon.svg",
|
|
15
|
+
"xiaomi": "https://timbalusercontent.com/assets/xiaomi_favicon.svg",
|
|
16
|
+
"byteplus": "https://timbalusercontent.com/assets/byteplus_favicon.svg",
|
|
17
|
+
"cerebras": "https://timbalusercontent.com/assets/cerebras_favicon.svg",
|
|
18
|
+
"sambanova": "https://timbalusercontent.com/assets/sambanova_favicon.svg",
|
|
19
|
+
"moonshot": "https://timbalusercontent.com/assets/moonshot_favicon.svg",
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
|
|
@@ -132,7 +132,7 @@ def _discover_framework_tools() -> dict[str, FrameworkTool]:
|
|
|
132
132
|
for meta in typing.get_args(candidate)[1:]:
|
|
133
133
|
if isinstance(meta, _Integration):
|
|
134
134
|
provider = meta.provider
|
|
135
|
-
provider_logo = f"https://
|
|
135
|
+
provider_logo = f"https://timbalusercontent.com/assets/{provider}_favicon.svg"
|
|
136
136
|
break
|
|
137
137
|
if provider:
|
|
138
138
|
break
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import time
|
|
2
|
+
from collections import deque
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
5
|
# `override` was introduced in Python 3.12; use `typing_extensions` for compatibility with older versions
|
|
@@ -98,17 +99,37 @@ ResponseEvent = (
|
|
|
98
99
|
logger = structlog.get_logger("timbal.collectors.impl.openai")
|
|
99
100
|
|
|
100
101
|
|
|
102
|
+
def _delta_reasoning_content(delta: Any) -> str | None:
|
|
103
|
+
"""Extract chat-completions reasoning text (Fireworks / DeepSeek / etc.).
|
|
104
|
+
|
|
105
|
+
OpenAI's typed ``ChoiceDelta`` does not declare ``reasoning_content``; providers
|
|
106
|
+
put it on the delta as an extra field (kept in ``model_extra``).
|
|
107
|
+
"""
|
|
108
|
+
rc = getattr(delta, "reasoning_content", None)
|
|
109
|
+
if isinstance(rc, str) and rc:
|
|
110
|
+
return rc
|
|
111
|
+
extra = getattr(delta, "model_extra", None) or {}
|
|
112
|
+
if isinstance(extra, dict):
|
|
113
|
+
for key in ("reasoning_content", "reasoning"):
|
|
114
|
+
val = extra.get(key)
|
|
115
|
+
if isinstance(val, str) and val:
|
|
116
|
+
return val
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
|
|
101
120
|
@register_collector
|
|
102
121
|
class ChatCompletionCollector(BaseCollector):
|
|
103
122
|
"""Collector for OpenAI chat completions streaming events."""
|
|
104
123
|
|
|
105
124
|
# Content block ID for text content (chat completions only have one text block)
|
|
106
125
|
TEXT_BLOCK_ID = "text_0"
|
|
126
|
+
THINKING_BLOCK_ID = "thinking_0"
|
|
107
127
|
|
|
108
128
|
def __init__(self, start: float, **kwargs: Any):
|
|
109
129
|
super().__init__(**kwargs)
|
|
110
130
|
self._start = start
|
|
111
131
|
self._content: str = ""
|
|
132
|
+
self._thinking: str = ""
|
|
112
133
|
# `_current_tool_call` is appended to `_tool_calls` by reference (same dict).
|
|
113
134
|
# Subsequent mutations of `_current_tool_call` propagate to the entry in
|
|
114
135
|
# `_tool_calls` without needing to re-append.
|
|
@@ -118,15 +139,40 @@ class ChatCompletionCollector(BaseCollector):
|
|
|
118
139
|
self._first_token: float | None = None
|
|
119
140
|
self._output_tokens: int = 0
|
|
120
141
|
self._text_block_started: bool = False
|
|
142
|
+
self._thinking_block_started: bool = False
|
|
121
143
|
self._content_blocks: set[str] = set()
|
|
122
144
|
self._stop_reason: str | None = None
|
|
123
145
|
self._pending_usage: Any | None = None # Last usage event, written once in result()
|
|
146
|
+
# One source chunk can produce multiple stream items (e.g. reasoning + text).
|
|
147
|
+
# process() returns the first; the rest drain via __anext__ / pop_pending_stream_item().
|
|
148
|
+
self._pending_stream_items: deque[Any] = deque()
|
|
124
149
|
|
|
125
150
|
@classmethod
|
|
126
151
|
@override
|
|
127
152
|
def can_handle(cls, event: Any) -> bool:
|
|
128
153
|
return isinstance(event, ChatCompletionEvent)
|
|
129
154
|
|
|
155
|
+
def pop_pending_stream_item(self) -> Any | None:
|
|
156
|
+
"""Return the next queued stream item, if any (used after process() on the peek chunk)."""
|
|
157
|
+
if self._pending_stream_items:
|
|
158
|
+
return self._pending_stream_items.popleft()
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
async def __anext__(self):
|
|
162
|
+
pending = self.pop_pending_stream_item()
|
|
163
|
+
if pending is not None:
|
|
164
|
+
return pending
|
|
165
|
+
return await super().__anext__()
|
|
166
|
+
|
|
167
|
+
def _emit_stream_items(self, items: list[Any]) -> Any:
|
|
168
|
+
"""Return the first stream item and queue any remaining for later yields."""
|
|
169
|
+
filtered = [item for item in items if item is not None]
|
|
170
|
+
if not filtered:
|
|
171
|
+
return None
|
|
172
|
+
first, *rest = filtered
|
|
173
|
+
self._pending_stream_items.extend(rest)
|
|
174
|
+
return first
|
|
175
|
+
|
|
130
176
|
@override
|
|
131
177
|
def process(self, event: ChatCompletionEvent) -> Any:
|
|
132
178
|
"""Processes OpenAI streaming events."""
|
|
@@ -143,15 +189,24 @@ class ChatCompletionCollector(BaseCollector):
|
|
|
143
189
|
# 'length' indicates max_tokens was reached
|
|
144
190
|
if event.choices[0].finish_reason:
|
|
145
191
|
self._stop_reason = event.choices[0].finish_reason
|
|
146
|
-
|
|
147
|
-
|
|
192
|
+
delta = event.choices[0].delta
|
|
193
|
+
has_tool_calls = bool(delta.tool_calls)
|
|
194
|
+
reasoning = _delta_reasoning_content(delta)
|
|
195
|
+
has_text = bool(delta.content)
|
|
196
|
+
# Calculate TTFT on first visible / reasoning / tool token
|
|
197
|
+
if self._first_token is None and (has_tool_calls or reasoning or has_text):
|
|
148
198
|
self._first_token = time.perf_counter()
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if
|
|
154
|
-
|
|
199
|
+
|
|
200
|
+
# Fireworks / Moonshot / DeepSeek-style: reasoning may co-arrive with
|
|
201
|
+
# visible content or tool_calls on the same chunk. Emit all of them.
|
|
202
|
+
items: list[Any] = []
|
|
203
|
+
if reasoning:
|
|
204
|
+
items.append(self._handle_reasoning_content(reasoning))
|
|
205
|
+
if has_tool_calls:
|
|
206
|
+
items.append(self._handle_tool_calls(event))
|
|
207
|
+
elif has_text:
|
|
208
|
+
items.append(self._handle_text_content(event))
|
|
209
|
+
return self._emit_stream_items(items)
|
|
155
210
|
|
|
156
211
|
@staticmethod
|
|
157
212
|
def _usage_billing_id(api_model: str) -> str:
|
|
@@ -296,6 +351,21 @@ class ChatCompletionCollector(BaseCollector):
|
|
|
296
351
|
)
|
|
297
352
|
return None
|
|
298
353
|
|
|
354
|
+
def _handle_reasoning_content(self, reasoning_chunk: str) -> TimbalThinking | TimbalThinkingDelta:
|
|
355
|
+
"""Handle ``delta.reasoning_content`` from OpenAI-compatible reasoning models."""
|
|
356
|
+
self._thinking += reasoning_chunk
|
|
357
|
+
if not self._thinking_block_started:
|
|
358
|
+
self._thinking_block_started = True
|
|
359
|
+
self._content_blocks.add(self.THINKING_BLOCK_ID)
|
|
360
|
+
return TimbalThinking(
|
|
361
|
+
id=self.THINKING_BLOCK_ID,
|
|
362
|
+
thinking=reasoning_chunk,
|
|
363
|
+
)
|
|
364
|
+
return TimbalThinkingDelta(
|
|
365
|
+
id=self.THINKING_BLOCK_ID,
|
|
366
|
+
thinking_delta=reasoning_chunk,
|
|
367
|
+
)
|
|
368
|
+
|
|
299
369
|
def _handle_text_content(self, event: ChatCompletionEvent) -> TimbalText | TimbalTextDelta:
|
|
300
370
|
"""Handle text content from OpenAI events."""
|
|
301
371
|
text_chunk = event.choices[0].delta.content
|
|
@@ -325,12 +395,17 @@ class ChatCompletionCollector(BaseCollector):
|
|
|
325
395
|
self._handle_usage(self._pending_usage)
|
|
326
396
|
|
|
327
397
|
span = get_run_context().current_span()
|
|
328
|
-
|
|
398
|
+
# finish_reason-only chunks never set _first_token — keep metrics defined.
|
|
399
|
+
first = self._first_token if self._first_token is not None else time.perf_counter()
|
|
400
|
+
ttft = first - self._start
|
|
329
401
|
span.metadata["ttft"] = ttft
|
|
330
|
-
|
|
402
|
+
elapsed = time.perf_counter() - first
|
|
403
|
+
tps = self._output_tokens / elapsed if elapsed > 0 else 0.0
|
|
331
404
|
span.metadata["tps"] = tps
|
|
332
405
|
|
|
333
|
-
content = []
|
|
406
|
+
content: list[Any] = []
|
|
407
|
+
if self._thinking:
|
|
408
|
+
content.append({"type": "thinking", "thinking": self._thinking})
|
|
334
409
|
if self._content:
|
|
335
410
|
content.append(self._content)
|
|
336
411
|
|
|
@@ -118,6 +118,15 @@ class _ProviderConfig:
|
|
|
118
118
|
supports_stream_options: bool = True
|
|
119
119
|
"""Whether the provider supports ``stream_options`` in Chat Completions."""
|
|
120
120
|
|
|
121
|
+
supports_platform_proxy: bool = True
|
|
122
|
+
"""If False, never fall back to the Timbal platform proxy — require the provider API key."""
|
|
123
|
+
|
|
124
|
+
supports_chat_reasoning_content: bool = False
|
|
125
|
+
"""If True, serialize ThinkingContent as top-level ``reasoning_content`` (Moonshot/Fireworks-style).
|
|
126
|
+
|
|
127
|
+
Otherwise thinking is omitted from outbound chat-completions messages (Vercel/LiteLLM default).
|
|
128
|
+
"""
|
|
129
|
+
|
|
121
130
|
|
|
122
131
|
_PROVIDERS: dict[str, _ProviderConfig] = {
|
|
123
132
|
"openai": _ProviderConfig(
|
|
@@ -137,6 +146,7 @@ _PROVIDERS: dict[str, _ProviderConfig] = {
|
|
|
137
146
|
"togetherai": _ProviderConfig(
|
|
138
147
|
env_key="TOGETHER_API_KEY",
|
|
139
148
|
default_base_url="https://api.together.xyz/v1/",
|
|
149
|
+
supports_chat_reasoning_content=True,
|
|
140
150
|
),
|
|
141
151
|
"xai": _ProviderConfig(
|
|
142
152
|
env_key="XAI_API_KEY",
|
|
@@ -150,10 +160,12 @@ _PROVIDERS: dict[str, _ProviderConfig] = {
|
|
|
150
160
|
"fireworks": _ProviderConfig(
|
|
151
161
|
env_key="FIREWORKS_API_KEY",
|
|
152
162
|
default_base_url="https://api.fireworks.ai/inference/v1",
|
|
163
|
+
supports_chat_reasoning_content=True,
|
|
153
164
|
),
|
|
154
165
|
"byteplus": _ProviderConfig(
|
|
155
166
|
env_key="BYTEPLUS_API_KEY",
|
|
156
167
|
default_base_url="https://ark.ap-southeast.bytepluses.com/api/v3",
|
|
168
|
+
supports_chat_reasoning_content=True,
|
|
157
169
|
),
|
|
158
170
|
"xiaomi": _ProviderConfig(
|
|
159
171
|
env_key="XIAOMI_API_KEY",
|
|
@@ -165,6 +177,12 @@ _PROVIDERS: dict[str, _ProviderConfig] = {
|
|
|
165
177
|
env_key="CEREBRAS_API_KEY",
|
|
166
178
|
default_base_url="https://api.cerebras.ai/v1",
|
|
167
179
|
),
|
|
180
|
+
"moonshot": _ProviderConfig(
|
|
181
|
+
env_key="MOONSHOT_API_KEY",
|
|
182
|
+
default_base_url="https://api.moonshot.ai/v1",
|
|
183
|
+
supports_platform_proxy=False,
|
|
184
|
+
supports_chat_reasoning_content=True,
|
|
185
|
+
),
|
|
168
186
|
"sambanova": _ProviderConfig(
|
|
169
187
|
env_key="SAMBANOVA_API_KEY",
|
|
170
188
|
default_base_url="https://api.sambanova.ai/v1",
|
|
@@ -188,7 +206,11 @@ def _resolve_client(
|
|
|
188
206
|
if not api_key:
|
|
189
207
|
api_key = os.getenv(config.env_key)
|
|
190
208
|
if not api_key:
|
|
191
|
-
if
|
|
209
|
+
if (
|
|
210
|
+
config.supports_platform_proxy
|
|
211
|
+
and run_context.platform_config is not None
|
|
212
|
+
and run_context.platform_config.subject is not None
|
|
213
|
+
):
|
|
192
214
|
api_key = run_context.platform_config.auth.header_value
|
|
193
215
|
base_url = (
|
|
194
216
|
f"https://{run_context.platform_config.host}"
|
|
@@ -416,8 +438,9 @@ async def _llm_router(
|
|
|
416
438
|
# Per-request headers: change every call, so passed via extra_headers on each .create().
|
|
417
439
|
request_headers: dict[str, str] = {
|
|
418
440
|
"x-timbal-run-id": run_context.id,
|
|
419
|
-
"x-timbal-call-id": call_id,
|
|
420
441
|
}
|
|
442
|
+
if call_id:
|
|
443
|
+
request_headers["x-timbal-call-id"] = call_id
|
|
421
444
|
if run_context.platform_config and run_context.platform_config.subject:
|
|
422
445
|
if run_context.platform_config.subject.app_id:
|
|
423
446
|
request_headers["x-timbal-app-id"] = run_context.platform_config.subject.app_id
|
|
@@ -528,8 +551,9 @@ async def _llm_router(
|
|
|
528
551
|
chat_completions_messages = []
|
|
529
552
|
if system_prompt:
|
|
530
553
|
chat_completions_messages.append({"role": "system", "content": system_prompt})
|
|
554
|
+
reasoning_as = "reasoning_content" if config.supports_chat_reasoning_content else "omit"
|
|
531
555
|
for message in messages:
|
|
532
|
-
chat_completions_message = message.to_openai_chat_completions_input()
|
|
556
|
+
chat_completions_message = message.to_openai_chat_completions_input(reasoning_as=reasoning_as)
|
|
533
557
|
chat_completions_messages.append(chat_completions_message)
|
|
534
558
|
|
|
535
559
|
# Some providers have incomplete OpenAI chat completions support.
|
|
@@ -54,7 +54,12 @@ 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.5-pro",
|
|
58
|
+
"openai/gpt-5.6-sol",
|
|
59
|
+
"openai/gpt-5.6-terra",
|
|
60
|
+
"openai/gpt-5.6-luna",
|
|
57
61
|
"openai/gpt-5.4",
|
|
62
|
+
"openai/gpt-5.4-pro",
|
|
58
63
|
"openai/gpt-5.4-mini",
|
|
59
64
|
"openai/gpt-5.4-nano",
|
|
60
65
|
"openai/gpt-5.3-chat-latest",
|
|
@@ -88,9 +93,12 @@ Model = Literal[
|
|
|
88
93
|
"togetherai/deepseek-ai/DeepSeek-V3.1",
|
|
89
94
|
"togetherai/deepseek-ai/DeepSeek-V4-Pro",
|
|
90
95
|
"togetherai/moonshotai/Kimi-K2.6",
|
|
96
|
+
"togetherai/moonshotai/Kimi-K2.7-Code",
|
|
91
97
|
"togetherai/MiniMaxAI/MiniMax-M2.7",
|
|
98
|
+
"togetherai/MiniMaxAI/MiniMax-M3",
|
|
92
99
|
"togetherai/zai-org/GLM-5",
|
|
93
100
|
"togetherai/zai-org/GLM-5.1",
|
|
101
|
+
"togetherai/zai-org/GLM-5.2",
|
|
94
102
|
"togetherai/zai-org/GLM-4.7",
|
|
95
103
|
"togetherai/openai/gpt-oss-120b",
|
|
96
104
|
"togetherai/openai/gpt-oss-20b",
|
|
@@ -108,28 +116,27 @@ Model = Literal[
|
|
|
108
116
|
"google/gemini-2.5-flash-lite",
|
|
109
117
|
"google/gemini-2.5-flash-image",
|
|
110
118
|
"google/gemini-2.5-flash-preview-tts",
|
|
111
|
-
"xai/grok-4",
|
|
112
|
-
"xai/grok-4
|
|
113
|
-
"xai/grok-4-fast-non-reasoning",
|
|
114
|
-
"xai/grok-4-1-fast-reasoning",
|
|
115
|
-
"xai/grok-4-1-fast-non-reasoning",
|
|
116
|
-
"groq/meta-llama/llama-4-scout-17b-16e-instruct",
|
|
119
|
+
"xai/grok-4.5",
|
|
120
|
+
"xai/grok-4.3",
|
|
117
121
|
"groq/llama-3.3-70b-versatile",
|
|
118
122
|
"groq/llama-3.1-8b-instant",
|
|
119
|
-
"groq/qwen/qwen3-
|
|
123
|
+
"groq/qwen/qwen3.6-27b",
|
|
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",
|
|
131
|
+
"fireworks/accounts/fireworks/models/kimi-k2p7-code",
|
|
125
132
|
"fireworks/accounts/fireworks/models/kimi-k2p5",
|
|
126
133
|
"fireworks/accounts/fireworks/models/minimax-m2p5",
|
|
134
|
+
"fireworks/accounts/fireworks/models/minimax-m2p7",
|
|
135
|
+
"fireworks/accounts/fireworks/models/minimax-m3",
|
|
127
136
|
"fireworks/accounts/fireworks/models/gpt-oss-120b",
|
|
128
137
|
"fireworks/accounts/fireworks/models/gpt-oss-20b",
|
|
129
138
|
"fireworks/accounts/fireworks/models/glm-5p1",
|
|
130
|
-
"
|
|
131
|
-
"xiaomi/mimo-v2-omni",
|
|
132
|
-
"xiaomi/mimo-v2-flash",
|
|
139
|
+
"fireworks/accounts/fireworks/models/glm-5p2",
|
|
133
140
|
"xiaomi/mimo-v2.5",
|
|
134
141
|
"xiaomi/mimo-v2.5-pro",
|
|
135
142
|
"byteplus/seed-2-0-lite-260228",
|
|
@@ -156,4 +163,9 @@ Model = Literal[
|
|
|
156
163
|
"sambanova/MiniMax-M2.7",
|
|
157
164
|
"sambanova/gemma-3-12b-it",
|
|
158
165
|
"sambanova/gemma-4-31B-it",
|
|
166
|
+
"moonshot/kimi-k3",
|
|
167
|
+
"moonshot/kimi-k2.7-code",
|
|
168
|
+
"moonshot/kimi-k2.7-code-highspeed",
|
|
169
|
+
"moonshot/kimi-k2.6",
|
|
170
|
+
"moonshot/kimi-k2.5",
|
|
159
171
|
]
|
|
@@ -1022,12 +1022,22 @@ class Runnable(ABC, BaseModel):
|
|
|
1022
1022
|
event_queue.put_nowait(event)
|
|
1023
1023
|
return event
|
|
1024
1024
|
|
|
1025
|
-
# We need to manually process the first chunk, since we removed it from the generator
|
|
1025
|
+
# We need to manually process the first chunk, since we removed it from the generator.
|
|
1026
|
+
# Some collectors (e.g. ChatCompletionCollector) can emit multiple stream items
|
|
1027
|
+
# per source chunk — process() returns the first and queues the rest.
|
|
1026
1028
|
first_event = collector.process(first_chunk)
|
|
1027
|
-
if first_event is not None
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1029
|
+
pending_events = [first_event] if first_event is not None else []
|
|
1030
|
+
pop_pending = getattr(collector, "pop_pending_stream_item", None)
|
|
1031
|
+
if callable(pop_pending):
|
|
1032
|
+
while True:
|
|
1033
|
+
pending_item = pop_pending()
|
|
1034
|
+
if pending_item is None:
|
|
1035
|
+
break
|
|
1036
|
+
pending_events.append(pending_item)
|
|
1037
|
+
for raw_event in pending_events:
|
|
1038
|
+
event = process_event(raw_event)
|
|
1039
|
+
if event is not None:
|
|
1040
|
+
yield (event, None, collector)
|
|
1031
1041
|
# Process remaining events
|
|
1032
1042
|
async for event in collector:
|
|
1033
1043
|
event = process_event(event)
|