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,501 @@
|
|
|
1
|
+
from typing import Literal, Optional, Dict, Any, List, Union
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from io import BytesIO, StringIO
|
|
4
|
+
import logging
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
from ..abstract import AbstractTool, AbstractToolArgsSchema, ToolResult
|
|
7
|
+
from .abstract import FileManagerInterface
|
|
8
|
+
from .local import LocalFileManager
|
|
9
|
+
from .tmp import TempFileManager
|
|
10
|
+
from .s3 import S3FileManager
|
|
11
|
+
from .gcs import GCSFileManager
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FileManagerFactory:
|
|
15
|
+
"""Factory for creating file managers"""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def create(
|
|
19
|
+
manager_type: Literal["fs", "temp", "s3", "gcs"],
|
|
20
|
+
**kwargs
|
|
21
|
+
) -> FileManagerInterface:
|
|
22
|
+
"""Create a file manager instance"""
|
|
23
|
+
managers = {
|
|
24
|
+
"fs": LocalFileManager,
|
|
25
|
+
"temp": TempFileManager,
|
|
26
|
+
"s3": S3FileManager,
|
|
27
|
+
"gcs": GCSFileManager,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if manager_type not in managers:
|
|
31
|
+
raise ValueError(
|
|
32
|
+
f"Unknown manager type: {manager_type}. "
|
|
33
|
+
f"Available: {list(managers.keys())}"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return managers[manager_type](**kwargs)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FileManagerToolArgs(AbstractToolArgsSchema):
|
|
40
|
+
"""
|
|
41
|
+
Arguments schema for FileManagerTool.
|
|
42
|
+
|
|
43
|
+
The operation field determines which file operation to perform.
|
|
44
|
+
Each operation requires different additional fields.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
operation: Literal[
|
|
48
|
+
"list", "upload", "download", "copy", "delete",
|
|
49
|
+
"exists", "get_url", "get_metadata", "create"
|
|
50
|
+
] = Field(
|
|
51
|
+
...,
|
|
52
|
+
description=(
|
|
53
|
+
"The file operation to perform. Options:\n"
|
|
54
|
+
"- 'list': List files in a directory\n"
|
|
55
|
+
"- 'upload': Upload a file to storage\n"
|
|
56
|
+
"- 'download': Download a file from storage\n"
|
|
57
|
+
"- 'copy': Copy a file within storage\n"
|
|
58
|
+
"- 'delete': Delete a file from storage\n"
|
|
59
|
+
"- 'exists': Check if a file exists\n"
|
|
60
|
+
"- 'get_url': Get a URL to access a file\n"
|
|
61
|
+
"- 'get_metadata': Get detailed file metadata\n"
|
|
62
|
+
"- 'create': Create a new file with content"
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Common fields
|
|
67
|
+
path: Optional[Union[str, Path]] = Field(
|
|
68
|
+
None,
|
|
69
|
+
description="File or directory path. Used by most operations."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# List operation
|
|
73
|
+
pattern: Optional[str] = Field(
|
|
74
|
+
"*",
|
|
75
|
+
description="Filename pattern for list operation (e.g., '*.txt', '*.pdf')"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Upload operation
|
|
79
|
+
source_path: Optional[str] = Field(
|
|
80
|
+
None,
|
|
81
|
+
description="Source file path for upload operation"
|
|
82
|
+
)
|
|
83
|
+
destination: Optional[str] = Field(
|
|
84
|
+
None,
|
|
85
|
+
description="Destination path or directory"
|
|
86
|
+
)
|
|
87
|
+
destination_name: Optional[str] = Field(
|
|
88
|
+
None,
|
|
89
|
+
description="Custom name for uploaded file (uses source name if not provided)"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Copy operation
|
|
93
|
+
source: Optional[str] = Field(
|
|
94
|
+
None,
|
|
95
|
+
description="Source file path for copy operation"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Create operation
|
|
99
|
+
content: Optional[str] = Field(
|
|
100
|
+
None,
|
|
101
|
+
description="Text content for create operation"
|
|
102
|
+
)
|
|
103
|
+
encoding: Optional[str] = Field(
|
|
104
|
+
"utf-8",
|
|
105
|
+
description="Text encoding for create operation"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# URL operation
|
|
109
|
+
expiry_seconds: Optional[int] = Field(
|
|
110
|
+
3600,
|
|
111
|
+
description="URL expiry time in seconds (default: 3600 = 1 hour)"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class FileManagerTool(AbstractTool):
|
|
116
|
+
"""
|
|
117
|
+
Tool for AI agents to interact with file systems.
|
|
118
|
+
|
|
119
|
+
Provides secure file operations across different storage backends:
|
|
120
|
+
- 'fs': Local filesystem
|
|
121
|
+
- 'temp': Temporary storage (auto-cleanup)
|
|
122
|
+
- 's3': AWS S3 buckets
|
|
123
|
+
- 'gcs': Google Cloud Storage
|
|
124
|
+
|
|
125
|
+
Usage Pattern:
|
|
126
|
+
The LLM must specify an 'operation' field to route to the correct action.
|
|
127
|
+
Each operation has specific required and optional fields.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
List files: {"operation": "list", "path": "documents", "pattern": "*.pdf"}
|
|
131
|
+
Upload: {"operation": "upload", "source_path": "/tmp/file.txt", "destination": "uploads"}
|
|
132
|
+
Download: {"operation": "download", "path": "reports/summary.pdf", "destination": "/tmp/summary.pdf"}
|
|
133
|
+
Get URL: {"operation": "get_url", "path": "shared/file.zip", "expiry_seconds": 7200}
|
|
134
|
+
Create: {"operation": "create", "path": "output.txt", "content": "Hello, World!"}
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
name: str = "file_manager"
|
|
138
|
+
description: str = "Manage files across different storage backends (local, S3, GCS, temp)"
|
|
139
|
+
args_schema: type[AbstractToolArgsSchema] = FileManagerToolArgs
|
|
140
|
+
|
|
141
|
+
def __init__(
|
|
142
|
+
self,
|
|
143
|
+
manager_type: Literal["fs", "temp", "s3", "gcs"] = "fs",
|
|
144
|
+
default_output_dir: str = "./outputs",
|
|
145
|
+
allowed_operations: Optional[set] = None,
|
|
146
|
+
max_file_size: int = 100 * 1024 * 1024, # 100MB
|
|
147
|
+
auto_create_dirs: bool = True,
|
|
148
|
+
**manager_kwargs
|
|
149
|
+
):
|
|
150
|
+
"""
|
|
151
|
+
Initialize file manager tool.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
manager_type: Type of file manager ("fs", "temp", "s3", "gcs")
|
|
155
|
+
default_output_dir: Default directory for file operations
|
|
156
|
+
allowed_operations: Set of allowed operations (None = all allowed)
|
|
157
|
+
max_file_size: Maximum file size in bytes
|
|
158
|
+
auto_create_dirs: Automatically create directories
|
|
159
|
+
**manager_kwargs: Additional arguments for the specific manager
|
|
160
|
+
"""
|
|
161
|
+
super().__init__()
|
|
162
|
+
|
|
163
|
+
self.manager_type = manager_type
|
|
164
|
+
self.default_output_dir = default_output_dir
|
|
165
|
+
self.max_file_size = max_file_size
|
|
166
|
+
self.auto_create_dirs = auto_create_dirs
|
|
167
|
+
self.logger = logging.getLogger('ai_parrot.tools.FileManager')
|
|
168
|
+
|
|
169
|
+
# Default to all operations if not specified
|
|
170
|
+
self.allowed_operations = allowed_operations or {
|
|
171
|
+
"list", "upload", "download", "copy", "delete",
|
|
172
|
+
"exists", "get_url", "get_metadata", "create"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# Create the appropriate file manager
|
|
176
|
+
self.manager = self._create_manager(manager_type, **manager_kwargs)
|
|
177
|
+
|
|
178
|
+
# Update description with specific manager type
|
|
179
|
+
self.description = (
|
|
180
|
+
f"Manage files in {manager_type} storage. "
|
|
181
|
+
f"Default output directory: {default_output_dir}. "
|
|
182
|
+
f"Allowed operations: {', '.join(sorted(self.allowed_operations))}. "
|
|
183
|
+
f"Max file size: {max_file_size / (1024*1024):.1f}MB"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
self.logger.info(
|
|
187
|
+
f"FileManagerTool initialized with {manager_type} manager, "
|
|
188
|
+
f"output dir: {default_output_dir}"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def _create_manager(
|
|
192
|
+
self,
|
|
193
|
+
manager_type: str,
|
|
194
|
+
**kwargs
|
|
195
|
+
) -> FileManagerInterface:
|
|
196
|
+
"""Create file manager with type-specific defaults"""
|
|
197
|
+
if manager_type == "fs":
|
|
198
|
+
return FileManagerFactory.create(
|
|
199
|
+
manager_type,
|
|
200
|
+
base_path=kwargs.get('base_path', Path.cwd()),
|
|
201
|
+
sandboxed=kwargs.get('sandboxed', True),
|
|
202
|
+
**{k: v for k, v in kwargs.items() if k not in ['base_path', 'sandboxed']}
|
|
203
|
+
)
|
|
204
|
+
elif manager_type == "temp":
|
|
205
|
+
return FileManagerFactory.create(
|
|
206
|
+
manager_type,
|
|
207
|
+
cleanup_on_exit=kwargs.get('cleanup_on_exit', True),
|
|
208
|
+
**{k: v for k, v in kwargs.items() if k != 'cleanup_on_exit'}
|
|
209
|
+
)
|
|
210
|
+
else: # s3 or gcs
|
|
211
|
+
return FileManagerFactory.create(manager_type, **kwargs)
|
|
212
|
+
|
|
213
|
+
def _check_operation(self, operation: str):
|
|
214
|
+
"""Check if operation is allowed"""
|
|
215
|
+
if operation not in self.allowed_operations:
|
|
216
|
+
raise PermissionError(
|
|
217
|
+
f"Operation '{operation}' not allowed. "
|
|
218
|
+
f"Allowed: {self.allowed_operations}"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
def _check_file_size(self, size: int):
|
|
222
|
+
"""Check if file size is within limits"""
|
|
223
|
+
if size > self.max_file_size:
|
|
224
|
+
raise ValueError(
|
|
225
|
+
f"File size ({size} bytes) exceeds maximum "
|
|
226
|
+
f"allowed size ({self.max_file_size} bytes)"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def _resolve_output_path(self, path: Optional[str] = None) -> str:
|
|
230
|
+
"""Resolve path relative to default output directory"""
|
|
231
|
+
if path is None:
|
|
232
|
+
return self.default_output_dir
|
|
233
|
+
|
|
234
|
+
if Path(path).is_absolute() or path.startswith(self.default_output_dir):
|
|
235
|
+
return path
|
|
236
|
+
|
|
237
|
+
return str(Path(self.default_output_dir) / path)
|
|
238
|
+
|
|
239
|
+
async def _execute(self, **kwargs) -> ToolResult:
|
|
240
|
+
"""
|
|
241
|
+
Execute file operation based on the operation field.
|
|
242
|
+
|
|
243
|
+
This is the main router method that dispatches to specific operations.
|
|
244
|
+
The LLM must provide an 'operation' field to determine which action to perform.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
**kwargs: Arguments matching FileManagerToolArgs schema
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
ToolResult with operation results
|
|
251
|
+
"""
|
|
252
|
+
# Validate and extract operation
|
|
253
|
+
args = FileManagerToolArgs(**kwargs)
|
|
254
|
+
operation = args.operation
|
|
255
|
+
|
|
256
|
+
self.logger.info(f"Executing operation: {operation}")
|
|
257
|
+
|
|
258
|
+
# Check if operation is allowed
|
|
259
|
+
self._check_operation(operation)
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
# Route to appropriate operation
|
|
263
|
+
if operation == "list":
|
|
264
|
+
result = await self._list_files(args)
|
|
265
|
+
elif operation == "upload":
|
|
266
|
+
result = await self._upload_file(args)
|
|
267
|
+
elif operation == "download":
|
|
268
|
+
result = await self._download_file(args)
|
|
269
|
+
elif operation == "copy":
|
|
270
|
+
result = await self._copy_file(args)
|
|
271
|
+
elif operation == "delete":
|
|
272
|
+
result = await self._delete_file(args)
|
|
273
|
+
elif operation == "exists":
|
|
274
|
+
result = await self._exists(args)
|
|
275
|
+
elif operation == "get_url":
|
|
276
|
+
result = await self._get_file_url(args)
|
|
277
|
+
elif operation == "get_metadata":
|
|
278
|
+
result = await self._get_file_metadata(args)
|
|
279
|
+
elif operation == "create":
|
|
280
|
+
result = await self._create_file(args)
|
|
281
|
+
else:
|
|
282
|
+
return ToolResult(
|
|
283
|
+
success=False,
|
|
284
|
+
result=None,
|
|
285
|
+
error=f"Unknown operation: {operation}"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return ToolResult(
|
|
289
|
+
success=True,
|
|
290
|
+
result=result,
|
|
291
|
+
metadata={
|
|
292
|
+
"operation": operation,
|
|
293
|
+
"manager_type": self.manager_type
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
except Exception as e:
|
|
298
|
+
self.logger.error(f"Operation {operation} failed: {str(e)}", exc_info=True)
|
|
299
|
+
return ToolResult(
|
|
300
|
+
success=False,
|
|
301
|
+
error=str(e),
|
|
302
|
+
metadata={
|
|
303
|
+
"operation": operation,
|
|
304
|
+
"manager_type": self.manager_type
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
async def _list_files(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
309
|
+
"""List files in a directory"""
|
|
310
|
+
path = self._resolve_output_path(args.path) if args.path else ""
|
|
311
|
+
pattern = args.pattern or "*"
|
|
312
|
+
|
|
313
|
+
self.logger.info(f"Listing files in '{path}' with pattern '{pattern}'")
|
|
314
|
+
|
|
315
|
+
files = await self.manager.list_files(path, pattern)
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
"files": [
|
|
319
|
+
{
|
|
320
|
+
"name": f.name,
|
|
321
|
+
"path": f.path,
|
|
322
|
+
"size": f.size,
|
|
323
|
+
"content_type": f.content_type,
|
|
324
|
+
"modified_at": f.modified_at.isoformat() if f.modified_at else None,
|
|
325
|
+
"url": f.url
|
|
326
|
+
}
|
|
327
|
+
for f in files
|
|
328
|
+
],
|
|
329
|
+
"count": len(files),
|
|
330
|
+
"directory": path,
|
|
331
|
+
"pattern": pattern
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async def _upload_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
335
|
+
"""Upload a file to storage"""
|
|
336
|
+
if not args.source_path:
|
|
337
|
+
raise ValueError("source_path is required for upload operation")
|
|
338
|
+
|
|
339
|
+
source = Path(args.source_path)
|
|
340
|
+
|
|
341
|
+
if not source.exists():
|
|
342
|
+
raise FileNotFoundError(f"Source file not found: {args.source_path}")
|
|
343
|
+
|
|
344
|
+
# Check file size
|
|
345
|
+
file_size = source.stat().st_size
|
|
346
|
+
self._check_file_size(file_size)
|
|
347
|
+
|
|
348
|
+
# Determine destination
|
|
349
|
+
dest = args.destination_name or source.name
|
|
350
|
+
|
|
351
|
+
if args.destination:
|
|
352
|
+
dest = str(Path(args.destination) / dest)
|
|
353
|
+
|
|
354
|
+
dest = self._resolve_output_path(dest)
|
|
355
|
+
|
|
356
|
+
self.logger.info(f"Uploading '{args.source_path}' to '{dest}'")
|
|
357
|
+
|
|
358
|
+
metadata = await self.manager.upload_file(source, dest)
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
"uploaded": True,
|
|
362
|
+
"name": metadata.name,
|
|
363
|
+
"path": metadata.path,
|
|
364
|
+
"size": metadata.size,
|
|
365
|
+
"content_type": metadata.content_type,
|
|
366
|
+
"url": metadata.url
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async def _download_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
370
|
+
"""Download a file from storage"""
|
|
371
|
+
if not args.path:
|
|
372
|
+
raise ValueError("path is required for download operation")
|
|
373
|
+
|
|
374
|
+
# Default destination in output dir
|
|
375
|
+
if args.destination is None:
|
|
376
|
+
destination = self._resolve_output_path(Path(args.path).name)
|
|
377
|
+
else:
|
|
378
|
+
destination = args.destination
|
|
379
|
+
|
|
380
|
+
dest_path = Path(destination)
|
|
381
|
+
|
|
382
|
+
self.logger.info(f"Downloading '{args.path}' to '{destination}'")
|
|
383
|
+
|
|
384
|
+
result = await self.manager.download_file(args.path, dest_path)
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
"downloaded": True,
|
|
388
|
+
"source": args.path,
|
|
389
|
+
"destination": str(result),
|
|
390
|
+
"size": dest_path.stat().st_size if dest_path.exists() else 0
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async def _copy_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
394
|
+
"""Copy a file within storage"""
|
|
395
|
+
if not args.source:
|
|
396
|
+
raise ValueError("source is required for copy operation")
|
|
397
|
+
if not args.destination:
|
|
398
|
+
raise ValueError("destination is required for copy operation")
|
|
399
|
+
|
|
400
|
+
self.logger.info(f"Copying '{args.source}' to '{args.destination}'")
|
|
401
|
+
|
|
402
|
+
metadata = await self.manager.copy_file(args.source, args.destination)
|
|
403
|
+
|
|
404
|
+
return {
|
|
405
|
+
"copied": True,
|
|
406
|
+
"source": args.source,
|
|
407
|
+
"destination": args.destination,
|
|
408
|
+
"name": metadata.name,
|
|
409
|
+
"size": metadata.size,
|
|
410
|
+
"url": metadata.url
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
async def _delete_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
414
|
+
"""Delete a file from storage"""
|
|
415
|
+
if not args.path:
|
|
416
|
+
raise ValueError("path is required for delete operation")
|
|
417
|
+
|
|
418
|
+
self.logger.info(f"Deleting file '{args.path}'")
|
|
419
|
+
|
|
420
|
+
deleted = await self.manager.delete_file(args.path)
|
|
421
|
+
|
|
422
|
+
return {
|
|
423
|
+
"deleted": deleted,
|
|
424
|
+
"path": args.path
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async def _exists(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
428
|
+
"""Check if a file exists"""
|
|
429
|
+
if not args.path:
|
|
430
|
+
raise ValueError("path is required for exists operation")
|
|
431
|
+
|
|
432
|
+
exists = await self.manager.exists(args.path)
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
"exists": exists,
|
|
436
|
+
"path": args.path
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async def _get_file_url(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
440
|
+
"""Get a URL to access the file"""
|
|
441
|
+
if not args.path:
|
|
442
|
+
raise ValueError("path is required for get_url operation")
|
|
443
|
+
|
|
444
|
+
expiry = args.expiry_seconds or 3600
|
|
445
|
+
|
|
446
|
+
url = await self.manager.get_file_url(args.path, expiry)
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
"url": url,
|
|
450
|
+
"path": args.path,
|
|
451
|
+
"expiry_seconds": expiry
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async def _get_file_metadata(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
455
|
+
"""Get detailed metadata about a file"""
|
|
456
|
+
if not args.path:
|
|
457
|
+
raise ValueError("path is required for get_metadata operation")
|
|
458
|
+
|
|
459
|
+
metadata = await self.manager.get_file_metadata(args.path)
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
"name": metadata.name,
|
|
463
|
+
"path": metadata.path,
|
|
464
|
+
"size": metadata.size,
|
|
465
|
+
"content_type": metadata.content_type,
|
|
466
|
+
"modified_at": metadata.modified_at.isoformat() if metadata.modified_at else None,
|
|
467
|
+
"url": metadata.url
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
async def _create_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
|
|
471
|
+
"""Create a new file with content"""
|
|
472
|
+
if not args.path:
|
|
473
|
+
raise ValueError("path is required for create operation")
|
|
474
|
+
if not args.content:
|
|
475
|
+
raise ValueError("content is required for create operation")
|
|
476
|
+
|
|
477
|
+
# Convert string to bytes
|
|
478
|
+
encoding = args.encoding or 'utf-8'
|
|
479
|
+
content_bytes = args.content.encode(encoding)
|
|
480
|
+
|
|
481
|
+
# Check size
|
|
482
|
+
self._check_file_size(len(content_bytes))
|
|
483
|
+
|
|
484
|
+
dest = self._resolve_output_path(args.path)
|
|
485
|
+
|
|
486
|
+
self.logger.info(f"Creating file '{dest}' ({len(content_bytes)} bytes)")
|
|
487
|
+
|
|
488
|
+
# Use create_from_bytes
|
|
489
|
+
metadata = await self.manager.create_from_bytes(
|
|
490
|
+
dest,
|
|
491
|
+
BytesIO(content_bytes)
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
"created": True,
|
|
496
|
+
"name": metadata.name,
|
|
497
|
+
"path": metadata.path,
|
|
498
|
+
"size": metadata.size,
|
|
499
|
+
"content_type": metadata.content_type,
|
|
500
|
+
"url": metadata.url
|
|
501
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""FileReaderTool implementation for reading various file formats."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, Optional, Tuple
|
|
7
|
+
|
|
8
|
+
import aiofiles
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from pydantic import Field
|
|
11
|
+
|
|
12
|
+
from markitdown import MarkItDown
|
|
13
|
+
|
|
14
|
+
from .abstract import AbstractTool, AbstractToolArgsSchema
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FileReaderToolArgs(AbstractToolArgsSchema):
|
|
18
|
+
"""Arguments for :class:`FileReaderTool`."""
|
|
19
|
+
|
|
20
|
+
file_path: str = Field(description="Path to the file to read")
|
|
21
|
+
encoding: Optional[str] = Field(
|
|
22
|
+
default="utf-8",
|
|
23
|
+
description="Text encoding to use for textual files",
|
|
24
|
+
)
|
|
25
|
+
sheet_name: Optional[str] = Field(
|
|
26
|
+
default=None,
|
|
27
|
+
description="Optional sheet name for Excel workbooks",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FileReaderTool(AbstractTool):
|
|
32
|
+
"""Tool that reads a file and returns its textual representation."""
|
|
33
|
+
|
|
34
|
+
name = "FileReaderTool"
|
|
35
|
+
description = "Read text, document, or tabular files into structured content"
|
|
36
|
+
args_schema = FileReaderToolArgs
|
|
37
|
+
|
|
38
|
+
_TEXT_EXTENSIONS = {".txt", ".md", ".markdown", ".log", ".csv"}
|
|
39
|
+
_MARKITDOWN_EXTENSIONS = {".pdf", ".ppt", ".pptx", ".doc", ".docx"}
|
|
40
|
+
_TABULAR_EXTENSIONS = {".csv", ".tsv", ".xls", ".xlsx", ".xlsm", ".xlsb"}
|
|
41
|
+
|
|
42
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self._markitdown = MarkItDown()
|
|
45
|
+
|
|
46
|
+
async def _execute(
|
|
47
|
+
self,
|
|
48
|
+
file_path: str,
|
|
49
|
+
encoding: Optional[str] = "utf-8",
|
|
50
|
+
sheet_name: Optional[str] = None,
|
|
51
|
+
**_: Any,
|
|
52
|
+
) -> Dict[str, Any]:
|
|
53
|
+
path = Path(file_path).expanduser().resolve()
|
|
54
|
+
|
|
55
|
+
if not path.exists():
|
|
56
|
+
raise FileNotFoundError(f"File not found: {path}")
|
|
57
|
+
|
|
58
|
+
if path.is_dir():
|
|
59
|
+
raise IsADirectoryError(f"Expected a file but received directory: {path}")
|
|
60
|
+
|
|
61
|
+
extension = path.suffix.lower()
|
|
62
|
+
|
|
63
|
+
if extension in self._TABULAR_EXTENSIONS:
|
|
64
|
+
content, metadata = await self._read_tabular_file(path, extension, sheet_name, encoding)
|
|
65
|
+
content_type = "tabular_json"
|
|
66
|
+
elif extension in self._MARKITDOWN_EXTENSIONS:
|
|
67
|
+
content, metadata = await self._read_markitdown_file(path)
|
|
68
|
+
content_type = "markdown"
|
|
69
|
+
elif extension in self._TEXT_EXTENSIONS:
|
|
70
|
+
content = await self._read_text_file(path, encoding=encoding)
|
|
71
|
+
metadata = {"encoding": encoding}
|
|
72
|
+
content_type = "text"
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError(f"Unsupported file extension: {extension}")
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
"file_path": str(path),
|
|
78
|
+
"content_type": content_type,
|
|
79
|
+
"content": content,
|
|
80
|
+
"metadata": {
|
|
81
|
+
"extension": extension,
|
|
82
|
+
**(metadata or {}),
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async def _read_text_file(self, path: Path, encoding: Optional[str]) -> str:
|
|
87
|
+
async with aiofiles.open(path, mode="r", encoding=encoding or "utf-8") as file:
|
|
88
|
+
return await file.read()
|
|
89
|
+
|
|
90
|
+
async def _read_markitdown_file(self, path: Path) -> Tuple[str, Dict[str, Any]]:
|
|
91
|
+
loop = asyncio.get_running_loop()
|
|
92
|
+
|
|
93
|
+
def convert() -> Tuple[str, Dict[str, Any]]:
|
|
94
|
+
result = self._markitdown.convert(str(path))
|
|
95
|
+
text_content = getattr(result, "text_content", "")
|
|
96
|
+
metadata = getattr(result, "metadata", None)
|
|
97
|
+
if text_content is None:
|
|
98
|
+
text_content = ""
|
|
99
|
+
return text_content, metadata or {}
|
|
100
|
+
|
|
101
|
+
return await loop.run_in_executor(None, convert)
|
|
102
|
+
|
|
103
|
+
async def _read_tabular_file(
|
|
104
|
+
self,
|
|
105
|
+
path: Path,
|
|
106
|
+
extension: str,
|
|
107
|
+
sheet_name: Optional[str],
|
|
108
|
+
encoding: Optional[str],
|
|
109
|
+
) -> Tuple[str, Dict[str, Any]]:
|
|
110
|
+
loop = asyncio.get_running_loop()
|
|
111
|
+
|
|
112
|
+
def load_dataframe() -> Tuple[str, Dict[str, Any]]:
|
|
113
|
+
if extension == ".csv" or extension == ".tsv":
|
|
114
|
+
sep = "\t" if extension == ".tsv" else ","
|
|
115
|
+
df = pd.read_csv(path, sep=sep, encoding=encoding or "utf-8")
|
|
116
|
+
else:
|
|
117
|
+
df = pd.read_excel(path, sheet_name=sheet_name)
|
|
118
|
+
|
|
119
|
+
json_content = df.to_json(orient="records", date_format="iso")
|
|
120
|
+
metadata: Dict[str, Any] = {
|
|
121
|
+
"rows": len(df.index),
|
|
122
|
+
"columns": list(df.columns),
|
|
123
|
+
}
|
|
124
|
+
if sheet_name is not None and extension != ".csv" and extension != ".tsv":
|
|
125
|
+
metadata["sheet_name"] = sheet_name
|
|
126
|
+
|
|
127
|
+
return json_content, metadata
|
|
128
|
+
|
|
129
|
+
return await loop.run_in_executor(None, load_dataframe)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .tool import (
|
|
2
|
+
FlowtaskToolkit,
|
|
3
|
+
FlowtaskTool, # Backward compatibility alias
|
|
4
|
+
FlowtaskComponentInput,
|
|
5
|
+
FlowtaskTaskExecutionInput,
|
|
6
|
+
FlowtaskRemoteExecutionInput,
|
|
7
|
+
FlowtaskCodeExecutionInput,
|
|
8
|
+
TaskCodeFormat,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"FlowtaskToolkit",
|
|
13
|
+
"FlowtaskTool",
|
|
14
|
+
"FlowtaskComponentInput",
|
|
15
|
+
"FlowtaskTaskExecutionInput",
|
|
16
|
+
"FlowtaskRemoteExecutionInput",
|
|
17
|
+
"FlowtaskCodeExecutionInput",
|
|
18
|
+
"TaskCodeFormat",
|
|
19
|
+
]
|