@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,178 @@
|
|
|
1
|
+
import { Search, Table, BarChart3, Code2, Files, FileEdit, FileDown } from 'lucide-react';
|
|
2
|
+
import type { LucideIcon } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
export type Tool = {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
icon: LucideIcon;
|
|
9
|
+
plugin?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Chat-facing behavior for every first-party tool. Keep tool progress copy and
|
|
14
|
+
* presentation decisions here so adding a tool does not require scattered
|
|
15
|
+
* name checks throughout the chat UI.
|
|
16
|
+
*/
|
|
17
|
+
export type ChatToolPlacement = 'source' | 'web-search' | 'visualization' | 'media' | 'inline';
|
|
18
|
+
|
|
19
|
+
export type ChatToolResultView =
|
|
20
|
+
| 'none'
|
|
21
|
+
| 'data-table'
|
|
22
|
+
| 'sandbox'
|
|
23
|
+
| 'corpus'
|
|
24
|
+
| 'document-edit'
|
|
25
|
+
| 'file-export'
|
|
26
|
+
| 'signature'
|
|
27
|
+
| 'image-analysis'
|
|
28
|
+
| 'media';
|
|
29
|
+
|
|
30
|
+
export interface ChatToolBehavior {
|
|
31
|
+
placement: ChatToolPlacement;
|
|
32
|
+
pendingLabel?: string;
|
|
33
|
+
resultView: ChatToolResultView;
|
|
34
|
+
compactResult?: boolean;
|
|
35
|
+
/** Keep quick operations moving without implying a measurable percentage. */
|
|
36
|
+
showProgressBar?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const CHAT_TOOL_BEHAVIORS: Record<string, ChatToolBehavior> = {
|
|
40
|
+
searchKnowledgeBase: { placement: 'source', resultView: 'none' },
|
|
41
|
+
// Renders through the generic output.ui.kind:'citations' contract
|
|
42
|
+
// (message-item.tsx / chat-citations.tsx), same as any other tool --
|
|
43
|
+
// nothing video-specific is hardcoded in the placement/resultView here.
|
|
44
|
+
queryVideoKnowledge: {
|
|
45
|
+
placement: 'inline',
|
|
46
|
+
pendingLabel: 'Reviewing the video…',
|
|
47
|
+
resultView: 'none',
|
|
48
|
+
},
|
|
49
|
+
queryVideoEvidence: {
|
|
50
|
+
placement: 'inline',
|
|
51
|
+
pendingLabel: 'Reviewing indexed video context…',
|
|
52
|
+
// Generic structured rows are rendered through ChatDataTable. Ordinary
|
|
53
|
+
// evidence results have no rows and remain citation/answer driven.
|
|
54
|
+
resultView: 'data-table',
|
|
55
|
+
compactResult: false,
|
|
56
|
+
},
|
|
57
|
+
inspectVideoKnowledge: {
|
|
58
|
+
placement: 'inline',
|
|
59
|
+
pendingLabel: 'Checking the relevant moment…',
|
|
60
|
+
resultView: 'none',
|
|
61
|
+
},
|
|
62
|
+
webSearch: { placement: 'web-search', resultView: 'none' },
|
|
63
|
+
presentMedia: { placement: 'media', resultView: 'media' },
|
|
64
|
+
queryTabularData: {
|
|
65
|
+
placement: 'inline',
|
|
66
|
+
pendingLabel: 'Checking data…',
|
|
67
|
+
resultView: 'data-table',
|
|
68
|
+
compactResult: true,
|
|
69
|
+
showProgressBar: false,
|
|
70
|
+
},
|
|
71
|
+
generateVisualization: {
|
|
72
|
+
placement: 'visualization',
|
|
73
|
+
pendingLabel: 'Preparing chart…',
|
|
74
|
+
resultView: 'none',
|
|
75
|
+
},
|
|
76
|
+
createDataExport: {
|
|
77
|
+
placement: 'inline',
|
|
78
|
+
pendingLabel: 'Preparing file…',
|
|
79
|
+
resultView: 'file-export',
|
|
80
|
+
showProgressBar: false,
|
|
81
|
+
},
|
|
82
|
+
executeAnalysis: {
|
|
83
|
+
placement: 'inline',
|
|
84
|
+
pendingLabel: 'Running analysis…',
|
|
85
|
+
resultView: 'sandbox',
|
|
86
|
+
},
|
|
87
|
+
analyzeCorpusWithCode: {
|
|
88
|
+
placement: 'inline',
|
|
89
|
+
pendingLabel: 'Analyzing documents…',
|
|
90
|
+
resultView: 'sandbox',
|
|
91
|
+
},
|
|
92
|
+
getIndexedData: {
|
|
93
|
+
placement: 'inline',
|
|
94
|
+
pendingLabel: 'Checking documents…',
|
|
95
|
+
resultView: 'corpus',
|
|
96
|
+
},
|
|
97
|
+
analyzeImageDeeply: {
|
|
98
|
+
placement: 'inline',
|
|
99
|
+
pendingLabel: 'Analyzing image…',
|
|
100
|
+
resultView: 'image-analysis',
|
|
101
|
+
},
|
|
102
|
+
fillDocumentForm: {
|
|
103
|
+
placement: 'inline',
|
|
104
|
+
pendingLabel: 'Updating document…',
|
|
105
|
+
resultView: 'document-edit',
|
|
106
|
+
},
|
|
107
|
+
editDocument: {
|
|
108
|
+
placement: 'inline',
|
|
109
|
+
pendingLabel: 'Updating document…',
|
|
110
|
+
resultView: 'document-edit',
|
|
111
|
+
},
|
|
112
|
+
requestDocumentSignature: {
|
|
113
|
+
placement: 'inline',
|
|
114
|
+
pendingLabel: 'Preparing signature…',
|
|
115
|
+
resultView: 'signature',
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const FALLBACK_CHAT_TOOL_BEHAVIOR: ChatToolBehavior = {
|
|
120
|
+
placement: 'inline',
|
|
121
|
+
pendingLabel: 'Working…',
|
|
122
|
+
resultView: 'none',
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export function getChatToolBehavior(toolId: string): ChatToolBehavior {
|
|
126
|
+
return CHAT_TOOL_BEHAVIORS[toolId] ?? FALLBACK_CHAT_TOOL_BEHAVIOR;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const BUILT_IN_TOOLS: Tool[] = [
|
|
130
|
+
{
|
|
131
|
+
id: 'searchKnowledgeBase',
|
|
132
|
+
name: 'Semantic Search',
|
|
133
|
+
description: 'Search the RAG knowledge base for text.',
|
|
134
|
+
icon: Search,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'queryTabularData',
|
|
138
|
+
name: 'Tabular Data Query',
|
|
139
|
+
description: 'Filter, group, and aggregate tabular data.',
|
|
140
|
+
icon: Table,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'generateVisualization',
|
|
144
|
+
name: 'Generate Charts',
|
|
145
|
+
description: 'Create interactive charts from Assistant results.',
|
|
146
|
+
icon: BarChart3,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 'createDataExport',
|
|
150
|
+
name: 'Export Answer',
|
|
151
|
+
description: 'Create a downloadable Excel, CSV, or PDF file from an Assistant result.',
|
|
152
|
+
icon: FileDown,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'executeAnalysis',
|
|
156
|
+
name: 'Python Sandbox',
|
|
157
|
+
description: 'Execute Python code for complex analysis.',
|
|
158
|
+
icon: Code2,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: 'getIndexedData',
|
|
162
|
+
name: 'Indexed Data',
|
|
163
|
+
description: 'List and filter source documents.',
|
|
164
|
+
icon: Files,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'analyzeCorpusWithCode',
|
|
168
|
+
name: 'Corpus Analysis',
|
|
169
|
+
description: 'Run code against the full indexed corpus.',
|
|
170
|
+
icon: Code2,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: 'fillDocumentForm',
|
|
174
|
+
name: 'Form Filler',
|
|
175
|
+
description: 'Fill forms in the active document.',
|
|
176
|
+
icon: FileEdit,
|
|
177
|
+
},
|
|
178
|
+
];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function formatErrorMessage(error: unknown): string {
|
|
2
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3
|
+
const normalized = message.toLowerCase();
|
|
4
|
+
|
|
5
|
+
// Provider SDKs sometimes echo the submitted key or a URL-encoded request
|
|
6
|
+
// URL in authentication failures. Besides being unreadable, that can expose
|
|
7
|
+
// credential material in a toast. Keep the actionable part instead.
|
|
8
|
+
if (
|
|
9
|
+
normalized.includes('authentication failed') ||
|
|
10
|
+
normalized.includes('invalid api key') ||
|
|
11
|
+
normalized.includes('invalid api_key') ||
|
|
12
|
+
normalized.includes('invalid token') ||
|
|
13
|
+
normalized.includes('unauthorized') ||
|
|
14
|
+
normalized.includes('status code 401')
|
|
15
|
+
) {
|
|
16
|
+
return 'Authentication failed. Check the API key for the selected provider.';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (message.includes('Is the docker daemon running?')) {
|
|
20
|
+
return 'Docker is not running. Please make sure the Docker daemon is started.';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (message.includes('fetch failed') || message.includes('Failed to fetch')) {
|
|
24
|
+
return 'Network error. Please check your connection and try again.';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Add more common error mappings here as needed
|
|
28
|
+
|
|
29
|
+
return message;
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { workspaceUrl, workspaceFetch as fetch } from '../host';
|
|
2
|
+
import type { CrawlJob } from '@larkup/core/types';
|
|
3
|
+
|
|
4
|
+
export interface JobsResponse {
|
|
5
|
+
jobs: CrawlJob[];
|
|
6
|
+
configured: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function fetchJobsWithSync(url: string): Promise<JobsResponse> {
|
|
10
|
+
const response = await fetch(url);
|
|
11
|
+
if (!response.ok) throw new Error('Could not load jobs.');
|
|
12
|
+
const { jobs, configured } = (await response.json()) as JobsResponse;
|
|
13
|
+
if (!Array.isArray(jobs)) throw new Error('Could not load jobs.');
|
|
14
|
+
const active = jobs.filter((job) => job.status === 'running' || job.status === 'queued');
|
|
15
|
+
if (active.length === 0) return { jobs, configured };
|
|
16
|
+
|
|
17
|
+
const advanced = await Promise.all(
|
|
18
|
+
active.map((job) =>
|
|
19
|
+
fetch(workspaceUrl(`/api/jobs/${job.id}`))
|
|
20
|
+
.then((result) => result.json())
|
|
21
|
+
.then((result) => result.job as CrawlJob)
|
|
22
|
+
.catch(() => job),
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
const advancedById = new Map(advanced.map((job) => [job.id, job]));
|
|
26
|
+
return { jobs: jobs.map((job) => advancedById.get(job.id) ?? job), configured };
|
|
27
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
2
|
+
|
|
3
|
+
export async function extractImagesFromPDF(
|
|
4
|
+
file: File,
|
|
5
|
+
): Promise<{ base64: string; pageNumber: number; index: number }[]> {
|
|
6
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
|
|
7
|
+
'pdfjs-dist/build/pdf.worker.min.mjs',
|
|
8
|
+
import.meta.url,
|
|
9
|
+
).toString();
|
|
10
|
+
|
|
11
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
12
|
+
const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(arrayBuffer) }).promise;
|
|
13
|
+
const numPages = pdf.numPages;
|
|
14
|
+
const images: { base64: string; pageNumber: number; index: number }[] = [];
|
|
15
|
+
|
|
16
|
+
let imageIndex = 0;
|
|
17
|
+
const toDataUrl = (source: HTMLCanvasElement) => {
|
|
18
|
+
const maxDimension = 1_600;
|
|
19
|
+
const scale = Math.min(1, maxDimension / Math.max(source.width, source.height));
|
|
20
|
+
if (scale === 1) return source.toDataURL('image/jpeg', 0.86);
|
|
21
|
+
|
|
22
|
+
const resized = document.createElement('canvas');
|
|
23
|
+
resized.width = Math.max(1, Math.round(source.width * scale));
|
|
24
|
+
resized.height = Math.max(1, Math.round(source.height * scale));
|
|
25
|
+
resized.getContext('2d')?.drawImage(source, 0, 0, resized.width, resized.height);
|
|
26
|
+
return resized.toDataURL('image/jpeg', 0.86);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
for (let i = 1; i <= numPages; i++) {
|
|
30
|
+
try {
|
|
31
|
+
const page = await pdf.getPage(i);
|
|
32
|
+
// A PDF page is a composite visual: diagrams are commonly vector
|
|
33
|
+
// drawings, while their caption, legend, and table may be text or
|
|
34
|
+
// separate XObjects. Indexing XObjects individually loses that context
|
|
35
|
+
// and makes image zero (often a cover) look like the best preview.
|
|
36
|
+
// One crisp rendered page preserves the complete source relationship.
|
|
37
|
+
const baseViewport = page.getViewport({ scale: 1 });
|
|
38
|
+
const desiredLongestEdge = 1_600;
|
|
39
|
+
const scale = Math.min(
|
|
40
|
+
2.5,
|
|
41
|
+
Math.max(1, desiredLongestEdge / Math.max(baseViewport.width, baseViewport.height)),
|
|
42
|
+
);
|
|
43
|
+
const viewport = page.getViewport({ scale });
|
|
44
|
+
const canvas = document.createElement('canvas');
|
|
45
|
+
canvas.width = Math.max(1, Math.round(viewport.width));
|
|
46
|
+
canvas.height = Math.max(1, Math.round(viewport.height));
|
|
47
|
+
const ctx = canvas.getContext('2d');
|
|
48
|
+
if (!ctx) continue;
|
|
49
|
+
await page.render({ canvas, viewport }).promise;
|
|
50
|
+
images.push({ base64: toDataUrl(canvas), pageNumber: i, index: imageIndex++ });
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error(`Error processing page ${i}`, err);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return images;
|
|
57
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
export interface MediaProgressStep {
|
|
2
|
+
stage: string;
|
|
3
|
+
status: 'waiting' | 'running' | 'completed' | 'skipped' | 'failed';
|
|
4
|
+
percent?: number;
|
|
5
|
+
current?: number;
|
|
6
|
+
total?: number;
|
|
7
|
+
unit?: string;
|
|
8
|
+
estimatedRemainingSeconds?: number;
|
|
9
|
+
elapsedSeconds?: number;
|
|
10
|
+
sequence?: number;
|
|
11
|
+
message?: string;
|
|
12
|
+
startedAt?: string;
|
|
13
|
+
updatedAt?: string;
|
|
14
|
+
finishedAt?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Use the current attempt rather than the original upload time after a retry. */
|
|
18
|
+
export function mediaProcessingStartedAt(asset: {
|
|
19
|
+
createdAt: string;
|
|
20
|
+
processingStartedAt?: string;
|
|
21
|
+
}): string {
|
|
22
|
+
return asset.processingStartedAt ?? asset.createdAt;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Returns the completed attempt duration when both persisted timestamps exist. */
|
|
26
|
+
export function completedMediaProcessingSeconds(asset: {
|
|
27
|
+
processingStatus: string;
|
|
28
|
+
processingStartedAt?: string;
|
|
29
|
+
processingSteps?: MediaProgressStep[];
|
|
30
|
+
}): number | null {
|
|
31
|
+
if (asset.processingStatus !== 'completed' || !asset.processingStartedAt) return null;
|
|
32
|
+
|
|
33
|
+
const startedAt = Date.parse(asset.processingStartedAt);
|
|
34
|
+
if (!Number.isFinite(startedAt)) return null;
|
|
35
|
+
|
|
36
|
+
const completedSteps =
|
|
37
|
+
asset.processingSteps
|
|
38
|
+
?.map((step) => Date.parse(step.finishedAt ?? ''))
|
|
39
|
+
.filter(Number.isFinite) ?? [];
|
|
40
|
+
if (completedSteps.length === 0) return null;
|
|
41
|
+
const finishedAt = Math.max(...completedSteps);
|
|
42
|
+
if (!Number.isFinite(finishedAt) || finishedAt < startedAt) return null;
|
|
43
|
+
return Math.round((finishedAt - startedAt) / 1_000);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const STAGE_LABELS: Record<string, string> = {
|
|
47
|
+
download: 'Download',
|
|
48
|
+
prepare: 'Cloud video preparation',
|
|
49
|
+
extract: 'Media extraction',
|
|
50
|
+
transcribe: 'Speech timeline',
|
|
51
|
+
vision: 'Visual analysis',
|
|
52
|
+
synthesize: 'Knowledge notes',
|
|
53
|
+
index: 'Search indexing',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** The most recently updated running stage is the primary visible work. */
|
|
57
|
+
export function primaryRunningMediaStep<T extends MediaProgressStep>(
|
|
58
|
+
steps: T[] | undefined,
|
|
59
|
+
): T | undefined {
|
|
60
|
+
return steps
|
|
61
|
+
?.filter((step) => step.status === 'running')
|
|
62
|
+
.reduce<T | undefined>((latest, step) => {
|
|
63
|
+
if (!latest) return step;
|
|
64
|
+
const latestAt = Date.parse(latest.updatedAt ?? latest.startedAt ?? '');
|
|
65
|
+
const stepAt = Date.parse(step.updatedAt ?? step.startedAt ?? '');
|
|
66
|
+
if (!Number.isFinite(latestAt)) return step;
|
|
67
|
+
return Number.isFinite(stepAt) && stepAt >= latestAt ? step : latest;
|
|
68
|
+
}, undefined);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function mediaStepProgress(step: MediaProgressStep | undefined): number | null {
|
|
72
|
+
if (!step) return null;
|
|
73
|
+
if (typeof step.percent === 'number' && Number.isFinite(step.percent)) {
|
|
74
|
+
return Math.max(0, Math.min(100, step.percent));
|
|
75
|
+
}
|
|
76
|
+
if (typeof step.current === 'number' && typeof step.total === 'number' && step.total > 0) {
|
|
77
|
+
return Math.max(0, Math.min(100, (step.current / step.total) * 100));
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Keep sub-percent worker movement visible without noisy trailing zeroes. */
|
|
83
|
+
export function formatMediaProgressPercent(value: number): string {
|
|
84
|
+
const bounded = Math.max(0, Math.min(100, Number.isFinite(value) ? value : 0));
|
|
85
|
+
const rounded = Math.round(bounded * 10) / 10;
|
|
86
|
+
return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Return the latest bounded worker measurement for this indexing attempt. */
|
|
90
|
+
export function smoothMediaProcessingProgress(
|
|
91
|
+
asset: {
|
|
92
|
+
processingProgress?: number;
|
|
93
|
+
processingStatus: string;
|
|
94
|
+
processingPaused?: boolean;
|
|
95
|
+
durationSecs?: number;
|
|
96
|
+
processingSteps?: MediaProgressStep[];
|
|
97
|
+
},
|
|
98
|
+
_now = Date.now(),
|
|
99
|
+
): number {
|
|
100
|
+
const reported = Math.max(0, Math.min(100, asset.processingProgress ?? 0));
|
|
101
|
+
if (asset.processingStatus === 'completed') return 100;
|
|
102
|
+
return reported;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Ease confirmed jumps and keep a slow asymptotic trickle while fresh worker
|
|
107
|
+
* heartbeats prove the job is active. It can approach, but never claim, 99%.
|
|
108
|
+
*/
|
|
109
|
+
export function advanceMediaProcessingProgress(
|
|
110
|
+
displayed: number,
|
|
111
|
+
confirmed: number,
|
|
112
|
+
elapsedMs: number,
|
|
113
|
+
workerActive = false,
|
|
114
|
+
): number {
|
|
115
|
+
const current = Math.max(0, Math.min(100, displayed));
|
|
116
|
+
const target = Math.max(0, Math.min(100, confirmed));
|
|
117
|
+
const boundedElapsed = Math.max(0, elapsedMs);
|
|
118
|
+
if (target > current) {
|
|
119
|
+
const maximumAdvance = boundedElapsed * 0.002;
|
|
120
|
+
return Math.round(Math.min(target, current + maximumAdvance) * 1_000) / 1_000;
|
|
121
|
+
}
|
|
122
|
+
if (!workerActive || current >= 99) return current;
|
|
123
|
+
const trickle = (99 - current) * (1 - Math.exp(-boundedElapsed / 1_000_000));
|
|
124
|
+
return Math.round(Math.min(99, current + trickle) * 1_000) / 1_000;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A running step without fresh worker telemetry is waiting, not progressing. */
|
|
128
|
+
export function isMediaStepTelemetryStale(
|
|
129
|
+
step: MediaProgressStep | undefined,
|
|
130
|
+
now = Date.now(),
|
|
131
|
+
maxAgeMs = 20_000,
|
|
132
|
+
): boolean {
|
|
133
|
+
if (!step || step.status !== 'running') return false;
|
|
134
|
+
const timestamp = Date.parse(step.updatedAt ?? step.startedAt ?? '');
|
|
135
|
+
return Number.isFinite(timestamp) && now - timestamp > maxAgeMs;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Reserve “Finalizing” for the last local publishing step. Visual analysis can
|
|
140
|
+
* legitimately spend time at 99% while building its search vectors, so calling
|
|
141
|
+
* that finalization would promise an imminent completion that is not true.
|
|
142
|
+
*/
|
|
143
|
+
export function isFinalizingMediaStep(step: MediaProgressStep | undefined): boolean {
|
|
144
|
+
const progress = mediaStepProgress(step);
|
|
145
|
+
return (
|
|
146
|
+
step?.status === 'running' && step.stage === 'index' && progress !== null && progress >= 98
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** A factual label for the active unit of work, separate from weighted overall progress. */
|
|
151
|
+
export function describeActiveMediaStep(step: MediaProgressStep | undefined): string | null {
|
|
152
|
+
if (!step) return null;
|
|
153
|
+
const label = STAGE_LABELS[step.stage] ?? step.stage;
|
|
154
|
+
const progress = mediaStepProgress(step);
|
|
155
|
+
const count =
|
|
156
|
+
typeof step.current === 'number' && typeof step.total === 'number' && step.total > 0
|
|
157
|
+
? `${step.current} / ${step.total}${step.unit ? ` ${step.unit}` : ''}`
|
|
158
|
+
: null;
|
|
159
|
+
if (progress === null) return `${label} · active request in progress`;
|
|
160
|
+
if (isFinalizingMediaStep(step)) {
|
|
161
|
+
return `${label} · finalizing verified results`;
|
|
162
|
+
}
|
|
163
|
+
return [label, count, `${Math.round(progress)}% this step`].filter(Boolean).join(' · ');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Estimate only countable work. A percentage-only ETA becomes misleading when
|
|
168
|
+
* a remote worker has reported an optimistic progress band but is still
|
|
169
|
+
* waiting on a model request.
|
|
170
|
+
*/
|
|
171
|
+
export function estimateMediaStepRemainingSeconds(
|
|
172
|
+
step: MediaProgressStep | undefined,
|
|
173
|
+
now = Date.now(),
|
|
174
|
+
): number | null {
|
|
175
|
+
if (
|
|
176
|
+
Number.isFinite(step?.estimatedRemainingSeconds) &&
|
|
177
|
+
(step?.estimatedRemainingSeconds ?? 0) > 5
|
|
178
|
+
) {
|
|
179
|
+
const updatedAt = Date.parse(step?.updatedAt ?? '');
|
|
180
|
+
if (!Number.isFinite(updatedAt) || isMediaStepTelemetryStale(step, now)) return null;
|
|
181
|
+
const sinceUpdate = Math.max(0, (now - updatedAt) / 1_000);
|
|
182
|
+
const remaining = Math.round((step?.estimatedRemainingSeconds ?? 0) - sinceUpdate);
|
|
183
|
+
// Never park at one second after a forecast has expired. Wait for the next
|
|
184
|
+
// measured worker update and display no ETA in the meantime.
|
|
185
|
+
return remaining > 0 ? remaining : null;
|
|
186
|
+
}
|
|
187
|
+
if (
|
|
188
|
+
!step?.startedAt ||
|
|
189
|
+
!Number.isFinite(step.current) ||
|
|
190
|
+
!Number.isFinite(step.total) ||
|
|
191
|
+
step.current === undefined ||
|
|
192
|
+
step.total === undefined ||
|
|
193
|
+
step.current < 2 ||
|
|
194
|
+
step.total <= step.current
|
|
195
|
+
) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const startedAt = new Date(step.startedAt).getTime();
|
|
200
|
+
if (!Number.isFinite(startedAt)) return null;
|
|
201
|
+
const elapsedSeconds = Math.max(0, (now - startedAt) / 1_000);
|
|
202
|
+
if (elapsedSeconds < 5) return null;
|
|
203
|
+
|
|
204
|
+
const remainingSeconds = Math.round(
|
|
205
|
+
(elapsedSeconds / step.current) * (step.total - step.current),
|
|
206
|
+
);
|
|
207
|
+
// A clearly unreasonable estimate is less useful than no estimate.
|
|
208
|
+
return remainingSeconds > 0 && remainingSeconds <= 12 * 60 * 60 ? remainingSeconds : null;
|
|
209
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface RemoteMediaEstimate {
|
|
2
|
+
originalUrl: string;
|
|
3
|
+
durationSecs?: number;
|
|
4
|
+
singleItemDurationSecs?: number;
|
|
5
|
+
singleItemUrl?: string;
|
|
6
|
+
entryCount?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function selectedRemoteDuration(
|
|
10
|
+
estimates: RemoteMediaEstimate[] | null,
|
|
11
|
+
singleItem: boolean,
|
|
12
|
+
): number {
|
|
13
|
+
return (
|
|
14
|
+
estimates?.reduce(
|
|
15
|
+
(total, estimate) =>
|
|
16
|
+
total +
|
|
17
|
+
(singleItem
|
|
18
|
+
? (estimate.singleItemDurationSecs ??
|
|
19
|
+
((estimate.entryCount ?? 1) <= 1 ? estimate.durationSecs : 0) ??
|
|
20
|
+
0)
|
|
21
|
+
: (estimate.durationSecs ?? 0)),
|
|
22
|
+
0,
|
|
23
|
+
) ?? 0
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function selectedRemoteUrls(
|
|
28
|
+
urls: string[],
|
|
29
|
+
estimates: RemoteMediaEstimate[] | null,
|
|
30
|
+
singleItem: boolean,
|
|
31
|
+
): string[] {
|
|
32
|
+
if (!singleItem) return urls;
|
|
33
|
+
const estimateByUrl = new Map(estimates?.map((estimate) => [estimate.originalUrl, estimate]));
|
|
34
|
+
return urls.map((url) => {
|
|
35
|
+
const inspectedUrl = estimateByUrl.get(url)?.singleItemUrl;
|
|
36
|
+
if (inspectedUrl) return inspectedUrl;
|
|
37
|
+
try {
|
|
38
|
+
const parsed = new URL(url);
|
|
39
|
+
if (parsed.hostname.includes('youtube.com')) {
|
|
40
|
+
parsed.searchParams.delete('list');
|
|
41
|
+
parsed.searchParams.delete('index');
|
|
42
|
+
return parsed.toString();
|
|
43
|
+
}
|
|
44
|
+
} catch {}
|
|
45
|
+
return url;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface ToolIndexingEstimateVariant {
|
|
2
|
+
processingSecondsPerSourceMinute: number;
|
|
3
|
+
maxProcessingSecondsPerSourceMinute?: number;
|
|
4
|
+
fixedOverheadSeconds?: number;
|
|
5
|
+
maxFixedOverheadSeconds?: number;
|
|
6
|
+
creditsPerSourceMinute: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function calculateToolIndexingEstimate(
|
|
10
|
+
estimate: ToolIndexingEstimateVariant | undefined,
|
|
11
|
+
sourceDurationSecs?: number,
|
|
12
|
+
) {
|
|
13
|
+
if (!estimate) return null;
|
|
14
|
+
const sourceMinutes = Math.max(0, (sourceDurationSecs ?? 0) / 60);
|
|
15
|
+
const displayDuration = sourceMinutes > 0 ? Math.max(sourceMinutes, 0.1) : 1;
|
|
16
|
+
const minimumMinutes = Math.max(
|
|
17
|
+
1,
|
|
18
|
+
Math.ceil(
|
|
19
|
+
((estimate.fixedOverheadSeconds ?? 0) +
|
|
20
|
+
estimate.processingSecondsPerSourceMinute * displayDuration) /
|
|
21
|
+
60,
|
|
22
|
+
),
|
|
23
|
+
);
|
|
24
|
+
const maximumMinutes = Math.max(
|
|
25
|
+
minimumMinutes,
|
|
26
|
+
Math.ceil(
|
|
27
|
+
((estimate.maxFixedOverheadSeconds ?? estimate.fixedOverheadSeconds ?? 0) +
|
|
28
|
+
(estimate.maxProcessingSecondsPerSourceMinute ??
|
|
29
|
+
estimate.processingSecondsPerSourceMinute) *
|
|
30
|
+
displayDuration) /
|
|
31
|
+
60,
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
return {
|
|
35
|
+
minimumMinutes,
|
|
36
|
+
maximumMinutes,
|
|
37
|
+
credits: Math.max(1, Math.ceil(estimate.creditsPerSourceMinute * displayDuration)),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@larkup/core/video-intelligence-capacity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@larkup/core/video-runtime-scope';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@larkup/core/error-formatter';
|
package/src/lib/utils.ts
ADDED
package/src/source.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@source "./**/*.{ts,tsx}";
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as idb from 'idb-keyval';
|
|
2
|
+
import { workspaceStorageScope } from './host';
|
|
3
|
+
const scoped = (key: IDBValidKey) =>
|
|
4
|
+
workspaceStorageScope() ? `${workspaceStorageScope()}:${String(key)}` : key;
|
|
5
|
+
export const get = <T = any>(key: IDBValidKey) => idb.get<T>(scoped(key));
|
|
6
|
+
export const set = <T>(key: IDBValidKey, value: T) => idb.set(scoped(key), value);
|
|
7
|
+
export const del = (key: IDBValidKey) => idb.del(scoped(key));
|
|
8
|
+
export async function keys(): Promise<IDBValidKey[]> {
|
|
9
|
+
const all = await idb.keys();
|
|
10
|
+
const prefix = workspaceStorageScope();
|
|
11
|
+
return prefix
|
|
12
|
+
? all
|
|
13
|
+
.filter((key) => typeof key === 'string' && key.startsWith(prefix + ':'))
|
|
14
|
+
.map((key) => String(key).slice(prefix.length + 1))
|
|
15
|
+
: all;
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { persist } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
interface ChatStore {
|
|
5
|
+
selectedModel: string;
|
|
6
|
+
setSelectedModel: (model: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useChatStore = create<ChatStore>()(
|
|
10
|
+
persist(
|
|
11
|
+
(set) => ({
|
|
12
|
+
selectedModel: '',
|
|
13
|
+
setSelectedModel: (model) => set({ selectedModel: model }),
|
|
14
|
+
}),
|
|
15
|
+
{
|
|
16
|
+
name: 'larkup-chat-store',
|
|
17
|
+
},
|
|
18
|
+
),
|
|
19
|
+
);
|