diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 51cd709bb7..c4666fba17 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -1209,6 +1209,17 @@ export function AlgoliaIcon(props: SVGProps) { ) } +export function AmplitudeIcon(props: SVGProps) { + return ( + + + + ) +} + export function GoogleBooksIcon(props: SVGProps) { return ( @@ -1938,13 +1949,11 @@ export function ElevenLabsIcon(props: SVGProps) { export function LinkupIcon(props: SVGProps) { return ( - - - - + + ) } @@ -2453,6 +2462,17 @@ export function OutlookIcon(props: SVGProps) { ) } +export function PagerDutyIcon(props: SVGProps) { + return ( + + + + ) +} + export function MicrosoftExcelIcon(props: SVGProps) { const id = useId() const gradientId = `excel_gradient_${id}` @@ -3996,10 +4016,10 @@ export function IntercomIcon(props: SVGProps) { export function LoopsIcon(props: SVGProps) { return ( - + ) @@ -5578,6 +5598,35 @@ export function GoogleMapsIcon(props: SVGProps) { ) } +export function GooglePagespeedIcon(props: SVGProps) { + return ( + + + + + + + + + + ) +} + export function GoogleTranslateIcon(props: SVGProps) { return ( diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index a69b0d90f5..6d15e539dc 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -9,6 +9,7 @@ import { AirtableIcon, AirweaveIcon, AlgoliaIcon, + AmplitudeIcon, ApifyIcon, ApolloIcon, ArxivIcon, @@ -56,6 +57,7 @@ import { GoogleGroupsIcon, GoogleIcon, GoogleMapsIcon, + GooglePagespeedIcon, GoogleSheetsIcon, GoogleSlidesIcon, GoogleTasksIcon, @@ -102,6 +104,7 @@ import { OpenAIIcon, OutlookIcon, PackageSearchIcon, + PagerDutyIcon, ParallelIcon, PerplexityIcon, PineconeIcon, @@ -167,6 +170,7 @@ export const blockTypeToIconMap: Record = { airtable: AirtableIcon, airweave: AirweaveIcon, algolia: AlgoliaIcon, + amplitude: AmplitudeIcon, apify: ApifyIcon, apollo: ApolloIcon, arxiv: ArxivIcon, @@ -211,6 +215,7 @@ export const blockTypeToIconMap: Record = { google_forms: GoogleFormsIcon, google_groups: GoogleGroupsIcon, google_maps: GoogleMapsIcon, + google_pagespeed: GooglePagespeedIcon, google_search: GoogleIcon, google_sheets_v2: GoogleSheetsIcon, google_slides_v2: GoogleSlidesIcon, @@ -258,6 +263,7 @@ export const blockTypeToIconMap: Record = { onepassword: OnePasswordIcon, openai: OpenAIIcon, outlook: OutlookIcon, + pagerduty: PagerDutyIcon, parallel_ai: ParallelIcon, perplexity: PerplexityIcon, pinecone: PineconeIcon, diff --git a/apps/docs/content/docs/en/tools/amplitude.mdx b/apps/docs/content/docs/en/tools/amplitude.mdx new file mode 100644 index 0000000000..177b5c5455 --- /dev/null +++ b/apps/docs/content/docs/en/tools/amplitude.mdx @@ -0,0 +1,313 @@ +--- +title: Amplitude +description: Track events and query analytics from Amplitude +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Amplitude](https://amplitude.com/) is a leading digital analytics platform that helps teams understand user behavior, measure product performance, and make data-driven decisions at scale. + +The Amplitude integration in Sim connects with the Amplitude HTTP and Dashboard REST APIs using API key and secret key authentication, allowing your agents to track events, manage user properties, and query analytics data programmatically. This API-based approach ensures secure access to Amplitude's full suite of analytics capabilities. + +With the Amplitude integration, your agents can: + +- **Track events**: Send custom events to Amplitude with rich properties, revenue data, and user context directly from your workflows +- **Identify users**: Set and update user properties using operations like $set, $setOnce, $add, $append, and $unset to maintain detailed user profiles +- **Search for users**: Look up users by User ID, Device ID, or Amplitude ID to retrieve profile information and metadata +- **Query event analytics**: Run event segmentation queries with grouping, custom metrics (uniques, totals, averages, DAU percentages), and flexible date ranges +- **Monitor user activity**: Retrieve event streams for specific users to understand individual user journeys and behavior patterns +- **Analyze active users**: Get active or new user counts over time with daily, weekly, or monthly granularity +- **Track revenue**: Access revenue LTV metrics including ARPU, ARPPU, total revenue, and paying user counts + +In Sim, the Amplitude integration enables powerful analytics automation scenarios. Your agents can track product events in real time based on workflow triggers, enrich user profiles as new data becomes available, query segmentation data to inform downstream decisions, or build monitoring workflows that alert on changes in key metrics. By connecting Sim with Amplitude, you can build intelligent agents that bridge the gap between analytics insights and automated action, enabling data-driven workflows that respond to user behavior patterns and product performance trends. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Amplitude into your workflow to track events, identify users and groups, search for users, query analytics, and retrieve revenue data. + + + +## Tools + +### `amplitude_send_event` + +Track an event in Amplitude using the HTTP V2 API. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `userId` | string | No | User ID \(required if no device_id\) | +| `deviceId` | string | No | Device ID \(required if no user_id\) | +| `eventType` | string | Yes | Name of the event \(e.g., "page_view", "purchase"\) | +| `eventProperties` | string | No | JSON object of custom event properties | +| `userProperties` | string | No | JSON object of user properties to set \(supports $set, $setOnce, $add, $append, $unset\) | +| `time` | string | No | Event timestamp in milliseconds since epoch | +| `sessionId` | string | No | Session start time in milliseconds since epoch | +| `insertId` | string | No | Unique ID for deduplication \(within 7-day window\) | +| `appVersion` | string | No | Application version string | +| `platform` | string | No | Platform \(e.g., "Web", "iOS", "Android"\) | +| `country` | string | No | Two-letter country code | +| `language` | string | No | Language code \(e.g., "en"\) | +| `ip` | string | No | IP address for geo-location | +| `price` | string | No | Price of the item purchased | +| `quantity` | string | No | Quantity of items purchased | +| `revenue` | string | No | Revenue amount | +| `productId` | string | No | Product identifier | +| `revenueType` | string | No | Revenue type \(e.g., "purchase", "refund"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `code` | number | Response code \(200 for success\) | +| `eventsIngested` | number | Number of events ingested | +| `payloadSizeBytes` | number | Size of the payload in bytes | +| `serverUploadTime` | number | Server upload timestamp | + +### `amplitude_identify_user` + +Set user properties in Amplitude using the Identify API. Supports $set, $setOnce, $add, $append, $unset operations. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `userId` | string | No | User ID \(required if no device_id\) | +| `deviceId` | string | No | Device ID \(required if no user_id\) | +| `userProperties` | string | Yes | JSON object of user properties. Use operations like $set, $setOnce, $add, $append, $unset. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `code` | number | HTTP response status code | +| `message` | string | Response message | + +### `amplitude_group_identify` + +Set group-level properties in Amplitude. Supports $set, $setOnce, $add, $append, $unset operations. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `groupType` | string | Yes | Group classification \(e.g., "company", "org_id"\) | +| `groupValue` | string | Yes | Specific group identifier \(e.g., "Acme Corp"\) | +| `groupProperties` | string | Yes | JSON object of group properties. Use operations like $set, $setOnce, $add, $append, $unset. | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `code` | number | HTTP response status code | +| `message` | string | Response message | + +### `amplitude_user_search` + +Search for a user by User ID, Device ID, or Amplitude ID using the Dashboard REST API. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `user` | string | Yes | User ID, Device ID, or Amplitude ID to search for | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `matches` | array | List of matching users | +| ↳ `amplitudeId` | number | Amplitude internal user ID | +| ↳ `userId` | string | External user ID | +| `type` | string | Match type \(e.g., match_user_or_device_id\) | + +### `amplitude_user_activity` + +Get the event stream for a specific user by their Amplitude ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `amplitudeId` | string | Yes | Amplitude internal user ID | +| `offset` | string | No | Offset for pagination \(default 0\) | +| `limit` | string | No | Maximum number of events to return \(default 1000, max 1000\) | +| `direction` | string | No | Sort direction: "latest" or "earliest" \(default: latest\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `events` | array | List of user events | +| ↳ `eventType` | string | Type of event | +| ↳ `eventTime` | string | Event timestamp | +| ↳ `eventProperties` | json | Custom event properties | +| ↳ `userProperties` | json | User properties at event time | +| ↳ `sessionId` | number | Session ID | +| ↳ `platform` | string | Platform | +| ↳ `country` | string | Country | +| ↳ `city` | string | City | +| `userData` | json | User metadata | +| ↳ `userId` | string | External user ID | +| ↳ `canonicalAmplitudeId` | number | Canonical Amplitude ID | +| ↳ `numEvents` | number | Total event count | +| ↳ `numSessions` | number | Total session count | +| ↳ `platform` | string | Primary platform | +| ↳ `country` | string | Country | + +### `amplitude_user_profile` + +Get a user profile including properties, cohort memberships, and computed properties. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `userId` | string | No | External user ID \(required if no device_id\) | +| `deviceId` | string | No | Device ID \(required if no user_id\) | +| `getAmpProps` | string | No | Include Amplitude user properties \(true/false, default: false\) | +| `getCohortIds` | string | No | Include cohort IDs the user belongs to \(true/false, default: false\) | +| `getComputations` | string | No | Include computed user properties \(true/false, default: false\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `userId` | string | External user ID | +| `deviceId` | string | Device ID | +| `ampProps` | json | Amplitude user properties \(library, first_used, last_used, custom properties\) | +| `cohortIds` | array | List of cohort IDs the user belongs to | +| `computations` | json | Computed user properties | + +### `amplitude_event_segmentation` + +Query event analytics data with segmentation. Get event counts, uniques, averages, and more. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `eventType` | string | Yes | Event type name to analyze | +| `start` | string | Yes | Start date in YYYYMMDD format | +| `end` | string | Yes | End date in YYYYMMDD format | +| `metric` | string | No | Metric type: uniques, totals, pct_dau, average, histogram, sums, value_avg, or formula \(default: uniques\) | +| `interval` | string | No | Time interval: 1 \(daily\), 7 \(weekly\), or 30 \(monthly\) | +| `groupBy` | string | No | Property name to group by \(prefix custom user properties with "gp:"\) | +| `limit` | string | No | Maximum number of group-by values \(max 1000\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `series` | json | Time-series data arrays indexed by series | +| `seriesLabels` | array | Labels for each data series | +| `seriesCollapsed` | json | Collapsed aggregate totals per series | +| `xValues` | array | Date values for the x-axis | + +### `amplitude_get_active_users` + +Get active or new user counts over a date range from the Dashboard REST API. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `start` | string | Yes | Start date in YYYYMMDD format | +| `end` | string | Yes | End date in YYYYMMDD format | +| `metric` | string | No | Metric type: "active" or "new" \(default: active\) | +| `interval` | string | No | Time interval: 1 \(daily\), 7 \(weekly\), or 30 \(monthly\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `series` | json | Array of data series with user counts per time interval | +| `seriesMeta` | array | Metadata labels for each data series \(e.g., segment names\) | +| `xValues` | array | Date values for the x-axis | + +### `amplitude_realtime_active_users` + +Get real-time active user counts at 5-minute granularity for the last 2 days. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `series` | json | Array of data series with active user counts at 5-minute intervals | +| `seriesLabels` | array | Labels for each series \(e.g., "Today", "Yesterday"\) | +| `xValues` | array | Time values for the x-axis \(e.g., "15:00", "15:05"\) | + +### `amplitude_list_events` + +List all event types in the Amplitude project with their weekly totals and unique counts. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `events` | array | List of event types in the project | +| ↳ `value` | string | Event type name | +| ↳ `displayName` | string | Event display name | +| ↳ `totals` | number | Weekly total count | +| ↳ `hidden` | boolean | Whether the event is hidden | +| ↳ `deleted` | boolean | Whether the event is deleted | + +### `amplitude_get_revenue` + +Get revenue LTV data including ARPU, ARPPU, total revenue, and paying user counts. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Amplitude API Key | +| `secretKey` | string | Yes | Amplitude Secret Key | +| `start` | string | Yes | Start date in YYYYMMDD format | +| `end` | string | Yes | End date in YYYYMMDD format | +| `metric` | string | No | Metric: 0 \(ARPU\), 1 \(ARPPU\), 2 \(Total Revenue\), 3 \(Paying Users\) | +| `interval` | string | No | Time interval: 1 \(daily\), 7 \(weekly\), or 30 \(monthly\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `series` | json | Array of revenue data series | +| `seriesLabels` | array | Labels for each data series | +| `xValues` | array | Date values for the x-axis | + + diff --git a/apps/docs/content/docs/en/tools/google_pagespeed.mdx b/apps/docs/content/docs/en/tools/google_pagespeed.mdx new file mode 100644 index 0000000000..65b62e0e75 --- /dev/null +++ b/apps/docs/content/docs/en/tools/google_pagespeed.mdx @@ -0,0 +1,84 @@ +--- +title: Google PageSpeed +description: Analyze webpage performance with Google PageSpeed Insights +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Google PageSpeed Insights](https://pagespeed.web.dev/) is a web performance analysis tool powered by Lighthouse that evaluates the quality of web pages across multiple dimensions including performance, accessibility, SEO, and best practices. + +With the Google PageSpeed integration in Sim, you can: + +- **Analyze webpage performance**: Get detailed performance scores and metrics for any public URL, including First Contentful Paint, Largest Contentful Paint, and Speed Index +- **Evaluate accessibility**: Check how well a webpage meets accessibility standards and identify areas for improvement +- **Audit SEO**: Assess a page's search engine optimization and discover opportunities to improve rankings +- **Review best practices**: Verify that a webpage follows modern web development best practices +- **Compare strategies**: Run analyses using either desktop or mobile strategies to understand performance across device types +- **Localize results**: Retrieve analysis results in different locales for internationalized reporting + +In Sim, the Google PageSpeed integration enables your agents to programmatically audit web pages as part of automated workflows. This is useful for monitoring site performance over time, triggering alerts when scores drop below thresholds, generating performance reports, and ensuring that deployed changes meet quality standards before release. + +### Getting Your API Key + +1. Go to the [Google Cloud Console](https://console.cloud.google.com/) +2. Create or select a project +3. Enable the **PageSpeed Insights API** from the API Library +4. Navigate to **Credentials** and create an API key +5. Use the API key in the Sim block configuration +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Analyze web pages for performance, accessibility, SEO, and best practices using Google PageSpeed Insights API powered by Lighthouse. + + + +## Tools + +### `google_pagespeed_analyze` + +Analyze a webpage for performance, accessibility, SEO, and best practices using Google PageSpeed Insights. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Google PageSpeed Insights API Key | +| `url` | string | Yes | The URL of the webpage to analyze | +| `category` | string | No | Lighthouse categories to analyze \(comma-separated\): performance, accessibility, best-practices, seo | +| `strategy` | string | No | Analysis strategy: desktop or mobile | +| `locale` | string | No | Locale for results \(e.g., en, fr, de\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `finalUrl` | string | The final URL after redirects | +| `performanceScore` | number | Performance category score \(0-1\) | +| `accessibilityScore` | number | Accessibility category score \(0-1\) | +| `bestPracticesScore` | number | Best Practices category score \(0-1\) | +| `seoScore` | number | SEO category score \(0-1\) | +| `firstContentfulPaint` | string | Time to First Contentful Paint \(display value\) | +| `firstContentfulPaintMs` | number | Time to First Contentful Paint in milliseconds | +| `largestContentfulPaint` | string | Time to Largest Contentful Paint \(display value\) | +| `largestContentfulPaintMs` | number | Time to Largest Contentful Paint in milliseconds | +| `totalBlockingTime` | string | Total Blocking Time \(display value\) | +| `totalBlockingTimeMs` | number | Total Blocking Time in milliseconds | +| `cumulativeLayoutShift` | string | Cumulative Layout Shift \(display value\) | +| `cumulativeLayoutShiftValue` | number | Cumulative Layout Shift numeric value | +| `speedIndex` | string | Speed Index \(display value\) | +| `speedIndexMs` | number | Speed Index in milliseconds | +| `interactive` | string | Time to Interactive \(display value\) | +| `interactiveMs` | number | Time to Interactive in milliseconds | +| `overallCategory` | string | Overall loading experience category \(FAST, AVERAGE, SLOW, or NONE\) | +| `analysisTimestamp` | string | UTC timestamp of the analysis | +| `lighthouseVersion` | string | Version of Lighthouse used for the analysis | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 3a1917fc19..612cba972c 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -6,6 +6,7 @@ "airtable", "airweave", "algolia", + "amplitude", "apify", "apollo", "arxiv", @@ -50,6 +51,7 @@ "google_forms", "google_groups", "google_maps", + "google_pagespeed", "google_search", "google_sheets", "google_slides", @@ -97,6 +99,7 @@ "onepassword", "openai", "outlook", + "pagerduty", "parallel_ai", "perplexity", "pinecone", diff --git a/apps/docs/content/docs/en/tools/pagerduty.mdx b/apps/docs/content/docs/en/tools/pagerduty.mdx new file mode 100644 index 0000000000..5876c1cd7d --- /dev/null +++ b/apps/docs/content/docs/en/tools/pagerduty.mdx @@ -0,0 +1,217 @@ +--- +title: PagerDuty +description: Manage incidents and on-call schedules with PagerDuty +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[PagerDuty](https://www.pagerduty.com/) is a leading incident management platform that helps engineering and operations teams detect, triage, and resolve infrastructure and application issues in real time. PagerDuty integrates with monitoring tools, orchestrates on-call schedules, and ensures the right people are alerted when incidents occur. + +The PagerDuty integration in Sim connects with the PagerDuty REST API v2 using API key authentication, enabling your agents to manage the full incident lifecycle and query on-call information programmatically. + +With the PagerDuty integration, your agents can: + +- **List and filter incidents**: Retrieve incidents filtered by status (triggered, acknowledged, resolved), service, date range, and sort order to monitor your operational health +- **Create incidents**: Trigger new incidents on specific services with custom titles, descriptions, urgency levels, and assignees directly from your workflows +- **Update incidents**: Acknowledge or resolve incidents, change urgency, and add resolution notes to keep your incident management in sync with automated processes +- **Add notes to incidents**: Attach contextual information, investigation findings, or automated diagnostics as notes on existing incidents +- **List services**: Query your PagerDuty service catalog to discover service IDs and metadata for use in other operations +- **Check on-call schedules**: Retrieve current on-call entries filtered by escalation policy or schedule to determine who is responsible at any given time + +In Sim, the PagerDuty integration enables powerful incident automation scenarios. Your agents can automatically create incidents based on monitoring alerts, enrich incidents with diagnostic data from other tools, resolve incidents when automated remediation succeeds, or build escalation workflows that check on-call schedules and route notifications accordingly. By connecting Sim with PagerDuty, you can build intelligent agents that bridge the gap between detection and response, reducing mean time to resolution and ensuring consistent incident handling across your organization. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate PagerDuty into your workflow to list, create, and update incidents, add notes, list services, and check on-call schedules. + + + +## Tools + +### `pagerduty_list_incidents` + +List incidents from PagerDuty with optional filters. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `statuses` | string | No | Comma-separated statuses to filter \(triggered, acknowledged, resolved\) | +| `serviceIds` | string | No | Comma-separated service IDs to filter | +| `since` | string | No | Start date filter \(ISO 8601 format\) | +| `until` | string | No | End date filter \(ISO 8601 format\) | +| `sortBy` | string | No | Sort field \(e.g., created_at:desc\) | +| `limit` | string | No | Maximum number of results \(max 100\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `incidents` | array | Array of incidents | +| ↳ `id` | string | Incident ID | +| ↳ `incidentNumber` | number | Incident number | +| ↳ `title` | string | Incident title | +| ↳ `status` | string | Incident status | +| ↳ `urgency` | string | Incident urgency | +| ↳ `createdAt` | string | Creation timestamp | +| ↳ `updatedAt` | string | Last updated timestamp | +| ↳ `serviceName` | string | Service name | +| ↳ `serviceId` | string | Service ID | +| ↳ `assigneeName` | string | Assignee name | +| ↳ `assigneeId` | string | Assignee ID | +| ↳ `escalationPolicyName` | string | Escalation policy name | +| ↳ `htmlUrl` | string | PagerDuty web URL | +| `total` | number | Total number of matching incidents | +| `more` | boolean | Whether more results are available | + +### `pagerduty_create_incident` + +Create a new incident in PagerDuty. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `fromEmail` | string | Yes | Email address of a valid PagerDuty user | +| `title` | string | Yes | Incident title/summary | +| `serviceId` | string | Yes | ID of the PagerDuty service | +| `urgency` | string | No | Urgency level \(high or low\) | +| `body` | string | No | Detailed description of the incident | +| `escalationPolicyId` | string | No | Escalation policy ID to assign | +| `assigneeId` | string | No | User ID to assign the incident to | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Created incident ID | +| `incidentNumber` | number | Incident number | +| `title` | string | Incident title | +| `status` | string | Incident status | +| `urgency` | string | Incident urgency | +| `createdAt` | string | Creation timestamp | +| `serviceName` | string | Service name | +| `serviceId` | string | Service ID | +| `htmlUrl` | string | PagerDuty web URL | + +### `pagerduty_update_incident` + +Update an incident in PagerDuty (acknowledge, resolve, change urgency, etc.). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `fromEmail` | string | Yes | Email address of a valid PagerDuty user | +| `incidentId` | string | Yes | ID of the incident to update | +| `status` | string | No | New status \(acknowledged or resolved\) | +| `title` | string | No | New incident title | +| `urgency` | string | No | New urgency \(high or low\) | +| `escalationLevel` | string | No | Escalation level to escalate to | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Incident ID | +| `incidentNumber` | number | Incident number | +| `title` | string | Incident title | +| `status` | string | Updated status | +| `urgency` | string | Updated urgency | +| `updatedAt` | string | Last updated timestamp | +| `htmlUrl` | string | PagerDuty web URL | + +### `pagerduty_add_note` + +Add a note to an existing PagerDuty incident. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `fromEmail` | string | Yes | Email address of a valid PagerDuty user | +| `incidentId` | string | Yes | ID of the incident to add the note to | +| `content` | string | Yes | Note content text | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Note ID | +| `content` | string | Note content | +| `createdAt` | string | Creation timestamp | +| `userName` | string | Name of the user who created the note | + +### `pagerduty_list_services` + +List services from PagerDuty with optional name filter. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `query` | string | No | Filter services by name | +| `limit` | string | No | Maximum number of results \(max 100\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `services` | array | Array of services | +| ↳ `id` | string | Service ID | +| ↳ `name` | string | Service name | +| ↳ `description` | string | Service description | +| ↳ `status` | string | Service status | +| ↳ `escalationPolicyName` | string | Escalation policy name | +| ↳ `escalationPolicyId` | string | Escalation policy ID | +| ↳ `createdAt` | string | Creation timestamp | +| ↳ `htmlUrl` | string | PagerDuty web URL | +| `total` | number | Total number of matching services | +| `more` | boolean | Whether more results are available | + +### `pagerduty_list_oncalls` + +List current on-call entries from PagerDuty. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | PagerDuty REST API Key | +| `escalationPolicyIds` | string | No | Comma-separated escalation policy IDs to filter | +| `scheduleIds` | string | No | Comma-separated schedule IDs to filter | +| `since` | string | No | Start time filter \(ISO 8601 format\) | +| `until` | string | No | End time filter \(ISO 8601 format\) | +| `limit` | string | No | Maximum number of results \(max 100\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `oncalls` | array | Array of on-call entries | +| ↳ `userName` | string | On-call user name | +| ↳ `userId` | string | On-call user ID | +| ↳ `escalationLevel` | number | Escalation level | +| ↳ `escalationPolicyName` | string | Escalation policy name | +| ↳ `escalationPolicyId` | string | Escalation policy ID | +| ↳ `scheduleName` | string | Schedule name | +| ↳ `scheduleId` | string | Schedule ID | +| ↳ `start` | string | On-call start time | +| ↳ `end` | string | On-call end time | +| `total` | number | Total number of matching on-call entries | +| `more` | boolean | Whether more results are available | + + diff --git a/apps/sim/blocks/blocks/amplitude.ts b/apps/sim/blocks/blocks/amplitude.ts new file mode 100644 index 0000000000..e9cbf61834 --- /dev/null +++ b/apps/sim/blocks/blocks/amplitude.ts @@ -0,0 +1,745 @@ +import { AmplitudeIcon } from '@/components/icons' +import { AuthMode, type BlockConfig } from '@/blocks/types' + +export const AmplitudeBlock: BlockConfig = { + type: 'amplitude', + name: 'Amplitude', + description: 'Track events and query analytics from Amplitude', + longDescription: + 'Integrate Amplitude into your workflow to track events, identify users and groups, search for users, query analytics, and retrieve revenue data.', + docsLink: 'https://docs.sim.ai/tools/amplitude', + category: 'tools', + bgColor: '#1B1F3B', + icon: AmplitudeIcon, + authMode: AuthMode.ApiKey, + + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Send Event', id: 'send_event' }, + { label: 'Identify User', id: 'identify_user' }, + { label: 'Group Identify', id: 'group_identify' }, + { label: 'User Search', id: 'user_search' }, + { label: 'User Activity', id: 'user_activity' }, + { label: 'User Profile', id: 'user_profile' }, + { label: 'Event Segmentation', id: 'event_segmentation' }, + { label: 'Get Active Users', id: 'get_active_users' }, + { label: 'Real-time Active Users', id: 'realtime_active_users' }, + { label: 'List Events', id: 'list_events' }, + { label: 'Get Revenue', id: 'get_revenue' }, + ], + value: () => 'send_event', + }, + + // API Key (required for all operations) + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + required: true, + placeholder: 'Enter your Amplitude API Key', + password: true, + condition: { + field: 'operation', + value: 'user_profile', + not: true, + }, + }, + + // API Key for user_profile (not required - uses only secretKey) + // User Profile uses Api-Key header with secret key only + + // Secret Key (required for Dashboard REST API operations + User Profile) + { + id: 'secretKey', + title: 'Secret Key', + type: 'short-input', + required: { + field: 'operation', + value: [ + 'user_search', + 'user_activity', + 'user_profile', + 'event_segmentation', + 'get_active_users', + 'realtime_active_users', + 'list_events', + 'get_revenue', + ], + }, + placeholder: 'Enter your Amplitude Secret Key', + password: true, + condition: { + field: 'operation', + value: [ + 'user_search', + 'user_activity', + 'user_profile', + 'event_segmentation', + 'get_active_users', + 'realtime_active_users', + 'list_events', + 'get_revenue', + ], + }, + }, + + // --- Send Event fields --- + { + id: 'eventType', + title: 'Event Type', + type: 'short-input', + required: { field: 'operation', value: 'send_event' }, + placeholder: 'e.g., page_view, purchase, signup', + condition: { field: 'operation', value: 'send_event' }, + }, + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'User identifier', + condition: { field: 'operation', value: ['send_event', 'identify_user'] }, + }, + { + id: 'profileUserId', + title: 'User ID', + type: 'short-input', + placeholder: 'External user ID (required if no Device ID)', + condition: { field: 'operation', value: 'user_profile' }, + }, + { + id: 'deviceId', + title: 'Device ID', + type: 'short-input', + placeholder: 'Device identifier', + condition: { field: 'operation', value: ['send_event', 'identify_user'] }, + mode: 'advanced', + }, + { + id: 'profileDeviceId', + title: 'Device ID', + type: 'short-input', + placeholder: 'Device ID (required if no User ID)', + condition: { field: 'operation', value: 'user_profile' }, + mode: 'advanced', + }, + { + id: 'eventProperties', + title: 'Event Properties', + type: 'long-input', + placeholder: '{"button": "signup", "page": "/home"}', + condition: { field: 'operation', value: 'send_event' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON object of event properties for an Amplitude event. Return ONLY the JSON object - no explanations, no extra text.', + generationType: 'json-object', + }, + }, + { + id: 'sendEventUserProperties', + title: 'User Properties', + type: 'long-input', + placeholder: '{"$set": {"plan": "premium"}}', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON object of user properties for Amplitude. Use $set, $setOnce, $add, $append, or $unset operations. Return ONLY the JSON object - no explanations, no extra text.', + generationType: 'json-object', + }, + }, + { + id: 'platform', + title: 'Platform', + type: 'short-input', + placeholder: 'e.g., Web, iOS, Android', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'appVersion', + title: 'App Version', + type: 'short-input', + placeholder: 'e.g., 1.0.0', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'insertId', + title: 'Insert ID', + type: 'short-input', + placeholder: 'Unique ID for deduplication', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'price', + title: 'Price', + type: 'short-input', + placeholder: '9.99', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'quantity', + title: 'Quantity', + type: 'short-input', + placeholder: '1', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'revenue', + title: 'Revenue', + type: 'short-input', + placeholder: '9.99', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'productId', + title: 'Product ID', + type: 'short-input', + placeholder: 'Product identifier', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'revenueType', + title: 'Revenue Type', + type: 'short-input', + placeholder: 'e.g., purchase, refund', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'country', + title: 'Country', + type: 'short-input', + placeholder: 'Two-letter country code (e.g., US)', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'language', + title: 'Language', + type: 'short-input', + placeholder: 'Language code (e.g., en)', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'ip', + title: 'IP Address', + type: 'short-input', + placeholder: 'IP for geo-location (use "$remote" for request IP)', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + { + id: 'time', + title: 'Timestamp', + type: 'short-input', + placeholder: 'Milliseconds since epoch', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a timestamp in milliseconds since epoch for the current time. Return ONLY the number - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'sessionId', + title: 'Session ID', + type: 'short-input', + placeholder: 'Session start time in milliseconds (-1 for no session)', + condition: { field: 'operation', value: 'send_event' }, + mode: 'advanced', + }, + + // --- Identify User fields --- + { + id: 'identifyUserProperties', + title: 'User Properties', + type: 'long-input', + required: { field: 'operation', value: 'identify_user' }, + placeholder: '{"$set": {"plan": "premium", "company": "Acme"}}', + condition: { field: 'operation', value: 'identify_user' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON object of user properties for Amplitude Identify API. Use $set, $setOnce, $add, $append, or $unset operations. Return ONLY the JSON object - no explanations, no extra text.', + generationType: 'json-object', + }, + }, + + // --- Group Identify fields --- + { + id: 'groupType', + title: 'Group Type', + type: 'short-input', + required: { field: 'operation', value: 'group_identify' }, + placeholder: 'e.g., company, org_id', + condition: { field: 'operation', value: 'group_identify' }, + }, + { + id: 'groupValue', + title: 'Group Value', + type: 'short-input', + required: { field: 'operation', value: 'group_identify' }, + placeholder: 'e.g., Acme Corp', + condition: { field: 'operation', value: 'group_identify' }, + }, + { + id: 'groupProperties', + title: 'Group Properties', + type: 'long-input', + required: { field: 'operation', value: 'group_identify' }, + placeholder: '{"$set": {"industry": "tech", "employee_count": 500}}', + condition: { field: 'operation', value: 'group_identify' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a JSON object of group properties for Amplitude Group Identify API. Use $set, $setOnce, $add, $append, or $unset operations. Return ONLY the JSON object - no explanations, no extra text.', + generationType: 'json-object', + }, + }, + + // --- User Search fields --- + { + id: 'searchUser', + title: 'User', + type: 'short-input', + required: { field: 'operation', value: 'user_search' }, + placeholder: 'User ID, Device ID, or Amplitude ID', + condition: { field: 'operation', value: 'user_search' }, + }, + + // --- User Activity fields --- + { + id: 'amplitudeId', + title: 'Amplitude ID', + type: 'short-input', + required: { field: 'operation', value: 'user_activity' }, + placeholder: 'Amplitude internal user ID', + condition: { field: 'operation', value: 'user_activity' }, + }, + { + id: 'activityOffset', + title: 'Offset', + type: 'short-input', + placeholder: '0', + condition: { field: 'operation', value: 'user_activity' }, + mode: 'advanced', + }, + { + id: 'activityLimit', + title: 'Limit', + type: 'short-input', + placeholder: '1000', + condition: { field: 'operation', value: 'user_activity' }, + mode: 'advanced', + }, + { + id: 'activityDirection', + title: 'Direction', + type: 'dropdown', + options: [ + { label: 'Latest First', id: 'latest' }, + { label: 'Earliest First', id: 'earliest' }, + ], + value: () => 'latest', + condition: { field: 'operation', value: 'user_activity' }, + mode: 'advanced', + }, + + // --- User Profile fields --- + { + id: 'getAmpProps', + title: 'Include User Properties', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', + condition: { field: 'operation', value: 'user_profile' }, + mode: 'advanced', + }, + { + id: 'getCohortIds', + title: 'Include Cohort IDs', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', + condition: { field: 'operation', value: 'user_profile' }, + mode: 'advanced', + }, + { + id: 'getComputations', + title: 'Include Computed Properties', + type: 'dropdown', + options: [ + { label: 'No', id: 'false' }, + { label: 'Yes', id: 'true' }, + ], + value: () => 'false', + condition: { field: 'operation', value: 'user_profile' }, + mode: 'advanced', + }, + + // --- Event Segmentation fields --- + { + id: 'segmentationEventType', + title: 'Event Type', + type: 'short-input', + required: { field: 'operation', value: 'event_segmentation' }, + placeholder: 'Event type to analyze', + condition: { field: 'operation', value: 'event_segmentation' }, + }, + { + id: 'segmentationStart', + title: 'Start Date', + type: 'short-input', + required: { field: 'operation', value: 'event_segmentation' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'event_segmentation' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'segmentationEnd', + title: 'End Date', + type: 'short-input', + required: { field: 'operation', value: 'event_segmentation' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'event_segmentation' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'segmentationMetric', + title: 'Metric', + type: 'dropdown', + options: [ + { label: 'Uniques', id: 'uniques' }, + { label: 'Totals', id: 'totals' }, + { label: '% DAU', id: 'pct_dau' }, + { label: 'Average', id: 'average' }, + { label: 'Histogram', id: 'histogram' }, + { label: 'Sums', id: 'sums' }, + { label: 'Value Average', id: 'value_avg' }, + { label: 'Formula', id: 'formula' }, + ], + value: () => 'uniques', + condition: { field: 'operation', value: 'event_segmentation' }, + mode: 'advanced', + }, + { + id: 'segmentationInterval', + title: 'Interval', + type: 'dropdown', + options: [ + { label: 'Daily', id: '1' }, + { label: 'Weekly', id: '7' }, + { label: 'Monthly', id: '30' }, + ], + value: () => '1', + condition: { field: 'operation', value: 'event_segmentation' }, + mode: 'advanced', + }, + { + id: 'segmentationGroupBy', + title: 'Group By', + type: 'short-input', + placeholder: 'Property name (prefix custom with "gp:")', + condition: { field: 'operation', value: 'event_segmentation' }, + mode: 'advanced', + }, + { + id: 'segmentationLimit', + title: 'Limit', + type: 'short-input', + placeholder: 'Max group-by values (max 1000)', + condition: { field: 'operation', value: 'event_segmentation' }, + mode: 'advanced', + }, + + // --- Get Active Users fields --- + { + id: 'activeUsersStart', + title: 'Start Date', + type: 'short-input', + required: { field: 'operation', value: 'get_active_users' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'get_active_users' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'activeUsersEnd', + title: 'End Date', + type: 'short-input', + required: { field: 'operation', value: 'get_active_users' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'get_active_users' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'activeUsersMetric', + title: 'Metric', + type: 'dropdown', + options: [ + { label: 'Active Users', id: 'active' }, + { label: 'New Users', id: 'new' }, + ], + value: () => 'active', + condition: { field: 'operation', value: 'get_active_users' }, + mode: 'advanced', + }, + { + id: 'activeUsersInterval', + title: 'Interval', + type: 'dropdown', + options: [ + { label: 'Daily', id: '1' }, + { label: 'Weekly', id: '7' }, + { label: 'Monthly', id: '30' }, + ], + value: () => '1', + condition: { field: 'operation', value: 'get_active_users' }, + mode: 'advanced', + }, + + // --- Get Revenue fields --- + { + id: 'revenueStart', + title: 'Start Date', + type: 'short-input', + required: { field: 'operation', value: 'get_revenue' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'get_revenue' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'revenueEnd', + title: 'End Date', + type: 'short-input', + required: { field: 'operation', value: 'get_revenue' }, + placeholder: 'YYYYMMDD', + condition: { field: 'operation', value: 'get_revenue' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a date in YYYYMMDD format. Return ONLY the date string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'revenueMetric', + title: 'Metric', + type: 'dropdown', + options: [ + { label: 'ARPU', id: '0' }, + { label: 'ARPPU', id: '1' }, + { label: 'Total Revenue', id: '2' }, + { label: 'Paying Users', id: '3' }, + ], + value: () => '2', + condition: { field: 'operation', value: 'get_revenue' }, + mode: 'advanced', + }, + { + id: 'revenueInterval', + title: 'Interval', + type: 'dropdown', + options: [ + { label: 'Daily', id: '1' }, + { label: 'Weekly', id: '7' }, + { label: 'Monthly', id: '30' }, + ], + value: () => '1', + condition: { field: 'operation', value: 'get_revenue' }, + mode: 'advanced', + }, + ], + + tools: { + access: [ + 'amplitude_send_event', + 'amplitude_identify_user', + 'amplitude_group_identify', + 'amplitude_user_search', + 'amplitude_user_activity', + 'amplitude_user_profile', + 'amplitude_event_segmentation', + 'amplitude_get_active_users', + 'amplitude_realtime_active_users', + 'amplitude_list_events', + 'amplitude_get_revenue', + ], + config: { + tool: (params) => `amplitude_${params.operation}`, + params: (params) => { + const result: Record = {} + + switch (params.operation) { + case 'send_event': + if (params.sendEventUserProperties) + result.userProperties = params.sendEventUserProperties + break + + case 'identify_user': + if (params.identifyUserProperties) result.userProperties = params.identifyUserProperties + break + + case 'user_search': + if (params.searchUser) result.user = params.searchUser + break + + case 'user_activity': + if (params.activityOffset) result.offset = params.activityOffset + if (params.activityLimit) result.limit = params.activityLimit + if (params.activityDirection) result.direction = params.activityDirection + break + + case 'user_profile': + if (params.profileUserId) result.userId = params.profileUserId + if (params.profileDeviceId) result.deviceId = params.profileDeviceId + break + + case 'event_segmentation': + if (params.segmentationEventType) result.eventType = params.segmentationEventType + if (params.segmentationStart) result.start = params.segmentationStart + if (params.segmentationEnd) result.end = params.segmentationEnd + if (params.segmentationMetric) result.metric = params.segmentationMetric + if (params.segmentationInterval) result.interval = params.segmentationInterval + if (params.segmentationGroupBy) result.groupBy = params.segmentationGroupBy + if (params.segmentationLimit) result.limit = params.segmentationLimit + break + + case 'get_active_users': + if (params.activeUsersStart) result.start = params.activeUsersStart + if (params.activeUsersEnd) result.end = params.activeUsersEnd + if (params.activeUsersMetric) result.metric = params.activeUsersMetric + if (params.activeUsersInterval) result.interval = params.activeUsersInterval + break + + case 'get_revenue': + if (params.revenueStart) result.start = params.revenueStart + if (params.revenueEnd) result.end = params.revenueEnd + if (params.revenueMetric) result.metric = params.revenueMetric + if (params.revenueInterval) result.interval = params.revenueInterval + break + } + + return result + }, + }, + }, + + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Amplitude API Key' }, + secretKey: { type: 'string', description: 'Amplitude Secret Key' }, + eventType: { type: 'string', description: 'Event type name' }, + userId: { type: 'string', description: 'User ID' }, + deviceId: { type: 'string', description: 'Device ID' }, + eventProperties: { type: 'string', description: 'Event properties JSON' }, + sendEventUserProperties: { type: 'string', description: 'User properties for send event' }, + identifyUserProperties: { type: 'string', description: 'User properties for identify' }, + groupType: { type: 'string', description: 'Group type classification' }, + groupValue: { type: 'string', description: 'Group identifier value' }, + groupProperties: { type: 'string', description: 'Group properties JSON' }, + searchUser: { type: 'string', description: 'User to search for' }, + amplitudeId: { type: 'string', description: 'Amplitude internal user ID' }, + profileUserId: { type: 'string', description: 'User ID for profile lookup' }, + profileDeviceId: { type: 'string', description: 'Device ID for profile lookup' }, + segmentationEventType: { type: 'string', description: 'Event type to analyze' }, + segmentationStart: { type: 'string', description: 'Segmentation start date' }, + segmentationEnd: { type: 'string', description: 'Segmentation end date' }, + activeUsersStart: { type: 'string', description: 'Active users start date' }, + activeUsersEnd: { type: 'string', description: 'Active users end date' }, + revenueStart: { type: 'string', description: 'Revenue start date' }, + revenueEnd: { type: 'string', description: 'Revenue end date' }, + }, + + outputs: { + code: { + type: 'number', + description: 'Response status code', + }, + message: { + type: 'string', + description: 'Response message (identify_user, group_identify)', + }, + eventsIngested: { + type: 'number', + description: 'Number of events ingested (send_event)', + }, + matches: { + type: 'json', + description: 'User search matches (amplitudeId, userId)', + }, + events: { + type: 'json', + description: 'Event list (list_events, user_activity)', + }, + userData: { + type: 'json', + description: 'User metadata (user_activity)', + }, + series: { + type: 'json', + description: 'Time-series data (segmentation, active_users, revenue, realtime)', + }, + seriesLabels: { + type: 'json', + description: 'Labels for each data series (segmentation, realtime, revenue)', + }, + seriesMeta: { + type: 'json', + description: 'Metadata labels for data series (active_users)', + }, + seriesCollapsed: { + type: 'json', + description: 'Collapsed aggregate totals per series (segmentation)', + }, + xValues: { + type: 'json', + description: 'X-axis date/time values for chart data', + }, + }, +} diff --git a/apps/sim/blocks/blocks/google_pagespeed.ts b/apps/sim/blocks/blocks/google_pagespeed.ts new file mode 100644 index 0000000000..955b895cbd --- /dev/null +++ b/apps/sim/blocks/blocks/google_pagespeed.ts @@ -0,0 +1,86 @@ +import { GooglePagespeedIcon } from '@/components/icons' +import { AuthMode, type BlockConfig } from '@/blocks/types' +import type { GooglePagespeedAnalyzeResponse } from '@/tools/google_pagespeed/types' + +export const GooglePagespeedBlock: BlockConfig = { + type: 'google_pagespeed', + name: 'Google PageSpeed', + description: 'Analyze webpage performance with Google PageSpeed Insights', + longDescription: + 'Analyze web pages for performance, accessibility, SEO, and best practices using Google PageSpeed Insights API powered by Lighthouse.', + docsLink: 'https://docs.sim.ai/tools/google_pagespeed', + category: 'tools', + bgColor: '#E0E0E0', + icon: GooglePagespeedIcon, + authMode: AuthMode.ApiKey, + + subBlocks: [ + { + id: 'url', + title: 'URL', + type: 'short-input', + required: true, + placeholder: 'https://example.com', + }, + { + id: 'strategy', + title: 'Strategy', + type: 'dropdown', + options: [ + { label: 'Desktop', id: 'desktop' }, + { label: 'Mobile', id: 'mobile' }, + ], + value: () => 'desktop', + }, + { + id: 'category', + title: 'Categories', + type: 'short-input', + placeholder: 'performance, accessibility, best-practices, seo', + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a comma-separated list of Google PageSpeed Insights categories to analyze. Valid values are: performance, accessibility, best-practices, seo. Return ONLY the comma-separated list - no explanations, no extra text.', + }, + }, + { + id: 'locale', + title: 'Locale', + type: 'short-input', + placeholder: 'en', + mode: 'advanced', + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + required: true, + placeholder: 'Enter your Google PageSpeed API key', + password: true, + }, + ], + + tools: { + access: ['google_pagespeed_analyze'], + config: { + tool: () => 'google_pagespeed_analyze', + }, + }, + + inputs: { + url: { type: 'string', description: 'URL to analyze' }, + strategy: { type: 'string', description: 'Analysis strategy (desktop or mobile)' }, + category: { type: 'string', description: 'Comma-separated categories to analyze' }, + locale: { type: 'string', description: 'Locale for results' }, + apiKey: { type: 'string', description: 'Google PageSpeed API key' }, + }, + + outputs: { + response: { + type: 'json', + description: + 'PageSpeed analysis results including category scores (performanceScore, accessibilityScore, bestPracticesScore, seoScore), Core Web Vitals display values and numeric values (firstContentfulPaint, largestContentfulPaint, totalBlockingTime, cumulativeLayoutShift, speedIndex, interactive), and metadata (finalUrl, overallCategory, analysisTimestamp, lighthouseVersion)', + }, + }, +} diff --git a/apps/sim/blocks/blocks/pagerduty.ts b/apps/sim/blocks/blocks/pagerduty.ts new file mode 100644 index 0000000000..34e1336bb9 --- /dev/null +++ b/apps/sim/blocks/blocks/pagerduty.ts @@ -0,0 +1,482 @@ +import { PagerDutyIcon } from '@/components/icons' +import { AuthMode, type BlockConfig } from '@/blocks/types' + +export const PagerDutyBlock: BlockConfig = { + type: 'pagerduty', + name: 'PagerDuty', + description: 'Manage incidents and on-call schedules with PagerDuty', + longDescription: + 'Integrate PagerDuty into your workflow to list, create, and update incidents, add notes, list services, and check on-call schedules.', + docsLink: 'https://docs.sim.ai/tools/pagerduty', + category: 'tools', + bgColor: '#06AC38', + icon: PagerDutyIcon, + authMode: AuthMode.ApiKey, + + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'List Incidents', id: 'list_incidents' }, + { label: 'Create Incident', id: 'create_incident' }, + { label: 'Update Incident', id: 'update_incident' }, + { label: 'Add Note', id: 'add_note' }, + { label: 'List Services', id: 'list_services' }, + { label: 'List On-Calls', id: 'list_oncalls' }, + ], + value: () => 'list_incidents', + }, + + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + required: true, + placeholder: 'Enter your PagerDuty REST API Key', + password: true, + }, + + { + id: 'fromEmail', + title: 'From Email', + type: 'short-input', + required: { + field: 'operation', + value: ['create_incident', 'update_incident', 'add_note'], + }, + placeholder: 'Valid PagerDuty user email (required for write operations)', + condition: { + field: 'operation', + value: ['create_incident', 'update_incident', 'add_note'], + }, + }, + + // --- List Incidents fields --- + { + id: 'statuses', + title: 'Statuses', + type: 'dropdown', + options: [ + { label: 'All', id: '' }, + { label: 'Triggered', id: 'triggered' }, + { label: 'Acknowledged', id: 'acknowledged' }, + { label: 'Resolved', id: 'resolved' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_incidents' }, + }, + { + id: 'listServiceIds', + title: 'Service IDs', + type: 'short-input', + placeholder: 'Comma-separated service IDs to filter', + condition: { field: 'operation', value: 'list_incidents' }, + mode: 'advanced', + }, + { + id: 'listSince', + title: 'Since', + type: 'short-input', + placeholder: 'Start date (ISO 8601, e.g., 2024-01-01T00:00:00Z)', + condition: { field: 'operation', value: 'list_incidents' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'listUntil', + title: 'Until', + type: 'short-input', + placeholder: 'End date (ISO 8601, e.g., 2024-12-31T23:59:59Z)', + condition: { field: 'operation', value: 'list_incidents' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'listSortBy', + title: 'Sort By', + type: 'dropdown', + options: [ + { label: 'Created At (newest)', id: 'created_at:desc' }, + { label: 'Created At (oldest)', id: 'created_at:asc' }, + ], + value: () => 'created_at:desc', + condition: { field: 'operation', value: 'list_incidents' }, + mode: 'advanced', + }, + { + id: 'listLimit', + title: 'Limit', + type: 'short-input', + placeholder: '25', + condition: { field: 'operation', value: 'list_incidents' }, + mode: 'advanced', + }, + + // --- Create Incident fields --- + { + id: 'title', + title: 'Title', + type: 'short-input', + required: { field: 'operation', value: 'create_incident' }, + placeholder: 'Incident title/summary', + condition: { field: 'operation', value: 'create_incident' }, + }, + { + id: 'createServiceId', + title: 'Service ID', + type: 'short-input', + required: { field: 'operation', value: 'create_incident' }, + placeholder: 'PagerDuty service ID', + condition: { field: 'operation', value: 'create_incident' }, + }, + { + id: 'createUrgency', + title: 'Urgency', + type: 'dropdown', + options: [ + { label: 'High', id: 'high' }, + { label: 'Low', id: 'low' }, + ], + value: () => 'high', + condition: { field: 'operation', value: 'create_incident' }, + }, + { + id: 'body', + title: 'Description', + type: 'long-input', + placeholder: 'Detailed description of the incident', + condition: { field: 'operation', value: 'create_incident' }, + }, + { + id: 'escalationPolicyId', + title: 'Escalation Policy ID', + type: 'short-input', + placeholder: 'Escalation policy ID (optional)', + condition: { field: 'operation', value: 'create_incident' }, + mode: 'advanced', + }, + { + id: 'assigneeId', + title: 'Assignee User ID', + type: 'short-input', + placeholder: 'User ID to assign (optional)', + condition: { field: 'operation', value: 'create_incident' }, + mode: 'advanced', + }, + + // --- Update Incident fields --- + { + id: 'updateIncidentId', + title: 'Incident ID', + type: 'short-input', + required: { field: 'operation', value: 'update_incident' }, + placeholder: 'ID of the incident to update', + condition: { field: 'operation', value: 'update_incident' }, + }, + { + id: 'updateStatus', + title: 'Status', + type: 'dropdown', + options: [ + { label: 'No Change', id: '' }, + { label: 'Acknowledged', id: 'acknowledged' }, + { label: 'Resolved', id: 'resolved' }, + ], + value: () => '', + condition: { field: 'operation', value: 'update_incident' }, + }, + { + id: 'updateTitle', + title: 'New Title', + type: 'short-input', + placeholder: 'New incident title (optional)', + condition: { field: 'operation', value: 'update_incident' }, + mode: 'advanced', + }, + { + id: 'updateUrgency', + title: 'Urgency', + type: 'dropdown', + options: [ + { label: 'No Change', id: '' }, + { label: 'High', id: 'high' }, + { label: 'Low', id: 'low' }, + ], + value: () => '', + condition: { field: 'operation', value: 'update_incident' }, + mode: 'advanced', + }, + { + id: 'updateEscalationLevel', + title: 'Escalation Level', + type: 'short-input', + placeholder: 'Escalation level number (e.g., 2)', + condition: { field: 'operation', value: 'update_incident' }, + mode: 'advanced', + }, + // --- Add Note fields --- + { + id: 'noteIncidentId', + title: 'Incident ID', + type: 'short-input', + required: { field: 'operation', value: 'add_note' }, + placeholder: 'ID of the incident', + condition: { field: 'operation', value: 'add_note' }, + }, + { + id: 'noteContent', + title: 'Note Content', + type: 'long-input', + required: { field: 'operation', value: 'add_note' }, + placeholder: 'Note text to add to the incident', + condition: { field: 'operation', value: 'add_note' }, + }, + + // --- List Services fields --- + { + id: 'serviceQuery', + title: 'Search Query', + type: 'short-input', + placeholder: 'Filter services by name', + condition: { field: 'operation', value: 'list_services' }, + }, + { + id: 'serviceLimit', + title: 'Limit', + type: 'short-input', + placeholder: '25', + condition: { field: 'operation', value: 'list_services' }, + mode: 'advanced', + }, + + // --- List On-Calls fields --- + { + id: 'oncallEscalationPolicyIds', + title: 'Escalation Policy IDs', + type: 'short-input', + placeholder: 'Comma-separated escalation policy IDs', + condition: { field: 'operation', value: 'list_oncalls' }, + }, + { + id: 'oncallScheduleIds', + title: 'Schedule IDs', + type: 'short-input', + placeholder: 'Comma-separated schedule IDs', + condition: { field: 'operation', value: 'list_oncalls' }, + mode: 'advanced', + }, + { + id: 'oncallLimit', + title: 'Limit', + type: 'short-input', + placeholder: '25', + condition: { field: 'operation', value: 'list_oncalls' }, + mode: 'advanced', + }, + { + id: 'oncallSince', + title: 'Since', + type: 'short-input', + placeholder: 'Start time (ISO 8601)', + condition: { field: 'operation', value: 'list_oncalls' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + { + id: 'oncallUntil', + title: 'Until', + type: 'short-input', + placeholder: 'End time (ISO 8601)', + condition: { field: 'operation', value: 'list_oncalls' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string - no explanations, no extra text.', + generationType: 'timestamp', + }, + }, + ], + + tools: { + access: [ + 'pagerduty_list_incidents', + 'pagerduty_create_incident', + 'pagerduty_update_incident', + 'pagerduty_add_note', + 'pagerduty_list_services', + 'pagerduty_list_oncalls', + ], + config: { + tool: (params) => `pagerduty_${params.operation}`, + params: (params) => { + const result: Record = {} + + switch (params.operation) { + case 'list_incidents': + if (params.statuses) result.statuses = params.statuses + if (params.listServiceIds) result.serviceIds = params.listServiceIds + if (params.listSince) result.since = params.listSince + if (params.listUntil) result.until = params.listUntil + if (params.listSortBy) result.sortBy = params.listSortBy + if (params.listLimit) result.limit = params.listLimit + break + + case 'create_incident': + if (params.createServiceId) result.serviceId = params.createServiceId + if (params.createUrgency) result.urgency = params.createUrgency + break + + case 'update_incident': + if (params.updateIncidentId) result.incidentId = params.updateIncidentId + if (params.updateStatus) result.status = params.updateStatus + if (params.updateTitle) result.title = params.updateTitle + if (params.updateUrgency) result.urgency = params.updateUrgency + if (params.updateEscalationLevel) result.escalationLevel = params.updateEscalationLevel + break + + case 'add_note': + if (params.noteIncidentId) result.incidentId = params.noteIncidentId + if (params.noteContent) result.content = params.noteContent + break + + case 'list_services': + if (params.serviceQuery) result.query = params.serviceQuery + if (params.serviceLimit) result.limit = params.serviceLimit + break + + case 'list_oncalls': + if (params.oncallEscalationPolicyIds) + result.escalationPolicyIds = params.oncallEscalationPolicyIds + if (params.oncallScheduleIds) result.scheduleIds = params.oncallScheduleIds + if (params.oncallSince) result.since = params.oncallSince + if (params.oncallUntil) result.until = params.oncallUntil + if (params.oncallLimit) result.limit = params.oncallLimit + break + } + + return result + }, + }, + }, + + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'PagerDuty REST API Key' }, + fromEmail: { type: 'string', description: 'Valid PagerDuty user email' }, + statuses: { type: 'string', description: 'Status filter for incidents' }, + listServiceIds: { type: 'string', description: 'Service IDs filter' }, + listSince: { type: 'string', description: 'Start date filter' }, + listUntil: { type: 'string', description: 'End date filter' }, + title: { type: 'string', description: 'Incident title' }, + createServiceId: { type: 'string', description: 'Service ID for new incident' }, + createUrgency: { type: 'string', description: 'Urgency level' }, + body: { type: 'string', description: 'Incident description' }, + updateIncidentId: { type: 'string', description: 'Incident ID to update' }, + updateStatus: { type: 'string', description: 'New status' }, + noteIncidentId: { type: 'string', description: 'Incident ID for note' }, + noteContent: { type: 'string', description: 'Note content' }, + escalationPolicyId: { type: 'string', description: 'Escalation policy ID' }, + assigneeId: { type: 'string', description: 'Assignee user ID' }, + updateTitle: { type: 'string', description: 'New incident title' }, + updateUrgency: { type: 'string', description: 'New urgency level' }, + updateEscalationLevel: { type: 'string', description: 'Escalation level number' }, + listSortBy: { type: 'string', description: 'Sort field' }, + listLimit: { type: 'string', description: 'Max results for incidents' }, + serviceQuery: { type: 'string', description: 'Service name filter' }, + serviceLimit: { type: 'string', description: 'Max results for services' }, + oncallEscalationPolicyIds: { type: 'string', description: 'Escalation policy IDs filter' }, + oncallScheduleIds: { type: 'string', description: 'Schedule IDs filter' }, + oncallSince: { type: 'string', description: 'On-call start time filter' }, + oncallUntil: { type: 'string', description: 'On-call end time filter' }, + oncallLimit: { type: 'string', description: 'Max results for on-calls' }, + }, + + outputs: { + incidents: { + type: 'json', + description: 'Array of incidents (list_incidents)', + }, + total: { + type: 'number', + description: 'Total count of results', + }, + more: { + type: 'boolean', + description: 'Whether more results are available', + }, + id: { + type: 'string', + description: 'Created/updated resource ID', + }, + incidentNumber: { + type: 'number', + description: 'Incident number', + }, + title: { + type: 'string', + description: 'Incident title', + }, + status: { + type: 'string', + description: 'Incident status', + }, + urgency: { + type: 'string', + description: 'Incident urgency', + }, + createdAt: { + type: 'string', + description: 'Creation timestamp', + }, + updatedAt: { + type: 'string', + description: 'Last updated timestamp', + }, + serviceName: { + type: 'string', + description: 'Service name', + }, + serviceId: { + type: 'string', + description: 'Service ID', + }, + htmlUrl: { + type: 'string', + description: 'PagerDuty web URL', + }, + content: { + type: 'string', + description: 'Note content (add_note)', + }, + userName: { + type: 'string', + description: 'User name (add_note)', + }, + services: { + type: 'json', + description: 'Array of services (list_services)', + }, + oncalls: { + type: 'json', + description: 'Array of on-call entries (list_oncalls)', + }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index b65005b316..0e3e2c695e 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -4,6 +4,7 @@ import { AhrefsBlock } from '@/blocks/blocks/ahrefs' import { AirtableBlock } from '@/blocks/blocks/airtable' import { AirweaveBlock } from '@/blocks/blocks/airweave' import { AlgoliaBlock } from '@/blocks/blocks/algolia' +import { AmplitudeBlock } from '@/blocks/blocks/amplitude' import { ApiBlock } from '@/blocks/blocks/api' import { ApiTriggerBlock } from '@/blocks/blocks/api_trigger' import { ApifyBlock } from '@/blocks/blocks/apify' @@ -56,6 +57,7 @@ import { GoogleDriveBlock } from '@/blocks/blocks/google_drive' import { GoogleFormsBlock } from '@/blocks/blocks/google_forms' import { GoogleGroupsBlock } from '@/blocks/blocks/google_groups' import { GoogleMapsBlock } from '@/blocks/blocks/google_maps' +import { GooglePagespeedBlock } from '@/blocks/blocks/google_pagespeed' import { GoogleSheetsBlock, GoogleSheetsV2Block } from '@/blocks/blocks/google_sheets' import { GoogleSlidesBlock, GoogleSlidesV2Block } from '@/blocks/blocks/google_slides' import { GoogleTasksBlock } from '@/blocks/blocks/google_tasks' @@ -112,6 +114,7 @@ import { OneDriveBlock } from '@/blocks/blocks/onedrive' import { OnePasswordBlock } from '@/blocks/blocks/onepassword' import { OpenAIBlock } from '@/blocks/blocks/openai' import { OutlookBlock } from '@/blocks/blocks/outlook' +import { PagerDutyBlock } from '@/blocks/blocks/pagerduty' import { ParallelBlock } from '@/blocks/blocks/parallel' import { PerplexityBlock } from '@/blocks/blocks/perplexity' import { PineconeBlock } from '@/blocks/blocks/pinecone' @@ -193,6 +196,7 @@ export const registry: Record = { airtable: AirtableBlock, airweave: AirweaveBlock, algolia: AlgoliaBlock, + amplitude: AmplitudeBlock, api: ApiBlock, api_trigger: ApiTriggerBlock, apify: ApifyBlock, @@ -250,6 +254,7 @@ export const registry: Record = { google_forms: GoogleFormsBlock, google_groups: GoogleGroupsBlock, google_maps: GoogleMapsBlock, + google_pagespeed: GooglePagespeedBlock, google_tasks: GoogleTasksBlock, google_translate: GoogleTranslateBlock, gong: GongBlock, @@ -313,6 +318,7 @@ export const registry: Record = { onedrive: OneDriveBlock, openai: OpenAIBlock, outlook: OutlookBlock, + pagerduty: PagerDutyBlock, parallel_ai: ParallelBlock, perplexity: PerplexityBlock, pinecone: PineconeBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 51cd709bb7..c4666fba17 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -1209,6 +1209,17 @@ export function AlgoliaIcon(props: SVGProps) { ) } +export function AmplitudeIcon(props: SVGProps) { + return ( + + + + ) +} + export function GoogleBooksIcon(props: SVGProps) { return ( @@ -1938,13 +1949,11 @@ export function ElevenLabsIcon(props: SVGProps) { export function LinkupIcon(props: SVGProps) { return ( - - - - + + ) } @@ -2453,6 +2462,17 @@ export function OutlookIcon(props: SVGProps) { ) } +export function PagerDutyIcon(props: SVGProps) { + return ( + + + + ) +} + export function MicrosoftExcelIcon(props: SVGProps) { const id = useId() const gradientId = `excel_gradient_${id}` @@ -3996,10 +4016,10 @@ export function IntercomIcon(props: SVGProps) { export function LoopsIcon(props: SVGProps) { return ( - + ) @@ -5578,6 +5598,35 @@ export function GoogleMapsIcon(props: SVGProps) { ) } +export function GooglePagespeedIcon(props: SVGProps) { + return ( + + + + + + + + + + ) +} + export function GoogleTranslateIcon(props: SVGProps) { return ( diff --git a/apps/sim/tools/amplitude/event_segmentation.ts b/apps/sim/tools/amplitude/event_segmentation.ts new file mode 100644 index 0000000000..d5cbab3357 --- /dev/null +++ b/apps/sim/tools/amplitude/event_segmentation.ts @@ -0,0 +1,134 @@ +import type { + AmplitudeEventSegmentationParams, + AmplitudeEventSegmentationResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const eventSegmentationTool: ToolConfig< + AmplitudeEventSegmentationParams, + AmplitudeEventSegmentationResponse +> = { + id: 'amplitude_event_segmentation', + name: 'Amplitude Event Segmentation', + description: + 'Query event analytics data with segmentation. Get event counts, uniques, averages, and more.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + eventType: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Event type name to analyze', + }, + start: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in YYYYMMDD format', + }, + end: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'End date in YYYYMMDD format', + }, + metric: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Metric type: uniques, totals, pct_dau, average, histogram, sums, value_avg, or formula (default: uniques)', + }, + interval: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Time interval: 1 (daily), 7 (weekly), or 30 (monthly)', + }, + groupBy: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Property name to group by (prefix custom user properties with "gp:")', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of group-by values (max 1000)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://amplitude.com/api/2/events/segmentation') + const eventObj = JSON.stringify({ event_type: params.eventType }) + url.searchParams.set('e', eventObj) + url.searchParams.set('start', params.start) + url.searchParams.set('end', params.end) + if (params.metric) url.searchParams.set('m', params.metric) + if (params.interval) url.searchParams.set('i', params.interval) + if (params.groupBy) url.searchParams.set('g', params.groupBy) + if (params.limit) url.searchParams.set('limit', params.limit) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude Event Segmentation API error: ${response.status}`) + } + + const result = data.data ?? {} + + return { + success: true, + output: { + series: result.series ?? [], + seriesLabels: result.seriesLabels ?? [], + seriesCollapsed: result.seriesCollapsed ?? [], + xValues: result.xValues ?? [], + }, + } + }, + + outputs: { + series: { + type: 'json', + description: 'Time-series data arrays indexed by series', + }, + seriesLabels: { + type: 'array', + description: 'Labels for each data series', + items: { type: 'string' }, + }, + seriesCollapsed: { + type: 'json', + description: 'Collapsed aggregate totals per series', + }, + xValues: { + type: 'array', + description: 'Date values for the x-axis', + items: { type: 'string' }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/get_active_users.ts b/apps/sim/tools/amplitude/get_active_users.ts new file mode 100644 index 0000000000..6670e5ab15 --- /dev/null +++ b/apps/sim/tools/amplitude/get_active_users.ts @@ -0,0 +1,105 @@ +import type { + AmplitudeGetActiveUsersParams, + AmplitudeGetActiveUsersResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const getActiveUsersTool: ToolConfig< + AmplitudeGetActiveUsersParams, + AmplitudeGetActiveUsersResponse +> = { + id: 'amplitude_get_active_users', + name: 'Amplitude Get Active Users', + description: 'Get active or new user counts over a date range from the Dashboard REST API.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + start: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in YYYYMMDD format', + }, + end: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'End date in YYYYMMDD format', + }, + metric: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Metric type: "active" or "new" (default: active)', + }, + interval: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Time interval: 1 (daily), 7 (weekly), or 30 (monthly)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://amplitude.com/api/2/users') + url.searchParams.set('start', params.start) + url.searchParams.set('end', params.end) + if (params.metric) url.searchParams.set('m', params.metric) + if (params.interval) url.searchParams.set('i', params.interval) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude Active Users API error: ${response.status}`) + } + + const result = data.data ?? {} + + return { + success: true, + output: { + series: result.series ?? [], + seriesMeta: result.seriesMeta ?? [], + xValues: result.xValues ?? [], + }, + } + }, + + outputs: { + series: { + type: 'json', + description: 'Array of data series with user counts per time interval', + }, + seriesMeta: { + type: 'array', + description: 'Metadata labels for each data series (e.g., segment names)', + items: { type: 'string' }, + }, + xValues: { + type: 'array', + description: 'Date values for the x-axis', + items: { type: 'string' }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/get_revenue.ts b/apps/sim/tools/amplitude/get_revenue.ts new file mode 100644 index 0000000000..264eb1e0f9 --- /dev/null +++ b/apps/sim/tools/amplitude/get_revenue.ts @@ -0,0 +1,102 @@ +import type { + AmplitudeGetRevenueParams, + AmplitudeGetRevenueResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const getRevenueTool: ToolConfig = { + id: 'amplitude_get_revenue', + name: 'Amplitude Get Revenue', + description: 'Get revenue LTV data including ARPU, ARPPU, total revenue, and paying user counts.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + start: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Start date in YYYYMMDD format', + }, + end: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'End date in YYYYMMDD format', + }, + metric: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Metric: 0 (ARPU), 1 (ARPPU), 2 (Total Revenue), 3 (Paying Users)', + }, + interval: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Time interval: 1 (daily), 7 (weekly), or 30 (monthly)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://amplitude.com/api/2/revenue/ltv') + url.searchParams.set('start', params.start) + url.searchParams.set('end', params.end) + if (params.metric) url.searchParams.set('m', params.metric) + if (params.interval) url.searchParams.set('i', params.interval) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude Revenue API error: ${response.status}`) + } + + const result = data.data ?? {} + + return { + success: true, + output: { + series: result.series ?? [], + seriesLabels: result.seriesLabels ?? [], + xValues: result.xValues ?? [], + }, + } + }, + + outputs: { + series: { + type: 'json', + description: 'Array of revenue data series', + }, + seriesLabels: { + type: 'array', + description: 'Labels for each data series', + items: { type: 'string' }, + }, + xValues: { + type: 'array', + description: 'Date values for the x-axis', + items: { type: 'string' }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/group_identify.ts b/apps/sim/tools/amplitude/group_identify.ts new file mode 100644 index 0000000000..b0bd548c49 --- /dev/null +++ b/apps/sim/tools/amplitude/group_identify.ts @@ -0,0 +1,99 @@ +import type { + AmplitudeGroupIdentifyParams, + AmplitudeGroupIdentifyResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const groupIdentifyTool: ToolConfig< + AmplitudeGroupIdentifyParams, + AmplitudeGroupIdentifyResponse +> = { + id: 'amplitude_group_identify', + name: 'Amplitude Group Identify', + description: + 'Set group-level properties in Amplitude. Supports $set, $setOnce, $add, $append, $unset operations.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + groupType: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Group classification (e.g., "company", "org_id")', + }, + groupValue: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Specific group identifier (e.g., "Acme Corp")', + }, + groupProperties: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'JSON object of group properties. Use operations like $set, $setOnce, $add, $append, $unset.', + }, + }, + + request: { + url: 'https://api2.amplitude.com/groupidentify', + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params) => { + let groupProperties: Record = {} + try { + groupProperties = JSON.parse(params.groupProperties) + } catch { + groupProperties = {} + } + + return { + api_key: params.apiKey, + identification: [ + { + group_type: params.groupType, + group_value: params.groupValue, + group_properties: groupProperties, + }, + ], + } + }, + }, + + transformResponse: async (response: Response) => { + const text = await response.text() + + if (!response.ok) { + throw new Error(`Amplitude Group Identify API error: ${text}`) + } + + return { + success: true, + output: { + code: response.status, + message: text || null, + }, + } + }, + + outputs: { + code: { + type: 'number', + description: 'HTTP response status code', + }, + message: { + type: 'string', + description: 'Response message', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/amplitude/identify_user.ts b/apps/sim/tools/amplitude/identify_user.ts new file mode 100644 index 0000000000..a0cb031680 --- /dev/null +++ b/apps/sim/tools/amplitude/identify_user.ts @@ -0,0 +1,97 @@ +import type { + AmplitudeIdentifyUserParams, + AmplitudeIdentifyUserResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const identifyUserTool: ToolConfig< + AmplitudeIdentifyUserParams, + AmplitudeIdentifyUserResponse +> = { + id: 'amplitude_identify_user', + name: 'Amplitude Identify User', + description: + 'Set user properties in Amplitude using the Identify API. Supports $set, $setOnce, $add, $append, $unset operations.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + userId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'User ID (required if no device_id)', + }, + deviceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID (required if no user_id)', + }, + userProperties: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'JSON object of user properties. Use operations like $set, $setOnce, $add, $append, $unset.', + }, + }, + + request: { + url: 'https://api2.amplitude.com/identify', + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params) => { + const identification: Record = {} + + if (params.userId) identification.user_id = params.userId + if (params.deviceId) identification.device_id = params.deviceId + + try { + identification.user_properties = JSON.parse(params.userProperties) + } catch { + identification.user_properties = {} + } + + return { + api_key: params.apiKey, + identification: [identification], + } + }, + }, + + transformResponse: async (response: Response) => { + const text = await response.text() + + if (!response.ok) { + throw new Error(`Amplitude Identify API error: ${text}`) + } + + return { + success: true, + output: { + code: response.status, + message: text || null, + }, + } + }, + + outputs: { + code: { + type: 'number', + description: 'HTTP response status code', + }, + message: { + type: 'string', + description: 'Response message', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/amplitude/index.ts b/apps/sim/tools/amplitude/index.ts new file mode 100644 index 0000000000..b0f1aab792 --- /dev/null +++ b/apps/sim/tools/amplitude/index.ts @@ -0,0 +1,23 @@ +import { eventSegmentationTool } from '@/tools/amplitude/event_segmentation' +import { getActiveUsersTool } from '@/tools/amplitude/get_active_users' +import { getRevenueTool } from '@/tools/amplitude/get_revenue' +import { groupIdentifyTool } from '@/tools/amplitude/group_identify' +import { identifyUserTool } from '@/tools/amplitude/identify_user' +import { listEventsTool } from '@/tools/amplitude/list_events' +import { realtimeActiveUsersTool } from '@/tools/amplitude/realtime_active_users' +import { sendEventTool } from '@/tools/amplitude/send_event' +import { userActivityTool } from '@/tools/amplitude/user_activity' +import { userProfileTool } from '@/tools/amplitude/user_profile' +import { userSearchTool } from '@/tools/amplitude/user_search' + +export const amplitudeSendEventTool = sendEventTool +export const amplitudeIdentifyUserTool = identifyUserTool +export const amplitudeGroupIdentifyTool = groupIdentifyTool +export const amplitudeUserSearchTool = userSearchTool +export const amplitudeUserActivityTool = userActivityTool +export const amplitudeUserProfileTool = userProfileTool +export const amplitudeEventSegmentationTool = eventSegmentationTool +export const amplitudeGetActiveUsersTool = getActiveUsersTool +export const amplitudeRealtimeActiveUsersTool = realtimeActiveUsersTool +export const amplitudeListEventsTool = listEventsTool +export const amplitudeGetRevenueTool = getRevenueTool diff --git a/apps/sim/tools/amplitude/list_events.ts b/apps/sim/tools/amplitude/list_events.ts new file mode 100644 index 0000000000..fa89d3ddf1 --- /dev/null +++ b/apps/sim/tools/amplitude/list_events.ts @@ -0,0 +1,79 @@ +import type { + AmplitudeListEventsParams, + AmplitudeListEventsResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const listEventsTool: ToolConfig = { + id: 'amplitude_list_events', + name: 'Amplitude List Events', + description: + 'List all event types in the Amplitude project with their weekly totals and unique counts.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + }, + + request: { + url: 'https://amplitude.com/api/2/events/list', + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude List Events API error: ${response.status}`) + } + + const events = (data.data ?? []).map( + (e: Record) => + ({ + value: (e.value as string) ?? '', + displayName: (e.display as string) ?? null, + totals: (e.totals as number) ?? 0, + hidden: (e.hidden as boolean) ?? false, + deleted: (e.deleted as boolean) ?? false, + }) as const + ) + + return { + success: true, + output: { + events, + }, + } + }, + + outputs: { + events: { + type: 'array', + description: 'List of event types in the project', + items: { + type: 'object', + properties: { + value: { type: 'string', description: 'Event type name' }, + displayName: { type: 'string', description: 'Event display name' }, + totals: { type: 'number', description: 'Weekly total count' }, + hidden: { type: 'boolean', description: 'Whether the event is hidden' }, + deleted: { type: 'boolean', description: 'Whether the event is deleted' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/realtime_active_users.ts b/apps/sim/tools/amplitude/realtime_active_users.ts new file mode 100644 index 0000000000..0462d699dc --- /dev/null +++ b/apps/sim/tools/amplitude/realtime_active_users.ts @@ -0,0 +1,74 @@ +import type { + AmplitudeRealtimeActiveUsersParams, + AmplitudeRealtimeActiveUsersResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const realtimeActiveUsersTool: ToolConfig< + AmplitudeRealtimeActiveUsersParams, + AmplitudeRealtimeActiveUsersResponse +> = { + id: 'amplitude_realtime_active_users', + name: 'Amplitude Real-time Active Users', + description: 'Get real-time active user counts at 5-minute granularity for the last 2 days.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + }, + + request: { + url: 'https://amplitude.com/api/2/realtime', + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude Real-time API error: ${response.status}`) + } + + const result = data.data ?? {} + + return { + success: true, + output: { + series: result.series ?? [], + seriesLabels: result.seriesLabels ?? [], + xValues: result.xValues ?? [], + }, + } + }, + + outputs: { + series: { + type: 'json', + description: 'Array of data series with active user counts at 5-minute intervals', + }, + seriesLabels: { + type: 'array', + description: 'Labels for each series (e.g., "Today", "Yesterday")', + items: { type: 'string' }, + }, + xValues: { + type: 'array', + description: 'Time values for the x-axis (e.g., "15:00", "15:05")', + items: { type: 'string' }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/send_event.ts b/apps/sim/tools/amplitude/send_event.ts new file mode 100644 index 0000000000..a24c0a45f3 --- /dev/null +++ b/apps/sim/tools/amplitude/send_event.ts @@ -0,0 +1,214 @@ +import type { AmplitudeSendEventParams, AmplitudeSendEventResponse } from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const sendEventTool: ToolConfig = { + id: 'amplitude_send_event', + name: 'Amplitude Send Event', + description: 'Track an event in Amplitude using the HTTP V2 API.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + userId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'User ID (required if no device_id)', + }, + deviceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID (required if no user_id)', + }, + eventType: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the event (e.g., "page_view", "purchase")', + }, + eventProperties: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'JSON object of custom event properties', + }, + userProperties: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON object of user properties to set (supports $set, $setOnce, $add, $append, $unset)', + }, + time: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Event timestamp in milliseconds since epoch', + }, + sessionId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Session start time in milliseconds since epoch', + }, + insertId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Unique ID for deduplication (within 7-day window)', + }, + appVersion: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Application version string', + }, + platform: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Platform (e.g., "Web", "iOS", "Android")', + }, + country: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Two-letter country code', + }, + language: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Language code (e.g., "en")', + }, + ip: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'IP address for geo-location', + }, + price: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Price of the item purchased', + }, + quantity: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Quantity of items purchased', + }, + revenue: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Revenue amount', + }, + productId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Product identifier', + }, + revenueType: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Revenue type (e.g., "purchase", "refund")', + }, + }, + + request: { + url: 'https://api2.amplitude.com/2/httpapi', + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params) => { + const event: Record = { + event_type: params.eventType, + } + + if (params.userId) event.user_id = params.userId + if (params.deviceId) event.device_id = params.deviceId + if (params.time) event.time = Number(params.time) + if (params.sessionId) event.session_id = Number(params.sessionId) + if (params.insertId) event.insert_id = params.insertId + if (params.appVersion) event.app_version = params.appVersion + if (params.platform) event.platform = params.platform + if (params.country) event.country = params.country + if (params.language) event.language = params.language + if (params.ip) event.ip = params.ip + if (params.price) event.price = Number(params.price) + if (params.quantity) event.quantity = Number(params.quantity) + if (params.revenue) event.revenue = Number(params.revenue) + if (params.productId) event.product_id = params.productId + if (params.revenueType) event.revenue_type = params.revenueType + + if (params.eventProperties) { + try { + event.event_properties = JSON.parse(params.eventProperties) + } catch { + event.event_properties = {} + } + } + + if (params.userProperties) { + try { + event.user_properties = JSON.parse(params.userProperties) + } catch { + event.user_properties = {} + } + } + + return { + api_key: params.apiKey, + events: [event], + } + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (data.code !== 200) { + throw new Error(data.error || `Amplitude API error: code ${data.code}`) + } + + return { + success: true, + output: { + code: data.code ?? 200, + eventsIngested: data.events_ingested ?? 0, + payloadSizeBytes: data.payload_size_bytes ?? 0, + serverUploadTime: data.server_upload_time ?? 0, + }, + } + }, + + outputs: { + code: { + type: 'number', + description: 'Response code (200 for success)', + }, + eventsIngested: { + type: 'number', + description: 'Number of events ingested', + }, + payloadSizeBytes: { + type: 'number', + description: 'Size of the payload in bytes', + }, + serverUploadTime: { + type: 'number', + description: 'Server upload timestamp', + }, + }, +} diff --git a/apps/sim/tools/amplitude/types.ts b/apps/sim/tools/amplitude/types.ts new file mode 100644 index 0000000000..737de7c8e4 --- /dev/null +++ b/apps/sim/tools/amplitude/types.ts @@ -0,0 +1,241 @@ +import type { ToolResponse } from '@/tools/types' + +/** + * Base params shared by endpoints using API key in body. + */ +export interface AmplitudeApiKeyParams { + apiKey: string +} + +/** + * Base params shared by endpoints using Basic Auth (api_key:secret_key). + */ +export interface AmplitudeBasicAuthParams { + apiKey: string + secretKey: string +} + +/** + * Send Event params (HTTP V2 API). + */ +export interface AmplitudeSendEventParams extends AmplitudeApiKeyParams { + userId?: string + deviceId?: string + eventType: string + eventProperties?: string + userProperties?: string + time?: string + sessionId?: string + insertId?: string + appVersion?: string + platform?: string + country?: string + language?: string + ip?: string + price?: string + quantity?: string + revenue?: string + productId?: string + revenueType?: string +} + +export interface AmplitudeSendEventResponse extends ToolResponse { + output: { + code: number + eventsIngested: number + payloadSizeBytes: number + serverUploadTime: number + } +} + +/** + * Identify User params (Identify API). + */ +export interface AmplitudeIdentifyUserParams extends AmplitudeApiKeyParams { + userId?: string + deviceId?: string + userProperties: string +} + +export interface AmplitudeIdentifyUserResponse extends ToolResponse { + output: { + code: number + message: string | null + } +} + +/** + * Group Identify params (Group Identify API). + */ +export interface AmplitudeGroupIdentifyParams extends AmplitudeApiKeyParams { + groupType: string + groupValue: string + groupProperties: string +} + +export interface AmplitudeGroupIdentifyResponse extends ToolResponse { + output: { + code: number + message: string | null + } +} + +/** + * User Search params (Dashboard REST API). + */ +export interface AmplitudeUserSearchParams extends AmplitudeBasicAuthParams { + user: string +} + +export interface AmplitudeUserSearchResponse extends ToolResponse { + output: { + matches: Array<{ + amplitudeId: number + userId: string | null + }> + type: string | null + } +} + +/** + * User Activity params (Dashboard REST API). + */ +export interface AmplitudeUserActivityParams extends AmplitudeBasicAuthParams { + amplitudeId: string + offset?: string + limit?: string + direction?: string +} + +export interface AmplitudeUserActivityResponse extends ToolResponse { + output: { + events: Array<{ + eventType: string + eventTime: string + eventProperties: Record + userProperties: Record + sessionId: number | null + platform: string | null + country: string | null + city: string | null + }> + userData: { + userId: string | null + canonicalAmplitudeId: number | null + numEvents: number | null + numSessions: number | null + platform: string | null + country: string | null + } | null + } +} + +/** + * User Profile params (User Profile API). + */ +export interface AmplitudeUserProfileParams { + secretKey: string + userId?: string + deviceId?: string + getAmpProps?: string + getCohortIds?: string + getComputations?: string +} + +export interface AmplitudeUserProfileResponse extends ToolResponse { + output: { + userId: string | null + deviceId: string | null + ampProps: Record | null + cohortIds: string[] | null + computations: Record | null + } +} + +/** + * Event Segmentation params (Dashboard REST API). + */ +export interface AmplitudeEventSegmentationParams extends AmplitudeBasicAuthParams { + eventType: string + start: string + end: string + metric?: string + interval?: string + groupBy?: string + limit?: string +} + +export interface AmplitudeEventSegmentationResponse extends ToolResponse { + output: { + series: unknown[] + seriesLabels: string[] + seriesCollapsed: unknown[] + xValues: string[] + } +} + +/** + * Get Active Users params (Dashboard REST API). + */ +export interface AmplitudeGetActiveUsersParams extends AmplitudeBasicAuthParams { + start: string + end: string + metric?: string + interval?: string +} + +export interface AmplitudeGetActiveUsersResponse extends ToolResponse { + output: { + series: number[][] + seriesMeta: string[] + xValues: string[] + } +} + +/** + * Real-time Active Users params (Dashboard REST API). + */ +export interface AmplitudeRealtimeActiveUsersParams extends AmplitudeBasicAuthParams {} + +export interface AmplitudeRealtimeActiveUsersResponse extends ToolResponse { + output: { + series: number[][] + seriesLabels: string[] + xValues: string[] + } +} + +/** + * List Events params (Dashboard REST API). + */ +export interface AmplitudeListEventsParams extends AmplitudeBasicAuthParams {} + +export interface AmplitudeListEventsResponse extends ToolResponse { + output: { + events: Array<{ + value: string + displayName: string | null + totals: number + hidden: boolean + deleted: boolean + }> + } +} + +/** + * Get Revenue params (Dashboard REST API). + */ +export interface AmplitudeGetRevenueParams extends AmplitudeBasicAuthParams { + start: string + end: string + metric?: string + interval?: string +} + +export interface AmplitudeGetRevenueResponse extends ToolResponse { + output: { + series: unknown[] + seriesLabels: string[] + xValues: string[] + } +} diff --git a/apps/sim/tools/amplitude/user_activity.ts b/apps/sim/tools/amplitude/user_activity.ts new file mode 100644 index 0000000000..1dfa504e55 --- /dev/null +++ b/apps/sim/tools/amplitude/user_activity.ts @@ -0,0 +1,144 @@ +import type { + AmplitudeUserActivityParams, + AmplitudeUserActivityResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const userActivityTool: ToolConfig< + AmplitudeUserActivityParams, + AmplitudeUserActivityResponse +> = { + id: 'amplitude_user_activity', + name: 'Amplitude User Activity', + description: 'Get the event stream for a specific user by their Amplitude ID.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + amplitudeId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Amplitude internal user ID', + }, + offset: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Offset for pagination (default 0)', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of events to return (default 1000, max 1000)', + }, + direction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Sort direction: "latest" or "earliest" (default: latest)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://amplitude.com/api/2/useractivity') + url.searchParams.set('user', params.amplitudeId.trim()) + if (params.offset) url.searchParams.set('offset', params.offset) + if (params.limit) url.searchParams.set('limit', params.limit) + if (params.direction) url.searchParams.set('direction', params.direction) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude User Activity API error: ${response.status}`) + } + + const events = (data.events ?? []).map( + (e: Record) => + ({ + eventType: (e.event_type as string) ?? '', + eventTime: (e.event_time as string) ?? '', + eventProperties: (e.event_properties as Record) ?? {}, + userProperties: (e.user_properties as Record) ?? {}, + sessionId: (e.session_id as number) ?? null, + platform: (e.platform as string) ?? null, + country: (e.country as string) ?? null, + city: (e.city as string) ?? null, + }) as const + ) + + const ud = data.userData as Record | undefined + const userData = ud + ? { + userId: (ud.user_id as string) ?? null, + canonicalAmplitudeId: (ud.canonical_amplitude_id as number) ?? null, + numEvents: (ud.num_events as number) ?? null, + numSessions: (ud.num_sessions as number) ?? null, + platform: (ud.platform as string) ?? null, + country: (ud.country as string) ?? null, + } + : null + + return { + success: true, + output: { + events, + userData, + }, + } + }, + + outputs: { + events: { + type: 'array', + description: 'List of user events', + items: { + type: 'object', + properties: { + eventType: { type: 'string', description: 'Type of event' }, + eventTime: { type: 'string', description: 'Event timestamp' }, + eventProperties: { type: 'json', description: 'Custom event properties' }, + userProperties: { type: 'json', description: 'User properties at event time' }, + sessionId: { type: 'number', description: 'Session ID' }, + platform: { type: 'string', description: 'Platform' }, + country: { type: 'string', description: 'Country' }, + city: { type: 'string', description: 'City' }, + }, + }, + }, + userData: { + type: 'json', + description: 'User metadata', + optional: true, + properties: { + userId: { type: 'string', description: 'External user ID' }, + canonicalAmplitudeId: { type: 'number', description: 'Canonical Amplitude ID' }, + numEvents: { type: 'number', description: 'Total event count' }, + numSessions: { type: 'number', description: 'Total session count' }, + platform: { type: 'string', description: 'Primary platform' }, + country: { type: 'string', description: 'Country' }, + }, + }, + }, +} diff --git a/apps/sim/tools/amplitude/user_profile.ts b/apps/sim/tools/amplitude/user_profile.ts new file mode 100644 index 0000000000..05395d7e4c --- /dev/null +++ b/apps/sim/tools/amplitude/user_profile.ts @@ -0,0 +1,120 @@ +import type { + AmplitudeUserProfileParams, + AmplitudeUserProfileResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const userProfileTool: ToolConfig = + { + id: 'amplitude_user_profile', + name: 'Amplitude User Profile', + description: + 'Get a user profile including properties, cohort memberships, and computed properties.', + version: '1.0.0', + + params: { + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + userId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'External user ID (required if no device_id)', + }, + deviceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Device ID (required if no user_id)', + }, + getAmpProps: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Include Amplitude user properties (true/false, default: false)', + }, + getCohortIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Include cohort IDs the user belongs to (true/false, default: false)', + }, + getComputations: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Include computed user properties (true/false, default: false)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://profile-api.amplitude.com/v1/userprofile') + if (params.userId) url.searchParams.set('user_id', params.userId.trim()) + if (params.deviceId) url.searchParams.set('device_id', params.deviceId.trim()) + if (params.getAmpProps) url.searchParams.set('get_amp_props', params.getAmpProps) + if (params.getCohortIds) url.searchParams.set('get_cohort_ids', params.getCohortIds) + if (params.getComputations) url.searchParams.set('get_computations', params.getComputations) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Api-Key ${params.secretKey}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude User Profile API error: ${response.status}`) + } + + const userData = data.userData ?? {} + + return { + success: true, + output: { + userId: (userData.user_id as string) ?? null, + deviceId: (userData.device_id as string) ?? null, + ampProps: (userData.amp_props as Record) ?? null, + cohortIds: (userData.cohort_ids as string[]) ?? null, + computations: (userData.computations as Record) ?? null, + }, + } + }, + + outputs: { + userId: { + type: 'string', + description: 'External user ID', + optional: true, + }, + deviceId: { + type: 'string', + description: 'Device ID', + optional: true, + }, + ampProps: { + type: 'json', + description: + 'Amplitude user properties (library, first_used, last_used, custom properties)', + optional: true, + }, + cohortIds: { + type: 'array', + description: 'List of cohort IDs the user belongs to', + optional: true, + items: { type: 'string' }, + }, + computations: { + type: 'json', + description: 'Computed user properties', + optional: true, + }, + }, + } diff --git a/apps/sim/tools/amplitude/user_search.ts b/apps/sim/tools/amplitude/user_search.ts new file mode 100644 index 0000000000..91d8d2b9af --- /dev/null +++ b/apps/sim/tools/amplitude/user_search.ts @@ -0,0 +1,89 @@ +import type { + AmplitudeUserSearchParams, + AmplitudeUserSearchResponse, +} from '@/tools/amplitude/types' +import type { ToolConfig } from '@/tools/types' + +export const userSearchTool: ToolConfig = { + id: 'amplitude_user_search', + name: 'Amplitude User Search', + description: + 'Search for a user by User ID, Device ID, or Amplitude ID using the Dashboard REST API.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude API Key', + }, + secretKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Amplitude Secret Key', + }, + user: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'User ID, Device ID, or Amplitude ID to search for', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://amplitude.com/api/2/usersearch') + url.searchParams.set('user', params.user.trim()) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${btoa(`${params.apiKey}:${params.secretKey}`)}`, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || `Amplitude User Search API error: ${response.status}`) + } + + const matches = (data.matches ?? []).map( + (m: Record) => + ({ + amplitudeId: (m.amplitude_id as number) ?? 0, + userId: (m.user_id as string) ?? null, + }) as const + ) + + return { + success: true, + output: { + matches, + type: (data.type as string) ?? null, + }, + } + }, + + outputs: { + matches: { + type: 'array', + description: 'List of matching users', + items: { + type: 'object', + properties: { + amplitudeId: { type: 'number', description: 'Amplitude internal user ID' }, + userId: { type: 'string', description: 'External user ID' }, + }, + }, + }, + type: { + type: 'string', + description: 'Match type (e.g., match_user_or_device_id)', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/google_pagespeed/analyze.ts b/apps/sim/tools/google_pagespeed/analyze.ts new file mode 100644 index 0000000000..a5fc0cfa5e --- /dev/null +++ b/apps/sim/tools/google_pagespeed/analyze.ts @@ -0,0 +1,223 @@ +import type { + GooglePagespeedAnalyzeParams, + GooglePagespeedAnalyzeResponse, +} from '@/tools/google_pagespeed/types' +import type { ToolConfig } from '@/tools/types' + +export const analyzeTool: ToolConfig = + { + id: 'google_pagespeed_analyze', + name: 'Google PageSpeed Analyze', + description: + 'Analyze a webpage for performance, accessibility, SEO, and best practices using Google PageSpeed Insights.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Google PageSpeed Insights API Key', + }, + url: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The URL of the webpage to analyze', + }, + category: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Lighthouse categories to analyze (comma-separated): performance, accessibility, best-practices, seo', + }, + strategy: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Analysis strategy: desktop or mobile', + }, + locale: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Locale for results (e.g., en, fr, de)', + }, + }, + + request: { + url: (params) => { + const url = new URL('https://www.googleapis.com/pagespeedonline/v5/runPagespeed') + url.searchParams.append('url', params.url.trim()) + url.searchParams.append('key', params.apiKey) + + if (params.category) { + const categories = params.category.split(',').map((c) => c.trim()) + for (const cat of categories) { + url.searchParams.append('category', cat) + } + } else { + url.searchParams.append('category', 'performance') + url.searchParams.append('category', 'accessibility') + url.searchParams.append('category', 'best-practices') + url.searchParams.append('category', 'seo') + } + + if (params.strategy) { + url.searchParams.append('strategy', params.strategy) + } + if (params.locale) { + url.searchParams.append('locale', params.locale) + } + + return url.toString() + }, + method: 'GET', + headers: () => ({ + Accept: 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message ?? 'Failed to analyze page') + } + + const lighthouse = data.lighthouseResult ?? {} + const categories = lighthouse.categories ?? {} + const audits = lighthouse.audits ?? {} + const loadingExperience = data.loadingExperience ?? {} + + return { + success: true, + output: { + finalUrl: data.id ?? null, + performanceScore: categories.performance?.score ?? null, + accessibilityScore: categories.accessibility?.score ?? null, + bestPracticesScore: categories['best-practices']?.score ?? null, + seoScore: categories.seo?.score ?? null, + firstContentfulPaint: audits['first-contentful-paint']?.displayValue ?? null, + firstContentfulPaintMs: audits['first-contentful-paint']?.numericValue ?? null, + largestContentfulPaint: audits['largest-contentful-paint']?.displayValue ?? null, + largestContentfulPaintMs: audits['largest-contentful-paint']?.numericValue ?? null, + totalBlockingTime: audits['total-blocking-time']?.displayValue ?? null, + totalBlockingTimeMs: audits['total-blocking-time']?.numericValue ?? null, + cumulativeLayoutShift: audits['cumulative-layout-shift']?.displayValue ?? null, + cumulativeLayoutShiftValue: audits['cumulative-layout-shift']?.numericValue ?? null, + speedIndex: audits['speed-index']?.displayValue ?? null, + speedIndexMs: audits['speed-index']?.numericValue ?? null, + interactive: audits.interactive?.displayValue ?? null, + interactiveMs: audits.interactive?.numericValue ?? null, + overallCategory: loadingExperience.overall_category ?? null, + analysisTimestamp: data.analysisUTCTimestamp ?? null, + lighthouseVersion: lighthouse.lighthouseVersion ?? null, + }, + } + }, + + outputs: { + finalUrl: { + type: 'string', + description: 'The final URL after redirects', + optional: true, + }, + performanceScore: { + type: 'number', + description: 'Performance category score (0-1)', + optional: true, + }, + accessibilityScore: { + type: 'number', + description: 'Accessibility category score (0-1)', + optional: true, + }, + bestPracticesScore: { + type: 'number', + description: 'Best Practices category score (0-1)', + optional: true, + }, + seoScore: { + type: 'number', + description: 'SEO category score (0-1)', + optional: true, + }, + firstContentfulPaint: { + type: 'string', + description: 'Time to First Contentful Paint (display value)', + optional: true, + }, + firstContentfulPaintMs: { + type: 'number', + description: 'Time to First Contentful Paint in milliseconds', + optional: true, + }, + largestContentfulPaint: { + type: 'string', + description: 'Time to Largest Contentful Paint (display value)', + optional: true, + }, + largestContentfulPaintMs: { + type: 'number', + description: 'Time to Largest Contentful Paint in milliseconds', + optional: true, + }, + totalBlockingTime: { + type: 'string', + description: 'Total Blocking Time (display value)', + optional: true, + }, + totalBlockingTimeMs: { + type: 'number', + description: 'Total Blocking Time in milliseconds', + optional: true, + }, + cumulativeLayoutShift: { + type: 'string', + description: 'Cumulative Layout Shift (display value)', + optional: true, + }, + cumulativeLayoutShiftValue: { + type: 'number', + description: 'Cumulative Layout Shift numeric value', + optional: true, + }, + speedIndex: { + type: 'string', + description: 'Speed Index (display value)', + optional: true, + }, + speedIndexMs: { + type: 'number', + description: 'Speed Index in milliseconds', + optional: true, + }, + interactive: { + type: 'string', + description: 'Time to Interactive (display value)', + optional: true, + }, + interactiveMs: { + type: 'number', + description: 'Time to Interactive in milliseconds', + optional: true, + }, + overallCategory: { + type: 'string', + description: 'Overall loading experience category (FAST, AVERAGE, SLOW, or NONE)', + optional: true, + }, + analysisTimestamp: { + type: 'string', + description: 'UTC timestamp of the analysis', + optional: true, + }, + lighthouseVersion: { + type: 'string', + description: 'Version of Lighthouse used for the analysis', + optional: true, + }, + }, + } diff --git a/apps/sim/tools/google_pagespeed/index.ts b/apps/sim/tools/google_pagespeed/index.ts new file mode 100644 index 0000000000..61d688f0be --- /dev/null +++ b/apps/sim/tools/google_pagespeed/index.ts @@ -0,0 +1,5 @@ +import { analyzeTool } from '@/tools/google_pagespeed/analyze' + +export const googlePagespeedAnalyzeTool = analyzeTool + +export * from '@/tools/google_pagespeed/types' diff --git a/apps/sim/tools/google_pagespeed/types.ts b/apps/sim/tools/google_pagespeed/types.ts new file mode 100644 index 0000000000..77f49aeee6 --- /dev/null +++ b/apps/sim/tools/google_pagespeed/types.ts @@ -0,0 +1,37 @@ +import type { ToolResponse } from '@/tools/types' + +export interface GooglePagespeedBaseParams { + apiKey: string +} + +export interface GooglePagespeedAnalyzeParams extends GooglePagespeedBaseParams { + url: string + category?: string + strategy?: string + locale?: string +} + +export interface GooglePagespeedAnalyzeResponse extends ToolResponse { + output: { + finalUrl: string | null + performanceScore: number | null + accessibilityScore: number | null + bestPracticesScore: number | null + seoScore: number | null + firstContentfulPaint: string | null + firstContentfulPaintMs: number | null + largestContentfulPaint: string | null + largestContentfulPaintMs: number | null + totalBlockingTime: string | null + totalBlockingTimeMs: number | null + cumulativeLayoutShift: string | null + cumulativeLayoutShiftValue: number | null + speedIndex: string | null + speedIndexMs: number | null + interactive: string | null + interactiveMs: number | null + overallCategory: string | null + analysisTimestamp: string | null + lighthouseVersion: string | null + } +} diff --git a/apps/sim/tools/pagerduty/add_note.ts b/apps/sim/tools/pagerduty/add_note.ts new file mode 100644 index 0000000000..5c900c1561 --- /dev/null +++ b/apps/sim/tools/pagerduty/add_note.ts @@ -0,0 +1,78 @@ +import type { PagerDutyAddNoteParams, PagerDutyAddNoteResponse } from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const addNoteTool: ToolConfig = { + id: 'pagerduty_add_note', + name: 'PagerDuty Add Note', + description: 'Add a note to an existing PagerDuty incident.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + fromEmail: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Email address of a valid PagerDuty user', + }, + incidentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the incident to add the note to', + }, + content: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Note content text', + }, + }, + + request: { + url: (params) => `https://api.pagerduty.com/incidents/${params.incidentId.trim()}/notes`, + method: 'POST', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + From: params.fromEmail, + }), + body: (params) => ({ + note: { + content: params.content, + }, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + const note = data.note ?? {} + return { + success: true, + output: { + id: note.id ?? null, + content: note.content ?? null, + createdAt: note.created_at ?? null, + userName: note.user?.summary ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Note ID' }, + content: { type: 'string', description: 'Note content' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + userName: { type: 'string', description: 'Name of the user who created the note' }, + }, +} diff --git a/apps/sim/tools/pagerduty/create_incident.ts b/apps/sim/tools/pagerduty/create_incident.ts new file mode 100644 index 0000000000..6a4c98854f --- /dev/null +++ b/apps/sim/tools/pagerduty/create_incident.ts @@ -0,0 +1,149 @@ +import type { + PagerDutyCreateIncidentParams, + PagerDutyCreateIncidentResponse, +} from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const createIncidentTool: ToolConfig< + PagerDutyCreateIncidentParams, + PagerDutyCreateIncidentResponse +> = { + id: 'pagerduty_create_incident', + name: 'PagerDuty Create Incident', + description: 'Create a new incident in PagerDuty.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + fromEmail: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Email address of a valid PagerDuty user', + }, + title: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Incident title/summary', + }, + serviceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the PagerDuty service', + }, + urgency: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Urgency level (high or low)', + }, + body: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Detailed description of the incident', + }, + escalationPolicyId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Escalation policy ID to assign', + }, + assigneeId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'User ID to assign the incident to', + }, + }, + + request: { + url: 'https://api.pagerduty.com/incidents', + method: 'POST', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + From: params.fromEmail, + }), + body: (params) => { + const incident: Record = { + type: 'incident', + title: params.title, + service: { + id: params.serviceId, + type: 'service_reference', + }, + } + + if (params.urgency) incident.urgency = params.urgency + if (params.body) { + incident.body = { + type: 'incident_body', + details: params.body, + } + } + if (params.escalationPolicyId) { + incident.escalation_policy = { + id: params.escalationPolicyId, + type: 'escalation_policy_reference', + } + } + if (params.assigneeId) { + incident.assignments = [ + { + assignee: { + id: params.assigneeId, + type: 'user_reference', + }, + }, + ] + } + + return { incident } + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + const inc = data.incident ?? {} + return { + success: true, + output: { + id: inc.id ?? null, + incidentNumber: inc.incident_number ?? null, + title: inc.title ?? null, + status: inc.status ?? null, + urgency: inc.urgency ?? null, + createdAt: inc.created_at ?? null, + serviceName: inc.service?.summary ?? null, + serviceId: inc.service?.id ?? null, + htmlUrl: inc.html_url ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Created incident ID' }, + incidentNumber: { type: 'number', description: 'Incident number' }, + title: { type: 'string', description: 'Incident title' }, + status: { type: 'string', description: 'Incident status' }, + urgency: { type: 'string', description: 'Incident urgency' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + serviceName: { type: 'string', description: 'Service name' }, + serviceId: { type: 'string', description: 'Service ID' }, + htmlUrl: { type: 'string', description: 'PagerDuty web URL' }, + }, +} diff --git a/apps/sim/tools/pagerduty/index.ts b/apps/sim/tools/pagerduty/index.ts new file mode 100644 index 0000000000..e6ee2bc34b --- /dev/null +++ b/apps/sim/tools/pagerduty/index.ts @@ -0,0 +1,13 @@ +import { addNoteTool } from '@/tools/pagerduty/add_note' +import { createIncidentTool } from '@/tools/pagerduty/create_incident' +import { listIncidentsTool } from '@/tools/pagerduty/list_incidents' +import { listOncallsTool } from '@/tools/pagerduty/list_oncalls' +import { listServicesTool } from '@/tools/pagerduty/list_services' +import { updateIncidentTool } from '@/tools/pagerduty/update_incident' + +export const pagerdutyListIncidentsTool = listIncidentsTool +export const pagerdutyCreateIncidentTool = createIncidentTool +export const pagerdutyUpdateIncidentTool = updateIncidentTool +export const pagerdutyAddNoteTool = addNoteTool +export const pagerdutyListServicesTool = listServicesTool +export const pagerdutyListOncallsTool = listOncallsTool diff --git a/apps/sim/tools/pagerduty/list_incidents.ts b/apps/sim/tools/pagerduty/list_incidents.ts new file mode 100644 index 0000000000..a2ed353076 --- /dev/null +++ b/apps/sim/tools/pagerduty/list_incidents.ts @@ -0,0 +1,161 @@ +import type { + PagerDutyListIncidentsParams, + PagerDutyListIncidentsResponse, +} from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const listIncidentsTool: ToolConfig< + PagerDutyListIncidentsParams, + PagerDutyListIncidentsResponse +> = { + id: 'pagerduty_list_incidents', + name: 'PagerDuty List Incidents', + description: 'List incidents from PagerDuty with optional filters.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + statuses: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated statuses to filter (triggered, acknowledged, resolved)', + }, + serviceIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated service IDs to filter', + }, + since: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Start date filter (ISO 8601 format)', + }, + until: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'End date filter (ISO 8601 format)', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Sort field (e.g., created_at:desc)', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results (max 100)', + }, + }, + + request: { + url: (params) => { + const query = new URLSearchParams() + if (params.statuses) { + for (const s of params.statuses.split(',')) { + query.append('statuses[]', s.trim()) + } + } + if (params.serviceIds) { + for (const id of params.serviceIds.split(',')) { + query.append('service_ids[]', id.trim()) + } + } + if (params.since) query.set('since', params.since) + if (params.until) query.set('until', params.until) + if (params.sortBy) query.set('sort_by', params.sortBy) + if (params.limit) query.set('limit', params.limit) + query.append('include[]', 'services') + const qs = query.toString() + return `https://api.pagerduty.com/incidents${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + return { + success: true, + output: { + incidents: (data.incidents ?? []).map( + ( + inc: Record & { + service?: Record + assignments?: Array & { assignee?: Record }> + escalation_policy?: Record + } + ) => ({ + id: inc.id ?? null, + incidentNumber: inc.incident_number ?? null, + title: inc.title ?? null, + status: inc.status ?? null, + urgency: inc.urgency ?? null, + createdAt: inc.created_at ?? null, + updatedAt: inc.updated_at ?? null, + serviceName: inc.service?.summary ?? null, + serviceId: inc.service?.id ?? null, + assigneeName: inc.assignments?.[0]?.assignee?.summary ?? null, + assigneeId: inc.assignments?.[0]?.assignee?.id ?? null, + escalationPolicyName: inc.escalation_policy?.summary ?? null, + htmlUrl: inc.html_url ?? null, + }) + ), + total: data.total ?? 0, + more: data.more ?? false, + }, + } + }, + + outputs: { + incidents: { + type: 'array', + description: 'Array of incidents', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Incident ID' }, + incidentNumber: { type: 'number', description: 'Incident number' }, + title: { type: 'string', description: 'Incident title' }, + status: { type: 'string', description: 'Incident status' }, + urgency: { type: 'string', description: 'Incident urgency' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + updatedAt: { type: 'string', description: 'Last updated timestamp' }, + serviceName: { type: 'string', description: 'Service name' }, + serviceId: { type: 'string', description: 'Service ID' }, + assigneeName: { type: 'string', description: 'Assignee name' }, + assigneeId: { type: 'string', description: 'Assignee ID' }, + escalationPolicyName: { type: 'string', description: 'Escalation policy name' }, + htmlUrl: { type: 'string', description: 'PagerDuty web URL' }, + }, + }, + }, + total: { + type: 'number', + description: 'Total number of matching incidents', + }, + more: { + type: 'boolean', + description: 'Whether more results are available', + }, + }, +} diff --git a/apps/sim/tools/pagerduty/list_oncalls.ts b/apps/sim/tools/pagerduty/list_oncalls.ts new file mode 100644 index 0000000000..92f436b9c3 --- /dev/null +++ b/apps/sim/tools/pagerduty/list_oncalls.ts @@ -0,0 +1,145 @@ +import type { + PagerDutyListOncallsParams, + PagerDutyListOncallsResponse, +} from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const listOncallsTool: ToolConfig = + { + id: 'pagerduty_list_oncalls', + name: 'PagerDuty List On-Calls', + description: 'List current on-call entries from PagerDuty.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + escalationPolicyIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated escalation policy IDs to filter', + }, + scheduleIds: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated schedule IDs to filter', + }, + since: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Start time filter (ISO 8601 format)', + }, + until: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'End time filter (ISO 8601 format)', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results (max 100)', + }, + }, + + request: { + url: (params) => { + const query = new URLSearchParams() + if (params.escalationPolicyIds) { + for (const id of params.escalationPolicyIds.split(',')) { + query.append('escalation_policy_ids[]', id.trim()) + } + } + if (params.scheduleIds) { + for (const id of params.scheduleIds.split(',')) { + query.append('schedule_ids[]', id.trim()) + } + } + if (params.since) query.set('since', params.since) + if (params.until) query.set('until', params.until) + if (params.limit) query.set('limit', params.limit) + const qs = query.toString() + return `https://api.pagerduty.com/oncalls${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + const oncalls = (data.oncalls ?? []).map( + ( + oc: Record & { + user?: Record + escalation_policy?: Record + schedule?: Record + } + ) => ({ + userName: oc.user?.summary ?? null, + userId: oc.user?.id ?? null, + escalationLevel: oc.escalation_level ?? 0, + escalationPolicyName: oc.escalation_policy?.summary ?? null, + escalationPolicyId: oc.escalation_policy?.id ?? null, + scheduleName: oc.schedule?.summary ?? null, + scheduleId: oc.schedule?.id ?? null, + start: oc.start ?? null, + end: oc.end ?? null, + }) + ) + + return { + success: true, + output: { + oncalls, + total: data.total ?? oncalls.length, + more: data.more ?? false, + }, + } + }, + + outputs: { + oncalls: { + type: 'array', + description: 'Array of on-call entries', + items: { + type: 'object', + properties: { + userName: { type: 'string', description: 'On-call user name' }, + userId: { type: 'string', description: 'On-call user ID' }, + escalationLevel: { type: 'number', description: 'Escalation level' }, + escalationPolicyName: { type: 'string', description: 'Escalation policy name' }, + escalationPolicyId: { type: 'string', description: 'Escalation policy ID' }, + scheduleName: { type: 'string', description: 'Schedule name' }, + scheduleId: { type: 'string', description: 'Schedule ID' }, + start: { type: 'string', description: 'On-call start time' }, + end: { type: 'string', description: 'On-call end time' }, + }, + }, + }, + total: { + type: 'number', + description: 'Total number of matching on-call entries', + }, + more: { + type: 'boolean', + description: 'Whether more results are available', + }, + }, + } diff --git a/apps/sim/tools/pagerduty/list_services.ts b/apps/sim/tools/pagerduty/list_services.ts new file mode 100644 index 0000000000..af281ffc83 --- /dev/null +++ b/apps/sim/tools/pagerduty/list_services.ts @@ -0,0 +1,108 @@ +import type { + PagerDutyListServicesParams, + PagerDutyListServicesResponse, +} from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const listServicesTool: ToolConfig< + PagerDutyListServicesParams, + PagerDutyListServicesResponse +> = { + id: 'pagerduty_list_services', + name: 'PagerDuty List Services', + description: 'List services from PagerDuty with optional name filter.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + query: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter services by name', + }, + limit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results (max 100)', + }, + }, + + request: { + url: (params) => { + const query = new URLSearchParams() + if (params.query) query.set('query', params.query) + if (params.limit) query.set('limit', params.limit) + const qs = query.toString() + return `https://api.pagerduty.com/services${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + return { + success: true, + output: { + services: (data.services ?? []).map( + (svc: Record & { escalation_policy?: Record }) => ({ + id: svc.id ?? null, + name: svc.name ?? null, + description: svc.description ?? null, + status: svc.status ?? null, + escalationPolicyName: svc.escalation_policy?.summary ?? null, + escalationPolicyId: svc.escalation_policy?.id ?? null, + createdAt: svc.created_at ?? null, + htmlUrl: svc.html_url ?? null, + }) + ), + total: data.total ?? 0, + more: data.more ?? false, + }, + } + }, + + outputs: { + services: { + type: 'array', + description: 'Array of services', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Service ID' }, + name: { type: 'string', description: 'Service name' }, + description: { type: 'string', description: 'Service description' }, + status: { type: 'string', description: 'Service status' }, + escalationPolicyName: { type: 'string', description: 'Escalation policy name' }, + escalationPolicyId: { type: 'string', description: 'Escalation policy ID' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + htmlUrl: { type: 'string', description: 'PagerDuty web URL' }, + }, + }, + }, + total: { + type: 'number', + description: 'Total number of matching services', + }, + more: { + type: 'boolean', + description: 'Whether more results are available', + }, + }, +} diff --git a/apps/sim/tools/pagerduty/types.ts b/apps/sim/tools/pagerduty/types.ts new file mode 100644 index 0000000000..ab800bf188 --- /dev/null +++ b/apps/sim/tools/pagerduty/types.ts @@ -0,0 +1,169 @@ +import type { ToolResponse } from '@/tools/types' + +/** + * Base params shared by all PagerDuty endpoints. + */ +export interface PagerDutyBaseParams { + apiKey: string +} + +/** + * Params that require a From header for write operations. + */ +export interface PagerDutyWriteParams extends PagerDutyBaseParams { + fromEmail: string +} + +/** + * List Incidents params. + */ +export interface PagerDutyListIncidentsParams extends PagerDutyBaseParams { + statuses?: string + serviceIds?: string + since?: string + until?: string + sortBy?: string + limit?: string +} + +export interface PagerDutyListIncidentsResponse extends ToolResponse { + output: { + incidents: Array<{ + id: string + incidentNumber: number + title: string + status: string + urgency: string + createdAt: string + updatedAt: string | null + serviceName: string | null + serviceId: string | null + assigneeName: string | null + assigneeId: string | null + escalationPolicyName: string | null + htmlUrl: string | null + }> + total: number + more: boolean + } +} + +/** + * Create Incident params. + */ +export interface PagerDutyCreateIncidentParams extends PagerDutyWriteParams { + title: string + serviceId: string + urgency?: string + body?: string + escalationPolicyId?: string + assigneeId?: string +} + +export interface PagerDutyCreateIncidentResponse extends ToolResponse { + output: { + id: string + incidentNumber: number + title: string + status: string + urgency: string + createdAt: string + serviceName: string | null + serviceId: string | null + htmlUrl: string | null + } +} + +/** + * Update Incident params. + */ +export interface PagerDutyUpdateIncidentParams extends PagerDutyWriteParams { + incidentId: string + status?: string + title?: string + urgency?: string + escalationLevel?: string +} + +export interface PagerDutyUpdateIncidentResponse extends ToolResponse { + output: { + id: string + incidentNumber: number + title: string + status: string + urgency: string + updatedAt: string | null + htmlUrl: string | null + } +} + +/** + * Add Note to Incident params. + */ +export interface PagerDutyAddNoteParams extends PagerDutyWriteParams { + incidentId: string + content: string +} + +export interface PagerDutyAddNoteResponse extends ToolResponse { + output: { + id: string + content: string + createdAt: string + userName: string | null + } +} + +/** + * List Services params. + */ +export interface PagerDutyListServicesParams extends PagerDutyBaseParams { + query?: string + limit?: string +} + +export interface PagerDutyListServicesResponse extends ToolResponse { + output: { + services: Array<{ + id: string + name: string + description: string | null + status: string + escalationPolicyName: string | null + escalationPolicyId: string | null + createdAt: string + htmlUrl: string | null + }> + total: number + more: boolean + } +} + +/** + * List On-Calls params. + */ +export interface PagerDutyListOncallsParams extends PagerDutyBaseParams { + escalationPolicyIds?: string + scheduleIds?: string + since?: string + until?: string + limit?: string +} + +export interface PagerDutyListOncallsResponse extends ToolResponse { + output: { + oncalls: Array<{ + userName: string | null + userId: string | null + escalationLevel: number + escalationPolicyName: string | null + escalationPolicyId: string | null + scheduleName: string | null + scheduleId: string | null + start: string | null + end: string | null + }> + total: number + more: boolean + } +} diff --git a/apps/sim/tools/pagerduty/update_incident.ts b/apps/sim/tools/pagerduty/update_incident.ts new file mode 100644 index 0000000000..156b5a1ad5 --- /dev/null +++ b/apps/sim/tools/pagerduty/update_incident.ts @@ -0,0 +1,117 @@ +import type { + PagerDutyUpdateIncidentParams, + PagerDutyUpdateIncidentResponse, +} from '@/tools/pagerduty/types' +import type { ToolConfig } from '@/tools/types' + +export const updateIncidentTool: ToolConfig< + PagerDutyUpdateIncidentParams, + PagerDutyUpdateIncidentResponse +> = { + id: 'pagerduty_update_incident', + name: 'PagerDuty Update Incident', + description: 'Update an incident in PagerDuty (acknowledge, resolve, change urgency, etc.).', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'PagerDuty REST API Key', + }, + fromEmail: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Email address of a valid PagerDuty user', + }, + incidentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the incident to update', + }, + status: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New status (acknowledged or resolved)', + }, + title: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New incident title', + }, + urgency: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New urgency (high or low)', + }, + escalationLevel: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Escalation level to escalate to', + }, + }, + + request: { + url: (params) => `https://api.pagerduty.com/incidents/${params.incidentId.trim()}`, + method: 'PUT', + headers: (params) => ({ + Authorization: `Token token=${params.apiKey}`, + Accept: 'application/vnd.pagerduty+json;version=2', + 'Content-Type': 'application/json', + From: params.fromEmail, + }), + body: (params) => { + const incident: Record = { + id: params.incidentId, + type: 'incident', + } + + if (params.status) incident.status = params.status + if (params.title) incident.title = params.title + if (params.urgency) incident.urgency = params.urgency + if (params.escalationLevel) { + incident.escalation_level = Number(params.escalationLevel) + } + return { incident } + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error?.message || `PagerDuty API error: ${response.status}`) + } + + const inc = data.incident ?? {} + return { + success: true, + output: { + id: inc.id ?? null, + incidentNumber: inc.incident_number ?? null, + title: inc.title ?? null, + status: inc.status ?? null, + urgency: inc.urgency ?? null, + updatedAt: inc.updated_at ?? null, + htmlUrl: inc.html_url ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Incident ID' }, + incidentNumber: { type: 'number', description: 'Incident number' }, + title: { type: 'string', description: 'Incident title' }, + status: { type: 'string', description: 'Updated status' }, + urgency: { type: 'string', description: 'Updated urgency' }, + updatedAt: { type: 'string', description: 'Last updated timestamp' }, + htmlUrl: { type: 'string', description: 'PagerDuty web URL' }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 00b9d1e47c..e44e35ed1b 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -42,6 +42,19 @@ import { algoliaSearchTool, algoliaUpdateSettingsTool, } from '@/tools/algolia' +import { + amplitudeEventSegmentationTool, + amplitudeGetActiveUsersTool, + amplitudeGetRevenueTool, + amplitudeGroupIdentifyTool, + amplitudeIdentifyUserTool, + amplitudeListEventsTool, + amplitudeRealtimeActiveUsersTool, + amplitudeSendEventTool, + amplitudeUserActivityTool, + amplitudeUserProfileTool, + amplitudeUserSearchTool, +} from '@/tools/amplitude' import { apifyRunActorAsyncTool, apifyRunActorSyncTool } from '@/tools/apify' import { apolloAccountBulkCreateTool, @@ -786,6 +799,7 @@ import { googleMapsTimezoneTool, googleMapsValidateAddressTool, } from '@/tools/google_maps' +import { googlePagespeedAnalyzeTool } from '@/tools/google_pagespeed' import { googleSheetsAppendTool, googleSheetsAppendV2Tool, @@ -1444,6 +1458,14 @@ import { outlookReadTool, outlookSendTool, } from '@/tools/outlook' +import { + pagerdutyAddNoteTool, + pagerdutyCreateIncidentTool, + pagerdutyListIncidentsTool, + pagerdutyListOncallsTool, + pagerdutyListServicesTool, + pagerdutyUpdateIncidentTool, +} from '@/tools/pagerduty' import { parallelDeepResearchTool, parallelExtractTool, parallelSearchTool } from '@/tools/parallel' import { perplexityChatTool, perplexitySearchTool } from '@/tools/perplexity' import { @@ -2248,6 +2270,17 @@ export const tools: Record = { a2a_send_message: a2aSendMessageTool, a2a_set_push_notification: a2aSetPushNotificationTool, airweave_search: airweaveSearchTool, + amplitude_send_event: amplitudeSendEventTool, + amplitude_identify_user: amplitudeIdentifyUserTool, + amplitude_group_identify: amplitudeGroupIdentifyTool, + amplitude_user_search: amplitudeUserSearchTool, + amplitude_user_activity: amplitudeUserActivityTool, + amplitude_user_profile: amplitudeUserProfileTool, + amplitude_event_segmentation: amplitudeEventSegmentationTool, + amplitude_get_active_users: amplitudeGetActiveUsersTool, + amplitude_realtime_active_users: amplitudeRealtimeActiveUsersTool, + amplitude_list_events: amplitudeListEventsTool, + amplitude_get_revenue: amplitudeGetRevenueTool, arxiv_get_author_papers: arxivGetAuthorPapersTool, arxiv_get_paper: arxivGetPaperTool, arxiv_search: arxivSearchTool, @@ -3163,6 +3196,7 @@ export const tools: Record = { google_maps_speed_limits: googleMapsSpeedLimitsTool, google_maps_timezone: googleMapsTimezoneTool, google_maps_validate_address: googleMapsValidateAddressTool, + google_pagespeed_analyze: googlePagespeedAnalyzeTool, google_tasks_create: googleTasksCreateTool, google_tasks_delete: googleTasksDeleteTool, google_tasks_get: googleTasksGetTool, @@ -3637,6 +3671,12 @@ export const tools: Record = { outlook_mark_unread: outlookMarkUnreadTool, outlook_delete: outlookDeleteTool, outlook_copy: outlookCopyTool, + pagerduty_list_incidents: pagerdutyListIncidentsTool, + pagerduty_create_incident: pagerdutyCreateIncidentTool, + pagerduty_update_incident: pagerdutyUpdateIncidentTool, + pagerduty_add_note: pagerdutyAddNoteTool, + pagerduty_list_services: pagerdutyListServicesTool, + pagerduty_list_oncalls: pagerdutyListOncallsTool, linear_read_issues: linearReadIssuesTool, linear_create_issue: linearCreateIssueTool, linear_get_issue: linearGetIssueTool,