@agent-native/core 0.108.0 → 0.109.1
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +25 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +162 -17
- package/corpus/core/src/a2a/correlation.ts +50 -0
- package/corpus/core/src/a2a/handlers.ts +200 -14
- package/corpus/core/src/a2a/index.ts +7 -1
- package/corpus/core/src/a2a/invoke.ts +77 -1
- package/corpus/core/src/a2a/server.ts +13 -1
- package/corpus/core/src/a2a/task-store.ts +146 -6
- package/corpus/core/src/a2a/types.ts +32 -0
- package/corpus/core/src/action.ts +5 -2
- package/corpus/core/src/agent/production-agent.ts +33 -4
- package/corpus/core/src/client/AssistantChat.tsx +648 -603
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
- package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
- package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
- package/corpus/core/src/client/analytics.ts +84 -0
- package/corpus/core/src/client/chat/message-components.tsx +94 -22
- package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
- package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
- package/corpus/core/src/client/chat-thread-url.ts +11 -0
- package/corpus/core/src/client/error-capture.ts +12 -0
- package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
- package/corpus/core/src/client/session-replay.ts +31 -0
- package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
- package/corpus/core/src/db/client.ts +55 -0
- package/corpus/core/src/extensions/actions.ts +2 -14
- package/corpus/core/src/extensions/store.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +3 -0
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/observability/traces.ts +172 -19
- package/corpus/core/src/progress/actions.ts +4 -2
- package/corpus/core/src/provider-api/index.ts +205 -105
- package/corpus/core/src/scripts/call-agent.ts +190 -19
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
- package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
- package/corpus/core/src/styles/agent-conversation.css +7 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
- package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
- package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
- package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
- package/corpus/templates/analytics/AGENTS.md +22 -13
- package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
- package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
- package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
- package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
- package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
- package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
- package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
- package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
- package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/analytics/app/i18n-data.ts +134 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
- package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
- package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
- package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
- package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
- package/corpus/templates/analytics/server/lib/gong.ts +54 -66
- package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
- package/corpus/templates/analytics/server/lib/notion.ts +83 -8
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
- package/corpus/templates/analytics/server/lib/slack.ts +242 -90
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
- package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
- package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
- package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
- package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
- package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
- package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
- package/corpus/templates/clips/app/entry.client.tsx +6 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
- package/corpus/templates/clips/app/routes/record.tsx +3 -3
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
- package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
- package/corpus/templates/clips/desktop/src/app.tsx +19 -7
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
- package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
- package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
- package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
- package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
- package/corpus/templates/clips/server/plugins/auth.ts +5 -5
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
- package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
- package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
- package/corpus/templates/clips/shared/share-meta.ts +1 -1
- package/corpus/templates/content/app/entry.client.tsx +6 -1
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
- package/corpus/templates/mail/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
- package/corpus/templates/slides/.env.example +0 -1
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/DEVELOPING.md +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/actions/logo-config.ts +6 -7
- package/corpus/templates/slides/actions/search-images.ts +11 -39
- package/corpus/templates/slides/actions/search-logos.ts +5 -52
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
- package/corpus/templates/slides/app/entry.client.tsx +6 -1
- package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
- package/corpus/templates/slides/server/register-secrets.ts +30 -0
- package/dist/a2a/client.d.ts +47 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +94 -12
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/correlation.d.ts +10 -0
- package/dist/a2a/correlation.d.ts.map +1 -0
- package/dist/a2a/correlation.js +40 -0
- package/dist/a2a/correlation.js.map +1 -0
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +147 -15
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/index.d.ts +4 -4
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +2 -2
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/invoke.d.ts +29 -2
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +33 -1
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +14 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/task-store.d.ts +12 -1
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +96 -6
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +27 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +5 -2
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +14 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +19 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +158 -136
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +27 -4
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +21 -39
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-sidebar-state.d.ts +1 -0
- package/dist/client/agent-sidebar-state.d.ts.map +1 -1
- package/dist/client/agent-sidebar-state.js +4 -0
- package/dist/client/agent-sidebar-state.js.map +1 -1
- package/dist/client/analytics.d.ts +14 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +67 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +8 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +62 -19
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +6 -0
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +83 -14
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
- package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
- package/dist/client/chat-thread-url.d.ts +2 -0
- package/dist/client/chat-thread-url.d.ts.map +1 -0
- package/dist/client/chat-thread-url.js +12 -0
- package/dist/client/chat-thread-url.js.map +1 -0
- package/dist/client/error-capture.d.ts.map +1 -1
- package/dist/client/error-capture.js +7 -0
- package/dist/client/error-capture.js.map +1 -1
- package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
- package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionSlot.js +28 -3
- package/dist/client/extensions/ExtensionSlot.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/route-chunk-recovery.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery.js +14 -9
- package/dist/client/route-chunk-recovery.js.map +1 -1
- package/dist/client/session-replay.d.ts +15 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +20 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +25 -1
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +33 -0
- package/dist/db/client.js.map +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +2 -10
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/store.js +1 -1
- package/dist/extensions/store.js.map +1 -1
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +2 -2
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts +9 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +137 -19
- package/dist/observability/traces.js.map +1 -1
- package/dist/progress/actions.d.ts.map +1 -1
- package/dist/progress/actions.js +3 -2
- package/dist/progress/actions.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +91 -8
- package/dist/provider-api/index.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +140 -17
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +62 -7
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +118 -5
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-conversation.css +7 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
- package/dist/templates/default/app/i18n/de-DE.ts +20 -0
- package/dist/templates/default/app/i18n/en-US.ts +20 -0
- package/dist/templates/default/app/i18n/es-ES.ts +20 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/templates/default/app/i18n/ar-SA.ts +20 -0
- package/src/templates/default/app/i18n/de-DE.ts +20 -0
- package/src/templates/default/app/i18n/en-US.ts +20 -0
- package/src/templates/default/app/i18n/es-ES.ts +20 -0
- package/src/templates/default/app/i18n/fr-FR.ts +21 -0
- package/src/templates/default/app/i18n/hi-IN.ts +19 -0
- package/src/templates/default/app/i18n/ja-JP.ts +20 -0
- package/src/templates/default/app/i18n/ko-KR.ts +19 -0
- package/src/templates/default/app/i18n/pt-BR.ts +20 -0
- package/src/templates/default/app/i18n/zh-CN.ts +19 -0
- package/src/templates/default/app/i18n/zh-TW.ts +19 -0
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
- package/corpus/templates/analytics/server/handlers/github.ts +0 -200
- package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
- package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
- package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
- package/corpus/templates/analytics/server/lib/github.ts +0 -660
- package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
- package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
- package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
- package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
- package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
- package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
- package/corpus/templates/slides/actions/image-search.ts +0 -64
- package/corpus/templates/slides/actions/import-github.ts +0 -182
- package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
|
@@ -9,6 +9,9 @@ export type Workspace = "primary" | "secondary";
|
|
|
9
9
|
const cache = new Map<string, { data: unknown; ts: number }>();
|
|
10
10
|
const CACHE_TTL_MS = 2 * 60 * 1000; // 2 minutes
|
|
11
11
|
const MAX_CACHE = 200;
|
|
12
|
+
const MAX_CHANNEL_PAGES = 10;
|
|
13
|
+
const MAX_USER_PAGES = 10;
|
|
14
|
+
const SLACK_PAGE_SIZE = 200;
|
|
12
15
|
|
|
13
16
|
async function getToken(workspace: Workspace): Promise<string> {
|
|
14
17
|
const envKey =
|
|
@@ -131,6 +134,41 @@ export interface SlackTeamInfo {
|
|
|
131
134
|
icon?: { image_68?: string };
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
export interface SlackPaginationMetadata {
|
|
138
|
+
cursor_type: "response_metadata" | "latest_ts" | "page" | "none";
|
|
139
|
+
request_cursor?: string;
|
|
140
|
+
next_cursor?: string;
|
|
141
|
+
provider_next_cursor?: string;
|
|
142
|
+
page?: number;
|
|
143
|
+
pages?: number;
|
|
144
|
+
next_page?: number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface SlackCoverageMetadata {
|
|
148
|
+
requested: number;
|
|
149
|
+
fetched: number;
|
|
150
|
+
returned: number;
|
|
151
|
+
total?: number;
|
|
152
|
+
pages_fetched: number;
|
|
153
|
+
coverage_complete: boolean;
|
|
154
|
+
truncated: boolean;
|
|
155
|
+
truncation_reasons: string[];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface SlackAuthorCoverageMetadata {
|
|
159
|
+
requested_users: number;
|
|
160
|
+
resolved_users: number;
|
|
161
|
+
unresolved_user_ids: string[];
|
|
162
|
+
requested_bots: number;
|
|
163
|
+
resolved_bots: number;
|
|
164
|
+
unresolved_bot_ids: string[];
|
|
165
|
+
directory_pages_fetched: number;
|
|
166
|
+
directory_next_cursor?: string;
|
|
167
|
+
coverage_complete: boolean;
|
|
168
|
+
truncated: boolean;
|
|
169
|
+
truncation_reasons: string[];
|
|
170
|
+
}
|
|
171
|
+
|
|
134
172
|
// User cache (keyed by workspace + userId)
|
|
135
173
|
const userCache = new Map<string, SlackUser>();
|
|
136
174
|
|
|
@@ -165,18 +203,26 @@ export async function getTeamInfo(
|
|
|
165
203
|
}
|
|
166
204
|
}
|
|
167
205
|
|
|
168
|
-
export async function
|
|
206
|
+
export async function listChannelsWithCoverage(
|
|
169
207
|
workspace: Workspace,
|
|
170
|
-
|
|
208
|
+
requestCursor?: string,
|
|
209
|
+
): Promise<{
|
|
210
|
+
channels: SlackChannel[];
|
|
211
|
+
total: number;
|
|
212
|
+
truncated: boolean;
|
|
213
|
+
pagination: SlackPaginationMetadata;
|
|
214
|
+
coverage: SlackCoverageMetadata;
|
|
215
|
+
}> {
|
|
171
216
|
const all: SlackChannel[] = [];
|
|
172
|
-
let cursor
|
|
217
|
+
let cursor = requestCursor;
|
|
218
|
+
let pagesFetched = 0;
|
|
173
219
|
|
|
174
|
-
// Paginate through
|
|
175
|
-
for (let i = 0; i <
|
|
220
|
+
// Paginate through the bounded channel directory.
|
|
221
|
+
for (let i = 0; i < MAX_CHANNEL_PAGES; i++) {
|
|
176
222
|
const params: Record<string, string> = {
|
|
177
223
|
types: "public_channel",
|
|
178
224
|
exclude_archived: "true",
|
|
179
|
-
limit:
|
|
225
|
+
limit: String(SLACK_PAGE_SIZE),
|
|
180
226
|
};
|
|
181
227
|
if (cursor) params.cursor = cursor;
|
|
182
228
|
|
|
@@ -186,17 +232,46 @@ export async function listChannels(
|
|
|
186
232
|
}>(workspace, "conversations.list", params, !cursor); // cache first page only
|
|
187
233
|
|
|
188
234
|
all.push(...(data.channels || []));
|
|
235
|
+
pagesFetched += 1;
|
|
189
236
|
cursor = data.response_metadata?.next_cursor;
|
|
190
237
|
if (!cursor) break;
|
|
191
238
|
}
|
|
192
239
|
|
|
193
|
-
|
|
240
|
+
const truncated = Boolean(cursor);
|
|
241
|
+
return {
|
|
242
|
+
channels: all,
|
|
243
|
+
total: all.length,
|
|
244
|
+
truncated,
|
|
245
|
+
pagination: {
|
|
246
|
+
cursor_type: "response_metadata",
|
|
247
|
+
...(requestCursor ? { request_cursor: requestCursor } : {}),
|
|
248
|
+
...(cursor ? { next_cursor: cursor } : {}),
|
|
249
|
+
},
|
|
250
|
+
coverage: {
|
|
251
|
+
requested: MAX_CHANNEL_PAGES * SLACK_PAGE_SIZE,
|
|
252
|
+
fetched: all.length,
|
|
253
|
+
returned: all.length,
|
|
254
|
+
pages_fetched: pagesFetched,
|
|
255
|
+
coverage_complete: !truncated,
|
|
256
|
+
truncated,
|
|
257
|
+
truncation_reasons: truncated ? ["page_cap"] : [],
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export async function listChannels(
|
|
263
|
+
workspace: Workspace,
|
|
264
|
+
): Promise<SlackChannel[]> {
|
|
265
|
+
return (await listChannelsWithCoverage(workspace)).channels;
|
|
194
266
|
}
|
|
195
267
|
|
|
196
268
|
export interface ChannelHistoryResult {
|
|
197
269
|
messages: SlackMessage[];
|
|
198
270
|
has_more: boolean;
|
|
199
271
|
next_cursor?: string; // timestamp of last message
|
|
272
|
+
truncated: boolean;
|
|
273
|
+
pagination: SlackPaginationMetadata;
|
|
274
|
+
coverage: SlackCoverageMetadata;
|
|
200
275
|
}
|
|
201
276
|
|
|
202
277
|
export async function getChannelHistory(
|
|
@@ -215,55 +290,38 @@ export async function getChannelHistory(
|
|
|
215
290
|
const data = await slackApi<{
|
|
216
291
|
messages: SlackMessage[];
|
|
217
292
|
has_more?: boolean;
|
|
293
|
+
response_metadata?: { next_cursor?: string };
|
|
218
294
|
}>(workspace, "conversations.history", params, false);
|
|
219
295
|
const messages = data.messages || [];
|
|
296
|
+
const nextCursor =
|
|
297
|
+
messages.length > 0 ? messages[messages.length - 1].ts : undefined;
|
|
298
|
+
const providerNextCursor = data.response_metadata?.next_cursor || undefined;
|
|
299
|
+
const hasMore = Boolean(data.has_more || providerNextCursor);
|
|
220
300
|
return {
|
|
221
301
|
messages,
|
|
222
|
-
has_more:
|
|
223
|
-
next_cursor:
|
|
224
|
-
|
|
302
|
+
has_more: hasMore,
|
|
303
|
+
next_cursor: nextCursor,
|
|
304
|
+
truncated: hasMore,
|
|
305
|
+
pagination: {
|
|
306
|
+
cursor_type: "latest_ts",
|
|
307
|
+
...(cursor ? { request_cursor: cursor } : {}),
|
|
308
|
+
...(nextCursor ? { next_cursor: nextCursor } : {}),
|
|
309
|
+
...(providerNextCursor
|
|
310
|
+
? { provider_next_cursor: providerNextCursor }
|
|
311
|
+
: {}),
|
|
312
|
+
},
|
|
313
|
+
coverage: {
|
|
314
|
+
requested: Math.min(limit, SLACK_PAGE_SIZE),
|
|
315
|
+
fetched: messages.length,
|
|
316
|
+
returned: messages.length,
|
|
317
|
+
pages_fetched: 1,
|
|
318
|
+
coverage_complete: !hasMore,
|
|
319
|
+
truncated: hasMore,
|
|
320
|
+
truncation_reasons: hasMore ? ["provider_has_more"] : [],
|
|
321
|
+
},
|
|
225
322
|
};
|
|
226
323
|
} catch (err: any) {
|
|
227
324
|
if (err.message?.includes("not_in_channel")) {
|
|
228
|
-
// Try to auto-join the channel (requires channels:join scope)
|
|
229
|
-
try {
|
|
230
|
-
const token = await getToken(workspace);
|
|
231
|
-
const joinRes = await fetch(
|
|
232
|
-
"https://slack.com/api/conversations.join",
|
|
233
|
-
{
|
|
234
|
-
method: "POST",
|
|
235
|
-
headers: {
|
|
236
|
-
Authorization: `Bearer ${token}`,
|
|
237
|
-
"Content-Type": "application/json",
|
|
238
|
-
},
|
|
239
|
-
body: JSON.stringify({ channel: channelId }),
|
|
240
|
-
},
|
|
241
|
-
);
|
|
242
|
-
const joinData = await joinRes.json();
|
|
243
|
-
if (joinData.ok) {
|
|
244
|
-
// Joined successfully, retry history
|
|
245
|
-
const data = await slackApi<{
|
|
246
|
-
messages: SlackMessage[];
|
|
247
|
-
has_more?: boolean;
|
|
248
|
-
}>(
|
|
249
|
-
workspace,
|
|
250
|
-
"conversations.history",
|
|
251
|
-
{
|
|
252
|
-
channel: channelId,
|
|
253
|
-
limit: String(Math.min(limit, 200)),
|
|
254
|
-
},
|
|
255
|
-
false,
|
|
256
|
-
);
|
|
257
|
-
const msgs = data.messages || [];
|
|
258
|
-
return {
|
|
259
|
-
messages: msgs,
|
|
260
|
-
has_more: !!data.has_more,
|
|
261
|
-
next_cursor: msgs.length > 0 ? msgs[msgs.length - 1].ts : undefined,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
} catch {
|
|
265
|
-
// join failed, fall through to friendly error
|
|
266
|
-
}
|
|
267
325
|
throw new Error(
|
|
268
326
|
"Bot is not in this channel. Please invite the bot to the channel in Slack: " +
|
|
269
327
|
"open the channel, click the channel name, go to Integrations > Add apps, " +
|
|
@@ -275,28 +333,35 @@ export async function getChannelHistory(
|
|
|
275
333
|
}
|
|
276
334
|
|
|
277
335
|
export async function searchMessages(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
): Promise<{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
query,
|
|
291
|
-
count: String(Math.min(count, 100)),
|
|
292
|
-
sort: "timestamp",
|
|
293
|
-
sort_dir: "desc",
|
|
294
|
-
},
|
|
295
|
-
false,
|
|
296
|
-
);
|
|
336
|
+
_workspace: Workspace,
|
|
337
|
+
_query: string,
|
|
338
|
+
_count = 50,
|
|
339
|
+
): Promise<{
|
|
340
|
+
messages: SlackMessage[];
|
|
341
|
+
total: number;
|
|
342
|
+
unsupported: true;
|
|
343
|
+
truncated: boolean;
|
|
344
|
+
pagination: SlackPaginationMetadata;
|
|
345
|
+
coverage: SlackCoverageMetadata;
|
|
346
|
+
guidance: string;
|
|
347
|
+
}> {
|
|
297
348
|
return {
|
|
298
|
-
messages:
|
|
299
|
-
total:
|
|
349
|
+
messages: [],
|
|
350
|
+
total: 0,
|
|
351
|
+
unsupported: true,
|
|
352
|
+
truncated: true,
|
|
353
|
+
pagination: { cursor_type: "none" },
|
|
354
|
+
coverage: {
|
|
355
|
+
requested: 0,
|
|
356
|
+
fetched: 0,
|
|
357
|
+
returned: 0,
|
|
358
|
+
pages_fetched: 0,
|
|
359
|
+
coverage_complete: false,
|
|
360
|
+
truncated: true,
|
|
361
|
+
truncation_reasons: ["bot_token_global_search_unsupported"],
|
|
362
|
+
},
|
|
363
|
+
guidance:
|
|
364
|
+
"Slack search.messages is unavailable with the configured bot credential. Use conversations.history through the shared Slack corpus recipe for a known channel.",
|
|
300
365
|
};
|
|
301
366
|
}
|
|
302
367
|
|
|
@@ -304,10 +369,7 @@ export async function getUserInfo(
|
|
|
304
369
|
workspace: Workspace,
|
|
305
370
|
userId: string,
|
|
306
371
|
): Promise<SlackUser> {
|
|
307
|
-
const cacheKey =
|
|
308
|
-
`${workspace}:${userId}`,
|
|
309
|
-
workspace === "secondary" ? "SLACK_BOT_TOKEN_2" : "SLACK_BOT_TOKEN",
|
|
310
|
-
);
|
|
372
|
+
const cacheKey = slackUserCacheKey(workspace, userId);
|
|
311
373
|
const cached = userCache.get(cacheKey);
|
|
312
374
|
if (cached) return cached;
|
|
313
375
|
|
|
@@ -351,38 +413,81 @@ export async function resolveUsers(
|
|
|
351
413
|
userIds: string[],
|
|
352
414
|
messages?: SlackMessage[],
|
|
353
415
|
): Promise<Record<string, SlackUser>> {
|
|
416
|
+
return (await resolveUsersWithCoverage(workspace, userIds, messages)).users;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export async function resolveUsersWithCoverage(
|
|
420
|
+
workspace: Workspace,
|
|
421
|
+
userIds: string[],
|
|
422
|
+
messages?: SlackMessage[],
|
|
423
|
+
): Promise<{
|
|
424
|
+
users: Record<string, SlackUser>;
|
|
425
|
+
coverage: SlackAuthorCoverageMetadata;
|
|
426
|
+
}> {
|
|
354
427
|
const unique = [...new Set(userIds)];
|
|
355
428
|
const results: Record<string, SlackUser> = {};
|
|
429
|
+
const unresolvedUsers = new Set(unique);
|
|
430
|
+
let directoryPagesFetched = 0;
|
|
431
|
+
let directoryNextCursor: string | undefined;
|
|
432
|
+
let directoryError = false;
|
|
433
|
+
|
|
434
|
+
for (const id of unique) {
|
|
435
|
+
const cacheKey = slackUserCacheKey(workspace, id);
|
|
436
|
+
const cached = userCache.get(cacheKey);
|
|
437
|
+
if (!cached) continue;
|
|
438
|
+
results[id] = cached;
|
|
439
|
+
unresolvedUsers.delete(id);
|
|
440
|
+
}
|
|
356
441
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
442
|
+
try {
|
|
443
|
+
while (unresolvedUsers.size > 0 && directoryPagesFetched < MAX_USER_PAGES) {
|
|
444
|
+
const params: Record<string, string> = {
|
|
445
|
+
limit: String(SLACK_PAGE_SIZE),
|
|
446
|
+
};
|
|
447
|
+
if (directoryNextCursor) params.cursor = directoryNextCursor;
|
|
448
|
+
const data = await slackApi<{
|
|
449
|
+
members: SlackUser[];
|
|
450
|
+
response_metadata?: { next_cursor?: string };
|
|
451
|
+
}>(workspace, "users.list", params, true);
|
|
452
|
+
directoryPagesFetched += 1;
|
|
453
|
+
|
|
454
|
+
for (const user of data.members || []) {
|
|
455
|
+
userCache.set(slackUserCacheKey(workspace, user.id), user);
|
|
456
|
+
if (!unresolvedUsers.has(user.id)) continue;
|
|
457
|
+
results[user.id] = user;
|
|
458
|
+
unresolvedUsers.delete(user.id);
|
|
368
459
|
}
|
|
369
|
-
|
|
370
|
-
|
|
460
|
+
|
|
461
|
+
directoryNextCursor = data.response_metadata?.next_cursor || undefined;
|
|
462
|
+
if (!directoryNextCursor) break;
|
|
463
|
+
}
|
|
464
|
+
} catch {
|
|
465
|
+
directoryError = true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const unresolvedUserIds = [...unresolvedUsers];
|
|
469
|
+
for (const id of unresolvedUserIds) {
|
|
470
|
+
results[id] = fallbackSlackUser(id);
|
|
471
|
+
}
|
|
371
472
|
|
|
372
473
|
// Resolve bot users from messages that have bot_id but no user
|
|
474
|
+
let resolvedBots = 0;
|
|
475
|
+
const unresolvedBotIds: string[] = [];
|
|
476
|
+
const botIds: string[] = [];
|
|
373
477
|
if (messages) {
|
|
374
|
-
|
|
478
|
+
botIds.push(
|
|
375
479
|
...new Set(
|
|
376
480
|
messages
|
|
377
481
|
.filter((m) => m.bot_id && !results[m.bot_id])
|
|
378
482
|
.map((m) => m.bot_id!),
|
|
379
483
|
),
|
|
380
|
-
|
|
484
|
+
);
|
|
381
485
|
|
|
382
486
|
await Promise.all(
|
|
383
487
|
botIds.map(async (botId) => {
|
|
384
488
|
try {
|
|
385
489
|
const bot = await getBotInfo(workspace, botId);
|
|
490
|
+
resolvedBots += 1;
|
|
386
491
|
results[botId] = {
|
|
387
492
|
id: botId,
|
|
388
493
|
name: bot.name,
|
|
@@ -394,6 +499,7 @@ export async function resolveUsers(
|
|
|
394
499
|
},
|
|
395
500
|
};
|
|
396
501
|
} catch {
|
|
502
|
+
unresolvedBotIds.push(botId);
|
|
397
503
|
// Use the username from the message if available
|
|
398
504
|
const msg = messages.find((m) => m.bot_id === botId);
|
|
399
505
|
results[botId] = {
|
|
@@ -411,7 +517,53 @@ export async function resolveUsers(
|
|
|
411
517
|
);
|
|
412
518
|
}
|
|
413
519
|
|
|
414
|
-
|
|
520
|
+
const directoryTruncated =
|
|
521
|
+
unresolvedUsers.size > 0 && Boolean(directoryNextCursor);
|
|
522
|
+
const coverageComplete =
|
|
523
|
+
unresolvedUserIds.length === 0 && unresolvedBotIds.length === 0;
|
|
524
|
+
const truncationReasons = [
|
|
525
|
+
...(directoryTruncated ? ["user_directory_page_cap"] : []),
|
|
526
|
+
...(directoryError ? ["user_directory_error"] : []),
|
|
527
|
+
...(unresolvedUserIds.length > 0 && !directoryTruncated && !directoryError
|
|
528
|
+
? ["users_not_found"]
|
|
529
|
+
: []),
|
|
530
|
+
...(unresolvedBotIds.length > 0 ? ["bots_not_found"] : []),
|
|
531
|
+
];
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
users: results,
|
|
535
|
+
coverage: {
|
|
536
|
+
requested_users: unique.length,
|
|
537
|
+
resolved_users: unique.length - unresolvedUserIds.length,
|
|
538
|
+
unresolved_user_ids: unresolvedUserIds,
|
|
539
|
+
requested_bots: botIds.length,
|
|
540
|
+
resolved_bots: resolvedBots,
|
|
541
|
+
unresolved_bot_ids: unresolvedBotIds,
|
|
542
|
+
directory_pages_fetched: directoryPagesFetched,
|
|
543
|
+
...(directoryNextCursor
|
|
544
|
+
? { directory_next_cursor: directoryNextCursor }
|
|
545
|
+
: {}),
|
|
546
|
+
coverage_complete: coverageComplete,
|
|
547
|
+
truncated: !coverageComplete,
|
|
548
|
+
truncation_reasons: truncationReasons,
|
|
549
|
+
},
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function slackUserCacheKey(workspace: Workspace, userId: string): string {
|
|
554
|
+
return scopedCredentialCacheKey(
|
|
555
|
+
`${workspace}:${userId}`,
|
|
556
|
+
workspace === "secondary" ? "SLACK_BOT_TOKEN_2" : "SLACK_BOT_TOKEN",
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function fallbackSlackUser(id: string): SlackUser {
|
|
561
|
+
return {
|
|
562
|
+
id,
|
|
563
|
+
name: id,
|
|
564
|
+
real_name: id,
|
|
565
|
+
profile: { display_name: id, image_48: "", image_72: "" },
|
|
566
|
+
};
|
|
415
567
|
}
|
|
416
568
|
|
|
417
569
|
/**
|
|
@@ -687,7 +687,7 @@ export default createAgentChatPlugin({
|
|
|
687
687
|
connectorCatalog: [...ANALYTICS_CONNECTOR_CATALOG],
|
|
688
688
|
externalAgents: {
|
|
689
689
|
// Keep the direct MCP surface deliberately curated. External agents
|
|
690
|
-
// should use ask_app for multi-step investigation;
|
|
690
|
+
// should use ask_app for multi-step investigation; cataloged actions are
|
|
691
691
|
// bounded fallback reads for callers that already know what they need.
|
|
692
692
|
authenticatedReads: "off",
|
|
693
693
|
writes: "ask_app_only",
|
|
@@ -704,8 +704,8 @@ export default createAgentChatPlugin({
|
|
|
704
704
|
analyticsSourceGuidanceOpening() +
|
|
705
705
|
"DASHBOARD CREATION RULE — You may create dashboards, analyses, SQL panels, or other resources only when the user explicitly asks you to (e.g. 'build me a dashboard for...', 'create a new analysis', 'add a chart for...'). Never create any resource proactively during research, trend analysis, or answering questions. If you think a dashboard would be useful, suggest it and wait for explicit confirmation before creating anything. Never add new items to the sidebar or modify existing dashboards without an explicit user directive. " +
|
|
706
706
|
"DASHBOARD MUTATION RULE — For dashboard edits, default to `mutate-dashboard` with the typed `dashboard.*` script API so the main payload is a string and avoids native-array serialization traps. It can move panels by id, edit titles/SQL/config, insert, duplicate, remove, and patch dashboard fields in one atomic save. The script API is constrained: no variables/imports/loops/functions, only JSON-compatible arguments on documented dashboard methods. Do not count shifting `/panels/<index>` positions for ordinary dashboard edits unless the user specifically asks for low-level JSON-pointer operations. " +
|
|
707
|
-
'DASHBOARD EXTENSION BOX RULE — Analytics dashboards support extension boxes.
|
|
708
|
-
"EXTENSION DATA-REPAIR RULE — When fixing data in an existing extension-backed dashboard or migrated surface such as Risk Meeting, inspect the current dashboard and extension first, then use `update-extension` `patches`/`edits` that change only the data-loading seam. Preserve the existing layout, CSS, copy, and interactions; never reconstruct the full HTML body for a data-only fix. Full-body replacement is blocked unless `allowFullReplacement=true
|
|
707
|
+
'DASHBOARD EXTENSION BOX RULE — Analytics dashboards support extension boxes. For ordinary requests such as "put X in this dashboard," insert a `chartType: "extension"` panel with `config.extensionId`; this author-selected embed is shared with the dashboard, appears in scheduled reports, and receives dashboard/panel/current-filter context. Use `config.extensionSlotId` only when the user explicitly asks for a personal/per-viewer slot. Slot ids use `analytics.dashboard.<dashboard-id>.panel.<panel-id>` and require `add-extension-slot-target` plus `install-extension`; installs are per-user, so viewers can see different content and report identities may see an empty slot. Use `get-sql-dashboard` panel summaries to inspect an existing box. ' +
|
|
708
|
+
"EXTENSION DATA-REPAIR RULE — When fixing data in an existing extension-backed dashboard or migrated surface such as Risk Meeting, inspect the current dashboard and extension first, then use `update-extension` `patches`/`edits` that change only the data-loading seam. Preserve the existing layout, CSS, copy, and interactions; never reconstruct the full HTML body for a data-only fix. Full-body replacement is blocked unless `allowFullReplacement=true`. A request that combines a visual rewrite such as compacting, removing sections, renaming, or changing padding with a data repair is a broad rewrite; after inspecting the current extension, use `allowFullReplacement=true` for the complete replacement. If a focused edit fails, change the target instead of retrying identical arguments. " +
|
|
709
709
|
'FIRST-PARTY DASHBOARD TIME RULE — AI-generated `source: "first-party"` panels are dashboard-time-bound by default: set `config.timeScope` to `dashboard` and include a matching dashboard time predicate. `{{timeRange}}` requires a matching `filters` entry with `id: "timeRange"` and `type: "select"`; `{{<id>Start}}`/`{{<id>End}}` require a matching `type: "date-range"` filter with that id. Allowed `timeScope` values are `dashboard`, `fixed-window`, `cohort-history`, and `all-time`; use `all-time` only when the user requests full available history and put all-time, lifetime, or historical in the title or description. Server validation rejects unbound first-party SQL. ' +
|
|
710
710
|
"DASHBOARD READ RULE — `get-sql-dashboard` is compact by default: use its `panels` summaries plus `layout.panelOrder`, `layout.firstPanelIds`, and `layout.groups[].rows[].rowNumber/panelIds` for orientation and verification. Pass `includeConfig: true` only when you truly need full panel SQL/config. " +
|
|
711
711
|
'DASHBOARD REORDER RULE — For simple chart/section moves, use `mutate-dashboard` code such as `dashboard.panels(["panel-a","panel-b"]).moveToTop();`. For visible placement requests like "second row" or "next to return rates", use row-aware placement such as `dashboard.insertPanel({...}).nextTo("retention-over-time")`, `.atRow(2)`, or `dashboard.panel("panel-a").moveNextTo("panel-b")`; these keep panels in the intended rendered row and expand/rebalance that row when needed. Never count shifting `/panels/<index>` positions for ordinary \'move this chart\' requests. Use `get-sql-dashboard.layout.groups[].rows` as proof of visible row placement, not only flat `panelOrder`. ' +
|
|
@@ -1 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
requireCredential,
|
|
5
|
+
runApiHandlerWithContext,
|
|
6
|
+
} from "../../../lib/credentials";
|
|
7
|
+
import { executeProviderApiRequest } from "../../../lib/provider-api";
|
|
8
|
+
|
|
9
|
+
export default defineEventHandler((event) =>
|
|
10
|
+
runApiHandlerWithContext(event, async () => {
|
|
11
|
+
const missing = await requireCredential(event, "PYLON_API_KEY", "Pylon");
|
|
12
|
+
if (missing) return missing;
|
|
13
|
+
try {
|
|
14
|
+
const query = getQuery(event);
|
|
15
|
+
const search =
|
|
16
|
+
typeof query.query === "string" && query.query.trim()
|
|
17
|
+
? query.query
|
|
18
|
+
: undefined;
|
|
19
|
+
const result = (await executeProviderApiRequest({
|
|
20
|
+
provider: "pylon",
|
|
21
|
+
method: "GET",
|
|
22
|
+
path: "/accounts",
|
|
23
|
+
...(search ? { query: { query: search } } : {}),
|
|
24
|
+
})) as { response?: { json?: unknown } };
|
|
25
|
+
const body = result.response?.json;
|
|
26
|
+
const accounts =
|
|
27
|
+
Array.isArray(body) || !body || typeof body !== "object"
|
|
28
|
+
? Array.isArray(body)
|
|
29
|
+
? body
|
|
30
|
+
: []
|
|
31
|
+
: Array.isArray((body as { data?: unknown }).data)
|
|
32
|
+
? (body as { data: unknown[] }).data
|
|
33
|
+
: [];
|
|
34
|
+
return { accounts, total: accounts.length };
|
|
35
|
+
} catch (error) {
|
|
36
|
+
setResponseStatus(event, 500);
|
|
37
|
+
return {
|
|
38
|
+
error: error instanceof Error ? error.message : String(error),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
@@ -1 +1,71 @@
|
|
|
1
|
-
|
|
1
|
+
import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
2
|
+
|
|
3
|
+
import pylonIssues from "../../../../actions/pylon-issues";
|
|
4
|
+
import {
|
|
5
|
+
requireCredential,
|
|
6
|
+
runApiHandlerWithContext,
|
|
7
|
+
} from "../../../lib/credentials";
|
|
8
|
+
import { executeProviderApiRequest } from "../../../lib/provider-api";
|
|
9
|
+
|
|
10
|
+
function queryString(value: unknown): string | undefined {
|
|
11
|
+
return typeof value === "string" && value.trim() ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function responseItems(value: unknown): unknown[] {
|
|
15
|
+
if (Array.isArray(value)) return value;
|
|
16
|
+
if (value && typeof value === "object" && "data" in value) {
|
|
17
|
+
const data = (value as { data?: unknown }).data;
|
|
18
|
+
return Array.isArray(data) ? data : [];
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default defineEventHandler((event) =>
|
|
24
|
+
runApiHandlerWithContext(event, async () => {
|
|
25
|
+
const missing = await requireCredential(event, "PYLON_API_KEY", "Pylon");
|
|
26
|
+
if (missing) return missing;
|
|
27
|
+
try {
|
|
28
|
+
const query = getQuery(event);
|
|
29
|
+
const accountId = queryString(query.account_id);
|
|
30
|
+
const state = queryString(query.state);
|
|
31
|
+
const search = queryString(query.query);
|
|
32
|
+
|
|
33
|
+
if (accountId || state || search) {
|
|
34
|
+
const now = new Date();
|
|
35
|
+
const start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1_000);
|
|
36
|
+
const response = (await executeProviderApiRequest({
|
|
37
|
+
provider: "pylon",
|
|
38
|
+
method: "GET",
|
|
39
|
+
path: "/issues",
|
|
40
|
+
query: {
|
|
41
|
+
...(accountId ? { account_id: accountId } : {}),
|
|
42
|
+
...(state ? { state } : {}),
|
|
43
|
+
...(search ? { query: search } : {}),
|
|
44
|
+
start_time: start.toISOString(),
|
|
45
|
+
end_time: now.toISOString(),
|
|
46
|
+
},
|
|
47
|
+
})) as { response?: { json?: unknown } };
|
|
48
|
+
const issues = responseItems(response.response?.json);
|
|
49
|
+
return { issues, total: issues.length };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const days = queryString(query.days);
|
|
53
|
+
const parsedDays = days == null ? 371 : Number(days);
|
|
54
|
+
if (!Number.isInteger(parsedDays) || parsedDays < 1 || parsedDays > 730) {
|
|
55
|
+
setResponseStatus(event, 400);
|
|
56
|
+
return { error: "days must be an integer between 1 and 730" };
|
|
57
|
+
}
|
|
58
|
+
const result = await pylonIssues.run({
|
|
59
|
+
days: parsedDays,
|
|
60
|
+
pageSize: 500,
|
|
61
|
+
maxPages: 20,
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
setResponseStatus(event, 500);
|
|
66
|
+
return {
|
|
67
|
+
error: error instanceof Error ? error.message : String(error),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
resolveCredential,
|
|
7
7
|
withRequestContextFromEvent,
|
|
8
8
|
} from "../../lib/credentials";
|
|
9
|
+
import { executeProviderApiRequest } from "../../lib/provider-api";
|
|
9
10
|
import {
|
|
10
11
|
CLAY_ANALYTICS_CREDENTIAL_KEYS,
|
|
11
12
|
HUBSPOT_ANALYTICS_CREDENTIAL_KEYS,
|
|
@@ -13,6 +14,32 @@ import {
|
|
|
13
14
|
resolveAnalyticsProviderCredential,
|
|
14
15
|
} from "../../lib/provider-credentials";
|
|
15
16
|
|
|
17
|
+
type ProviderApiConnectionResponse = {
|
|
18
|
+
response?: {
|
|
19
|
+
ok?: boolean;
|
|
20
|
+
status?: number;
|
|
21
|
+
text?: string;
|
|
22
|
+
json?: unknown;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function providerApiConnectionResult(
|
|
27
|
+
provider: string,
|
|
28
|
+
result: unknown,
|
|
29
|
+
): { ok: boolean; error?: string } {
|
|
30
|
+
const response = (result as ProviderApiConnectionResponse).response;
|
|
31
|
+
if (response?.ok) return { ok: true };
|
|
32
|
+
|
|
33
|
+
const detail =
|
|
34
|
+
response?.text?.trim() ||
|
|
35
|
+
(response?.json === undefined ? "" : JSON.stringify(response.json));
|
|
36
|
+
const status = response?.status ?? "unknown";
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: `${provider} API error ${status}${detail ? `: ${detail}` : ""}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
export default defineEventHandler(async (event) => {
|
|
17
44
|
const body = await readBody(event);
|
|
18
45
|
const { source } = body as { source?: string };
|
|
@@ -66,8 +93,17 @@ export default defineEventHandler(async (event) => {
|
|
|
66
93
|
const sa = await resolveCredential("MIXPANEL_SERVICE_ACCOUNT", ctx);
|
|
67
94
|
if (!projectId || !sa)
|
|
68
95
|
return { ok: false, error: "Missing credentials" };
|
|
69
|
-
const
|
|
70
|
-
|
|
96
|
+
const result = await executeProviderApiRequest({
|
|
97
|
+
provider: "mixpanel",
|
|
98
|
+
method: "GET",
|
|
99
|
+
path: "/events/top",
|
|
100
|
+
query: {
|
|
101
|
+
type: "general",
|
|
102
|
+
limit: 1,
|
|
103
|
+
project_id: "{projectId}",
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return providerApiConnectionResult("Mixpanel", result);
|
|
71
107
|
}
|
|
72
108
|
|
|
73
109
|
case "posthog": {
|
|
@@ -75,8 +111,12 @@ export default defineEventHandler(async (event) => {
|
|
|
75
111
|
const projectId = await resolveCredential("POSTHOG_PROJECT_ID", ctx);
|
|
76
112
|
if (!apiKey || !projectId)
|
|
77
113
|
return { ok: false, error: "Missing credentials" };
|
|
78
|
-
const
|
|
79
|
-
|
|
114
|
+
const result = await executeProviderApiRequest({
|
|
115
|
+
provider: "posthog",
|
|
116
|
+
method: "GET",
|
|
117
|
+
path: "/api/projects/{projectId}/",
|
|
118
|
+
});
|
|
119
|
+
return providerApiConnectionResult("PostHog", result);
|
|
80
120
|
}
|
|
81
121
|
|
|
82
122
|
case "postgresql": {
|