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
|
File without changes
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
from typing import List, Dict, Any, Tuple, Optional
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import re
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ChunkInfo:
|
|
9
|
+
"""Information about a document chunk"""
|
|
10
|
+
chunk_id: str
|
|
11
|
+
parent_document_id: str
|
|
12
|
+
chunk_index: int
|
|
13
|
+
chunk_text: str
|
|
14
|
+
start_position: int
|
|
15
|
+
end_position: int
|
|
16
|
+
chunk_embedding: np.ndarray
|
|
17
|
+
metadata: Dict[str, Any]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LateChunkingProcessor:
|
|
21
|
+
"""
|
|
22
|
+
Late Chunking processor integrated with PgVectorStore.
|
|
23
|
+
|
|
24
|
+
Late chunking generates embeddings for the full document first, then creates
|
|
25
|
+
contextually-aware chunk embeddings that preserve the global document context.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
vector_store,
|
|
31
|
+
chunk_size: int = 8192,
|
|
32
|
+
chunk_overlap: int = 200,
|
|
33
|
+
preserve_sentences: bool = True,
|
|
34
|
+
min_chunk_size: int = 100
|
|
35
|
+
):
|
|
36
|
+
self.vector_store = vector_store
|
|
37
|
+
self.chunk_size = chunk_size
|
|
38
|
+
self.chunk_overlap = chunk_overlap
|
|
39
|
+
self.preserve_sentences = preserve_sentences
|
|
40
|
+
self.min_chunk_size = min_chunk_size
|
|
41
|
+
|
|
42
|
+
async def process_document_late_chunking(
|
|
43
|
+
self,
|
|
44
|
+
document_text: str,
|
|
45
|
+
document_id: str,
|
|
46
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
47
|
+
) -> Tuple[np.ndarray, List[ChunkInfo]]:
|
|
48
|
+
"""
|
|
49
|
+
Process document with late chunking strategy.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
document_text: Full document text
|
|
53
|
+
document_id: Unique document identifier
|
|
54
|
+
metadata: Optional metadata for the document
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Tuple of (full_document_embedding, list_of_chunk_info)
|
|
58
|
+
"""
|
|
59
|
+
# Step 1: Generate full-document embedding for global context
|
|
60
|
+
full_embedding = self.vector_store._embed_.embed_query(document_text)
|
|
61
|
+
|
|
62
|
+
# Step 2: Split into semantic chunks
|
|
63
|
+
chunks = self._semantic_chunk_split(document_text)
|
|
64
|
+
|
|
65
|
+
# Step 3: Generate contextual embeddings for each chunk
|
|
66
|
+
chunk_infos = []
|
|
67
|
+
|
|
68
|
+
for chunk_idx, (chunk_text, start_pos, end_pos) in enumerate(chunks):
|
|
69
|
+
# Create contextual prompt that includes document context
|
|
70
|
+
contextual_text = self._create_contextual_text(
|
|
71
|
+
document_text, chunk_text, start_pos, end_pos
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Generate embedding with context
|
|
75
|
+
chunk_embedding = self.vector_store._embed_.embed_query(contextual_text)
|
|
76
|
+
|
|
77
|
+
# Create chunk ID
|
|
78
|
+
chunk_id = f"{document_id}_chunk_{chunk_idx:04d}"
|
|
79
|
+
|
|
80
|
+
# Prepare chunk metadata
|
|
81
|
+
chunk_metadata = {
|
|
82
|
+
**(metadata or {}),
|
|
83
|
+
'parent_document_id': document_id,
|
|
84
|
+
'chunk_index': chunk_idx,
|
|
85
|
+
'total_chunks': len(chunks),
|
|
86
|
+
'start_position': start_pos,
|
|
87
|
+
'end_position': end_pos,
|
|
88
|
+
'chunk_size': len(chunk_text),
|
|
89
|
+
'is_chunk': True,
|
|
90
|
+
'chunk_type': 'late_chunking',
|
|
91
|
+
'context_preserved': True
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
chunk_info = ChunkInfo(
|
|
95
|
+
chunk_id=chunk_id,
|
|
96
|
+
parent_document_id=document_id,
|
|
97
|
+
chunk_index=chunk_idx,
|
|
98
|
+
chunk_text=chunk_text,
|
|
99
|
+
start_position=start_pos,
|
|
100
|
+
end_position=end_pos,
|
|
101
|
+
chunk_embedding=chunk_embedding,
|
|
102
|
+
metadata=chunk_metadata
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
chunk_infos.append(chunk_info)
|
|
106
|
+
|
|
107
|
+
return np.array(full_embedding), chunk_infos
|
|
108
|
+
|
|
109
|
+
def _semantic_chunk_split(self, text: str) -> List[Tuple[str, int, int]]:
|
|
110
|
+
"""
|
|
111
|
+
Split text preserving semantic boundaries.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of (chunk_text, start_position, end_position) tuples
|
|
115
|
+
"""
|
|
116
|
+
if self.preserve_sentences:
|
|
117
|
+
return self._sentence_aware_chunking(text)
|
|
118
|
+
else:
|
|
119
|
+
return self._simple_chunking(text)
|
|
120
|
+
|
|
121
|
+
def _sentence_aware_chunking(self, text: str) -> List[Tuple[str, int, int]]:
|
|
122
|
+
"""Split text while preserving sentence boundaries."""
|
|
123
|
+
# Split by sentences (basic approach - could use spaCy for better results)
|
|
124
|
+
sentence_endings = re.finditer(r'[.!?]+\s+', text)
|
|
125
|
+
sentence_positions = [0] + [m.end() for m in sentence_endings] + [len(text)]
|
|
126
|
+
|
|
127
|
+
chunks = []
|
|
128
|
+
current_start = 0
|
|
129
|
+
|
|
130
|
+
for i in range(1, len(sentence_positions)):
|
|
131
|
+
current_end = sentence_positions[i]
|
|
132
|
+
current_size = current_end - current_start
|
|
133
|
+
|
|
134
|
+
# If current chunk is too large, create chunk at previous boundary
|
|
135
|
+
if current_size > self.chunk_size and len(chunks) > 0:
|
|
136
|
+
# Find the last good break point
|
|
137
|
+
prev_end = sentence_positions[i-1]
|
|
138
|
+
if prev_end - current_start >= self.min_chunk_size:
|
|
139
|
+
chunk_text = text[current_start:prev_end].strip()
|
|
140
|
+
chunks.append((chunk_text, current_start, prev_end))
|
|
141
|
+
|
|
142
|
+
# Start new chunk with overlap
|
|
143
|
+
overlap_start = max(current_start, prev_end - self.chunk_overlap)
|
|
144
|
+
current_start = overlap_start
|
|
145
|
+
|
|
146
|
+
# If we're at the end, add final chunk
|
|
147
|
+
if i == len(sentence_positions) - 1:
|
|
148
|
+
chunk_text = text[current_start:current_end].strip()
|
|
149
|
+
if len(chunk_text) >= self.min_chunk_size:
|
|
150
|
+
chunks.append((chunk_text, current_start, current_end))
|
|
151
|
+
|
|
152
|
+
return chunks if chunks else [(text, 0, len(text))]
|
|
153
|
+
|
|
154
|
+
def _simple_chunking(self, text: str) -> List[Tuple[str, int, int]]:
|
|
155
|
+
"""Simple character-based chunking with overlap."""
|
|
156
|
+
chunks = []
|
|
157
|
+
start = 0
|
|
158
|
+
|
|
159
|
+
while start < len(text):
|
|
160
|
+
end = min(start + self.chunk_size, len(text))
|
|
161
|
+
chunk_text = text[start:end].strip()
|
|
162
|
+
|
|
163
|
+
if len(chunk_text) >= self.min_chunk_size:
|
|
164
|
+
chunks.append((chunk_text, start, end))
|
|
165
|
+
|
|
166
|
+
# Move start position with overlap
|
|
167
|
+
start += self.chunk_size - self.chunk_overlap
|
|
168
|
+
|
|
169
|
+
if end == len(text):
|
|
170
|
+
break
|
|
171
|
+
|
|
172
|
+
return chunks
|
|
173
|
+
|
|
174
|
+
def _create_contextual_text(
|
|
175
|
+
self,
|
|
176
|
+
full_text: str,
|
|
177
|
+
chunk_text: str,
|
|
178
|
+
start_pos: int,
|
|
179
|
+
end_pos: int
|
|
180
|
+
) -> str:
|
|
181
|
+
"""
|
|
182
|
+
Create contextual text that includes surrounding context for better embeddings.
|
|
183
|
+
"""
|
|
184
|
+
# Get surrounding context (e.g., 200 chars before and after)
|
|
185
|
+
context_window = 200
|
|
186
|
+
|
|
187
|
+
context_start = max(0, start_pos - context_window)
|
|
188
|
+
context_end = min(len(full_text), end_pos + context_window)
|
|
189
|
+
|
|
190
|
+
# Extract context
|
|
191
|
+
before_context = full_text[context_start:start_pos] if context_start < start_pos else ""
|
|
192
|
+
after_context = full_text[end_pos:context_end] if end_pos < context_end else ""
|
|
193
|
+
|
|
194
|
+
# Create contextual text with clear boundaries
|
|
195
|
+
contextual_text = f"{before_context.strip()} [FOCUS] {chunk_text} [/FOCUS] {after_context.strip()}" # noqa
|
|
196
|
+
|
|
197
|
+
return contextual_text.strip()
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# parrot/telemetry/__init__.py
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
import time
|
|
5
|
+
import openlit
|
|
6
|
+
from opentelemetry import trace, metrics
|
|
7
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
8
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TelemetryMixin:
|
|
12
|
+
"""Mixin to add observability to LLM clients"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, *args, **kwargs):
|
|
15
|
+
super().__init__(*args, **kwargs)
|
|
16
|
+
self._telemetry_enabled = kwargs.get('enable_telemetry', True)
|
|
17
|
+
|
|
18
|
+
if self._telemetry_enabled:
|
|
19
|
+
# Get tracer and meter for this client
|
|
20
|
+
self.tracer = trace.get_tracer(f"parrot.client.{self.client_name}")
|
|
21
|
+
self.meter = metrics.get_meter(f"parrot.client.{self.client_name}")
|
|
22
|
+
|
|
23
|
+
# Create metrics
|
|
24
|
+
self.request_counter = self.meter.create_counter(
|
|
25
|
+
name="llm.requests",
|
|
26
|
+
description="Total LLM requests",
|
|
27
|
+
unit="1"
|
|
28
|
+
)
|
|
29
|
+
self.token_counter = self.meter.create_counter(
|
|
30
|
+
name="llm.tokens",
|
|
31
|
+
description="Total tokens used",
|
|
32
|
+
unit="1"
|
|
33
|
+
)
|
|
34
|
+
self.latency_histogram = self.meter.create_histogram(
|
|
35
|
+
name="llm.request.duration",
|
|
36
|
+
description="LLM request duration",
|
|
37
|
+
unit="ms"
|
|
38
|
+
)
|
|
39
|
+
self.error_counter = self.meter.create_counter(
|
|
40
|
+
name="llm.errors",
|
|
41
|
+
description="LLM errors",
|
|
42
|
+
unit="1"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@contextmanager
|
|
46
|
+
def track_request(self, operation: str, **attributes):
|
|
47
|
+
"""Context manager for tracking LLM requests"""
|
|
48
|
+
if not self._telemetry_enabled:
|
|
49
|
+
yield {}
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
start_time = time.time()
|
|
53
|
+
span_attributes = {
|
|
54
|
+
"llm.provider": self.client_name,
|
|
55
|
+
"llm.operation": operation,
|
|
56
|
+
**attributes
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
with self.tracer.start_as_current_span(
|
|
60
|
+
f"{self.client_name}.{operation}",
|
|
61
|
+
attributes=span_attributes
|
|
62
|
+
) as span:
|
|
63
|
+
metrics = {
|
|
64
|
+
"start_time": start_time,
|
|
65
|
+
"span": span
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
yield metrics
|
|
70
|
+
# Success tracking
|
|
71
|
+
self.request_counter.add(1, {
|
|
72
|
+
"provider": self.client_name,
|
|
73
|
+
"operation": operation,
|
|
74
|
+
"status": "success"
|
|
75
|
+
})
|
|
76
|
+
except Exception as e:
|
|
77
|
+
# Error tracking
|
|
78
|
+
self.error_counter.add(1, {
|
|
79
|
+
"provider": self.client_name,
|
|
80
|
+
"operation": operation,
|
|
81
|
+
"error_type": type(e).__name__
|
|
82
|
+
})
|
|
83
|
+
span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
|
|
84
|
+
span.record_exception(e)
|
|
85
|
+
raise
|
|
86
|
+
finally:
|
|
87
|
+
# Always track latency
|
|
88
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
89
|
+
self.latency_histogram.record(duration_ms, {
|
|
90
|
+
"provider": self.client_name,
|
|
91
|
+
"operation": operation
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
def track_tokens(self, usage: Dict[str, int], model: str):
|
|
95
|
+
"""Track token usage"""
|
|
96
|
+
if not self._telemetry_enabled:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if "input_tokens" in usage:
|
|
100
|
+
self.token_counter.add(usage["input_tokens"], {
|
|
101
|
+
"provider": self.client_name,
|
|
102
|
+
"model": model,
|
|
103
|
+
"token_type": "input"
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
if "output_tokens" in usage:
|
|
107
|
+
self.token_counter.add(usage["output_tokens"], {
|
|
108
|
+
"provider": self.client_name,
|
|
109
|
+
"model": model,
|
|
110
|
+
"token_type": "output"
|
|
111
|
+
})
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Union
|
|
6
|
+
import datetime
|
|
7
|
+
from navconfig.logging import logging
|
|
8
|
+
|
|
9
|
+
from jinja2 import (
|
|
10
|
+
BaseLoader,
|
|
11
|
+
ChoiceLoader,
|
|
12
|
+
DictLoader,
|
|
13
|
+
Environment,
|
|
14
|
+
FileSystemBytecodeCache,
|
|
15
|
+
FileSystemLoader,
|
|
16
|
+
TemplateError,
|
|
17
|
+
TemplateNotFound,
|
|
18
|
+
StrictUndefined,
|
|
19
|
+
select_autoescape,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
PathLike = Union[str, Path]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class JinjaConfig:
|
|
27
|
+
"""Configuration for the async Jinja2 Environment."""
|
|
28
|
+
template_dirs: list[Path] = field(default_factory=list)
|
|
29
|
+
extensions: list[str] = field(default_factory=lambda: [
|
|
30
|
+
"jinja2.ext.i18n",
|
|
31
|
+
"jinja2.ext.loopcontrols",
|
|
32
|
+
"jinja2_time.TimeExtension",
|
|
33
|
+
"jinja2_iso8601.ISO8601Extension",
|
|
34
|
+
"jinja2.ext.do",
|
|
35
|
+
"jinja2_humanize_extension.HumanizeExtension",
|
|
36
|
+
# "jinja2.ext.debug", # enable in dev if desired
|
|
37
|
+
])
|
|
38
|
+
bytecode_cache_dir: Optional[Path] = None
|
|
39
|
+
bytecode_cache_pattern: str = "%s.cache"
|
|
40
|
+
autoescape: Any = select_autoescape(["html", "xml", "j2", "jinja", "jinja2"])
|
|
41
|
+
undefined: Any = StrictUndefined # raise on missing variables
|
|
42
|
+
keep_trailing_newline: bool = True
|
|
43
|
+
trim_blocks: bool = True
|
|
44
|
+
lstrip_blocks: bool = True
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TemplateEngine:
|
|
48
|
+
"""
|
|
49
|
+
Async-only Jinja2 template engine with:
|
|
50
|
+
- multiple directories
|
|
51
|
+
- in-memory templates
|
|
52
|
+
- pluggable extensions/filters/globals
|
|
53
|
+
- optional bytecode cache
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
template_dirs: Optional[Union[PathLike, Sequence[PathLike]]] = None,
|
|
59
|
+
*,
|
|
60
|
+
extensions: Optional[Sequence[str]] = None,
|
|
61
|
+
bytecode_cache_dir: Optional[PathLike] = None,
|
|
62
|
+
filters: Optional[Mapping[str, Any]] = None,
|
|
63
|
+
globals_: Optional[Mapping[str, Any]] = None,
|
|
64
|
+
config: Optional[JinjaConfig] = None,
|
|
65
|
+
debug: bool = False,
|
|
66
|
+
) -> None:
|
|
67
|
+
cfg = config or JinjaConfig()
|
|
68
|
+
self.logger = logging.getLogger(__name__)
|
|
69
|
+
|
|
70
|
+
# Normalize directories
|
|
71
|
+
if template_dirs is not None:
|
|
72
|
+
if isinstance(template_dirs, (str, Path)):
|
|
73
|
+
cfg.template_dirs.append(Path(template_dirs).resolve())
|
|
74
|
+
else:
|
|
75
|
+
cfg.template_dirs.extend(Path(p).resolve() for p in template_dirs)
|
|
76
|
+
|
|
77
|
+
# Validate & store directories
|
|
78
|
+
self._fs_dirs: list[Path] = []
|
|
79
|
+
for d in cfg.template_dirs:
|
|
80
|
+
if not d.exists():
|
|
81
|
+
raise ValueError(f"Template directory not found: {d}")
|
|
82
|
+
if not d.is_dir():
|
|
83
|
+
raise ValueError(f"Template path is not a directory: {d}")
|
|
84
|
+
self._fs_dirs.append(d)
|
|
85
|
+
|
|
86
|
+
# Extensions
|
|
87
|
+
self._configure_extensions(cfg, extensions, debug)
|
|
88
|
+
|
|
89
|
+
# Optional bytecode cache
|
|
90
|
+
self._bytecode_cache = None
|
|
91
|
+
if bytecode_cache_dir is not None:
|
|
92
|
+
bdir = Path(bytecode_cache_dir).resolve()
|
|
93
|
+
bdir.mkdir(parents=True, exist_ok=True)
|
|
94
|
+
self._bytecode_cache = FileSystemBytecodeCache(str(bdir), cfg.bytecode_cache_pattern)
|
|
95
|
+
elif cfg.bytecode_cache_dir:
|
|
96
|
+
bdir = Path(cfg.bytecode_cache_dir).resolve()
|
|
97
|
+
bdir.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
self._bytecode_cache = FileSystemBytecodeCache(str(bdir), cfg.bytecode_cache_pattern)
|
|
99
|
+
|
|
100
|
+
# Loaders: FileSystem + (optional) in-memory DictLoader
|
|
101
|
+
self._dict_loader = DictLoader({})
|
|
102
|
+
fs_loader = FileSystemLoader([str(p) for p in self._fs_dirs]) if self._fs_dirs else None
|
|
103
|
+
|
|
104
|
+
if fs_loader:
|
|
105
|
+
loader: BaseLoader = ChoiceLoader([self._dict_loader, fs_loader])
|
|
106
|
+
else:
|
|
107
|
+
loader = self._dict_loader # still works with only in-memory templates
|
|
108
|
+
|
|
109
|
+
# Build the environment (async-only)
|
|
110
|
+
self.env = Environment(
|
|
111
|
+
loader=loader,
|
|
112
|
+
enable_async=True,
|
|
113
|
+
extensions=self._extensions,
|
|
114
|
+
bytecode_cache=self._bytecode_cache,
|
|
115
|
+
autoescape=cfg.autoescape,
|
|
116
|
+
undefined=cfg.undefined,
|
|
117
|
+
keep_trailing_newline=cfg.keep_trailing_newline,
|
|
118
|
+
trim_blocks=cfg.trim_blocks,
|
|
119
|
+
lstrip_blocks=cfg.lstrip_blocks,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Useful default filters/globals
|
|
123
|
+
self.env.filters.setdefault("datetime", datetime.datetime.fromtimestamp)
|
|
124
|
+
# Add user-supplied
|
|
125
|
+
if filters:
|
|
126
|
+
for name, fn in filters.items():
|
|
127
|
+
self.env.filters[name] = fn
|
|
128
|
+
if globals_:
|
|
129
|
+
for name, val in globals_.items():
|
|
130
|
+
self.env.globals[name] = val
|
|
131
|
+
|
|
132
|
+
self.logger.debug(
|
|
133
|
+
"AsyncTemplateEngine initialized: dirs=%s, extensions=%s, bytecode_cache=%s",
|
|
134
|
+
[str(d) for d in self._fs_dirs],
|
|
135
|
+
self._extensions,
|
|
136
|
+
bool(self._bytecode_cache),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def _configure_extensions(self, cfg: JinjaConfig, extensions: Optional[Sequence[str]], debug: bool) -> None:
|
|
140
|
+
"""Configure Jinja2 extensions."""
|
|
141
|
+
# Merge extensions
|
|
142
|
+
self._extensions: list[str] = list(cfg.extensions)
|
|
143
|
+
if extensions:
|
|
144
|
+
for ext in extensions:
|
|
145
|
+
if ext not in self._extensions:
|
|
146
|
+
self._extensions.append(ext)
|
|
147
|
+
if debug and "jinja2.ext.debug" not in self._extensions:
|
|
148
|
+
self._extensions.append("jinja2.ext.debug")
|
|
149
|
+
|
|
150
|
+
# -------- Public API
|
|
151
|
+
def add_template_dir(self, path: PathLike) -> None:
|
|
152
|
+
"""Add a new filesystem directory to the search path at runtime."""
|
|
153
|
+
p = Path(path).resolve()
|
|
154
|
+
if not p.exists() or not p.is_dir():
|
|
155
|
+
raise ValueError(f"Template directory invalid: {p}")
|
|
156
|
+
self._fs_dirs.append(p)
|
|
157
|
+
|
|
158
|
+
# Rebuild loader chain (ChoiceLoader is immutable in practice)
|
|
159
|
+
current_dicts = self._dict_loader.mapping
|
|
160
|
+
self._dict_loader = DictLoader(current_dicts)
|
|
161
|
+
fs_loader = FileSystemLoader([str(d) for d in self._fs_dirs])
|
|
162
|
+
self.env.loader = ChoiceLoader([self._dict_loader, fs_loader])
|
|
163
|
+
|
|
164
|
+
def add_templates(self, templates: Mapping[str, str]) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Add/override in-memory templates.
|
|
167
|
+
Example: add_templates({'layout.html': '<html>{{ self.block() }}</html>'})
|
|
168
|
+
"""
|
|
169
|
+
for name, content in templates.items():
|
|
170
|
+
self._dict_loader.mapping[name] = content
|
|
171
|
+
|
|
172
|
+
def get_template(self, name: str):
|
|
173
|
+
"""Get a compiled template by name (raises FileNotFoundError on miss)."""
|
|
174
|
+
try:
|
|
175
|
+
return self.env.get_template(name)
|
|
176
|
+
except TemplateNotFound as ex:
|
|
177
|
+
raise FileNotFoundError(f"Template not found: {name}") from ex
|
|
178
|
+
except Exception as ex:
|
|
179
|
+
raise RuntimeError(f"Error loading template '{name}': {ex}") from ex
|
|
180
|
+
|
|
181
|
+
async def render(self, name: str, params: Optional[Mapping[str, Any]] = None) -> str:
|
|
182
|
+
"""
|
|
183
|
+
Async render of a template by name.
|
|
184
|
+
Only async path is supported (no sync render).
|
|
185
|
+
"""
|
|
186
|
+
params = dict(params or {})
|
|
187
|
+
try:
|
|
188
|
+
tmpl = self.get_template(name)
|
|
189
|
+
# MUST use render_async because enable_async=True
|
|
190
|
+
return await tmpl.render_async(**params)
|
|
191
|
+
except TemplateError as ex:
|
|
192
|
+
raise ValueError(f"Template error while rendering '{name}': {ex}") from ex
|
|
193
|
+
except Exception as ex:
|
|
194
|
+
raise RuntimeError(f"Unexpected error rendering '{name}': {ex}") from ex
|
|
195
|
+
|
|
196
|
+
async def render_string(self, source: str, params: Optional[Mapping[str, Any]] = None) -> str:
|
|
197
|
+
"""
|
|
198
|
+
Async render from a string (compiled via the current environment).
|
|
199
|
+
Useful for ad-hoc/injected content.
|
|
200
|
+
"""
|
|
201
|
+
params = dict(params or {})
|
|
202
|
+
try:
|
|
203
|
+
tmpl = self.env.from_string(source)
|
|
204
|
+
return await tmpl.render_async(**params)
|
|
205
|
+
except TemplateError as ex:
|
|
206
|
+
raise ValueError(f"Template error while rendering string: {ex}") from ex
|
|
207
|
+
except Exception as ex:
|
|
208
|
+
raise RuntimeError(f"Unexpected error rendering string: {ex}") from ex
|
|
209
|
+
|
|
210
|
+
def add_filters(self, filters: Mapping[str, Any]) -> None:
|
|
211
|
+
"""Register additional filters (supports async filters too)."""
|
|
212
|
+
for name, fn in filters.items():
|
|
213
|
+
self.env.filters[name] = fn
|
|
214
|
+
|
|
215
|
+
def add_globals(self, globals_: Mapping[str, Any]) -> None:
|
|
216
|
+
"""Register additional global variables/functions."""
|
|
217
|
+
for name, val in globals_.items():
|
|
218
|
+
self.env.globals[name] = val
|
|
219
|
+
|
|
220
|
+
def compile_directory(self, target: PathLike, *, zip: Optional[str] = "deflated") -> None:
|
|
221
|
+
"""
|
|
222
|
+
Optionally precompile all templates from filesystem loaders into `target`.
|
|
223
|
+
Skips silently if there are no filesystem directories.
|
|
224
|
+
"""
|
|
225
|
+
if not self._fs_dirs:
|
|
226
|
+
return
|
|
227
|
+
target_path = Path(target).resolve()
|
|
228
|
+
target_path.mkdir(parents=True, exist_ok=True)
|
|
229
|
+
try:
|
|
230
|
+
self.env.compile_templates(
|
|
231
|
+
target=str(target_path),
|
|
232
|
+
zip=zip
|
|
233
|
+
)
|
|
234
|
+
except Exception as ex:
|
|
235
|
+
# If a transient decode error happens, try once again without failing the app
|
|
236
|
+
self.logger.warning(
|
|
237
|
+
f"Compile templates failed once: {ex}; retrying…"
|
|
238
|
+
)
|
|
239
|
+
self.env.compile_templates(
|
|
240
|
+
target=str(target_path),
|
|
241
|
+
zip=zip
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ------------------------------
|
|
246
|
+
# Minimal usage example (async)
|
|
247
|
+
# ------------------------------
|
|
248
|
+
# engine = TemplateEngine(
|
|
249
|
+
# template_dirs=["/path/to/templates", "/path/to/partials"],
|
|
250
|
+
# extensions=["jinja2.ext.debug"], # optional
|
|
251
|
+
# bytecode_cache_dir="/tmp/jinja-cache", # optional
|
|
252
|
+
# filters={"jsonify": json_encoder}, # e.g. your custom filter
|
|
253
|
+
# globals_={"app_name": "QuerySource"}, # optional
|
|
254
|
+
# )
|
|
255
|
+
#
|
|
256
|
+
# engine.add_templates({"inline.html": "Hello {{ name }}!"})
|
|
257
|
+
#
|
|
258
|
+
# html = await engine.render("index.html", {"user": "Pilar"})
|
|
259
|
+
# text = await engine.render_string("Hi {{ who }}", {"who": "there"})
|
parrot/tools/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools infrastructure for building Agents.
|
|
3
|
+
"""
|
|
4
|
+
from parrot.plugins import setup_plugin_importer, dynamic_import_helper
|
|
5
|
+
from .abstract import AbstractTool, ToolResult
|
|
6
|
+
from .toolkit import AbstractToolkit, ToolkitTool
|
|
7
|
+
from .decorators import tool_schema, tool
|
|
8
|
+
|
|
9
|
+
setup_plugin_importer('parrot.tools', 'tools')
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"AbstractTool",
|
|
13
|
+
"ToolResult",
|
|
14
|
+
"AbstractToolkit",
|
|
15
|
+
"ToolkitTool",
|
|
16
|
+
"tool_schema",
|
|
17
|
+
"tool",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Enable dynamic imports
|
|
21
|
+
def __getattr__(name):
|
|
22
|
+
return dynamic_import_helper(__name__, name)
|
|
23
|
+
|