timbal 2.2.6__tar.gz → 2.2.8__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.6 → timbal-2.2.8}/PKG-INFO +1 -1
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/_version.py +2 -2
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/cli_utils.py +17 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/cst_utils.py +71 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/add_edge.py +11 -3
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/add_step.py +24 -7
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/add_tool.py +2 -3
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/remove_edge.py +11 -2
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/set_config.py +2 -3
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/set_param.py +37 -11
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/set_position.py +11 -1
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/models.py +2 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/models.yaml +20 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/file.py +23 -8
- {timbal-2.2.6 → timbal-2.2.8}/.gitignore +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/LICENSE +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/README.md +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/chat-completions.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/create-from-workforce.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/jobs/cancel.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/jobs/get.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/jobs/list.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/jobs/retry.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/link.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/list-context-vars.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/list-policies.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/messages.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/responses.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/docs/api-reference/ace/unlink.mdx +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/pyproject.toml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/pyrightconfig.json +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/__main__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/flow.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/format.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/model_discovery.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/test.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/tool_discovery.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/remove_step.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/codegen/transformers/remove_tool.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/anthropic.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/default.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/message.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/openai.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/string.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/impl/timbal.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/collectors/registry.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/agent.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/fallback_model.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/llm_router.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/mcp.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/memory_compaction.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/runnable.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/skill.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/test_model.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/tool.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/tool_set.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/core/workflow.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/errors.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/cli.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/display.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/agent.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_examples.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_flow_validators.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_negations.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_parallel.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_subagent.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/eval_transforms.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/fixtures/test_invalid_validator.yaml +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/models.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/runner.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/utils.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/comparison_base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/contains.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/contains_all.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/contains_any.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/context.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/email.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/ends_with.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/eq.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/gt.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/gte.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/json.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/language.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/length.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/llm_base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/lt.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/lte.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/max_length.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/min_length.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/not_null.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/parallel.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/pattern.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/prompt.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/semantic.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/seq.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/starts_with.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/evals/validators/type.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/logs.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/integrations.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/knowledge_bases/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/knowledge_bases/query.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/tool_proxy.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/types.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/platform/utils.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/__main__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/http.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/jobs.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/voice.html +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/server/voice.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/config.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/config_loader.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/context.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/dependency_analyzer.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/exporters/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/exporters/otel.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/in_memory.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/jsonl.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/platform.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/providers/sqlite.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/span.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/state/tracing/trace.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/_creds.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/asana.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/bash.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/cala.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/cloudflare.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/dynamics_business_central.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/dynamics_sales.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/edit.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/elasticsearch.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/elevenlabs.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/excel.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/fal.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/fathom.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/firecrawl.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/gemini_images.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/gmail.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_analytics.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_business.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_calendar.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_docs.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_drive.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_maps.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_merchant_center.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_search_console.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/google_sheets.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/happy_scribe.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/higgsfield.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/hubspot.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/interaction.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/jira.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/klaviyo.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/knowledge_base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/krea.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/lancedb.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/linkedin.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/mongodb.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/netsuite.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/onedrive.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/outlook.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/parallel.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/pinecone.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/powerbi.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/quiver_ai.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/read.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/replicate.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/resend.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/salesforce.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/scraperapi.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/sharepoint.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/shopify.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/slack.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/stripe.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/tavily.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/web_search.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/write.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/xai.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/zendesk.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/tools/zoho_crm.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/approval.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/custom.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/file.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/text.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/thinking.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/tool_result.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/content/tool_use.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/approval.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/base.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/delta.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/interaction.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/output.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/events/start.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/message.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/types/run_status.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/import_spec.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/model.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/net.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/schema.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/utils/serialization.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/voice/__init__.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/python/timbal/voice/elevenlabs.py +0 -0
- {timbal-2.2.6 → timbal-2.2.8}/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.8'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 2, 8)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -3,10 +3,27 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
+
import json
|
|
6
7
|
import sys
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
|
|
11
|
+
def parse_json_arg(raw: str, flag: str, *, hint: str = "") -> object:
|
|
12
|
+
"""Parse a CLI argument as JSON, raising a clear ``ValueError`` on failure.
|
|
13
|
+
|
|
14
|
+
``json.JSONDecodeError`` messages like ``Expecting value: line 1 column 1``
|
|
15
|
+
give no clue that the fix is quoting; this wraps them with the flag name,
|
|
16
|
+
the offending input, and an optional usage hint.
|
|
17
|
+
"""
|
|
18
|
+
try:
|
|
19
|
+
return json.loads(raw)
|
|
20
|
+
except json.JSONDecodeError as e:
|
|
21
|
+
message = f"{flag} must be a valid JSON literal (got {raw!r}): {e}."
|
|
22
|
+
if hint:
|
|
23
|
+
message = f"{message} {hint}"
|
|
24
|
+
raise ValueError(message) from e
|
|
25
|
+
|
|
26
|
+
|
|
10
27
|
def arg_input(value: str) -> str:
|
|
11
28
|
"""argparse ``type`` callable supporting file and stdin redirection.
|
|
12
29
|
|
|
@@ -190,6 +190,77 @@ def collect_step_names(
|
|
|
190
190
|
return var_to_name
|
|
191
191
|
|
|
192
192
|
|
|
193
|
+
def collect_chained_step_names(
|
|
194
|
+
tree: cst.Module,
|
|
195
|
+
entry_point: str,
|
|
196
|
+
assignments: dict[str, cst.Call],
|
|
197
|
+
) -> dict[str, str]:
|
|
198
|
+
"""Build a step variable → runtime name mapping for chained ``.step()`` calls.
|
|
199
|
+
|
|
200
|
+
Covers steps added in the entry point assignment itself, e.g.
|
|
201
|
+
``workflow = Workflow(...).step(a).step(b)``. These steps exist in the
|
|
202
|
+
graph but cannot be modified by the standalone-statement transformers
|
|
203
|
+
(set-param, add-edge, remove-edge).
|
|
204
|
+
"""
|
|
205
|
+
var_to_name: dict[str, str] = {}
|
|
206
|
+
for stmt in tree.body:
|
|
207
|
+
if not isinstance(stmt, cst.SimpleStatementLine):
|
|
208
|
+
continue
|
|
209
|
+
for item in stmt.body:
|
|
210
|
+
if not isinstance(item, cst.Assign):
|
|
211
|
+
continue
|
|
212
|
+
if not any(
|
|
213
|
+
isinstance(t.target, cst.Name) and t.target.value == entry_point
|
|
214
|
+
for t in item.targets
|
|
215
|
+
):
|
|
216
|
+
continue
|
|
217
|
+
node = item.value
|
|
218
|
+
while isinstance(node, cst.Call) and isinstance(node.func, cst.Attribute):
|
|
219
|
+
if node.func.attr.value == "step" and node.args:
|
|
220
|
+
first_arg = node.args[0].value
|
|
221
|
+
resolved = resolve_runnable_name(first_arg, assignments)
|
|
222
|
+
if isinstance(first_arg, cst.Name):
|
|
223
|
+
var_to_name[first_arg.value] = resolved if resolved is not None else first_arg.value
|
|
224
|
+
elif resolved is not None:
|
|
225
|
+
var_to_name[resolved] = resolved
|
|
226
|
+
node = node.func.value
|
|
227
|
+
return var_to_name
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def require_step(
|
|
231
|
+
ref: str,
|
|
232
|
+
step_names: dict[str, str],
|
|
233
|
+
chained_step_names: dict[str, str] | None = None,
|
|
234
|
+
*,
|
|
235
|
+
kind: str = "Target",
|
|
236
|
+
operation: str,
|
|
237
|
+
) -> str:
|
|
238
|
+
"""Resolve *ref* (a step variable name or runtime name) to the runtime name.
|
|
239
|
+
|
|
240
|
+
``step_names`` are the steps the operation can address. When *ref* only
|
|
241
|
+
matches ``chained_step_names`` (steps the operation cannot modify), or
|
|
242
|
+
matches nothing, a ``ValueError`` with an actionable message is raised.
|
|
243
|
+
"""
|
|
244
|
+
if ref in step_names.values():
|
|
245
|
+
return ref
|
|
246
|
+
if ref in step_names:
|
|
247
|
+
return step_names[ref]
|
|
248
|
+
|
|
249
|
+
chained = chained_step_names or {}
|
|
250
|
+
if ref in chained or ref in chained.values():
|
|
251
|
+
raise ValueError(
|
|
252
|
+
f"{kind} step '{ref}' is added via a chained .step() call, which {operation} "
|
|
253
|
+
f"cannot modify. Rewrite it as a standalone '<workflow>.step(...)' statement first."
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
available = sorted(set(step_names.values()) | set(chained.values()))
|
|
257
|
+
if available:
|
|
258
|
+
raise ValueError(
|
|
259
|
+
f"{kind} step '{ref}' not found in workflow. Available steps: {', '.join(available)}."
|
|
260
|
+
)
|
|
261
|
+
raise ValueError(f"{kind} step '{ref}' not found in workflow. The workflow has no steps.")
|
|
262
|
+
|
|
263
|
+
|
|
193
264
|
def is_bare_function_step(
|
|
194
265
|
tree: cst.Module,
|
|
195
266
|
entry_point: str,
|
|
@@ -5,8 +5,10 @@ import libcst as cst
|
|
|
5
5
|
from ..cli_utils import arg_input
|
|
6
6
|
from ..cst_utils import (
|
|
7
7
|
collect_assignments,
|
|
8
|
+
collect_chained_step_names,
|
|
8
9
|
collect_step_names,
|
|
9
10
|
has_import,
|
|
11
|
+
require_step,
|
|
10
12
|
resolve_entry_point_type,
|
|
11
13
|
)
|
|
12
14
|
|
|
@@ -45,10 +47,16 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
45
47
|
raise ValueError("add-edge requires a Workflow entry point.")
|
|
46
48
|
|
|
47
49
|
when_expr = args.when if args.when else None
|
|
48
|
-
assignments = collect_assignments(tree)
|
|
49
|
-
step_names = collect_step_names(tree, entry_point, assignments)
|
|
50
|
+
assignments = collect_assignments(tree)
|
|
51
|
+
step_names = collect_step_names(tree, entry_point, assignments)
|
|
52
|
+
chained_step_names = collect_chained_step_names(tree, entry_point, assignments)
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
require_step(args.target, step_names, chained_step_names, kind="Target", operation="add-edge")
|
|
55
|
+
# Sources only need to exist in the graph — they are referenced by runtime
|
|
56
|
+
# name inside the target's depends_on list.
|
|
57
|
+
source = require_step(args.source, {**step_names, **chained_step_names}, kind="Source", operation="add-edge")
|
|
58
|
+
|
|
59
|
+
return EdgeAdder(entry_point, source, args.target, when_expr, assignments, step_names)
|
|
52
60
|
|
|
53
61
|
|
|
54
62
|
class EdgeAdder(cst.CSTTransformer):
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
import json
|
|
3
2
|
|
|
4
3
|
import libcst as cst
|
|
5
4
|
|
|
6
|
-
from ..cli_utils import arg_input
|
|
5
|
+
from ..cli_utils import arg_input, parse_json_arg
|
|
7
6
|
from ..cst_utils import (
|
|
8
7
|
build_cst_value,
|
|
9
8
|
collect_assignments,
|
|
@@ -132,6 +131,19 @@ def _clean_position(position: dict[str, float]) -> dict[str, int | float]:
|
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
|
|
134
|
+
def _reject_non_name_config(config: dict, step_kind: str) -> None:
|
|
135
|
+
"""Only Agent steps take constructor params via --config; for other step
|
|
136
|
+
kinds the only accepted key is 'name' (an alias for --name). Anything else
|
|
137
|
+
would previously be dropped silently — a common trap."""
|
|
138
|
+
unknown = set(config.keys()) - {"name"}
|
|
139
|
+
if unknown:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"--config for {step_kind} steps only accepts 'name'; "
|
|
142
|
+
f"got: {', '.join(sorted(unknown))}. "
|
|
143
|
+
f"Use set-param to set the step's parameters, or set-config for its constructor."
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
135
147
|
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
136
148
|
sp = subparsers.add_parser(
|
|
137
149
|
"add-step",
|
|
@@ -160,6 +172,8 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
160
172
|
type=arg_input,
|
|
161
173
|
help=(
|
|
162
174
|
'Agent constructor params as JSON. E.g. \'{"name": "agent_a", "model": "openai/gpt-4o-mini"}\'. '
|
|
175
|
+
"Framework tool and Custom steps only accept 'name' here (equivalent to --name); "
|
|
176
|
+
"use set-param for their step parameters. "
|
|
163
177
|
"Use '@path' to read from file or '-' to read from stdin."
|
|
164
178
|
),
|
|
165
179
|
)
|
|
@@ -175,7 +189,7 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
175
189
|
|
|
176
190
|
assignments = collect_assignments(tree) if tree else {}
|
|
177
191
|
step_type = args.step_type
|
|
178
|
-
config =
|
|
192
|
+
config = parse_json_arg(args.config, "--config") if args.config else {}
|
|
179
193
|
|
|
180
194
|
if args.x is not None and args.y is not None:
|
|
181
195
|
position = _clean_position({"x": args.x, "y": args.y})
|
|
@@ -199,6 +213,7 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
199
213
|
)
|
|
200
214
|
|
|
201
215
|
if step_type == "Custom":
|
|
216
|
+
_reject_non_name_config(config, "Custom")
|
|
202
217
|
if not args.definition:
|
|
203
218
|
raise ValueError("--definition is required for Custom steps.")
|
|
204
219
|
func_tree = cst.parse_module(args.definition)
|
|
@@ -210,7 +225,7 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
210
225
|
if func_def is None:
|
|
211
226
|
raise ValueError("--definition must contain a function definition.")
|
|
212
227
|
func_name = func_def.name.value
|
|
213
|
-
runtime_name = args.step_name
|
|
228
|
+
runtime_name = args.step_name or config.get("name") or func_name
|
|
214
229
|
var_name = runtime_name
|
|
215
230
|
# When the function name collides with the Tool variable name, add
|
|
216
231
|
# a _fn suffix to the function to avoid shadowing.
|
|
@@ -258,9 +273,11 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
258
273
|
)
|
|
259
274
|
|
|
260
275
|
# Framework tool step.
|
|
276
|
+
_reject_non_name_config(config, "framework tool")
|
|
261
277
|
framework_names = get_framework_tool_names()
|
|
262
|
-
|
|
263
|
-
|
|
278
|
+
step_name = args.step_name or config.get("name")
|
|
279
|
+
var_name = step_name if step_name else framework_names[step_type]
|
|
280
|
+
runtime_name = step_name if step_name else framework_names[step_type]
|
|
264
281
|
return StepAdder(
|
|
265
282
|
entry_point, assignments,
|
|
266
283
|
step_type=step_type,
|
|
@@ -268,7 +285,7 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
268
285
|
func_name=None,
|
|
269
286
|
var_name=var_name,
|
|
270
287
|
runtime_name=runtime_name,
|
|
271
|
-
step_name=
|
|
288
|
+
step_name=step_name,
|
|
272
289
|
position=position,
|
|
273
290
|
)
|
|
274
291
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
import json
|
|
3
2
|
|
|
4
3
|
import libcst as cst
|
|
5
4
|
|
|
6
|
-
from ..cli_utils import arg_input
|
|
5
|
+
from ..cli_utils import arg_input, parse_json_arg
|
|
7
6
|
from ..cst_utils import (
|
|
8
7
|
build_cst_value,
|
|
9
8
|
collect_assignments,
|
|
@@ -99,7 +98,7 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
99
98
|
if args.tool_name is not None and args.tool_name == "":
|
|
100
99
|
raise ValueError("--name cannot be empty. Omit --name to use the default tool name.")
|
|
101
100
|
|
|
102
|
-
config =
|
|
101
|
+
config = parse_json_arg(args.config, "--config") if getattr(args, "config", None) else {}
|
|
103
102
|
if config:
|
|
104
103
|
# Reject keys that would collide with explicit flags / derived values.
|
|
105
104
|
# Without this, the generated source has duplicate kwargs and ruff
|
|
@@ -4,7 +4,9 @@ import libcst as cst
|
|
|
4
4
|
|
|
5
5
|
from ..cst_utils import (
|
|
6
6
|
collect_assignments,
|
|
7
|
+
collect_chained_step_names,
|
|
7
8
|
collect_step_names,
|
|
9
|
+
require_step,
|
|
8
10
|
resolve_entry_point_type,
|
|
9
11
|
)
|
|
10
12
|
|
|
@@ -32,8 +34,15 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
32
34
|
if ep_type != "Workflow":
|
|
33
35
|
raise ValueError("remove-edge requires a Workflow entry point.")
|
|
34
36
|
|
|
35
|
-
assignments = collect_assignments(tree)
|
|
36
|
-
step_names = collect_step_names(tree, entry_point, assignments)
|
|
37
|
+
assignments = collect_assignments(tree)
|
|
38
|
+
step_names = collect_step_names(tree, entry_point, assignments)
|
|
39
|
+
chained_step_names = collect_chained_step_names(tree, entry_point, assignments)
|
|
40
|
+
|
|
41
|
+
# Only the target must be addressable — the source may already have been
|
|
42
|
+
# removed from the workflow, and remove-edge is how dangling references
|
|
43
|
+
# (stale depends_on entries, step_span kwargs) get cleaned up.
|
|
44
|
+
require_step(args.target, step_names, chained_step_names, kind="Target", operation="remove-edge")
|
|
45
|
+
|
|
37
46
|
return EdgeRemover(entry_point, args.source, args.target, assignments, step_names)
|
|
38
47
|
|
|
39
48
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
import json
|
|
3
2
|
|
|
4
3
|
import libcst as cst
|
|
5
4
|
|
|
6
|
-
from ..cli_utils import arg_input
|
|
5
|
+
from ..cli_utils import arg_input, parse_json_arg
|
|
7
6
|
from ..cst_utils import (
|
|
8
7
|
build_cst_value,
|
|
9
8
|
collect_assignments,
|
|
@@ -53,7 +52,7 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
53
52
|
def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None = None) -> cst.CSTTransformer:
|
|
54
53
|
ep_type = resolve_entry_point_type(tree, entry_point) if tree else None
|
|
55
54
|
|
|
56
|
-
config =
|
|
55
|
+
config = parse_json_arg(args.config, "--config") if args.config else {}
|
|
57
56
|
|
|
58
57
|
# --- Workflow entry point ---
|
|
59
58
|
if ep_type == "Workflow":
|
|
@@ -4,10 +4,13 @@ import re
|
|
|
4
4
|
|
|
5
5
|
import libcst as cst
|
|
6
6
|
|
|
7
|
-
from ..cli_utils import arg_input
|
|
7
|
+
from ..cli_utils import arg_input, parse_json_arg
|
|
8
8
|
from ..cst_utils import (
|
|
9
9
|
collect_assignments,
|
|
10
|
+
collect_chained_step_names,
|
|
11
|
+
collect_step_names,
|
|
10
12
|
has_import,
|
|
13
|
+
require_step,
|
|
11
14
|
resolve_entry_point_type,
|
|
12
15
|
resolve_runnable_name,
|
|
13
16
|
)
|
|
@@ -108,7 +111,9 @@ def register(subparsers: argparse._SubParsersAction) -> None:
|
|
|
108
111
|
default=None,
|
|
109
112
|
type=arg_input,
|
|
110
113
|
help=(
|
|
111
|
-
"Static value as a JSON literal (required for type=value).
|
|
114
|
+
"Static value as a JSON literal (required for type=value). "
|
|
115
|
+
"Strings must include the JSON quotes, e.g. --value '\"is:unread\"'. "
|
|
116
|
+
"Use 'null' to remove the param. "
|
|
112
117
|
"Use '@path' to read from file or '-' to read from stdin."
|
|
113
118
|
),
|
|
114
119
|
)
|
|
@@ -120,32 +125,48 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
120
125
|
if ep_type != "Workflow":
|
|
121
126
|
raise ValueError("set-param requires a Workflow entry point.")
|
|
122
127
|
|
|
128
|
+
assignments = collect_assignments(tree)
|
|
129
|
+
step_names = collect_step_names(tree, entry_point, assignments)
|
|
130
|
+
chained_step_names = collect_chained_step_names(tree, entry_point, assignments)
|
|
131
|
+
|
|
132
|
+
require_step(args.target, step_names, chained_step_names, kind="Target", operation="set-param")
|
|
133
|
+
|
|
123
134
|
param_type = args.param_type
|
|
124
135
|
|
|
125
136
|
if param_type == "map":
|
|
126
137
|
if not args.source:
|
|
127
138
|
raise ValueError("--source is required for type=map.")
|
|
139
|
+
# Sources only need to exist in the graph (chained steps are fine) —
|
|
140
|
+
# they are referenced by runtime name inside step_span().
|
|
141
|
+
source = require_step(
|
|
142
|
+
args.source, {**step_names, **chained_step_names}, kind="Source", operation="set-param",
|
|
143
|
+
)
|
|
128
144
|
return ParamSetter(
|
|
129
145
|
entry_point=entry_point,
|
|
130
146
|
target=args.target,
|
|
131
147
|
param_name=args.name,
|
|
132
148
|
param_type="map",
|
|
133
|
-
source=
|
|
149
|
+
source=source,
|
|
134
150
|
key=args.key,
|
|
135
|
-
assignments=
|
|
151
|
+
assignments=assignments,
|
|
152
|
+
step_names=step_names,
|
|
136
153
|
)
|
|
137
154
|
|
|
138
155
|
if param_type == "value":
|
|
139
156
|
if args.value is None:
|
|
140
157
|
raise ValueError("--value is required for type=value.")
|
|
141
|
-
value =
|
|
158
|
+
value = parse_json_arg(
|
|
159
|
+
args.value, "--value",
|
|
160
|
+
hint="String values must include the JSON quotes, e.g. --value '\"is:unread label:inbox\"'.",
|
|
161
|
+
)
|
|
142
162
|
return ParamSetter(
|
|
143
163
|
entry_point=entry_point,
|
|
144
164
|
target=args.target,
|
|
145
165
|
param_name=args.name,
|
|
146
166
|
param_type="value",
|
|
147
167
|
value=value,
|
|
148
|
-
assignments=
|
|
168
|
+
assignments=assignments,
|
|
169
|
+
step_names=step_names,
|
|
149
170
|
)
|
|
150
171
|
|
|
151
172
|
raise ValueError(f"Unknown param type: {param_type}")
|
|
@@ -164,6 +185,7 @@ class ParamSetter(cst.CSTTransformer):
|
|
|
164
185
|
key: str | None = None,
|
|
165
186
|
value: object = None,
|
|
166
187
|
assignments: dict[str, cst.Call] | None = None,
|
|
188
|
+
step_names: dict[str, str] | None = None,
|
|
167
189
|
):
|
|
168
190
|
self.entry_point = entry_point
|
|
169
191
|
self.target = target
|
|
@@ -173,6 +195,7 @@ class ParamSetter(cst.CSTTransformer):
|
|
|
173
195
|
self.key = key
|
|
174
196
|
self.value = value
|
|
175
197
|
self.assignments = assignments or {}
|
|
198
|
+
self.step_names = step_names or {}
|
|
176
199
|
self.needs_reorder = param_type == "map"
|
|
177
200
|
|
|
178
201
|
def _is_step_call(self, call: cst.Call) -> bool:
|
|
@@ -197,16 +220,19 @@ class ParamSetter(cst.CSTTransformer):
|
|
|
197
220
|
return False
|
|
198
221
|
|
|
199
222
|
def _matches_target(self, call: cst.Call) -> bool:
|
|
223
|
+
"""Match by variable name or runtime name (mirrors add-edge)."""
|
|
200
224
|
if not call.args:
|
|
201
225
|
return False
|
|
202
226
|
first_arg = call.args[0].value
|
|
203
227
|
if isinstance(first_arg, cst.Name):
|
|
204
228
|
var_name = first_arg.value
|
|
205
|
-
if var_name
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
229
|
+
if var_name == self.target:
|
|
230
|
+
return True
|
|
231
|
+
runtime_name = self.step_names.get(var_name)
|
|
232
|
+
if runtime_name is None and var_name in self.assignments:
|
|
233
|
+
runtime_name = resolve_runnable_name(self.assignments[var_name])
|
|
234
|
+
if runtime_name is not None and runtime_name == self.target:
|
|
235
|
+
return True
|
|
210
236
|
return False
|
|
211
237
|
|
|
212
238
|
def leave_Expr(self, original_node: cst.Expr, updated_node: cst.Expr) -> cst.Expr:
|
|
@@ -5,7 +5,10 @@ import libcst as cst
|
|
|
5
5
|
from ..cst_utils import (
|
|
6
6
|
build_cst_value,
|
|
7
7
|
collect_assignments,
|
|
8
|
+
collect_chained_step_names,
|
|
9
|
+
collect_step_names,
|
|
8
10
|
is_bare_function_step,
|
|
11
|
+
require_step,
|
|
9
12
|
resolve_entry_point_type,
|
|
10
13
|
resolve_runnable_name,
|
|
11
14
|
wrap_bare_function_step,
|
|
@@ -42,7 +45,14 @@ def run(entry_point: str, args: argparse.Namespace, *, tree: cst.Module | None =
|
|
|
42
45
|
assignments = collect_assignments(tree)
|
|
43
46
|
return StepPositionSetter(entry_point, args.name, position, assignments), tree
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
# Position lives on the step's constructor assignment, so chained
|
|
49
|
+
# steps are addressable too — validate against the full graph.
|
|
50
|
+
step_names = collect_step_names(tree, entry_point, assignments)
|
|
51
|
+
chained_step_names = collect_chained_step_names(tree, entry_point, assignments)
|
|
52
|
+
name = require_step(
|
|
53
|
+
args.name, {**step_names, **chained_step_names}, kind="Target", operation="set-position",
|
|
54
|
+
)
|
|
55
|
+
return StepPositionSetter(entry_point, name, position, assignments)
|
|
46
56
|
|
|
47
57
|
# Agent (or unknown) entry point — set on the constructor directly.
|
|
48
58
|
if args.name:
|
|
@@ -43,7 +43,9 @@ def get_context_window(model_id: str) -> int | None:
|
|
|
43
43
|
# ---------------------------------------------------------------------------
|
|
44
44
|
# Model type with provider prefixes
|
|
45
45
|
Model = Literal[
|
|
46
|
+
"anthropic/claude-fable-5",
|
|
46
47
|
"anthropic/claude-opus-4-8",
|
|
48
|
+
"anthropic/claude-sonnet-5",
|
|
47
49
|
"anthropic/claude-opus-4-7",
|
|
48
50
|
"anthropic/claude-opus-4-6",
|
|
49
51
|
"anthropic/claude-opus-4-5",
|
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
models:
|
|
12
12
|
|
|
13
|
+
- id: "anthropic/claude-fable-5"
|
|
14
|
+
provider: anthropic
|
|
15
|
+
display_name: "Claude Fable 5"
|
|
16
|
+
description: "Anthropic's most capable widely released model for long-horizon agentic work, complex reasoning, and ambitious coding tasks."
|
|
17
|
+
input_price: 10.0
|
|
18
|
+
output_price: 50.0
|
|
19
|
+
context_window: 1000000
|
|
20
|
+
capabilities: [vision, tools, reasoning]
|
|
21
|
+
notes: "Includes safety classifiers; blocked requests return stop_reason refusal. Configure Opus 4.8 fallback for production workloads."
|
|
22
|
+
|
|
13
23
|
- id: "anthropic/claude-opus-4-8"
|
|
14
24
|
provider: anthropic
|
|
15
25
|
display_name: "Claude Opus 4.8"
|
|
@@ -19,6 +29,16 @@ models:
|
|
|
19
29
|
context_window: 1000000
|
|
20
30
|
capabilities: [vision, tools, reasoning]
|
|
21
31
|
|
|
32
|
+
- id: "anthropic/claude-sonnet-5"
|
|
33
|
+
provider: anthropic
|
|
34
|
+
display_name: "Claude Sonnet 5"
|
|
35
|
+
description: "Best combination of speed and intelligence. Drop-in upgrade from Sonnet 4.6 for coding, agents, and professional work."
|
|
36
|
+
input_price: 3.0
|
|
37
|
+
output_price: 15.0
|
|
38
|
+
context_window: 1000000
|
|
39
|
+
capabilities: [vision, tools, reasoning]
|
|
40
|
+
notes: "Introductory API pricing ($2/$10 per 1M tokens) through August 31, 2026."
|
|
41
|
+
|
|
22
42
|
- id: "anthropic/claude-opus-4-7"
|
|
23
43
|
provider: anthropic
|
|
24
44
|
display_name: "Claude Opus 4.7"
|
|
@@ -5,7 +5,7 @@ import tempfile
|
|
|
5
5
|
from collections.abc import Callable, Iterator
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any
|
|
8
|
-
from urllib.parse import
|
|
8
|
+
from urllib.parse import unquote, urlparse
|
|
9
9
|
from urllib.request import urlopen
|
|
10
10
|
|
|
11
11
|
from pydantic import (
|
|
@@ -36,6 +36,13 @@ def _is_local_path(source: str) -> bool:
|
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
# Hosts serving platform-persisted content. URLs on these hosts are already
|
|
40
|
+
# durable — re-uploading them via POST /files is wasteful and (worse) renames
|
|
41
|
+
# the object using the encoded basename. `platform_config.cdn` is checked too,
|
|
42
|
+
# but its default ("content.timbal.ai") predates the timbalusercontent.com move.
|
|
43
|
+
_PLATFORM_CDN_HOSTS = ("timbalusercontent.com", "content.timbal.ai")
|
|
44
|
+
|
|
45
|
+
|
|
39
46
|
def _extract_filename(headers: dict, url: str) -> str:
|
|
40
47
|
"""Extract filename from Content-Disposition header, falling back to URL path."""
|
|
41
48
|
filename = None
|
|
@@ -46,7 +53,9 @@ def _extract_filename(headers: dict, url: str) -> str:
|
|
|
46
53
|
except (IndexError, AttributeError):
|
|
47
54
|
pass
|
|
48
55
|
if not filename:
|
|
49
|
-
|
|
56
|
+
# Decode the basename: URL paths are percent-encoded, but the filename is
|
|
57
|
+
# used as-is for re-uploads — keeping it encoded double-encodes downstream.
|
|
58
|
+
filename = unquote(urlparse(url).path.split("/")[-1])
|
|
50
59
|
return filename
|
|
51
60
|
|
|
52
61
|
|
|
@@ -386,7 +395,12 @@ class File(io.IOBase):
|
|
|
386
395
|
url = str(self)
|
|
387
396
|
if not run_context.platform_config:
|
|
388
397
|
return url
|
|
389
|
-
|
|
398
|
+
# .hostname (unlike .netloc) drops port/userinfo and lowercases,
|
|
399
|
+
# so e.g. "content.timbal.ai:443" still matches. The configured cdn
|
|
400
|
+
# may carry a port too — strip it the same way.
|
|
401
|
+
host = urlparse(url).hostname
|
|
402
|
+
cdn_host = urlparse(f"//{run_context.platform_config.cdn}").hostname
|
|
403
|
+
if host and (host == cdn_host or host in _PLATFORM_CDN_HOSTS):
|
|
390
404
|
object.__setattr__(self, "__persisted__", url)
|
|
391
405
|
return url
|
|
392
406
|
|
|
@@ -416,11 +430,12 @@ class File(io.IOBase):
|
|
|
416
430
|
from ..platform.utils import _request
|
|
417
431
|
res = await _request("POST", path, files=files)
|
|
418
432
|
upload_response = UploadFileResponse.model_validate(res.json())
|
|
419
|
-
#
|
|
420
|
-
#
|
|
421
|
-
#
|
|
422
|
-
|
|
423
|
-
|
|
433
|
+
# The platform returns a fully percent-encoded URL — use it verbatim.
|
|
434
|
+
# Reconstructing it from `name` (raw, unencoded) breaks whenever the name
|
|
435
|
+
# needs encoding: removesuffix() finds no match, so the encoded name got
|
|
436
|
+
# appended to the already-complete URL, yielding a duplicated, doubly
|
|
437
|
+
# encoded path that 403s on the CDN.
|
|
438
|
+
url = upload_response.url
|
|
424
439
|
object.__setattr__(self, "__persisted__", url)
|
|
425
440
|
return url
|
|
426
441
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|