@larkup/workspace-app 0.0.0-stage → 0.1.0
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.
- package/LICENSE +176 -0
- package/README.md +4 -2
- package/assets/github.svg +3 -0
- package/assets/icons/Confluence.png +0 -0
- package/assets/icons/Instagram.png +0 -0
- package/assets/icons/Northflank.png +0 -0
- package/assets/icons/Salesforce.png +0 -0
- package/assets/icons/agentskills.png +0 -0
- package/assets/icons/airtable.png +0 -0
- package/assets/icons/asana.png +0 -0
- package/assets/icons/ashby.png +0 -0
- package/assets/icons/audio.png +0 -0
- package/assets/icons/aws-kendra.png +0 -0
- package/assets/icons/aws.svg +38 -0
- package/assets/icons/azure-ai-search.png +0 -0
- package/assets/icons/azure.svg +1 -0
- package/assets/icons/bigquery.png +0 -0
- package/assets/icons/bing.png +0 -0
- package/assets/icons/bitbucket.png +0 -0
- package/assets/icons/brave.png +0 -0
- package/assets/icons/browserbase.png +0 -0
- package/assets/icons/calendly.png +0 -0
- package/assets/icons/chroma.png +0 -0
- package/assets/icons/cloudflare.png +0 -0
- package/assets/icons/cohere.svg +30 -0
- package/assets/icons/databricks.png +0 -0
- package/assets/icons/daytonaio.png +0 -0
- package/assets/icons/daytonaio2.png +0 -0
- package/assets/icons/deepgram.png +0 -0
- package/assets/icons/deepl.png +0 -0
- package/assets/icons/digital-ocean.webp +0 -0
- package/assets/icons/discord.png +0 -0
- package/assets/icons/e2b-2.png +0 -0
- package/assets/icons/e2b.png +0 -0
- package/assets/icons/elevenlabs.png +0 -0
- package/assets/icons/email.png +0 -0
- package/assets/icons/exa.png +0 -0
- package/assets/icons/excel.png +0 -0
- package/assets/icons/fal.png +0 -0
- package/assets/icons/firecrawl.png +0 -0
- package/assets/icons/firecrawl2.png +0 -0
- package/assets/icons/flyio.jpeg +0 -0
- package/assets/icons/gcp.svg +1 -0
- package/assets/icons/gemini.svg +1 -0
- package/assets/icons/gmail.png +0 -0
- package/assets/icons/google-analytics.png +0 -0
- package/assets/icons/google-calender.png +0 -0
- package/assets/icons/google-docs.png +0 -0
- package/assets/icons/google-drive.png +0 -0
- package/assets/icons/google-maps.png +0 -0
- package/assets/icons/google-meet.png +0 -0
- package/assets/icons/google-sheets.png +0 -0
- package/assets/icons/google-slides.png +0 -0
- package/assets/icons/google-tasks.png +0 -0
- package/assets/icons/google.png +0 -0
- package/assets/icons/grok.png +0 -0
- package/assets/icons/hubspot.png +0 -0
- package/assets/icons/image.png +0 -0
- package/assets/icons/jina.svg +1 -0
- package/assets/icons/jira.png +0 -0
- package/assets/icons/lancedb2.png +0 -0
- package/assets/icons/linear.png +0 -0
- package/assets/icons/linux.png +0 -0
- package/assets/icons/looker.png +0 -0
- package/assets/icons/luma.png +0 -0
- package/assets/icons/mac.png +0 -0
- package/assets/icons/markdown.png +0 -0
- package/assets/icons/mcp.png +0 -0
- package/assets/icons/mcp.svg +1 -0
- package/assets/icons/messenger.svg +1 -0
- package/assets/icons/microsoft-intra.png +0 -0
- package/assets/icons/microsoft-onenote.png +0 -0
- package/assets/icons/microsoft-planner.png +0 -0
- package/assets/icons/microsoft-teams.png +0 -0
- package/assets/icons/miro.png +0 -0
- package/assets/icons/mistral.svg +469 -0
- package/assets/icons/modal.png +0 -0
- package/assets/icons/ngrok.png +0 -0
- package/assets/icons/nomic.png +0 -0
- package/assets/icons/onedrive.png +0 -0
- package/assets/icons/openai.svg +1 -0
- package/assets/icons/outlook-calendar.png +0 -0
- package/assets/icons/outlook-email.png +0 -0
- package/assets/icons/outlook.png +0 -0
- package/assets/icons/pdf.png +0 -0
- package/assets/icons/personio.png +0 -0
- package/assets/icons/pgvector2.png +0 -0
- package/assets/icons/phone.png +0 -0
- package/assets/icons/pinecone.png +0 -0
- package/assets/icons/pipedrive.png +0 -0
- package/assets/icons/power-pi.png +0 -0
- package/assets/icons/pylon.png +0 -0
- package/assets/icons/python.png +0 -0
- package/assets/icons/qdrant.svg +35 -0
- package/assets/icons/revai.png +0 -0
- package/assets/icons/revai.svg +1 -0
- package/assets/icons/sap.png +0 -0
- package/assets/icons/serpapi.svg +34 -0
- package/assets/icons/serper.png +0 -0
- package/assets/icons/servicenow.png +0 -0
- package/assets/icons/sharepoint.png +0 -0
- package/assets/icons/slack.png +0 -0
- package/assets/icons/snowflake.png +0 -0
- package/assets/icons/statistia.png +0 -0
- package/assets/icons/stripe.png +0 -0
- package/assets/icons/supabase.png +0 -0
- package/assets/icons/tableau.png +0 -0
- package/assets/icons/tavily.png +0 -0
- package/assets/icons/telegram.png +0 -0
- package/assets/icons/typescript.png +0 -0
- package/assets/icons/vercel copy.svg +1 -0
- package/assets/icons/vercel.svg +1 -0
- package/assets/icons/vertex-ai.png +0 -0
- package/assets/icons/video.png +0 -0
- package/assets/icons/voyage-light.png +0 -0
- package/assets/icons/weaviate.webp +0 -0
- package/assets/icons/webcontainers.svg +11 -0
- package/assets/icons/webhook.png +0 -0
- package/assets/icons/whatsapp copy.png +0 -0
- package/assets/icons/whatsapp.png +0 -0
- package/assets/icons/windows.png +0 -0
- package/assets/icons/word.png +0 -0
- package/assets/icons/zendesk.png +0 -0
- package/assets/icons/zoom.png +0 -0
- package/assets/notion-white.png +0 -0
- package/assets/notion.png +0 -0
- package/dist-types/asset-server.d.ts +3 -0
- package/dist-types/asset-server.d.ts.map +1 -0
- package/dist-types/components/alerts/generic-alert.d.ts +15 -0
- package/dist-types/components/alerts/generic-alert.d.ts.map +1 -0
- package/dist-types/components/chat/canvas/doc-editor-provider.d.ts +62 -0
- package/dist-types/components/chat/canvas/doc-editor-provider.d.ts.map +1 -0
- package/dist-types/components/chat/canvas/document-canvas.d.ts +7 -0
- package/dist-types/components/chat/canvas/document-canvas.d.ts.map +1 -0
- package/dist-types/components/chat/canvas/document-field.d.ts +13 -0
- package/dist-types/components/chat/canvas/document-field.d.ts.map +1 -0
- package/dist-types/components/chat/canvas/document-viewer.d.ts +2 -0
- package/dist-types/components/chat/canvas/document-viewer.d.ts.map +1 -0
- package/dist-types/components/chat/canvas/file-attachment-button.d.ts +9 -0
- package/dist-types/components/chat/canvas/file-attachment-button.d.ts.map +1 -0
- package/dist-types/components/chat/chat-workspace.d.ts +4 -0
- package/dist-types/components/chat/chat-workspace.d.ts.map +1 -0
- package/dist-types/components/chat/message-actions.d.ts +11 -0
- package/dist-types/components/chat/message-actions.d.ts.map +1 -0
- package/dist-types/components/chat/message-item.d.ts +20 -0
- package/dist-types/components/chat/message-item.d.ts.map +1 -0
- package/dist-types/components/chat/message-queue.d.ts +15 -0
- package/dist-types/components/chat/message-queue.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-chart.d.ts +6 -0
- package/dist-types/components/chat/tools/chat-chart.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-citations.d.ts +32 -0
- package/dist-types/components/chat/tools/chat-citations.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-data-table.d.ts +14 -0
- package/dist-types/components/chat/tools/chat-data-table.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-file-export.d.ts +5 -0
- package/dist-types/components/chat/tools/chat-file-export.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-media-preview.d.ts +35 -0
- package/dist-types/components/chat/tools/chat-media-preview.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-sandbox-result.d.ts +17 -0
- package/dist-types/components/chat/tools/chat-sandbox-result.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-signature-request.d.ts +13 -0
- package/dist-types/components/chat/tools/chat-signature-request.d.ts.map +1 -0
- package/dist-types/components/chat/tools/chat-tabs.d.ts +17 -0
- package/dist-types/components/chat/tools/chat-tabs.d.ts.map +1 -0
- package/dist-types/components/chat/tools/corpus-data-result.d.ts +36 -0
- package/dist-types/components/chat/tools/corpus-data-result.d.ts.map +1 -0
- package/dist-types/components/chat/tools/knowledge-base-result.d.ts +14 -0
- package/dist-types/components/chat/tools/knowledge-base-result.d.ts.map +1 -0
- package/dist-types/components/chat/tools/visual-placement-modal.d.ts +23 -0
- package/dist-types/components/chat/tools/visual-placement-modal.d.ts.map +1 -0
- package/dist-types/components/configure/custom-model-modal.d.ts +13 -0
- package/dist-types/components/configure/custom-model-modal.d.ts.map +1 -0
- package/dist-types/components/configure/store-fields.d.ts +11 -0
- package/dist-types/components/configure/store-fields.d.ts.map +1 -0
- package/dist-types/components/data/corpus-panel.d.ts +12 -0
- package/dist-types/components/data/corpus-panel.d.ts.map +1 -0
- package/dist-types/components/data/data-entry-mode-switch.d.ts +13 -0
- package/dist-types/components/data/data-entry-mode-switch.d.ts.map +1 -0
- package/dist-types/components/data/data-primary-action.d.ts +7 -0
- package/dist-types/components/data/data-primary-action.d.ts.map +1 -0
- package/dist-types/components/data/data-workspace.d.ts +6 -0
- package/dist-types/components/data/data-workspace.d.ts.map +1 -0
- package/dist-types/components/data/groups-panel.d.ts +5 -0
- package/dist-types/components/data/groups-panel.d.ts.map +1 -0
- package/dist-types/components/data/integration-resources-panel.d.ts +9 -0
- package/dist-types/components/data/integration-resources-panel.d.ts.map +1 -0
- package/dist-types/components/data/integrations-panel.d.ts +5 -0
- package/dist-types/components/data/integrations-panel.d.ts.map +1 -0
- package/dist-types/components/data/jobs-panel.d.ts +6 -0
- package/dist-types/components/data/jobs-panel.d.ts.map +1 -0
- package/dist-types/components/data/jobs-tracking-button.d.ts +2 -0
- package/dist-types/components/data/jobs-tracking-button.d.ts.map +1 -0
- package/dist-types/components/data/live-media-progress.d.ts +9 -0
- package/dist-types/components/data/live-media-progress.d.ts.map +1 -0
- package/dist-types/components/data/media-indexing-jobs-panel.d.ts +34 -0
- package/dist-types/components/data/media-indexing-jobs-panel.d.ts.map +1 -0
- package/dist-types/components/data/media-panel.d.ts +58 -0
- package/dist-types/components/data/media-panel.d.ts.map +1 -0
- package/dist-types/components/data/notion-panel.d.ts +6 -0
- package/dist-types/components/data/notion-panel.d.ts.map +1 -0
- package/dist-types/components/data/paste-panel.d.ts +7 -0
- package/dist-types/components/data/paste-panel.d.ts.map +1 -0
- package/dist-types/components/data/project-data-page.d.ts +3 -0
- package/dist-types/components/data/project-data-page.d.ts.map +1 -0
- package/dist-types/components/data/scrape-panel.d.ts +9 -0
- package/dist-types/components/data/scrape-panel.d.ts.map +1 -0
- package/dist-types/components/data/tabular-preview.d.ts +10 -0
- package/dist-types/components/data/tabular-preview.d.ts.map +1 -0
- package/dist-types/components/data/tool-indexing-dialog.d.ts +54 -0
- package/dist-types/components/data/tool-indexing-dialog.d.ts.map +1 -0
- package/dist-types/components/data/upload-panel.d.ts +7 -0
- package/dist-types/components/data/upload-panel.d.ts.map +1 -0
- package/dist-types/components/data/web-crawler-status.d.ts +3 -0
- package/dist-types/components/data/web-crawler-status.d.ts.map +1 -0
- package/dist-types/components/projects/project-form-dialog.d.ts +10 -0
- package/dist-types/components/projects/project-form-dialog.d.ts.map +1 -0
- package/dist-types/components/projects/project-provider.d.ts +34 -0
- package/dist-types/components/projects/project-provider.d.ts.map +1 -0
- package/dist-types/components/settings/general/agent-customization-section.d.ts +2 -0
- package/dist-types/components/settings/general/agent-customization-section.d.ts.map +1 -0
- package/dist-types/components/settings/general/mcp-connections-section.d.ts +2 -0
- package/dist-types/components/settings/general/mcp-connections-section.d.ts.map +1 -0
- package/dist-types/components/settings/general/model-combobox.d.ts +24 -0
- package/dist-types/components/settings/general/model-combobox.d.ts.map +1 -0
- package/dist-types/components/settings/general/models-section.d.ts +2 -0
- package/dist-types/components/settings/general/models-section.d.ts.map +1 -0
- package/dist-types/components/settings/general/sandbox-section.d.ts +7 -0
- package/dist-types/components/settings/general/sandbox-section.d.ts.map +1 -0
- package/dist-types/components/settings/general/search-scraping-section.d.ts +2 -0
- package/dist-types/components/settings/general/search-scraping-section.d.ts.map +1 -0
- package/dist-types/components/settings/general/storage-indexing-section.d.ts +2 -0
- package/dist-types/components/settings/general/storage-indexing-section.d.ts.map +1 -0
- package/dist-types/components/ui/alert-dialog.d.ts +19 -0
- package/dist-types/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist-types/components/ui/alert.d.ts +11 -0
- package/dist-types/components/ui/alert.d.ts.map +1 -0
- package/dist-types/components/ui/badge.d.ts +8 -0
- package/dist-types/components/ui/badge.d.ts.map +1 -0
- package/dist-types/components/ui/card.d.ts +2 -0
- package/dist-types/components/ui/card.d.ts.map +1 -0
- package/dist-types/components/ui/checkbox.d.ts +4 -0
- package/dist-types/components/ui/checkbox.d.ts.map +1 -0
- package/dist-types/components/ui/collapsible.d.ts +6 -0
- package/dist-types/components/ui/collapsible.d.ts.map +1 -0
- package/dist-types/components/ui/command.d.ts +20 -0
- package/dist-types/components/ui/command.d.ts.map +1 -0
- package/dist-types/components/ui/dialog.d.ts +18 -0
- package/dist-types/components/ui/dialog.d.ts.map +1 -0
- package/dist-types/components/ui/dropdown-menu.d.ts +30 -0
- package/dist-types/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist-types/components/ui/input-group.d.ts +19 -0
- package/dist-types/components/ui/input-group.d.ts.map +1 -0
- package/dist-types/components/ui/input.d.ts +4 -0
- package/dist-types/components/ui/input.d.ts.map +1 -0
- package/dist-types/components/ui/line-tabs.d.ts +15 -0
- package/dist-types/components/ui/line-tabs.d.ts.map +1 -0
- package/dist-types/components/ui/popover.d.ts +10 -0
- package/dist-types/components/ui/popover.d.ts.map +1 -0
- package/dist-types/components/ui/progress.d.ts +8 -0
- package/dist-types/components/ui/progress.d.ts.map +1 -0
- package/dist-types/components/ui/scroll-area.d.ts +6 -0
- package/dist-types/components/ui/scroll-area.d.ts.map +1 -0
- package/dist-types/components/ui/sheet.d.ts +15 -0
- package/dist-types/components/ui/sheet.d.ts.map +1 -0
- package/dist-types/components/ui/slider.d.ts +4 -0
- package/dist-types/components/ui/slider.d.ts.map +1 -0
- package/dist-types/components/ui/switch.d.ts +6 -0
- package/dist-types/components/ui/switch.d.ts.map +1 -0
- package/dist-types/components/ui/table.d.ts +2 -0
- package/dist-types/components/ui/table.d.ts.map +1 -0
- package/dist-types/components/ui/tabs.d.ts +11 -0
- package/dist-types/components/ui/tabs.d.ts.map +1 -0
- package/dist-types/components/ui/textarea.d.ts +2 -0
- package/dist-types/components/ui/textarea.d.ts.map +1 -0
- package/dist-types/components/ui/tooltip.d.ts +7 -0
- package/dist-types/components/ui/tooltip.d.ts.map +1 -0
- package/dist-types/hooks/use-copy-to-clipboard.d.ts +5 -0
- package/dist-types/hooks/use-copy-to-clipboard.d.ts.map +1 -0
- package/dist-types/hooks/use-integration-auth.d.ts +10 -0
- package/dist-types/hooks/use-integration-auth.d.ts.map +1 -0
- package/dist-types/hooks/use-live-media-progress.d.ts +14 -0
- package/dist-types/hooks/use-live-media-progress.d.ts.map +1 -0
- package/dist-types/hooks/use-notion-auth.d.ts +9 -0
- package/dist-types/hooks/use-notion-auth.d.ts.map +1 -0
- package/dist-types/host.d.ts +20 -0
- package/dist-types/host.d.ts.map +1 -0
- package/dist-types/lib/browser-cache.d.ts +7 -0
- package/dist-types/lib/browser-cache.d.ts.map +1 -0
- package/dist-types/lib/chat/chart-config.d.ts +2 -0
- package/dist-types/lib/chat/chart-config.d.ts.map +1 -0
- package/dist-types/lib/chat/data-export.d.ts +2 -0
- package/dist-types/lib/chat/data-export.d.ts.map +1 -0
- package/dist-types/lib/chat/live-tool-progress.d.ts +44 -0
- package/dist-types/lib/chat/live-tool-progress.d.ts.map +1 -0
- package/dist-types/lib/chat/message-feedback.d.ts +2 -0
- package/dist-types/lib/chat/message-feedback.d.ts.map +1 -0
- package/dist-types/lib/chat/table-presentation.d.ts +2 -0
- package/dist-types/lib/chat/table-presentation.d.ts.map +1 -0
- package/dist-types/lib/chat/tool-output.d.ts +3 -0
- package/dist-types/lib/chat/tool-output.d.ts.map +1 -0
- package/dist-types/lib/chat-supporting-clip.d.ts +11 -0
- package/dist-types/lib/chat-supporting-clip.d.ts.map +1 -0
- package/dist-types/lib/constants/stores.d.ts +6 -0
- package/dist-types/lib/constants/stores.d.ts.map +1 -0
- package/dist-types/lib/constants/tools.d.ts +27 -0
- package/dist-types/lib/constants/tools.d.ts.map +1 -0
- package/dist-types/lib/error-formatter.d.ts +2 -0
- package/dist-types/lib/error-formatter.d.ts.map +1 -0
- package/dist-types/lib/jobs-client.d.ts +7 -0
- package/dist-types/lib/jobs-client.d.ts.map +1 -0
- package/dist-types/lib/media/pdf.d.ts +6 -0
- package/dist-types/lib/media/pdf.d.ts.map +1 -0
- package/dist-types/lib/media/progress.d.ts +61 -0
- package/dist-types/lib/media/progress.d.ts.map +1 -0
- package/dist-types/lib/media/source-selection.d.ts +10 -0
- package/dist-types/lib/media/source-selection.d.ts.map +1 -0
- package/dist-types/lib/media/tool-indexing-estimate.d.ts +13 -0
- package/dist-types/lib/media/tool-indexing-estimate.d.ts.map +1 -0
- package/dist-types/lib/media/video-intelligence-capacity.d.ts +2 -0
- package/dist-types/lib/media/video-intelligence-capacity.d.ts.map +1 -0
- package/dist-types/lib/media/video-runtime-scope.d.ts +2 -0
- package/dist-types/lib/media/video-runtime-scope.d.ts.map +1 -0
- package/dist-types/lib/shared/error-formatter.d.ts +2 -0
- package/dist-types/lib/shared/error-formatter.d.ts.map +1 -0
- package/dist-types/lib/utils.d.ts +3 -0
- package/dist-types/lib/utils.d.ts.map +1 -0
- package/dist-types/storage.d.ts +5 -0
- package/dist-types/storage.d.ts.map +1 -0
- package/dist-types/store/chat-store.d.ts +19 -0
- package/dist-types/store/chat-store.d.ts.map +1 -0
- package/dist-types/store/scrape-store.d.ts +42 -0
- package/dist-types/store/scrape-store.d.ts.map +1 -0
- package/package.json +579 -3
- package/scripts/build-assets.mjs +12 -0
- package/src/asset-data.json +1 -0
- package/src/asset-server.ts +19 -0
- package/src/components/alerts/generic-alert.tsx +76 -0
- package/src/components/chat/canvas/doc-editor-provider.tsx +338 -0
- package/src/components/chat/canvas/document-canvas.tsx +98 -0
- package/src/components/chat/canvas/document-field.tsx +167 -0
- package/src/components/chat/canvas/document-viewer.tsx +446 -0
- package/src/components/chat/canvas/file-attachment-button.tsx +88 -0
- package/src/components/chat/chat-workspace.tsx +1552 -0
- package/src/components/chat/message-actions.tsx +96 -0
- package/src/components/chat/message-item.tsx +1398 -0
- package/src/components/chat/message-queue.tsx +86 -0
- package/src/components/chat/tools/chat-chart.tsx +558 -0
- package/src/components/chat/tools/chat-citations.tsx +152 -0
- package/src/components/chat/tools/chat-data-table.tsx +373 -0
- package/src/components/chat/tools/chat-file-export.tsx +49 -0
- package/src/components/chat/tools/chat-media-preview.tsx +466 -0
- package/src/components/chat/tools/chat-sandbox-result.tsx +130 -0
- package/src/components/chat/tools/chat-signature-request.tsx +810 -0
- package/src/components/chat/tools/chat-tabs.tsx +59 -0
- package/src/components/chat/tools/corpus-data-result.tsx +194 -0
- package/src/components/chat/tools/knowledge-base-result.tsx +345 -0
- package/src/components/chat/tools/visual-placement-modal.tsx +308 -0
- package/src/components/configure/custom-model-modal.tsx +209 -0
- package/src/components/configure/store-fields.tsx +129 -0
- package/src/components/data/corpus-panel.tsx +1223 -0
- package/src/components/data/data-entry-mode-switch.tsx +53 -0
- package/src/components/data/data-primary-action.ts +6 -0
- package/src/components/data/data-workspace.tsx +623 -0
- package/src/components/data/groups-panel.tsx +530 -0
- package/src/components/data/integration-resources-panel.tsx +282 -0
- package/src/components/data/integrations-panel.tsx +392 -0
- package/src/components/data/jobs-panel.tsx +490 -0
- package/src/components/data/jobs-tracking-button.tsx +224 -0
- package/src/components/data/live-media-progress.tsx +79 -0
- package/src/components/data/media-indexing-jobs-panel.tsx +190 -0
- package/src/components/data/media-panel.tsx +2905 -0
- package/src/components/data/notion-panel.tsx +408 -0
- package/src/components/data/paste-panel.tsx +82 -0
- package/src/components/data/project-data-page.tsx +55 -0
- package/src/components/data/scrape-panel.tsx +1290 -0
- package/src/components/data/tabular-preview.tsx +205 -0
- package/src/components/data/tool-indexing-dialog.tsx +210 -0
- package/src/components/data/upload-panel.tsx +1313 -0
- package/src/components/data/web-crawler-status.tsx +132 -0
- package/src/components/projects/project-form-dialog.tsx +97 -0
- package/src/components/projects/project-provider.tsx +143 -0
- package/src/components/settings/general/agent-customization-section.tsx +620 -0
- package/src/components/settings/general/mcp-connections-section.tsx +907 -0
- package/src/components/settings/general/model-combobox.tsx +235 -0
- package/src/components/settings/general/models-section.tsx +909 -0
- package/src/components/settings/general/sandbox-section.tsx +394 -0
- package/src/components/settings/general/search-scraping-section.tsx +757 -0
- package/src/components/settings/general/storage-indexing-section.tsx +394 -0
- package/src/components/ui/alert-dialog.tsx +162 -0
- package/src/components/ui/alert.tsx +69 -0
- package/src/components/ui/badge.tsx +49 -0
- package/src/components/ui/card.tsx +9 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/collapsible.tsx +17 -0
- package/src/components/ui/command.tsx +175 -0
- package/src/components/ui/dialog.tsx +138 -0
- package/src/components/ui/dropdown-menu.tsx +267 -0
- package/src/components/ui/input-group.tsx +146 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/line-tabs.tsx +49 -0
- package/src/components/ui/popover.tsx +77 -0
- package/src/components/ui/progress.tsx +66 -0
- package/src/components/ui/scroll-area.tsx +51 -0
- package/src/components/ui/sheet.tsx +125 -0
- package/src/components/ui/slider.tsx +52 -0
- package/src/components/ui/switch.tsx +32 -0
- package/src/components/ui/table.tsx +10 -0
- package/src/components/ui/tabs.tsx +77 -0
- package/src/components/ui/textarea.tsx +1 -0
- package/src/components/ui/tooltip.tsx +54 -0
- package/src/hooks/use-copy-to-clipboard.ts +25 -0
- package/src/hooks/use-integration-auth.ts +39 -0
- package/src/hooks/use-live-media-progress.ts +71 -0
- package/src/hooks/use-notion-auth.ts +66 -0
- package/src/host.ts +55 -0
- package/src/lib/browser-cache.ts +17 -0
- package/src/lib/chat/chart-config.ts +1 -0
- package/src/lib/chat/data-export.ts +1 -0
- package/src/lib/chat/live-tool-progress.ts +69 -0
- package/src/lib/chat/message-feedback.ts +1 -0
- package/src/lib/chat/table-presentation.ts +1 -0
- package/src/lib/chat/tool-output.ts +14 -0
- package/src/lib/chat-supporting-clip.ts +16 -0
- package/src/lib/constants/stores.ts +12 -0
- package/src/lib/constants/tools.ts +178 -0
- package/src/lib/error-formatter.ts +30 -0
- package/src/lib/jobs-client.ts +27 -0
- package/src/lib/media/pdf.ts +57 -0
- package/src/lib/media/progress.ts +209 -0
- package/src/lib/media/source-selection.ts +47 -0
- package/src/lib/media/tool-indexing-estimate.ts +39 -0
- package/src/lib/media/video-intelligence-capacity.ts +1 -0
- package/src/lib/media/video-runtime-scope.ts +1 -0
- package/src/lib/shared/error-formatter.ts +1 -0
- package/src/lib/utils.ts +6 -0
- package/src/source.css +1 -0
- package/src/storage.ts +16 -0
- package/src/store/chat-store.ts +19 -0
- package/src/store/scrape-store.ts +76 -0
- package/src/styles.d.ts +1 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
|
+
|
|
6
|
+
export interface ChatTabItem {
|
|
7
|
+
label: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
content: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ChatTabsConfig {
|
|
13
|
+
tabs: ChatTabItem[];
|
|
14
|
+
defaultIndex?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Premium tabbed interface for chat tool responses.
|
|
19
|
+
* Supports optional icons per tab with a smooth animated underline.
|
|
20
|
+
*/
|
|
21
|
+
export function ChatTabs({ config }: { config: ChatTabsConfig }) {
|
|
22
|
+
const { tabs, defaultIndex = 0 } = config;
|
|
23
|
+
const [active, setActive] = useState(defaultIndex);
|
|
24
|
+
|
|
25
|
+
if (!tabs || tabs.length === 0) return null;
|
|
26
|
+
if (tabs.length === 1) return <>{tabs[0].content}</>;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className="w-full my-4 animate-in fade-in slide-in-from-bottom-2 duration-500">
|
|
30
|
+
{/* Tab bar */}
|
|
31
|
+
<div className="flex items-center gap-0.5 border-b border-border/30 px-1">
|
|
32
|
+
{tabs.map((tab, i) => (
|
|
33
|
+
<button
|
|
34
|
+
key={i}
|
|
35
|
+
type="button"
|
|
36
|
+
onClick={() => setActive(i)}
|
|
37
|
+
className={cn(
|
|
38
|
+
'relative flex items-center gap-1.5 px-3 py-2.5 text-xs font-medium transition-colors',
|
|
39
|
+
'focus:outline-none focus-visible:outline-none',
|
|
40
|
+
active === i ? 'text-foreground' : 'text-muted-foreground hover:text-foreground/70',
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
{tab.icon && <span className="shrink-0 [&_svg]:size-3.5">{tab.icon}</span>}
|
|
44
|
+
<span>{tab.label}</span>
|
|
45
|
+
{/* Animated underline */}
|
|
46
|
+
{active === i && (
|
|
47
|
+
<span className="absolute bottom-0 left-2 right-2 h-0.5 rounded-full bg-foreground animate-in fade-in zoom-in-75 duration-300" />
|
|
48
|
+
)}
|
|
49
|
+
</button>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{/* Tab content */}
|
|
54
|
+
<div key={active} className="pt-3 animate-in fade-in slide-in-from-bottom-1 duration-400">
|
|
55
|
+
{tabs[active]?.content}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { ChevronDown, Database, FileText, Globe, Upload, Table2, Image } from 'lucide-react';
|
|
5
|
+
import { ChatDataTable, type DataTableConfig } from './chat-data-table';
|
|
6
|
+
import { Card } from '../../ui/card';
|
|
7
|
+
|
|
8
|
+
interface CorpusDocumentSummary {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
source: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
charCount: number;
|
|
14
|
+
status?: string;
|
|
15
|
+
metadata?: Record<string, any>;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
content?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface CorpusSummary {
|
|
21
|
+
totalDocuments: number;
|
|
22
|
+
bySource: Record<string, number>;
|
|
23
|
+
byStatus: Record<string, number>;
|
|
24
|
+
topMetadataKeys: { key: string; count: number }[];
|
|
25
|
+
totalCharacters: number;
|
|
26
|
+
dateRange: { earliest: string; latest: string } | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface CorpusDataConfig {
|
|
30
|
+
documents: CorpusDocumentSummary[];
|
|
31
|
+
total: number;
|
|
32
|
+
summary: CorpusSummary;
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const SOURCE_ICONS: Record<string, React.ReactNode> = {
|
|
37
|
+
paste: <FileText className="size-3" />,
|
|
38
|
+
upload: <Upload className="size-3" />,
|
|
39
|
+
scrape: <Globe className="size-3" />,
|
|
40
|
+
tabular: <Table2 className="size-3" />,
|
|
41
|
+
media: <Image className="size-3" />,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const SOURCE_COLORS: Record<string, string> = {
|
|
45
|
+
paste: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
|
46
|
+
upload: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-400',
|
|
47
|
+
scrape: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400',
|
|
48
|
+
tabular: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400',
|
|
49
|
+
media: 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function formatChars(chars: number): string {
|
|
53
|
+
if (chars >= 1_000_000) return `${(chars / 1_000_000).toFixed(1)}M`;
|
|
54
|
+
if (chars >= 1_000) return `${(chars / 1_000).toFixed(1)}K`;
|
|
55
|
+
return String(chars);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function CorpusDataResult({ config }: { config: CorpusDataConfig }) {
|
|
59
|
+
const [showTable, setShowTable] = useState(false);
|
|
60
|
+
const { documents, total, summary, error } = config;
|
|
61
|
+
|
|
62
|
+
if (error) {
|
|
63
|
+
return (
|
|
64
|
+
<Card className="overflow-hidden animate-in fade-in slide-in-from-bottom-2 duration-500">
|
|
65
|
+
<div className="flex items-center gap-2 px-4 py-3 text-sm text-red-600 dark:text-red-400">
|
|
66
|
+
<Database className="size-4" />
|
|
67
|
+
<span>Failed to fetch corpus data: {error}</span>
|
|
68
|
+
</div>
|
|
69
|
+
</Card>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (summary.totalDocuments === 0) {
|
|
74
|
+
return (
|
|
75
|
+
<div className="flex items-center gap-2 px-2 py-1 text-xs text-muted-foreground animate-in fade-in slide-in-from-bottom-2 duration-500">
|
|
76
|
+
<Database className="size-3" />
|
|
77
|
+
<span>No documents found in the corpus.</span>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Build source badges
|
|
83
|
+
const sourceEntries = Object.entries(summary.bySource).sort((a, b) => b[1] - a[1]);
|
|
84
|
+
const statusEntries = Object.entries(summary.byStatus).sort((a, b) => b[1] - a[1]);
|
|
85
|
+
|
|
86
|
+
// Build table config from documents
|
|
87
|
+
const tableConfig: DataTableConfig | null =
|
|
88
|
+
documents.length > 0
|
|
89
|
+
? {
|
|
90
|
+
columns: ['title', 'source', 'status', 'charCount', 'createdAt'],
|
|
91
|
+
rows: documents.map((d) => ({
|
|
92
|
+
title: d.title,
|
|
93
|
+
source: d.source,
|
|
94
|
+
status: d.status ?? 'unindexed',
|
|
95
|
+
charCount: d.charCount,
|
|
96
|
+
createdAt: d.createdAt.split('T')[0],
|
|
97
|
+
...(d.url ? { url: d.url } : {}),
|
|
98
|
+
})),
|
|
99
|
+
totalRows: total,
|
|
100
|
+
}
|
|
101
|
+
: null;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Card className="overflow-hidden animate-in fade-in slide-in-from-bottom-2 duration-500">
|
|
105
|
+
{/* Summary header */}
|
|
106
|
+
<div className="border-b border-border/40 px-4 py-3">
|
|
107
|
+
<div className="flex items-center justify-between">
|
|
108
|
+
<div className="flex items-center gap-2">
|
|
109
|
+
<div className="flex h-6 w-6 items-center justify-center rounded-md bg-primary/10 text-primary">
|
|
110
|
+
<Database className="size-3" />
|
|
111
|
+
</div>
|
|
112
|
+
<span className="text-sm font-medium text-foreground">Corpus Overview</span>
|
|
113
|
+
<span className="rounded-full bg-secondary px-2 py-0.5 text-[11px] tabular-nums text-muted-foreground">
|
|
114
|
+
{total.toLocaleString()} {total === 1 ? 'document' : 'documents'}
|
|
115
|
+
</span>
|
|
116
|
+
</div>
|
|
117
|
+
<span className="text-[11px] tabular-nums text-muted-foreground">
|
|
118
|
+
{formatChars(summary.totalCharacters)} chars
|
|
119
|
+
</span>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{/* Source & status badges */}
|
|
123
|
+
<div className="mt-2.5 flex flex-wrap gap-1.5">
|
|
124
|
+
{sourceEntries.map(([source, count]) => (
|
|
125
|
+
<span
|
|
126
|
+
key={source}
|
|
127
|
+
className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium ${
|
|
128
|
+
SOURCE_COLORS[source] ?? 'bg-secondary text-muted-foreground'
|
|
129
|
+
}`}
|
|
130
|
+
>
|
|
131
|
+
{SOURCE_ICONS[source]}
|
|
132
|
+
{source}
|
|
133
|
+
<span className="tabular-nums font-normal opacity-70">{count}</span>
|
|
134
|
+
</span>
|
|
135
|
+
))}
|
|
136
|
+
{statusEntries.map(([status, count]) => (
|
|
137
|
+
<span
|
|
138
|
+
key={status}
|
|
139
|
+
className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium ${
|
|
140
|
+
status === 'indexed'
|
|
141
|
+
? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400'
|
|
142
|
+
: 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400'
|
|
143
|
+
}`}
|
|
144
|
+
>
|
|
145
|
+
{status}
|
|
146
|
+
<span className="tabular-nums font-normal opacity-70">{count}</span>
|
|
147
|
+
</span>
|
|
148
|
+
))}
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
{/* Metadata keys */}
|
|
152
|
+
{summary.topMetadataKeys.length > 0 && (
|
|
153
|
+
<div className="mt-2 flex flex-wrap gap-1">
|
|
154
|
+
<span className="text-[10px] text-muted-foreground/60 self-center mr-0.5">
|
|
155
|
+
metadata:
|
|
156
|
+
</span>
|
|
157
|
+
{summary.topMetadataKeys.slice(0, 8).map(({ key, count }) => (
|
|
158
|
+
<span
|
|
159
|
+
key={key}
|
|
160
|
+
className="rounded bg-secondary/60 px-1.5 py-0.5 text-[10px] text-muted-foreground"
|
|
161
|
+
>
|
|
162
|
+
{key} <span className="tabular-nums opacity-60">({count})</span>
|
|
163
|
+
</span>
|
|
164
|
+
))}
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
{/* Expandable document table */}
|
|
170
|
+
{tableConfig && (
|
|
171
|
+
<>
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
onClick={() => setShowTable((o) => !o)}
|
|
175
|
+
className="flex w-full items-center justify-between px-4 py-2 text-xs text-muted-foreground hover:bg-secondary/30 transition-colors"
|
|
176
|
+
>
|
|
177
|
+
<span>
|
|
178
|
+
{showTable ? 'Hide' : 'Show'} documents ({documents.length}
|
|
179
|
+
{total > documents.length ? ` of ${total}` : ''})
|
|
180
|
+
</span>
|
|
181
|
+
<ChevronDown
|
|
182
|
+
className={`size-3.5 transition-transform ${showTable ? 'rotate-180' : ''}`}
|
|
183
|
+
/>
|
|
184
|
+
</button>
|
|
185
|
+
{showTable && (
|
|
186
|
+
<div className="border-t border-border/40 px-3 py-3">
|
|
187
|
+
<ChatDataTable config={tableConfig} />
|
|
188
|
+
</div>
|
|
189
|
+
)}
|
|
190
|
+
</>
|
|
191
|
+
)}
|
|
192
|
+
</Card>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
ChevronDown,
|
|
6
|
+
Database,
|
|
7
|
+
ExternalLink,
|
|
8
|
+
FileText,
|
|
9
|
+
Image as ImageIcon,
|
|
10
|
+
Loader2,
|
|
11
|
+
} from 'lucide-react';
|
|
12
|
+
import { isIndeterminateProgress } from '../../../lib/chat/live-tool-progress';
|
|
13
|
+
|
|
14
|
+
function Typewriter({ text, animate }: { text: string; animate: boolean }) {
|
|
15
|
+
const [length, setLength] = useState(animate ? 0 : text.length);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!animate) {
|
|
19
|
+
setLength(text.length);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
setLength((prev) => Math.min(prev, text.length));
|
|
23
|
+
const interval = setInterval(() => {
|
|
24
|
+
setLength((prev) => {
|
|
25
|
+
if (prev >= text.length) {
|
|
26
|
+
clearInterval(interval);
|
|
27
|
+
return prev;
|
|
28
|
+
}
|
|
29
|
+
return prev + 1;
|
|
30
|
+
});
|
|
31
|
+
}, 20);
|
|
32
|
+
return () => clearInterval(interval);
|
|
33
|
+
}, [text, animate]);
|
|
34
|
+
|
|
35
|
+
return <>{text.substring(0, length)}</>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface KBHit {
|
|
39
|
+
title: string;
|
|
40
|
+
url: string;
|
|
41
|
+
score: number;
|
|
42
|
+
text: string;
|
|
43
|
+
context?: string;
|
|
44
|
+
timelineContext?: Array<{
|
|
45
|
+
role: 'before' | 'matched' | 'after';
|
|
46
|
+
text: string;
|
|
47
|
+
startSecs?: number;
|
|
48
|
+
endSecs?: number;
|
|
49
|
+
}>;
|
|
50
|
+
images?: { imageUrl: string; index: number; pageNumber?: number }[];
|
|
51
|
+
metadata?: {
|
|
52
|
+
mediaAssetId?: string;
|
|
53
|
+
mediaType?: 'image' | 'video' | 'audio';
|
|
54
|
+
fileName?: string;
|
|
55
|
+
startSecs?: number;
|
|
56
|
+
endSecs?: number;
|
|
57
|
+
images?: { imageUrl: string; index: number }[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Renders knowledge base retrieval results from tool-searchKnowledgeBase parts.
|
|
63
|
+
*/
|
|
64
|
+
export function KnowledgeBaseResult({
|
|
65
|
+
parts,
|
|
66
|
+
isShimmering,
|
|
67
|
+
activity,
|
|
68
|
+
}: {
|
|
69
|
+
parts: any[];
|
|
70
|
+
isShimmering?: boolean;
|
|
71
|
+
activity?: {
|
|
72
|
+
percent: number;
|
|
73
|
+
label: string;
|
|
74
|
+
message: string;
|
|
75
|
+
phase?: 'waking-up' | 'analyzing';
|
|
76
|
+
} | null;
|
|
77
|
+
}) {
|
|
78
|
+
const [open, setOpen] = useState(false);
|
|
79
|
+
const isRunning = parts.some((part: any) => {
|
|
80
|
+
// New format
|
|
81
|
+
if (part.type === 'tool-invocation') {
|
|
82
|
+
const state = part.toolInvocation?.state;
|
|
83
|
+
return state === 'partial-call' || state === 'call';
|
|
84
|
+
}
|
|
85
|
+
// Legacy format
|
|
86
|
+
return part.state === 'input-streaming' || part.state === 'input-available';
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Track if this component mounted while running (so we only animate new searches)
|
|
90
|
+
const [isNew] = useState(isRunning);
|
|
91
|
+
|
|
92
|
+
const query = useMemo(() => {
|
|
93
|
+
for (const part of parts) {
|
|
94
|
+
const rawArgs =
|
|
95
|
+
part.type === 'tool-invocation' ? part.toolInvocation?.args : (part.input ?? part.args);
|
|
96
|
+
if (rawArgs?.query) {
|
|
97
|
+
return rawArgs.query;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return '';
|
|
101
|
+
}, [parts]);
|
|
102
|
+
const hits = useMemo<KBHit[]>(
|
|
103
|
+
() =>
|
|
104
|
+
parts.flatMap((part: any) => {
|
|
105
|
+
const rawResult =
|
|
106
|
+
part.type === 'tool-invocation'
|
|
107
|
+
? part.toolInvocation?.result
|
|
108
|
+
: (part.output ?? part.result);
|
|
109
|
+
const result = parseToolResult(rawResult);
|
|
110
|
+
return Array.isArray(result?.hits) ? result.hits : [];
|
|
111
|
+
}),
|
|
112
|
+
[parts],
|
|
113
|
+
);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
setOpen(isRunning);
|
|
116
|
+
}, [isRunning]);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<div className="mb-0 w-full p" data-testid="chat-citations">
|
|
120
|
+
<div className="relative inline-flex items-center">
|
|
121
|
+
{isShimmering && (
|
|
122
|
+
<div className="pointer-events-none absolute inset-0 z-10 animate-pulse bg-linear-to-r from-transparent via-foreground/5 to-transparent" />
|
|
123
|
+
)}
|
|
124
|
+
<button
|
|
125
|
+
type="button"
|
|
126
|
+
onClick={() => hits.length > 0 && setOpen((o) => !o)}
|
|
127
|
+
className={`flex items-center gap-2 pr-2 py-1.5 text-xs transition-colors duration-500 rounded-md ${
|
|
128
|
+
hits.length > 0 ? 'hover:bg-muted/50 cursor-pointer' : 'cursor-default'
|
|
129
|
+
} ${isRunning ? 'text-foreground' : 'text-muted-foreground'}`}
|
|
130
|
+
>
|
|
131
|
+
{isRunning ? (
|
|
132
|
+
<Loader2 className="h-3.5 w-3.5 shrink-0 animate-spin" />
|
|
133
|
+
) : (
|
|
134
|
+
<Database className="h-3.5 w-3.5 shrink-0" />
|
|
135
|
+
)}
|
|
136
|
+
<span className="truncate max-w-62.5 sm:max-w-100">
|
|
137
|
+
{query ? (
|
|
138
|
+
<>
|
|
139
|
+
<span className="mr-1">{isRunning ? 'Searching' : 'Searched'}</span>
|
|
140
|
+
<span className="font-medium">
|
|
141
|
+
“
|
|
142
|
+
<Typewriter text={query} animate={isNew} />
|
|
143
|
+
”
|
|
144
|
+
</span>
|
|
145
|
+
</>
|
|
146
|
+
) : isRunning ? (
|
|
147
|
+
'Finding relevant sources…'
|
|
148
|
+
) : hits.length > 0 ? (
|
|
149
|
+
'Sources'
|
|
150
|
+
) : (
|
|
151
|
+
'No matching sources'
|
|
152
|
+
)}
|
|
153
|
+
</span>
|
|
154
|
+
{!isRunning && hits.length > 0 ? (
|
|
155
|
+
<span className="shrink-0 text-[10px] bg-secondary text-foreground px-1.5 py-0.5 rounded-full font-medium ml-1">
|
|
156
|
+
{hits.length} source{hits.length === 1 ? '' : 's'}
|
|
157
|
+
</span>
|
|
158
|
+
) : null}
|
|
159
|
+
{!isRunning && hits.length > 0 ? (
|
|
160
|
+
<ChevronDown
|
|
161
|
+
className={`h-3 w-3 shrink-0 transition-transform ${open ? 'rotate-180' : ''}`}
|
|
162
|
+
/>
|
|
163
|
+
) : null}
|
|
164
|
+
</button>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
{isRunning && activity ? (
|
|
168
|
+
<div
|
|
169
|
+
className="mt-2.5 max-w-2xl rounded-xl border border-emerald-500/70 bg-background px-3 py-2.5"
|
|
170
|
+
aria-live="polite"
|
|
171
|
+
data-testid="video-analysis-progress"
|
|
172
|
+
>
|
|
173
|
+
<div className="flex items-center justify-between gap-3 text-xs">
|
|
174
|
+
<span className="larkup-shimmer-text font-medium">{activity.message}</span>
|
|
175
|
+
{isIndeterminateProgress(activity.percent) ? null : (
|
|
176
|
+
<span className="shrink-0 tabular-nums text-muted-foreground">
|
|
177
|
+
{Math.max(1, Math.round(activity.percent))}%
|
|
178
|
+
</span>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
<div
|
|
182
|
+
className="mt-2 h-1.5 overflow-hidden rounded-full bg-emerald-950/10 dark:bg-emerald-100/10"
|
|
183
|
+
role="progressbar"
|
|
184
|
+
aria-label={activity.message}
|
|
185
|
+
aria-valuemin={0}
|
|
186
|
+
aria-valuemax={100}
|
|
187
|
+
{...(isIndeterminateProgress(activity.percent)
|
|
188
|
+
? {}
|
|
189
|
+
: { 'aria-valuenow': Math.max(1, Math.round(activity.percent)) })}
|
|
190
|
+
>
|
|
191
|
+
{isIndeterminateProgress(activity.percent) ? (
|
|
192
|
+
<div className="larkup-progress-shuttle h-full rounded-full bg-emerald-500" />
|
|
193
|
+
) : (
|
|
194
|
+
<div
|
|
195
|
+
className="h-full rounded-full bg-emerald-500 transition-[width] duration-700 ease-out"
|
|
196
|
+
style={{ width: `${Math.max(6, Math.min(100, activity.percent))}%` }}
|
|
197
|
+
/>
|
|
198
|
+
)}
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
) : null}
|
|
202
|
+
|
|
203
|
+
{open && hits.length > 0 ? (
|
|
204
|
+
<div
|
|
205
|
+
className="mt-2 overflow-hidden rounded-xl border border-border bg-card"
|
|
206
|
+
data-testid="citation-list"
|
|
207
|
+
>
|
|
208
|
+
{isRunning && hits.length === 0 ? (
|
|
209
|
+
<div className="flex items-center gap-2 px-3.5 py-2.5">
|
|
210
|
+
<Loader2 className="size-3 animate-spin text-muted-foreground" />
|
|
211
|
+
</div>
|
|
212
|
+
) : null}
|
|
213
|
+
{hits.slice(0, 4).map((h, i) => (
|
|
214
|
+
<div
|
|
215
|
+
key={`${h.title}-${i}`}
|
|
216
|
+
className="flex gap-3 border-b border-border/60 px-3.5 py-3 last:border-0"
|
|
217
|
+
data-testid="citation-source"
|
|
218
|
+
>
|
|
219
|
+
<SourceThumbnail hit={h} />
|
|
220
|
+
<div className="min-w-0 flex-1">
|
|
221
|
+
<div className="flex items-start justify-between gap-3">
|
|
222
|
+
<SourceTitle hit={h} />
|
|
223
|
+
{isSafeSourceUrl(h.url) ? (
|
|
224
|
+
<a
|
|
225
|
+
href={h.url}
|
|
226
|
+
target="_blank"
|
|
227
|
+
rel="noreferrer"
|
|
228
|
+
aria-label={`Open ${h.title}`}
|
|
229
|
+
className="mt-0.5 shrink-0 text-muted-foreground transition-colors hover:text-foreground"
|
|
230
|
+
>
|
|
231
|
+
<ExternalLink className="size-3.5" />
|
|
232
|
+
</a>
|
|
233
|
+
) : null}
|
|
234
|
+
</div>
|
|
235
|
+
{h.metadata?.mediaType ? (
|
|
236
|
+
<div className="mt-1.5 flex items-center gap-2 text-[11px] text-muted-foreground">
|
|
237
|
+
<span className="capitalize">{h.metadata.mediaType} source</span>
|
|
238
|
+
{Number.isFinite(h.metadata.startSecs) ? (
|
|
239
|
+
<span className="rounded-md bg-muted px-1.5 py-0.5 font-mono tabular-nums">
|
|
240
|
+
{formatTimestamp(h.metadata.startSecs!)}
|
|
241
|
+
{Number.isFinite(h.metadata.endSecs)
|
|
242
|
+
? `–${formatTimestamp(h.metadata.endSecs!)}`
|
|
243
|
+
: ''}
|
|
244
|
+
</span>
|
|
245
|
+
) : null}
|
|
246
|
+
</div>
|
|
247
|
+
) : null}
|
|
248
|
+
{contextForHit(h) ? (
|
|
249
|
+
<div className="mt-2 rounded-lg bg-muted/55 px-2.5 py-2">
|
|
250
|
+
<div className="mb-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
251
|
+
Indexed context
|
|
252
|
+
</div>
|
|
253
|
+
<p
|
|
254
|
+
className="line-clamp-4 text-xs leading-relaxed text-foreground/80"
|
|
255
|
+
dir="auto"
|
|
256
|
+
>
|
|
257
|
+
{contextForHit(h)}
|
|
258
|
+
</p>
|
|
259
|
+
</div>
|
|
260
|
+
) : null}
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
))}
|
|
264
|
+
</div>
|
|
265
|
+
) : null}
|
|
266
|
+
</div>
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function contextForHit(hit: KBHit) {
|
|
271
|
+
const direct = hit.context?.trim();
|
|
272
|
+
if (direct) return direct;
|
|
273
|
+
const matched = hit.timelineContext?.find((item) => item.role === 'matched')?.text?.trim();
|
|
274
|
+
if (matched) return matched;
|
|
275
|
+
const text = hit.text?.trim();
|
|
276
|
+
return text && !text.startsWith('Verified media evidence is available') ? text : '';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function formatTimestamp(seconds: number) {
|
|
280
|
+
const total = Math.max(0, Math.floor(seconds));
|
|
281
|
+
const hours = Math.floor(total / 3_600);
|
|
282
|
+
const minutes = Math.floor((total % 3_600) / 60);
|
|
283
|
+
const rest = total % 60;
|
|
284
|
+
return hours > 0
|
|
285
|
+
? `${hours}:${String(minutes).padStart(2, '0')}:${String(rest).padStart(2, '0')}`
|
|
286
|
+
: `${minutes}:${String(rest).padStart(2, '0')}`;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function parseToolResult(value: unknown): { hits?: KBHit[] } | null {
|
|
290
|
+
if (typeof value === 'string') {
|
|
291
|
+
try {
|
|
292
|
+
return parseToolResult(JSON.parse(value));
|
|
293
|
+
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return typeof value === 'object' && value !== null ? (value as { hits?: KBHit[] }) : null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function isSafeSourceUrl(url: string | undefined) {
|
|
301
|
+
return Boolean(url && (url.startsWith('/') || /^https?:\/\//i.test(url)));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function SourceTitle({ hit }: { hit: KBHit }) {
|
|
305
|
+
const title = hit.title || 'Untitled source';
|
|
306
|
+
const className =
|
|
307
|
+
'line-clamp-1 text-xs font-medium text-foreground transition-colors hover:text-primary hover:underline';
|
|
308
|
+
return isSafeSourceUrl(hit.url) ? (
|
|
309
|
+
<a href={hit.url} target="_blank" rel="noreferrer" className={className}>
|
|
310
|
+
{title}
|
|
311
|
+
</a>
|
|
312
|
+
) : (
|
|
313
|
+
<span className="line-clamp-1 text-xs font-medium text-foreground">{title}</span>
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function SourceThumbnail({ hit }: { hit: KBHit }) {
|
|
318
|
+
const [imageUnavailable, setImageUnavailable] = useState(false);
|
|
319
|
+
const image = (hit.images ?? hit.metadata?.images)?.find((candidate) =>
|
|
320
|
+
isSafeSourceUrl(candidate.imageUrl),
|
|
321
|
+
);
|
|
322
|
+
if (image && !imageUnavailable) {
|
|
323
|
+
return (
|
|
324
|
+
// Retrieval supplies this URL; it is never a model-suggested placeholder.
|
|
325
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
326
|
+
<img
|
|
327
|
+
src={image.imageUrl}
|
|
328
|
+
alt=""
|
|
329
|
+
className="size-11 shrink-0 rounded-md border border-border object-cover"
|
|
330
|
+
loading="lazy"
|
|
331
|
+
onError={() => setImageUnavailable(true)}
|
|
332
|
+
/>
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<div className="flex size-11 shrink-0 items-center justify-center rounded-md border border-border bg-muted/40 text-muted-foreground">
|
|
338
|
+
{hit.metadata?.mediaType === 'image' ? (
|
|
339
|
+
<ImageIcon className="size-4" />
|
|
340
|
+
) : (
|
|
341
|
+
<FileText className="size-4" />
|
|
342
|
+
)}
|
|
343
|
+
</div>
|
|
344
|
+
);
|
|
345
|
+
}
|