timbal 2.2.3__tar.gz → 2.2.5__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.3 → timbal-2.2.5}/PKG-INFO +1 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/_version.py +2 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/flow.py +63 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/workflow.py +32 -8
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/__init__.py +7 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/elasticsearch.py +5 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/elevenlabs.py +3 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/fal.py +9 -6
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/gemini_images.py +3 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_analytics.py +8 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_docs.py +1 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_drive.py +2 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/higgsfield.py +5 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/jira.py +4 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/onedrive.py +2 -2
- timbal-2.2.5/python/timbal/tools/parallel.py +191 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/pinecone.py +4 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/quiver_ai.py +5 -3
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/replicate.py +5 -3
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/sharepoint.py +2 -2
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/stripe.py +4 -1
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/zendesk.py +8 -2
- {timbal-2.2.3 → timbal-2.2.5}/.gitignore +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/LICENSE +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/README.md +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/chat-completions.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/create-from-workforce.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/jobs/cancel.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/jobs/get.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/jobs/list.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/jobs/retry.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/link.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/list-context-vars.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/list-policies.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/messages.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/responses.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/docs/api-reference/ace/unlink.mdx +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/pyproject.toml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/pyrightconfig.json +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/__main__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/cli_utils.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/cst_utils.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/format.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/model_discovery.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/test.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/tool_discovery.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/add_edge.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/add_step.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/add_tool.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/remove_edge.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/remove_step.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/remove_tool.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/set_config.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/set_param.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/codegen/transformers/set_position.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/anthropic.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/default.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/message.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/openai.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/string.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/impl/timbal.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/collectors/registry.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/agent.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/fallback_model.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/llm_router.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/mcp.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/memory_compaction.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/models.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/runnable.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/skill.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/test_model.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/tool.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/core/tool_set.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/errors.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/cli.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/display.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/agent.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_examples.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_flow_validators.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_negations.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_parallel.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_subagent.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/eval_transforms.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/fixtures/test_invalid_validator.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/models.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/runner.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/utils.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/comparison_base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/contains.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/contains_all.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/contains_any.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/context.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/email.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/ends_with.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/eq.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/gt.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/gte.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/json.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/language.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/length.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/llm_base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/lt.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/lte.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/max_length.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/min_length.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/not_null.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/parallel.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/pattern.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/prompt.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/semantic.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/seq.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/starts_with.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/evals/validators/type.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/logs.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/models.yaml +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/integrations.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/knowledge_bases/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/knowledge_bases/query.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/tool_proxy.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/types.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/platform/utils.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/__main__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/http.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/jobs.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/voice.html +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/server/voice.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/config.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/config_loader.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/context.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/dependency_analyzer.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/exporters/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/exporters/otel.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/in_memory.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/jsonl.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/platform.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/providers/sqlite.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/span.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/state/tracing/trace.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/_creds.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/asana.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/bash.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/cala.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/cloudflare.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/dynamics_business_central.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/dynamics_sales.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/edit.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/excel.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/fathom.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/firecrawl.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/gmail.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_business.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_calendar.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_maps.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_merchant_center.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_search_console.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/google_sheets.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/happy_scribe.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/hubspot.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/interaction.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/klaviyo.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/knowledge_base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/krea.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/lancedb.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/linkedin.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/mongodb.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/netsuite.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/outlook.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/powerbi.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/read.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/resend.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/salesforce.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/scraperapi.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/shopify.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/slack.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/tavily.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/web_search.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/write.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/xai.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/tools/zoho_crm.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/approval.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/custom.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/file.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/text.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/thinking.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/tool_result.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/content/tool_use.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/approval.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/base.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/delta.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/interaction.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/output.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/events/start.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/file.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/message.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/types/run_status.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/import_spec.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/model.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/net.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/schema.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/utils/serialization.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/voice/__init__.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/python/timbal/voice/elevenlabs.py +0 -0
- {timbal-2.2.3 → timbal-2.2.5}/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.5'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 2, 5)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -203,6 +203,24 @@ def _build_node(runnable: Any, *, include_tools: bool = True) -> dict[str, Any]:
|
|
|
203
203
|
return node
|
|
204
204
|
|
|
205
205
|
|
|
206
|
+
def _edge_kind(kinds: set[str] | None) -> str:
|
|
207
|
+
"""Collapse a set of edge-origin kinds into a single label for JSON output.
|
|
208
|
+
|
|
209
|
+
A dependency can arise from several sources at once (e.g. an explicit
|
|
210
|
+
``depends_on`` that also reads the step's output via a param map). Precedence
|
|
211
|
+
is ``ordering > when > param`` so explicit sequencing is never masked by
|
|
212
|
+
param wiring. Unknown/missing (e.g. edges from a direct ``_link``) default to
|
|
213
|
+
``ordering`` — the safe choice, since ordering edges are never reduced away.
|
|
214
|
+
"""
|
|
215
|
+
if not kinds:
|
|
216
|
+
return "ordering"
|
|
217
|
+
if "ordering" in kinds:
|
|
218
|
+
return "ordering"
|
|
219
|
+
if "when" in kinds:
|
|
220
|
+
return "when"
|
|
221
|
+
return "param"
|
|
222
|
+
|
|
223
|
+
|
|
206
224
|
def get_flow(workspace_path: str | Path) -> dict[str, Any]:
|
|
207
225
|
"""Return a ReactFlow-compatible graph for the workspace entry point.
|
|
208
226
|
|
|
@@ -239,12 +257,14 @@ def get_flow(workspace_path: str | Path) -> dict[str, Any]:
|
|
|
239
257
|
|
|
240
258
|
for _step_name, step in runnable._steps.items():
|
|
241
259
|
when_source = _get_when_source(step) if step.when else None
|
|
260
|
+
kinds_map = getattr(step, "previous_steps_kinds", None) or {}
|
|
242
261
|
for prev_name in step.previous_steps:
|
|
243
262
|
prev_step = runnable._steps[prev_name]
|
|
244
263
|
edge: dict[str, Any] = {
|
|
245
264
|
"id": f"{prev_step._path}->{step._path}",
|
|
246
265
|
"source": prev_step._path,
|
|
247
266
|
"target": step._path,
|
|
267
|
+
"kind": _edge_kind(kinds_map.get(prev_name)),
|
|
248
268
|
}
|
|
249
269
|
if when_source is not None:
|
|
250
270
|
edge["when"] = when_source
|
|
@@ -390,6 +410,48 @@ def _fmt_node_lines(node: dict, indent: str) -> list[str]:
|
|
|
390
410
|
return lines
|
|
391
411
|
|
|
392
412
|
|
|
413
|
+
def _reduce_param_edges(edges: list[dict]) -> list[dict]:
|
|
414
|
+
"""Drop param-induced edges that are transitively implied by another path.
|
|
415
|
+
|
|
416
|
+
A param dependency ``A → C`` (the handler/agent on C reads A's output) is a
|
|
417
|
+
real await-gate at runtime, but for an execution-order view it is redundant
|
|
418
|
+
when A already reaches C through some other path (e.g. ``A → B → C``). Left
|
|
419
|
+
in, such edges turn a linear pipeline into a misleading fan-out from the
|
|
420
|
+
first step.
|
|
421
|
+
|
|
422
|
+
Only edges whose single ``kind`` is ``param`` are eligible for removal —
|
|
423
|
+
explicit ordering (``depends_on`` / hooks) and ``when`` edges are always
|
|
424
|
+
kept so user-added structure never silently disappears from the compact
|
|
425
|
+
view. The full edge set (including these) is retained in the JSON output.
|
|
426
|
+
"""
|
|
427
|
+
adj: dict[str, list[str]] = defaultdict(list)
|
|
428
|
+
for e in edges:
|
|
429
|
+
adj[e["source"]].append(e["target"])
|
|
430
|
+
|
|
431
|
+
def _reaches(start: str, goal: str, skip: tuple[str, str]) -> bool:
|
|
432
|
+
"""True if ``goal`` is reachable from ``start`` without using the direct ``skip`` edge."""
|
|
433
|
+
stack = [start]
|
|
434
|
+
seen = {start}
|
|
435
|
+
while stack:
|
|
436
|
+
node = stack.pop()
|
|
437
|
+
for nxt in adj.get(node, []):
|
|
438
|
+
if (node, nxt) == skip:
|
|
439
|
+
continue
|
|
440
|
+
if nxt == goal:
|
|
441
|
+
return True
|
|
442
|
+
if nxt not in seen:
|
|
443
|
+
seen.add(nxt)
|
|
444
|
+
stack.append(nxt)
|
|
445
|
+
return False
|
|
446
|
+
|
|
447
|
+
kept: list[dict] = []
|
|
448
|
+
for e in edges:
|
|
449
|
+
if e.get("kind") == "param" and _reaches(e["source"], e["target"], (e["source"], e["target"])):
|
|
450
|
+
continue
|
|
451
|
+
kept.append(e)
|
|
452
|
+
return kept
|
|
453
|
+
|
|
454
|
+
|
|
393
455
|
def _build_edge_lines(edges: list[dict]) -> list[str]:
|
|
394
456
|
"""Render edges grouped by source, one line per source node."""
|
|
395
457
|
targets_of: dict[str, list[tuple[str, str | None]]] = defaultdict(list)
|
|
@@ -472,6 +534,7 @@ def format_compact(flow: dict) -> str:
|
|
|
472
534
|
for line in _fmt_node_lines(node, indent=" "):
|
|
473
535
|
lines.append(line)
|
|
474
536
|
|
|
537
|
+
edges = _reduce_param_edges(edges)
|
|
475
538
|
if edges:
|
|
476
539
|
lines.append("")
|
|
477
540
|
lines.append("EDGES")
|
|
@@ -142,29 +142,53 @@ class Workflow(Runnable):
|
|
|
142
142
|
self._steps[runnable.name] = runnable
|
|
143
143
|
runnable.previous_steps = set()
|
|
144
144
|
runnable.next_steps = set()
|
|
145
|
+
# Per-source edge kinds: maps a previous step name -> set of kinds
|
|
146
|
+
# ("ordering" | "when" | "param"). Used by introspection (get_flow) to
|
|
147
|
+
# distinguish explicit sequencing from param/when-induced dependencies.
|
|
148
|
+
# Runtime sequencing only ever looks at ``previous_steps``.
|
|
149
|
+
runnable.previous_steps_kinds = {}
|
|
145
150
|
runnable.when = None
|
|
146
151
|
|
|
147
152
|
# Explicit dependencies
|
|
148
153
|
if depends_on and not isinstance(depends_on, list):
|
|
149
154
|
raise ValueError("depends_on must be a list of step names")
|
|
150
|
-
depends_on = set(depends_on or []) # Deduplicate here to avoid duplicate _is_dag calls
|
|
151
155
|
|
|
152
|
-
|
|
153
|
-
depends_on.
|
|
154
|
-
|
|
156
|
+
# Track dependency origins so introspection can tell explicit ordering
|
|
157
|
+
# (depends_on / hooks) apart from param- and when-induced wiring. These
|
|
158
|
+
# all merge into ``previous_steps`` for execution, but the distinction is
|
|
159
|
+
# lossy once merged (a step can be both an explicit dep and a param dep),
|
|
160
|
+
# so we record it here while the sources are still separate.
|
|
161
|
+
ordering_deps = set(depends_on or [])
|
|
162
|
+
# Hooks read sibling outputs via step_span(); treat as ordering so they
|
|
163
|
+
# are never silently collapsed in compact views.
|
|
164
|
+
ordering_deps.update(runnable._pre_hook_dependencies)
|
|
165
|
+
ordering_deps.update(runnable._post_hook_dependencies)
|
|
166
|
+
# Handler-body step_span() references are data wiring, not explicit ordering.
|
|
167
|
+
param_deps = set(runnable._dependencies)
|
|
168
|
+
when_deps: set[str] = set()
|
|
155
169
|
|
|
156
170
|
# Optional handler to determine whether to execute the step, and inspect it to automatically link steps
|
|
157
171
|
if when:
|
|
158
172
|
inspect_result = runnable._inspect_callable(when)
|
|
159
173
|
runnable.when = {"callable": when, **inspect_result}
|
|
160
|
-
|
|
174
|
+
when_deps.update(inspect_result["dependencies"])
|
|
161
175
|
|
|
162
176
|
# Use kwargs as default params for the runnable, and inspect callables to automatically link steps
|
|
163
177
|
runnable._prepare_default_params(kwargs)
|
|
164
178
|
for v in runnable._default_runtime_params.values():
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
param_deps.update(v["dependencies"])
|
|
180
|
+
|
|
181
|
+
edge_kinds: dict[str, set[str]] = {}
|
|
182
|
+
for dep in ordering_deps:
|
|
183
|
+
edge_kinds.setdefault(dep, set()).add("ordering")
|
|
184
|
+
for dep in when_deps:
|
|
185
|
+
edge_kinds.setdefault(dep, set()).add("when")
|
|
186
|
+
for dep in param_deps:
|
|
187
|
+
edge_kinds.setdefault(dep, set()).add("param")
|
|
188
|
+
runnable.previous_steps_kinds = edge_kinds
|
|
189
|
+
|
|
190
|
+
# Deduplicate (set union) to avoid duplicate _is_dag calls per shared dep.
|
|
191
|
+
for dep in edge_kinds:
|
|
168
192
|
logger.info("Linking steps", previous_step=dep, next_step=runnable.name)
|
|
169
193
|
self._link(dep, runnable.name)
|
|
170
194
|
|
|
@@ -493,6 +493,7 @@ if TYPE_CHECKING:
|
|
|
493
493
|
OutlookTrash,
|
|
494
494
|
OutlookUpdateEmail,
|
|
495
495
|
)
|
|
496
|
+
from .parallel import ParallelExtract, ParallelSearch, ParallelTaskRun
|
|
496
497
|
from .pinecone import (
|
|
497
498
|
PineconeCreateIndex,
|
|
498
499
|
PineconeDeleteVectors,
|
|
@@ -1330,6 +1331,9 @@ __all__ = [
|
|
|
1330
1331
|
"TavilyExtract",
|
|
1331
1332
|
"TavilyMap",
|
|
1332
1333
|
"TavilySearch",
|
|
1334
|
+
"ParallelSearch",
|
|
1335
|
+
"ParallelExtract",
|
|
1336
|
+
"ParallelTaskRun",
|
|
1333
1337
|
"WebSearch",
|
|
1334
1338
|
"Write",
|
|
1335
1339
|
"XSearch",
|
|
@@ -2400,6 +2404,9 @@ _LAZY_IMPORTS = {
|
|
|
2400
2404
|
"TavilyExtract": ".tavily",
|
|
2401
2405
|
"TavilyMap": ".tavily",
|
|
2402
2406
|
"TavilySearch": ".tavily",
|
|
2407
|
+
"ParallelSearch": ".parallel",
|
|
2408
|
+
"ParallelExtract": ".parallel",
|
|
2409
|
+
"ParallelTaskRun": ".parallel",
|
|
2403
2410
|
"WebSearch": ".web_search",
|
|
2404
2411
|
"Write": ".write",
|
|
2405
2412
|
"XSearch": ".xai",
|
|
@@ -33,8 +33,11 @@ async def _resolve_credentials(tool: Any) -> tuple[str, str | None]:
|
|
|
33
33
|
class ElasticsearchIngestAttachment(Tool):
|
|
34
34
|
name: str = "elasticsearch_ingest_attachment"
|
|
35
35
|
description: str | None = (
|
|
36
|
-
"Ingest a
|
|
37
|
-
"
|
|
36
|
+
"Ingest and parse a file attachment — PDF, Word DOCX, PowerPoint PPTX, "
|
|
37
|
+
"Excel, HTML, RTF, or plain text document — into searchable full text in "
|
|
38
|
+
"an Elasticsearch index using the ingest-attachment (Apache Tika) pipeline. "
|
|
39
|
+
"Extract text and metadata from a base64-encoded document or file for "
|
|
40
|
+
"full-text search."
|
|
38
41
|
)
|
|
39
42
|
integration: Annotated[str, Integration("elasticsearch")] | None = None
|
|
40
43
|
api_key: SecretStr | None = None
|
|
@@ -13,8 +13,9 @@ _ELEVENLABS_BASE = "https://api.elevenlabs.io/v1"
|
|
|
13
13
|
class ElevenLabsTextToSpeech(Tool):
|
|
14
14
|
name: str = "elevenlabs_text_to_speech"
|
|
15
15
|
description: str | None = (
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"Generate a voiceover or narration from text: text-to-speech (TTS) that "
|
|
17
|
+
"produces natural spoken audio in a chosen ElevenLabs voice. Returns the "
|
|
18
|
+
"audio as a base64 string."
|
|
18
19
|
)
|
|
19
20
|
integration: Annotated[str, Integration("elevenlabs")] | None = None
|
|
20
21
|
api_key: SecretStr | None = None
|
|
@@ -37,12 +37,15 @@ def _queue_model_path_from_submit_response(data: dict[str, Any]) -> str | None:
|
|
|
37
37
|
class FalQueueSubmit(Tool):
|
|
38
38
|
name: str = "fal_queue_submit"
|
|
39
39
|
description: str | None = (
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
40
|
+
"Run an AI model on fal (e.g. FLUX) to generate images, video, or audio — "
|
|
41
|
+
"submits an async inference/generation job to fal's queue. General-purpose "
|
|
42
|
+
"model runner. Returns request_id, status_url, response_url, cancel_url, and "
|
|
43
|
+
"queue_model_path (canonical path for follow-up calls). Important: fal may "
|
|
44
|
+
"rewrite the route—e.g. you submit fal-ai/flux/schnell but URLs use fal-ai/flux. "
|
|
45
|
+
"For fal_queue_status, fal_queue_result, and fal_queue_cancel always pass "
|
|
46
|
+
"model_id=queue_model_path from this response (or the path segment from "
|
|
47
|
+
"status_url before /requests/), not the original submit string, or status "
|
|
48
|
+
"polling can return HTTP 405."
|
|
46
49
|
)
|
|
47
50
|
integration: Annotated[str, Integration("fal")] | None = None
|
|
48
51
|
api_key: SecretStr | None = None
|
|
@@ -148,8 +148,9 @@ class GeminiImagesGenerateImage(Tool):
|
|
|
148
148
|
class GeminiImagesAnalyzeImage(Tool):
|
|
149
149
|
name: str = "gemini_analyze_image"
|
|
150
150
|
description: str | None = (
|
|
151
|
-
"Analyze
|
|
152
|
-
"
|
|
151
|
+
"Analyze an image with the Gemini vision model: describe a picture, photo, "
|
|
152
|
+
"or screenshot, answer questions about its contents, and OCR — read, "
|
|
153
|
+
"extract, and transcribe text from an image."
|
|
153
154
|
)
|
|
154
155
|
integration: Annotated[str, Integration("gemini")] | None = None
|
|
155
156
|
api_key: SecretStr | None = None
|
|
@@ -74,7 +74,10 @@ class GoogleAnalyticsListAccountSummaries(Tool):
|
|
|
74
74
|
|
|
75
75
|
class GoogleAnalyticsRunReport(Tool):
|
|
76
76
|
name: str = "google_analytics_run_report"
|
|
77
|
-
description: str | None =
|
|
77
|
+
description: str | None = (
|
|
78
|
+
"Run a standard GA4 analytics report — website traffic, visitors, sessions, "
|
|
79
|
+
"pageviews, and conversions — with dimensions, metrics, and date ranges."
|
|
80
|
+
)
|
|
78
81
|
integration: Annotated[str, Integration("google_analytics")] | None = None
|
|
79
82
|
token: SecretStr | None = None
|
|
80
83
|
default_property_id: str | None = None
|
|
@@ -131,7 +134,10 @@ class GoogleAnalyticsRunReport(Tool):
|
|
|
131
134
|
|
|
132
135
|
class GoogleAnalyticsRunRealtimeReport(Tool):
|
|
133
136
|
name: str = "google_analytics_run_realtime_report"
|
|
134
|
-
description: str | None =
|
|
137
|
+
description: str | None = (
|
|
138
|
+
"Run a GA4 realtime report: active users and visitors on your site right "
|
|
139
|
+
"now — live website traffic and events."
|
|
140
|
+
)
|
|
135
141
|
integration: Annotated[str, Integration("google_analytics")] | None = None
|
|
136
142
|
token: SecretStr | None = None
|
|
137
143
|
default_property_id: str | None = None
|
|
@@ -505,7 +505,7 @@ class GoogleDocsGetTabContent(Tool):
|
|
|
505
505
|
class GoogleDocsGetDocument(Tool):
|
|
506
506
|
name: str = "google_docs_get_document"
|
|
507
507
|
description: str | None = (
|
|
508
|
-
"
|
|
508
|
+
"Read and return the text contents of a Google Docs document. "
|
|
509
509
|
"Set include_tabs_content=true for multi-tab documents."
|
|
510
510
|
)
|
|
511
511
|
integration: Annotated[str, Integration("google_docs")] | None = None
|
|
@@ -143,7 +143,7 @@ class GoogleDriveGetDownloadLink(Tool):
|
|
|
143
143
|
|
|
144
144
|
class GoogleDriveGetFile(Tool):
|
|
145
145
|
name: str = "google_drive_get_file"
|
|
146
|
-
description: str | None = "Download and return content of a Google Drive file."
|
|
146
|
+
description: str | None = "Download and return the content of a Google Drive file or document (PDF, Word, etc.) by id."
|
|
147
147
|
integration: Annotated[str, Integration("google_drive")] | None = None
|
|
148
148
|
token: SecretStr | None = None
|
|
149
149
|
|
|
@@ -308,7 +308,7 @@ class GoogleDriveSearchFolders(Tool):
|
|
|
308
308
|
|
|
309
309
|
class GoogleDriveSearchFiles(Tool):
|
|
310
310
|
name: str = "google_drive_search_files"
|
|
311
|
-
description: str | None = "Search
|
|
311
|
+
description: str | None = "Search Google Drive to find a file, document, or folder by name or query. Locate documents in Drive. Supports pagination, filtering by folder, name, and trashed status."
|
|
312
312
|
integration: Annotated[str, Integration("google_drive")] | None = None
|
|
313
313
|
token: SecretStr | None = None
|
|
314
314
|
|
|
@@ -653,7 +653,11 @@ class HiggsfieldSoulTrain(_HiggsfieldTool):
|
|
|
653
653
|
|
|
654
654
|
class HiggsfieldSoulGenerate(_HiggsfieldTool):
|
|
655
655
|
name: str = "higgsfield_soul_generate"
|
|
656
|
-
description: str | None =
|
|
656
|
+
description: str | None = (
|
|
657
|
+
"Generate photorealistic images of a person or character with Higgsfield "
|
|
658
|
+
"Soul — UGC-style content, avatars, and character image generation from a "
|
|
659
|
+
"prompt, using a trained Soul character."
|
|
660
|
+
)
|
|
657
661
|
|
|
658
662
|
def __init__(self, **kwargs: Any) -> None:
|
|
659
663
|
async def _soul_generate(
|
|
@@ -495,7 +495,10 @@ class JiraGetIssueTypesForProject(Tool):
|
|
|
495
495
|
|
|
496
496
|
class JiraCreateIssue(Tool):
|
|
497
497
|
name: str = "jira_create_issue"
|
|
498
|
-
description: str | None =
|
|
498
|
+
description: str | None = (
|
|
499
|
+
"Create a Jira issue — a bug, task, story, or ticket — from a fields "
|
|
500
|
+
"payload (project, issuetype, summary, etc.)."
|
|
501
|
+
)
|
|
499
502
|
integration: Annotated[str, Integration("jira")] | None = None
|
|
500
503
|
token: SecretStr | None = None
|
|
501
504
|
|
|
@@ -127,7 +127,7 @@ class OneDriveListFiles(Tool):
|
|
|
127
127
|
|
|
128
128
|
class OneDriveGetFile(Tool):
|
|
129
129
|
name: str = "onedrive_get_file"
|
|
130
|
-
description: str | None = "Get
|
|
130
|
+
description: str | None = "Get the content and metadata of a OneDrive file or document by id."
|
|
131
131
|
integration: Annotated[str, Integration("onedrive")] | None = None
|
|
132
132
|
|
|
133
133
|
def get_config(self) -> dict[str, Any]:
|
|
@@ -210,7 +210,7 @@ class OneDriveFindFile(Tool):
|
|
|
210
210
|
|
|
211
211
|
class OneDriveDownloadFile(Tool):
|
|
212
212
|
name: str = "onedrive_download_file"
|
|
213
|
-
description: str | None = "Download a file
|
|
213
|
+
description: str | None = "Download a OneDrive file or document (Word, Excel, PDF, etc.) by id."
|
|
214
214
|
integration: Annotated[str, Integration("onedrive")] | None = None
|
|
215
215
|
|
|
216
216
|
def get_config(self) -> dict[str, Any]:
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, SecretStr
|
|
4
|
+
|
|
5
|
+
from ..core.tool import Tool
|
|
6
|
+
from ..platform.integrations import Integration
|
|
7
|
+
from ._creds import resolve_api_key
|
|
8
|
+
|
|
9
|
+
_BASE_URL = "https://api.parallel.ai"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ParallelSearch(Tool):
|
|
13
|
+
name: str = "parallel_search"
|
|
14
|
+
description: str | None = (
|
|
15
|
+
"Search the web with Parallel. Takes a natural-language objective and/or keyword "
|
|
16
|
+
"queries and returns ranked results with LLM-optimized excerpts, titles, and URLs."
|
|
17
|
+
)
|
|
18
|
+
integration: Annotated[str, Integration("parallel")] | None = None
|
|
19
|
+
api_key: SecretStr | None = None
|
|
20
|
+
|
|
21
|
+
def get_config(self) -> dict[str, Any]:
|
|
22
|
+
"""See base class."""
|
|
23
|
+
return {
|
|
24
|
+
**super().get_config(),
|
|
25
|
+
**self._annotate_config({"integration": self.integration, "api_key": self.api_key}),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
29
|
+
async def _parallel_search(
|
|
30
|
+
search_queries: list[str] = Field(..., description="Concise keyword search queries, 3-6 words each"),
|
|
31
|
+
objective: str | None = Field(None, description="Natural-language description of the underlying question or goal"),
|
|
32
|
+
mode: str = Field("advanced", description='Search mode: "turbo", "basic", or "advanced"'),
|
|
33
|
+
max_results: int = Field(10, description="Maximum number of results to return"),
|
|
34
|
+
max_chars_total: int | None = Field(None, description="Upper bound on total excerpt characters across results"),
|
|
35
|
+
include_domains: list[str] | None = Field(None, description="Only include results from these domains"),
|
|
36
|
+
exclude_domains: list[str] | None = Field(None, description="Exclude results from these domains"),
|
|
37
|
+
location: str | None = Field(None, description="ISO 3166-1 alpha-2 country code to bias results (e.g. 'US')"),
|
|
38
|
+
) -> dict:
|
|
39
|
+
api_key = await resolve_api_key(tool=self, provider_name="Parallel", env_var="PARALLEL_API_KEY")
|
|
40
|
+
import httpx
|
|
41
|
+
|
|
42
|
+
advanced_settings: dict[str, Any] = {"max_results": max_results}
|
|
43
|
+
if location:
|
|
44
|
+
advanced_settings["location"] = location
|
|
45
|
+
source_policy: dict[str, Any] = {}
|
|
46
|
+
if include_domains:
|
|
47
|
+
source_policy["include_domains"] = include_domains
|
|
48
|
+
if exclude_domains:
|
|
49
|
+
source_policy["exclude_domains"] = exclude_domains
|
|
50
|
+
if source_policy:
|
|
51
|
+
advanced_settings["source_policy"] = source_policy
|
|
52
|
+
|
|
53
|
+
payload: dict[str, Any] = {
|
|
54
|
+
"search_queries": search_queries,
|
|
55
|
+
"mode": mode,
|
|
56
|
+
"advanced_settings": advanced_settings,
|
|
57
|
+
}
|
|
58
|
+
if objective:
|
|
59
|
+
payload["objective"] = objective
|
|
60
|
+
if max_chars_total is not None:
|
|
61
|
+
payload["max_chars_total"] = max_chars_total
|
|
62
|
+
|
|
63
|
+
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client:
|
|
64
|
+
response = await client.post(
|
|
65
|
+
f"{_BASE_URL}/v1/search",
|
|
66
|
+
headers={"x-api-key": api_key, "Content-Type": "application/json"},
|
|
67
|
+
json=payload,
|
|
68
|
+
timeout=httpx.Timeout(60.0, read=None),
|
|
69
|
+
)
|
|
70
|
+
response.raise_for_status()
|
|
71
|
+
return response.json()
|
|
72
|
+
|
|
73
|
+
super().__init__(handler=_parallel_search, **kwargs)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ParallelExtract(Tool):
|
|
77
|
+
name: str = "parallel_extract"
|
|
78
|
+
description: str | None = (
|
|
79
|
+
"Extract content from specific web pages with Parallel. Provide up to 20 URLs and get back "
|
|
80
|
+
"LLM-optimized excerpts (and optionally full page content) for each, ranked against an "
|
|
81
|
+
"optional objective and queries."
|
|
82
|
+
)
|
|
83
|
+
integration: Annotated[str, Integration("parallel")] | None = None
|
|
84
|
+
api_key: SecretStr | None = None
|
|
85
|
+
|
|
86
|
+
def get_config(self) -> dict[str, Any]:
|
|
87
|
+
"""See base class."""
|
|
88
|
+
return {
|
|
89
|
+
**super().get_config(),
|
|
90
|
+
**self._annotate_config({"integration": self.integration, "api_key": self.api_key}),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
94
|
+
async def _parallel_extract(
|
|
95
|
+
urls: list[str] = Field(..., description="URLs to extract content from (up to 20)"),
|
|
96
|
+
objective: str | None = Field(None, description="Natural-language description of what to extract from the pages"),
|
|
97
|
+
search_queries: list[str] | None = Field(None, description="Optional keyword queries to rank excerpts against"),
|
|
98
|
+
max_chars_total: int | None = Field(None, description="Upper bound on total characters across all excerpts"),
|
|
99
|
+
max_chars_per_result: int | None = Field(None, description="Upper bound on excerpt characters per URL"),
|
|
100
|
+
full_content: bool = Field(False, description="Return the full cleaned page content in addition to excerpts"),
|
|
101
|
+
) -> dict:
|
|
102
|
+
api_key = await resolve_api_key(tool=self, provider_name="Parallel", env_var="PARALLEL_API_KEY")
|
|
103
|
+
import httpx
|
|
104
|
+
|
|
105
|
+
advanced_settings: dict[str, Any] = {}
|
|
106
|
+
if max_chars_per_result is not None:
|
|
107
|
+
advanced_settings["excerpt_settings"] = {"max_chars_per_result": max_chars_per_result}
|
|
108
|
+
if full_content:
|
|
109
|
+
advanced_settings["full_content"] = True
|
|
110
|
+
|
|
111
|
+
payload: dict[str, Any] = {"urls": urls}
|
|
112
|
+
if objective:
|
|
113
|
+
payload["objective"] = objective
|
|
114
|
+
if search_queries:
|
|
115
|
+
payload["search_queries"] = search_queries
|
|
116
|
+
if max_chars_total is not None:
|
|
117
|
+
payload["max_chars_total"] = max_chars_total
|
|
118
|
+
if advanced_settings:
|
|
119
|
+
payload["advanced_settings"] = advanced_settings
|
|
120
|
+
|
|
121
|
+
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client:
|
|
122
|
+
response = await client.post(
|
|
123
|
+
f"{_BASE_URL}/v1/extract",
|
|
124
|
+
headers={"x-api-key": api_key, "Content-Type": "application/json"},
|
|
125
|
+
json=payload,
|
|
126
|
+
timeout=httpx.Timeout(120.0, read=None),
|
|
127
|
+
)
|
|
128
|
+
response.raise_for_status()
|
|
129
|
+
return response.json()
|
|
130
|
+
|
|
131
|
+
super().__init__(handler=_parallel_extract, **kwargs)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ParallelTaskRun(Tool):
|
|
135
|
+
name: str = "parallel_task_run"
|
|
136
|
+
description: str | None = (
|
|
137
|
+
"Run a Parallel research task: give a plain-language objective and Parallel performs web "
|
|
138
|
+
"research and returns an answer with citations. Optionally pass a JSON schema to get "
|
|
139
|
+
"structured output. Blocks until the run completes."
|
|
140
|
+
)
|
|
141
|
+
integration: Annotated[str, Integration("parallel")] | None = None
|
|
142
|
+
api_key: SecretStr | None = None
|
|
143
|
+
|
|
144
|
+
def get_config(self) -> dict[str, Any]:
|
|
145
|
+
"""See base class."""
|
|
146
|
+
return {
|
|
147
|
+
**super().get_config(),
|
|
148
|
+
**self._annotate_config({"integration": self.integration, "api_key": self.api_key}),
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
152
|
+
async def _parallel_task_run(
|
|
153
|
+
input: str | dict = Field(..., description="The research objective as text, or a structured input object"),
|
|
154
|
+
processor: str = Field("base", description='Depth/latency tier: "lite", "base", "core", "pro", or "ultra" (append "-fast" for low-latency variants, e.g. "ultra-fast")'),
|
|
155
|
+
output_schema: dict | None = Field(None, description="Optional JSON schema for structured output. Omit to get a text answer."),
|
|
156
|
+
output_description: str | None = Field(None, description="Natural-language description of the desired output when not using a JSON schema"),
|
|
157
|
+
) -> dict:
|
|
158
|
+
api_key = await resolve_api_key(tool=self, provider_name="Parallel", env_var="PARALLEL_API_KEY")
|
|
159
|
+
import httpx
|
|
160
|
+
|
|
161
|
+
task_spec: dict[str, Any] = {}
|
|
162
|
+
if output_schema is not None:
|
|
163
|
+
task_spec["output_schema"] = {"type": "json", "json_schema": output_schema}
|
|
164
|
+
elif output_description is not None:
|
|
165
|
+
task_spec["output_schema"] = {"type": "text", "description": output_description}
|
|
166
|
+
|
|
167
|
+
payload: dict[str, Any] = {"input": input, "processor": processor}
|
|
168
|
+
if task_spec:
|
|
169
|
+
payload["task_spec"] = task_spec
|
|
170
|
+
|
|
171
|
+
headers = {"x-api-key": api_key, "Content-Type": "application/json"}
|
|
172
|
+
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client:
|
|
173
|
+
create = await client.post(
|
|
174
|
+
f"{_BASE_URL}/v1/tasks/runs",
|
|
175
|
+
headers=headers,
|
|
176
|
+
json=payload,
|
|
177
|
+
timeout=httpx.Timeout(60.0, read=None),
|
|
178
|
+
)
|
|
179
|
+
create.raise_for_status()
|
|
180
|
+
run_id = create.json()["run_id"]
|
|
181
|
+
|
|
182
|
+
# Blocks until the run is completed.
|
|
183
|
+
result = await client.get(
|
|
184
|
+
f"{_BASE_URL}/v1/tasks/runs/{run_id}/result",
|
|
185
|
+
headers=headers,
|
|
186
|
+
timeout=httpx.Timeout(600.0, read=None),
|
|
187
|
+
)
|
|
188
|
+
result.raise_for_status()
|
|
189
|
+
return result.json()
|
|
190
|
+
|
|
191
|
+
super().__init__(handler=_parallel_task_run, **kwargs)
|
|
@@ -160,7 +160,10 @@ class PineconeUpsertVectors(Tool):
|
|
|
160
160
|
|
|
161
161
|
class PineconeQuery(Tool):
|
|
162
162
|
name: str = "pinecone_query"
|
|
163
|
-
description: str | None =
|
|
163
|
+
description: str | None = (
|
|
164
|
+
"Query a Pinecone vector index for nearest neighbors — semantic similarity "
|
|
165
|
+
"search / vector search over stored embeddings."
|
|
166
|
+
)
|
|
164
167
|
integration: Annotated[str, Integration("pinecone")] | None = None
|
|
165
168
|
api_key: SecretStr | None = None
|
|
166
169
|
|
|
@@ -39,9 +39,11 @@ def _normalize_image(image: str | dict[str, str]) -> dict[str, str]:
|
|
|
39
39
|
class QuiverAIGenerateSVG(Tool):
|
|
40
40
|
name: str = "quiver_ai_generate_svg"
|
|
41
41
|
description: str | None = (
|
|
42
|
-
"Generate
|
|
43
|
-
"
|
|
44
|
-
"
|
|
42
|
+
"Generate SVG vector graphics — logos, icons, and illustrations — from a "
|
|
43
|
+
"text prompt with QuiverAI's Arrow models. Produces scalable vector (SVG) "
|
|
44
|
+
"output, not raster images. Supports optional reference images to guide "
|
|
45
|
+
"style/composition. Returns raw SVG markup along with request metadata and "
|
|
46
|
+
"credit usage."
|
|
45
47
|
)
|
|
46
48
|
integration: Annotated[str, Integration("quiver_ai")] | None = None
|
|
47
49
|
api_key: SecretStr | None = None
|
|
@@ -22,9 +22,11 @@ def _replicate_headers(api_token: str, extra: dict[str, str] | None = None) -> d
|
|
|
22
22
|
class ReplicateCreatePrediction(Tool):
|
|
23
23
|
name: str = "replicate_create_prediction"
|
|
24
24
|
description: str | None = (
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
25
|
+
"Run any AI model on Replicate (owner/name model refs) to generate images, "
|
|
26
|
+
"video, audio, or text from inputs. General-purpose model runner / inference "
|
|
27
|
+
"call for open-source and community models. Use official model refs like "
|
|
28
|
+
"owner/name or a full version id. Optionally wait up to N seconds for "
|
|
29
|
+
"completion via prefer_wait_seconds."
|
|
28
30
|
)
|
|
29
31
|
integration: Annotated[str, Integration("replicate")] | None = None
|
|
30
32
|
api_token: SecretStr | None = None
|
|
@@ -252,8 +252,8 @@ class SharePointGetFile(Tool):
|
|
|
252
252
|
class SharePointDownloadFile(Tool):
|
|
253
253
|
name: str = "sharepoint_download_file"
|
|
254
254
|
description: str | None = (
|
|
255
|
-
"Download a file
|
|
256
|
-
"(safe for Word, Excel, PDF and other binaries)."
|
|
255
|
+
"Download a SharePoint file or document (Word, Excel, PDF, etc.) by file id. "
|
|
256
|
+
"Returns base64-encoded content (safe for Word, Excel, PDF and other binaries)."
|
|
257
257
|
)
|
|
258
258
|
integration: Annotated[str, Integration("sharepoint")] | None = None
|
|
259
259
|
|
|
@@ -147,7 +147,10 @@ class SearchCustomer(Tool):
|
|
|
147
147
|
|
|
148
148
|
class CreatePayment(Tool):
|
|
149
149
|
name: str = "stripe_create_payment"
|
|
150
|
-
description: str | None =
|
|
150
|
+
description: str | None = (
|
|
151
|
+
"Charge a customer / collect a payment — create a Stripe PaymentIntent to "
|
|
152
|
+
"bill, take, or process a payment."
|
|
153
|
+
)
|
|
151
154
|
integration: Annotated[str, Integration("stripe")] | None = None
|
|
152
155
|
api_key: SecretStr | None = None
|
|
153
156
|
|