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
parrot/tools/ddgo.py
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DuckDuckGo Search Toolkit for AI-Parrot.
|
|
3
|
+
|
|
4
|
+
This toolkit provides web search capabilities using the ddgs library directly,
|
|
5
|
+
removing all Langchain dependencies and implementing proper backoff retry for rate limiting.
|
|
6
|
+
"""
|
|
7
|
+
import asyncio
|
|
8
|
+
from typing import Dict, Any, List, Optional
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
import backoff
|
|
11
|
+
from ddgs import DDGS
|
|
12
|
+
from ddgs.exceptions import (
|
|
13
|
+
DDGSException,
|
|
14
|
+
RatelimitException,
|
|
15
|
+
TimeoutException,
|
|
16
|
+
)
|
|
17
|
+
from navconfig.logging import logging
|
|
18
|
+
from .toolkit import AbstractToolkit
|
|
19
|
+
from .abstract import ToolResult
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Pydantic schemas for tool arguments
|
|
24
|
+
class WebSearchArgs(BaseModel):
|
|
25
|
+
"""Arguments for web search."""
|
|
26
|
+
query: str = Field(description="Search query")
|
|
27
|
+
region: str = Field(default="us-en", description="Search region (e.g., us-en, uk-en, ru-ru)")
|
|
28
|
+
safesearch: str = Field(default="moderate", description="Safe search level: on, moderate, off")
|
|
29
|
+
timelimit: Optional[str] = Field(default=None, description="Time limit: d(day), w(week), m(month), y(year)")
|
|
30
|
+
max_results: int = Field(default=10, description="Maximum number of results to return")
|
|
31
|
+
page: int = Field(default=1, description="Page number for results")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NewsSearchArgs(BaseModel):
|
|
35
|
+
"""Arguments for news search."""
|
|
36
|
+
query: str = Field(description="News search query")
|
|
37
|
+
region: str = Field(default="us-en", description="Search region")
|
|
38
|
+
safesearch: str = Field(default="moderate", description="Safe search level")
|
|
39
|
+
timelimit: Optional[str] = Field(default=None, description="Time limit for news")
|
|
40
|
+
max_results: int = Field(default=10, description="Maximum number of news results")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ImageSearchArgs(BaseModel):
|
|
44
|
+
"""Arguments for image search."""
|
|
45
|
+
query: str = Field(description="Image search query")
|
|
46
|
+
region: str = Field(default="us-en", description="Search region")
|
|
47
|
+
safesearch: str = Field(default="moderate", description="Safe search level")
|
|
48
|
+
size: Optional[str] = Field(default=None, description="Image size filter: Small, Medium, Large, Wallpaper")
|
|
49
|
+
color: Optional[str] = Field(default=None, description="Color filter: color, Monochrome, Red, Orange, etc.")
|
|
50
|
+
type_image: Optional[str] = Field(default=None, description="Image type: photo, clipart, gif, transparent, line")
|
|
51
|
+
layout: Optional[str] = Field(default=None, description="Layout: Square, Tall, Wide")
|
|
52
|
+
license_image: Optional[str] = Field(default=None, description="License: any, Public, Share, ShareCommercially, Modify")
|
|
53
|
+
max_results: int = Field(default=10, description="Maximum number of image results")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class VideoSearchArgs(BaseModel):
|
|
57
|
+
"""Arguments for video search."""
|
|
58
|
+
query: str = Field(description="Video search query")
|
|
59
|
+
region: str = Field(default="us-en", description="Search region")
|
|
60
|
+
safesearch: str = Field(default="moderate", description="Safe search level")
|
|
61
|
+
timelimit: Optional[str] = Field(default=None, description="Time limit for videos")
|
|
62
|
+
resolution: Optional[str] = Field(default=None, description="Video resolution: high, standard")
|
|
63
|
+
duration: Optional[str] = Field(default=None, description="Video duration: short, medium, long")
|
|
64
|
+
license_videos: Optional[str] = Field(default=None, description="Video license filter")
|
|
65
|
+
max_results: int = Field(default=10, description="Maximum number of video results")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class DuckDuckGoToolkit(AbstractToolkit):
|
|
69
|
+
"""
|
|
70
|
+
DuckDuckGo Search Toolkit providing comprehensive search capabilities.
|
|
71
|
+
|
|
72
|
+
This toolkit uses the ddgs library directly for improved performance and reliability,
|
|
73
|
+
with built-in backoff retry mechanisms for handling rate limits.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(self, **kwargs):
|
|
77
|
+
"""Initialize the DuckDuckGo toolkit."""
|
|
78
|
+
super().__init__(**kwargs)
|
|
79
|
+
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
|
80
|
+
|
|
81
|
+
# Backoff configuration
|
|
82
|
+
self.max_retries = kwargs.get('max_retries', 3)
|
|
83
|
+
self.backoff_factor = kwargs.get('backoff_factor', 2.0)
|
|
84
|
+
self.max_wait_time = kwargs.get('max_wait_time', 60.0)
|
|
85
|
+
|
|
86
|
+
def _get_backoff_decorator(self):
|
|
87
|
+
"""Get the backoff decorator for retry logic."""
|
|
88
|
+
return backoff.on_exception(
|
|
89
|
+
backoff.expo,
|
|
90
|
+
(RatelimitException, TimeoutException, DDGSException),
|
|
91
|
+
max_tries=self.max_retries,
|
|
92
|
+
factor=self.backoff_factor,
|
|
93
|
+
max_time=self.max_wait_time,
|
|
94
|
+
logger=self.logger
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
async def web_search(
|
|
98
|
+
self,
|
|
99
|
+
query: str,
|
|
100
|
+
region: str = "us-en",
|
|
101
|
+
safesearch: str = "moderate",
|
|
102
|
+
timelimit: Optional[str] = None,
|
|
103
|
+
max_results: int = 10,
|
|
104
|
+
page: int = 1
|
|
105
|
+
) -> ToolResult:
|
|
106
|
+
"""
|
|
107
|
+
Search the web using DuckDuckGo.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
query: Search query
|
|
111
|
+
region: Search region (e.g., us-en, uk-en, ru-ru)
|
|
112
|
+
safesearch: Safe search level (on, moderate, off)
|
|
113
|
+
timelimit: Time limit (d, w, m, y)
|
|
114
|
+
max_results: Maximum number of results
|
|
115
|
+
page: Page number for results
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
ToolResult containing search results
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
# Create backoff-wrapped search function
|
|
122
|
+
@self._get_backoff_decorator()
|
|
123
|
+
def _search():
|
|
124
|
+
ddgs = DDGS()
|
|
125
|
+
return ddgs.text(
|
|
126
|
+
query=query,
|
|
127
|
+
region=region,
|
|
128
|
+
safesearch=safesearch,
|
|
129
|
+
timelimit=timelimit,
|
|
130
|
+
max_results=max_results,
|
|
131
|
+
page=page,
|
|
132
|
+
backend="auto"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Execute search in thread pool to avoid blocking
|
|
136
|
+
loop = asyncio.get_event_loop()
|
|
137
|
+
results = await loop.run_in_executor(None, _search)
|
|
138
|
+
|
|
139
|
+
return ToolResult(
|
|
140
|
+
status="success",
|
|
141
|
+
result={
|
|
142
|
+
"query": query,
|
|
143
|
+
"total_results": len(results),
|
|
144
|
+
"results": results,
|
|
145
|
+
"search_type": "web"
|
|
146
|
+
},
|
|
147
|
+
metadata={
|
|
148
|
+
"region": region,
|
|
149
|
+
"safesearch": safesearch,
|
|
150
|
+
"timelimit": timelimit,
|
|
151
|
+
"page": page
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
except Exception as e:
|
|
156
|
+
self.logger.error(f"Web search failed for query '{query}': {str(e)}")
|
|
157
|
+
return ToolResult(
|
|
158
|
+
status="error",
|
|
159
|
+
result=[],
|
|
160
|
+
error=f"Search failed: {str(e)}",
|
|
161
|
+
metadata={"query": query}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
async def news_search(
|
|
165
|
+
self,
|
|
166
|
+
query: str,
|
|
167
|
+
region: str = "us-en",
|
|
168
|
+
safesearch: str = "moderate",
|
|
169
|
+
timelimit: Optional[str] = None,
|
|
170
|
+
max_results: int = 10
|
|
171
|
+
) -> ToolResult:
|
|
172
|
+
"""
|
|
173
|
+
Search for news using DuckDuckGo.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
query: News search query
|
|
177
|
+
region: Search region
|
|
178
|
+
safesearch: Safe search level
|
|
179
|
+
timelimit: Time limit for news
|
|
180
|
+
max_results: Maximum number of results
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
ToolResult containing news results
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
@self._get_backoff_decorator()
|
|
187
|
+
def _search():
|
|
188
|
+
ddgs = DDGS()
|
|
189
|
+
return ddgs.news(
|
|
190
|
+
query=query,
|
|
191
|
+
region=region,
|
|
192
|
+
safesearch=safesearch,
|
|
193
|
+
timelimit=timelimit,
|
|
194
|
+
max_results=max_results
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
loop = asyncio.get_event_loop()
|
|
198
|
+
results = await loop.run_in_executor(None, _search)
|
|
199
|
+
|
|
200
|
+
return ToolResult(
|
|
201
|
+
status="success",
|
|
202
|
+
result={
|
|
203
|
+
"query": query,
|
|
204
|
+
"total_results": len(results),
|
|
205
|
+
"results": results,
|
|
206
|
+
"search_type": "news"
|
|
207
|
+
},
|
|
208
|
+
metadata={
|
|
209
|
+
"region": region,
|
|
210
|
+
"safesearch": safesearch,
|
|
211
|
+
"timelimit": timelimit
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
self.logger.error(f"News search failed for query '{query}': {str(e)}")
|
|
217
|
+
return ToolResult(
|
|
218
|
+
status="error",
|
|
219
|
+
result=[],
|
|
220
|
+
error=f"News search failed: {str(e)}",
|
|
221
|
+
metadata={"query": query}
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
async def image_search(
|
|
225
|
+
self,
|
|
226
|
+
query: str,
|
|
227
|
+
region: str = "us-en",
|
|
228
|
+
safesearch: str = "moderate",
|
|
229
|
+
size: Optional[str] = None,
|
|
230
|
+
color: Optional[str] = None,
|
|
231
|
+
type_image: Optional[str] = None,
|
|
232
|
+
layout: Optional[str] = None,
|
|
233
|
+
license_image: Optional[str] = None,
|
|
234
|
+
max_results: int = 10
|
|
235
|
+
) -> ToolResult:
|
|
236
|
+
"""
|
|
237
|
+
Search for images using DuckDuckGo.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
query: Image search query
|
|
241
|
+
region: Search region
|
|
242
|
+
safesearch: Safe search level
|
|
243
|
+
size: Image size filter
|
|
244
|
+
color: Color filter
|
|
245
|
+
type_image: Image type filter
|
|
246
|
+
layout: Layout filter
|
|
247
|
+
license_image: License filter
|
|
248
|
+
max_results: Maximum number of results
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
ToolResult containing image results
|
|
252
|
+
"""
|
|
253
|
+
try:
|
|
254
|
+
@self._get_backoff_decorator()
|
|
255
|
+
def _search():
|
|
256
|
+
ddgs = DDGS()
|
|
257
|
+
return ddgs.images(
|
|
258
|
+
query=query,
|
|
259
|
+
region=region,
|
|
260
|
+
safesearch=safesearch,
|
|
261
|
+
size=size,
|
|
262
|
+
color=color,
|
|
263
|
+
type_image=type_image,
|
|
264
|
+
layout=layout,
|
|
265
|
+
license_image=license_image,
|
|
266
|
+
max_results=max_results
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
loop = asyncio.get_event_loop()
|
|
270
|
+
results = await loop.run_in_executor(None, _search)
|
|
271
|
+
|
|
272
|
+
return ToolResult(
|
|
273
|
+
status="success",
|
|
274
|
+
result={
|
|
275
|
+
"query": query,
|
|
276
|
+
"total_results": len(results),
|
|
277
|
+
"results": results,
|
|
278
|
+
"search_type": "images"
|
|
279
|
+
},
|
|
280
|
+
metadata={
|
|
281
|
+
"region": region,
|
|
282
|
+
"safesearch": safesearch,
|
|
283
|
+
"size": size,
|
|
284
|
+
"color": color,
|
|
285
|
+
"type_image": type_image,
|
|
286
|
+
"layout": layout,
|
|
287
|
+
"license_image": license_image
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
except Exception as e:
|
|
292
|
+
self.logger.error(f"Image search failed for query '{query}': {str(e)}")
|
|
293
|
+
return ToolResult(
|
|
294
|
+
status="error",
|
|
295
|
+
result=[],
|
|
296
|
+
error=f"Image search failed: {str(e)}",
|
|
297
|
+
metadata={"query": query}
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
async def video_search(
|
|
301
|
+
self,
|
|
302
|
+
query: str,
|
|
303
|
+
region: str = "us-en",
|
|
304
|
+
safesearch: str = "moderate",
|
|
305
|
+
timelimit: Optional[str] = None,
|
|
306
|
+
resolution: Optional[str] = None,
|
|
307
|
+
duration: Optional[str] = None,
|
|
308
|
+
license_videos: Optional[str] = None,
|
|
309
|
+
max_results: int = 10
|
|
310
|
+
) -> ToolResult:
|
|
311
|
+
"""
|
|
312
|
+
Search for videos using DuckDuckGo.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
query: Video search query
|
|
316
|
+
region: Search region
|
|
317
|
+
safesearch: Safe search level
|
|
318
|
+
timelimit: Time limit for videos
|
|
319
|
+
resolution: Video resolution filter
|
|
320
|
+
duration: Video duration filter
|
|
321
|
+
license_videos: Video license filter
|
|
322
|
+
max_results: Maximum number of results
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
ToolResult containing video results
|
|
326
|
+
"""
|
|
327
|
+
try:
|
|
328
|
+
@self._get_backoff_decorator()
|
|
329
|
+
def _search():
|
|
330
|
+
ddgs = DDGS()
|
|
331
|
+
return ddgs.videos(
|
|
332
|
+
query=query,
|
|
333
|
+
region=region,
|
|
334
|
+
safesearch=safesearch,
|
|
335
|
+
timelimit=timelimit,
|
|
336
|
+
resolution=resolution,
|
|
337
|
+
duration=duration,
|
|
338
|
+
license_videos=license_videos,
|
|
339
|
+
max_results=max_results
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
loop = asyncio.get_event_loop()
|
|
343
|
+
results = await loop.run_in_executor(None, _search)
|
|
344
|
+
|
|
345
|
+
return ToolResult(
|
|
346
|
+
status="success",
|
|
347
|
+
result={
|
|
348
|
+
"query": query,
|
|
349
|
+
"total_results": len(results),
|
|
350
|
+
"results": results,
|
|
351
|
+
"search_type": "videos"
|
|
352
|
+
},
|
|
353
|
+
metadata={
|
|
354
|
+
"region": region,
|
|
355
|
+
"safesearch": safesearch,
|
|
356
|
+
"timelimit": timelimit,
|
|
357
|
+
"resolution": resolution,
|
|
358
|
+
"duration": duration,
|
|
359
|
+
"license_videos": license_videos
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
except Exception as e:
|
|
364
|
+
self.logger.error(f"Video search failed for query '{query}': {str(e)}")
|
|
365
|
+
return ToolResult(
|
|
366
|
+
status="error",
|
|
367
|
+
result=[],
|
|
368
|
+
error=f"Video search failed: {str(e)}",
|
|
369
|
+
metadata={"query": query}
|
|
370
|
+
)
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from typing import Callable, Optional, Dict, Any, Type, Union, get_args, get_origin, get_type_hints
|
|
2
|
+
from functools import wraps
|
|
3
|
+
import inspect
|
|
4
|
+
import re
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Decorator for custom argument schemas
|
|
10
|
+
def tool_schema(schema: Type[BaseModel], description: Optional[str] = None):
|
|
11
|
+
"""
|
|
12
|
+
Decorator to specify a custom argument schema for a toolkit method.
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
@tool_schema(MyCustomSchema)
|
|
16
|
+
async def my_tool(self, arg1: str, arg2: int) -> str:
|
|
17
|
+
'''My custom tool.'''
|
|
18
|
+
return result
|
|
19
|
+
"""
|
|
20
|
+
def decorator(func):
|
|
21
|
+
# print(f"Decorating {func.__name__} with {schema}")
|
|
22
|
+
func._args_schema = schema
|
|
23
|
+
func._tool_description = description or func.__doc__ or f"Tool: {func.__name__}"
|
|
24
|
+
return func
|
|
25
|
+
return decorator
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def tool(
|
|
29
|
+
name: Optional[str] = None,
|
|
30
|
+
description: Optional[str] = None,
|
|
31
|
+
schema: Optional[Dict[str, Any]] = None,
|
|
32
|
+
auto_register: bool = False
|
|
33
|
+
):
|
|
34
|
+
"""
|
|
35
|
+
Decorator to mark a function as a tool with automatic schema generation.
|
|
36
|
+
|
|
37
|
+
Automatically extracts:
|
|
38
|
+
- Name from function name (or use custom name)
|
|
39
|
+
- Description from docstring (or use custom description)
|
|
40
|
+
- Input schema from type hints (or use custom schema)
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
name: Optional custom tool name (defaults to function name)
|
|
44
|
+
description: Optional custom description (defaults to docstring)
|
|
45
|
+
schema: Optional custom input schema (auto-generated from type hints if not provided)
|
|
46
|
+
auto_register: If True, automatically register with active client/bot
|
|
47
|
+
|
|
48
|
+
Usage:
|
|
49
|
+
@tool()
|
|
50
|
+
def get_weather(location: str) -> str:
|
|
51
|
+
'''Get weather for a location.'''
|
|
52
|
+
return f"Weather in {location}"
|
|
53
|
+
|
|
54
|
+
@tool(name="custom_name", description="Custom description")
|
|
55
|
+
def my_function(param: int) -> str:
|
|
56
|
+
return str(param)
|
|
57
|
+
"""
|
|
58
|
+
def decorator(func: Callable) -> Callable:
|
|
59
|
+
# Extract metadata
|
|
60
|
+
tool_name = name or func.__name__
|
|
61
|
+
tool_description = description or _extract_description(func)
|
|
62
|
+
|
|
63
|
+
# Generate schema from type hints if not provided
|
|
64
|
+
if schema is None:
|
|
65
|
+
tool_schema = _generate_schema_from_function(func)
|
|
66
|
+
else:
|
|
67
|
+
tool_schema = schema
|
|
68
|
+
|
|
69
|
+
# Store metadata on the function
|
|
70
|
+
func._tool_metadata = {
|
|
71
|
+
'name': tool_name,
|
|
72
|
+
'description': tool_description,
|
|
73
|
+
'schema': tool_schema,
|
|
74
|
+
'function': func,
|
|
75
|
+
'auto_register': auto_register
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Mark as a tool
|
|
79
|
+
func._is_tool = True
|
|
80
|
+
|
|
81
|
+
@wraps(func)
|
|
82
|
+
def wrapper(*args, **kwargs):
|
|
83
|
+
return func(*args, **kwargs)
|
|
84
|
+
|
|
85
|
+
# Preserve metadata on wrapper
|
|
86
|
+
wrapper._tool_metadata = func._tool_metadata
|
|
87
|
+
wrapper._is_tool = True
|
|
88
|
+
|
|
89
|
+
return wrapper
|
|
90
|
+
|
|
91
|
+
return decorator
|
|
92
|
+
|
|
93
|
+
def _extract_description(func: Callable) -> str:
|
|
94
|
+
"""
|
|
95
|
+
Extract description from function docstring.
|
|
96
|
+
Takes the first line or paragraph of the docstring.
|
|
97
|
+
"""
|
|
98
|
+
if not func.__doc__:
|
|
99
|
+
return f"Tool: {func.__name__}"
|
|
100
|
+
|
|
101
|
+
# Get first line or first paragraph
|
|
102
|
+
docstring = func.__doc__.strip()
|
|
103
|
+
|
|
104
|
+
# Split by newlines and get first non-empty line
|
|
105
|
+
lines = [line.strip() for line in docstring.split('\n')]
|
|
106
|
+
non_empty = [line for line in lines if line]
|
|
107
|
+
|
|
108
|
+
if non_empty:
|
|
109
|
+
return non_empty[0]
|
|
110
|
+
|
|
111
|
+
return f"Tool: {func.__name__}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _generate_schema_from_function(func: Callable) -> Dict[str, Any]:
|
|
115
|
+
"""
|
|
116
|
+
Generate JSON schema from function signature and type hints.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
func: The function to generate schema for
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
JSON schema dictionary
|
|
123
|
+
"""
|
|
124
|
+
sig = inspect.signature(func)
|
|
125
|
+
|
|
126
|
+
# Get type hints
|
|
127
|
+
try:
|
|
128
|
+
type_hints = get_type_hints(func)
|
|
129
|
+
except Exception:
|
|
130
|
+
# If get_type_hints fails, fall back to annotations
|
|
131
|
+
type_hints = func.__annotations__ or {}
|
|
132
|
+
|
|
133
|
+
properties = {}
|
|
134
|
+
required = []
|
|
135
|
+
|
|
136
|
+
for param_name, param in sig.parameters.items():
|
|
137
|
+
# Skip self and cls
|
|
138
|
+
if param_name in ('self', 'cls'):
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
# Get type hint (default to string if not specified)
|
|
142
|
+
param_type = type_hints.get(param_name, str)
|
|
143
|
+
|
|
144
|
+
# Convert Python types to JSON schema types
|
|
145
|
+
json_type = _python_type_to_json_type(param_type)
|
|
146
|
+
|
|
147
|
+
# Get description from docstring if available
|
|
148
|
+
param_description = _extract_param_description(func, param_name)
|
|
149
|
+
|
|
150
|
+
# Build property definition
|
|
151
|
+
if isinstance(json_type, dict):
|
|
152
|
+
# Complex type (List, Optional, Union, etc.)
|
|
153
|
+
prop_def = json_type.copy()
|
|
154
|
+
if param_description:
|
|
155
|
+
prop_def['description'] = param_description
|
|
156
|
+
else:
|
|
157
|
+
prop_def['description'] = f"The {param_name} parameter"
|
|
158
|
+
else:
|
|
159
|
+
# Simple type
|
|
160
|
+
prop_def = {
|
|
161
|
+
'type': json_type,
|
|
162
|
+
'description': param_description or f"The {param_name} parameter"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
properties[param_name] = prop_def
|
|
166
|
+
|
|
167
|
+
# Check if parameter is required (no default value)
|
|
168
|
+
if param.default == inspect.Parameter.empty:
|
|
169
|
+
required.append(param_name)
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
'type': 'object',
|
|
173
|
+
'properties': properties,
|
|
174
|
+
'required': required
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
def _extract_param_description(func: Callable, param_name: str) -> Optional[str]:
|
|
178
|
+
"""
|
|
179
|
+
Extract parameter description from docstring.
|
|
180
|
+
Looks for Google, NumPy, or Sphinx style docstrings.
|
|
181
|
+
"""
|
|
182
|
+
if not func.__doc__:
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
docstring = func.__doc__
|
|
186
|
+
|
|
187
|
+
# Google style: Args: section
|
|
188
|
+
google_pattern = rf'{param_name}\s*:\s*(.+?)(?:\n|$)'
|
|
189
|
+
match = re.search(google_pattern, docstring)
|
|
190
|
+
if match:
|
|
191
|
+
return match.group(1).strip()
|
|
192
|
+
|
|
193
|
+
# Sphinx style: :param name: description
|
|
194
|
+
sphinx_pattern = rf':param\s+{param_name}\s*:\s*(.+?)(?:\n|$)'
|
|
195
|
+
match = re.search(sphinx_pattern, docstring)
|
|
196
|
+
if match:
|
|
197
|
+
return match.group(1).strip()
|
|
198
|
+
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _python_type_to_json_type(python_type: Any) -> Union[str, Dict[str, Any]]:
|
|
203
|
+
"""
|
|
204
|
+
Convert Python type hints to JSON schema types.
|
|
205
|
+
|
|
206
|
+
Handles:
|
|
207
|
+
- Basic types (str, int, float, bool)
|
|
208
|
+
- Optional types
|
|
209
|
+
- List types
|
|
210
|
+
- Dict types
|
|
211
|
+
- Union types
|
|
212
|
+
- Enum types
|
|
213
|
+
"""
|
|
214
|
+
# Handle None type
|
|
215
|
+
if python_type is type(None):
|
|
216
|
+
return "null"
|
|
217
|
+
|
|
218
|
+
# Get origin for generic types (List, Dict, Optional, etc.)
|
|
219
|
+
origin = get_origin(python_type)
|
|
220
|
+
|
|
221
|
+
# Handle Optional[T] -> Union[T, None]
|
|
222
|
+
if origin is Union:
|
|
223
|
+
args = get_args(python_type)
|
|
224
|
+
# Check if it's Optional (Union with None)
|
|
225
|
+
if type(None) in args:
|
|
226
|
+
# It's Optional, get the non-None type
|
|
227
|
+
non_none_types = [t for t in args if t is not type(None)]
|
|
228
|
+
if len(non_none_types) == 1:
|
|
229
|
+
# Optional[T] - return the type with nullable
|
|
230
|
+
base_type = _python_type_to_json_type(non_none_types[0])
|
|
231
|
+
if isinstance(base_type, dict):
|
|
232
|
+
return base_type
|
|
233
|
+
return {"type": [base_type, "null"]}
|
|
234
|
+
# Regular Union - return anyOf
|
|
235
|
+
return {
|
|
236
|
+
"anyOf": [_python_type_to_json_type(t) for t in args]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Handle List[T]
|
|
240
|
+
if origin is list or python_type is list:
|
|
241
|
+
args = get_args(python_type)
|
|
242
|
+
if args:
|
|
243
|
+
item_type = _python_type_to_json_type(args[0])
|
|
244
|
+
return {
|
|
245
|
+
"type": "array",
|
|
246
|
+
"items": {"type": item_type} if isinstance(item_type, str) else item_type
|
|
247
|
+
}
|
|
248
|
+
return "array"
|
|
249
|
+
|
|
250
|
+
# Handle Dict[K, V]
|
|
251
|
+
if origin is dict or python_type is dict:
|
|
252
|
+
return "object"
|
|
253
|
+
|
|
254
|
+
# Handle Enum
|
|
255
|
+
if inspect.isclass(python_type) and issubclass(python_type, Enum):
|
|
256
|
+
return {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"enum": [e.value for e in python_type]
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# Basic types
|
|
262
|
+
type_mapping = {
|
|
263
|
+
str: "string",
|
|
264
|
+
int: "integer",
|
|
265
|
+
float: "number",
|
|
266
|
+
bool: "boolean",
|
|
267
|
+
list: "array",
|
|
268
|
+
dict: "object",
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return type_mapping.get(python_type, "string")
|