ai-parrot 0.17.2__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentui/.prettierrc +15 -0
- agentui/QUICKSTART.md +272 -0
- agentui/README.md +59 -0
- agentui/env.example +16 -0
- agentui/jsconfig.json +14 -0
- agentui/package-lock.json +4242 -0
- agentui/package.json +34 -0
- agentui/scripts/postinstall/apply-patches.mjs +260 -0
- agentui/src/app.css +61 -0
- agentui/src/app.d.ts +13 -0
- agentui/src/app.html +12 -0
- agentui/src/components/LoadingSpinner.svelte +64 -0
- agentui/src/components/ThemeSwitcher.svelte +159 -0
- agentui/src/components/index.js +4 -0
- agentui/src/lib/api/bots.ts +60 -0
- agentui/src/lib/api/chat.ts +22 -0
- agentui/src/lib/api/http.ts +25 -0
- agentui/src/lib/components/BotCard.svelte +33 -0
- agentui/src/lib/components/ChatBubble.svelte +63 -0
- agentui/src/lib/components/Toast.svelte +21 -0
- agentui/src/lib/config.ts +20 -0
- agentui/src/lib/stores/auth.svelte.ts +73 -0
- agentui/src/lib/stores/theme.svelte.js +64 -0
- agentui/src/lib/stores/toast.svelte.ts +31 -0
- agentui/src/lib/utils/conversation.ts +39 -0
- agentui/src/routes/+layout.svelte +20 -0
- agentui/src/routes/+page.svelte +232 -0
- agentui/src/routes/login/+page.svelte +200 -0
- agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
- agentui/src/routes/talk/[agentId]/+page.ts +7 -0
- agentui/static/README.md +1 -0
- agentui/svelte.config.js +11 -0
- agentui/tailwind.config.ts +53 -0
- agentui/tsconfig.json +3 -0
- agentui/vite.config.ts +10 -0
- ai_parrot-0.17.2.dist-info/METADATA +472 -0
- ai_parrot-0.17.2.dist-info/RECORD +535 -0
- ai_parrot-0.17.2.dist-info/WHEEL +6 -0
- ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
- ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
- ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
- crew-builder/.prettierrc +15 -0
- crew-builder/QUICKSTART.md +259 -0
- crew-builder/README.md +113 -0
- crew-builder/env.example +17 -0
- crew-builder/jsconfig.json +14 -0
- crew-builder/package-lock.json +4182 -0
- crew-builder/package.json +37 -0
- crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
- crew-builder/src/app.css +62 -0
- crew-builder/src/app.d.ts +13 -0
- crew-builder/src/app.html +12 -0
- crew-builder/src/components/LoadingSpinner.svelte +64 -0
- crew-builder/src/components/ThemeSwitcher.svelte +149 -0
- crew-builder/src/components/index.js +9 -0
- crew-builder/src/lib/api/bots.ts +60 -0
- crew-builder/src/lib/api/chat.ts +80 -0
- crew-builder/src/lib/api/client.ts +56 -0
- crew-builder/src/lib/api/crew/crew.ts +136 -0
- crew-builder/src/lib/api/index.ts +5 -0
- crew-builder/src/lib/api/o365/auth.ts +65 -0
- crew-builder/src/lib/auth/auth.ts +54 -0
- crew-builder/src/lib/components/AgentNode.svelte +43 -0
- crew-builder/src/lib/components/BotCard.svelte +33 -0
- crew-builder/src/lib/components/ChatBubble.svelte +67 -0
- crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
- crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
- crew-builder/src/lib/components/JsonViewer.svelte +24 -0
- crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
- crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
- crew-builder/src/lib/components/Toast.svelte +67 -0
- crew-builder/src/lib/components/Toolbar.svelte +157 -0
- crew-builder/src/lib/components/index.ts +10 -0
- crew-builder/src/lib/config.ts +8 -0
- crew-builder/src/lib/stores/auth.svelte.ts +228 -0
- crew-builder/src/lib/stores/crewStore.ts +369 -0
- crew-builder/src/lib/stores/theme.svelte.js +145 -0
- crew-builder/src/lib/stores/toast.svelte.ts +69 -0
- crew-builder/src/lib/utils/conversation.ts +39 -0
- crew-builder/src/lib/utils/markdown.ts +122 -0
- crew-builder/src/lib/utils/talkHistory.ts +47 -0
- crew-builder/src/routes/+layout.svelte +20 -0
- crew-builder/src/routes/+page.svelte +539 -0
- crew-builder/src/routes/agents/+page.svelte +247 -0
- crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
- crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
- crew-builder/src/routes/builder/+page.svelte +204 -0
- crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
- crew-builder/src/routes/crew/ask/+page.ts +1 -0
- crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
- crew-builder/src/routes/login/+page.svelte +197 -0
- crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
- crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
- crew-builder/static/README.md +1 -0
- crew-builder/svelte.config.js +11 -0
- crew-builder/tailwind.config.ts +53 -0
- crew-builder/tsconfig.json +3 -0
- crew-builder/vite.config.ts +10 -0
- mcp_servers/calculator_server.py +309 -0
- parrot/__init__.py +27 -0
- parrot/__pycache__/__init__.cpython-310.pyc +0 -0
- parrot/__pycache__/version.cpython-310.pyc +0 -0
- parrot/_version.py +34 -0
- parrot/a2a/__init__.py +48 -0
- parrot/a2a/client.py +658 -0
- parrot/a2a/discovery.py +89 -0
- parrot/a2a/mixin.py +257 -0
- parrot/a2a/models.py +376 -0
- parrot/a2a/server.py +770 -0
- parrot/agents/__init__.py +29 -0
- parrot/bots/__init__.py +12 -0
- parrot/bots/a2a_agent.py +19 -0
- parrot/bots/abstract.py +3139 -0
- parrot/bots/agent.py +1129 -0
- parrot/bots/basic.py +9 -0
- parrot/bots/chatbot.py +669 -0
- parrot/bots/data.py +1618 -0
- parrot/bots/database/__init__.py +5 -0
- parrot/bots/database/abstract.py +3071 -0
- parrot/bots/database/cache.py +286 -0
- parrot/bots/database/models.py +468 -0
- parrot/bots/database/prompts.py +154 -0
- parrot/bots/database/retries.py +98 -0
- parrot/bots/database/router.py +269 -0
- parrot/bots/database/sql.py +41 -0
- parrot/bots/db/__init__.py +6 -0
- parrot/bots/db/abstract.py +556 -0
- parrot/bots/db/bigquery.py +602 -0
- parrot/bots/db/cache.py +85 -0
- parrot/bots/db/documentdb.py +668 -0
- parrot/bots/db/elastic.py +1014 -0
- parrot/bots/db/influx.py +898 -0
- parrot/bots/db/mock.py +96 -0
- parrot/bots/db/multi.py +783 -0
- parrot/bots/db/prompts.py +185 -0
- parrot/bots/db/sql.py +1255 -0
- parrot/bots/db/tools.py +212 -0
- parrot/bots/document.py +680 -0
- parrot/bots/hrbot.py +15 -0
- parrot/bots/kb.py +170 -0
- parrot/bots/mcp.py +36 -0
- parrot/bots/orchestration/README.md +463 -0
- parrot/bots/orchestration/__init__.py +1 -0
- parrot/bots/orchestration/agent.py +155 -0
- parrot/bots/orchestration/crew.py +3330 -0
- parrot/bots/orchestration/fsm.py +1179 -0
- parrot/bots/orchestration/hr.py +434 -0
- parrot/bots/orchestration/storage/__init__.py +4 -0
- parrot/bots/orchestration/storage/memory.py +100 -0
- parrot/bots/orchestration/storage/mixin.py +119 -0
- parrot/bots/orchestration/verify.py +202 -0
- parrot/bots/product.py +204 -0
- parrot/bots/prompts/__init__.py +96 -0
- parrot/bots/prompts/agents.py +155 -0
- parrot/bots/prompts/data.py +216 -0
- parrot/bots/prompts/output_generation.py +8 -0
- parrot/bots/scraper/__init__.py +3 -0
- parrot/bots/scraper/models.py +122 -0
- parrot/bots/scraper/scraper.py +1173 -0
- parrot/bots/scraper/templates.py +115 -0
- parrot/bots/stores/__init__.py +5 -0
- parrot/bots/stores/local.py +172 -0
- parrot/bots/webdev.py +81 -0
- parrot/cli.py +17 -0
- parrot/clients/__init__.py +16 -0
- parrot/clients/base.py +1491 -0
- parrot/clients/claude.py +1191 -0
- parrot/clients/factory.py +129 -0
- parrot/clients/google.py +4567 -0
- parrot/clients/gpt.py +1975 -0
- parrot/clients/grok.py +432 -0
- parrot/clients/groq.py +986 -0
- parrot/clients/hf.py +582 -0
- parrot/clients/models.py +18 -0
- parrot/conf.py +395 -0
- parrot/embeddings/__init__.py +9 -0
- parrot/embeddings/base.py +157 -0
- parrot/embeddings/google.py +98 -0
- parrot/embeddings/huggingface.py +74 -0
- parrot/embeddings/openai.py +84 -0
- parrot/embeddings/processor.py +88 -0
- parrot/exceptions.c +13868 -0
- parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/exceptions.pxd +22 -0
- parrot/exceptions.pxi +15 -0
- parrot/exceptions.pyx +44 -0
- parrot/generators/__init__.py +29 -0
- parrot/generators/base.py +200 -0
- parrot/generators/html.py +293 -0
- parrot/generators/react.py +205 -0
- parrot/generators/streamlit.py +203 -0
- parrot/generators/template.py +105 -0
- parrot/handlers/__init__.py +4 -0
- parrot/handlers/agent.py +861 -0
- parrot/handlers/agents/__init__.py +1 -0
- parrot/handlers/agents/abstract.py +900 -0
- parrot/handlers/bots.py +338 -0
- parrot/handlers/chat.py +915 -0
- parrot/handlers/creation.sql +192 -0
- parrot/handlers/crew/ARCHITECTURE.md +362 -0
- parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
- parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
- parrot/handlers/crew/__init__.py +0 -0
- parrot/handlers/crew/handler.py +801 -0
- parrot/handlers/crew/models.py +229 -0
- parrot/handlers/crew/redis_persistence.py +523 -0
- parrot/handlers/jobs/__init__.py +10 -0
- parrot/handlers/jobs/job.py +384 -0
- parrot/handlers/jobs/mixin.py +627 -0
- parrot/handlers/jobs/models.py +115 -0
- parrot/handlers/jobs/worker.py +31 -0
- parrot/handlers/models.py +596 -0
- parrot/handlers/o365_auth.py +105 -0
- parrot/handlers/stream.py +337 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/aws.py +143 -0
- parrot/interfaces/credentials.py +113 -0
- parrot/interfaces/database.py +27 -0
- parrot/interfaces/google.py +1123 -0
- parrot/interfaces/hierarchy.py +1227 -0
- parrot/interfaces/http.py +651 -0
- parrot/interfaces/images/__init__.py +0 -0
- parrot/interfaces/images/plugins/__init__.py +24 -0
- parrot/interfaces/images/plugins/abstract.py +58 -0
- parrot/interfaces/images/plugins/analisys.py +148 -0
- parrot/interfaces/images/plugins/classify.py +150 -0
- parrot/interfaces/images/plugins/classifybase.py +182 -0
- parrot/interfaces/images/plugins/detect.py +150 -0
- parrot/interfaces/images/plugins/exif.py +1103 -0
- parrot/interfaces/images/plugins/hash.py +52 -0
- parrot/interfaces/images/plugins/vision.py +104 -0
- parrot/interfaces/images/plugins/yolo.py +66 -0
- parrot/interfaces/images/plugins/zerodetect.py +197 -0
- parrot/interfaces/o365.py +978 -0
- parrot/interfaces/onedrive.py +822 -0
- parrot/interfaces/sharepoint.py +1435 -0
- parrot/interfaces/soap.py +257 -0
- parrot/loaders/__init__.py +8 -0
- parrot/loaders/abstract.py +1131 -0
- parrot/loaders/audio.py +199 -0
- parrot/loaders/basepdf.py +53 -0
- parrot/loaders/basevideo.py +1568 -0
- parrot/loaders/csv.py +409 -0
- parrot/loaders/docx.py +116 -0
- parrot/loaders/epubloader.py +316 -0
- parrot/loaders/excel.py +199 -0
- parrot/loaders/factory.py +55 -0
- parrot/loaders/files/__init__.py +0 -0
- parrot/loaders/files/abstract.py +39 -0
- parrot/loaders/files/html.py +26 -0
- parrot/loaders/files/text.py +63 -0
- parrot/loaders/html.py +152 -0
- parrot/loaders/markdown.py +442 -0
- parrot/loaders/pdf.py +373 -0
- parrot/loaders/pdfmark.py +320 -0
- parrot/loaders/pdftables.py +506 -0
- parrot/loaders/ppt.py +476 -0
- parrot/loaders/qa.py +63 -0
- parrot/loaders/splitters/__init__.py +10 -0
- parrot/loaders/splitters/base.py +138 -0
- parrot/loaders/splitters/md.py +228 -0
- parrot/loaders/splitters/token.py +143 -0
- parrot/loaders/txt.py +26 -0
- parrot/loaders/video.py +89 -0
- parrot/loaders/videolocal.py +218 -0
- parrot/loaders/videounderstanding.py +377 -0
- parrot/loaders/vimeo.py +167 -0
- parrot/loaders/web.py +599 -0
- parrot/loaders/youtube.py +504 -0
- parrot/manager/__init__.py +5 -0
- parrot/manager/manager.py +1030 -0
- parrot/mcp/__init__.py +28 -0
- parrot/mcp/adapter.py +105 -0
- parrot/mcp/cli.py +174 -0
- parrot/mcp/client.py +119 -0
- parrot/mcp/config.py +75 -0
- parrot/mcp/integration.py +842 -0
- parrot/mcp/oauth.py +933 -0
- parrot/mcp/server.py +225 -0
- parrot/mcp/transports/__init__.py +3 -0
- parrot/mcp/transports/base.py +279 -0
- parrot/mcp/transports/grpc_session.py +163 -0
- parrot/mcp/transports/http.py +312 -0
- parrot/mcp/transports/mcp.proto +108 -0
- parrot/mcp/transports/quic.py +1082 -0
- parrot/mcp/transports/sse.py +330 -0
- parrot/mcp/transports/stdio.py +309 -0
- parrot/mcp/transports/unix.py +395 -0
- parrot/mcp/transports/websocket.py +547 -0
- parrot/memory/__init__.py +16 -0
- parrot/memory/abstract.py +209 -0
- parrot/memory/agent.py +32 -0
- parrot/memory/cache.py +175 -0
- parrot/memory/core.py +555 -0
- parrot/memory/file.py +153 -0
- parrot/memory/mem.py +131 -0
- parrot/memory/redis.py +613 -0
- parrot/models/__init__.py +46 -0
- parrot/models/basic.py +118 -0
- parrot/models/compliance.py +208 -0
- parrot/models/crew.py +395 -0
- parrot/models/detections.py +654 -0
- parrot/models/generation.py +85 -0
- parrot/models/google.py +223 -0
- parrot/models/groq.py +23 -0
- parrot/models/openai.py +30 -0
- parrot/models/outputs.py +285 -0
- parrot/models/responses.py +938 -0
- parrot/notifications/__init__.py +743 -0
- parrot/openapi/__init__.py +3 -0
- parrot/openapi/components.yaml +641 -0
- parrot/openapi/config.py +322 -0
- parrot/outputs/__init__.py +32 -0
- parrot/outputs/formats/__init__.py +108 -0
- parrot/outputs/formats/altair.py +359 -0
- parrot/outputs/formats/application.py +122 -0
- parrot/outputs/formats/base.py +351 -0
- parrot/outputs/formats/bokeh.py +356 -0
- parrot/outputs/formats/card.py +424 -0
- parrot/outputs/formats/chart.py +436 -0
- parrot/outputs/formats/d3.py +255 -0
- parrot/outputs/formats/echarts.py +310 -0
- parrot/outputs/formats/generators/__init__.py +0 -0
- parrot/outputs/formats/generators/abstract.py +61 -0
- parrot/outputs/formats/generators/panel.py +145 -0
- parrot/outputs/formats/generators/streamlit.py +86 -0
- parrot/outputs/formats/generators/terminal.py +63 -0
- parrot/outputs/formats/holoviews.py +310 -0
- parrot/outputs/formats/html.py +147 -0
- parrot/outputs/formats/jinja2.py +46 -0
- parrot/outputs/formats/json.py +87 -0
- parrot/outputs/formats/map.py +933 -0
- parrot/outputs/formats/markdown.py +172 -0
- parrot/outputs/formats/matplotlib.py +237 -0
- parrot/outputs/formats/mixins/__init__.py +0 -0
- parrot/outputs/formats/mixins/emaps.py +855 -0
- parrot/outputs/formats/plotly.py +341 -0
- parrot/outputs/formats/seaborn.py +310 -0
- parrot/outputs/formats/table.py +397 -0
- parrot/outputs/formats/template_report.py +138 -0
- parrot/outputs/formats/yaml.py +125 -0
- parrot/outputs/formatter.py +152 -0
- parrot/outputs/templates/__init__.py +95 -0
- parrot/pipelines/__init__.py +0 -0
- parrot/pipelines/abstract.py +210 -0
- parrot/pipelines/detector.py +124 -0
- parrot/pipelines/models.py +90 -0
- parrot/pipelines/planogram.py +3002 -0
- parrot/pipelines/table.sql +97 -0
- parrot/plugins/__init__.py +106 -0
- parrot/plugins/importer.py +80 -0
- parrot/py.typed +0 -0
- parrot/registry/__init__.py +18 -0
- parrot/registry/registry.py +594 -0
- parrot/scheduler/__init__.py +1189 -0
- parrot/scheduler/models.py +60 -0
- parrot/security/__init__.py +16 -0
- parrot/security/prompt_injection.py +268 -0
- parrot/security/security_events.sql +25 -0
- parrot/services/__init__.py +1 -0
- parrot/services/mcp/__init__.py +8 -0
- parrot/services/mcp/config.py +13 -0
- parrot/services/mcp/server.py +295 -0
- parrot/services/o365_remote_auth.py +235 -0
- parrot/stores/__init__.py +7 -0
- parrot/stores/abstract.py +352 -0
- parrot/stores/arango.py +1090 -0
- parrot/stores/bigquery.py +1377 -0
- parrot/stores/cache.py +106 -0
- parrot/stores/empty.py +10 -0
- parrot/stores/faiss_store.py +1157 -0
- parrot/stores/kb/__init__.py +9 -0
- parrot/stores/kb/abstract.py +68 -0
- parrot/stores/kb/cache.py +165 -0
- parrot/stores/kb/doc.py +325 -0
- parrot/stores/kb/hierarchy.py +346 -0
- parrot/stores/kb/local.py +457 -0
- parrot/stores/kb/prompt.py +28 -0
- parrot/stores/kb/redis.py +659 -0
- parrot/stores/kb/store.py +115 -0
- parrot/stores/kb/user.py +374 -0
- parrot/stores/models.py +59 -0
- parrot/stores/pgvector.py +3 -0
- parrot/stores/postgres.py +2853 -0
- parrot/stores/utils/__init__.py +0 -0
- parrot/stores/utils/chunking.py +197 -0
- parrot/telemetry/__init__.py +3 -0
- parrot/telemetry/mixin.py +111 -0
- parrot/template/__init__.py +3 -0
- parrot/template/engine.py +259 -0
- parrot/tools/__init__.py +23 -0
- parrot/tools/abstract.py +644 -0
- parrot/tools/agent.py +363 -0
- parrot/tools/arangodbsearch.py +537 -0
- parrot/tools/arxiv_tool.py +188 -0
- parrot/tools/calculator/__init__.py +3 -0
- parrot/tools/calculator/operations/__init__.py +38 -0
- parrot/tools/calculator/operations/calculus.py +80 -0
- parrot/tools/calculator/operations/statistics.py +76 -0
- parrot/tools/calculator/tool.py +150 -0
- parrot/tools/cloudwatch.py +988 -0
- parrot/tools/codeinterpreter/__init__.py +127 -0
- parrot/tools/codeinterpreter/executor.py +371 -0
- parrot/tools/codeinterpreter/internals.py +473 -0
- parrot/tools/codeinterpreter/models.py +643 -0
- parrot/tools/codeinterpreter/prompts.py +224 -0
- parrot/tools/codeinterpreter/tool.py +664 -0
- parrot/tools/company_info/__init__.py +6 -0
- parrot/tools/company_info/tool.py +1138 -0
- parrot/tools/correlationanalysis.py +437 -0
- parrot/tools/database/abstract.py +286 -0
- parrot/tools/database/bq.py +115 -0
- parrot/tools/database/cache.py +284 -0
- parrot/tools/database/models.py +95 -0
- parrot/tools/database/pg.py +343 -0
- parrot/tools/databasequery.py +1159 -0
- parrot/tools/db.py +1800 -0
- parrot/tools/ddgo.py +370 -0
- parrot/tools/decorators.py +271 -0
- parrot/tools/dftohtml.py +282 -0
- parrot/tools/document.py +549 -0
- parrot/tools/ecs.py +819 -0
- parrot/tools/edareport.py +368 -0
- parrot/tools/elasticsearch.py +1049 -0
- parrot/tools/employees.py +462 -0
- parrot/tools/epson/__init__.py +96 -0
- parrot/tools/excel.py +683 -0
- parrot/tools/file/__init__.py +13 -0
- parrot/tools/file/abstract.py +76 -0
- parrot/tools/file/gcs.py +378 -0
- parrot/tools/file/local.py +284 -0
- parrot/tools/file/s3.py +511 -0
- parrot/tools/file/tmp.py +309 -0
- parrot/tools/file/tool.py +501 -0
- parrot/tools/file_reader.py +129 -0
- parrot/tools/flowtask/__init__.py +19 -0
- parrot/tools/flowtask/tool.py +761 -0
- parrot/tools/gittoolkit.py +508 -0
- parrot/tools/google/__init__.py +18 -0
- parrot/tools/google/base.py +169 -0
- parrot/tools/google/tools.py +1251 -0
- parrot/tools/googlelocation.py +5 -0
- parrot/tools/googleroutes.py +5 -0
- parrot/tools/googlesearch.py +5 -0
- parrot/tools/googlesitesearch.py +5 -0
- parrot/tools/googlevoice.py +2 -0
- parrot/tools/gvoice.py +695 -0
- parrot/tools/ibisworld/README.md +225 -0
- parrot/tools/ibisworld/__init__.py +11 -0
- parrot/tools/ibisworld/tool.py +366 -0
- parrot/tools/jiratoolkit.py +1718 -0
- parrot/tools/manager.py +1098 -0
- parrot/tools/math.py +152 -0
- parrot/tools/metadata.py +476 -0
- parrot/tools/msteams.py +1621 -0
- parrot/tools/msword.py +635 -0
- parrot/tools/multidb.py +580 -0
- parrot/tools/multistoresearch.py +369 -0
- parrot/tools/networkninja.py +167 -0
- parrot/tools/nextstop/__init__.py +4 -0
- parrot/tools/nextstop/base.py +286 -0
- parrot/tools/nextstop/employee.py +733 -0
- parrot/tools/nextstop/store.py +462 -0
- parrot/tools/notification.py +435 -0
- parrot/tools/o365/__init__.py +42 -0
- parrot/tools/o365/base.py +295 -0
- parrot/tools/o365/bundle.py +522 -0
- parrot/tools/o365/events.py +554 -0
- parrot/tools/o365/mail.py +992 -0
- parrot/tools/o365/onedrive.py +497 -0
- parrot/tools/o365/sharepoint.py +641 -0
- parrot/tools/openapi_toolkit.py +904 -0
- parrot/tools/openweather.py +527 -0
- parrot/tools/pdfprint.py +1001 -0
- parrot/tools/powerbi.py +518 -0
- parrot/tools/powerpoint.py +1113 -0
- parrot/tools/pricestool.py +146 -0
- parrot/tools/products/__init__.py +246 -0
- parrot/tools/prophet_tool.py +171 -0
- parrot/tools/pythonpandas.py +630 -0
- parrot/tools/pythonrepl.py +910 -0
- parrot/tools/qsource.py +436 -0
- parrot/tools/querytoolkit.py +395 -0
- parrot/tools/quickeda.py +827 -0
- parrot/tools/resttool.py +553 -0
- parrot/tools/retail/__init__.py +0 -0
- parrot/tools/retail/bby.py +528 -0
- parrot/tools/sandboxtool.py +703 -0
- parrot/tools/sassie/__init__.py +352 -0
- parrot/tools/scraping/__init__.py +7 -0
- parrot/tools/scraping/docs/select.md +466 -0
- parrot/tools/scraping/documentation.md +1278 -0
- parrot/tools/scraping/driver.py +436 -0
- parrot/tools/scraping/models.py +576 -0
- parrot/tools/scraping/options.py +85 -0
- parrot/tools/scraping/orchestrator.py +517 -0
- parrot/tools/scraping/readme.md +740 -0
- parrot/tools/scraping/tool.py +3115 -0
- parrot/tools/seasonaldetection.py +642 -0
- parrot/tools/shell_tool/__init__.py +5 -0
- parrot/tools/shell_tool/actions.py +408 -0
- parrot/tools/shell_tool/engine.py +155 -0
- parrot/tools/shell_tool/models.py +322 -0
- parrot/tools/shell_tool/tool.py +442 -0
- parrot/tools/site_search.py +214 -0
- parrot/tools/textfile.py +418 -0
- parrot/tools/think.py +378 -0
- parrot/tools/toolkit.py +298 -0
- parrot/tools/webapp_tool.py +187 -0
- parrot/tools/whatif.py +1279 -0
- parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
- parrot/tools/workday/__init__.py +6 -0
- parrot/tools/workday/models.py +1389 -0
- parrot/tools/workday/tool.py +1293 -0
- parrot/tools/yfinance_tool.py +306 -0
- parrot/tools/zipcode.py +217 -0
- parrot/utils/__init__.py +2 -0
- parrot/utils/helpers.py +73 -0
- parrot/utils/parsers/__init__.py +5 -0
- parrot/utils/parsers/toml.c +12078 -0
- parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/parsers/toml.pyx +21 -0
- parrot/utils/toml.py +11 -0
- parrot/utils/types.cpp +20936 -0
- parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/types.pyx +213 -0
- parrot/utils/uv.py +11 -0
- parrot/version.py +10 -0
- parrot/yaml-rs/Cargo.lock +350 -0
- parrot/yaml-rs/Cargo.toml +19 -0
- parrot/yaml-rs/pyproject.toml +19 -0
- parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
- parrot/yaml-rs/src/lib.rs +222 -0
- requirements/docker-compose.yml +24 -0
- requirements/requirements-dev.txt +21 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
from typing import Any, Optional, Tuple, List, Dict, Union
|
|
2
|
+
import json
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from .base import BaseRenderer
|
|
5
|
+
from . import register_renderer
|
|
6
|
+
from ...models.outputs import OutputMode
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from rich.table import Table as RichTable
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
RICH_AVAILABLE = True
|
|
12
|
+
except ImportError:
|
|
13
|
+
RICH_AVAILABLE = False
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from ipywidgets import HTML as IPyHTML
|
|
17
|
+
IPYWIDGETS_AVAILABLE = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
IPYWIDGETS_AVAILABLE = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
GRIDJS_SYSTEM_PROMPT = """
|
|
23
|
+
**GRID.JS CODE GENERATION MODE**
|
|
24
|
+
|
|
25
|
+
**Objective:** Generate a single, valid Grid.js Javascript code block.
|
|
26
|
+
|
|
27
|
+
**INSTRUCTIONS:**
|
|
28
|
+
1. **Analyze Request:** Understand the user's goal for the table.
|
|
29
|
+
2. **Generate Grid.js Code:** Create a complete Grid.js or ag-grid configuration.
|
|
30
|
+
3. **Use Sample Data:** If the user asks for a type of table but doesn't provide data, generate appropriate sample data to illustrate the table's structure.
|
|
31
|
+
4. **Output:** Return ONLY the Javascript code inside a ```javascript code block. Do not add explanations.
|
|
32
|
+
|
|
33
|
+
**BASIC STRUCTURE EXAMPLE:**
|
|
34
|
+
|
|
35
|
+
* If the user requests a gridjs table, respond with code similar to the following:
|
|
36
|
+
```javascript
|
|
37
|
+
new gridjs.Grid({
|
|
38
|
+
columns: ["Name", "Email", "Phone Number"],
|
|
39
|
+
data: [
|
|
40
|
+
["John", "john@example.com", "(353) 01 222 3333"],
|
|
41
|
+
["Mark", "mark@gmail.com", "(01) 22 888 4444"],
|
|
42
|
+
["Eoin", "eoin@gmail.com", "0097 22 654 00033"],
|
|
43
|
+
["Sarah", "sarahcdd@gmail.com", "+322 876 1233"],
|
|
44
|
+
["Afshin", "afshin@mail.com", "(353) 22 87 8356"]
|
|
45
|
+
]
|
|
46
|
+
}).render(document.getElementById("wrapper"));
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
* if the user requests a ag-grid table, respond with code similar to the following:
|
|
50
|
+
```javascript
|
|
51
|
+
const columnDefs = [
|
|
52
|
+
{ headerName: "Make", field: "make" },
|
|
53
|
+
{ headerName: "Model", field: "model" },
|
|
54
|
+
{ headerName: "Price", field: "price" }
|
|
55
|
+
];
|
|
56
|
+
const rowData = [
|
|
57
|
+
{ make: "Toyota", model: "Celica", price: 35000 },
|
|
58
|
+
{ make: "Ford", model: "Mondeo", price: 32000 },
|
|
59
|
+
{ make: "Porsche", model: "Boxster", price: 72000 }
|
|
60
|
+
];
|
|
61
|
+
const gridOptions = {
|
|
62
|
+
columnDefs: columnDefs,
|
|
63
|
+
rowData: rowData
|
|
64
|
+
};
|
|
65
|
+
new agGrid.Grid(document.getElementById('myGrid'), gridOptions);
|
|
66
|
+
```
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@register_renderer(OutputMode.TABLE, system_prompt=GRIDJS_SYSTEM_PROMPT)
|
|
70
|
+
class TableRenderer(BaseRenderer):
|
|
71
|
+
"""
|
|
72
|
+
Renderer for Tables supporting Rich (Terminal), HTML (Simple), Grid.js, and Ag-Grid.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def _extract_data(self, response: Any) -> pd.DataFrame:
|
|
76
|
+
"""Extract data into a Pandas DataFrame."""
|
|
77
|
+
# 1. Handle PandasAgentResponse
|
|
78
|
+
output = getattr(response, 'output', None)
|
|
79
|
+
|
|
80
|
+
if output is not None:
|
|
81
|
+
if hasattr(output, 'to_dataframe'):
|
|
82
|
+
return output.to_dataframe()
|
|
83
|
+
if hasattr(output, 'data') and output.data is not None:
|
|
84
|
+
return pd.DataFrame(output.data)
|
|
85
|
+
|
|
86
|
+
# 2. Handle direct DataFrame
|
|
87
|
+
if isinstance(output, pd.DataFrame):
|
|
88
|
+
return output
|
|
89
|
+
|
|
90
|
+
# 3. Handle list of dicts
|
|
91
|
+
if isinstance(output, list):
|
|
92
|
+
return pd.DataFrame(output)
|
|
93
|
+
|
|
94
|
+
# 4. Handle dict (single record or dict of lists)
|
|
95
|
+
if isinstance(output, dict):
|
|
96
|
+
return pd.DataFrame(output) if all(isinstance(v, list) for v in output.values()) else pd.DataFrame([output])
|
|
97
|
+
|
|
98
|
+
# 5. Fallback: Check response.data attribute directly (AIMessage)
|
|
99
|
+
if hasattr(response, 'data') and response.data is not None:
|
|
100
|
+
if isinstance(response.data, pd.DataFrame):
|
|
101
|
+
return response.data
|
|
102
|
+
return pd.DataFrame(response.data)
|
|
103
|
+
|
|
104
|
+
return pd.DataFrame()
|
|
105
|
+
|
|
106
|
+
def _render_rich_table(self, df: pd.DataFrame, title: str) -> Any:
|
|
107
|
+
"""Render a Rich Table object."""
|
|
108
|
+
if not RICH_AVAILABLE:
|
|
109
|
+
return df.to_string()
|
|
110
|
+
|
|
111
|
+
table = RichTable(title=title, show_header=True, header_style="bold magenta")
|
|
112
|
+
|
|
113
|
+
# Add columns
|
|
114
|
+
for column in df.columns:
|
|
115
|
+
table.add_column(str(column), overflow="fold")
|
|
116
|
+
|
|
117
|
+
# Add rows
|
|
118
|
+
for _, row in df.iterrows():
|
|
119
|
+
table.add_row(*[str(item) for item in row])
|
|
120
|
+
|
|
121
|
+
return table
|
|
122
|
+
|
|
123
|
+
def _render_simple_table(self, data: Any) -> str:
|
|
124
|
+
if isinstance(data, pd.DataFrame):
|
|
125
|
+
return data.to_html(index=False)
|
|
126
|
+
elif isinstance(data, list) and all(isinstance(i, dict) for i in data):
|
|
127
|
+
df = pd.DataFrame(data)
|
|
128
|
+
return df.to_html(index=False)
|
|
129
|
+
elif isinstance(data, str):
|
|
130
|
+
return data
|
|
131
|
+
else:
|
|
132
|
+
raise TypeError(f"Unsupported data type for simple table: {type(data)}")
|
|
133
|
+
|
|
134
|
+
def _generate_gridjs_code(self, df: pd.DataFrame, element_id: str = "wrapper") -> str:
|
|
135
|
+
"""Generate Grid.js configuration and render code."""
|
|
136
|
+
columns = df.columns.tolist()
|
|
137
|
+
# Convert data to JSON-serializable list of lists
|
|
138
|
+
data = df.values.tolist()
|
|
139
|
+
|
|
140
|
+
# Serialize safely to avoid JS syntax errors
|
|
141
|
+
json_data = json.dumps(data)
|
|
142
|
+
json_columns = json.dumps(columns)
|
|
143
|
+
|
|
144
|
+
return f"""
|
|
145
|
+
new gridjs.Grid({{
|
|
146
|
+
columns: {json_columns},
|
|
147
|
+
data: {json_data},
|
|
148
|
+
search: true,
|
|
149
|
+
sort: true,
|
|
150
|
+
pagination: {{
|
|
151
|
+
limit: 10
|
|
152
|
+
}},
|
|
153
|
+
className: {{
|
|
154
|
+
table: 'table-body'
|
|
155
|
+
}}
|
|
156
|
+
}}).render(document.getElementById("{element_id}"));
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def _generate_aggrid_code(self, df: pd.DataFrame, element_id: str = "wrapper") -> str:
|
|
160
|
+
"""Generate Ag-Grid configuration and render code."""
|
|
161
|
+
# Define columns definition
|
|
162
|
+
column_defs = [
|
|
163
|
+
{"headerName": col, "field": col, "sortable": True, "filter": True} for col in df.columns
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
# Data is list of dicts for Ag-Grid
|
|
167
|
+
row_data = df.to_dict(orient='records')
|
|
168
|
+
|
|
169
|
+
json_col_defs = json.dumps(column_defs)
|
|
170
|
+
json_row_data = json.dumps(row_data)
|
|
171
|
+
|
|
172
|
+
return f"""
|
|
173
|
+
const gridOptions = {{
|
|
174
|
+
columnDefs: {json_col_defs},
|
|
175
|
+
rowData: {json_row_data},
|
|
176
|
+
pagination: true,
|
|
177
|
+
paginationPageSize: 10,
|
|
178
|
+
defaultColDef: {{
|
|
179
|
+
flex: 1,
|
|
180
|
+
minWidth: 100,
|
|
181
|
+
resizable: true,
|
|
182
|
+
}}
|
|
183
|
+
}};
|
|
184
|
+
const gridDiv = document.getElementById("{element_id}");
|
|
185
|
+
agGrid.createGrid(gridDiv, gridOptions);
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
def _build_html_document(
|
|
189
|
+
self,
|
|
190
|
+
table_content: str,
|
|
191
|
+
table_mode: str,
|
|
192
|
+
title: str = "Table",
|
|
193
|
+
html_mode: str = "partial",
|
|
194
|
+
element_id: str = "wrapper",
|
|
195
|
+
script_nonce: Optional[str] = None,
|
|
196
|
+
style_nonce: Optional[str] = None,
|
|
197
|
+
content_security_policy: Optional[str] = None,
|
|
198
|
+
) -> str:
|
|
199
|
+
"""
|
|
200
|
+
Build the final HTML output (partial or complete).
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
table_content: The HTML table or JS code.
|
|
204
|
+
table_mode: 'simple', 'grid', or 'ag-grid'.
|
|
205
|
+
html_mode: 'partial' (embeddable) or 'complete' (standalone).
|
|
206
|
+
"""
|
|
207
|
+
head_content = ""
|
|
208
|
+
partial_head_content = ""
|
|
209
|
+
body_content = ""
|
|
210
|
+
script_nonce_attr = f' nonce="{script_nonce}"' if script_nonce else ""
|
|
211
|
+
style_nonce_attr = f' nonce="{style_nonce}"' if style_nonce else ""
|
|
212
|
+
|
|
213
|
+
# 1. Configuration based on mode
|
|
214
|
+
if table_mode == 'grid':
|
|
215
|
+
# Grid.js CDNs
|
|
216
|
+
head_content = f"""
|
|
217
|
+
<link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet" />
|
|
218
|
+
<script src="https://unpkg.com/gridjs/dist/gridjs.umd.js" defer></script>
|
|
219
|
+
"""
|
|
220
|
+
partial_head_content = head_content
|
|
221
|
+
body_content = f"""
|
|
222
|
+
<div id="{element_id}"></div>
|
|
223
|
+
<script{script_nonce_attr}>
|
|
224
|
+
document.addEventListener('DOMContentLoaded', function () {{
|
|
225
|
+
{table_content}
|
|
226
|
+
}});
|
|
227
|
+
</script>
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
elif table_mode == 'ag-grid':
|
|
231
|
+
# Ag-Grid CDNs
|
|
232
|
+
head_content = """
|
|
233
|
+
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js" defer></script>
|
|
234
|
+
"""
|
|
235
|
+
partial_head_content = head_content
|
|
236
|
+
# Note: Ag-Grid requires a height on the container
|
|
237
|
+
body_content = f"""
|
|
238
|
+
<div id="{element_id}" class="ag-theme-alpine" style="height: 500px; width: 100%;"></div>
|
|
239
|
+
<script{script_nonce_attr}>
|
|
240
|
+
document.addEventListener('DOMContentLoaded', function () {{
|
|
241
|
+
if (window.agGrid && document.getElementById('{element_id}')) {{
|
|
242
|
+
{table_content}
|
|
243
|
+
}}
|
|
244
|
+
}});
|
|
245
|
+
</script>
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
else:
|
|
249
|
+
# simple
|
|
250
|
+
# Basic Bootstrap for simple tables
|
|
251
|
+
head_content = f"""
|
|
252
|
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
|
253
|
+
<style{style_nonce_attr}>
|
|
254
|
+
.dataframe {{ width: 100%; }}
|
|
255
|
+
.dataframe td, .dataframe th {{ padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }}
|
|
256
|
+
</style>
|
|
257
|
+
"""
|
|
258
|
+
partial_head_content = f"""
|
|
259
|
+
<style{style_nonce_attr}>
|
|
260
|
+
@import url('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css');
|
|
261
|
+
.dataframe {{ width: 100%; }}
|
|
262
|
+
.dataframe td, .dataframe th {{ padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }}
|
|
263
|
+
</style>
|
|
264
|
+
"""
|
|
265
|
+
body_content = f'<div class="table-responsive">{table_content}</div>'
|
|
266
|
+
|
|
267
|
+
# Optional CSP meta for complete documents. This is useful when a nonce is provided
|
|
268
|
+
# so that inline scripts/styles still satisfy strict policies.
|
|
269
|
+
csp_meta_tag = ""
|
|
270
|
+
if html_mode == "complete":
|
|
271
|
+
if content_security_policy:
|
|
272
|
+
csp_meta_tag = f"<meta http-equiv=\"Content-Security-Policy\" content=\"{content_security_policy}\">"
|
|
273
|
+
elif script_nonce or style_nonce:
|
|
274
|
+
csp_parts = [
|
|
275
|
+
"default-src 'self' https://cdn.jsdelivr.net https://unpkg.com",
|
|
276
|
+
"img-src 'self' data: https://cdn.jsdelivr.net https://unpkg.com",
|
|
277
|
+
"font-src 'self' data: https://cdn.jsdelivr.net https://unpkg.com",
|
|
278
|
+
]
|
|
279
|
+
script_src = ["'self'", "https://cdn.jsdelivr.net", "https://unpkg.com"]
|
|
280
|
+
style_src = ["'self'", "https://cdn.jsdelivr.net", "https://unpkg.com"]
|
|
281
|
+
|
|
282
|
+
if script_nonce:
|
|
283
|
+
script_src.append(f"'nonce-{script_nonce}'")
|
|
284
|
+
else:
|
|
285
|
+
script_src.append("'unsafe-inline'")
|
|
286
|
+
|
|
287
|
+
if style_nonce:
|
|
288
|
+
style_src.append(f"'nonce-{style_nonce}'")
|
|
289
|
+
else:
|
|
290
|
+
style_src.append("'unsafe-inline'")
|
|
291
|
+
|
|
292
|
+
csp_parts.append(f"script-src {' '.join(script_src)}")
|
|
293
|
+
csp_parts.append(f"style-src {' '.join(style_src)}")
|
|
294
|
+
csp_meta_tag = f"<meta http-equiv=\"Content-Security-Policy\" content=\"{' ; '.join(csp_parts)}\">"
|
|
295
|
+
|
|
296
|
+
# 2. Return Partial (Embeddable)
|
|
297
|
+
if html_mode == "partial":
|
|
298
|
+
return f"""
|
|
299
|
+
<div>
|
|
300
|
+
{partial_head_content}
|
|
301
|
+
{body_content}
|
|
302
|
+
</div>
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
# 3. Return Complete (Standalone)
|
|
306
|
+
return f"""<!DOCTYPE html>
|
|
307
|
+
<html lang="en">
|
|
308
|
+
<head>
|
|
309
|
+
<meta charset="UTF-8">
|
|
310
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
311
|
+
{csp_meta_tag}
|
|
312
|
+
<title>{title}</title>
|
|
313
|
+
{head_content}
|
|
314
|
+
</head>
|
|
315
|
+
<body>
|
|
316
|
+
<div class="container mt-4">
|
|
317
|
+
<h2>{title}</h2>
|
|
318
|
+
{body_content}
|
|
319
|
+
</div>
|
|
320
|
+
</body>
|
|
321
|
+
</html>"""
|
|
322
|
+
|
|
323
|
+
async def render(
|
|
324
|
+
self,
|
|
325
|
+
response: Any,
|
|
326
|
+
table_mode: str = 'simple', # simple, grid, ag-grid
|
|
327
|
+
title: str = 'Table',
|
|
328
|
+
environment: str = 'terminal',
|
|
329
|
+
html_mode: str = 'partial',
|
|
330
|
+
**kwargs,
|
|
331
|
+
) -> Tuple[Any, Optional[Any]]:
|
|
332
|
+
"""
|
|
333
|
+
Render table in the appropriate format.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
Tuple[Any, Optional[Any]]: (raw_data_df, rendered_output)
|
|
337
|
+
"""
|
|
338
|
+
# 1. Extract Data
|
|
339
|
+
df = self._extract_data(response)
|
|
340
|
+
|
|
341
|
+
if df.empty:
|
|
342
|
+
return "No Data Available", None
|
|
343
|
+
|
|
344
|
+
data_content = df.to_dict(orient='records')
|
|
345
|
+
|
|
346
|
+
output_format = kwargs.get('output_format', environment)
|
|
347
|
+
|
|
348
|
+
# 2. Environment: Terminal -> Rich Table
|
|
349
|
+
if output_format == 'terminal':
|
|
350
|
+
rich_table = self._render_rich_table(df, title)
|
|
351
|
+
return data_content, rich_table
|
|
352
|
+
|
|
353
|
+
# 3. Prepare Content for HTML/JS
|
|
354
|
+
content = ""
|
|
355
|
+
if table_mode == 'simple':
|
|
356
|
+
# Convert to HTML Table
|
|
357
|
+
content = df.to_html(classes="table table-striped table-bordered", index=False)
|
|
358
|
+
|
|
359
|
+
elif table_mode == 'grid':
|
|
360
|
+
# Generate Grid.js Code
|
|
361
|
+
# Check if code was pre-generated by LLM (in response.code) - Future proofing
|
|
362
|
+
if hasattr(response, 'code') and isinstance(response.code, str) and "new gridjs.Grid" in response.code:
|
|
363
|
+
content = response.code
|
|
364
|
+
else:
|
|
365
|
+
content = self._generate_gridjs_code(df, "wrapper_grid")
|
|
366
|
+
|
|
367
|
+
elif table_mode == 'ag-grid':
|
|
368
|
+
# Generate Ag-Grid Code
|
|
369
|
+
if hasattr(response, 'code') and isinstance(response.code, str) and "new agGrid.Grid" in response.code:
|
|
370
|
+
content = response.code
|
|
371
|
+
else:
|
|
372
|
+
content = self._generate_aggrid_code(df, "wrapper_ag")
|
|
373
|
+
|
|
374
|
+
# 4. Build Wrapped HTML
|
|
375
|
+
wrapper_id = f"wrapper_{table_mode}" if table_mode != 'simple' else "wrapper"
|
|
376
|
+
script_nonce = kwargs.get('script_nonce')
|
|
377
|
+
style_nonce = kwargs.get('style_nonce')
|
|
378
|
+
content_security_policy = kwargs.get('content_security_policy')
|
|
379
|
+
wrapped_html = self._build_html_document(
|
|
380
|
+
content,
|
|
381
|
+
table_mode,
|
|
382
|
+
title=title,
|
|
383
|
+
html_mode=html_mode,
|
|
384
|
+
element_id=wrapper_id,
|
|
385
|
+
script_nonce=script_nonce,
|
|
386
|
+
style_nonce=style_nonce,
|
|
387
|
+
content_security_policy=content_security_policy,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# 5. Environment: Jupyter -> Widget
|
|
391
|
+
if output_format in {'jupyter', 'notebook', 'colab'}:
|
|
392
|
+
if IPYWIDGETS_AVAILABLE:
|
|
393
|
+
return df, IPyHTML(value=wrapped_html)
|
|
394
|
+
return df, wrapped_html
|
|
395
|
+
|
|
396
|
+
# 6. Environment: HTML (return string)
|
|
397
|
+
return data_content, wrapped_html
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
from dataclasses import asdict
|
|
3
|
+
from ...models.outputs import OutputMode
|
|
4
|
+
from ...template.engine import TemplateEngine
|
|
5
|
+
from . import register_renderer
|
|
6
|
+
from .base import BaseRenderer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@register_renderer(OutputMode.TEMPLATE_REPORT)
|
|
10
|
+
class TemplateReportRenderer(BaseRenderer):
|
|
11
|
+
"""
|
|
12
|
+
Renders AI output using Jinja2 templates via the TemplateEngine.
|
|
13
|
+
|
|
14
|
+
Supports both file-based templates and in-memory templates via add_template().
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, template_engine: Optional[TemplateEngine] = None):
|
|
18
|
+
"""
|
|
19
|
+
Initialize the TemplateReportRenderer.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
template_engine: Optional TemplateEngine instance. If not provided,
|
|
23
|
+
one will be created on first use.
|
|
24
|
+
"""
|
|
25
|
+
self._template_engine = template_engine
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def template_engine(self) -> TemplateEngine:
|
|
29
|
+
"""
|
|
30
|
+
Lazy initialization of TemplateEngine if not provided.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
TemplateEngine instance
|
|
34
|
+
"""
|
|
35
|
+
if self._template_engine is None:
|
|
36
|
+
# Initialize with no template directories (will use in-memory only)
|
|
37
|
+
self._template_engine = TemplateEngine()
|
|
38
|
+
return self._template_engine
|
|
39
|
+
|
|
40
|
+
def add_template(self, name: str, content: str) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Add an in-memory template to the engine.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
name: Template name (e.g., 'report.html', 'summary.md')
|
|
46
|
+
content: Jinja2 template content
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
renderer.add_template('report.html', '<h1>{{ title }}</h1>')
|
|
50
|
+
"""
|
|
51
|
+
self.template_engine.add_templates({name: content})
|
|
52
|
+
|
|
53
|
+
async def render(self, data: Any, **kwargs: Any) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Renders data using a Jinja2 template asynchronously.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
data: The data to render. Can be:
|
|
59
|
+
- dict: passed directly to template
|
|
60
|
+
- Pydantic model: converted via model_dump()
|
|
61
|
+
- dataclass: converted via asdict()
|
|
62
|
+
- any object with attributes: accessible in template
|
|
63
|
+
**kwargs: Additional arguments:
|
|
64
|
+
- template: (required) Template name to use
|
|
65
|
+
- template_engine: (optional) Override the default engine
|
|
66
|
+
- Additional kwargs are passed to the template context
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Rendered template content as string
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ValueError: If template is not provided or not found
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
result = await renderer.render(
|
|
76
|
+
{"title": "Report", "items": [1, 2, 3]},
|
|
77
|
+
template="report.html"
|
|
78
|
+
)
|
|
79
|
+
"""
|
|
80
|
+
# Get template name
|
|
81
|
+
template_name: str = kwargs.pop("template", None)
|
|
82
|
+
if not template_name:
|
|
83
|
+
raise ValueError(
|
|
84
|
+
"Template name must be provided via 'template' kwarg. "
|
|
85
|
+
"Example: renderer.render(data, template='report.html')"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Allow overriding the template engine
|
|
89
|
+
engine = kwargs.pop("template_engine", None) or self.template_engine
|
|
90
|
+
|
|
91
|
+
# Prepare the template context
|
|
92
|
+
context = self._prepare_template_context(data, kwargs)
|
|
93
|
+
|
|
94
|
+
# Render the template
|
|
95
|
+
try:
|
|
96
|
+
return await engine.render(template_name, context)
|
|
97
|
+
except FileNotFoundError as e:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"Template '{template_name}' not found. "
|
|
100
|
+
f"Use add_template() to add in-memory templates or "
|
|
101
|
+
f"ensure the template exists in the template directories."
|
|
102
|
+
) from e
|
|
103
|
+
except Exception as e:
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
f"Failed to render template '{template_name}': {e}"
|
|
106
|
+
) from e
|
|
107
|
+
|
|
108
|
+
def _prepare_template_context(
|
|
109
|
+
self, data: Any, extra_kwargs: Dict[str, Any]
|
|
110
|
+
) -> Dict[str, Any]:
|
|
111
|
+
"""
|
|
112
|
+
Prepare the context dictionary for template rendering.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
data: The main data to render
|
|
116
|
+
extra_kwargs: Additional kwargs to include in context
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Dictionary to pass to template
|
|
120
|
+
"""
|
|
121
|
+
# Start with extra kwargs
|
|
122
|
+
context = dict(extra_kwargs)
|
|
123
|
+
|
|
124
|
+
# Handle different data types
|
|
125
|
+
if isinstance(data, dict):
|
|
126
|
+
# Merge dict data with kwargs (data takes precedence)
|
|
127
|
+
context |= data
|
|
128
|
+
elif hasattr(data, 'model_dump'):
|
|
129
|
+
# Pydantic model
|
|
130
|
+
context |= data.model_dump()
|
|
131
|
+
elif hasattr(data, '__dataclass_fields__'):
|
|
132
|
+
# Dataclass
|
|
133
|
+
context |= asdict(data)
|
|
134
|
+
else:
|
|
135
|
+
# Primitive or unknown type - wrap as 'data'
|
|
136
|
+
context['data'] = data
|
|
137
|
+
|
|
138
|
+
return context
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from typing import Any, Tuple
|
|
2
|
+
import json
|
|
3
|
+
from dataclasses import is_dataclass, asdict
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
try:
|
|
6
|
+
import yaml_rs # pylint: disable=E0401 # noqa
|
|
7
|
+
YAML_RS_AVAILABLE = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
YAML_RS_AVAILABLE = False
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from datamodel.parsers.json import json_encoder # pylint: disable=E0611 # noqa
|
|
12
|
+
from . import register_renderer
|
|
13
|
+
from .base import BaseRenderer
|
|
14
|
+
from ...models.outputs import OutputMode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@register_renderer(OutputMode.YAML)
|
|
18
|
+
class YAMLRenderer(BaseRenderer):
|
|
19
|
+
"""Renderer for YAML output using yaml-rs (Rust) or PyYAML fallback"""
|
|
20
|
+
|
|
21
|
+
def _json_as_yaml(self, data: Any, indent: int = 2) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Fallback: Format JSON as YAML-like structure.
|
|
24
|
+
Useful when yaml_rs is missing or fails on specific types.
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
# First ensure it's serializable via json_encoder logic
|
|
28
|
+
if not isinstance(data, str):
|
|
29
|
+
data = json.loads(json_encoder(data))
|
|
30
|
+
|
|
31
|
+
import yaml
|
|
32
|
+
return yaml.dump(data, indent=indent, sort_keys=False, default_flow_style=False)
|
|
33
|
+
except ImportError:
|
|
34
|
+
# Manual JSON-to-YAML-ish conversion if PyYAML is also missing
|
|
35
|
+
json_str = json.dumps(data, indent=indent, sort_keys=False)
|
|
36
|
+
yaml_like = json_str.replace('{', '').replace('}', '')
|
|
37
|
+
yaml_like = yaml_like.replace('[', '').replace(']', '')
|
|
38
|
+
yaml_like = yaml_like.replace('",', '"')
|
|
39
|
+
return yaml_like.replace('"', '')
|
|
40
|
+
|
|
41
|
+
def _serialize(self, data: Any, indent: int = 2, sort_keys: bool = False) -> str:
|
|
42
|
+
"""Serialize data to YAML string."""
|
|
43
|
+
try:
|
|
44
|
+
if isinstance(data, pd.DataFrame):
|
|
45
|
+
data = data.to_dict(orient='records')
|
|
46
|
+
elif is_dataclass(data):
|
|
47
|
+
data = asdict(data)
|
|
48
|
+
elif isinstance(data, BaseModel):
|
|
49
|
+
data = data.model_dump()
|
|
50
|
+
if not YAML_RS_AVAILABLE:
|
|
51
|
+
return self._json_as_yaml(data, indent)
|
|
52
|
+
try:
|
|
53
|
+
return yaml_rs.dumps(data, indent=indent, sort_keys=sort_keys)
|
|
54
|
+
except Exception:
|
|
55
|
+
# Fallback to python implementation on error
|
|
56
|
+
return self._json_as_yaml(data, indent)
|
|
57
|
+
except Exception as e:
|
|
58
|
+
print('DATA > ', data)
|
|
59
|
+
return f"error_serializing_to_yaml: {str(e)}"
|
|
60
|
+
|
|
61
|
+
def _wrap_output(self, yaml_string: str, environment: str) -> Any:
|
|
62
|
+
"""
|
|
63
|
+
Wrap the YAML string into an environment-specific container.
|
|
64
|
+
"""
|
|
65
|
+
# --- Terminal (Rich) ---
|
|
66
|
+
if environment == 'terminal':
|
|
67
|
+
try:
|
|
68
|
+
from rich.panel import Panel as RichPanel
|
|
69
|
+
from rich.syntax import Syntax
|
|
70
|
+
|
|
71
|
+
syntax = Syntax(yaml_string, "yaml", theme="monokai", line_numbers=True)
|
|
72
|
+
return RichPanel(syntax, title="YAML Output", border_style="green")
|
|
73
|
+
except ImportError:
|
|
74
|
+
return yaml_string
|
|
75
|
+
|
|
76
|
+
# --- Jupyter / Notebook ---
|
|
77
|
+
elif environment in {'jupyter', 'notebook'}:
|
|
78
|
+
try:
|
|
79
|
+
from ipywidgets import HTML
|
|
80
|
+
from pygments import highlight
|
|
81
|
+
from pygments.lexers import YamlLexer
|
|
82
|
+
from pygments.formatters import HtmlFormatter
|
|
83
|
+
|
|
84
|
+
formatter = HtmlFormatter(style='colorful', noclasses=True)
|
|
85
|
+
highlighted_html = highlight(yaml_string, YamlLexer(), formatter)
|
|
86
|
+
|
|
87
|
+
return HTML(
|
|
88
|
+
value=f'<div style="max-height: 500px; overflow-y: auto; background-color: #f8f8f8; padding: 10px;">{highlighted_html}</div>'
|
|
89
|
+
)
|
|
90
|
+
except ImportError:
|
|
91
|
+
return self._wrap_html(yaml_string)
|
|
92
|
+
|
|
93
|
+
# --- HTML ---
|
|
94
|
+
elif environment == 'html':
|
|
95
|
+
return self._wrap_html(yaml_string)
|
|
96
|
+
|
|
97
|
+
# Default
|
|
98
|
+
return yaml_string
|
|
99
|
+
|
|
100
|
+
async def render(
|
|
101
|
+
self,
|
|
102
|
+
response: Any,
|
|
103
|
+
environment: str = 'default',
|
|
104
|
+
**kwargs,
|
|
105
|
+
) -> Tuple[str, Any]:
|
|
106
|
+
"""
|
|
107
|
+
Render response as YAML.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Tuple[str, Any]: (yaml_string, wrapped_content)
|
|
111
|
+
"""
|
|
112
|
+
indent = kwargs.get('indent', 2)
|
|
113
|
+
sort_keys = kwargs.get('sort_keys', False)
|
|
114
|
+
output_format = kwargs.get('output_format', environment)
|
|
115
|
+
|
|
116
|
+
# 1. Extract Data
|
|
117
|
+
data = self._extract_data(response)
|
|
118
|
+
|
|
119
|
+
# 2. Serialize to content string
|
|
120
|
+
yaml_string = self._serialize(data, indent=indent, sort_keys=sort_keys)
|
|
121
|
+
|
|
122
|
+
# 3. Wrap content based on environment
|
|
123
|
+
wrapped_output = self._wrap_output(yaml_string, output_format)
|
|
124
|
+
|
|
125
|
+
return yaml_string, wrapped_output
|