@agent-native/core 0.154.5 → 0.157.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
- package/corpus/templates/analytics/actions/bigquery.ts +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
- package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/calendar/AGENTS.md +2 -0
- package/corpus/templates/calendar/DEVELOPING.md +4 -4
- package/corpus/templates/calendar/actions/get-settings.ts +4 -11
- package/corpus/templates/calendar/actions/update-availability.ts +15 -4
- package/corpus/templates/calendar/actions/update-settings.ts +15 -4
- package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
- package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
- package/corpus/templates/calendar/app/i18n-data.ts +30 -0
- package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
- package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
- package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
- package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
- package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
- package/corpus/templates/calendar/shared/api.ts +1 -0
- package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
- package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
- package/corpus/templates/calendar/shared/settings.ts +44 -0
- package/corpus/templates/clips/AGENTS.md +2 -0
- package/corpus/templates/clips/actions/add-comment.ts +5 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
- package/corpus/templates/clips/actions/update-comment.ts +9 -2
- package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
- package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
- package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
- package/corpus/templates/clips/app/root.tsx +2 -1
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
- package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +116 -19
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
- package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
- package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
- package/corpus/templates/clips/desktop/src/styles.css +117 -0
- package/corpus/templates/clips/server/db/index.ts +10 -0
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/recordings.ts +3 -1
- package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
- package/corpus/templates/clips/server/plugins/db.ts +5 -0
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
- package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
- package/corpus/templates/content/actions/add-comment.ts +2 -1
- package/corpus/templates/content/actions/update-comment.ts +1 -1
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
- package/corpus/templates/design/actions/generate-design.ts +10 -7
- package/corpus/templates/design/actions/present-design-variants.ts +35 -6
- package/corpus/templates/design/actions/run-design-audit.ts +33 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +66 -0
- package/corpus/templates/dispatch/.env.example +5 -0
- package/corpus/templates/dispatch/AGENTS.md +24 -19
- package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
- package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
- package/corpus/templates/factory/AGENTS.md +5 -1
- package/corpus/templates/factory/README.md +23 -0
- package/corpus/templates/factory/actions/view-screen.ts +17 -0
- package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
- package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
- package/corpus/templates/factory/app/routes/factory.tsx +41 -0
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
- package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
- package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
- package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
- package/corpus/templates/mail/vite.config.ts +7 -0
- package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
- package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
- package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
- package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +105 -9
- package/dist/agent/thread-data-builder.js +17 -1
- package/dist/agent/types.d.ts +9 -0
- package/dist/cli/skills-content/help.js +6 -4
- package/dist/cli/skills.js +17 -2
- package/dist/cli/workspacify.d.ts +5 -0
- package/dist/cli/workspacify.js +65 -8
- package/dist/client/AgentPanel.d.ts +5 -0
- package/dist/client/AgentPanel.js +32 -13
- package/dist/client/AssistantChat.d.ts +36 -1
- package/dist/client/AssistantChat.js +175 -110
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/active-run-state.d.ts +14 -1
- package/dist/client/active-run-state.js +0 -0
- package/dist/client/agent-chat-adapter.js +107 -5
- package/dist/client/analytics.js +9 -2
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/chat-first/apps-rail.js +9 -4
- package/dist/client/chat-first/primary-nav.d.ts +2 -1
- package/dist/client/chat-first/primary-nav.js +3 -3
- package/dist/client/chat-first/types.d.ts +5 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
- package/dist/client/markdown/InlineMarkdown.js +65 -0
- package/dist/client/markdown/index.d.ts +1 -0
- package/dist/client/markdown/index.js +1 -0
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/review/ReviewThreadPanel.js +2 -1
- package/dist/client/run-stream-ownership.d.ts +39 -0
- package/dist/client/run-stream-ownership.js +65 -0
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +10 -0
- package/dist/feature-flags/store.js +112 -1
- package/dist/guards/no-env-credentials.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/integrations/adapters/slack.js +5 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.js +3 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/resources/agents.js +40 -5
- package/dist/resources/metadata.d.ts +10 -0
- package/dist/resources/metadata.js +7 -3
- package/dist/review/actions/create-review-comment.js +1 -1
- package/dist/review/actions/reply-review-comment.js +1 -1
- package/dist/review/actions/resolve-review-thread.js +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-routes.js +32 -6
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-discovery.js +14 -3
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/core-routes-plugin.js +1 -1
- package/dist/server/identity-sso-migrations.d.ts +7 -0
- package/dist/server/identity-sso-migrations.js +36 -0
- package/dist/server/identity-sso-store.d.ts +3 -2
- package/dist/server/identity-sso-store.js +8 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +4 -0
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/dist/tracking/providers.js +13 -3
- package/dist/workspace-files/tool.js +1 -1
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +3 -2
package/corpus/README.md
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: account-health
|
|
3
|
+
description: >-
|
|
4
|
+
How to produce a trustworthy named-customer account health, QBR, renewal, or
|
|
5
|
+
contract-usage readout. Use when a prompt names an organization or account.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Account Health
|
|
9
|
+
|
|
10
|
+
Use these checks for named customer, organization, account-health, QBR,
|
|
11
|
+
renewal, risk, expansion, contract-utilization, or adoption questions. This is
|
|
12
|
+
not an ordinary metric lookup: a wrong identity or metric definition can put
|
|
13
|
+
another customer's data into a customer-facing decision.
|
|
14
|
+
|
|
15
|
+
## Identity lock
|
|
16
|
+
|
|
17
|
+
Treat an organization ID supplied in a prompt as a lookup key, not as proof that
|
|
18
|
+
the rows returned by a warehouse query belong to that customer.
|
|
19
|
+
|
|
20
|
+
1. Resolve the ID through the canonical CRM or contract source first.
|
|
21
|
+
2. Record the resolved customer name, organization ID, root organization ID,
|
|
22
|
+
and any canonical account key.
|
|
23
|
+
3. Carry the same resolved identity through every usage query and check the
|
|
24
|
+
returned rows against it.
|
|
25
|
+
4. Stop and report an identity mismatch if a result contains another customer,
|
|
26
|
+
mixed organization IDs, or an unresolved ID. Do not summarize the rows or
|
|
27
|
+
silently choose the most plausible customer.
|
|
28
|
+
|
|
29
|
+
## Source order and completeness
|
|
30
|
+
|
|
31
|
+
1. Use the catalog and organization data dictionary before writing warehouse
|
|
32
|
+
SQL. Approved definitions and saved query shapes outrank a table name that
|
|
33
|
+
merely sounds right.
|
|
34
|
+
2. Gather available CRM, contract, support, and conversation evidence. Treat
|
|
35
|
+
that context as complementary, not as a complete usage result.
|
|
36
|
+
3. For account health, product usage is mandatory: query approved definitions
|
|
37
|
+
for each requested product or feature dimension separately, using an explicit
|
|
38
|
+
window (default 90 days for adoption unless the user asks for another one).
|
|
39
|
+
4. Report source, window, filters, row counts, identity join, freshness, and
|
|
40
|
+
gaps. A missing source is a gap, not a reason to fill in a plausible value.
|
|
41
|
+
|
|
42
|
+
## Metric contracts
|
|
43
|
+
|
|
44
|
+
- **Contract metric** - distinguish the contracted measure from similarly named
|
|
45
|
+
platform, web, content, or event metrics. Do not use a familiar synonym when
|
|
46
|
+
comparing against a contract.
|
|
47
|
+
- **Completed-month usage** - “last month” excludes the current partial month.
|
|
48
|
+
Verify the month/as-of field and freshness before using a reporting table;
|
|
49
|
+
a single current-month snapshot is not last month's completed value.
|
|
50
|
+
- **Seats** - use the total distinct contracted/eligible users for the stated
|
|
51
|
+
period when comparing with a seat contract. Do not substitute DAU, WAU, or a
|
|
52
|
+
point-in-time daily active count, and label active users separately.
|
|
53
|
+
- **Capacity usage** - report actual usage, contracted capacity, and utilization.
|
|
54
|
+
Explicitly flag utilization at or above 100% as an overage risk and potential
|
|
55
|
+
renewal/expansion signal.
|
|
56
|
+
- **Adoption** - keep separate products or feature dimensions separate. Include
|
|
57
|
+
feature adoption, active-user/session counts, and last activity only when the
|
|
58
|
+
source query returns them; absence claims require complete coverage for the
|
|
59
|
+
stated window.
|
|
60
|
+
|
|
61
|
+
## Known source traps
|
|
62
|
+
|
|
63
|
+
- If a saved query or dictionary entry is marked deprecated or retired, do not
|
|
64
|
+
run it; use the current approved replacement and note the stale reference.
|
|
65
|
+
- A source that returns only one current partial-period snapshot is not proof of
|
|
66
|
+
a completed-period value. Verify the period/as-of field and freshness first.
|
|
67
|
+
- If the dictionary does not define the requested contract metric or the
|
|
68
|
+
replacement source cannot be verified, ask or report the gap instead of
|
|
69
|
+
guessing from a similarly named table.
|
|
70
|
+
|
|
71
|
+
## Answer shape
|
|
72
|
+
|
|
73
|
+
Lead with the identity check, then provide a compact table of contract versus
|
|
74
|
+
actual usage, followed by product/feature adoption signals, account context,
|
|
75
|
+
risks, and next steps. Make every number traceable to one source and explicitly
|
|
76
|
+
say when the readout is partial.
|
|
@@ -69,6 +69,9 @@ answers the question.
|
|
|
69
69
|
-- Or for TIMESTAMP columns: WHERE event_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
For account health, verify the reporting period, as-of field, and freshness.
|
|
73
|
+
Never label a current partial-month snapshot as last month's completed usage.
|
|
74
|
+
|
|
72
75
|
## Actions
|
|
73
76
|
|
|
74
77
|
| Action | Use |
|
|
@@ -29,7 +29,8 @@ For any question about a specific customer account, follow this source order:
|
|
|
29
29
|
Not every source is needed for every question — start with the primary source
|
|
30
30
|
and add secondary sources only when the question requires them. But do not
|
|
31
31
|
stop at one source for a "deep dive" — at minimum pull CRM + Gong + product
|
|
32
|
-
usage for any account health question.
|
|
32
|
+
usage for any account health question. Read `account-health` for the identity
|
|
33
|
+
lock and contract-metric rules before querying the warehouse.
|
|
33
34
|
|
|
34
35
|
## 1. Plan Before You Query (Catalog-First)
|
|
35
36
|
|
|
@@ -12,11 +12,12 @@ The analytics app connects to multiple data sources. This skill covers general p
|
|
|
12
12
|
## Approach
|
|
13
13
|
|
|
14
14
|
0. **Orient catalog-first** — before querying, consult what already exists: the injected `<data-dictionary>` and data-source status tell you which sources are configured and which table/columns/join paths to use. Use them to pick the one source that owns the fact instead of fanning out blind queries.
|
|
15
|
-
1. **
|
|
16
|
-
2. **
|
|
17
|
-
3. **
|
|
18
|
-
4. **
|
|
19
|
-
5. **
|
|
15
|
+
1. **Route named account health deliberately** — for a customer/org health, QBR, renewal, contract-utilization, risk, or adoption request, read `account-health` before writing SQL. It adds identity-lock and metric-definition checks that an ordinary lookup does not need.
|
|
16
|
+
2. **Read the relevant provider skill first** — check `.agents/skills/<provider>/SKILL.md` for table names, column mappings, auth, and gotchas. For BigQuery, read `.agents/skills/bigquery/SKILL.md` and use `search-bigquery-schema` before guessing table or column names.
|
|
17
|
+
3. **Clarify if ambiguous** — if the metric definition, date range, or grain is unclear and a wrong guess would change the numbers, use the `ask-question` clarifying tool (multiple-choice) before querying. Ask at most once per turn; skip it when the dictionary or the user already answered.
|
|
18
|
+
4. **Use existing actions or connected provider MCP tools** — call the provider action/tool with structured arguments, then filter or aggregate the returned records in your answer
|
|
19
|
+
5. **Write ad-hoc scripts** — if no existing script covers the question, create one in `actions/`
|
|
20
|
+
6. **Present data in chat** — don't just say "check the dashboard" — actually query, get the data, and present it. Only present numbers you actually retrieved; never report a value you did not query.
|
|
20
21
|
|
|
21
22
|
For events recorded by the analytics template itself via its `/track` endpoint, use `pnpm action query-agent-native-analytics --sql "SELECT ... FROM analytics_events ..."`. This includes pageviews, site/app traffic, template usage, app usage, and event counts collected by this analytics app. Pageviews and traffic can also live in GA4, BigQuery/warehouse tables, Mixpanel, PostHog, Amplitude, or another configured provider, so choose the source from the user's wording, connected-source status, existing dashboards, data dictionary, and user/org resources. Ask one concise clarification if multiple configured sources are plausible. Do not use `db-query` for data-source analysis; `db-query` is only for internal app tables and will confuse analytics questions. The shipped `agent-native-templates-first-party` SQL dashboard is the template engagement dashboard for the first-party collector source.
|
|
22
23
|
|
|
@@ -11,6 +11,8 @@ Read the relevant skill before deeper work:
|
|
|
11
11
|
- `data-querying` for source inspection, SQL generation, result handling, and
|
|
12
12
|
`/chart` embeds; `bigquery`, `hubspot`, `gong`, `prometheus` for provider
|
|
13
13
|
specifics.
|
|
14
|
+
- `account-health` for named customer health, QBR, renewal, contract usage,
|
|
15
|
+
identity, and product adoption.
|
|
14
16
|
- `cross-source-analysis` for questions spanning sources (identity stitching,
|
|
15
17
|
de-duplication).
|
|
16
18
|
- `dashboard-management` for dashboard/panel storage, layout, extensions,
|
|
@@ -64,6 +66,7 @@ Read the relevant skill before deeper work:
|
|
|
64
66
|
suggest and wait otherwise. Scope them to the question, avoid decorative
|
|
65
67
|
metrics, and never modify existing dashboards without a directive.
|
|
66
68
|
- For named account/deal deep dives, call `account-deep-dive` first.
|
|
69
|
+
- For named account health, read `account-health` before querying.
|
|
67
70
|
- When the user challenges coverage or asks why records are missing, rerun from
|
|
68
71
|
the source cohort and include the updated answer directly — never claim a
|
|
69
72
|
revision you didn't produce.
|
|
@@ -362,7 +362,7 @@ async function loadGongEvidence(options: {
|
|
|
362
362
|
|
|
363
363
|
export default defineAction({
|
|
364
364
|
description:
|
|
365
|
-
"Build a
|
|
365
|
+
"Build a bounded CRM/Gong account or deal evidence bundle from HubSpot and Gong. Use this first for named account, customer, deal, opportunity, renewal, risk, or deep-dive prompts. This is not a complete account-health result: for account health, follow it with verified product-usage queries for the resolved customer using the account-health skill.",
|
|
366
366
|
schema: z.object({
|
|
367
367
|
query: z
|
|
368
368
|
.string()
|
|
@@ -602,10 +602,11 @@ export default defineAction({
|
|
|
602
602
|
emailCount: emails.length,
|
|
603
603
|
gongCallCount: gong.calls.length,
|
|
604
604
|
transcriptCount: gong.transcripts.length,
|
|
605
|
+
productUsageIncluded: false,
|
|
605
606
|
gaps,
|
|
606
607
|
},
|
|
607
608
|
guidance:
|
|
608
|
-
"Synthesize a
|
|
609
|
+
"Synthesize a CRM/Gong deal deep dive from this evidence. Include: executive summary, company/deal overview, key contacts and roles, dated timeline, Gong conversation evidence with call dates/titles, current state and risk assessment, likely blockers, recommended next steps, and methodology/gaps. Attribute every claim to HubSpot or Gong evidence and distinguish customer statements from internal notes. This bundle does not include product usage, contract utilization, adoption, or cross-source identity validation; for account health, run the account-health checks and report those gaps until verified usage evidence is present.",
|
|
609
610
|
};
|
|
610
611
|
},
|
|
611
612
|
});
|
|
@@ -69,7 +69,7 @@ function stopForBigQueryCancellation(): never {
|
|
|
69
69
|
|
|
70
70
|
export default defineAction({
|
|
71
71
|
description:
|
|
72
|
-
"Query the user-configured BigQuery data warehouse. Use this when the user asks for warehouse SQL, BigQuery, or a data-dictionary metric/table that lives in BigQuery. If the user names a provider action such as Jira or Pylon, use that provider action first and do not use BigQuery unless the user explicitly asks for a warehouse copy. Pass standard SQL via the `sql` arg. Do NOT use `db-query` for warehouse data (it only reaches the app's own SQL database). If a query fails with a schema or SQL error (unknown dataset/table/column, syntax), treat it as a normal debugging signal: inspect the real schema with `search-bigquery-schema` (or query INFORMATION_SCHEMA), correct the query based on the error, and run it again — a few corrective attempts are expected. Surface the error to the user only if it still fails after a few attempts or is non-recoverable (missing credentials, permission, quota). Never rerun identical failing SQL, and never substitute made-up numbers for data you could not query.",
|
|
72
|
+
"Query the user-configured BigQuery data warehouse. Use this when the user asks for warehouse SQL, BigQuery, or a data-dictionary metric/table that lives in BigQuery. If the user names a provider action such as Jira or Pylon, use that provider action first and do not use BigQuery unless the user explicitly asks for a warehouse copy. For a named customer or organization ID, resolve the canonical CRM/contract identity first and verify the returned rows carry the same customer and org/root-org identifiers. For account health, distinguish completed-month usage from current partial snapshots, contract metrics from similarly named platform metrics, total distinct contracted users from DAU/WAU, and actual usage from contracted capacity. Pass standard SQL via the `sql` arg. Do NOT use `db-query` for warehouse data (it only reaches the app's own SQL database). If a query fails with a schema or SQL error (unknown dataset/table/column, syntax), treat it as a normal debugging signal: inspect the real schema with `search-bigquery-schema` (or query INFORMATION_SCHEMA), correct the query based on the error, and run it again — a few corrective attempts are expected. Surface the error to the user only if it still fails after a few attempts or is non-recoverable (missing credentials, permission, quota). Never rerun identical failing SQL, and never substitute made-up numbers for data you could not query.",
|
|
73
73
|
schema: z.object({
|
|
74
74
|
sql: z.string().describe("SQL query to execute"),
|
|
75
75
|
}),
|
|
@@ -231,6 +231,9 @@ export function formatSqlChartError(error: unknown): string {
|
|
|
231
231
|
if (/inactivity timeout|too much time has passed/i.test(readableMessage)) {
|
|
232
232
|
return "This chart took too long to load. Try again.";
|
|
233
233
|
}
|
|
234
|
+
if (/abort(?:ed|ing)?|signal is aborted/i.test(readableMessage)) {
|
|
235
|
+
return "This chart load was interrupted. Try again.";
|
|
236
|
+
}
|
|
234
237
|
if (/internal server error/i.test(readableMessage)) {
|
|
235
238
|
return "This chart could not be loaded. Try again.";
|
|
236
239
|
}
|
|
@@ -1381,7 +1384,7 @@ export function SqlChart({
|
|
|
1381
1384
|
className={`flex flex-1 flex-col items-center justify-center gap-3 px-4 ${placeholderPadY} ${placeholderMinH}`}
|
|
1382
1385
|
role="alert"
|
|
1383
1386
|
>
|
|
1384
|
-
<p className="text-center text-sm text-
|
|
1387
|
+
<p className="text-center text-sm text-destructive break-words">
|
|
1385
1388
|
{formatSqlChartError(error)}
|
|
1386
1389
|
</p>
|
|
1387
1390
|
<Button
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
20
20
|
import { cn } from "@/lib/utils";
|
|
21
21
|
|
|
22
|
+
import { formatExplorerPropertyLabel } from "../property-label";
|
|
22
23
|
import { KNOWN_PROPERTIES, ENRICHED_PROPERTY_MAP } from "../types";
|
|
23
24
|
import { useDynamicProperties } from "../use-dynamic-schema";
|
|
24
25
|
|
|
@@ -66,6 +67,11 @@ export function PropertyCombobox({
|
|
|
66
67
|
setOpen(false);
|
|
67
68
|
};
|
|
68
69
|
|
|
70
|
+
const displayLabel = useMemo(() => {
|
|
71
|
+
if (!value) return null;
|
|
72
|
+
return formatExplorerPropertyLabel(value);
|
|
73
|
+
}, [value]);
|
|
74
|
+
|
|
69
75
|
return (
|
|
70
76
|
<Popover open={open} onOpenChange={setOpen}>
|
|
71
77
|
<PopoverTrigger asChild>
|
|
@@ -77,12 +83,12 @@ export function PropertyCombobox({
|
|
|
77
83
|
size="sm"
|
|
78
84
|
>
|
|
79
85
|
<span className="truncate">
|
|
80
|
-
{
|
|
86
|
+
{displayLabel || triggerLabel || t("explorer.selectProperty")}
|
|
81
87
|
</span>
|
|
82
88
|
<IconSelector className="ml-1 h-3 w-3 shrink-0 opacity-50" />
|
|
83
89
|
</Button>
|
|
84
90
|
</PopoverTrigger>
|
|
85
|
-
<PopoverContent className="w-[
|
|
91
|
+
<PopoverContent className="w-[320px] p-0" align="start">
|
|
86
92
|
<Command shouldFilter={true}>
|
|
87
93
|
<CommandInput
|
|
88
94
|
placeholder={t("explorer.searchOrTypeProperty")}
|
|
@@ -137,7 +143,7 @@ export function PropertyCombobox({
|
|
|
137
143
|
value === prop ? "opacity-100" : "opacity-0",
|
|
138
144
|
)}
|
|
139
145
|
/>
|
|
140
|
-
{enriched?.label ?? prop}
|
|
146
|
+
{enriched?.label ?? formatExplorerPropertyLabel(prop)}
|
|
141
147
|
{enriched && (
|
|
142
148
|
<span className="ml-auto text-[9px] bg-primary/10 text-primary px-1.5 py-0.5 rounded">
|
|
143
149
|
{t("explorer.joined")}
|
|
@@ -166,7 +172,9 @@ export function PropertyCombobox({
|
|
|
166
172
|
value === p.name ? "opacity-100" : "opacity-0",
|
|
167
173
|
)}
|
|
168
174
|
/>
|
|
169
|
-
<span className="truncate">
|
|
175
|
+
<span className="truncate">
|
|
176
|
+
{formatExplorerPropertyLabel(p.name)}
|
|
177
|
+
</span>
|
|
170
178
|
<span className="ml-auto text-[10px] text-muted-foreground">
|
|
171
179
|
{p.count.toLocaleString()}
|
|
172
180
|
</span>
|
package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
20
20
|
import { cn } from "@/lib/utils";
|
|
21
21
|
|
|
22
|
+
import { formatExplorerPropertyLabel } from "../property-label";
|
|
22
23
|
import { usePropertyValues } from "../use-dynamic-schema";
|
|
23
24
|
|
|
24
25
|
interface PropertyValueComboboxProps {
|
|
@@ -61,7 +62,7 @@ export function PropertyValueCombobox({
|
|
|
61
62
|
)}
|
|
62
63
|
</Button>
|
|
63
64
|
</PopoverTrigger>
|
|
64
|
-
<PopoverContent className="w-[
|
|
65
|
+
<PopoverContent className="w-[280px] p-0" align="start">
|
|
65
66
|
<Command shouldFilter={true}>
|
|
66
67
|
<CommandInput
|
|
67
68
|
placeholder={t("explorer.searchOrTypeValue")}
|
|
@@ -96,7 +97,9 @@ export function PropertyValueCombobox({
|
|
|
96
97
|
</CommandEmpty>
|
|
97
98
|
{values.length > 0 && (
|
|
98
99
|
<CommandGroup
|
|
99
|
-
heading={t("explorer.topValuesForProperty", {
|
|
100
|
+
heading={t("explorer.topValuesForProperty", {
|
|
101
|
+
property: formatExplorerPropertyLabel(property),
|
|
102
|
+
})}
|
|
100
103
|
>
|
|
101
104
|
{values.map((v) => (
|
|
102
105
|
<CommandItem
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const PROPERTY_ACRONYMS: Record<string, string> = {
|
|
2
|
+
api: "API",
|
|
3
|
+
fbclid: "FBCLID",
|
|
4
|
+
gclid: "GCLID",
|
|
5
|
+
id: "ID",
|
|
6
|
+
url: "URL",
|
|
7
|
+
utm: "UTM",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function formatExplorerPropertyLabel(property: string): string {
|
|
11
|
+
const trimmed = property.trim();
|
|
12
|
+
if (!trimmed) return property;
|
|
13
|
+
|
|
14
|
+
const spaced = trimmed
|
|
15
|
+
.replace(/[_-]+/g, " ")
|
|
16
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
17
|
+
.replace(/\s+/g, " ")
|
|
18
|
+
.trim();
|
|
19
|
+
|
|
20
|
+
if (!spaced) return property;
|
|
21
|
+
|
|
22
|
+
return spaced
|
|
23
|
+
.split(" ")
|
|
24
|
+
.map((word, index) => {
|
|
25
|
+
const lower = word.toLowerCase();
|
|
26
|
+
return (
|
|
27
|
+
PROPERTY_ACRONYMS[lower] ??
|
|
28
|
+
(index === 0 ? lower.charAt(0).toUpperCase() + lower.slice(1) : lower)
|
|
29
|
+
);
|
|
30
|
+
})
|
|
31
|
+
.join(" ");
|
|
32
|
+
}
|
|
@@ -20,8 +20,8 @@ const DEFAULT_MAX_BATCHES_PER_SWEEP = 4;
|
|
|
20
20
|
const MAX_BATCHES_PER_SWEEP = 4;
|
|
21
21
|
const DEFAULT_PARALLELISM = 8;
|
|
22
22
|
const MAX_PARALLELISM = 8;
|
|
23
|
-
const DEFAULT_MAX_ACTIVE_SESSIONS = 80;
|
|
24
23
|
const DEFAULT_MAX_TOTAL_SESSIONS = 250;
|
|
24
|
+
const PRESSURE_RETRY_MS = 60 * 1000;
|
|
25
25
|
|
|
26
26
|
type Query =
|
|
27
27
|
| string
|
|
@@ -813,7 +813,7 @@ export async function queueFirstPartyAnalyticsBigQueryBackfill(
|
|
|
813
813
|
|
|
814
814
|
async function pressureSnapshot(
|
|
815
815
|
db: Executor,
|
|
816
|
-
): Promise<{ paused: boolean; reason?: string }> {
|
|
816
|
+
): Promise<{ paused: boolean; degraded?: boolean; reason?: string }> {
|
|
817
817
|
if (!isPostgres()) return { paused: false };
|
|
818
818
|
try {
|
|
819
819
|
const result = await db.execute({
|
|
@@ -833,15 +833,11 @@ async function pressureSnapshot(
|
|
|
833
833
|
const active = numberValue(row, "active_sessions");
|
|
834
834
|
const waiting = numberValue(row, "waiting_sessions");
|
|
835
835
|
const lockWaiters = numberValue(row, "lock_waiters");
|
|
836
|
-
const maxActive = positiveEnvNumber(
|
|
837
|
-
"ANALYTICS_BIGQUERY_BACKFILL_MAX_ACTIVE_SESSIONS",
|
|
838
|
-
DEFAULT_MAX_ACTIVE_SESSIONS,
|
|
839
|
-
);
|
|
840
836
|
const maxTotal = positiveEnvNumber(
|
|
841
837
|
"ANALYTICS_BIGQUERY_BACKFILL_MAX_TOTAL_SESSIONS",
|
|
842
838
|
DEFAULT_MAX_TOTAL_SESSIONS,
|
|
843
839
|
);
|
|
844
|
-
if (lockWaiters > 0 ||
|
|
840
|
+
if (lockWaiters > 0 || waiting >= 8 || total >= maxTotal) {
|
|
845
841
|
return {
|
|
846
842
|
paused: true,
|
|
847
843
|
reason: `database pressure: total=${total}, active=${active}, waiting=${waiting}, lockWaiters=${lockWaiters}`,
|
|
@@ -850,20 +846,51 @@ async function pressureSnapshot(
|
|
|
850
846
|
return { paused: false };
|
|
851
847
|
} catch (error) {
|
|
852
848
|
return {
|
|
853
|
-
paused:
|
|
849
|
+
paused: false,
|
|
850
|
+
degraded: true,
|
|
854
851
|
reason: `pressure probe failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
855
852
|
};
|
|
856
853
|
}
|
|
857
854
|
}
|
|
858
855
|
|
|
856
|
+
async function recordPressurePause(
|
|
857
|
+
db: Executor,
|
|
858
|
+
jobId: string | null,
|
|
859
|
+
reason: string,
|
|
860
|
+
): Promise<void> {
|
|
861
|
+
if (!jobId) return;
|
|
862
|
+
const retryAt = new Date(Date.now() + PRESSURE_RETRY_MS).toISOString();
|
|
863
|
+
await db.execute({
|
|
864
|
+
sql: `UPDATE ${JOB_TABLE}
|
|
865
|
+
SET last_error = ?, next_run_at = ?, updated_at = ?
|
|
866
|
+
WHERE id = ? AND status <> 'completed'`,
|
|
867
|
+
args: [reason.slice(0, 1_000), retryAt, new Date().toISOString(), jobId],
|
|
868
|
+
timeoutMs: 5_000,
|
|
869
|
+
maxAttempts: 1,
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
|
|
859
873
|
export async function runFirstPartyAnalyticsBigQueryBackfillOnce(): Promise<BigQueryBackfillSweepResult> {
|
|
860
874
|
if (process.env.ANALYTICS_BIGQUERY_BACKFILL_JOBS?.trim() === "0") {
|
|
861
875
|
return { status: "disabled", batches: 0, copied: 0, remaining: 0 };
|
|
862
876
|
}
|
|
863
877
|
|
|
864
878
|
const db = executor();
|
|
879
|
+
const coordinator = await getNextFirstPartyAnalyticsBigQueryBackfillJob(
|
|
880
|
+
db,
|
|
881
|
+
new Date().toISOString(),
|
|
882
|
+
);
|
|
883
|
+
if (!coordinator) {
|
|
884
|
+
return { status: "idle", batches: 0, copied: 0, remaining: 0 };
|
|
885
|
+
}
|
|
886
|
+
|
|
865
887
|
const initialPressure = await pressureSnapshot(db);
|
|
866
888
|
if (initialPressure.paused) {
|
|
889
|
+
await recordPressurePause(
|
|
890
|
+
db,
|
|
891
|
+
coordinator.id,
|
|
892
|
+
initialPressure.reason ?? "database pressure",
|
|
893
|
+
);
|
|
867
894
|
return {
|
|
868
895
|
status: "paused-pressure",
|
|
869
896
|
batches: 0,
|
|
@@ -873,21 +900,19 @@ export async function runFirstPartyAnalyticsBigQueryBackfillOnce(): Promise<BigQ
|
|
|
873
900
|
};
|
|
874
901
|
}
|
|
875
902
|
|
|
876
|
-
const coordinator = await getNextFirstPartyAnalyticsBigQueryBackfillJob(
|
|
877
|
-
db,
|
|
878
|
-
new Date().toISOString(),
|
|
879
|
-
);
|
|
880
|
-
if (!coordinator) {
|
|
881
|
-
return { status: "idle", batches: 0, copied: 0, remaining: 0 };
|
|
882
|
-
}
|
|
883
|
-
|
|
884
903
|
await ensureBackfillShards(db, coordinator);
|
|
885
904
|
|
|
886
905
|
let batches = 0;
|
|
887
906
|
let copied = 0;
|
|
907
|
+
let degraded = initialPressure.degraded === true;
|
|
888
908
|
for (let index = 0; index < maxBatchesPerSweep(); index += 1) {
|
|
889
909
|
const pressure = await pressureSnapshot(db);
|
|
890
910
|
if (pressure.paused) {
|
|
911
|
+
await recordPressurePause(
|
|
912
|
+
db,
|
|
913
|
+
coordinator.id,
|
|
914
|
+
pressure.reason ?? "database pressure",
|
|
915
|
+
);
|
|
891
916
|
return {
|
|
892
917
|
status: "paused-pressure",
|
|
893
918
|
batches,
|
|
@@ -896,10 +921,11 @@ export async function runFirstPartyAnalyticsBigQueryBackfillOnce(): Promise<BigQ
|
|
|
896
921
|
reason: pressure.reason,
|
|
897
922
|
};
|
|
898
923
|
}
|
|
924
|
+
degraded ||= pressure.degraded === true;
|
|
899
925
|
|
|
900
926
|
const claimed = (
|
|
901
927
|
await Promise.all(
|
|
902
|
-
Array.from({ length: parallelism() }, () =>
|
|
928
|
+
Array.from({ length: degraded ? 1 : parallelism() }, () =>
|
|
903
929
|
claimNextShard(db, coordinator.id, new Date().toISOString()),
|
|
904
930
|
),
|
|
905
931
|
)
|
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
const DATA_DICTIONARY_KEY_PREFIX = "data-dict-";
|
|
12
12
|
const MAX_QUERY_LENGTH = 12_000;
|
|
13
13
|
const MAX_CATALOG_DASHBOARD_HYDRATION = 24;
|
|
14
|
+
const RETIRED_CATALOG_STATES = new Set([
|
|
15
|
+
"deprecated",
|
|
16
|
+
"obsolete",
|
|
17
|
+
"removed",
|
|
18
|
+
"retired",
|
|
19
|
+
]);
|
|
14
20
|
const STOP_WORDS = new Set([
|
|
15
21
|
"a",
|
|
16
22
|
"all",
|
|
@@ -61,6 +67,15 @@ const STOP_WORDS = new Set([
|
|
|
61
67
|
type DictionaryEntry = Record<string, unknown>;
|
|
62
68
|
type DashboardPanel = Record<string, unknown>;
|
|
63
69
|
|
|
70
|
+
function isRetiredCatalogReference(value: Record<string, unknown>): boolean {
|
|
71
|
+
if (value.deprecated === true) return true;
|
|
72
|
+
return [value.status, value.lifecycle, value.state].some(
|
|
73
|
+
(candidate) =>
|
|
74
|
+
typeof candidate === "string" &&
|
|
75
|
+
RETIRED_CATALOG_STATES.has(candidate.trim().toLowerCase()),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
64
79
|
export type AnalyticsQueryCatalogCandidate =
|
|
65
80
|
| {
|
|
66
81
|
kind: "dashboard-panel";
|
|
@@ -296,6 +311,7 @@ function dashboardPanelCandidates(args: {
|
|
|
296
311
|
const wantsDemo = /\bdemo\b|node exporter/i.test(args.search);
|
|
297
312
|
|
|
298
313
|
return panels.flatMap((panel) => {
|
|
314
|
+
if (isRetiredCatalogReference(panel)) return [];
|
|
299
315
|
// 38k of the ~39k indexed panels are clones of the demo Node Exporter dashboard.
|
|
300
316
|
// They drown real saved work and are never the answer to a real data question.
|
|
301
317
|
if (!wantsDemo && text(panel.source) === "demo") return [];
|
|
@@ -391,6 +407,7 @@ function dictionaryCandidates(
|
|
|
391
407
|
search: string,
|
|
392
408
|
): AnalyticsQueryCatalogCandidate[] {
|
|
393
409
|
return entries.flatMap((entry) => {
|
|
410
|
+
if (isRetiredCatalogReference(entry)) return [];
|
|
394
411
|
const { score, matchedTerms } = matchScore(search, [
|
|
395
412
|
{ value: entry.metric, weight: 28 },
|
|
396
413
|
{ value: entry.commonQuestions, weight: 16 },
|
|
@@ -105,6 +105,9 @@ function hasPartialDashboardBuild(
|
|
|
105
105
|
export const BOUNDED_STRUCTURED_LOOKUP_GUIDANCE =
|
|
106
106
|
"BOUNDED STRUCTURED LOOKUP FAST PATH — Treat existing analytics work like an engineer treats existing code: grep before writing. For an ordinary count, aggregate, grouped metric, trend, or record lookup, first call `search-analytics-query-catalog` once with focused metric/entity terms. It searches accessible dashboard names, chart titles/descriptions/saved queries, shipped dashboard patterns, and data-dictionary definitions together. Prefer the strongest approved dictionary or saved-chart match, preserve its source and business logic, adapt only the requested filters and explicit time window, then run one bounded query against that source. A user-named source wins, but still use a matching saved definition when it supplies the source's proven query shape. If there is no useful match, inspect only the most likely source schema or ask one clarification; do not fan out across providers. Do not separately list every dashboard, call data-source status, browse the whole dictionary, load provider catalogs/corpus tools, or query a second source after a strong match. Once the query succeeds, answer immediately with its source, time window, filters, row count, and only necessary caveats. Do not enrich, cross-check, retry, or add breakdowns unless the user requested them, the first query failed, or its result conflicts with the known definition. The words `all`, `total`, or `exact` in a structured aggregate do not by themselves make it a corpus investigation. Never repeat an identical invalid or failed tool call; correct its arguments once or surface the error. This does not waive the real-data requirement: never answer from a guess, stale value, or unverified result. ";
|
|
107
107
|
|
|
108
|
+
export const ANALYTICS_ACCOUNT_HEALTH_GUIDANCE =
|
|
109
|
+
"ACCOUNT HEALTH / CUSTOMER SCOPE GUARD — Use this for a named customer, organization ID, account-health, QBR, renewal, contract-usage, risk, or adoption request. Treat a prompt-supplied org ID as a lookup key, not proof of row ownership: resolve it against canonical account data first, carry the resolved customer name plus organization/root-organization identifiers through every usage query, and stop if results contain a different customer, mixed IDs, or an unresolved identity. Use the account-health skill. Account health is incomplete until verified usage queries cover each requested product or feature dimension separately. Before warehouse SQL, use the catalog/dictionary and schema metadata. Do not run definitions marked deprecated or retired, or use a source whose freshness cannot be verified; use the current approved definition instead. Do not call a current partial-period snapshot a completed period without proving the period/as-of row and freshness. Distinguish contract metrics from similarly named platform metrics, total distinct contracted users from DAU/WAU, and actual usage from contracted capacity. Always surface utilization at or above 100%, report adoption window and coverage, and state gaps instead of inferring them. ";
|
|
110
|
+
|
|
108
111
|
export const DASHBOARD_REFERENCE_GUIDANCE =
|
|
109
112
|
"DASHBOARD REFERENCE DISCOVERY — When the user asks to replicate, clone, or adapt an existing dashboard, this branch takes precedence over the ordinary metric fast path: call `search-dashboard-references` with focused terms before creating, editing, or querying anything. It searches accessible active saved dashboard ids, names, descriptions, and serialized config with bounded SQL wildcard matches, including legacy saved dashboards. Treat each result as a reference to inspect with `get-sql-dashboard` when `kind` is `sql` or `get-explorer-dashboard` when `kind` is `explorer`, not as proof that its source is authoritative for the new request. Do not automatically route a replication request to first-party Analytics or copy its source semantics without checking the user's requested provider and scope. ";
|
|
110
113
|
|
|
@@ -156,6 +159,7 @@ export function analyticsSourceGuidanceOpening(): string {
|
|
|
156
159
|
NON_ANALYTICS_REQUEST_GUIDANCE +
|
|
157
160
|
DASHBOARD_REFERENCE_GUIDANCE +
|
|
158
161
|
BOUNDED_STRUCTURED_LOOKUP_GUIDANCE +
|
|
162
|
+
ANALYTICS_ACCOUNT_HEALTH_GUIDANCE +
|
|
159
163
|
BUILT_IN_FIRST_PARTY_SOURCE_GUIDANCE +
|
|
160
164
|
ANALYTICS_OBSERVABILITY_INCIDENT_GUIDANCE +
|
|
161
165
|
`DATA-SOURCE SETUP UX — Chat remains available when no external data source is connected. For a live-data request that needs an unavailable external provider, explain what is missing in the context of the user's question and guide them naturally to [Connect data sources](${ANALYTICS_DATA_SOURCES_LINK}). Use that real link from the app; do not emit a generic canned no-data sentence. For general conversation, conceptual questions, and questions the built-in first-party source can answer, continue helping normally. ` +
|
|
@@ -159,7 +159,9 @@ export function AssetPreviewDialog({
|
|
|
159
159
|
onClick={() => setShowDetails((value) => !value)}
|
|
160
160
|
>
|
|
161
161
|
<IconInfoCircle className="h-4 w-4" />
|
|
162
|
-
{
|
|
162
|
+
{showDetails
|
|
163
|
+
? t("library.hideDetails")
|
|
164
|
+
: t("library.viewDetails")}
|
|
163
165
|
</Button>
|
|
164
166
|
<DialogClose
|
|
165
167
|
aria-label={t("library.closePreview")}
|