ai-parrot 0.17.2__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
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.
- agentui/.prettierrc +15 -0
- agentui/QUICKSTART.md +272 -0
- agentui/README.md +59 -0
- agentui/env.example +16 -0
- agentui/jsconfig.json +14 -0
- agentui/package-lock.json +4242 -0
- agentui/package.json +34 -0
- agentui/scripts/postinstall/apply-patches.mjs +260 -0
- agentui/src/app.css +61 -0
- agentui/src/app.d.ts +13 -0
- agentui/src/app.html +12 -0
- agentui/src/components/LoadingSpinner.svelte +64 -0
- agentui/src/components/ThemeSwitcher.svelte +159 -0
- agentui/src/components/index.js +4 -0
- agentui/src/lib/api/bots.ts +60 -0
- agentui/src/lib/api/chat.ts +22 -0
- agentui/src/lib/api/http.ts +25 -0
- agentui/src/lib/components/BotCard.svelte +33 -0
- agentui/src/lib/components/ChatBubble.svelte +63 -0
- agentui/src/lib/components/Toast.svelte +21 -0
- agentui/src/lib/config.ts +20 -0
- agentui/src/lib/stores/auth.svelte.ts +73 -0
- agentui/src/lib/stores/theme.svelte.js +64 -0
- agentui/src/lib/stores/toast.svelte.ts +31 -0
- agentui/src/lib/utils/conversation.ts +39 -0
- agentui/src/routes/+layout.svelte +20 -0
- agentui/src/routes/+page.svelte +232 -0
- agentui/src/routes/login/+page.svelte +200 -0
- agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
- agentui/src/routes/talk/[agentId]/+page.ts +7 -0
- agentui/static/README.md +1 -0
- agentui/svelte.config.js +11 -0
- agentui/tailwind.config.ts +53 -0
- agentui/tsconfig.json +3 -0
- agentui/vite.config.ts +10 -0
- ai_parrot-0.17.2.dist-info/METADATA +472 -0
- ai_parrot-0.17.2.dist-info/RECORD +535 -0
- ai_parrot-0.17.2.dist-info/WHEEL +6 -0
- ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
- ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
- ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
- crew-builder/.prettierrc +15 -0
- crew-builder/QUICKSTART.md +259 -0
- crew-builder/README.md +113 -0
- crew-builder/env.example +17 -0
- crew-builder/jsconfig.json +14 -0
- crew-builder/package-lock.json +4182 -0
- crew-builder/package.json +37 -0
- crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
- crew-builder/src/app.css +62 -0
- crew-builder/src/app.d.ts +13 -0
- crew-builder/src/app.html +12 -0
- crew-builder/src/components/LoadingSpinner.svelte +64 -0
- crew-builder/src/components/ThemeSwitcher.svelte +149 -0
- crew-builder/src/components/index.js +9 -0
- crew-builder/src/lib/api/bots.ts +60 -0
- crew-builder/src/lib/api/chat.ts +80 -0
- crew-builder/src/lib/api/client.ts +56 -0
- crew-builder/src/lib/api/crew/crew.ts +136 -0
- crew-builder/src/lib/api/index.ts +5 -0
- crew-builder/src/lib/api/o365/auth.ts +65 -0
- crew-builder/src/lib/auth/auth.ts +54 -0
- crew-builder/src/lib/components/AgentNode.svelte +43 -0
- crew-builder/src/lib/components/BotCard.svelte +33 -0
- crew-builder/src/lib/components/ChatBubble.svelte +67 -0
- crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
- crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
- crew-builder/src/lib/components/JsonViewer.svelte +24 -0
- crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
- crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
- crew-builder/src/lib/components/Toast.svelte +67 -0
- crew-builder/src/lib/components/Toolbar.svelte +157 -0
- crew-builder/src/lib/components/index.ts +10 -0
- crew-builder/src/lib/config.ts +8 -0
- crew-builder/src/lib/stores/auth.svelte.ts +228 -0
- crew-builder/src/lib/stores/crewStore.ts +369 -0
- crew-builder/src/lib/stores/theme.svelte.js +145 -0
- crew-builder/src/lib/stores/toast.svelte.ts +69 -0
- crew-builder/src/lib/utils/conversation.ts +39 -0
- crew-builder/src/lib/utils/markdown.ts +122 -0
- crew-builder/src/lib/utils/talkHistory.ts +47 -0
- crew-builder/src/routes/+layout.svelte +20 -0
- crew-builder/src/routes/+page.svelte +539 -0
- crew-builder/src/routes/agents/+page.svelte +247 -0
- crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
- crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
- crew-builder/src/routes/builder/+page.svelte +204 -0
- crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
- crew-builder/src/routes/crew/ask/+page.ts +1 -0
- crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
- crew-builder/src/routes/login/+page.svelte +197 -0
- crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
- crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
- crew-builder/static/README.md +1 -0
- crew-builder/svelte.config.js +11 -0
- crew-builder/tailwind.config.ts +53 -0
- crew-builder/tsconfig.json +3 -0
- crew-builder/vite.config.ts +10 -0
- mcp_servers/calculator_server.py +309 -0
- parrot/__init__.py +27 -0
- parrot/__pycache__/__init__.cpython-310.pyc +0 -0
- parrot/__pycache__/version.cpython-310.pyc +0 -0
- parrot/_version.py +34 -0
- parrot/a2a/__init__.py +48 -0
- parrot/a2a/client.py +658 -0
- parrot/a2a/discovery.py +89 -0
- parrot/a2a/mixin.py +257 -0
- parrot/a2a/models.py +376 -0
- parrot/a2a/server.py +770 -0
- parrot/agents/__init__.py +29 -0
- parrot/bots/__init__.py +12 -0
- parrot/bots/a2a_agent.py +19 -0
- parrot/bots/abstract.py +3139 -0
- parrot/bots/agent.py +1129 -0
- parrot/bots/basic.py +9 -0
- parrot/bots/chatbot.py +669 -0
- parrot/bots/data.py +1618 -0
- parrot/bots/database/__init__.py +5 -0
- parrot/bots/database/abstract.py +3071 -0
- parrot/bots/database/cache.py +286 -0
- parrot/bots/database/models.py +468 -0
- parrot/bots/database/prompts.py +154 -0
- parrot/bots/database/retries.py +98 -0
- parrot/bots/database/router.py +269 -0
- parrot/bots/database/sql.py +41 -0
- parrot/bots/db/__init__.py +6 -0
- parrot/bots/db/abstract.py +556 -0
- parrot/bots/db/bigquery.py +602 -0
- parrot/bots/db/cache.py +85 -0
- parrot/bots/db/documentdb.py +668 -0
- parrot/bots/db/elastic.py +1014 -0
- parrot/bots/db/influx.py +898 -0
- parrot/bots/db/mock.py +96 -0
- parrot/bots/db/multi.py +783 -0
- parrot/bots/db/prompts.py +185 -0
- parrot/bots/db/sql.py +1255 -0
- parrot/bots/db/tools.py +212 -0
- parrot/bots/document.py +680 -0
- parrot/bots/hrbot.py +15 -0
- parrot/bots/kb.py +170 -0
- parrot/bots/mcp.py +36 -0
- parrot/bots/orchestration/README.md +463 -0
- parrot/bots/orchestration/__init__.py +1 -0
- parrot/bots/orchestration/agent.py +155 -0
- parrot/bots/orchestration/crew.py +3330 -0
- parrot/bots/orchestration/fsm.py +1179 -0
- parrot/bots/orchestration/hr.py +434 -0
- parrot/bots/orchestration/storage/__init__.py +4 -0
- parrot/bots/orchestration/storage/memory.py +100 -0
- parrot/bots/orchestration/storage/mixin.py +119 -0
- parrot/bots/orchestration/verify.py +202 -0
- parrot/bots/product.py +204 -0
- parrot/bots/prompts/__init__.py +96 -0
- parrot/bots/prompts/agents.py +155 -0
- parrot/bots/prompts/data.py +216 -0
- parrot/bots/prompts/output_generation.py +8 -0
- parrot/bots/scraper/__init__.py +3 -0
- parrot/bots/scraper/models.py +122 -0
- parrot/bots/scraper/scraper.py +1173 -0
- parrot/bots/scraper/templates.py +115 -0
- parrot/bots/stores/__init__.py +5 -0
- parrot/bots/stores/local.py +172 -0
- parrot/bots/webdev.py +81 -0
- parrot/cli.py +17 -0
- parrot/clients/__init__.py +16 -0
- parrot/clients/base.py +1491 -0
- parrot/clients/claude.py +1191 -0
- parrot/clients/factory.py +129 -0
- parrot/clients/google.py +4567 -0
- parrot/clients/gpt.py +1975 -0
- parrot/clients/grok.py +432 -0
- parrot/clients/groq.py +986 -0
- parrot/clients/hf.py +582 -0
- parrot/clients/models.py +18 -0
- parrot/conf.py +395 -0
- parrot/embeddings/__init__.py +9 -0
- parrot/embeddings/base.py +157 -0
- parrot/embeddings/google.py +98 -0
- parrot/embeddings/huggingface.py +74 -0
- parrot/embeddings/openai.py +84 -0
- parrot/embeddings/processor.py +88 -0
- parrot/exceptions.c +13868 -0
- parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/exceptions.pxd +22 -0
- parrot/exceptions.pxi +15 -0
- parrot/exceptions.pyx +44 -0
- parrot/generators/__init__.py +29 -0
- parrot/generators/base.py +200 -0
- parrot/generators/html.py +293 -0
- parrot/generators/react.py +205 -0
- parrot/generators/streamlit.py +203 -0
- parrot/generators/template.py +105 -0
- parrot/handlers/__init__.py +4 -0
- parrot/handlers/agent.py +861 -0
- parrot/handlers/agents/__init__.py +1 -0
- parrot/handlers/agents/abstract.py +900 -0
- parrot/handlers/bots.py +338 -0
- parrot/handlers/chat.py +915 -0
- parrot/handlers/creation.sql +192 -0
- parrot/handlers/crew/ARCHITECTURE.md +362 -0
- parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
- parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
- parrot/handlers/crew/__init__.py +0 -0
- parrot/handlers/crew/handler.py +801 -0
- parrot/handlers/crew/models.py +229 -0
- parrot/handlers/crew/redis_persistence.py +523 -0
- parrot/handlers/jobs/__init__.py +10 -0
- parrot/handlers/jobs/job.py +384 -0
- parrot/handlers/jobs/mixin.py +627 -0
- parrot/handlers/jobs/models.py +115 -0
- parrot/handlers/jobs/worker.py +31 -0
- parrot/handlers/models.py +596 -0
- parrot/handlers/o365_auth.py +105 -0
- parrot/handlers/stream.py +337 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/aws.py +143 -0
- parrot/interfaces/credentials.py +113 -0
- parrot/interfaces/database.py +27 -0
- parrot/interfaces/google.py +1123 -0
- parrot/interfaces/hierarchy.py +1227 -0
- parrot/interfaces/http.py +651 -0
- parrot/interfaces/images/__init__.py +0 -0
- parrot/interfaces/images/plugins/__init__.py +24 -0
- parrot/interfaces/images/plugins/abstract.py +58 -0
- parrot/interfaces/images/plugins/analisys.py +148 -0
- parrot/interfaces/images/plugins/classify.py +150 -0
- parrot/interfaces/images/plugins/classifybase.py +182 -0
- parrot/interfaces/images/plugins/detect.py +150 -0
- parrot/interfaces/images/plugins/exif.py +1103 -0
- parrot/interfaces/images/plugins/hash.py +52 -0
- parrot/interfaces/images/plugins/vision.py +104 -0
- parrot/interfaces/images/plugins/yolo.py +66 -0
- parrot/interfaces/images/plugins/zerodetect.py +197 -0
- parrot/interfaces/o365.py +978 -0
- parrot/interfaces/onedrive.py +822 -0
- parrot/interfaces/sharepoint.py +1435 -0
- parrot/interfaces/soap.py +257 -0
- parrot/loaders/__init__.py +8 -0
- parrot/loaders/abstract.py +1131 -0
- parrot/loaders/audio.py +199 -0
- parrot/loaders/basepdf.py +53 -0
- parrot/loaders/basevideo.py +1568 -0
- parrot/loaders/csv.py +409 -0
- parrot/loaders/docx.py +116 -0
- parrot/loaders/epubloader.py +316 -0
- parrot/loaders/excel.py +199 -0
- parrot/loaders/factory.py +55 -0
- parrot/loaders/files/__init__.py +0 -0
- parrot/loaders/files/abstract.py +39 -0
- parrot/loaders/files/html.py +26 -0
- parrot/loaders/files/text.py +63 -0
- parrot/loaders/html.py +152 -0
- parrot/loaders/markdown.py +442 -0
- parrot/loaders/pdf.py +373 -0
- parrot/loaders/pdfmark.py +320 -0
- parrot/loaders/pdftables.py +506 -0
- parrot/loaders/ppt.py +476 -0
- parrot/loaders/qa.py +63 -0
- parrot/loaders/splitters/__init__.py +10 -0
- parrot/loaders/splitters/base.py +138 -0
- parrot/loaders/splitters/md.py +228 -0
- parrot/loaders/splitters/token.py +143 -0
- parrot/loaders/txt.py +26 -0
- parrot/loaders/video.py +89 -0
- parrot/loaders/videolocal.py +218 -0
- parrot/loaders/videounderstanding.py +377 -0
- parrot/loaders/vimeo.py +167 -0
- parrot/loaders/web.py +599 -0
- parrot/loaders/youtube.py +504 -0
- parrot/manager/__init__.py +5 -0
- parrot/manager/manager.py +1030 -0
- parrot/mcp/__init__.py +28 -0
- parrot/mcp/adapter.py +105 -0
- parrot/mcp/cli.py +174 -0
- parrot/mcp/client.py +119 -0
- parrot/mcp/config.py +75 -0
- parrot/mcp/integration.py +842 -0
- parrot/mcp/oauth.py +933 -0
- parrot/mcp/server.py +225 -0
- parrot/mcp/transports/__init__.py +3 -0
- parrot/mcp/transports/base.py +279 -0
- parrot/mcp/transports/grpc_session.py +163 -0
- parrot/mcp/transports/http.py +312 -0
- parrot/mcp/transports/mcp.proto +108 -0
- parrot/mcp/transports/quic.py +1082 -0
- parrot/mcp/transports/sse.py +330 -0
- parrot/mcp/transports/stdio.py +309 -0
- parrot/mcp/transports/unix.py +395 -0
- parrot/mcp/transports/websocket.py +547 -0
- parrot/memory/__init__.py +16 -0
- parrot/memory/abstract.py +209 -0
- parrot/memory/agent.py +32 -0
- parrot/memory/cache.py +175 -0
- parrot/memory/core.py +555 -0
- parrot/memory/file.py +153 -0
- parrot/memory/mem.py +131 -0
- parrot/memory/redis.py +613 -0
- parrot/models/__init__.py +46 -0
- parrot/models/basic.py +118 -0
- parrot/models/compliance.py +208 -0
- parrot/models/crew.py +395 -0
- parrot/models/detections.py +654 -0
- parrot/models/generation.py +85 -0
- parrot/models/google.py +223 -0
- parrot/models/groq.py +23 -0
- parrot/models/openai.py +30 -0
- parrot/models/outputs.py +285 -0
- parrot/models/responses.py +938 -0
- parrot/notifications/__init__.py +743 -0
- parrot/openapi/__init__.py +3 -0
- parrot/openapi/components.yaml +641 -0
- parrot/openapi/config.py +322 -0
- parrot/outputs/__init__.py +32 -0
- parrot/outputs/formats/__init__.py +108 -0
- parrot/outputs/formats/altair.py +359 -0
- parrot/outputs/formats/application.py +122 -0
- parrot/outputs/formats/base.py +351 -0
- parrot/outputs/formats/bokeh.py +356 -0
- parrot/outputs/formats/card.py +424 -0
- parrot/outputs/formats/chart.py +436 -0
- parrot/outputs/formats/d3.py +255 -0
- parrot/outputs/formats/echarts.py +310 -0
- parrot/outputs/formats/generators/__init__.py +0 -0
- parrot/outputs/formats/generators/abstract.py +61 -0
- parrot/outputs/formats/generators/panel.py +145 -0
- parrot/outputs/formats/generators/streamlit.py +86 -0
- parrot/outputs/formats/generators/terminal.py +63 -0
- parrot/outputs/formats/holoviews.py +310 -0
- parrot/outputs/formats/html.py +147 -0
- parrot/outputs/formats/jinja2.py +46 -0
- parrot/outputs/formats/json.py +87 -0
- parrot/outputs/formats/map.py +933 -0
- parrot/outputs/formats/markdown.py +172 -0
- parrot/outputs/formats/matplotlib.py +237 -0
- parrot/outputs/formats/mixins/__init__.py +0 -0
- parrot/outputs/formats/mixins/emaps.py +855 -0
- parrot/outputs/formats/plotly.py +341 -0
- parrot/outputs/formats/seaborn.py +310 -0
- parrot/outputs/formats/table.py +397 -0
- parrot/outputs/formats/template_report.py +138 -0
- parrot/outputs/formats/yaml.py +125 -0
- parrot/outputs/formatter.py +152 -0
- parrot/outputs/templates/__init__.py +95 -0
- parrot/pipelines/__init__.py +0 -0
- parrot/pipelines/abstract.py +210 -0
- parrot/pipelines/detector.py +124 -0
- parrot/pipelines/models.py +90 -0
- parrot/pipelines/planogram.py +3002 -0
- parrot/pipelines/table.sql +97 -0
- parrot/plugins/__init__.py +106 -0
- parrot/plugins/importer.py +80 -0
- parrot/py.typed +0 -0
- parrot/registry/__init__.py +18 -0
- parrot/registry/registry.py +594 -0
- parrot/scheduler/__init__.py +1189 -0
- parrot/scheduler/models.py +60 -0
- parrot/security/__init__.py +16 -0
- parrot/security/prompt_injection.py +268 -0
- parrot/security/security_events.sql +25 -0
- parrot/services/__init__.py +1 -0
- parrot/services/mcp/__init__.py +8 -0
- parrot/services/mcp/config.py +13 -0
- parrot/services/mcp/server.py +295 -0
- parrot/services/o365_remote_auth.py +235 -0
- parrot/stores/__init__.py +7 -0
- parrot/stores/abstract.py +352 -0
- parrot/stores/arango.py +1090 -0
- parrot/stores/bigquery.py +1377 -0
- parrot/stores/cache.py +106 -0
- parrot/stores/empty.py +10 -0
- parrot/stores/faiss_store.py +1157 -0
- parrot/stores/kb/__init__.py +9 -0
- parrot/stores/kb/abstract.py +68 -0
- parrot/stores/kb/cache.py +165 -0
- parrot/stores/kb/doc.py +325 -0
- parrot/stores/kb/hierarchy.py +346 -0
- parrot/stores/kb/local.py +457 -0
- parrot/stores/kb/prompt.py +28 -0
- parrot/stores/kb/redis.py +659 -0
- parrot/stores/kb/store.py +115 -0
- parrot/stores/kb/user.py +374 -0
- parrot/stores/models.py +59 -0
- parrot/stores/pgvector.py +3 -0
- parrot/stores/postgres.py +2853 -0
- parrot/stores/utils/__init__.py +0 -0
- parrot/stores/utils/chunking.py +197 -0
- parrot/telemetry/__init__.py +3 -0
- parrot/telemetry/mixin.py +111 -0
- parrot/template/__init__.py +3 -0
- parrot/template/engine.py +259 -0
- parrot/tools/__init__.py +23 -0
- parrot/tools/abstract.py +644 -0
- parrot/tools/agent.py +363 -0
- parrot/tools/arangodbsearch.py +537 -0
- parrot/tools/arxiv_tool.py +188 -0
- parrot/tools/calculator/__init__.py +3 -0
- parrot/tools/calculator/operations/__init__.py +38 -0
- parrot/tools/calculator/operations/calculus.py +80 -0
- parrot/tools/calculator/operations/statistics.py +76 -0
- parrot/tools/calculator/tool.py +150 -0
- parrot/tools/cloudwatch.py +988 -0
- parrot/tools/codeinterpreter/__init__.py +127 -0
- parrot/tools/codeinterpreter/executor.py +371 -0
- parrot/tools/codeinterpreter/internals.py +473 -0
- parrot/tools/codeinterpreter/models.py +643 -0
- parrot/tools/codeinterpreter/prompts.py +224 -0
- parrot/tools/codeinterpreter/tool.py +664 -0
- parrot/tools/company_info/__init__.py +6 -0
- parrot/tools/company_info/tool.py +1138 -0
- parrot/tools/correlationanalysis.py +437 -0
- parrot/tools/database/abstract.py +286 -0
- parrot/tools/database/bq.py +115 -0
- parrot/tools/database/cache.py +284 -0
- parrot/tools/database/models.py +95 -0
- parrot/tools/database/pg.py +343 -0
- parrot/tools/databasequery.py +1159 -0
- parrot/tools/db.py +1800 -0
- parrot/tools/ddgo.py +370 -0
- parrot/tools/decorators.py +271 -0
- parrot/tools/dftohtml.py +282 -0
- parrot/tools/document.py +549 -0
- parrot/tools/ecs.py +819 -0
- parrot/tools/edareport.py +368 -0
- parrot/tools/elasticsearch.py +1049 -0
- parrot/tools/employees.py +462 -0
- parrot/tools/epson/__init__.py +96 -0
- parrot/tools/excel.py +683 -0
- parrot/tools/file/__init__.py +13 -0
- parrot/tools/file/abstract.py +76 -0
- parrot/tools/file/gcs.py +378 -0
- parrot/tools/file/local.py +284 -0
- parrot/tools/file/s3.py +511 -0
- parrot/tools/file/tmp.py +309 -0
- parrot/tools/file/tool.py +501 -0
- parrot/tools/file_reader.py +129 -0
- parrot/tools/flowtask/__init__.py +19 -0
- parrot/tools/flowtask/tool.py +761 -0
- parrot/tools/gittoolkit.py +508 -0
- parrot/tools/google/__init__.py +18 -0
- parrot/tools/google/base.py +169 -0
- parrot/tools/google/tools.py +1251 -0
- parrot/tools/googlelocation.py +5 -0
- parrot/tools/googleroutes.py +5 -0
- parrot/tools/googlesearch.py +5 -0
- parrot/tools/googlesitesearch.py +5 -0
- parrot/tools/googlevoice.py +2 -0
- parrot/tools/gvoice.py +695 -0
- parrot/tools/ibisworld/README.md +225 -0
- parrot/tools/ibisworld/__init__.py +11 -0
- parrot/tools/ibisworld/tool.py +366 -0
- parrot/tools/jiratoolkit.py +1718 -0
- parrot/tools/manager.py +1098 -0
- parrot/tools/math.py +152 -0
- parrot/tools/metadata.py +476 -0
- parrot/tools/msteams.py +1621 -0
- parrot/tools/msword.py +635 -0
- parrot/tools/multidb.py +580 -0
- parrot/tools/multistoresearch.py +369 -0
- parrot/tools/networkninja.py +167 -0
- parrot/tools/nextstop/__init__.py +4 -0
- parrot/tools/nextstop/base.py +286 -0
- parrot/tools/nextstop/employee.py +733 -0
- parrot/tools/nextstop/store.py +462 -0
- parrot/tools/notification.py +435 -0
- parrot/tools/o365/__init__.py +42 -0
- parrot/tools/o365/base.py +295 -0
- parrot/tools/o365/bundle.py +522 -0
- parrot/tools/o365/events.py +554 -0
- parrot/tools/o365/mail.py +992 -0
- parrot/tools/o365/onedrive.py +497 -0
- parrot/tools/o365/sharepoint.py +641 -0
- parrot/tools/openapi_toolkit.py +904 -0
- parrot/tools/openweather.py +527 -0
- parrot/tools/pdfprint.py +1001 -0
- parrot/tools/powerbi.py +518 -0
- parrot/tools/powerpoint.py +1113 -0
- parrot/tools/pricestool.py +146 -0
- parrot/tools/products/__init__.py +246 -0
- parrot/tools/prophet_tool.py +171 -0
- parrot/tools/pythonpandas.py +630 -0
- parrot/tools/pythonrepl.py +910 -0
- parrot/tools/qsource.py +436 -0
- parrot/tools/querytoolkit.py +395 -0
- parrot/tools/quickeda.py +827 -0
- parrot/tools/resttool.py +553 -0
- parrot/tools/retail/__init__.py +0 -0
- parrot/tools/retail/bby.py +528 -0
- parrot/tools/sandboxtool.py +703 -0
- parrot/tools/sassie/__init__.py +352 -0
- parrot/tools/scraping/__init__.py +7 -0
- parrot/tools/scraping/docs/select.md +466 -0
- parrot/tools/scraping/documentation.md +1278 -0
- parrot/tools/scraping/driver.py +436 -0
- parrot/tools/scraping/models.py +576 -0
- parrot/tools/scraping/options.py +85 -0
- parrot/tools/scraping/orchestrator.py +517 -0
- parrot/tools/scraping/readme.md +740 -0
- parrot/tools/scraping/tool.py +3115 -0
- parrot/tools/seasonaldetection.py +642 -0
- parrot/tools/shell_tool/__init__.py +5 -0
- parrot/tools/shell_tool/actions.py +408 -0
- parrot/tools/shell_tool/engine.py +155 -0
- parrot/tools/shell_tool/models.py +322 -0
- parrot/tools/shell_tool/tool.py +442 -0
- parrot/tools/site_search.py +214 -0
- parrot/tools/textfile.py +418 -0
- parrot/tools/think.py +378 -0
- parrot/tools/toolkit.py +298 -0
- parrot/tools/webapp_tool.py +187 -0
- parrot/tools/whatif.py +1279 -0
- parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
- parrot/tools/workday/__init__.py +6 -0
- parrot/tools/workday/models.py +1389 -0
- parrot/tools/workday/tool.py +1293 -0
- parrot/tools/yfinance_tool.py +306 -0
- parrot/tools/zipcode.py +217 -0
- parrot/utils/__init__.py +2 -0
- parrot/utils/helpers.py +73 -0
- parrot/utils/parsers/__init__.py +5 -0
- parrot/utils/parsers/toml.c +12078 -0
- parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/parsers/toml.pyx +21 -0
- parrot/utils/toml.py +11 -0
- parrot/utils/types.cpp +20936 -0
- parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/types.pyx +213 -0
- parrot/utils/uv.py +11 -0
- parrot/version.py +10 -0
- parrot/yaml-rs/Cargo.lock +350 -0
- parrot/yaml-rs/Cargo.toml +19 -0
- parrot/yaml-rs/pyproject.toml +19 -0
- parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
- parrot/yaml-rs/src/lib.rs +222 -0
- requirements/docker-compose.yml +24 -0
- requirements/requirements-dev.txt +21 -0
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FlowtaskToolkit for AI-Parrot - Execute Flowtask components and tasks dynamically.
|
|
3
|
+
|
|
4
|
+
This toolkit provides tools for:
|
|
5
|
+
- Running individual Flowtask components with custom input data
|
|
6
|
+
- Executing local Flowtask tasks
|
|
7
|
+
- Calling remote Flowtask API endpoints
|
|
8
|
+
- Running tasks from JSON/YAML code definitions
|
|
9
|
+
"""
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
import io
|
|
13
|
+
import uuid
|
|
14
|
+
import json
|
|
15
|
+
import asyncio
|
|
16
|
+
import traceback
|
|
17
|
+
import importlib
|
|
18
|
+
from typing import Any, Dict, List, Optional, Union, Type
|
|
19
|
+
from enum import Enum
|
|
20
|
+
from contextlib import redirect_stdout
|
|
21
|
+
from pydantic import BaseModel, Field
|
|
22
|
+
import pandas as pd
|
|
23
|
+
from ..toolkit import AbstractToolkit
|
|
24
|
+
from ..decorators import tool_schema
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# -----------------------------
|
|
28
|
+
# Input models (schemas)
|
|
29
|
+
# -----------------------------
|
|
30
|
+
|
|
31
|
+
class FlowtaskComponentInput(BaseModel):
|
|
32
|
+
"""Input schema for component_call tool."""
|
|
33
|
+
|
|
34
|
+
component_name: str = Field(
|
|
35
|
+
description="Name of the Flowtask component to execute (e.g., 'GooglePlaces', 'GoogleGeoCoding')"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
attributes: Dict[str, Any] = Field(
|
|
39
|
+
default_factory=dict,
|
|
40
|
+
description="Dictionary of attributes to pass to the component (e.g., {'use_proxies': True, 'type': 'traffic'})"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
input_data: Union[Dict[str, Any], List[Dict[str, Any]], str] = Field(
|
|
44
|
+
description="Input data for the component - can be a dictionary, list of dictionaries, or JSON string"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
structured_output: Optional[Dict[str, Any]] = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description="Optional structured output schema to format the results"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return_as_dataframe: bool = Field(
|
|
53
|
+
default=False,
|
|
54
|
+
description="Whether to return the result as a pandas DataFrame (if possible)"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class FlowtaskTaskExecutionInput(BaseModel):
|
|
59
|
+
"""Input schema for task_execution tool."""
|
|
60
|
+
|
|
61
|
+
program: str = Field(
|
|
62
|
+
description="Program name/slug for the task (e.g., 'nextstop', 'test')"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
task_name: str = Field(
|
|
66
|
+
description="Name of the task to execute (e.g., 'employees_report')"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
debug: bool = Field(
|
|
70
|
+
default=True,
|
|
71
|
+
description="Whether to run in debug mode"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FlowtaskRemoteExecutionInput(BaseModel):
|
|
76
|
+
"""Input schema for remote_execution tool."""
|
|
77
|
+
|
|
78
|
+
program: str = Field(
|
|
79
|
+
description="Program name/slug for the task"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
task_name: str = Field(
|
|
83
|
+
description="Name of the task to execute"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
long_running: bool = Field(
|
|
87
|
+
default=False,
|
|
88
|
+
description="If True, task is enqueued and returns immediately with status. "
|
|
89
|
+
"If False, waits for task completion."
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
timeout: float = Field(
|
|
93
|
+
default=300.0,
|
|
94
|
+
description="Timeout in seconds for the API call (only applies when long_running=False)"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
max_retries: int = Field(
|
|
98
|
+
default=3,
|
|
99
|
+
description="Maximum number of retry attempts on failure"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
backoff_factor: float = Field(
|
|
103
|
+
default=1.0,
|
|
104
|
+
description="Backoff factor for exponential retry delay (delay = backoff_factor * 2^attempt)"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class TaskCodeFormat(str, Enum):
|
|
109
|
+
"""Format of the task code."""
|
|
110
|
+
JSON = "json"
|
|
111
|
+
YAML = "yaml"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class FlowtaskCodeExecutionInput(BaseModel):
|
|
115
|
+
"""Input schema for code_execution tool."""
|
|
116
|
+
|
|
117
|
+
task_code: str = Field(
|
|
118
|
+
description="The task definition as JSON or YAML string"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
format: TaskCodeFormat = Field(
|
|
122
|
+
default=TaskCodeFormat.YAML,
|
|
123
|
+
description="Format of the task code: 'json' or 'yaml'"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# -----------------------------
|
|
128
|
+
# Toolkit implementation
|
|
129
|
+
# -----------------------------
|
|
130
|
+
|
|
131
|
+
class FlowtaskToolkit(AbstractToolkit):
|
|
132
|
+
"""
|
|
133
|
+
Toolkit for executing Flowtask components and tasks dynamically.
|
|
134
|
+
|
|
135
|
+
This toolkit provides multiple tools for:
|
|
136
|
+
- Running individual Flowtask components with custom input data
|
|
137
|
+
- Executing local Flowtask tasks by program/task name
|
|
138
|
+
- Calling remote Flowtask API endpoints
|
|
139
|
+
- Running tasks from JSON/YAML code definitions
|
|
140
|
+
|
|
141
|
+
Example usage:
|
|
142
|
+
toolkit = FlowtaskToolkit()
|
|
143
|
+
tools = toolkit.get_tools()
|
|
144
|
+
|
|
145
|
+
# Execute a component
|
|
146
|
+
result = await toolkit.flowtask_component_call(
|
|
147
|
+
component_name="GooglePlaces",
|
|
148
|
+
input_data=[{"address": "123 Main St"}]
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Run a local task
|
|
152
|
+
result = await toolkit.flowtask_task_execution(
|
|
153
|
+
program="nextstop",
|
|
154
|
+
task_name="employees_report"
|
|
155
|
+
)
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(self, **kwargs):
|
|
159
|
+
"""Initialize the FlowtaskToolkit."""
|
|
160
|
+
super().__init__(**kwargs)
|
|
161
|
+
|
|
162
|
+
# Component cache to avoid repeated imports
|
|
163
|
+
self._component_cache: Dict[str, Type] = {}
|
|
164
|
+
|
|
165
|
+
# Known components (can be extended)
|
|
166
|
+
self.known_components = {
|
|
167
|
+
'GooglePlaces',
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# ANSI escape pattern for cleaning stdout
|
|
171
|
+
self._ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
|
172
|
+
|
|
173
|
+
# -----------------------------
|
|
174
|
+
# Helper methods
|
|
175
|
+
# -----------------------------
|
|
176
|
+
|
|
177
|
+
def _import_component(self, component_name: str) -> Type:
|
|
178
|
+
"""
|
|
179
|
+
Dynamically import a Flowtask component.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
component_name: Name of the component to import
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Component class
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
ImportError: If component cannot be imported
|
|
189
|
+
"""
|
|
190
|
+
# Check cache first
|
|
191
|
+
if component_name in self._component_cache:
|
|
192
|
+
return self._component_cache[component_name]
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
# Import from flowtask.components
|
|
196
|
+
module_path = f"flowtask.components.{component_name}"
|
|
197
|
+
module = importlib.import_module(module_path)
|
|
198
|
+
component_class = getattr(module, component_name)
|
|
199
|
+
|
|
200
|
+
# Cache the component
|
|
201
|
+
self._component_cache[component_name] = component_class
|
|
202
|
+
return component_class
|
|
203
|
+
|
|
204
|
+
except ImportError as e:
|
|
205
|
+
raise ImportError(
|
|
206
|
+
f"Could not import component '{component_name}': {str(e)}"
|
|
207
|
+
)
|
|
208
|
+
except AttributeError as e:
|
|
209
|
+
raise ImportError(
|
|
210
|
+
f"Component '{component_name}' not found in module: {str(e)}"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def _prepare_input_data(
|
|
214
|
+
self,
|
|
215
|
+
input_data: Union[Dict, List, str]
|
|
216
|
+
) -> Union[pd.DataFrame, Dict, List]:
|
|
217
|
+
"""
|
|
218
|
+
Prepare input data for the component.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
input_data: Raw input data
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Processed input data (DataFrame, dict, or list)
|
|
225
|
+
"""
|
|
226
|
+
try:
|
|
227
|
+
# Handle string input (assume JSON)
|
|
228
|
+
if isinstance(input_data, str):
|
|
229
|
+
input_data = json.loads(input_data)
|
|
230
|
+
|
|
231
|
+
# Convert list of dictionaries to DataFrame
|
|
232
|
+
if isinstance(input_data, list) and len(input_data) > 0:
|
|
233
|
+
if isinstance(input_data[0], dict):
|
|
234
|
+
return pd.DataFrame(input_data)
|
|
235
|
+
else:
|
|
236
|
+
return input_data
|
|
237
|
+
|
|
238
|
+
# Convert dictionary to DataFrame if it has list values
|
|
239
|
+
if isinstance(input_data, dict):
|
|
240
|
+
if all(isinstance(v, list) for v in input_data.values()):
|
|
241
|
+
try:
|
|
242
|
+
return pd.DataFrame(input_data)
|
|
243
|
+
except ValueError:
|
|
244
|
+
return input_data
|
|
245
|
+
else:
|
|
246
|
+
# Single row dictionary
|
|
247
|
+
return pd.DataFrame([input_data])
|
|
248
|
+
|
|
249
|
+
return input_data
|
|
250
|
+
|
|
251
|
+
except Exception:
|
|
252
|
+
return input_data
|
|
253
|
+
|
|
254
|
+
def _format_output(
|
|
255
|
+
self,
|
|
256
|
+
result: Any,
|
|
257
|
+
structured_output: Optional[Dict[str, Any]] = None,
|
|
258
|
+
return_as_dataframe: bool = False
|
|
259
|
+
) -> Any:
|
|
260
|
+
"""
|
|
261
|
+
Format the component output according to specifications.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
result: Raw component result
|
|
265
|
+
structured_output: Optional output structure
|
|
266
|
+
return_as_dataframe: Whether to return as DataFrame
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Formatted result
|
|
270
|
+
"""
|
|
271
|
+
try:
|
|
272
|
+
# If result is already a DataFrame
|
|
273
|
+
if isinstance(result, pd.DataFrame):
|
|
274
|
+
if return_as_dataframe:
|
|
275
|
+
return {
|
|
276
|
+
"data": result.to_dict(orient='records'),
|
|
277
|
+
"columns": list(result.columns),
|
|
278
|
+
"shape": result.shape,
|
|
279
|
+
"type": "dataframe"
|
|
280
|
+
}
|
|
281
|
+
else:
|
|
282
|
+
return result.to_dict(orient='records')
|
|
283
|
+
|
|
284
|
+
# If result is a list and we want DataFrame format
|
|
285
|
+
if isinstance(result, list) and return_as_dataframe:
|
|
286
|
+
if result and isinstance(result[0], dict):
|
|
287
|
+
df = pd.DataFrame(result)
|
|
288
|
+
return {
|
|
289
|
+
"data": result,
|
|
290
|
+
"columns": list(df.columns),
|
|
291
|
+
"shape": df.shape,
|
|
292
|
+
"type": "dataframe"
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# Apply structured output if specified
|
|
296
|
+
if structured_output:
|
|
297
|
+
return self._apply_structured_output(result, structured_output)
|
|
298
|
+
|
|
299
|
+
return result
|
|
300
|
+
|
|
301
|
+
except Exception:
|
|
302
|
+
return result
|
|
303
|
+
|
|
304
|
+
def _apply_structured_output(
|
|
305
|
+
self,
|
|
306
|
+
result: Any,
|
|
307
|
+
structure: Dict[str, Any]
|
|
308
|
+
) -> Dict[str, Any]:
|
|
309
|
+
"""
|
|
310
|
+
Apply structured output formatting to the result.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
result: Raw result data
|
|
314
|
+
structure: Desired output structure
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
Structured result
|
|
318
|
+
"""
|
|
319
|
+
try:
|
|
320
|
+
if isinstance(result, pd.DataFrame):
|
|
321
|
+
data = result.to_dict(orient='records')
|
|
322
|
+
elif isinstance(result, list):
|
|
323
|
+
data = result
|
|
324
|
+
else:
|
|
325
|
+
data = [result] if not isinstance(result, list) else result
|
|
326
|
+
|
|
327
|
+
structured_result = {}
|
|
328
|
+
for key, mapping in structure.items():
|
|
329
|
+
if isinstance(mapping, str):
|
|
330
|
+
if isinstance(data, list) and data:
|
|
331
|
+
structured_result[key] = [
|
|
332
|
+
item.get(mapping) for item in data if isinstance(item, dict)
|
|
333
|
+
]
|
|
334
|
+
else:
|
|
335
|
+
structured_result[key] = data.get(mapping) if isinstance(data, dict) else None
|
|
336
|
+
elif isinstance(mapping, dict):
|
|
337
|
+
structured_result[key] = self._apply_structured_output(data, mapping)
|
|
338
|
+
else:
|
|
339
|
+
structured_result[key] = mapping
|
|
340
|
+
|
|
341
|
+
return structured_result
|
|
342
|
+
|
|
343
|
+
except Exception:
|
|
344
|
+
return result
|
|
345
|
+
|
|
346
|
+
def _format_task_result(self, result: Any) -> Dict[str, Any]:
|
|
347
|
+
"""
|
|
348
|
+
Format task execution result for consistent output.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
result: Task execution result (typically DataFrame)
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Formatted result dictionary
|
|
355
|
+
"""
|
|
356
|
+
if isinstance(result, pd.DataFrame):
|
|
357
|
+
return {
|
|
358
|
+
"type": "dataframe",
|
|
359
|
+
"data": result.to_dict(orient='records'),
|
|
360
|
+
"columns": list(result.columns),
|
|
361
|
+
"shape": list(result.shape),
|
|
362
|
+
"row_count": len(result)
|
|
363
|
+
}
|
|
364
|
+
elif isinstance(result, dict):
|
|
365
|
+
return {"type": "dict", "data": result}
|
|
366
|
+
elif isinstance(result, list):
|
|
367
|
+
return {"type": "list", "data": result, "count": len(result)}
|
|
368
|
+
else:
|
|
369
|
+
return {"type": type(result).__name__, "data": str(result)}
|
|
370
|
+
|
|
371
|
+
# -----------------------------
|
|
372
|
+
# Tools (public async methods)
|
|
373
|
+
# -----------------------------
|
|
374
|
+
|
|
375
|
+
@tool_schema(FlowtaskComponentInput)
|
|
376
|
+
async def flowtask_component_call(
|
|
377
|
+
self,
|
|
378
|
+
component_name: str,
|
|
379
|
+
input_data: Union[Dict[str, Any], List[Dict[str, Any]], str],
|
|
380
|
+
attributes: Optional[Dict[str, Any]] = None,
|
|
381
|
+
structured_output: Optional[Dict[str, Any]] = None,
|
|
382
|
+
return_as_dataframe: bool = False
|
|
383
|
+
) -> Dict[str, Any]:
|
|
384
|
+
"""
|
|
385
|
+
Execute a single Flowtask component with custom input data and attributes.
|
|
386
|
+
|
|
387
|
+
This tool imports and runs any Flowtask component dynamically, allowing
|
|
388
|
+
flexible data processing with custom configurations.
|
|
389
|
+
|
|
390
|
+
Example:
|
|
391
|
+
result = await flowtask_component_call(
|
|
392
|
+
component_name="GooglePlaces",
|
|
393
|
+
input_data=[{"address": "123 Main St"}],
|
|
394
|
+
attributes={"use_proxies": True}
|
|
395
|
+
)
|
|
396
|
+
"""
|
|
397
|
+
attributes = attributes or {}
|
|
398
|
+
|
|
399
|
+
try:
|
|
400
|
+
# Import the component
|
|
401
|
+
component_cls = self._import_component(component_name)
|
|
402
|
+
|
|
403
|
+
# Prepare input data
|
|
404
|
+
processed_input = self._prepare_input_data(input_data)
|
|
405
|
+
|
|
406
|
+
# Create component instance with attributes
|
|
407
|
+
component_kwargs = attributes.copy()
|
|
408
|
+
component_kwargs['input'] = processed_input
|
|
409
|
+
|
|
410
|
+
try:
|
|
411
|
+
component = component_cls(**component_kwargs)
|
|
412
|
+
except TypeError as e:
|
|
413
|
+
return {
|
|
414
|
+
"status": "error",
|
|
415
|
+
"error": f"Failed to initialize component '{component_name}': {str(e)}",
|
|
416
|
+
"component_name": component_name
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# Execute the component using async context manager
|
|
420
|
+
async with component as comp:
|
|
421
|
+
result = await comp.run()
|
|
422
|
+
|
|
423
|
+
# Format the output
|
|
424
|
+
formatted_result = self._format_output(
|
|
425
|
+
result,
|
|
426
|
+
structured_output,
|
|
427
|
+
return_as_dataframe
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
"status": "success",
|
|
432
|
+
"result": formatted_result,
|
|
433
|
+
"metadata": {
|
|
434
|
+
"component_name": component_name,
|
|
435
|
+
"attributes": attributes,
|
|
436
|
+
"input_type": type(processed_input).__name__,
|
|
437
|
+
"output_type": type(result).__name__
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
except ImportError as e:
|
|
442
|
+
return {
|
|
443
|
+
"status": "error",
|
|
444
|
+
"error": str(e),
|
|
445
|
+
"component_name": component_name
|
|
446
|
+
}
|
|
447
|
+
except Exception as e:
|
|
448
|
+
return {
|
|
449
|
+
"status": "error",
|
|
450
|
+
"error": f"Failed to execute component '{component_name}': {str(e)}",
|
|
451
|
+
"error_type": type(e).__name__,
|
|
452
|
+
"component_name": component_name
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@tool_schema(FlowtaskTaskExecutionInput)
|
|
456
|
+
async def flowtask_task_execution(
|
|
457
|
+
self,
|
|
458
|
+
program: str,
|
|
459
|
+
task_name: str,
|
|
460
|
+
debug: bool = True
|
|
461
|
+
) -> Dict[str, Any]:
|
|
462
|
+
"""
|
|
463
|
+
Execute a Flowtask Task locally by program and task name.
|
|
464
|
+
|
|
465
|
+
This runs the task using the local Flowtask Task instance,
|
|
466
|
+
which processes the DAG-based workflow defined in the task configuration.
|
|
467
|
+
|
|
468
|
+
Example:
|
|
469
|
+
result = await flowtask_task_execution(
|
|
470
|
+
program="nextstop",
|
|
471
|
+
task_name="employees_report",
|
|
472
|
+
debug=True
|
|
473
|
+
)
|
|
474
|
+
"""
|
|
475
|
+
try:
|
|
476
|
+
from flowtask.tasks.task import Task
|
|
477
|
+
|
|
478
|
+
task = Task(program=program, task=task_name, debug=debug)
|
|
479
|
+
|
|
480
|
+
async with task as t:
|
|
481
|
+
result = await t.run()
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
"status": "success",
|
|
485
|
+
"program": program,
|
|
486
|
+
"task": task_name,
|
|
487
|
+
"result": self._format_task_result(result)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
except ImportError as e:
|
|
491
|
+
return {
|
|
492
|
+
"status": "error",
|
|
493
|
+
"error": f"Flowtask not installed or import error: {str(e)}",
|
|
494
|
+
"program": program,
|
|
495
|
+
"task": task_name
|
|
496
|
+
}
|
|
497
|
+
except Exception as e:
|
|
498
|
+
return {
|
|
499
|
+
"status": "error",
|
|
500
|
+
"error": str(e),
|
|
501
|
+
"error_type": type(e).__name__,
|
|
502
|
+
"program": program,
|
|
503
|
+
"task": task_name
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
@tool_schema(FlowtaskRemoteExecutionInput)
|
|
507
|
+
async def flowtask_remote_execution(
|
|
508
|
+
self,
|
|
509
|
+
program: str,
|
|
510
|
+
task_name: str,
|
|
511
|
+
long_running: bool = False,
|
|
512
|
+
timeout: float = 300.0,
|
|
513
|
+
max_retries: int = 3,
|
|
514
|
+
backoff_factor: float = 1.0
|
|
515
|
+
) -> Dict[str, Any]:
|
|
516
|
+
"""
|
|
517
|
+
Execute a Flowtask Task remotely via the Flowtask API.
|
|
518
|
+
|
|
519
|
+
Calls the Flowtask API endpoint to run a task. If long_running is True,
|
|
520
|
+
the task is enqueued and returns immediately with status. Otherwise,
|
|
521
|
+
waits for task completion.
|
|
522
|
+
|
|
523
|
+
Uses exponential backoff retry on transient failures.
|
|
524
|
+
|
|
525
|
+
Example:
|
|
526
|
+
result = await flowtask_remote_execution(
|
|
527
|
+
program="nextstop",
|
|
528
|
+
task_name="employees_report",
|
|
529
|
+
long_running=False,
|
|
530
|
+
timeout=600.0
|
|
531
|
+
)
|
|
532
|
+
"""
|
|
533
|
+
try:
|
|
534
|
+
import httpx
|
|
535
|
+
except ImportError:
|
|
536
|
+
return {
|
|
537
|
+
"status": "error",
|
|
538
|
+
"error": "httpx package not installed. Install with: pip install httpx"
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
# Get TASK_DOMAIN from environment - required
|
|
542
|
+
task_domain = os.getenv("TASK_DOMAIN")
|
|
543
|
+
if not task_domain:
|
|
544
|
+
return {
|
|
545
|
+
"status": "error",
|
|
546
|
+
"error": "TASK_DOMAIN environment variable is not set. "
|
|
547
|
+
"Please set it to the Flowtask API base URL."
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
url = f"{task_domain.rstrip('/')}/api/v2/task/{program}/{task_name}"
|
|
551
|
+
payload = {"long_running": long_running}
|
|
552
|
+
|
|
553
|
+
last_error = None
|
|
554
|
+
|
|
555
|
+
for attempt in range(max_retries):
|
|
556
|
+
try:
|
|
557
|
+
async with httpx.AsyncClient(timeout=timeout) as client:
|
|
558
|
+
response = await client.post(url, json=payload)
|
|
559
|
+
|
|
560
|
+
# Handle different response codes
|
|
561
|
+
if response.status_code == 200:
|
|
562
|
+
return {
|
|
563
|
+
"status": "success",
|
|
564
|
+
"program": program,
|
|
565
|
+
"task": task_name,
|
|
566
|
+
"response": response.json()
|
|
567
|
+
}
|
|
568
|
+
elif response.status_code == 202:
|
|
569
|
+
# Task queued (long_running=True)
|
|
570
|
+
return {
|
|
571
|
+
"status": "queued",
|
|
572
|
+
"program": program,
|
|
573
|
+
"task": task_name,
|
|
574
|
+
"response": response.json()
|
|
575
|
+
}
|
|
576
|
+
elif response.status_code == 400:
|
|
577
|
+
# Task execution error
|
|
578
|
+
return {
|
|
579
|
+
"status": "task_error",
|
|
580
|
+
"program": program,
|
|
581
|
+
"task": task_name,
|
|
582
|
+
"response": response.json()
|
|
583
|
+
}
|
|
584
|
+
elif response.status_code == 406:
|
|
585
|
+
# Result not acceptable (known Flowtask bug)
|
|
586
|
+
return {
|
|
587
|
+
"status": "result_error",
|
|
588
|
+
"program": program,
|
|
589
|
+
"task": task_name,
|
|
590
|
+
"response": response.json(),
|
|
591
|
+
"note": "406 error - result data format issue (known Flowtask behavior)"
|
|
592
|
+
}
|
|
593
|
+
else:
|
|
594
|
+
# Other errors - may be transient, retry
|
|
595
|
+
last_error = f"HTTP {response.status_code}: {response.text}"
|
|
596
|
+
if attempt < max_retries - 1:
|
|
597
|
+
delay = backoff_factor * (2 ** attempt)
|
|
598
|
+
await asyncio.sleep(delay)
|
|
599
|
+
continue
|
|
600
|
+
return {
|
|
601
|
+
"status": "error",
|
|
602
|
+
"error": last_error,
|
|
603
|
+
"program": program,
|
|
604
|
+
"task": task_name
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
except httpx.TimeoutException:
|
|
608
|
+
last_error = f"Request timed out after {timeout} seconds"
|
|
609
|
+
if attempt < max_retries - 1:
|
|
610
|
+
delay = backoff_factor * (2 ** attempt)
|
|
611
|
+
await asyncio.sleep(delay)
|
|
612
|
+
continue
|
|
613
|
+
|
|
614
|
+
except httpx.RequestError as e:
|
|
615
|
+
last_error = f"Request error: {str(e)}"
|
|
616
|
+
if attempt < max_retries - 1:
|
|
617
|
+
delay = backoff_factor * (2 ** attempt)
|
|
618
|
+
await asyncio.sleep(delay)
|
|
619
|
+
continue
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
"status": "error",
|
|
623
|
+
"error": last_error or "Max retries exceeded",
|
|
624
|
+
"program": program,
|
|
625
|
+
"task": task_name,
|
|
626
|
+
"retries": max_retries
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
@tool_schema(FlowtaskCodeExecutionInput)
|
|
630
|
+
async def flowtask_code_execution(
|
|
631
|
+
self,
|
|
632
|
+
task_code: str,
|
|
633
|
+
format: TaskCodeFormat = TaskCodeFormat.YAML
|
|
634
|
+
) -> Dict[str, Any]:
|
|
635
|
+
"""
|
|
636
|
+
Execute a Flowtask Task from a JSON or YAML code definition.
|
|
637
|
+
|
|
638
|
+
This allows running ad-hoc task definitions without requiring them to be
|
|
639
|
+
saved as files. The task code should follow the standard Flowtask task
|
|
640
|
+
definition format with name, description, and steps.
|
|
641
|
+
|
|
642
|
+
Example:
|
|
643
|
+
result = await flowtask_code_execution(
|
|
644
|
+
task_code='''
|
|
645
|
+
name: My Task
|
|
646
|
+
steps:
|
|
647
|
+
- GooglePlaces:
|
|
648
|
+
input: [{"address": "123 Main St"}]
|
|
649
|
+
''',
|
|
650
|
+
format="yaml"
|
|
651
|
+
)
|
|
652
|
+
"""
|
|
653
|
+
try:
|
|
654
|
+
from flowtask.storages import MemoryTaskStorage
|
|
655
|
+
from flowtask.tasks.task import Task
|
|
656
|
+
except ImportError as e:
|
|
657
|
+
return {
|
|
658
|
+
"status": "error",
|
|
659
|
+
"error": f"Flowtask not installed or import error: {str(e)}"
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
# Parse task code
|
|
663
|
+
try:
|
|
664
|
+
if format == TaskCodeFormat.YAML or format == "yaml":
|
|
665
|
+
import yaml
|
|
666
|
+
body_task = yaml.safe_load(task_code)
|
|
667
|
+
else:
|
|
668
|
+
body_task = json.loads(task_code)
|
|
669
|
+
except Exception as e:
|
|
670
|
+
return {
|
|
671
|
+
"status": "error",
|
|
672
|
+
"error": f"Failed to parse task code as {format}: {str(e)}"
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
task_id = str(uuid.uuid4())
|
|
676
|
+
error = None
|
|
677
|
+
stacktrace = None
|
|
678
|
+
captured_stdout = None
|
|
679
|
+
stats = None
|
|
680
|
+
result = None
|
|
681
|
+
|
|
682
|
+
try:
|
|
683
|
+
task = Task(task=task_id)
|
|
684
|
+
|
|
685
|
+
async with task as t:
|
|
686
|
+
t.taskstore = MemoryTaskStorage()
|
|
687
|
+
stdout = io.StringIO()
|
|
688
|
+
|
|
689
|
+
if await t.start(payload=body_task):
|
|
690
|
+
try:
|
|
691
|
+
with redirect_stdout(stdout):
|
|
692
|
+
result = await t.run()
|
|
693
|
+
except Exception as e:
|
|
694
|
+
result = None
|
|
695
|
+
stacktrace = traceback.format_exc()
|
|
696
|
+
error = str(e)
|
|
697
|
+
|
|
698
|
+
captured_stdout = stdout.getvalue()
|
|
699
|
+
stats = t.get_stats()
|
|
700
|
+
else:
|
|
701
|
+
error = "Failed to start task with provided payload"
|
|
702
|
+
|
|
703
|
+
except Exception as e:
|
|
704
|
+
error = str(e)
|
|
705
|
+
stacktrace = traceback.format_exc()
|
|
706
|
+
|
|
707
|
+
# Clean ANSI escape codes from stdout
|
|
708
|
+
clean_stdout = None
|
|
709
|
+
if captured_stdout:
|
|
710
|
+
clean_stdout = self._ansi_escape.sub('', captured_stdout)
|
|
711
|
+
|
|
712
|
+
return {
|
|
713
|
+
"status": "success" if error is None else "error",
|
|
714
|
+
"task_id": task_id,
|
|
715
|
+
"result": self._format_task_result(result) if result is not None else None,
|
|
716
|
+
"error": error,
|
|
717
|
+
"stacktrace": stacktrace,
|
|
718
|
+
"stdout": clean_stdout,
|
|
719
|
+
"stats": stats
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
# -----------------------------
|
|
723
|
+
# Utility methods
|
|
724
|
+
# -----------------------------
|
|
725
|
+
|
|
726
|
+
def list_known_components(self) -> List[str]:
|
|
727
|
+
"""
|
|
728
|
+
Get a list of known Flowtask components.
|
|
729
|
+
|
|
730
|
+
Returns:
|
|
731
|
+
List of component names
|
|
732
|
+
"""
|
|
733
|
+
return sorted(list(self.known_components))
|
|
734
|
+
|
|
735
|
+
def add_known_component(self, component_name: str) -> None:
|
|
736
|
+
"""
|
|
737
|
+
Add a component to the known components list.
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
component_name: Name of the component to add
|
|
741
|
+
"""
|
|
742
|
+
self.known_components.add(component_name)
|
|
743
|
+
|
|
744
|
+
def clear_component_cache(self) -> None:
|
|
745
|
+
"""Clear the component import cache."""
|
|
746
|
+
self._component_cache.clear()
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
# Backward compatibility alias
|
|
750
|
+
FlowtaskTool = FlowtaskToolkit
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
__all__ = [
|
|
754
|
+
"FlowtaskToolkit",
|
|
755
|
+
"FlowtaskTool", # Backward compatibility
|
|
756
|
+
"FlowtaskComponentInput",
|
|
757
|
+
"FlowtaskTaskExecutionInput",
|
|
758
|
+
"FlowtaskRemoteExecutionInput",
|
|
759
|
+
"FlowtaskCodeExecutionInput",
|
|
760
|
+
"TaskCodeFormat",
|
|
761
|
+
]
|