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/think.py
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ThinkTool - A metacognitive tool for explicit agent reasoning.
|
|
3
|
+
|
|
4
|
+
This tool implements the "Thinking as a Tool" pattern, a simplified version
|
|
5
|
+
of the ReAct (Reasoning + Acting) paradigm. By converting the agent's internal
|
|
6
|
+
reasoning into an explicit, observable action, it forces Chain-of-Thought
|
|
7
|
+
reasoning and improves decision-making quality.
|
|
8
|
+
|
|
9
|
+
Key benefits:
|
|
10
|
+
- Forces explicit reasoning before complex actions
|
|
11
|
+
- Makes the decision-making process observable and auditable
|
|
12
|
+
- Prevents impulsive actions by requiring deliberation
|
|
13
|
+
- Improves response quality through structured thinking
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
from parrot.tools import ThinkTool, ToolManager
|
|
17
|
+
|
|
18
|
+
# Basic usage
|
|
19
|
+
think_tool = ThinkTool()
|
|
20
|
+
|
|
21
|
+
# With custom context for specific domains
|
|
22
|
+
data_think = ThinkTool(
|
|
23
|
+
extra_context="Focus on data quality, transformations, and analysis strategy."
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# With custom output handler
|
|
27
|
+
def log_thoughts(input_data: ThinkInput) -> str:
|
|
28
|
+
print(f"Agent thinking: {input_data.thoughts}")
|
|
29
|
+
return "Reasoning recorded"
|
|
30
|
+
|
|
31
|
+
think_tool = ThinkTool(output_handler=log_thoughts)
|
|
32
|
+
|
|
33
|
+
# Register with ToolManager
|
|
34
|
+
tool_manager = ToolManager()
|
|
35
|
+
tool_manager.register_tool(think_tool)
|
|
36
|
+
|
|
37
|
+
Example agent interaction:
|
|
38
|
+
Agent: think(thoughts="The user wants correlation analysis between sales and
|
|
39
|
+
temperature. I should first check data types, handle
|
|
40
|
+
missing values, then compute Pearson correlation...")
|
|
41
|
+
Agent: execute_code("df[['sales', 'temperature']].dropna().corr()")
|
|
42
|
+
"""
|
|
43
|
+
from typing import Callable, Dict, Optional, Type, Union
|
|
44
|
+
from pydantic import Field
|
|
45
|
+
from .abstract import (
|
|
46
|
+
AbstractTool,
|
|
47
|
+
AbstractToolArgsSchema,
|
|
48
|
+
ToolResult,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ThinkInput(AbstractToolArgsSchema):
|
|
53
|
+
"""
|
|
54
|
+
Input schema for the ThinkTool.
|
|
55
|
+
|
|
56
|
+
The thoughts field captures the agent's reasoning process, including:
|
|
57
|
+
- Problem analysis and clarification
|
|
58
|
+
- Assumptions being made
|
|
59
|
+
- Planned approach or strategy
|
|
60
|
+
- Potential issues or edge cases to consider
|
|
61
|
+
|
|
62
|
+
Note: A 'next_step' field was intentionally omitted as it tends to
|
|
63
|
+
cause hallucinations and rigid behavior in practice.
|
|
64
|
+
"""
|
|
65
|
+
thoughts: str = Field(
|
|
66
|
+
...,
|
|
67
|
+
description=(
|
|
68
|
+
"Describe your reasoning process: analyze the problem, "
|
|
69
|
+
"clarify assumptions, identify potential issues, and "
|
|
70
|
+
"outline your planned approach before taking action."
|
|
71
|
+
),
|
|
72
|
+
min_length=10, # Encourage substantive thinking
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ThinkTool(AbstractTool):
|
|
77
|
+
"""
|
|
78
|
+
A metacognitive tool that forces explicit reasoning before action.
|
|
79
|
+
|
|
80
|
+
This tool implements the "Thinking as a Tool" pattern, which converts
|
|
81
|
+
the agent's internal reasoning into an observable, recorded action.
|
|
82
|
+
The primary value is in the process (forcing deliberation) rather
|
|
83
|
+
than the output.
|
|
84
|
+
|
|
85
|
+
Use cases:
|
|
86
|
+
- Complex multi-step tasks requiring careful planning
|
|
87
|
+
- Debugging agent decision-making processes
|
|
88
|
+
- Improving response quality through deliberate thinking
|
|
89
|
+
- Auditing and understanding agent reasoning
|
|
90
|
+
|
|
91
|
+
When NOT to use:
|
|
92
|
+
- Simple, straightforward tasks where it adds unnecessary latency
|
|
93
|
+
- When using LLM's native extended_thinking (would be redundant)
|
|
94
|
+
- Highly structured workflows with predetermined reasoning
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
name: Tool identifier ("think" by default)
|
|
98
|
+
description: Tool description for the LLM
|
|
99
|
+
args_schema: Pydantic model for input validation (ThinkInput)
|
|
100
|
+
|
|
101
|
+
Example:
|
|
102
|
+
>>> think_tool = ThinkTool()
|
|
103
|
+
>>> result = await think_tool.execute(
|
|
104
|
+
... thoughts="Analyzing the CSV structure: I see columns for date, "
|
|
105
|
+
... "amount, and category. I should parse dates first, "
|
|
106
|
+
... "then aggregate by category for the monthly report."
|
|
107
|
+
... )
|
|
108
|
+
>>> print(result.status)
|
|
109
|
+
'success'
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
name: str = "think"
|
|
113
|
+
description: str = (
|
|
114
|
+
"Use when you need to reason through a problem, clarify your "
|
|
115
|
+
"assumptions, or plan your approach before acting. Think before "
|
|
116
|
+
"complex operations, multi-step tasks, or when facing ambiguity."
|
|
117
|
+
)
|
|
118
|
+
args_schema: Type[AbstractToolArgsSchema] = ThinkInput
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
name: Optional[str] = None,
|
|
123
|
+
description: Optional[str] = None,
|
|
124
|
+
extra_context: str = "",
|
|
125
|
+
output_handler: Optional[Union[str, Callable[[ThinkInput], str]]] = None,
|
|
126
|
+
**kwargs
|
|
127
|
+
):
|
|
128
|
+
"""
|
|
129
|
+
Initialize the ThinkTool.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
name: Custom tool name (default: "think")
|
|
133
|
+
description: Custom description (appends extra_context if provided)
|
|
134
|
+
extra_context: Additional instructions appended to the description.
|
|
135
|
+
Useful for domain-specific thinking guidance.
|
|
136
|
+
output_handler: Either a static string response or a callable that
|
|
137
|
+
receives ThinkInput and returns a string. The callable
|
|
138
|
+
can be used for logging, metrics, or custom processing.
|
|
139
|
+
**kwargs: Additional arguments passed to AbstractTool
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
# Domain-specific thinking tool
|
|
143
|
+
scraping_think = ThinkTool(
|
|
144
|
+
name="plan_scraping",
|
|
145
|
+
extra_context="Consider page structure, anti-bot measures, "
|
|
146
|
+
"and optimal selectors before scraping."
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# With custom output processing
|
|
150
|
+
def track_reasoning(input_data):
|
|
151
|
+
metrics.record_thought(input_data.thoughts)
|
|
152
|
+
return "Reasoning tracked"
|
|
153
|
+
|
|
154
|
+
tracked_think = ThinkTool(output_handler=track_reasoning)
|
|
155
|
+
"""
|
|
156
|
+
# Handle name override
|
|
157
|
+
if name:
|
|
158
|
+
self.name = name
|
|
159
|
+
|
|
160
|
+
# Handle description with extra context
|
|
161
|
+
if description:
|
|
162
|
+
self.description = description
|
|
163
|
+
if extra_context:
|
|
164
|
+
self.description = f"{self.description} {extra_context}"
|
|
165
|
+
|
|
166
|
+
# Set output handler (default: simple acknowledgment)
|
|
167
|
+
self._output_handler: Union[str, Callable[[ThinkInput], str]] = (
|
|
168
|
+
output_handler if output_handler is not None else "OK"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
super().__init__(**kwargs)
|
|
172
|
+
|
|
173
|
+
async def _execute(
|
|
174
|
+
self,
|
|
175
|
+
thoughts: str,
|
|
176
|
+
**kwargs
|
|
177
|
+
) -> ToolResult:
|
|
178
|
+
"""
|
|
179
|
+
Execute the think operation.
|
|
180
|
+
|
|
181
|
+
The actual value of this tool is in the process of thinking,
|
|
182
|
+
not in the execution result. The agent's thoughts are recorded
|
|
183
|
+
in the tool call history, making the reasoning process observable.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
thoughts: The agent's reasoning/thinking content
|
|
187
|
+
**kwargs: Additional arguments (ignored)
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
ToolResult with status and acknowledgment message
|
|
191
|
+
"""
|
|
192
|
+
# Create input model for potential handler use
|
|
193
|
+
input_data = ThinkInput(thoughts=thoughts)
|
|
194
|
+
|
|
195
|
+
# Generate output based on handler type
|
|
196
|
+
if callable(self._output_handler):
|
|
197
|
+
try:
|
|
198
|
+
output = self._output_handler(input_data)
|
|
199
|
+
except Exception as e:
|
|
200
|
+
self.logger.warning(f"Output handler failed: {e}")
|
|
201
|
+
output = "OK"
|
|
202
|
+
else:
|
|
203
|
+
output = self._output_handler
|
|
204
|
+
|
|
205
|
+
return ToolResult(
|
|
206
|
+
status="success",
|
|
207
|
+
result=output,
|
|
208
|
+
metadata={
|
|
209
|
+
"thought_length": len(thoughts),
|
|
210
|
+
"tool_type": "metacognitive",
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# =============================================================================
|
|
216
|
+
# Specialized Variants
|
|
217
|
+
# =============================================================================
|
|
218
|
+
|
|
219
|
+
class DataAnalysisThinkTool(ThinkTool):
|
|
220
|
+
"""
|
|
221
|
+
Specialized thinking tool for data analysis tasks.
|
|
222
|
+
|
|
223
|
+
Guides the agent to consider data quality, transformations,
|
|
224
|
+
and analysis strategy before executing data operations.
|
|
225
|
+
|
|
226
|
+
Example:
|
|
227
|
+
>>> tool = DataAnalysisThinkTool()
|
|
228
|
+
>>> result = await tool.execute(
|
|
229
|
+
... thoughts="Dataset has 10k rows with 3 date columns. "
|
|
230
|
+
... "I'll parse dates, check for nulls in the amount "
|
|
231
|
+
... "column, then create a pivot table by month."
|
|
232
|
+
... )
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
name: str = "think_data_analysis"
|
|
236
|
+
description: str = (
|
|
237
|
+
"Use before data analysis operations. Reason about data quality, "
|
|
238
|
+
"required transformations, potential issues (nulls, types, outliers), "
|
|
239
|
+
"and your analysis strategy."
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class ScrapingPlanTool(ThinkTool):
|
|
244
|
+
"""
|
|
245
|
+
Specialized thinking tool for web scraping tasks.
|
|
246
|
+
|
|
247
|
+
Guides the agent to plan scraping strategy considering page structure,
|
|
248
|
+
anti-bot measures, and selector reliability.
|
|
249
|
+
|
|
250
|
+
Example:
|
|
251
|
+
>>> tool = ScrapingPlanTool()
|
|
252
|
+
>>> result = await tool.execute(
|
|
253
|
+
... thoughts="Target page uses infinite scroll with lazy loading. "
|
|
254
|
+
... "I'll use incremental scrolling with dynamic waits. "
|
|
255
|
+
... "Product cards have consistent class 'product-item'."
|
|
256
|
+
... )
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
name: str = "plan_scraping"
|
|
260
|
+
description: str = (
|
|
261
|
+
"Use before web scraping operations. Plan your approach considering "
|
|
262
|
+
"page structure (static/dynamic/SPA), anti-bot measures, pagination "
|
|
263
|
+
"type, and selector strategy. Identify reliable selectors and "
|
|
264
|
+
"potential failure points."
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class QueryPlanTool(ThinkTool):
|
|
269
|
+
"""
|
|
270
|
+
Specialized thinking tool for database query planning.
|
|
271
|
+
|
|
272
|
+
Guides the agent to consider query optimization, table relationships,
|
|
273
|
+
and potential performance issues.
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
>>> tool = QueryPlanTool()
|
|
277
|
+
>>> result = await tool.execute(
|
|
278
|
+
... thoughts="Need to join orders with customers and products. "
|
|
279
|
+
... "Orders table is large (~5M rows), should filter by "
|
|
280
|
+
... "date range first. Index exists on order_date."
|
|
281
|
+
... )
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
name: str = "plan_query"
|
|
285
|
+
description: str = (
|
|
286
|
+
"Use before complex database queries. Consider table relationships, "
|
|
287
|
+
"query optimization (indexes, filters), potential performance issues, "
|
|
288
|
+
"and the best approach to retrieve the required data."
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class RAGRetrievalThinkTool(ThinkTool):
|
|
293
|
+
"""
|
|
294
|
+
Specialized thinking tool for RAG retrieval strategy.
|
|
295
|
+
|
|
296
|
+
Guides the agent to plan retrieval approach based on query type,
|
|
297
|
+
expected document relevance, and retrieval method selection.
|
|
298
|
+
|
|
299
|
+
Particularly useful for Adaptive Agentic RAG implementations.
|
|
300
|
+
|
|
301
|
+
Example:
|
|
302
|
+
>>> tool = RAGRetrievalThinkTool()
|
|
303
|
+
>>> result = await tool.execute(
|
|
304
|
+
... thoughts="User query is factual and specific. Dense retrieval "
|
|
305
|
+
... "should work well. Will use top-5 chunks with "
|
|
306
|
+
... "reranking. No need for hybrid search here."
|
|
307
|
+
... )
|
|
308
|
+
"""
|
|
309
|
+
|
|
310
|
+
name: str = "plan_retrieval"
|
|
311
|
+
description: str = (
|
|
312
|
+
"Use before RAG retrieval operations. Analyze query type (factual, "
|
|
313
|
+
"exploratory, comparative), decide on retrieval strategy (dense, "
|
|
314
|
+
"sparse, hybrid), determine chunk count, and consider if reranking "
|
|
315
|
+
"or query expansion is needed."
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# =============================================================================
|
|
320
|
+
# Factory Function
|
|
321
|
+
# =============================================================================
|
|
322
|
+
|
|
323
|
+
def create_think_tool(
|
|
324
|
+
domain: Optional[str] = None,
|
|
325
|
+
name: Optional[str] = None,
|
|
326
|
+
extra_context: str = "",
|
|
327
|
+
output_handler: Optional[Union[str, Callable[[ThinkInput], str]]] = None,
|
|
328
|
+
) -> ThinkTool:
|
|
329
|
+
"""
|
|
330
|
+
Factory function to create domain-specific ThinkTool instances.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
domain: Predefined domain ('data', 'scraping', 'query', 'rag')
|
|
334
|
+
or None for generic ThinkTool
|
|
335
|
+
name: Custom tool name (overrides domain default)
|
|
336
|
+
extra_context: Additional context appended to description
|
|
337
|
+
output_handler: Custom output handler
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Configured ThinkTool instance
|
|
341
|
+
|
|
342
|
+
Example:
|
|
343
|
+
# Using predefined domain
|
|
344
|
+
data_tool = create_think_tool(domain='data')
|
|
345
|
+
|
|
346
|
+
# Custom configuration
|
|
347
|
+
custom_tool = create_think_tool(
|
|
348
|
+
domain='scraping',
|
|
349
|
+
name='plan_ecommerce_scrape',
|
|
350
|
+
extra_context='Consider rate limiting for this e-commerce site.'
|
|
351
|
+
)
|
|
352
|
+
"""
|
|
353
|
+
domain_map: Dict[str, Type[ThinkTool]] = {
|
|
354
|
+
'data': DataAnalysisThinkTool,
|
|
355
|
+
'data_analysis': DataAnalysisThinkTool,
|
|
356
|
+
'scraping': ScrapingPlanTool,
|
|
357
|
+
'web_scraping': ScrapingPlanTool,
|
|
358
|
+
'query': QueryPlanTool,
|
|
359
|
+
'database': QueryPlanTool,
|
|
360
|
+
'rag': RAGRetrievalThinkTool,
|
|
361
|
+
'retrieval': RAGRetrievalThinkTool,
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if domain and domain.lower() in domain_map:
|
|
365
|
+
tool_class = domain_map[domain.lower()]
|
|
366
|
+
tool = tool_class(
|
|
367
|
+
name=name,
|
|
368
|
+
extra_context=extra_context,
|
|
369
|
+
output_handler=output_handler,
|
|
370
|
+
)
|
|
371
|
+
else:
|
|
372
|
+
tool = ThinkTool(
|
|
373
|
+
name=name,
|
|
374
|
+
extra_context=extra_context,
|
|
375
|
+
output_handler=output_handler,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return tool
|
parrot/tools/toolkit.py
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AbstractToolkit for creating collections of tools from class methods.
|
|
3
|
+
"""
|
|
4
|
+
import inspect
|
|
5
|
+
from typing import Dict, List, Type, Optional, Any, get_type_hints
|
|
6
|
+
from abc import ABC
|
|
7
|
+
from pydantic import BaseModel, create_model, Field
|
|
8
|
+
from navconfig.logging import logging
|
|
9
|
+
from datamodel.parsers.json import json_decoder, json_encoder # noqa pylint: disable=E0611
|
|
10
|
+
from ..conf import BASE_STATIC_URL
|
|
11
|
+
from .abstract import AbstractTool, AbstractToolArgsSchema
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ToolkitTool(AbstractTool):
|
|
15
|
+
"""
|
|
16
|
+
A specialized AbstractTool that wraps a method from a toolkit.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
name: str,
|
|
22
|
+
bound_method: callable,
|
|
23
|
+
description: str = None,
|
|
24
|
+
args_schema: Type[BaseModel] = None,
|
|
25
|
+
**kwargs
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Initialize a toolkit tool.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
name: Tool name
|
|
32
|
+
bound_method: The bound coroutine method to wrap
|
|
33
|
+
description: Tool description
|
|
34
|
+
args_schema: Pydantic model for arguments
|
|
35
|
+
**kwargs: Additional arguments
|
|
36
|
+
"""
|
|
37
|
+
self.bound_method = bound_method
|
|
38
|
+
|
|
39
|
+
# Set up the tool
|
|
40
|
+
super().__init__(
|
|
41
|
+
name=name,
|
|
42
|
+
description=description or bound_method.__doc__ or f"Tool: {name}",
|
|
43
|
+
**kwargs
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Set the args schema
|
|
47
|
+
if args_schema:
|
|
48
|
+
self.args_schema = args_schema
|
|
49
|
+
else:
|
|
50
|
+
# Try to generate schema from method signature
|
|
51
|
+
self.args_schema = self._generate_args_schema_from_method()
|
|
52
|
+
|
|
53
|
+
def _generate_args_schema_from_method(self) -> Type[BaseModel]:
|
|
54
|
+
"""
|
|
55
|
+
Generate a Pydantic schema from the method's type hints.
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
# Get method signature
|
|
59
|
+
sig = inspect.signature(self.bound_method)
|
|
60
|
+
type_hints = get_type_hints(self.bound_method)
|
|
61
|
+
|
|
62
|
+
# Build fields for Pydantic model
|
|
63
|
+
fields = {}
|
|
64
|
+
|
|
65
|
+
for param_name, param in sig.parameters.items():
|
|
66
|
+
# Skip 'self' parameter (shouldn't be there for bound methods, but just in case)
|
|
67
|
+
if param_name == 'self':
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
# Get type hint
|
|
71
|
+
param_type = type_hints.get(param_name, Any)
|
|
72
|
+
|
|
73
|
+
# Handle Optional types and defaults
|
|
74
|
+
if param.default == param.empty:
|
|
75
|
+
# Required parameter
|
|
76
|
+
default_value = ...
|
|
77
|
+
else:
|
|
78
|
+
# Has default value
|
|
79
|
+
default_value = param.default
|
|
80
|
+
|
|
81
|
+
# Create field with description based on parameter name
|
|
82
|
+
description = f"Parameter: {param_name}"
|
|
83
|
+
fields[param_name] = (param_type, Field(default=default_value, description=description))
|
|
84
|
+
|
|
85
|
+
# Create dynamic Pydantic model
|
|
86
|
+
if fields:
|
|
87
|
+
return create_model(
|
|
88
|
+
f"{self.name}Args",
|
|
89
|
+
**fields
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
# No parameters, return base schema
|
|
93
|
+
return AbstractToolArgsSchema
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
self.logger.warning(f"Could not generate schema for {self.name}: {e}")
|
|
97
|
+
return AbstractToolArgsSchema
|
|
98
|
+
|
|
99
|
+
async def _execute(self, **kwargs) -> Any:
|
|
100
|
+
"""
|
|
101
|
+
Execute the toolkit method.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
**kwargs: Method arguments
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Method result
|
|
108
|
+
"""
|
|
109
|
+
return await self.bound_method(**kwargs)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class AbstractToolkit(ABC):
|
|
113
|
+
"""
|
|
114
|
+
Abstract base class for creating toolkits - collections of related tools.
|
|
115
|
+
|
|
116
|
+
A toolkit automatically converts all public async methods into tools.
|
|
117
|
+
Each method becomes a tool with:
|
|
118
|
+
- Name: method name
|
|
119
|
+
- Description: method docstring
|
|
120
|
+
- Schema: automatically generated from type hints
|
|
121
|
+
|
|
122
|
+
Usage:
|
|
123
|
+
class MyToolkit(AbstractToolkit):
|
|
124
|
+
async def search_web(self, query: str) -> str:
|
|
125
|
+
'''Search the web for information.'''
|
|
126
|
+
# Implementation here
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
async def calculate(self, expression: str) -> float:
|
|
130
|
+
'''Calculate a mathematical expression.'''
|
|
131
|
+
# Implementation here
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
# Get all tools
|
|
135
|
+
toolkit = MyToolkit()
|
|
136
|
+
tools = toolkit.get_tools()
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
# Configuration
|
|
140
|
+
input_class: Optional[Type[BaseModel]] = None # Default input schema (optional)
|
|
141
|
+
return_direct: bool = False # Whether tools return results directly
|
|
142
|
+
json_encoder: Type[Any] = json_encoder
|
|
143
|
+
json_decoder: Type[Any] = json_decoder
|
|
144
|
+
base_url: str = BASE_STATIC_URL
|
|
145
|
+
|
|
146
|
+
def __init__(self, **kwargs):
|
|
147
|
+
"""
|
|
148
|
+
Initialize the toolkit.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
**kwargs: Configuration options
|
|
152
|
+
"""
|
|
153
|
+
# Configuration
|
|
154
|
+
self.return_direct = kwargs.get('return_direct', self.return_direct)
|
|
155
|
+
self.base_url = kwargs.get('base_url', self.base_url)
|
|
156
|
+
|
|
157
|
+
# Tool cache
|
|
158
|
+
self._tool_cache: Dict[str, ToolkitTool] = {}
|
|
159
|
+
self._tools_generated = False
|
|
160
|
+
|
|
161
|
+
async def start(self) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Optional startup logic for the toolkit.
|
|
164
|
+
Override in subclasses if needed.
|
|
165
|
+
"""
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
async def stop(self) -> None:
|
|
169
|
+
"""
|
|
170
|
+
Optional shutdown logic for the toolkit.
|
|
171
|
+
Override in subclasses if needed.
|
|
172
|
+
"""
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
async def cleanup(self) -> None:
|
|
176
|
+
"""
|
|
177
|
+
Optional cleanup logic for the toolkit.
|
|
178
|
+
Override in subclasses if needed.
|
|
179
|
+
"""
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
def get_tools(self) -> List[AbstractTool]:
|
|
183
|
+
"""
|
|
184
|
+
Get all tools from this toolkit.
|
|
185
|
+
|
|
186
|
+
Inspects all public async methods and converts them to tools.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
List of AbstractTool instances
|
|
190
|
+
"""
|
|
191
|
+
if self._tools_generated and self._tool_cache:
|
|
192
|
+
return list(self._tool_cache.values())
|
|
193
|
+
|
|
194
|
+
tools = []
|
|
195
|
+
|
|
196
|
+
# Inspect all methods - get bound methods
|
|
197
|
+
for name in dir(self):
|
|
198
|
+
# Skip private methods and non-methods
|
|
199
|
+
if name.startswith('_'):
|
|
200
|
+
continue
|
|
201
|
+
|
|
202
|
+
# Skip toolkit management methods
|
|
203
|
+
if name in ('get_tools', 'get_tool', 'list_tool_names', 'start', 'stop', 'cleanup'):
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
# Get the attribute
|
|
207
|
+
attr = getattr(self, name)
|
|
208
|
+
|
|
209
|
+
# Check if it's a coroutine function
|
|
210
|
+
if not inspect.iscoroutinefunction(attr):
|
|
211
|
+
continue
|
|
212
|
+
|
|
213
|
+
# Create tool from bound method
|
|
214
|
+
tool = self._create_tool_from_method(name, attr)
|
|
215
|
+
tools.append(tool)
|
|
216
|
+
self._tool_cache[name] = tool
|
|
217
|
+
|
|
218
|
+
self._tools_generated = True
|
|
219
|
+
return tools
|
|
220
|
+
|
|
221
|
+
def get_tool(self, name: str) -> Optional[AbstractTool]:
|
|
222
|
+
"""
|
|
223
|
+
Get a specific tool by name.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
name: Tool name
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
AbstractTool instance or None if not found
|
|
230
|
+
"""
|
|
231
|
+
if not self._tools_generated:
|
|
232
|
+
self.get_tools() # Ensure tools are generated
|
|
233
|
+
|
|
234
|
+
return self._tool_cache.get(name)
|
|
235
|
+
|
|
236
|
+
def list_tool_names(self) -> List[str]:
|
|
237
|
+
"""
|
|
238
|
+
Get a list of all tool names in this toolkit.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
List of tool names
|
|
242
|
+
"""
|
|
243
|
+
if not self._tools_generated:
|
|
244
|
+
self.get_tools()
|
|
245
|
+
|
|
246
|
+
return list(self._tool_cache.keys())
|
|
247
|
+
|
|
248
|
+
def _create_tool_from_method(self, name: str, bound_method: callable) -> ToolkitTool:
|
|
249
|
+
"""
|
|
250
|
+
Create a ToolkitTool from a bound method.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
name: Method name
|
|
254
|
+
bound_method: The bound coroutine method
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
ToolkitTool instance
|
|
258
|
+
"""
|
|
259
|
+
# Get description from docstring
|
|
260
|
+
description = bound_method.__doc__ or f"Tool: {name}"
|
|
261
|
+
description = description.strip()
|
|
262
|
+
|
|
263
|
+
# Determine args schema - prioritize method-specific schema
|
|
264
|
+
args_schema = getattr(bound_method, '_args_schema', None)
|
|
265
|
+
|
|
266
|
+
# If no custom schema is defined, always generate from method signature
|
|
267
|
+
# This ensures each method only gets the parameters it actually needs
|
|
268
|
+
if not args_schema:
|
|
269
|
+
args_schema = None # Let ToolkitTool generate it from the method signature
|
|
270
|
+
|
|
271
|
+
# Create the tool
|
|
272
|
+
tool = ToolkitTool(
|
|
273
|
+
name=name,
|
|
274
|
+
bound_method=bound_method,
|
|
275
|
+
description=description,
|
|
276
|
+
args_schema=args_schema,
|
|
277
|
+
return_direct=self.return_direct
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
return tool
|
|
281
|
+
|
|
282
|
+
def get_toolkit_info(self) -> Dict[str, Any]:
|
|
283
|
+
"""
|
|
284
|
+
Get information about this toolkit.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Dictionary with toolkit information
|
|
288
|
+
"""
|
|
289
|
+
tools = self.get_tools()
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
"toolkit_name": self.__class__.__name__,
|
|
293
|
+
"tool_count": len(tools),
|
|
294
|
+
"tool_names": [tool.name for tool in tools],
|
|
295
|
+
"tool_descriptions": {tool.name: tool.description for tool in tools},
|
|
296
|
+
"return_direct": self.return_direct,
|
|
297
|
+
"base_url": self.base_url
|
|
298
|
+
}
|