@agent-native/core 0.72.3 → 0.73.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/core/CHANGELOG.md +38 -0
- package/corpus/core/docs/content/skills-guide.md +14 -0
- package/corpus/core/docs/content/template-clips.md +7 -1
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/a2a/client.ts +7 -3
- package/corpus/core/src/agent/durable-background.ts +25 -12
- package/corpus/core/src/cli/create.ts +1 -1
- package/corpus/core/src/cli/skills.ts +450 -19
- package/corpus/core/src/client/api-path.ts +28 -0
- package/corpus/core/src/client/embed-auth.ts +26 -0
- package/corpus/core/src/client/mcp-app-host.ts +6 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +227 -33
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -1
- package/corpus/core/src/demo/fetch-interceptor.ts +1 -1
- package/corpus/core/src/embedding/agent.ts +6 -1
- package/corpus/core/src/embedding/bridge.ts +34 -1
- package/corpus/core/src/mcp/build-server.ts +38 -10
- package/corpus/core/src/mcp/embed-app.ts +120 -45
- package/corpus/core/src/mcp/index.ts +5 -0
- package/corpus/core/src/mcp/org-directory.ts +70 -11
- package/corpus/core/src/mcp/server.ts +14 -0
- package/corpus/core/src/mcp-client/config.ts +12 -0
- package/corpus/core/src/mcp-client/index.ts +2 -0
- package/corpus/core/src/mcp-client/manager.ts +268 -9
- package/corpus/core/src/mcp-client/remote-store.ts +154 -0
- package/corpus/core/src/mcp-client/routes.ts +2 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +8 -0
- package/corpus/core/src/server/auth.ts +7 -0
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/server/onboarding-html.ts +95 -9
- package/corpus/core/src/shared/mcp-embed-headers.ts +44 -3
- package/corpus/core/src/templates/default/AGENTS.md +4 -0
- package/corpus/core/src/templates/default/package.json +2 -1
- package/corpus/core/src/templates/headless/AGENTS.md +4 -0
- package/corpus/core/src/templates/headless/package.json +1 -0
- package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-root/README.md +4 -0
- package/corpus/core/src/templates/workspace-root/package.json +1 -0
- package/corpus/core/src/vite/client.ts +53 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +3 -4
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +144 -40
- package/corpus/templates/analytics/app/global.css +15 -13
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +9 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +0 -26
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +0 -23
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/pivot.ts +65 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +3 -4
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-charts-now-fill-sparse-template-time-series-suppor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-rows-now-auto-fit-panels-so-one-two-or-three-chart.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-traffic-tables-now-show-top-urls-and-shared-clips-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +5 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-template-dashboards-now-include-repeat-users-ret.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-retention-charts-now-break-out-1-day-and-7-day-return-rates-.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +256 -44
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +7 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +35 -8
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +287 -42
- package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +17 -10
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +15 -6
- package/corpus/templates/assets/AGENTS.md +7 -5
- package/corpus/templates/assets/actions/generate-asset.ts +161 -0
- package/corpus/templates/assets/actions/list-assets.ts +4 -2
- package/corpus/templates/assets/actions/open-asset-picker.ts +84 -3
- package/corpus/templates/assets/app/routes/library.tsx +243 -40
- package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +1 -1
- package/corpus/templates/calendar/server/plugins/auth.ts +12 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +7 -7
- package/corpus/templates/clips/AGENTS.md +6 -2
- package/corpus/templates/clips/app/components/capture-install-options.tsx +20 -4
- package/corpus/templates/clips/app/components/player/player-controls.tsx +62 -32
- package/corpus/templates/clips/app/lib/capture-install-options.ts +39 -5
- package/corpus/templates/clips/app/routes/download.tsx +2 -2
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-06-24-inline-slack-playback-controls-no-longer-shift-when-adjustin.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-console-log-stream-all-le.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-fetch-xhr-network-request.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-the-chrome-extension-option-now-only-appears-on-supported-hosts.md +5 -0
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +13 -8
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/scripts/package.ts +15 -2
- package/corpus/templates/clips/chrome-extension/src/overlay.css +4 -25
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +1 -3
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +9 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +67 -24
- package/corpus/templates/design/AGENTS.md +10 -5
- package/corpus/templates/design/actions/connect-assets-mcp.ts +131 -0
- package/corpus/templates/design/actions/insert-asset.ts +219 -0
- package/corpus/templates/design/actions/view-screen.ts +3 -1
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +53 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -1
- package/corpus/templates/design/server/plugins/assets-mcp.ts +60 -0
- package/corpus/templates/mail/server/plugins/auth.ts +4 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +271 -197
- package/corpus/templates/plan/server/plan-content.ts +45 -2
- package/dist/a2a/client.d.ts +1 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +5 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/durable-background.d.ts +9 -4
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +24 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/cli/create.js +1 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +361 -19
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/api-path.d.ts.map +1 -1
- package/dist/client/api-path.js +27 -0
- package/dist/client/api-path.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +27 -0
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts.map +1 -1
- package/dist/client/mcp-app-host.js +5 -0
- package/dist/client/mcp-app-host.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +179 -33
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +3 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/demo/fetch-interceptor.js +1 -1
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/embedding/agent.d.ts +1 -1
- package/dist/embedding/agent.d.ts.map +1 -1
- package/dist/embedding/agent.js +1 -1
- package/dist/embedding/agent.js.map +1 -1
- package/dist/embedding/bridge.d.ts.map +1 -1
- package/dist/embedding/bridge.js +27 -1
- package/dist/embedding/bridge.js.map +1 -1
- package/dist/extensions/schema.d.ts +2 -2
- 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 +32 -9
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +120 -45
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/org-directory.d.ts +1 -0
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +59 -11
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp-client/config.d.ts +12 -0
- package/dist/mcp-client/config.d.ts.map +1 -1
- package/dist/mcp-client/config.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/manager.d.ts +2 -0
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +201 -9
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/remote-store.d.ts +27 -0
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +105 -0
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +1 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +2 -2
- package/dist/provider-api/actions/query-staged-dataset.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +8 -8
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +8 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts +7 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +1 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +15 -0
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +73 -9
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +3 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +40 -3
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/package.json +2 -1
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/headless/package.json +1 -0
- package/dist/templates/workspace-root/AGENTS.md +4 -0
- package/dist/templates/workspace-root/README.md +4 -0
- package/dist/templates/workspace-root/package.json +1 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +44 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/skills-guide.md +14 -0
- package/docs/content/template-clips.md +7 -1
- package/package.json +6 -6
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/package.json +2 -1
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/headless/package.json +1 -0
- package/src/templates/workspace-root/AGENTS.md +4 -0
- package/src/templates/workspace-root/README.md +4 -0
- package/src/templates/workspace-root/package.json +1 -0
|
@@ -88,6 +88,18 @@ function fixed(sql: string): (window?: MetricWindow) => string {
|
|
|
88
88
|
return () => sql;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
const SIGNUP_TEMPLATE_EXPR =
|
|
92
|
+
"COALESCE(NULLIF(template, ''), NULLIF(properties::jsonb ->> 'templateId', ''), NULLIF(properties::jsonb ->> 'agent_native_template', ''), NULLIF(properties::jsonb ->> 'agentNativeTemplate', ''), NULLIF(app, ''), NULLIF(properties::jsonb ->> 'agent_native_app', ''), NULLIF(properties::jsonb ->> 'agentNativeApp', ''), 'unknown')";
|
|
93
|
+
const DASHBOARD_TIME_RANGE_FILTER =
|
|
94
|
+
"('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))";
|
|
95
|
+
const DASHBOARD_EMAIL_FILTER =
|
|
96
|
+
"('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))";
|
|
97
|
+
const TOTAL_SIGNUPS_SQL = `SELECT COUNT(*) AS signups FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`;
|
|
98
|
+
const SIGNUPS_OVER_TIME_SQL = `WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY timestamp) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT substr(timestamp, 1, 10) AS date, ${SIGNUP_TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
|
|
99
|
+
const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${SIGNUP_TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '1 day', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
|
|
100
|
+
const SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${SIGNUP_TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
|
|
101
|
+
const SIGNUPS_BY_TEMPLATE_SQL = `SELECT ${SIGNUP_TEMPLATE_EXPR} AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${SIGNUP_TEMPLATE_EXPR} ORDER BY count DESC`;
|
|
102
|
+
|
|
91
103
|
/**
|
|
92
104
|
* Catalog entries. Order here is the default panel order when a caller passes
|
|
93
105
|
* metrics; callers can reorder by listing keys in the order they want.
|
|
@@ -96,19 +108,16 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
96
108
|
// --- Signups -------------------------------------------------------------
|
|
97
109
|
{
|
|
98
110
|
key: "total-signups",
|
|
99
|
-
title: "Signups",
|
|
111
|
+
title: "Total Signups",
|
|
100
112
|
chartType: "metric",
|
|
101
113
|
source: "first-party",
|
|
102
114
|
width: 1,
|
|
103
115
|
windowed: false,
|
|
104
|
-
buildSql: fixed(
|
|
105
|
-
"SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup'",
|
|
106
|
-
),
|
|
116
|
+
buildSql: fixed(TOTAL_SIGNUPS_SQL),
|
|
107
117
|
config: {
|
|
108
|
-
yKey: "
|
|
118
|
+
yKey: "signups",
|
|
109
119
|
yFormatter: "number",
|
|
110
|
-
description:
|
|
111
|
-
"Better Auth user creation events from all Agent Native templates",
|
|
120
|
+
description: "Total signup events in the selected time range.",
|
|
112
121
|
},
|
|
113
122
|
},
|
|
114
123
|
{
|
|
@@ -118,14 +127,18 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
118
127
|
source: "first-party",
|
|
119
128
|
width: 2,
|
|
120
129
|
windowed: false,
|
|
121
|
-
buildSql: fixed(
|
|
122
|
-
"SELECT substr(timestamp, 1, 10) AS date, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' GROUP BY substr(timestamp, 1, 10) ORDER BY date",
|
|
123
|
-
),
|
|
130
|
+
buildSql: fixed(SIGNUPS_OVER_TIME_SQL),
|
|
124
131
|
config: {
|
|
125
132
|
xKey: "date",
|
|
126
133
|
yKey: "count",
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
yFormatter: "number",
|
|
135
|
+
pivot: {
|
|
136
|
+
xKey: "date",
|
|
137
|
+
seriesKey: "template",
|
|
138
|
+
valueKey: "count",
|
|
139
|
+
},
|
|
140
|
+
stacked: true,
|
|
141
|
+
description: "Daily signup events stacked by inferred template/app.",
|
|
129
142
|
},
|
|
130
143
|
},
|
|
131
144
|
{
|
|
@@ -133,16 +146,15 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
133
146
|
title: "Signups by Template",
|
|
134
147
|
chartType: "bar",
|
|
135
148
|
source: "first-party",
|
|
136
|
-
width:
|
|
149
|
+
width: 2,
|
|
137
150
|
windowed: false,
|
|
138
|
-
buildSql: fixed(
|
|
139
|
-
"SELECT COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' GROUP BY COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') ORDER BY count DESC LIMIT 20",
|
|
140
|
-
),
|
|
151
|
+
buildSql: fixed(SIGNUPS_BY_TEMPLATE_SQL),
|
|
141
152
|
config: {
|
|
142
153
|
xKey: "template",
|
|
143
154
|
yKey: "count",
|
|
144
|
-
|
|
145
|
-
|
|
155
|
+
yFormatter: "number",
|
|
156
|
+
color: "var(--brand-purple)",
|
|
157
|
+
description: "Signup events grouped by inferred template/app.",
|
|
146
158
|
},
|
|
147
159
|
},
|
|
148
160
|
|
|
@@ -253,45 +265,85 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
253
265
|
width: 2,
|
|
254
266
|
windowed: false,
|
|
255
267
|
buildSql: fixed(
|
|
256
|
-
"SELECT substr(timestamp, 1, 10) AS date, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY substr(timestamp, 1, 10) ORDER BY date",
|
|
268
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
|
|
257
269
|
),
|
|
258
|
-
config: {
|
|
270
|
+
config: {
|
|
271
|
+
xKey: "date",
|
|
272
|
+
yKey: "count",
|
|
273
|
+
yFormatter: "number",
|
|
274
|
+
pivot: {
|
|
275
|
+
xKey: "date",
|
|
276
|
+
seriesKey: "template",
|
|
277
|
+
valueKey: "count",
|
|
278
|
+
},
|
|
279
|
+
stacked: true,
|
|
280
|
+
},
|
|
259
281
|
},
|
|
260
282
|
{
|
|
261
283
|
key: "clicks-by-template",
|
|
262
|
-
title: "Clicks by Template",
|
|
263
|
-
chartType: "
|
|
284
|
+
title: "Clicks by Template Over Time",
|
|
285
|
+
chartType: "area",
|
|
264
286
|
source: "first-party",
|
|
265
|
-
width:
|
|
287
|
+
width: 2,
|
|
266
288
|
windowed: false,
|
|
267
289
|
buildSql: fixed(
|
|
268
|
-
"SELECT COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY COALESCE(NULLIF(template, ''), 'unknown') ORDER BY
|
|
290
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
|
|
269
291
|
),
|
|
270
|
-
config: {
|
|
292
|
+
config: {
|
|
293
|
+
xKey: "date",
|
|
294
|
+
yKey: "count",
|
|
295
|
+
yFormatter: "number",
|
|
296
|
+
pivot: {
|
|
297
|
+
xKey: "date",
|
|
298
|
+
seriesKey: "template",
|
|
299
|
+
valueKey: "count",
|
|
300
|
+
},
|
|
301
|
+
stacked: true,
|
|
302
|
+
},
|
|
271
303
|
},
|
|
272
304
|
{
|
|
273
305
|
key: "demo-clicks-by-template",
|
|
274
|
-
title: "Try-Demo Clicks
|
|
275
|
-
chartType: "
|
|
306
|
+
title: "Try-Demo Clicks Over Time",
|
|
307
|
+
chartType: "area",
|
|
276
308
|
source: "first-party",
|
|
277
|
-
width:
|
|
309
|
+
width: 2,
|
|
278
310
|
windowed: false,
|
|
279
311
|
buildSql: fixed(
|
|
280
|
-
"SELECT COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' GROUP BY COALESCE(NULLIF(template, ''), 'unknown') ORDER BY
|
|
312
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
|
|
281
313
|
),
|
|
282
|
-
config: {
|
|
314
|
+
config: {
|
|
315
|
+
xKey: "date",
|
|
316
|
+
yKey: "count",
|
|
317
|
+
yFormatter: "number",
|
|
318
|
+
pivot: {
|
|
319
|
+
xKey: "date",
|
|
320
|
+
seriesKey: "template",
|
|
321
|
+
valueKey: "count",
|
|
322
|
+
},
|
|
323
|
+
stacked: true,
|
|
324
|
+
},
|
|
283
325
|
},
|
|
284
326
|
{
|
|
285
327
|
key: "cli-copies-by-template",
|
|
286
|
-
title: "CLI Copies by Template",
|
|
287
|
-
chartType: "
|
|
328
|
+
title: "CLI Copies by Template Over Time",
|
|
329
|
+
chartType: "area",
|
|
288
330
|
source: "first-party",
|
|
289
|
-
width:
|
|
331
|
+
width: 2,
|
|
290
332
|
windowed: false,
|
|
291
333
|
buildSql: fixed(
|
|
292
|
-
"SELECT COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY COALESCE(NULLIF(template, ''), 'unknown') ORDER BY
|
|
334
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
|
|
293
335
|
),
|
|
294
|
-
config: {
|
|
336
|
+
config: {
|
|
337
|
+
xKey: "date",
|
|
338
|
+
yKey: "count",
|
|
339
|
+
yFormatter: "number",
|
|
340
|
+
pivot: {
|
|
341
|
+
xKey: "date",
|
|
342
|
+
seriesKey: "template",
|
|
343
|
+
valueKey: "count",
|
|
344
|
+
},
|
|
345
|
+
stacked: true,
|
|
346
|
+
},
|
|
295
347
|
},
|
|
296
348
|
{
|
|
297
349
|
key: "cli-copies-over-time",
|
|
@@ -301,9 +353,19 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
301
353
|
width: 2,
|
|
302
354
|
windowed: false,
|
|
303
355
|
buildSql: fixed(
|
|
304
|
-
"SELECT substr(timestamp, 1, 10) AS date, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY substr(timestamp, 1, 10) ORDER BY date",
|
|
356
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
|
|
305
357
|
),
|
|
306
|
-
config: {
|
|
358
|
+
config: {
|
|
359
|
+
xKey: "date",
|
|
360
|
+
yKey: "count",
|
|
361
|
+
yFormatter: "number",
|
|
362
|
+
pivot: {
|
|
363
|
+
xKey: "date",
|
|
364
|
+
seriesKey: "template",
|
|
365
|
+
valueKey: "count",
|
|
366
|
+
},
|
|
367
|
+
stacked: true,
|
|
368
|
+
},
|
|
307
369
|
},
|
|
308
370
|
|
|
309
371
|
// --- Activity / pageviews ------------------------------------------------
|
|
@@ -314,17 +376,200 @@ const ENTRIES: FirstPartyMetric[] = [
|
|
|
314
376
|
source: "first-party",
|
|
315
377
|
width: 2,
|
|
316
378
|
windowed: false,
|
|
317
|
-
//
|
|
318
|
-
//
|
|
379
|
+
// Browser telemetry emits explicit `pageview` events with URL context, so
|
|
380
|
+
// keep pageview panels scoped to that event instead of all tracked events.
|
|
319
381
|
buildSql: fixed(
|
|
320
|
-
|
|
382
|
+
`SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') ORDER BY date, template`,
|
|
321
383
|
),
|
|
322
384
|
config: {
|
|
323
385
|
xKey: "date",
|
|
324
386
|
yKey: "count",
|
|
325
|
-
|
|
387
|
+
yFormatter: "number",
|
|
388
|
+
pivot: {
|
|
389
|
+
xKey: "date",
|
|
390
|
+
seriesKey: "template",
|
|
391
|
+
valueKey: "count",
|
|
392
|
+
},
|
|
393
|
+
stacked: true,
|
|
394
|
+
description: "Pageview events per day stacked by inferred template/app.",
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
key: "top-visited-urls",
|
|
399
|
+
title: "Top Visited URLs",
|
|
400
|
+
chartType: "table",
|
|
401
|
+
source: "first-party",
|
|
402
|
+
width: 2,
|
|
403
|
+
windowed: false,
|
|
404
|
+
buildSql: fixed(
|
|
405
|
+
`WITH pageviews AS (SELECT COALESCE(CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') END, NULLIF(url, ''), NULLIF(path, ''), 'unknown') AS url, CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN NULLIF(url, '') LIKE 'http%' THEN url ELSE COALESCE(NULLIF(url, ''), NULLIF(path, ''), '') END AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY 1, 2) SELECT url, views, users, last_seen, href FROM pageviews ORDER BY views DESC LIMIT 25`,
|
|
406
|
+
),
|
|
407
|
+
config: {
|
|
408
|
+
description:
|
|
409
|
+
"Most-viewed URLs in the selected time range. Links open in a new tab.",
|
|
410
|
+
sortable: true,
|
|
411
|
+
limit: 25,
|
|
412
|
+
columns: [
|
|
413
|
+
{ key: "url", label: "URL", format: "link", linkKey: "href" },
|
|
414
|
+
{ key: "views", label: "Views", format: "number" },
|
|
415
|
+
{ key: "users", label: "Users", format: "number" },
|
|
416
|
+
{ key: "last_seen", label: "Last seen", format: "date" },
|
|
417
|
+
{ key: "href", hidden: true },
|
|
418
|
+
],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
key: "top-visited-clips",
|
|
423
|
+
title: "Top Visited Clips",
|
|
424
|
+
chartType: "table",
|
|
425
|
+
source: "first-party",
|
|
426
|
+
width: 2,
|
|
427
|
+
windowed: false,
|
|
428
|
+
buildSql: fixed(
|
|
429
|
+
`WITH clip_events AS (SELECT COALESCE(NULLIF(properties::jsonb ->> 'recording_id', ''), NULLIF(path, ''), NULLIF(url, ''), 'unknown') AS clip_key, CASE WHEN NULLIF(url, '') LIKE 'http%' THEN url WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN NULLIF(path, '') LIKE '/%' THEN 'https://clips.agent-native.com' || path ELSE COALESCE(NULLIF(url, ''), '') END AS href, user_id, anonymous_id, timestamp FROM analytics_events WHERE event_name = 'share_view' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND COALESCE(NULLIF(properties::jsonb ->> 'surface', ''), 'clip') = 'clip'), clip_views AS (SELECT clip_key, COALESCE(MAX(NULLIF(href, '')), clip_key) AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM clip_events GROUP BY clip_key) SELECT CASE WHEN href LIKE 'http%' THEN href ELSE clip_key END AS clip, views, users, last_seen, href FROM clip_views ORDER BY views DESC LIMIT 25`,
|
|
430
|
+
),
|
|
431
|
+
config: {
|
|
432
|
+
description: "Most-viewed shared Clips pages in the selected time range.",
|
|
433
|
+
sortable: true,
|
|
434
|
+
limit: 25,
|
|
435
|
+
columns: [
|
|
436
|
+
{ key: "clip", label: "Clip URL", format: "link", linkKey: "href" },
|
|
437
|
+
{ key: "views", label: "Views", format: "number" },
|
|
438
|
+
{ key: "users", label: "Users", format: "number" },
|
|
439
|
+
{ key: "last_seen", label: "Last seen", format: "date" },
|
|
440
|
+
{ key: "href", hidden: true },
|
|
441
|
+
],
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
key: "repeat-users",
|
|
446
|
+
title: "Repeat Users",
|
|
447
|
+
chartType: "metric",
|
|
448
|
+
source: "first-party",
|
|
449
|
+
width: 1,
|
|
450
|
+
windowed: false,
|
|
451
|
+
buildSql: fixed(
|
|
452
|
+
"WITH user_days AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, COUNT(DISTINCT substr(timestamp, 1, 10)) AS active_days FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD'))) AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io')) GROUP BY COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) SELECT COUNT(*) AS count FROM user_days WHERE active_days >= 2",
|
|
453
|
+
),
|
|
454
|
+
config: {
|
|
455
|
+
yKey: "count",
|
|
456
|
+
yFormatter: "number",
|
|
457
|
+
description:
|
|
458
|
+
"Distinct users with activity on at least two days in the selected time range. Uses user_id first, then anonymous_id.",
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
key: "retention-over-time",
|
|
463
|
+
title: "1d / 7d Retention Over Time",
|
|
464
|
+
chartType: "line",
|
|
465
|
+
source: "first-party",
|
|
466
|
+
width: 3,
|
|
467
|
+
windowed: false,
|
|
468
|
+
buildSql: fixed(
|
|
469
|
+
"WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))), first_seen AS (SELECT user_key, MIN(event_date) AS cohort_date FROM base GROUP BY user_key), cohorts AS (SELECT user_key, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))), retention AS (SELECT c.cohort_date AS date, '1d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date UNION ALL SELECT c.cohort_date AS date, '7d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date) SELECT date, period, rate FROM retention ORDER BY date, period",
|
|
470
|
+
),
|
|
471
|
+
config: {
|
|
472
|
+
xKey: "date",
|
|
473
|
+
yKey: "rate",
|
|
474
|
+
yFormatter: "percent",
|
|
475
|
+
pivot: {
|
|
476
|
+
xKey: "date",
|
|
477
|
+
seriesKey: "period",
|
|
478
|
+
valueKey: "rate",
|
|
479
|
+
},
|
|
480
|
+
colors: ["#10b981", "#8b5cf6"],
|
|
481
|
+
description:
|
|
482
|
+
"First-seen daily cohorts in the selected range. Cohorts must be at least seven days old so both lines are mature.",
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
key: "one-day-retention-by-template",
|
|
487
|
+
title: "1d Retention by Template",
|
|
488
|
+
chartType: "line",
|
|
489
|
+
source: "first-party",
|
|
490
|
+
width: 2,
|
|
491
|
+
windowed: false,
|
|
492
|
+
buildSql: fixed(ONE_DAY_RETENTION_BY_TEMPLATE_SQL),
|
|
493
|
+
config: {
|
|
494
|
+
xKey: "date",
|
|
495
|
+
yKey: "rate",
|
|
496
|
+
yFormatter: "percent",
|
|
497
|
+
pivot: {
|
|
498
|
+
xKey: "date",
|
|
499
|
+
seriesKey: "template",
|
|
500
|
+
valueKey: "rate",
|
|
501
|
+
},
|
|
502
|
+
description:
|
|
503
|
+
"Per-template first-seen cohorts in the selected range. A user is retained when they return to the same template the next day.",
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
key: "seven-day-retention-by-template",
|
|
508
|
+
title: "7d Retention by Template",
|
|
509
|
+
chartType: "line",
|
|
510
|
+
source: "first-party",
|
|
511
|
+
width: 2,
|
|
512
|
+
windowed: false,
|
|
513
|
+
buildSql: fixed(SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL),
|
|
514
|
+
config: {
|
|
515
|
+
xKey: "date",
|
|
516
|
+
yKey: "rate",
|
|
517
|
+
yFormatter: "percent",
|
|
518
|
+
pivot: {
|
|
519
|
+
xKey: "date",
|
|
520
|
+
seriesKey: "template",
|
|
521
|
+
valueKey: "rate",
|
|
522
|
+
},
|
|
523
|
+
description:
|
|
524
|
+
"Per-template first-seen cohorts in the selected range. A user is retained when they return to the same template seven days later.",
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
key: "dau-over-time",
|
|
529
|
+
title: "DAU by Template",
|
|
530
|
+
chartType: "area",
|
|
531
|
+
source: "first-party",
|
|
532
|
+
width: 2,
|
|
533
|
+
windowed: false,
|
|
534
|
+
buildSql: fixed(
|
|
535
|
+
"SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD'))) AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io')) GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') ORDER BY date, template",
|
|
536
|
+
),
|
|
537
|
+
config: {
|
|
538
|
+
xKey: "date",
|
|
539
|
+
yKey: "users",
|
|
540
|
+
yFormatter: "number",
|
|
541
|
+
pivot: {
|
|
542
|
+
xKey: "date",
|
|
543
|
+
seriesKey: "template",
|
|
544
|
+
valueKey: "users",
|
|
545
|
+
},
|
|
546
|
+
stacked: true,
|
|
547
|
+
description:
|
|
548
|
+
"Distinct active users per day in the selected time range, stacked by template. Uses user_id first, then anonymous_id.",
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
key: "wau-over-time",
|
|
553
|
+
title: "WAU by Template",
|
|
554
|
+
chartType: "area",
|
|
555
|
+
source: "first-party",
|
|
556
|
+
width: 2,
|
|
557
|
+
windowed: false,
|
|
558
|
+
buildSql: fixed(
|
|
559
|
+
"WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))), days AS (SELECT DISTINCT event_date AS date FROM base WHERE ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND event_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT d.date, b.template, COUNT(DISTINCT b.user_key) AS users FROM days d JOIN base b ON b.event_date >= to_char(d.date::date - INTERVAL '6 days', 'YYYY-MM-DD') AND b.event_date <= d.date GROUP BY d.date, b.template ORDER BY d.date, b.template",
|
|
560
|
+
),
|
|
561
|
+
config: {
|
|
562
|
+
xKey: "date",
|
|
563
|
+
yKey: "users",
|
|
564
|
+
yFormatter: "number",
|
|
565
|
+
pivot: {
|
|
566
|
+
xKey: "date",
|
|
567
|
+
seriesKey: "template",
|
|
568
|
+
valueKey: "users",
|
|
569
|
+
},
|
|
570
|
+
stacked: true,
|
|
326
571
|
description:
|
|
327
|
-
"
|
|
572
|
+
"Trailing 7-day distinct active users for each active date in the selected time range, stacked by template.",
|
|
328
573
|
},
|
|
329
574
|
},
|
|
330
575
|
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: a2a-assets
|
|
3
|
-
description:
|
|
3
|
+
description: Use Assets from other apps or MCP hosts to generate, refine, export, and insert brand images or videos.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Assets MCP Tool
|
|
7
7
|
|
|
8
|
-
Use
|
|
8
|
+
Use the Assets MCP tool surface when another app or external host needs brand
|
|
9
|
+
imagery, video, or reusable source media and Assets owns the library. Prefer the
|
|
10
|
+
pure MCP `generate-asset` flow for human-in-the-loop generation because it can
|
|
11
|
+
return the inline picker. A2A remains useful for unattended cross-app
|
|
12
|
+
delegation, but A2A replies cannot render MCP App pickers.
|
|
9
13
|
|
|
10
14
|
## Caller Flow
|
|
11
15
|
|
|
12
|
-
1.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
1. For human selection, call `generate-asset` with the brief, `callerAppId`, and
|
|
17
|
+
`libraryId` when known. It will match the library, generate candidates, and
|
|
18
|
+
return the Assets picker filtered to the new run IDs.
|
|
19
|
+
2. For unattended A2A-style work, call `match-library` or `list-libraries` when
|
|
20
|
+
the library is ambiguous, then call `generate-image-batch` with one slot per
|
|
21
|
+
destination, such as one hero per slide. Pass `source: "a2a"` and
|
|
22
|
+
`callerAppId` with the calling app id (`slides`, `design`, `content`,
|
|
23
|
+
`mail`) so the Assets audit log can group cross-agent generations.
|
|
18
24
|
3. Treat image batches as complete when the action returns. Use returned
|
|
19
25
|
successful `images` entries directly; only regenerate slots that returned
|
|
20
26
|
`ok: false`.
|
|
@@ -25,7 +31,8 @@ Use A2A when another app needs brand imagery, video, or reusable source media an
|
|
|
25
31
|
6. For video, call `generate-video` and then `refresh-generation-run` until the run completes.
|
|
26
32
|
7. Preserve returned `assetId`, `runId`, `previewUrl`, `downloadUrl`, and
|
|
27
33
|
`embedPath` exactly.
|
|
28
|
-
8. Insert exported URLs into the caller's artifact.
|
|
34
|
+
8. Insert chosen/exported URLs into the caller's artifact. Design callers should
|
|
35
|
+
call `insert-asset` after the picker returns a selected asset.
|
|
29
36
|
9. On feedback, call `refine-image` with the prior `assetId`, `source: "a2a"`,
|
|
30
37
|
and the same `callerAppId`, then replace only the affected destination.
|
|
31
38
|
|
|
@@ -16,9 +16,14 @@ or generated image/video assets that another app can reference by ID and URL.
|
|
|
16
16
|
|
|
17
17
|
## Choose The Path
|
|
18
18
|
|
|
19
|
-
- Use `
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
- Use `generate-asset` when a person should get newly generated, on-brand image
|
|
20
|
+
candidates and choose the winner in the inline picker. It matches a library
|
|
21
|
+
when `libraryId` is omitted, generates candidates, returns the picker filtered
|
|
22
|
+
to those run IDs, and works in in-app chat plus external MCP hosts.
|
|
23
|
+
- Use `open-asset-picker` when a person should browse, search, or select an
|
|
24
|
+
existing asset in UI, or when you want the picker to handle generation itself.
|
|
25
|
+
Pass `mediaType: "image"` by default, or `mediaType: "video"` for video
|
|
26
|
+
libraries.
|
|
22
27
|
- Use unattended actions when the agent already knows what to do:
|
|
23
28
|
`search-assets`, `list-assets`, `generate-image`, `generate-image-batch`,
|
|
24
29
|
`generate-video`, `refresh-generation-run`, and `export-asset`.
|
|
@@ -41,7 +46,9 @@ or generated image/video assets that another app can reference by ID and URL.
|
|
|
41
46
|
|
|
42
47
|
## Image Workflows
|
|
43
48
|
|
|
44
|
-
1.
|
|
49
|
+
1. For human-in-the-loop generation, call `generate-asset` first and preserve
|
|
50
|
+
the returned picker/candidate metadata. For unattended generation, pick or
|
|
51
|
+
match the library with `list-libraries` or `match-library`.
|
|
45
52
|
If the user wants a default look rather than a brand library, call
|
|
46
53
|
`list-library-presets` and then `create-library-from-preset`; the resulting
|
|
47
54
|
library is editable and reusable like any other library.
|
|
@@ -85,8 +92,10 @@ deferred.
|
|
|
85
92
|
Do not put shared secrets in skill files.
|
|
86
93
|
- Local customization: run `npx @agent-native/core@latest app-skill launch --local` from the
|
|
87
94
|
Assets app-skill manifest, or pass `--into <path>` for editable source.
|
|
88
|
-
- For
|
|
89
|
-
|
|
95
|
+
- For MCP callers, `generate-asset` is the portable first choice because the
|
|
96
|
+
same MCP App picker renders inline in Agent-Native chat, ChatGPT, and Claude
|
|
97
|
+
when the host supports MCP Apps. Include exact `assetId`, `runId`, media type,
|
|
98
|
+
and URLs in the final response so the caller can attach or embed the media.
|
|
90
99
|
Include `presetId` and `sessionId` when present.
|
|
91
100
|
|
|
92
101
|
## Don't
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Assets — Agent Guide
|
|
2
2
|
|
|
3
3
|
Assets is an agent-native asset library and generation workspace. The agent
|
|
4
|
-
manages libraries, images, generated assets, inline
|
|
5
|
-
collaboration, and
|
|
4
|
+
manages libraries, images, generated assets, inline MCP App pickers,
|
|
5
|
+
notifications, collaboration, and portable asset requests through actions and
|
|
6
|
+
SQL state.
|
|
6
7
|
|
|
7
8
|
Detailed library, generation, image, embed, and engine rules live in
|
|
8
9
|
`.agents/skills/`.
|
|
@@ -61,9 +62,10 @@ Read the relevant skill before deeper work:
|
|
|
61
62
|
plain image-generation requests. Keep `npx @agent-native/core@latest connect` running until
|
|
62
63
|
browser authorization finishes, restart the client if tools are not visible,
|
|
63
64
|
and redact any MCP auth headers or tokens when debugging local config.
|
|
64
|
-
- For human-in-the-loop image creation,
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
- For human-in-the-loop image creation, prefer `generate-asset` so Assets
|
|
66
|
+
matches the library, generates candidates, and returns the inline picker
|
|
67
|
+
filtered to those candidates. Use `open-asset-picker` when the user only needs
|
|
68
|
+
to browse/search/pick or when you want the picker to handle generation itself.
|
|
67
69
|
- If the picker opens as a browser fallback instead of inline, selecting an
|
|
68
70
|
asset copies a handoff summary; ask the caller to paste it back into chat.
|
|
69
71
|
- Treat Codex, Claude Code, and Claude Desktop Code as link-out hosts for MCP
|